Skip to content

fix(expo): link iOS SDK through podspec SPM dependencies - #8927

Merged
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking
Jun 19, 2026
Merged

fix(expo): link iOS SDK through podspec SPM dependencies#8927
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking

Conversation

@mikepitre

@mikepitremikepitre commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Link clerk-ios from ClerkExpo.podspec using React Native's spm_dependency, so the ClerkExpo pod target can import ClerkKit and ClerkKitUI directly.
  • Remove the config plugin's app-target SPM/project mutation and copied native bridge injection.
  • Remove the old optional native bridge facade now that the Clerk iOS SDK is available inside the ClerkExpo pod target; module and view wrappers call ClerkNativeBridge.shared directly.
  • Bump the @clerk/expo React Native peer dependency from >=0.73 to >=0.75, since this fix relies on React Native's podspec Swift Package Manager dependency support.

Motivation

Expo SDK 54 generates import ClerkExpo for Expo modules while SDK 56 generates internal import ClerkExpo. The import form is not the real problem; the issue was that ClerkExpo depended on ClerkKit/ClerkKitUI through app-target project mutation instead of declaring the Swift package dependency on the pod target that actually imports those modules.

Moving the SPM dependency into the podspec keeps the dependency attached to the correct native target and avoids having to special-case Expo's generated import style.

Because the Clerk iOS SDK is now visible to the pod target, the separate ClerkExpoBridge.swift protocol/global registry layer is no longer needed. The remaining readiness and native-client-change coordination lives on ClerkNativeBridge.

Verification

  • git diff --check
  • pnpm --filter @clerk/expo test
  • Fresh Expo SDK 54 and SDK 56 apps installed @clerk/expo from a packed tarball
  • npx expo prebuild --clean --platform ios passed for both apps
  • Clean Release simulator builds passed for both apps, fetching clerk-ios1.2.4 through SPM
  • Installed and launched both apps on the iOS simulator; verified AuthView, UserButton, JS sign-in, and JS sign-out

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved iOS development-build compatibility across Expo SDK versions with more reliable native SDK linking and configuration.
    • Refined native-to-JS client-change updates to stay consistent after app reconfiguration and theme loading.
  • Chores

    • Simplified iOS setup by reading the host SDK version from app metadata and using it when communicating with the native layer.
  • Tests

    • Removed an obsolete iOS version injection test.
  • Compatibility

    • Raised the minimum supported React Native version to 0.75+.

@changeset-bot

changeset-botBot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ea697ef

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

This PR includes changesets to release 1 package
NameType
@clerk/expoMinor

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

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

@vercel

vercelBot commented Jun 19, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJun 19, 2026 9:42am
swingsetReadyReadyPreview, CommentJun 19, 2026 9:42am

Request Review

@coderabbitai

coderabbitaiBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f46b3e8a-ee41-4167-8d6d-9d6271d22c1e

📥 Commits

Reviewing files that changed from the base of the PR and between ee5f933 and ea697ef.

📒 Files selected for processing (1)
  • .changeset/tidy-expo-ios-import.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-expo-ios-import.md

📝 Walkthrough

Walkthrough

The Clerk iOS SDK is now linked via React Native's native SPM podspec support rather than manual Expo config plugin injection. ClerkExpo.podspec declares the SPM dependency and expands its source file list. ClerkNativeBridge is refactored to a static observer/emitter pattern reading the SDK version from Info.plist. app.plugin.js is reduced to setting only the deployment target and writing ClerkExpoVersion to Info.plist.

Changes

iOS SPM Podspec Integration

Layer / File(s)Summary
Podspec SPM dependency declaration and source files
packages/expo/ios/ClerkExpo.podspec, packages/expo/package.json
Podspec pins clerk_ios_version to 1.2.4, adds a conditional SPM block for ClerkKit/ClerkKitUI, expands s.source_files to cover all native bridge and view manager files, and raises the react-native peer dependency minimum to >=0.75.
ClerkNativeBridge static observer/emitter refactor and Info.plist version
packages/expo/ios/ClerkNativeBridge.swift
ClerkExpoHeaderMiddleware reads hostSdkVersion from Bundle.main Info.plist key ClerkExpoVersion at runtime instead of a build-time placeholder. configure gains an early loadThemes() call. Readiness and client-change plumbing is replaced with new static addReadyObserver/removeReadyObserver/emitReady and setClientChangedEmitter/emitClientChanged methods. Reconfigure path now posts a notification instead of emitting bridge-ready events.
ClerkExpoModule decoupled from optional bridge instance
packages/expo/ios/ClerkExpoModule.swift
Removes all top-level bridge protocol, event enum, observer registry, and global bridge variable declarations. Initializer registers a client-changed emitter via ClerkNativeBridge.setClientChangedEmitter. configure, getClientToken, and syncFromJsClientToken call ClerkNativeBridge.shared directly instead of guarding on an optional instance. The free function emitClerkNativeClientChanged is removed.
Native views switched to ClerkNativeBridge.shared singleton
packages/expo/ios/ClerkNativeViewHost.swift, packages/expo/ios/ClerkAuthNativeView.swift, packages/expo/ios/ClerkUserButtonNativeView.swift, packages/expo/ios/ClerkUserProfileNativeView.swift
ClerkNativeViewHost removes ClerkNativeBridgeReadyObserver conformance and switches to NotificationCenter observation of .clerkNativeSDKDidConfigure, adding explicit observer removal on window detach and in deinit. The three native view controllers replace guarded optional bridge lookups with direct ClerkNativeBridge.shared calls.
app.plugin.js simplification and changeset
packages/expo/app.plugin.js, .changeset/tidy-expo-ios-import.md
Removes all SPM injection, bridge file copying, AppDelegate method injection, and Podfile post-install hook logic from app.plugin.js, leaving only a deployment target update and an Info.plistClerkExpoVersion write. Documentation is updated to reflect the simplified setup. A patch changeset documents the iOS build fix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • clerk/javascript#8883: Replaces the __CLERK_EXPO_VERSION__ placeholder injection and ClerkExpoHeaderMiddleware request header wiring that this PR refactors to use Info.plist-driven runtime version reading.
  • clerk/javascript#8867: Pins clerk-ios to 1.2.4 in iOS integration, matching the version now declared via clerk_ios_version in the podspec.
  • clerk/javascript#8920: Modifies ClerkNativeBridge.swift in the configure/readiness signaling path, directly overlapping with this PR's refactoring of emitReady and loadThemes call placement.

Suggested reviewers

  • wobsoriano

Poem

🐇 No more Podfile hooks to fear,
The SPM lives in the podspec near!
Info.plist holds the version now,
The singleton bridge takes a bow.
Less plugin code, cleaner deploy —
This bunny hops with iOS joy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 17.24% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately summarizes the main change: moving iOS SDK linking from app-target configuration to podspec SPM dependencies.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@pkg-pr-new

pkg-pr-newBot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8927

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8927

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8927

@clerk/upgrade

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

@clerk/vue

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

commit: ea697ef

@github-actions

github-actionsBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-19T09:43:45.347Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on ea697ef.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/expo/ios/ClerkExpo.podspec (1)

20-21: 💤 Low value

Consider externalizing the Clerk iOS SDK version.

The clerk_ios_version = '1.2.4' is hardcoded in the podspec. Every Clerk iOS SDK update will require manually editing this file. Consider whether the version could be read from package.json or another configuration source to reduce maintenance overhead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/expo/ios/ClerkExpo.podspec` around lines 20 - 21, The
clerk_ios_version variable is hardcoded as '1.2.4' in the podspec file,
requiring manual updates whenever the Clerk iOS SDK version changes. Externalize
this version by reading it from package.json or another centralized
configuration source instead of hardcoding it. Modify the clerk_ios_version
assignment to dynamically fetch the version from the appropriate configuration
file, reducing maintenance overhead and keeping the dependency version
synchronized across your project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/expo/ios/ClerkExpoBridge.swift`:
- Around line 36-58: The clerkNativeBridgeReadyObservers hash table is accessed
without synchronization in the methods addClerkNativeBridgeReadyObserver,
removeClerkNativeBridgeReadyObserver, and emitClerkNativeBridgeReady, and
similarly clerkNativeClientChangedEmitter is accessed in
setClerkNativeClientChangedEmitter and emitClerkNativeClientChanged without
synchronization. Since NSHashTable is not thread-safe, concurrent calls from
different threads can corrupt the data structure or cause crashes. Create a
private serial DispatchQueue and wrap all accesses to both
clerkNativeBridgeReadyObservers and clerkNativeClientChangedEmitter within
synchronized blocks using this queue, ensuring all read and write operations are
serialized and thread-safe.
---
Nitpick comments:
In `@packages/expo/ios/ClerkExpo.podspec`:
- Around line 20-21: The clerk_ios_version variable is hardcoded as '1.2.4' in
the podspec file, requiring manual updates whenever the Clerk iOS SDK version
changes. Externalize this version by reading it from package.json or another
centralized configuration source instead of hardcoding it. Modify the
clerk_ios_version assignment to dynamically fetch the version from the
appropriate configuration file, reducing maintenance overhead and keeping the
dependency version synchronized across your project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cfed06c-5d52-4b43-bbe1-7a2655f71514

📥 Commits

Reviewing files that changed from the base of the PR and between 88525a6 and 5faa0bc.

📒 Files selected for processing (8)
  • .changeset/tidy-expo-ios-import.md
  • packages/expo/app.plugin.js
  • packages/expo/ios/ClerkExpo.podspec
  • packages/expo/ios/ClerkExpoBridge.swift
  • packages/expo/ios/ClerkExpoModule.swift
  • packages/expo/ios/ClerkNativeBridge.swift
  • packages/expo/package.json
  • packages/expo/src/__tests__/appPlugin.injectClerkExpoVersion.test.js
💤 Files with no reviewable changes (1)
  • packages/expo/src/tests/appPlugin.injectClerkExpoVersion.test.js

Comment threadpackages/expo/ios/ClerkExpoBridge.swift Outdated

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:f7088d0604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/expo/app.plugin.js

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:83e37e979b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

products: ['ClerkKit', 'ClerkKitUI']
)
else
raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep RN 0.73/0.74 pod installs working

For apps still on React Native 0.73/0.74 (which satisfied @clerk/expo's previous peer range and can receive this patch via a caret range), spm_dependency is not defined by RN's CocoaPods scripts, so this raise makes every iOS pod install fail even though those apps built with the old Xcode-project injection path. Because this is being released as a patch, please keep a fallback for those RN versions or avoid shipping this path to them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Our supported expo range is >=53, so supporting 0.73 and 0.74 is already a mismatch. Expo 53 contains React Native 0.79

@wobsorianowobsoriano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested this locally in both Expo SDK 54 and 56. Runs successfully ✅

@wobsoriano
wobsoriano merged commit bfe280a into mainJun 19, 2026
49 checks passed
@wobsoriano
wobsoriano deleted the mike/fix-expo-ios-spm-podspec-linking branch June 19, 2026 10:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mikepitre@wobsoriano
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
fix(expo): link iOS SDK through podspec SPM dependencies by mikepitre · Pull Request #8927 · clerk/javascript · GitHub
Skip to content

fix(expo): link iOS SDK through podspec SPM dependencies - #8927

Merged
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking
Jun 19, 2026
Merged

fix(expo): link iOS SDK through podspec SPM dependencies#8927
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking

Conversation

@mikepitre

@mikepitremikepitre commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Link clerk-ios from ClerkExpo.podspec using React Native's spm_dependency, so the ClerkExpo pod target can import ClerkKit and ClerkKitUI directly.
  • Remove the config plugin's app-target SPM/project mutation and copied native bridge injection.
  • Remove the old optional native bridge facade now that the Clerk iOS SDK is available inside the ClerkExpo pod target; module and view wrappers call ClerkNativeBridge.shared directly.
  • Bump the @clerk/expo React Native peer dependency from >=0.73 to >=0.75, since this fix relies on React Native's podspec Swift Package Manager dependency support.

Motivation

Expo SDK 54 generates import ClerkExpo for Expo modules while SDK 56 generates internal import ClerkExpo. The import form is not the real problem; the issue was that ClerkExpo depended on ClerkKit/ClerkKitUI through app-target project mutation instead of declaring the Swift package dependency on the pod target that actually imports those modules.

Moving the SPM dependency into the podspec keeps the dependency attached to the correct native target and avoids having to special-case Expo's generated import style.

Because the Clerk iOS SDK is now visible to the pod target, the separate ClerkExpoBridge.swift protocol/global registry layer is no longer needed. The remaining readiness and native-client-change coordination lives on ClerkNativeBridge.

Verification

  • git diff --check
  • pnpm --filter @clerk/expo test
  • Fresh Expo SDK 54 and SDK 56 apps installed @clerk/expo from a packed tarball
  • npx expo prebuild --clean --platform ios passed for both apps
  • Clean Release simulator builds passed for both apps, fetching clerk-ios1.2.4 through SPM
  • Installed and launched both apps on the iOS simulator; verified AuthView, UserButton, JS sign-in, and JS sign-out

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved iOS development-build compatibility across Expo SDK versions with more reliable native SDK linking and configuration.
    • Refined native-to-JS client-change updates to stay consistent after app reconfiguration and theme loading.
  • Chores

    • Simplified iOS setup by reading the host SDK version from app metadata and using it when communicating with the native layer.
  • Tests

    • Removed an obsolete iOS version injection test.
  • Compatibility

    • Raised the minimum supported React Native version to 0.75+.

@changeset-bot

changeset-botBot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ea697ef

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

This PR includes changesets to release 1 package
NameType
@clerk/expoMinor

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

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

@vercel

vercelBot commented Jun 19, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJun 19, 2026 9:42am
swingsetReadyReadyPreview, CommentJun 19, 2026 9:42am

Request Review

@coderabbitai

coderabbitaiBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f46b3e8a-ee41-4167-8d6d-9d6271d22c1e

📥 Commits

Reviewing files that changed from the base of the PR and between ee5f933 and ea697ef.

📒 Files selected for processing (1)
  • .changeset/tidy-expo-ios-import.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-expo-ios-import.md

📝 Walkthrough

Walkthrough

The Clerk iOS SDK is now linked via React Native's native SPM podspec support rather than manual Expo config plugin injection. ClerkExpo.podspec declares the SPM dependency and expands its source file list. ClerkNativeBridge is refactored to a static observer/emitter pattern reading the SDK version from Info.plist. app.plugin.js is reduced to setting only the deployment target and writing ClerkExpoVersion to Info.plist.

Changes

iOS SPM Podspec Integration

Layer / File(s)Summary
Podspec SPM dependency declaration and source files
packages/expo/ios/ClerkExpo.podspec, packages/expo/package.json
Podspec pins clerk_ios_version to 1.2.4, adds a conditional SPM block for ClerkKit/ClerkKitUI, expands s.source_files to cover all native bridge and view manager files, and raises the react-native peer dependency minimum to >=0.75.
ClerkNativeBridge static observer/emitter refactor and Info.plist version
packages/expo/ios/ClerkNativeBridge.swift
ClerkExpoHeaderMiddleware reads hostSdkVersion from Bundle.main Info.plist key ClerkExpoVersion at runtime instead of a build-time placeholder. configure gains an early loadThemes() call. Readiness and client-change plumbing is replaced with new static addReadyObserver/removeReadyObserver/emitReady and setClientChangedEmitter/emitClientChanged methods. Reconfigure path now posts a notification instead of emitting bridge-ready events.
ClerkExpoModule decoupled from optional bridge instance
packages/expo/ios/ClerkExpoModule.swift
Removes all top-level bridge protocol, event enum, observer registry, and global bridge variable declarations. Initializer registers a client-changed emitter via ClerkNativeBridge.setClientChangedEmitter. configure, getClientToken, and syncFromJsClientToken call ClerkNativeBridge.shared directly instead of guarding on an optional instance. The free function emitClerkNativeClientChanged is removed.
Native views switched to ClerkNativeBridge.shared singleton
packages/expo/ios/ClerkNativeViewHost.swift, packages/expo/ios/ClerkAuthNativeView.swift, packages/expo/ios/ClerkUserButtonNativeView.swift, packages/expo/ios/ClerkUserProfileNativeView.swift
ClerkNativeViewHost removes ClerkNativeBridgeReadyObserver conformance and switches to NotificationCenter observation of .clerkNativeSDKDidConfigure, adding explicit observer removal on window detach and in deinit. The three native view controllers replace guarded optional bridge lookups with direct ClerkNativeBridge.shared calls.
app.plugin.js simplification and changeset
packages/expo/app.plugin.js, .changeset/tidy-expo-ios-import.md
Removes all SPM injection, bridge file copying, AppDelegate method injection, and Podfile post-install hook logic from app.plugin.js, leaving only a deployment target update and an Info.plistClerkExpoVersion write. Documentation is updated to reflect the simplified setup. A patch changeset documents the iOS build fix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • clerk/javascript#8883: Replaces the __CLERK_EXPO_VERSION__ placeholder injection and ClerkExpoHeaderMiddleware request header wiring that this PR refactors to use Info.plist-driven runtime version reading.
  • clerk/javascript#8867: Pins clerk-ios to 1.2.4 in iOS integration, matching the version now declared via clerk_ios_version in the podspec.
  • clerk/javascript#8920: Modifies ClerkNativeBridge.swift in the configure/readiness signaling path, directly overlapping with this PR's refactoring of emitReady and loadThemes call placement.

Suggested reviewers

  • wobsoriano

Poem

🐇 No more Podfile hooks to fear,
The SPM lives in the podspec near!
Info.plist holds the version now,
The singleton bridge takes a bow.
Less plugin code, cleaner deploy —
This bunny hops with iOS joy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 17.24% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately summarizes the main change: moving iOS SDK linking from app-target configuration to podspec SPM dependencies.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@pkg-pr-new

pkg-pr-newBot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8927

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8927

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8927

@clerk/upgrade

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

@clerk/vue

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

commit: ea697ef

@github-actions

github-actionsBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-19T09:43:45.347Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on ea697ef.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/expo/ios/ClerkExpo.podspec (1)

20-21: 💤 Low value

Consider externalizing the Clerk iOS SDK version.

The clerk_ios_version = '1.2.4' is hardcoded in the podspec. Every Clerk iOS SDK update will require manually editing this file. Consider whether the version could be read from package.json or another configuration source to reduce maintenance overhead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/expo/ios/ClerkExpo.podspec` around lines 20 - 21, The
clerk_ios_version variable is hardcoded as '1.2.4' in the podspec file,
requiring manual updates whenever the Clerk iOS SDK version changes. Externalize
this version by reading it from package.json or another centralized
configuration source instead of hardcoding it. Modify the clerk_ios_version
assignment to dynamically fetch the version from the appropriate configuration
file, reducing maintenance overhead and keeping the dependency version
synchronized across your project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/expo/ios/ClerkExpoBridge.swift`:
- Around line 36-58: The clerkNativeBridgeReadyObservers hash table is accessed
without synchronization in the methods addClerkNativeBridgeReadyObserver,
removeClerkNativeBridgeReadyObserver, and emitClerkNativeBridgeReady, and
similarly clerkNativeClientChangedEmitter is accessed in
setClerkNativeClientChangedEmitter and emitClerkNativeClientChanged without
synchronization. Since NSHashTable is not thread-safe, concurrent calls from
different threads can corrupt the data structure or cause crashes. Create a
private serial DispatchQueue and wrap all accesses to both
clerkNativeBridgeReadyObservers and clerkNativeClientChangedEmitter within
synchronized blocks using this queue, ensuring all read and write operations are
serialized and thread-safe.
---
Nitpick comments:
In `@packages/expo/ios/ClerkExpo.podspec`:
- Around line 20-21: The clerk_ios_version variable is hardcoded as '1.2.4' in
the podspec file, requiring manual updates whenever the Clerk iOS SDK version
changes. Externalize this version by reading it from package.json or another
centralized configuration source instead of hardcoding it. Modify the
clerk_ios_version assignment to dynamically fetch the version from the
appropriate configuration file, reducing maintenance overhead and keeping the
dependency version synchronized across your project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cfed06c-5d52-4b43-bbe1-7a2655f71514

📥 Commits

Reviewing files that changed from the base of the PR and between 88525a6 and 5faa0bc.

📒 Files selected for processing (8)
  • .changeset/tidy-expo-ios-import.md
  • packages/expo/app.plugin.js
  • packages/expo/ios/ClerkExpo.podspec
  • packages/expo/ios/ClerkExpoBridge.swift
  • packages/expo/ios/ClerkExpoModule.swift
  • packages/expo/ios/ClerkNativeBridge.swift
  • packages/expo/package.json
  • packages/expo/src/__tests__/appPlugin.injectClerkExpoVersion.test.js
💤 Files with no reviewable changes (1)
  • packages/expo/src/tests/appPlugin.injectClerkExpoVersion.test.js

Comment threadpackages/expo/ios/ClerkExpoBridge.swift Outdated

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:f7088d0604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/expo/app.plugin.js

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:83e37e979b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

products: ['ClerkKit', 'ClerkKitUI']
)
else
raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep RN 0.73/0.74 pod installs working

For apps still on React Native 0.73/0.74 (which satisfied @clerk/expo's previous peer range and can receive this patch via a caret range), spm_dependency is not defined by RN's CocoaPods scripts, so this raise makes every iOS pod install fail even though those apps built with the old Xcode-project injection path. Because this is being released as a patch, please keep a fallback for those RN versions or avoid shipping this path to them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Our supported expo range is >=53, so supporting 0.73 and 0.74 is already a mismatch. Expo 53 contains React Native 0.79

@wobsorianowobsoriano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested this locally in both Expo SDK 54 and 56. Runs successfully ✅

@wobsoriano
wobsoriano merged commit bfe280a into mainJun 19, 2026
49 checks passed
@wobsoriano
wobsoriano deleted the mike/fix-expo-ios-spm-podspec-linking branch June 19, 2026 10:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mikepitre@wobsoriano
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(expo): link iOS SDK through podspec SPM dependencies by mikepitre · Pull Request #8927 · clerk/javascript · GitHub
Skip to content

fix(expo): link iOS SDK through podspec SPM dependencies - #8927

Merged
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking
Jun 19, 2026
Merged

fix(expo): link iOS SDK through podspec SPM dependencies#8927
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking

Conversation

@mikepitre

@mikepitremikepitre commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Link clerk-ios from ClerkExpo.podspec using React Native's spm_dependency, so the ClerkExpo pod target can import ClerkKit and ClerkKitUI directly.
  • Remove the config plugin's app-target SPM/project mutation and copied native bridge injection.
  • Remove the old optional native bridge facade now that the Clerk iOS SDK is available inside the ClerkExpo pod target; module and view wrappers call ClerkNativeBridge.shared directly.
  • Bump the @clerk/expo React Native peer dependency from >=0.73 to >=0.75, since this fix relies on React Native's podspec Swift Package Manager dependency support.

Motivation

Expo SDK 54 generates import ClerkExpo for Expo modules while SDK 56 generates internal import ClerkExpo. The import form is not the real problem; the issue was that ClerkExpo depended on ClerkKit/ClerkKitUI through app-target project mutation instead of declaring the Swift package dependency on the pod target that actually imports those modules.

Moving the SPM dependency into the podspec keeps the dependency attached to the correct native target and avoids having to special-case Expo's generated import style.

Because the Clerk iOS SDK is now visible to the pod target, the separate ClerkExpoBridge.swift protocol/global registry layer is no longer needed. The remaining readiness and native-client-change coordination lives on ClerkNativeBridge.

Verification

  • git diff --check
  • pnpm --filter @clerk/expo test
  • Fresh Expo SDK 54 and SDK 56 apps installed @clerk/expo from a packed tarball
  • npx expo prebuild --clean --platform ios passed for both apps
  • Clean Release simulator builds passed for both apps, fetching clerk-ios1.2.4 through SPM
  • Installed and launched both apps on the iOS simulator; verified AuthView, UserButton, JS sign-in, and JS sign-out

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved iOS development-build compatibility across Expo SDK versions with more reliable native SDK linking and configuration.
    • Refined native-to-JS client-change updates to stay consistent after app reconfiguration and theme loading.
  • Chores

    • Simplified iOS setup by reading the host SDK version from app metadata and using it when communicating with the native layer.
  • Tests

    • Removed an obsolete iOS version injection test.
  • Compatibility

    • Raised the minimum supported React Native version to 0.75+.

@changeset-bot

changeset-botBot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ea697ef

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

This PR includes changesets to release 1 package
NameType
@clerk/expoMinor

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

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

@vercel

vercelBot commented Jun 19, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJun 19, 2026 9:42am
swingsetReadyReadyPreview, CommentJun 19, 2026 9:42am

Request Review

@coderabbitai

coderabbitaiBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f46b3e8a-ee41-4167-8d6d-9d6271d22c1e

📥 Commits

Reviewing files that changed from the base of the PR and between ee5f933 and ea697ef.

📒 Files selected for processing (1)
  • .changeset/tidy-expo-ios-import.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-expo-ios-import.md

📝 Walkthrough

Walkthrough

The Clerk iOS SDK is now linked via React Native's native SPM podspec support rather than manual Expo config plugin injection. ClerkExpo.podspec declares the SPM dependency and expands its source file list. ClerkNativeBridge is refactored to a static observer/emitter pattern reading the SDK version from Info.plist. app.plugin.js is reduced to setting only the deployment target and writing ClerkExpoVersion to Info.plist.

Changes

iOS SPM Podspec Integration

Layer / File(s)Summary
Podspec SPM dependency declaration and source files
packages/expo/ios/ClerkExpo.podspec, packages/expo/package.json
Podspec pins clerk_ios_version to 1.2.4, adds a conditional SPM block for ClerkKit/ClerkKitUI, expands s.source_files to cover all native bridge and view manager files, and raises the react-native peer dependency minimum to >=0.75.
ClerkNativeBridge static observer/emitter refactor and Info.plist version
packages/expo/ios/ClerkNativeBridge.swift
ClerkExpoHeaderMiddleware reads hostSdkVersion from Bundle.main Info.plist key ClerkExpoVersion at runtime instead of a build-time placeholder. configure gains an early loadThemes() call. Readiness and client-change plumbing is replaced with new static addReadyObserver/removeReadyObserver/emitReady and setClientChangedEmitter/emitClientChanged methods. Reconfigure path now posts a notification instead of emitting bridge-ready events.
ClerkExpoModule decoupled from optional bridge instance
packages/expo/ios/ClerkExpoModule.swift
Removes all top-level bridge protocol, event enum, observer registry, and global bridge variable declarations. Initializer registers a client-changed emitter via ClerkNativeBridge.setClientChangedEmitter. configure, getClientToken, and syncFromJsClientToken call ClerkNativeBridge.shared directly instead of guarding on an optional instance. The free function emitClerkNativeClientChanged is removed.
Native views switched to ClerkNativeBridge.shared singleton
packages/expo/ios/ClerkNativeViewHost.swift, packages/expo/ios/ClerkAuthNativeView.swift, packages/expo/ios/ClerkUserButtonNativeView.swift, packages/expo/ios/ClerkUserProfileNativeView.swift
ClerkNativeViewHost removes ClerkNativeBridgeReadyObserver conformance and switches to NotificationCenter observation of .clerkNativeSDKDidConfigure, adding explicit observer removal on window detach and in deinit. The three native view controllers replace guarded optional bridge lookups with direct ClerkNativeBridge.shared calls.
app.plugin.js simplification and changeset
packages/expo/app.plugin.js, .changeset/tidy-expo-ios-import.md
Removes all SPM injection, bridge file copying, AppDelegate method injection, and Podfile post-install hook logic from app.plugin.js, leaving only a deployment target update and an Info.plistClerkExpoVersion write. Documentation is updated to reflect the simplified setup. A patch changeset documents the iOS build fix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • clerk/javascript#8883: Replaces the __CLERK_EXPO_VERSION__ placeholder injection and ClerkExpoHeaderMiddleware request header wiring that this PR refactors to use Info.plist-driven runtime version reading.
  • clerk/javascript#8867: Pins clerk-ios to 1.2.4 in iOS integration, matching the version now declared via clerk_ios_version in the podspec.
  • clerk/javascript#8920: Modifies ClerkNativeBridge.swift in the configure/readiness signaling path, directly overlapping with this PR's refactoring of emitReady and loadThemes call placement.

Suggested reviewers

  • wobsoriano

Poem

🐇 No more Podfile hooks to fear,
The SPM lives in the podspec near!
Info.plist holds the version now,
The singleton bridge takes a bow.
Less plugin code, cleaner deploy —
This bunny hops with iOS joy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 17.24% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately summarizes the main change: moving iOS SDK linking from app-target configuration to podspec SPM dependencies.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@pkg-pr-new

pkg-pr-newBot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8927

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8927

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8927

@clerk/upgrade

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

@clerk/vue

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

commit: ea697ef

@github-actions

github-actionsBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-19T09:43:45.347Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on ea697ef.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/expo/ios/ClerkExpo.podspec (1)

20-21: 💤 Low value

Consider externalizing the Clerk iOS SDK version.

The clerk_ios_version = '1.2.4' is hardcoded in the podspec. Every Clerk iOS SDK update will require manually editing this file. Consider whether the version could be read from package.json or another configuration source to reduce maintenance overhead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/expo/ios/ClerkExpo.podspec` around lines 20 - 21, The
clerk_ios_version variable is hardcoded as '1.2.4' in the podspec file,
requiring manual updates whenever the Clerk iOS SDK version changes. Externalize
this version by reading it from package.json or another centralized
configuration source instead of hardcoding it. Modify the clerk_ios_version
assignment to dynamically fetch the version from the appropriate configuration
file, reducing maintenance overhead and keeping the dependency version
synchronized across your project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/expo/ios/ClerkExpoBridge.swift`:
- Around line 36-58: The clerkNativeBridgeReadyObservers hash table is accessed
without synchronization in the methods addClerkNativeBridgeReadyObserver,
removeClerkNativeBridgeReadyObserver, and emitClerkNativeBridgeReady, and
similarly clerkNativeClientChangedEmitter is accessed in
setClerkNativeClientChangedEmitter and emitClerkNativeClientChanged without
synchronization. Since NSHashTable is not thread-safe, concurrent calls from
different threads can corrupt the data structure or cause crashes. Create a
private serial DispatchQueue and wrap all accesses to both
clerkNativeBridgeReadyObservers and clerkNativeClientChangedEmitter within
synchronized blocks using this queue, ensuring all read and write operations are
serialized and thread-safe.
---
Nitpick comments:
In `@packages/expo/ios/ClerkExpo.podspec`:
- Around line 20-21: The clerk_ios_version variable is hardcoded as '1.2.4' in
the podspec file, requiring manual updates whenever the Clerk iOS SDK version
changes. Externalize this version by reading it from package.json or another
centralized configuration source instead of hardcoding it. Modify the
clerk_ios_version assignment to dynamically fetch the version from the
appropriate configuration file, reducing maintenance overhead and keeping the
dependency version synchronized across your project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cfed06c-5d52-4b43-bbe1-7a2655f71514

📥 Commits

Reviewing files that changed from the base of the PR and between 88525a6 and 5faa0bc.

📒 Files selected for processing (8)
  • .changeset/tidy-expo-ios-import.md
  • packages/expo/app.plugin.js
  • packages/expo/ios/ClerkExpo.podspec
  • packages/expo/ios/ClerkExpoBridge.swift
  • packages/expo/ios/ClerkExpoModule.swift
  • packages/expo/ios/ClerkNativeBridge.swift
  • packages/expo/package.json
  • packages/expo/src/__tests__/appPlugin.injectClerkExpoVersion.test.js
💤 Files with no reviewable changes (1)
  • packages/expo/src/tests/appPlugin.injectClerkExpoVersion.test.js

Comment threadpackages/expo/ios/ClerkExpoBridge.swift Outdated

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:f7088d0604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/expo/app.plugin.js

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:83e37e979b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

products: ['ClerkKit', 'ClerkKitUI']
)
else
raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep RN 0.73/0.74 pod installs working

For apps still on React Native 0.73/0.74 (which satisfied @clerk/expo's previous peer range and can receive this patch via a caret range), spm_dependency is not defined by RN's CocoaPods scripts, so this raise makes every iOS pod install fail even though those apps built with the old Xcode-project injection path. Because this is being released as a patch, please keep a fallback for those RN versions or avoid shipping this path to them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Our supported expo range is >=53, so supporting 0.73 and 0.74 is already a mismatch. Expo 53 contains React Native 0.79

@wobsorianowobsoriano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested this locally in both Expo SDK 54 and 56. Runs successfully ✅

@wobsoriano
wobsoriano merged commit bfe280a into mainJun 19, 2026
49 checks passed
@wobsoriano
wobsoriano deleted the mike/fix-expo-ios-spm-podspec-linking branch June 19, 2026 10:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mikepitre@wobsoriano
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(expo): link iOS SDK through podspec SPM dependencies by mikepitre · Pull Request #8927 · clerk/javascript · GitHub
Skip to content

fix(expo): link iOS SDK through podspec SPM dependencies - #8927

Merged
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking
Jun 19, 2026
Merged

fix(expo): link iOS SDK through podspec SPM dependencies#8927
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking

Conversation

@mikepitre

@mikepitremikepitre commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Link clerk-ios from ClerkExpo.podspec using React Native's spm_dependency, so the ClerkExpo pod target can import ClerkKit and ClerkKitUI directly.
  • Remove the config plugin's app-target SPM/project mutation and copied native bridge injection.
  • Remove the old optional native bridge facade now that the Clerk iOS SDK is available inside the ClerkExpo pod target; module and view wrappers call ClerkNativeBridge.shared directly.
  • Bump the @clerk/expo React Native peer dependency from >=0.73 to >=0.75, since this fix relies on React Native's podspec Swift Package Manager dependency support.

Motivation

Expo SDK 54 generates import ClerkExpo for Expo modules while SDK 56 generates internal import ClerkExpo. The import form is not the real problem; the issue was that ClerkExpo depended on ClerkKit/ClerkKitUI through app-target project mutation instead of declaring the Swift package dependency on the pod target that actually imports those modules.

Moving the SPM dependency into the podspec keeps the dependency attached to the correct native target and avoids having to special-case Expo's generated import style.

Because the Clerk iOS SDK is now visible to the pod target, the separate ClerkExpoBridge.swift protocol/global registry layer is no longer needed. The remaining readiness and native-client-change coordination lives on ClerkNativeBridge.

Verification

  • git diff --check
  • pnpm --filter @clerk/expo test
  • Fresh Expo SDK 54 and SDK 56 apps installed @clerk/expo from a packed tarball
  • npx expo prebuild --clean --platform ios passed for both apps
  • Clean Release simulator builds passed for both apps, fetching clerk-ios1.2.4 through SPM
  • Installed and launched both apps on the iOS simulator; verified AuthView, UserButton, JS sign-in, and JS sign-out

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved iOS development-build compatibility across Expo SDK versions with more reliable native SDK linking and configuration.
    • Refined native-to-JS client-change updates to stay consistent after app reconfiguration and theme loading.
  • Chores

    • Simplified iOS setup by reading the host SDK version from app metadata and using it when communicating with the native layer.
  • Tests

    • Removed an obsolete iOS version injection test.
  • Compatibility

    • Raised the minimum supported React Native version to 0.75+.

@changeset-bot

changeset-botBot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ea697ef

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

This PR includes changesets to release 1 package
NameType
@clerk/expoMinor

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

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

@vercel

vercelBot commented Jun 19, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJun 19, 2026 9:42am
swingsetReadyReadyPreview, CommentJun 19, 2026 9:42am

Request Review

@coderabbitai

coderabbitaiBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f46b3e8a-ee41-4167-8d6d-9d6271d22c1e

📥 Commits

Reviewing files that changed from the base of the PR and between ee5f933 and ea697ef.

📒 Files selected for processing (1)
  • .changeset/tidy-expo-ios-import.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-expo-ios-import.md

📝 Walkthrough

Walkthrough

The Clerk iOS SDK is now linked via React Native's native SPM podspec support rather than manual Expo config plugin injection. ClerkExpo.podspec declares the SPM dependency and expands its source file list. ClerkNativeBridge is refactored to a static observer/emitter pattern reading the SDK version from Info.plist. app.plugin.js is reduced to setting only the deployment target and writing ClerkExpoVersion to Info.plist.

Changes

iOS SPM Podspec Integration

Layer / File(s)Summary
Podspec SPM dependency declaration and source files
packages/expo/ios/ClerkExpo.podspec, packages/expo/package.json
Podspec pins clerk_ios_version to 1.2.4, adds a conditional SPM block for ClerkKit/ClerkKitUI, expands s.source_files to cover all native bridge and view manager files, and raises the react-native peer dependency minimum to >=0.75.
ClerkNativeBridge static observer/emitter refactor and Info.plist version
packages/expo/ios/ClerkNativeBridge.swift
ClerkExpoHeaderMiddleware reads hostSdkVersion from Bundle.main Info.plist key ClerkExpoVersion at runtime instead of a build-time placeholder. configure gains an early loadThemes() call. Readiness and client-change plumbing is replaced with new static addReadyObserver/removeReadyObserver/emitReady and setClientChangedEmitter/emitClientChanged methods. Reconfigure path now posts a notification instead of emitting bridge-ready events.
ClerkExpoModule decoupled from optional bridge instance
packages/expo/ios/ClerkExpoModule.swift
Removes all top-level bridge protocol, event enum, observer registry, and global bridge variable declarations. Initializer registers a client-changed emitter via ClerkNativeBridge.setClientChangedEmitter. configure, getClientToken, and syncFromJsClientToken call ClerkNativeBridge.shared directly instead of guarding on an optional instance. The free function emitClerkNativeClientChanged is removed.
Native views switched to ClerkNativeBridge.shared singleton
packages/expo/ios/ClerkNativeViewHost.swift, packages/expo/ios/ClerkAuthNativeView.swift, packages/expo/ios/ClerkUserButtonNativeView.swift, packages/expo/ios/ClerkUserProfileNativeView.swift
ClerkNativeViewHost removes ClerkNativeBridgeReadyObserver conformance and switches to NotificationCenter observation of .clerkNativeSDKDidConfigure, adding explicit observer removal on window detach and in deinit. The three native view controllers replace guarded optional bridge lookups with direct ClerkNativeBridge.shared calls.
app.plugin.js simplification and changeset
packages/expo/app.plugin.js, .changeset/tidy-expo-ios-import.md
Removes all SPM injection, bridge file copying, AppDelegate method injection, and Podfile post-install hook logic from app.plugin.js, leaving only a deployment target update and an Info.plistClerkExpoVersion write. Documentation is updated to reflect the simplified setup. A patch changeset documents the iOS build fix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • clerk/javascript#8883: Replaces the __CLERK_EXPO_VERSION__ placeholder injection and ClerkExpoHeaderMiddleware request header wiring that this PR refactors to use Info.plist-driven runtime version reading.
  • clerk/javascript#8867: Pins clerk-ios to 1.2.4 in iOS integration, matching the version now declared via clerk_ios_version in the podspec.
  • clerk/javascript#8920: Modifies ClerkNativeBridge.swift in the configure/readiness signaling path, directly overlapping with this PR's refactoring of emitReady and loadThemes call placement.

Suggested reviewers

  • wobsoriano

Poem

🐇 No more Podfile hooks to fear,
The SPM lives in the podspec near!
Info.plist holds the version now,
The singleton bridge takes a bow.
Less plugin code, cleaner deploy —
This bunny hops with iOS joy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 17.24% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately summarizes the main change: moving iOS SDK linking from app-target configuration to podspec SPM dependencies.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@pkg-pr-new

pkg-pr-newBot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8927

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8927

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8927

@clerk/upgrade

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

@clerk/vue

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

commit: ea697ef

@github-actions

github-actionsBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-19T09:43:45.347Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on ea697ef.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/expo/ios/ClerkExpo.podspec (1)

20-21: 💤 Low value

Consider externalizing the Clerk iOS SDK version.

The clerk_ios_version = '1.2.4' is hardcoded in the podspec. Every Clerk iOS SDK update will require manually editing this file. Consider whether the version could be read from package.json or another configuration source to reduce maintenance overhead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/expo/ios/ClerkExpo.podspec` around lines 20 - 21, The
clerk_ios_version variable is hardcoded as '1.2.4' in the podspec file,
requiring manual updates whenever the Clerk iOS SDK version changes. Externalize
this version by reading it from package.json or another centralized
configuration source instead of hardcoding it. Modify the clerk_ios_version
assignment to dynamically fetch the version from the appropriate configuration
file, reducing maintenance overhead and keeping the dependency version
synchronized across your project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/expo/ios/ClerkExpoBridge.swift`:
- Around line 36-58: The clerkNativeBridgeReadyObservers hash table is accessed
without synchronization in the methods addClerkNativeBridgeReadyObserver,
removeClerkNativeBridgeReadyObserver, and emitClerkNativeBridgeReady, and
similarly clerkNativeClientChangedEmitter is accessed in
setClerkNativeClientChangedEmitter and emitClerkNativeClientChanged without
synchronization. Since NSHashTable is not thread-safe, concurrent calls from
different threads can corrupt the data structure or cause crashes. Create a
private serial DispatchQueue and wrap all accesses to both
clerkNativeBridgeReadyObservers and clerkNativeClientChangedEmitter within
synchronized blocks using this queue, ensuring all read and write operations are
serialized and thread-safe.
---
Nitpick comments:
In `@packages/expo/ios/ClerkExpo.podspec`:
- Around line 20-21: The clerk_ios_version variable is hardcoded as '1.2.4' in
the podspec file, requiring manual updates whenever the Clerk iOS SDK version
changes. Externalize this version by reading it from package.json or another
centralized configuration source instead of hardcoding it. Modify the
clerk_ios_version assignment to dynamically fetch the version from the
appropriate configuration file, reducing maintenance overhead and keeping the
dependency version synchronized across your project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cfed06c-5d52-4b43-bbe1-7a2655f71514

📥 Commits

Reviewing files that changed from the base of the PR and between 88525a6 and 5faa0bc.

📒 Files selected for processing (8)
  • .changeset/tidy-expo-ios-import.md
  • packages/expo/app.plugin.js
  • packages/expo/ios/ClerkExpo.podspec
  • packages/expo/ios/ClerkExpoBridge.swift
  • packages/expo/ios/ClerkExpoModule.swift
  • packages/expo/ios/ClerkNativeBridge.swift
  • packages/expo/package.json
  • packages/expo/src/__tests__/appPlugin.injectClerkExpoVersion.test.js
💤 Files with no reviewable changes (1)
  • packages/expo/src/tests/appPlugin.injectClerkExpoVersion.test.js

Comment threadpackages/expo/ios/ClerkExpoBridge.swift Outdated

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:f7088d0604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/expo/app.plugin.js

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:83e37e979b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

products: ['ClerkKit', 'ClerkKitUI']
)
else
raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep RN 0.73/0.74 pod installs working

For apps still on React Native 0.73/0.74 (which satisfied @clerk/expo's previous peer range and can receive this patch via a caret range), spm_dependency is not defined by RN's CocoaPods scripts, so this raise makes every iOS pod install fail even though those apps built with the old Xcode-project injection path. Because this is being released as a patch, please keep a fallback for those RN versions or avoid shipping this path to them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Our supported expo range is >=53, so supporting 0.73 and 0.74 is already a mismatch. Expo 53 contains React Native 0.79

@wobsorianowobsoriano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested this locally in both Expo SDK 54 and 56. Runs successfully ✅

@wobsoriano
wobsoriano merged commit bfe280a into mainJun 19, 2026
49 checks passed
@wobsoriano
wobsoriano deleted the mike/fix-expo-ios-spm-podspec-linking branch June 19, 2026 10:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mikepitre@wobsoriano
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' fix(expo): link iOS SDK through podspec SPM dependencies by mikepitre · Pull Request #8927 · clerk/javascript · GitHub
Skip to content

fix(expo): link iOS SDK through podspec SPM dependencies - #8927

Merged
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking
Jun 19, 2026
Merged

fix(expo): link iOS SDK through podspec SPM dependencies#8927
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking

Conversation

@mikepitre

@mikepitremikepitre commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Link clerk-ios from ClerkExpo.podspec using React Native's spm_dependency, so the ClerkExpo pod target can import ClerkKit and ClerkKitUI directly.
  • Remove the config plugin's app-target SPM/project mutation and copied native bridge injection.
  • Remove the old optional native bridge facade now that the Clerk iOS SDK is available inside the ClerkExpo pod target; module and view wrappers call ClerkNativeBridge.shared directly.
  • Bump the @clerk/expo React Native peer dependency from >=0.73 to >=0.75, since this fix relies on React Native's podspec Swift Package Manager dependency support.

Motivation

Expo SDK 54 generates import ClerkExpo for Expo modules while SDK 56 generates internal import ClerkExpo. The import form is not the real problem; the issue was that ClerkExpo depended on ClerkKit/ClerkKitUI through app-target project mutation instead of declaring the Swift package dependency on the pod target that actually imports those modules.

Moving the SPM dependency into the podspec keeps the dependency attached to the correct native target and avoids having to special-case Expo's generated import style.

Because the Clerk iOS SDK is now visible to the pod target, the separate ClerkExpoBridge.swift protocol/global registry layer is no longer needed. The remaining readiness and native-client-change coordination lives on ClerkNativeBridge.

Verification

  • git diff --check
  • pnpm --filter @clerk/expo test
  • Fresh Expo SDK 54 and SDK 56 apps installed @clerk/expo from a packed tarball
  • npx expo prebuild --clean --platform ios passed for both apps
  • Clean Release simulator builds passed for both apps, fetching clerk-ios1.2.4 through SPM
  • Installed and launched both apps on the iOS simulator; verified AuthView, UserButton, JS sign-in, and JS sign-out

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved iOS development-build compatibility across Expo SDK versions with more reliable native SDK linking and configuration.
    • Refined native-to-JS client-change updates to stay consistent after app reconfiguration and theme loading.
  • Chores

    • Simplified iOS setup by reading the host SDK version from app metadata and using it when communicating with the native layer.
  • Tests

    • Removed an obsolete iOS version injection test.
  • Compatibility

    • Raised the minimum supported React Native version to 0.75+.

@changeset-bot

changeset-botBot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ea697ef

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

This PR includes changesets to release 1 package
NameType
@clerk/expoMinor

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

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

@vercel

vercelBot commented Jun 19, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJun 19, 2026 9:42am
swingsetReadyReadyPreview, CommentJun 19, 2026 9:42am

Request Review

@coderabbitai

coderabbitaiBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f46b3e8a-ee41-4167-8d6d-9d6271d22c1e

📥 Commits

Reviewing files that changed from the base of the PR and between ee5f933 and ea697ef.

📒 Files selected for processing (1)
  • .changeset/tidy-expo-ios-import.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-expo-ios-import.md

📝 Walkthrough

Walkthrough

The Clerk iOS SDK is now linked via React Native's native SPM podspec support rather than manual Expo config plugin injection. ClerkExpo.podspec declares the SPM dependency and expands its source file list. ClerkNativeBridge is refactored to a static observer/emitter pattern reading the SDK version from Info.plist. app.plugin.js is reduced to setting only the deployment target and writing ClerkExpoVersion to Info.plist.

Changes

iOS SPM Podspec Integration

Layer / File(s)Summary
Podspec SPM dependency declaration and source files
packages/expo/ios/ClerkExpo.podspec, packages/expo/package.json
Podspec pins clerk_ios_version to 1.2.4, adds a conditional SPM block for ClerkKit/ClerkKitUI, expands s.source_files to cover all native bridge and view manager files, and raises the react-native peer dependency minimum to >=0.75.
ClerkNativeBridge static observer/emitter refactor and Info.plist version
packages/expo/ios/ClerkNativeBridge.swift
ClerkExpoHeaderMiddleware reads hostSdkVersion from Bundle.main Info.plist key ClerkExpoVersion at runtime instead of a build-time placeholder. configure gains an early loadThemes() call. Readiness and client-change plumbing is replaced with new static addReadyObserver/removeReadyObserver/emitReady and setClientChangedEmitter/emitClientChanged methods. Reconfigure path now posts a notification instead of emitting bridge-ready events.
ClerkExpoModule decoupled from optional bridge instance
packages/expo/ios/ClerkExpoModule.swift
Removes all top-level bridge protocol, event enum, observer registry, and global bridge variable declarations. Initializer registers a client-changed emitter via ClerkNativeBridge.setClientChangedEmitter. configure, getClientToken, and syncFromJsClientToken call ClerkNativeBridge.shared directly instead of guarding on an optional instance. The free function emitClerkNativeClientChanged is removed.
Native views switched to ClerkNativeBridge.shared singleton
packages/expo/ios/ClerkNativeViewHost.swift, packages/expo/ios/ClerkAuthNativeView.swift, packages/expo/ios/ClerkUserButtonNativeView.swift, packages/expo/ios/ClerkUserProfileNativeView.swift
ClerkNativeViewHost removes ClerkNativeBridgeReadyObserver conformance and switches to NotificationCenter observation of .clerkNativeSDKDidConfigure, adding explicit observer removal on window detach and in deinit. The three native view controllers replace guarded optional bridge lookups with direct ClerkNativeBridge.shared calls.
app.plugin.js simplification and changeset
packages/expo/app.plugin.js, .changeset/tidy-expo-ios-import.md
Removes all SPM injection, bridge file copying, AppDelegate method injection, and Podfile post-install hook logic from app.plugin.js, leaving only a deployment target update and an Info.plistClerkExpoVersion write. Documentation is updated to reflect the simplified setup. A patch changeset documents the iOS build fix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • clerk/javascript#8883: Replaces the __CLERK_EXPO_VERSION__ placeholder injection and ClerkExpoHeaderMiddleware request header wiring that this PR refactors to use Info.plist-driven runtime version reading.
  • clerk/javascript#8867: Pins clerk-ios to 1.2.4 in iOS integration, matching the version now declared via clerk_ios_version in the podspec.
  • clerk/javascript#8920: Modifies ClerkNativeBridge.swift in the configure/readiness signaling path, directly overlapping with this PR's refactoring of emitReady and loadThemes call placement.

Suggested reviewers

  • wobsoriano

Poem

🐇 No more Podfile hooks to fear,
The SPM lives in the podspec near!
Info.plist holds the version now,
The singleton bridge takes a bow.
Less plugin code, cleaner deploy —
This bunny hops with iOS joy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 17.24% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately summarizes the main change: moving iOS SDK linking from app-target configuration to podspec SPM dependencies.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@pkg-pr-new

pkg-pr-newBot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8927

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8927

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8927

@clerk/upgrade

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

@clerk/vue

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

commit: ea697ef

@github-actions

github-actionsBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-19T09:43:45.347Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on ea697ef.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/expo/ios/ClerkExpo.podspec (1)

20-21: 💤 Low value

Consider externalizing the Clerk iOS SDK version.

The clerk_ios_version = '1.2.4' is hardcoded in the podspec. Every Clerk iOS SDK update will require manually editing this file. Consider whether the version could be read from package.json or another configuration source to reduce maintenance overhead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/expo/ios/ClerkExpo.podspec` around lines 20 - 21, The
clerk_ios_version variable is hardcoded as '1.2.4' in the podspec file,
requiring manual updates whenever the Clerk iOS SDK version changes. Externalize
this version by reading it from package.json or another centralized
configuration source instead of hardcoding it. Modify the clerk_ios_version
assignment to dynamically fetch the version from the appropriate configuration
file, reducing maintenance overhead and keeping the dependency version
synchronized across your project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/expo/ios/ClerkExpoBridge.swift`:
- Around line 36-58: The clerkNativeBridgeReadyObservers hash table is accessed
without synchronization in the methods addClerkNativeBridgeReadyObserver,
removeClerkNativeBridgeReadyObserver, and emitClerkNativeBridgeReady, and
similarly clerkNativeClientChangedEmitter is accessed in
setClerkNativeClientChangedEmitter and emitClerkNativeClientChanged without
synchronization. Since NSHashTable is not thread-safe, concurrent calls from
different threads can corrupt the data structure or cause crashes. Create a
private serial DispatchQueue and wrap all accesses to both
clerkNativeBridgeReadyObservers and clerkNativeClientChangedEmitter within
synchronized blocks using this queue, ensuring all read and write operations are
serialized and thread-safe.
---
Nitpick comments:
In `@packages/expo/ios/ClerkExpo.podspec`:
- Around line 20-21: The clerk_ios_version variable is hardcoded as '1.2.4' in
the podspec file, requiring manual updates whenever the Clerk iOS SDK version
changes. Externalize this version by reading it from package.json or another
centralized configuration source instead of hardcoding it. Modify the
clerk_ios_version assignment to dynamically fetch the version from the
appropriate configuration file, reducing maintenance overhead and keeping the
dependency version synchronized across your project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cfed06c-5d52-4b43-bbe1-7a2655f71514

📥 Commits

Reviewing files that changed from the base of the PR and between 88525a6 and 5faa0bc.

📒 Files selected for processing (8)
  • .changeset/tidy-expo-ios-import.md
  • packages/expo/app.plugin.js
  • packages/expo/ios/ClerkExpo.podspec
  • packages/expo/ios/ClerkExpoBridge.swift
  • packages/expo/ios/ClerkExpoModule.swift
  • packages/expo/ios/ClerkNativeBridge.swift
  • packages/expo/package.json
  • packages/expo/src/__tests__/appPlugin.injectClerkExpoVersion.test.js
💤 Files with no reviewable changes (1)
  • packages/expo/src/tests/appPlugin.injectClerkExpoVersion.test.js

Comment threadpackages/expo/ios/ClerkExpoBridge.swift Outdated

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:f7088d0604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/expo/app.plugin.js

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:83e37e979b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

products: ['ClerkKit', 'ClerkKitUI']
)
else
raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep RN 0.73/0.74 pod installs working

For apps still on React Native 0.73/0.74 (which satisfied @clerk/expo's previous peer range and can receive this patch via a caret range), spm_dependency is not defined by RN's CocoaPods scripts, so this raise makes every iOS pod install fail even though those apps built with the old Xcode-project injection path. Because this is being released as a patch, please keep a fallback for those RN versions or avoid shipping this path to them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Our supported expo range is >=53, so supporting 0.73 and 0.74 is already a mismatch. Expo 53 contains React Native 0.79

@wobsorianowobsoriano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested this locally in both Expo SDK 54 and 56. Runs successfully ✅

@wobsoriano
wobsoriano merged commit bfe280a into mainJun 19, 2026
49 checks passed
@wobsoriano
wobsoriano deleted the mike/fix-expo-ios-spm-podspec-linking branch June 19, 2026 10:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mikepitre@wobsoriano
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(expo): link iOS SDK through podspec SPM dependencies by mikepitre · Pull Request #8927 · clerk/javascript · GitHub
Skip to content

fix(expo): link iOS SDK through podspec SPM dependencies - #8927

Merged
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking
Jun 19, 2026
Merged

fix(expo): link iOS SDK through podspec SPM dependencies#8927
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking

Conversation

@mikepitre

@mikepitremikepitre commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Link clerk-ios from ClerkExpo.podspec using React Native's spm_dependency, so the ClerkExpo pod target can import ClerkKit and ClerkKitUI directly.
  • Remove the config plugin's app-target SPM/project mutation and copied native bridge injection.
  • Remove the old optional native bridge facade now that the Clerk iOS SDK is available inside the ClerkExpo pod target; module and view wrappers call ClerkNativeBridge.shared directly.
  • Bump the @clerk/expo React Native peer dependency from >=0.73 to >=0.75, since this fix relies on React Native's podspec Swift Package Manager dependency support.

Motivation

Expo SDK 54 generates import ClerkExpo for Expo modules while SDK 56 generates internal import ClerkExpo. The import form is not the real problem; the issue was that ClerkExpo depended on ClerkKit/ClerkKitUI through app-target project mutation instead of declaring the Swift package dependency on the pod target that actually imports those modules.

Moving the SPM dependency into the podspec keeps the dependency attached to the correct native target and avoids having to special-case Expo's generated import style.

Because the Clerk iOS SDK is now visible to the pod target, the separate ClerkExpoBridge.swift protocol/global registry layer is no longer needed. The remaining readiness and native-client-change coordination lives on ClerkNativeBridge.

Verification

  • git diff --check
  • pnpm --filter @clerk/expo test
  • Fresh Expo SDK 54 and SDK 56 apps installed @clerk/expo from a packed tarball
  • npx expo prebuild --clean --platform ios passed for both apps
  • Clean Release simulator builds passed for both apps, fetching clerk-ios1.2.4 through SPM
  • Installed and launched both apps on the iOS simulator; verified AuthView, UserButton, JS sign-in, and JS sign-out

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved iOS development-build compatibility across Expo SDK versions with more reliable native SDK linking and configuration.
    • Refined native-to-JS client-change updates to stay consistent after app reconfiguration and theme loading.
  • Chores

    • Simplified iOS setup by reading the host SDK version from app metadata and using it when communicating with the native layer.
  • Tests

    • Removed an obsolete iOS version injection test.
  • Compatibility

    • Raised the minimum supported React Native version to 0.75+.

@changeset-bot

changeset-botBot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ea697ef

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

This PR includes changesets to release 1 package
NameType
@clerk/expoMinor

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

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

@vercel

vercelBot commented Jun 19, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJun 19, 2026 9:42am
swingsetReadyReadyPreview, CommentJun 19, 2026 9:42am

Request Review

@coderabbitai

coderabbitaiBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f46b3e8a-ee41-4167-8d6d-9d6271d22c1e

📥 Commits

Reviewing files that changed from the base of the PR and between ee5f933 and ea697ef.

📒 Files selected for processing (1)
  • .changeset/tidy-expo-ios-import.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-expo-ios-import.md

📝 Walkthrough

Walkthrough

The Clerk iOS SDK is now linked via React Native's native SPM podspec support rather than manual Expo config plugin injection. ClerkExpo.podspec declares the SPM dependency and expands its source file list. ClerkNativeBridge is refactored to a static observer/emitter pattern reading the SDK version from Info.plist. app.plugin.js is reduced to setting only the deployment target and writing ClerkExpoVersion to Info.plist.

Changes

iOS SPM Podspec Integration

Layer / File(s)Summary
Podspec SPM dependency declaration and source files
packages/expo/ios/ClerkExpo.podspec, packages/expo/package.json
Podspec pins clerk_ios_version to 1.2.4, adds a conditional SPM block for ClerkKit/ClerkKitUI, expands s.source_files to cover all native bridge and view manager files, and raises the react-native peer dependency minimum to >=0.75.
ClerkNativeBridge static observer/emitter refactor and Info.plist version
packages/expo/ios/ClerkNativeBridge.swift
ClerkExpoHeaderMiddleware reads hostSdkVersion from Bundle.main Info.plist key ClerkExpoVersion at runtime instead of a build-time placeholder. configure gains an early loadThemes() call. Readiness and client-change plumbing is replaced with new static addReadyObserver/removeReadyObserver/emitReady and setClientChangedEmitter/emitClientChanged methods. Reconfigure path now posts a notification instead of emitting bridge-ready events.
ClerkExpoModule decoupled from optional bridge instance
packages/expo/ios/ClerkExpoModule.swift
Removes all top-level bridge protocol, event enum, observer registry, and global bridge variable declarations. Initializer registers a client-changed emitter via ClerkNativeBridge.setClientChangedEmitter. configure, getClientToken, and syncFromJsClientToken call ClerkNativeBridge.shared directly instead of guarding on an optional instance. The free function emitClerkNativeClientChanged is removed.
Native views switched to ClerkNativeBridge.shared singleton
packages/expo/ios/ClerkNativeViewHost.swift, packages/expo/ios/ClerkAuthNativeView.swift, packages/expo/ios/ClerkUserButtonNativeView.swift, packages/expo/ios/ClerkUserProfileNativeView.swift
ClerkNativeViewHost removes ClerkNativeBridgeReadyObserver conformance and switches to NotificationCenter observation of .clerkNativeSDKDidConfigure, adding explicit observer removal on window detach and in deinit. The three native view controllers replace guarded optional bridge lookups with direct ClerkNativeBridge.shared calls.
app.plugin.js simplification and changeset
packages/expo/app.plugin.js, .changeset/tidy-expo-ios-import.md
Removes all SPM injection, bridge file copying, AppDelegate method injection, and Podfile post-install hook logic from app.plugin.js, leaving only a deployment target update and an Info.plistClerkExpoVersion write. Documentation is updated to reflect the simplified setup. A patch changeset documents the iOS build fix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • clerk/javascript#8883: Replaces the __CLERK_EXPO_VERSION__ placeholder injection and ClerkExpoHeaderMiddleware request header wiring that this PR refactors to use Info.plist-driven runtime version reading.
  • clerk/javascript#8867: Pins clerk-ios to 1.2.4 in iOS integration, matching the version now declared via clerk_ios_version in the podspec.
  • clerk/javascript#8920: Modifies ClerkNativeBridge.swift in the configure/readiness signaling path, directly overlapping with this PR's refactoring of emitReady and loadThemes call placement.

Suggested reviewers

  • wobsoriano

Poem

🐇 No more Podfile hooks to fear,
The SPM lives in the podspec near!
Info.plist holds the version now,
The singleton bridge takes a bow.
Less plugin code, cleaner deploy —
This bunny hops with iOS joy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 17.24% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately summarizes the main change: moving iOS SDK linking from app-target configuration to podspec SPM dependencies.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@pkg-pr-new

pkg-pr-newBot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8927

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8927

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8927

@clerk/upgrade

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

@clerk/vue

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

commit: ea697ef

@github-actions

github-actionsBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-19T09:43:45.347Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on ea697ef.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/expo/ios/ClerkExpo.podspec (1)

20-21: 💤 Low value

Consider externalizing the Clerk iOS SDK version.

The clerk_ios_version = '1.2.4' is hardcoded in the podspec. Every Clerk iOS SDK update will require manually editing this file. Consider whether the version could be read from package.json or another configuration source to reduce maintenance overhead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/expo/ios/ClerkExpo.podspec` around lines 20 - 21, The
clerk_ios_version variable is hardcoded as '1.2.4' in the podspec file,
requiring manual updates whenever the Clerk iOS SDK version changes. Externalize
this version by reading it from package.json or another centralized
configuration source instead of hardcoding it. Modify the clerk_ios_version
assignment to dynamically fetch the version from the appropriate configuration
file, reducing maintenance overhead and keeping the dependency version
synchronized across your project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/expo/ios/ClerkExpoBridge.swift`:
- Around line 36-58: The clerkNativeBridgeReadyObservers hash table is accessed
without synchronization in the methods addClerkNativeBridgeReadyObserver,
removeClerkNativeBridgeReadyObserver, and emitClerkNativeBridgeReady, and
similarly clerkNativeClientChangedEmitter is accessed in
setClerkNativeClientChangedEmitter and emitClerkNativeClientChanged without
synchronization. Since NSHashTable is not thread-safe, concurrent calls from
different threads can corrupt the data structure or cause crashes. Create a
private serial DispatchQueue and wrap all accesses to both
clerkNativeBridgeReadyObservers and clerkNativeClientChangedEmitter within
synchronized blocks using this queue, ensuring all read and write operations are
serialized and thread-safe.
---
Nitpick comments:
In `@packages/expo/ios/ClerkExpo.podspec`:
- Around line 20-21: The clerk_ios_version variable is hardcoded as '1.2.4' in
the podspec file, requiring manual updates whenever the Clerk iOS SDK version
changes. Externalize this version by reading it from package.json or another
centralized configuration source instead of hardcoding it. Modify the
clerk_ios_version assignment to dynamically fetch the version from the
appropriate configuration file, reducing maintenance overhead and keeping the
dependency version synchronized across your project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cfed06c-5d52-4b43-bbe1-7a2655f71514

📥 Commits

Reviewing files that changed from the base of the PR and between 88525a6 and 5faa0bc.

📒 Files selected for processing (8)
  • .changeset/tidy-expo-ios-import.md
  • packages/expo/app.plugin.js
  • packages/expo/ios/ClerkExpo.podspec
  • packages/expo/ios/ClerkExpoBridge.swift
  • packages/expo/ios/ClerkExpoModule.swift
  • packages/expo/ios/ClerkNativeBridge.swift
  • packages/expo/package.json
  • packages/expo/src/__tests__/appPlugin.injectClerkExpoVersion.test.js
💤 Files with no reviewable changes (1)
  • packages/expo/src/tests/appPlugin.injectClerkExpoVersion.test.js

Comment threadpackages/expo/ios/ClerkExpoBridge.swift Outdated

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:f7088d0604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/expo/app.plugin.js

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:83e37e979b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

products: ['ClerkKit', 'ClerkKitUI']
)
else
raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep RN 0.73/0.74 pod installs working

For apps still on React Native 0.73/0.74 (which satisfied @clerk/expo's previous peer range and can receive this patch via a caret range), spm_dependency is not defined by RN's CocoaPods scripts, so this raise makes every iOS pod install fail even though those apps built with the old Xcode-project injection path. Because this is being released as a patch, please keep a fallback for those RN versions or avoid shipping this path to them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Our supported expo range is >=53, so supporting 0.73 and 0.74 is already a mismatch. Expo 53 contains React Native 0.79

@wobsorianowobsoriano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested this locally in both Expo SDK 54 and 56. Runs successfully ✅

@wobsoriano
wobsoriano merged commit bfe280a into mainJun 19, 2026
49 checks passed
@wobsoriano
wobsoriano deleted the mike/fix-expo-ios-spm-podspec-linking branch June 19, 2026 10:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mikepitre@wobsoriano
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(expo): link iOS SDK through podspec SPM dependencies by mikepitre · Pull Request #8927 · clerk/javascript · GitHub
Skip to content

fix(expo): link iOS SDK through podspec SPM dependencies - #8927

Merged
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking
Jun 19, 2026
Merged

fix(expo): link iOS SDK through podspec SPM dependencies#8927
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking

Conversation

@mikepitre

@mikepitremikepitre commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Link clerk-ios from ClerkExpo.podspec using React Native's spm_dependency, so the ClerkExpo pod target can import ClerkKit and ClerkKitUI directly.
  • Remove the config plugin's app-target SPM/project mutation and copied native bridge injection.
  • Remove the old optional native bridge facade now that the Clerk iOS SDK is available inside the ClerkExpo pod target; module and view wrappers call ClerkNativeBridge.shared directly.
  • Bump the @clerk/expo React Native peer dependency from >=0.73 to >=0.75, since this fix relies on React Native's podspec Swift Package Manager dependency support.

Motivation

Expo SDK 54 generates import ClerkExpo for Expo modules while SDK 56 generates internal import ClerkExpo. The import form is not the real problem; the issue was that ClerkExpo depended on ClerkKit/ClerkKitUI through app-target project mutation instead of declaring the Swift package dependency on the pod target that actually imports those modules.

Moving the SPM dependency into the podspec keeps the dependency attached to the correct native target and avoids having to special-case Expo's generated import style.

Because the Clerk iOS SDK is now visible to the pod target, the separate ClerkExpoBridge.swift protocol/global registry layer is no longer needed. The remaining readiness and native-client-change coordination lives on ClerkNativeBridge.

Verification

  • git diff --check
  • pnpm --filter @clerk/expo test
  • Fresh Expo SDK 54 and SDK 56 apps installed @clerk/expo from a packed tarball
  • npx expo prebuild --clean --platform ios passed for both apps
  • Clean Release simulator builds passed for both apps, fetching clerk-ios1.2.4 through SPM
  • Installed and launched both apps on the iOS simulator; verified AuthView, UserButton, JS sign-in, and JS sign-out

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved iOS development-build compatibility across Expo SDK versions with more reliable native SDK linking and configuration.
    • Refined native-to-JS client-change updates to stay consistent after app reconfiguration and theme loading.
  • Chores

    • Simplified iOS setup by reading the host SDK version from app metadata and using it when communicating with the native layer.
  • Tests

    • Removed an obsolete iOS version injection test.
  • Compatibility

    • Raised the minimum supported React Native version to 0.75+.

@changeset-bot

changeset-botBot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ea697ef

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

This PR includes changesets to release 1 package
NameType
@clerk/expoMinor

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

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

@vercel

vercelBot commented Jun 19, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJun 19, 2026 9:42am
swingsetReadyReadyPreview, CommentJun 19, 2026 9:42am

Request Review

@coderabbitai

coderabbitaiBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f46b3e8a-ee41-4167-8d6d-9d6271d22c1e

📥 Commits

Reviewing files that changed from the base of the PR and between ee5f933 and ea697ef.

📒 Files selected for processing (1)
  • .changeset/tidy-expo-ios-import.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-expo-ios-import.md

📝 Walkthrough

Walkthrough

The Clerk iOS SDK is now linked via React Native's native SPM podspec support rather than manual Expo config plugin injection. ClerkExpo.podspec declares the SPM dependency and expands its source file list. ClerkNativeBridge is refactored to a static observer/emitter pattern reading the SDK version from Info.plist. app.plugin.js is reduced to setting only the deployment target and writing ClerkExpoVersion to Info.plist.

Changes

iOS SPM Podspec Integration

Layer / File(s)Summary
Podspec SPM dependency declaration and source files
packages/expo/ios/ClerkExpo.podspec, packages/expo/package.json
Podspec pins clerk_ios_version to 1.2.4, adds a conditional SPM block for ClerkKit/ClerkKitUI, expands s.source_files to cover all native bridge and view manager files, and raises the react-native peer dependency minimum to >=0.75.
ClerkNativeBridge static observer/emitter refactor and Info.plist version
packages/expo/ios/ClerkNativeBridge.swift
ClerkExpoHeaderMiddleware reads hostSdkVersion from Bundle.main Info.plist key ClerkExpoVersion at runtime instead of a build-time placeholder. configure gains an early loadThemes() call. Readiness and client-change plumbing is replaced with new static addReadyObserver/removeReadyObserver/emitReady and setClientChangedEmitter/emitClientChanged methods. Reconfigure path now posts a notification instead of emitting bridge-ready events.
ClerkExpoModule decoupled from optional bridge instance
packages/expo/ios/ClerkExpoModule.swift
Removes all top-level bridge protocol, event enum, observer registry, and global bridge variable declarations. Initializer registers a client-changed emitter via ClerkNativeBridge.setClientChangedEmitter. configure, getClientToken, and syncFromJsClientToken call ClerkNativeBridge.shared directly instead of guarding on an optional instance. The free function emitClerkNativeClientChanged is removed.
Native views switched to ClerkNativeBridge.shared singleton
packages/expo/ios/ClerkNativeViewHost.swift, packages/expo/ios/ClerkAuthNativeView.swift, packages/expo/ios/ClerkUserButtonNativeView.swift, packages/expo/ios/ClerkUserProfileNativeView.swift
ClerkNativeViewHost removes ClerkNativeBridgeReadyObserver conformance and switches to NotificationCenter observation of .clerkNativeSDKDidConfigure, adding explicit observer removal on window detach and in deinit. The three native view controllers replace guarded optional bridge lookups with direct ClerkNativeBridge.shared calls.
app.plugin.js simplification and changeset
packages/expo/app.plugin.js, .changeset/tidy-expo-ios-import.md
Removes all SPM injection, bridge file copying, AppDelegate method injection, and Podfile post-install hook logic from app.plugin.js, leaving only a deployment target update and an Info.plistClerkExpoVersion write. Documentation is updated to reflect the simplified setup. A patch changeset documents the iOS build fix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • clerk/javascript#8883: Replaces the __CLERK_EXPO_VERSION__ placeholder injection and ClerkExpoHeaderMiddleware request header wiring that this PR refactors to use Info.plist-driven runtime version reading.
  • clerk/javascript#8867: Pins clerk-ios to 1.2.4 in iOS integration, matching the version now declared via clerk_ios_version in the podspec.
  • clerk/javascript#8920: Modifies ClerkNativeBridge.swift in the configure/readiness signaling path, directly overlapping with this PR's refactoring of emitReady and loadThemes call placement.

Suggested reviewers

  • wobsoriano

Poem

🐇 No more Podfile hooks to fear,
The SPM lives in the podspec near!
Info.plist holds the version now,
The singleton bridge takes a bow.
Less plugin code, cleaner deploy —
This bunny hops with iOS joy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 17.24% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately summarizes the main change: moving iOS SDK linking from app-target configuration to podspec SPM dependencies.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@pkg-pr-new

pkg-pr-newBot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8927

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8927

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8927

@clerk/upgrade

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

@clerk/vue

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

commit: ea697ef

@github-actions

github-actionsBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-19T09:43:45.347Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on ea697ef.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/expo/ios/ClerkExpo.podspec (1)

20-21: 💤 Low value

Consider externalizing the Clerk iOS SDK version.

The clerk_ios_version = '1.2.4' is hardcoded in the podspec. Every Clerk iOS SDK update will require manually editing this file. Consider whether the version could be read from package.json or another configuration source to reduce maintenance overhead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/expo/ios/ClerkExpo.podspec` around lines 20 - 21, The
clerk_ios_version variable is hardcoded as '1.2.4' in the podspec file,
requiring manual updates whenever the Clerk iOS SDK version changes. Externalize
this version by reading it from package.json or another centralized
configuration source instead of hardcoding it. Modify the clerk_ios_version
assignment to dynamically fetch the version from the appropriate configuration
file, reducing maintenance overhead and keeping the dependency version
synchronized across your project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/expo/ios/ClerkExpoBridge.swift`:
- Around line 36-58: The clerkNativeBridgeReadyObservers hash table is accessed
without synchronization in the methods addClerkNativeBridgeReadyObserver,
removeClerkNativeBridgeReadyObserver, and emitClerkNativeBridgeReady, and
similarly clerkNativeClientChangedEmitter is accessed in
setClerkNativeClientChangedEmitter and emitClerkNativeClientChanged without
synchronization. Since NSHashTable is not thread-safe, concurrent calls from
different threads can corrupt the data structure or cause crashes. Create a
private serial DispatchQueue and wrap all accesses to both
clerkNativeBridgeReadyObservers and clerkNativeClientChangedEmitter within
synchronized blocks using this queue, ensuring all read and write operations are
serialized and thread-safe.
---
Nitpick comments:
In `@packages/expo/ios/ClerkExpo.podspec`:
- Around line 20-21: The clerk_ios_version variable is hardcoded as '1.2.4' in
the podspec file, requiring manual updates whenever the Clerk iOS SDK version
changes. Externalize this version by reading it from package.json or another
centralized configuration source instead of hardcoding it. Modify the
clerk_ios_version assignment to dynamically fetch the version from the
appropriate configuration file, reducing maintenance overhead and keeping the
dependency version synchronized across your project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cfed06c-5d52-4b43-bbe1-7a2655f71514

📥 Commits

Reviewing files that changed from the base of the PR and between 88525a6 and 5faa0bc.

📒 Files selected for processing (8)
  • .changeset/tidy-expo-ios-import.md
  • packages/expo/app.plugin.js
  • packages/expo/ios/ClerkExpo.podspec
  • packages/expo/ios/ClerkExpoBridge.swift
  • packages/expo/ios/ClerkExpoModule.swift
  • packages/expo/ios/ClerkNativeBridge.swift
  • packages/expo/package.json
  • packages/expo/src/__tests__/appPlugin.injectClerkExpoVersion.test.js
💤 Files with no reviewable changes (1)
  • packages/expo/src/tests/appPlugin.injectClerkExpoVersion.test.js

Comment threadpackages/expo/ios/ClerkExpoBridge.swift Outdated

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:f7088d0604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/expo/app.plugin.js

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:83e37e979b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

products: ['ClerkKit', 'ClerkKitUI']
)
else
raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep RN 0.73/0.74 pod installs working

For apps still on React Native 0.73/0.74 (which satisfied @clerk/expo's previous peer range and can receive this patch via a caret range), spm_dependency is not defined by RN's CocoaPods scripts, so this raise makes every iOS pod install fail even though those apps built with the old Xcode-project injection path. Because this is being released as a patch, please keep a fallback for those RN versions or avoid shipping this path to them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Our supported expo range is >=53, so supporting 0.73 and 0.74 is already a mismatch. Expo 53 contains React Native 0.79

@wobsorianowobsoriano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested this locally in both Expo SDK 54 and 56. Runs successfully ✅

@wobsoriano
wobsoriano merged commit bfe280a into mainJun 19, 2026
49 checks passed
@wobsoriano
wobsoriano deleted the mike/fix-expo-ios-spm-podspec-linking branch June 19, 2026 10:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mikepitre@wobsoriano
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); fix(expo): link iOS SDK through podspec SPM dependencies by mikepitre · Pull Request #8927 · clerk/javascript · GitHub
Skip to content

fix(expo): link iOS SDK through podspec SPM dependencies - #8927

Merged
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking
Jun 19, 2026
Merged

fix(expo): link iOS SDK through podspec SPM dependencies#8927
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking

Conversation

@mikepitre

@mikepitremikepitre commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Link clerk-ios from ClerkExpo.podspec using React Native's spm_dependency, so the ClerkExpo pod target can import ClerkKit and ClerkKitUI directly.
  • Remove the config plugin's app-target SPM/project mutation and copied native bridge injection.
  • Remove the old optional native bridge facade now that the Clerk iOS SDK is available inside the ClerkExpo pod target; module and view wrappers call ClerkNativeBridge.shared directly.
  • Bump the @clerk/expo React Native peer dependency from >=0.73 to >=0.75, since this fix relies on React Native's podspec Swift Package Manager dependency support.

Motivation

Expo SDK 54 generates import ClerkExpo for Expo modules while SDK 56 generates internal import ClerkExpo. The import form is not the real problem; the issue was that ClerkExpo depended on ClerkKit/ClerkKitUI through app-target project mutation instead of declaring the Swift package dependency on the pod target that actually imports those modules.

Moving the SPM dependency into the podspec keeps the dependency attached to the correct native target and avoids having to special-case Expo's generated import style.

Because the Clerk iOS SDK is now visible to the pod target, the separate ClerkExpoBridge.swift protocol/global registry layer is no longer needed. The remaining readiness and native-client-change coordination lives on ClerkNativeBridge.

Verification

  • git diff --check
  • pnpm --filter @clerk/expo test
  • Fresh Expo SDK 54 and SDK 56 apps installed @clerk/expo from a packed tarball
  • npx expo prebuild --clean --platform ios passed for both apps
  • Clean Release simulator builds passed for both apps, fetching clerk-ios1.2.4 through SPM
  • Installed and launched both apps on the iOS simulator; verified AuthView, UserButton, JS sign-in, and JS sign-out

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved iOS development-build compatibility across Expo SDK versions with more reliable native SDK linking and configuration.
    • Refined native-to-JS client-change updates to stay consistent after app reconfiguration and theme loading.
  • Chores

    • Simplified iOS setup by reading the host SDK version from app metadata and using it when communicating with the native layer.
  • Tests

    • Removed an obsolete iOS version injection test.
  • Compatibility

    • Raised the minimum supported React Native version to 0.75+.

@changeset-bot

changeset-botBot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ea697ef

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

This PR includes changesets to release 1 package
NameType
@clerk/expoMinor

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

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

@vercel

vercelBot commented Jun 19, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJun 19, 2026 9:42am
swingsetReadyReadyPreview, CommentJun 19, 2026 9:42am

Request Review

@coderabbitai

coderabbitaiBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f46b3e8a-ee41-4167-8d6d-9d6271d22c1e

📥 Commits

Reviewing files that changed from the base of the PR and between ee5f933 and ea697ef.

📒 Files selected for processing (1)
  • .changeset/tidy-expo-ios-import.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-expo-ios-import.md

📝 Walkthrough

Walkthrough

The Clerk iOS SDK is now linked via React Native's native SPM podspec support rather than manual Expo config plugin injection. ClerkExpo.podspec declares the SPM dependency and expands its source file list. ClerkNativeBridge is refactored to a static observer/emitter pattern reading the SDK version from Info.plist. app.plugin.js is reduced to setting only the deployment target and writing ClerkExpoVersion to Info.plist.

Changes

iOS SPM Podspec Integration

Layer / File(s)Summary
Podspec SPM dependency declaration and source files
packages/expo/ios/ClerkExpo.podspec, packages/expo/package.json
Podspec pins clerk_ios_version to 1.2.4, adds a conditional SPM block for ClerkKit/ClerkKitUI, expands s.source_files to cover all native bridge and view manager files, and raises the react-native peer dependency minimum to >=0.75.
ClerkNativeBridge static observer/emitter refactor and Info.plist version
packages/expo/ios/ClerkNativeBridge.swift
ClerkExpoHeaderMiddleware reads hostSdkVersion from Bundle.main Info.plist key ClerkExpoVersion at runtime instead of a build-time placeholder. configure gains an early loadThemes() call. Readiness and client-change plumbing is replaced with new static addReadyObserver/removeReadyObserver/emitReady and setClientChangedEmitter/emitClientChanged methods. Reconfigure path now posts a notification instead of emitting bridge-ready events.
ClerkExpoModule decoupled from optional bridge instance
packages/expo/ios/ClerkExpoModule.swift
Removes all top-level bridge protocol, event enum, observer registry, and global bridge variable declarations. Initializer registers a client-changed emitter via ClerkNativeBridge.setClientChangedEmitter. configure, getClientToken, and syncFromJsClientToken call ClerkNativeBridge.shared directly instead of guarding on an optional instance. The free function emitClerkNativeClientChanged is removed.
Native views switched to ClerkNativeBridge.shared singleton
packages/expo/ios/ClerkNativeViewHost.swift, packages/expo/ios/ClerkAuthNativeView.swift, packages/expo/ios/ClerkUserButtonNativeView.swift, packages/expo/ios/ClerkUserProfileNativeView.swift
ClerkNativeViewHost removes ClerkNativeBridgeReadyObserver conformance and switches to NotificationCenter observation of .clerkNativeSDKDidConfigure, adding explicit observer removal on window detach and in deinit. The three native view controllers replace guarded optional bridge lookups with direct ClerkNativeBridge.shared calls.
app.plugin.js simplification and changeset
packages/expo/app.plugin.js, .changeset/tidy-expo-ios-import.md
Removes all SPM injection, bridge file copying, AppDelegate method injection, and Podfile post-install hook logic from app.plugin.js, leaving only a deployment target update and an Info.plistClerkExpoVersion write. Documentation is updated to reflect the simplified setup. A patch changeset documents the iOS build fix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • clerk/javascript#8883: Replaces the __CLERK_EXPO_VERSION__ placeholder injection and ClerkExpoHeaderMiddleware request header wiring that this PR refactors to use Info.plist-driven runtime version reading.
  • clerk/javascript#8867: Pins clerk-ios to 1.2.4 in iOS integration, matching the version now declared via clerk_ios_version in the podspec.
  • clerk/javascript#8920: Modifies ClerkNativeBridge.swift in the configure/readiness signaling path, directly overlapping with this PR's refactoring of emitReady and loadThemes call placement.

Suggested reviewers

  • wobsoriano

Poem

🐇 No more Podfile hooks to fear,
The SPM lives in the podspec near!
Info.plist holds the version now,
The singleton bridge takes a bow.
Less plugin code, cleaner deploy —
This bunny hops with iOS joy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 17.24% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately summarizes the main change: moving iOS SDK linking from app-target configuration to podspec SPM dependencies.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@pkg-pr-new

pkg-pr-newBot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8927

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8927

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8927

@clerk/upgrade

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

@clerk/vue

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

commit: ea697ef

@github-actions

github-actionsBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-19T09:43:45.347Z

Summary

MetricCount
Packages analyzed19
Packages with changes0
🔴 Breaking changes0
🟡 Non-breaking changes0
🟢 Additions0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on ea697ef.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/expo/ios/ClerkExpo.podspec (1)

20-21: 💤 Low value

Consider externalizing the Clerk iOS SDK version.

The clerk_ios_version = '1.2.4' is hardcoded in the podspec. Every Clerk iOS SDK update will require manually editing this file. Consider whether the version could be read from package.json or another configuration source to reduce maintenance overhead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/expo/ios/ClerkExpo.podspec` around lines 20 - 21, The
clerk_ios_version variable is hardcoded as '1.2.4' in the podspec file,
requiring manual updates whenever the Clerk iOS SDK version changes. Externalize
this version by reading it from package.json or another centralized
configuration source instead of hardcoding it. Modify the clerk_ios_version
assignment to dynamically fetch the version from the appropriate configuration
file, reducing maintenance overhead and keeping the dependency version
synchronized across your project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/expo/ios/ClerkExpoBridge.swift`:
- Around line 36-58: The clerkNativeBridgeReadyObservers hash table is accessed
without synchronization in the methods addClerkNativeBridgeReadyObserver,
removeClerkNativeBridgeReadyObserver, and emitClerkNativeBridgeReady, and
similarly clerkNativeClientChangedEmitter is accessed in
setClerkNativeClientChangedEmitter and emitClerkNativeClientChanged without
synchronization. Since NSHashTable is not thread-safe, concurrent calls from
different threads can corrupt the data structure or cause crashes. Create a
private serial DispatchQueue and wrap all accesses to both
clerkNativeBridgeReadyObservers and clerkNativeClientChangedEmitter within
synchronized blocks using this queue, ensuring all read and write operations are
serialized and thread-safe.
---
Nitpick comments:
In `@packages/expo/ios/ClerkExpo.podspec`:
- Around line 20-21: The clerk_ios_version variable is hardcoded as '1.2.4' in
the podspec file, requiring manual updates whenever the Clerk iOS SDK version
changes. Externalize this version by reading it from package.json or another
centralized configuration source instead of hardcoding it. Modify the
clerk_ios_version assignment to dynamically fetch the version from the
appropriate configuration file, reducing maintenance overhead and keeping the
dependency version synchronized across your project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cfed06c-5d52-4b43-bbe1-7a2655f71514

📥 Commits

Reviewing files that changed from the base of the PR and between 88525a6 and 5faa0bc.

📒 Files selected for processing (8)
  • .changeset/tidy-expo-ios-import.md
  • packages/expo/app.plugin.js
  • packages/expo/ios/ClerkExpo.podspec
  • packages/expo/ios/ClerkExpoBridge.swift
  • packages/expo/ios/ClerkExpoModule.swift
  • packages/expo/ios/ClerkNativeBridge.swift
  • packages/expo/package.json
  • packages/expo/src/__tests__/appPlugin.injectClerkExpoVersion.test.js
💤 Files with no reviewable changes (1)
  • packages/expo/src/tests/appPlugin.injectClerkExpoVersion.test.js

Comment threadpackages/expo/ios/ClerkExpoBridge.swift Outdated

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:f7088d0604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/expo/app.plugin.js

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:83e37e979b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

products: ['ClerkKit', 'ClerkKitUI']
)
else
raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep RN 0.73/0.74 pod installs working

For apps still on React Native 0.73/0.74 (which satisfied @clerk/expo's previous peer range and can receive this patch via a caret range), spm_dependency is not defined by RN's CocoaPods scripts, so this raise makes every iOS pod install fail even though those apps built with the old Xcode-project injection path. Because this is being released as a patch, please keep a fallback for those RN versions or avoid shipping this path to them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Our supported expo range is >=53, so supporting 0.73 and 0.74 is already a mismatch. Expo 53 contains React Native 0.79

@wobsorianowobsoriano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested this locally in both Expo SDK 54 and 56. Runs successfully ✅

@wobsoriano
wobsoriano merged commit bfe280a into mainJun 19, 2026
49 checks passed
@wobsoriano
wobsoriano deleted the mike/fix-expo-ios-spm-podspec-linking branch June 19, 2026 10:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mikepitre@wobsoriano