Skip to content

feat: macOS support (+example app +ci/cd) - #298

Open
samuelscheit wants to merge 7 commits into
margelo:mainfrom
samuelscheit:main
Open

feat: macOS support (+example app +ci/cd)#298
samuelscheit wants to merge 7 commits into
margelo:mainfrom
samuelscheit:main

Conversation

@samuelscheit

@samuelscheit samuelscheit commented Aug 5, 2026

Copy link
Copy Markdown

Summary

Partially resolves #34

This PR adds first-class React Native macOS support to the example app and test infrastructure.

The new desktop workspace reuses the existing SQLite, TypeORM, sqlite-vec, SQL console, benchmark, and shared Mocha test flows while adding the macOS-specific native, navigation, Metro, Babel, CocoaPods, and CI plumbing required to run them reliably.

It also introduces a deterministic macOS integration-test transport because React Native Harness does not currently provide a macOS runner or desktop-app lifecycle bridge.

What鈥檚 included

React Native macOS example workspace

  • Added a standalone example/macos React Native macOS workspace.
  • Reused the shared example application logic and screens:
    • SQLite API examples
    • TypeORM flows
    • sqlite-vec workflows
    • SQL console
    • Benchmarks
    • Shared unit-test registration
  • Added macOS-specific navigation so the desktop app uses a platform-safe implementation without affecting iOS or Android navigation.
  • Added macOS-specific Metro and Babel configuration, including React Native macOS module resolution and desktop-safe polyfill handling.

Native macOS integration

  • Added the Xcode project, workspace, application delegate, entitlements, app sandbox configuration, and CocoaPods setup.
  • Wired React Native macOS autolinking and generated native registration.
  • Configured the macOS app to store databases under Application Support.
  • Enabled sqlite-vec for the macOS example build.
  • Patched react-native-get-random-values so it registers correctly in a macOS new-architecture build.
  • Added the macOS Pod workspace to lockfile maintenance.

SQLite thread-safety configuration

SQLite is now configured per Apple target through NITRO_SQLITE_THREADSAFE.

  • The setting accepts only 0 or 1.
  • iOS keeps its previous default: SQLITE_THREADSAFE=0.
  • The macOS example explicitly uses SQLITE_THREADSAFE=1.
  • The macOS opt-in is required because Nitro async APIs execute on worker threads and can otherwise access SQLite concurrently.

This preserves the existing iOS configuration while preventing the macOS app from crashing during repeated or concurrent async SQLite CI work.

macOS CI coverage

Added dedicated macOS workflows for pushes and pull requests.

  • Cached macOS build workflow for the desktop example.
  • PR integration workflow that:
    1. Installs Pods.
    2. Builds the macOS application.
    3. Starts Metro on an ephemeral port.
    4. Launches the compiled app.
    5. Waits for a structured test report.
    6. Fails on app startup, Metro startup, timeout, or test failures.
    7. Reliably tears down app and Metro process groups.

Test-result transport

React Native Harness currently supports Android and iOS, but not macOS desktop-process lifecycle management.

Until upstream macOS support exists, the macOS runner uses a small explicit test-only transport:

  • The runner creates a loopback HTTP endpoint path.
  • It supplies the report URL and Metro port through the launched app鈥檚 environment.
  • AppDelegate exposes the report URL only as a test initial prop.
  • The test-only macOS root runs the existing shared Mocha suite.
  • It posts structured results back to the runner.
  • Normal app launches still render the regular application.

This keeps production behavior unchanged while giving CI deterministic completion and actionable failures.

Documentation

Added or updated documentation for:

  • Installing and launching the macOS example
  • CocoaPods setup for React Native macOS
  • Application Support database storage
  • sqlite-vec opt-in and vector-search workflows
  • NITRO_SQLITE_THREADSAFE configuration for Apple builds

Validation

  • macOS CocoaPods installation succeeds with SQLITE_THREADSAFE=1.
  • iOS CocoaPods installation retains SQLITE_THREADSAFE=0.
  • Clean macOS Debug build succeeds.
  • macOS integration runner passed four consecutive runs:
    • 69 passed, 0 failed
  • TypeScript, ESLint, Prettier, Podspec syntax, lockfile, and invalid-configuration checks pass.

AI assistance

This PR was implemented and documented with AI assistance. The validation results above were run locally against the resulting macOS build.

Screenshots

image image image image

The benchmark reset flow used the module-scoped largeDb variable as a proxy for whether the on-disk database existed. SQLite files survive app restarts while that variable does not, so a fresh runtime reopened an existing large database and unconditionally attempted to create Test again. This surfaced as "table Test already exists" before the benchmark could run.\n\nKeep the benchmark connection open for the current runtime and rebuild its schema transactionally on every reset. The shared schema helper drops the old Test table before recreating the expected STRICT table, preserving deterministic benchmark data whether the database is new, persisted from a previous launch, or reused in the same session. The misleading user-database error label is corrected as well.\n\nAdd a native regression test that begins with an incompatible existing Test table and verifies that the reset helper replaces it with the full benchmark schema. Register it with the unit suite so the persisted-schema lifecycle is covered without inserting 300,000 benchmark rows during tests.
Add a first-class React Native macOS example workspace that reuses the shared SQLite, TypeORM, sqlite-vec, console, and benchmark flows while providing a macOS-safe navigation implementation and platform-specific Metro/Babel configuration.

Wire CocoaPods, autolinking, generated native registration, app sandbox configuration, database storage under Application Support, and sqlite-vec opt-in support for macOS. Patch react-native-get-random-values so it registers correctly in the macOS new-architecture build.

Replace the legacy thread-unsafe SQLite performance toggle with a single thread-safe configuration. Async operations execute on Nitro worker threads, so SQLite must retain mutex support to avoid crashes during repeat and concurrent test runs.

Add matching CI coverage: a cached macOS build workflow for pushes and pull requests, plus a PR integration workflow that builds the app, starts Metro on an ephemeral port, launches the compiled app, and waits for its structured test report. The runner propagates app and Metro startup failures, validates results, and reliably tears down child process groups.

React Native Harness currently supports Android and iOS targets, but has no macOS platform runner or desktop-process lifecycle integration. The macOS workflow therefore uses a small explicit result transport instead of the Harness WebSocket bridge: the runner creates a loopback HTTP endpoint, supplies its unguessable URL and Metro port through the launched app's environment, and the AppDelegate exposes the URL only as a test initial prop. The test-only macOS root runs the shared Mocha suite and posts its structured result to that endpoint. This preserves normal app behavior while giving CI a deterministic completion signal and actionable test failures; it can be replaced by the standard Harness bridge once macOS support exists upstream.

Keep release lockfile maintenance in sync with the new macOS Pods workspace, share the test registration used by the UI and CI runner, and document macOS installation, launch, database-location, and vector-search workflows.
Restore the original performance_mode selector and its mode 1 default, including the thread-unsafe SQLite compile flag and the existing mode 2 thread-safe branch. This preserves the Apple build behavior and local configuration point that existed before macOS support was added.

Regenerate the iOS and macOS Pod lockfiles so CocoaPods consumes the restored podspec consistently in local builds, release lockfile maintenance, and CI.
Expose the Android, iOS, and macOS harness workflows through workflow_dispatch so maintainers can validate any platform without waiting for a pull request event.\n\nThe existing pull_request path filters remain unchanged, preserving the current automatic CI scope while enabling on-demand reruns and investigation from the Actions UI.
Replace the hard-coded legacy performance selector with the validated NITRO_SQLITE_THREADSAFE CocoaPods setting. The setting accepts only 0 or 1 and defaults to 0, retaining the existing iOS build configuration.

Opt the React Native macOS example into SQLITE_THREADSAFE=1 because its async APIs execute on Nitro worker threads. This avoids unsafe concurrent SQLite access while leaving iOS behavior unchanged.

Regenerate the macOS Podfile lockfile and document how downstream Apple applications can opt into mutex support before installing Pods.

Validation: ruby podspec syntax check; macOS and iOS pod installs; generated Debug/Release xcconfig checks for macOS=1 and iOS=0; clean macOS Debug build; four CI-style macOS runner passes with 69 passing tests each; root typecheck; non-mutating ESLint checks; Prettier check; invalid configuration rejection.
Align every handwritten SQLite helper and hybrid object with Nitrogen's generated margelo::nitro::rnnitrosqlite namespace. This removes the stale parallel namespace and broad using declarations that made the generated macOS bindings and native implementation refer to different types.

Resolve internal headers relative to their owning directory so CocoaPods cannot accidentally select op-sqlite's similarly named headers. Correct SQLite column metadata comparisons so declared BOOLEAN, FLOAT, INTEGER, TEXT, and BLOB types map to their intended Nitro result representations.

Expose the package source through the react-native export condition. React Native macOS can now resolve the local package without falling back from a missing prebuilt CommonJS artifact during development.

Validated with package type checking and build, a clean Metro macOS bundle, CocoaPods installation, an arm64 macOS Xcode build, and the ORM benchmark's native Column, Objects, Types, and unsupported Arrays paths.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for react-native-windows and react-native-macos

1 participant