Expo Easy Passkey

Releasing

Maintainer steps for versioning, publishing, and recovery

This page is for maintainers publishing Expo Easy Passkey. App teams installing the package usually only need Install, Platforms, and Device E2E.

Release model

expo-easy-passkey is the only package published to npm. It contains the public TypeScript API, the Expo native module, the config plugin, iOS and Android native code, and generated binding files used during release validation.

The repository has internal source boundaries that are not npm package boundaries:

  • packages/module is the released package.
  • crates/passkey-core and crates/passkey-ffi are internal Rust crates used for tests, fixtures, and generated native bindings.
  • apps/example, apps/docs, and tooling/* are private workspaces.

Changesets handles package versioning and changelog entries. During the alpha stream, Changesets runs in prerelease mode with the alpha tag, so the first release PR should version expo-easy-passkey as 0.1.0-alpha.0.

Contributors

Every user-facing change should include a changeset:

pnpm changeset

Choose the semver intent for expo-easy-passkey:

  • patch for fixes and small documentation corrections that affect published package users.
  • minor for additive APIs, native platform support, or meaningful behavior improvements.
  • major for breaking public API or config changes.

For the alpha stream, Changesets converts that intent into an alpha prerelease version. Commit the generated .changeset/*.md file with the code change.

Before merging a feature PR, CI should pass the repository verification jobs, including TypeScript, Rust, binding freshness, Android compile, and iOS compile.

Maintainers

After feature PRs land on main, the release workflow runs. If there are pending changesets, it opens or updates a Changesets release PR.

Review the release PR before merging it:

  • Confirm only expo-easy-passkey is versioned.
  • Confirm packages/module/CHANGELOG.md describes the release clearly.
  • Confirm package metadata still points to the single installable package.
  • Confirm CI is green, including pnpm check and pnpm verify:release-acceptance.
  • Confirm required manual device E2E notes are recorded under Release evidence below.
  • Confirm response shapes and public error codes are unchanged, or that the changelog includes an explicit compatibility note.

Merging the release PR runs the release workflow again. This time Changesets publishes expo-easy-passkey to npm, creates tags, and updates GitHub release metadata.

After publish, verify npm:

npm view expo-easy-passkey version
npm view expo-easy-passkey dist-tags

For alpha releases, verify that the latest alpha is on the alpha dist-tag and not promoted to the stable latest tag.

Automation

The release workflow runs on pushes to main and on manual workflow_dispatch.

Before publication work starts, trusted jobs rebuild native Rust artifacts from the checked-out release commit and the committed Cargo.lock:

  • Android builds every supported ABI (arm64-v8a, armeabi-v7a, x86, x86_64) on Linux with the NDK.
  • Apple builds the device (ios-arm64) and simulator (ios-arm64_x86_64-simulator) xcframework slices on macOS.

Those jobs write into isolated runner temp roots (--artifacts-root), then upload immutable workflow artifacts plus metadata that records the source commit, lockfile digest, toolchain identity, target inventory, and output checksums. A missing supported target or build failure blocks the downstream release job.

Separate smoke jobs then download those exact artifacts (they do not rebuild natives) into packages/module, pack expo-easy-passkey, install the tarball into disposable Android and Apple consumers, inspect every required ABI and Apple device/simulator slice, and execute one exported UniFFI helper from the packaged runtime for each platform family. Missing, stale, mismatched, or unloadable binaries fail before publication.

Native libraries, the Apple xcframework, and .rust-artifacts metadata are gitignored because they are not bit-reproducible across hosts. Checkout never supplies publication binaries. Trusted jobs rebuild from the release commit, and the release job stages only those smoke-validated outputs.

The release job downloads the same smoke-validated Android and Apple artifacts into isolated staging directories, runs prepare-trusted-native-artifacts to wipe package native paths and install only those trusted outputs, writes packages/module/.rust-artifacts/release-evidence.json (source commit, lockfile digest, per-platform toolchain, target inventory, and checksums), uploads that evidence, then performs:

pnpm install --frozen-lockfile
pnpm rust:fmt
pnpm rust:clippy
pnpm bindgen:check
pnpm check
pnpm verify:release-acceptance
pnpm build
pnpm pack:check

Any contract, native artifact, packed-consumer, web import, or acceptance-plan wiring failure blocks publication. Publication cannot fall back to checkout binaries: prepare replaces them before pack:check and changeset publish. npm provenance remains enabled via publishConfig.provenance and the workflow id-token: write permission, so the published package is attested to this workflow run and commit.

Then changesets/action either opens the release PR or publishes with:

pnpm version-packages
pnpm release

pnpm pack:check builds the package, runs the Expo module prepublish check, and performs a dry-run npm pack inspection for expo-easy-passkey.

GitHub and npm

The repository must allow the release workflow to write contents and pull requests. The workflow also requests id-token: write so npm can attach provenance to published artifacts.

Configure these settings before the first release:

  • Add NPM_TOKEN as a GitHub Actions secret.
  • Use an npm automation token or trusted-publishing-compatible token policy that can publish expo-easy-passkey.
  • Keep npm 2FA enabled for the maintainer account; use a token type compatible with CI publishing.
  • Ensure the npm package name is available and the token has permission to publish it.
  • Ensure GitHub Actions can create pull requests and tags with GITHUB_TOKEN.

Release evidence

Before merging a release PR, review and record the evidence that proves the cross-platform contract:

Automated evidence (must be green in CI / release):

  • Package-to-relying-party registration and authentication for the HTTPS iOS origin and configured Android APK-key-hash origins
  • Exact origin trust, concurrent and replayed ceremony isolation, iOS pre-presentation policy validation, and web/SSR unsupported behavior
  • Trusted native artifact build, packaged-target inspection, FFI smoke tests, and exact-artifact publication checks
  • release-evidence.json source commit, lockfile digest, toolchain, target inventory, and checksums

Required real-device evidence from Device E2E (fixtures cannot prove these):

  • Association: hosted apple-app-site-association and assetlinks.json
  • Signing: app build certificates match Digital Asset Links and the server Android origin allowlist
  • System UI: platform passkey sheets appear for registration and authentication
  • User verification: biometric or device credential completion succeeds end to end

Compatibility evidence:

  • Existing WebAuthn response shapes and public error codes remain unchanged unless the changelog includes an explicit compatibility note

Record the device model, OS version, app build profile, relying-party domain, server environment, and which association / signing paths were exercised. Keep those notes with the release PR review.

Validation

Run the full local verification suite before merging a release PR when native, Rust, generated binding, or public API changes are involved:

pnpm verify
pnpm test:acceptance
pnpm verify:release-acceptance
pnpm bindgen:check
pnpm --filter expo-easy-passkey prepublishOnly
pnpm --filter expo-easy-passkey pack --dry-run

pnpm verify already includes pnpm check, which runs the acceptance Jest files. pnpm test:acceptance is the local subset if you want to re-run only those suites.

Before release, run device E2E too. Passkey ceremonies depend on platform accounts, signing certificates, associated domains, Digital Asset Links, credential providers, and user verification UI. Follow Device E2E and complete the Release evidence checklist above.

When Rust, UniFFI, or native helper code changes, regenerate packageable native Rust artifacts locally for development and review. Trusted release jobs rebuild and upload immutable artifacts with metadata, then smoke-test the packed package against those outputs before publication:

pnpm build:rust-artifacts
# or platform-scoped:
# pnpm build:rust-artifacts android
# pnpm build:rust-artifacts apple
pnpm bindgen:check
pnpm --filter expo-easy-passkey build
# After metadata exists under packages/module/.rust-artifacts/:
# pnpm smoke:native-artifacts --platform apple
# pnpm smoke:native-artifacts --platform android
# pnpm prepare:trusted-native-artifacts --android-from <trusted-android> --apple-from <trusted-apple> \
#   --expected-source-commit <sha> --evidence-output packages/module/.rust-artifacts/release-evidence.json
pnpm pack:check

Local pnpm build:rust-artifacts writes Android shared libraries to packages/module/android/src/main/jniLibs, the iOS xcframework to packages/module/ios/rust, and metadata under packages/module/.rust-artifacts/ for development. Those paths are gitignored. Release jobs build into isolated temp roots, smoke-test the packed package against those outputs, then prepare:trusted-native-artifacts stages only the trusted CI artifacts and ships release-evidence.json inside the npm package.

Failures

If the release PR checks fail, fix the failing code or generated artifacts in a normal PR. The release PR will update after the fix lands on main.

If npm publish fails before a version is published, fix the token, package metadata, or workflow issue and rerun the release workflow.

If npm publish partially succeeds, do not republish the same version. Inspect npm first:

npm view expo-easy-passkey versions
npm view expo-easy-passkey dist-tags

If an alpha version was published with the wrong dist-tag, correct the tag instead of publishing a replacement version:

npm dist-tag add expo-easy-passkey@0.1.0-alpha.0 alpha
npm dist-tag rm expo-easy-passkey latest

If a bad package has already been published, publish a new patch or prerelease version with a changeset that explains the fix. Avoid unpublishing unless the case satisfies npm's unpublish policy.

On this page