refactor(mobile): adopt Expo Modules 2.0 for function-only native members#12051

merged2
mobile/sdk58-scene-geometry
mobile/sdk58-expo-modules-2
openedSep 16, 2026byJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 21d ago

Stacked on #12050. A trial of the SDK 58 Expo Modules 2.0 macros on the parts of our native modules they fit.

The plain functions of T3NativeControls and the composer clipboard write are now @JS members bound by the macro instead of definition() entries. Main-thread work is @MainActor isolated the way expo-haptics does it, and the two showcase file reads run with @JS(.concurrent) so they never block the JavaScript thread. The JS surface is unchanged.

Deliberately not migrated: views (2.0 has no view API yet; that is most of our native surface) and the promise-backed presenters that resolve when a sheet closes. @ExpoModule merges the @JS members with what stays in definition().

Validation: compiles on Xcode 27 with the macro plugin wired by autolinking; the showcase and native-controls JS callers are untouched.

Model: Claude Fable 5. Harness: Claude Code.

Checks

23 successful Β· 9 skipped
All checks passed
c4e77d0
Synced from GitHub

Review in Change Stack β†’

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

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: pingdotgg/t3code/.coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 077ad2ca-28ec-4cdc-a93f-c37b90971c59

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 6ea0c048b56f72f7e15dd471976343b5f6eec4ff and 0f1b45a6d5d774277fc210c460028995c4215b6b.

πŸ“’ Files selected for processing (1)
  • apps/mobile/modules/t3-native-controls/ios/T3NativeControlsModule.swift

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.


πŸ“ Walkthrough

Walkthrough

The iOS modules adopt Expo Modules 2.0 annotations for JavaScript-callable methods. The clipboard, dismissal, orientation, showcase lookup, capture, and readiness methods retain their described behavior, with the noted orientation-version check removed.

Changes

Expo Modules 2.0 Native API Migration

Layer / File(s)Summary
Composer editor method binding
apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorModule.swift
The module declares its name with @ExpoModule. Clipboard writing uses an asynchronous @JS method isolated to the main actor.
Native controls presentation and showcase methods
apps/mobile/modules/t3-native-controls/ios/T3NativeControlsModule.swift
Dismissal, orientation, showcase lookup, capture, and readiness methods use annotated declarations. The dismissal helpers are renamed. Orientation application no longer returns early on iOS versions below 16.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Refactor

Suggested reviewers: chrisdeeming

Merge Risk: βšͺ Minimal Β· up to 0f1b4

The migrated native methods preserve their JavaScript contracts, and showcase capture waits for the requested scene’s readiness signal. No actionable merge-blocking risk remains.

πŸš₯ Pre-merge checks | βœ… 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 26.32% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 2 files.Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check⚠️ WarningThe description explains the implementation and includes focused verification. It does not clearly state the problem, expected behavior, or reproduction context. It also links a stacked pull request b…Add a clear Problem section with the prior behavior and expected behavior. Add the triaged issue or discussion link with the explicit maintainer approval comment, or explain why this focused change qualifies for an exemption. Expand Verific…
βœ… Passed checks (3 passed)
Check nameStatusExplanation
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.
Title checkβœ… PassedThe title clearly identifies the main change: adopting Expo Modules 2.0 for function-only native members.
Full details: Description check

Explanation

The description explains the implementation and includes focused verification. It does not clearly state the problem, expected behavior, or reproduction context. It also links a stacked pull request but does not provide the required triaged issue or explicit maintainer approval and approval comment.

Resolution

Add a clear Problem section with the prior behavior and expected behavior. Add the triaged issue or discussion link with the explicit maintainer approval comment, or explain why this focused change qualifies for an exemption. Expand Verification with the specific compilation or manual-check result and any checks that were not run.

  • Fix all pre-merge checks with AI
✨ Finishing Touches πŸ’‘ 1
πŸ“ Generate docstrings πŸ’‘
  • Create stacked PR
  • Commit on current branch
πŸ§ͺ Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

Synced from GitHub

Thread transfer impact

βœ… Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wireβ€”13.5 KiBβ€”15.1 KiBβœ…
CodexThread snapshot wireβ€”7.1 KiBβ€”7.3 KiBβœ…
CodexLive turn WebSocket wireβ€”6.5 KiBβ€”7.8 KiBβœ…
CodexLive turn WebSocket decodedβ€”56.3 KiBβ€”66.4 KiBβœ…
CodexLive turn messagesβ€”10β€”21βœ…
ClaudeTotal thread wireβ€”13.5 KiBβ€”15.1 KiBβœ…
ClaudeThread snapshot wireβ€”7.1 KiBβ€”7.3 KiBβœ…
ClaudeLive turn WebSocket wireβ€”6.4 KiBβ€”7.8 KiBβœ…
ClaudeLive turn WebSocket decodedβ€”57.0 KiBβ€”66.4 KiBβœ…
ClaudeLive turn messagesβ€”9β€”21βœ…

Baseline: unavailable Β· PR result: c4e77d0 Β· Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 114.0 KiB
  • Claude decoded thread snapshot: 114.7 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

apps/mobile/modules/t3-native-controls/ios/T3NativeControlsModule.swiftlines 124–125Outdated Β· 79abff3Open thread
……@@ -60,103 +53,109 @@ public final class T3NativeControlsModule: Module {
150- SecItemDelete([kSecClass as String: itemClass] as CFDictionary)
151- }
124+ @JS(.concurrent)
125+ func getShowcaseScene() async -> String? {
MmacroscopeappBoton lines 124–125Sep 16, 2026

🟑 Medium ios/T3NativeControlsModule.swift:124

getShowcaseScene now returns a Promise, so the synchronous getNativeShowcaseScene() call invokes .trim() on that Promise and falls back to null on iOS. Keep this exported getter synchronous, or update the consumer to await it.

βœ… Resolved in ce481e57b63e8dd7a61d8e36f3927cdcaf60e9b1

Synced from GitHub

Approvability

Verdict: Approved at f2928db

Macroscope's review found this PR approvable β€” This is a contained Expo Modules 2.0 binding migration across two existing iOS modules, preserving the JavaScript surface, views, presenters, and supported-device behavior. Runtime scheduling changes are explicit and limited to main-actor UIKit calls and non-product showcase metadata.

Notes:

  • Diff unchanged. Approvability was decided on eligibility alone.

No code changes detected at c4e77d0. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

Added 2 commits

  • refactor(mobile): adopt Expo Modules 2.0 for function-only native members6265e72
  • fix(mobile): preserve the synchronous showcase scene getterc4e77d0