diff --git a/.changeset/android-picker-viewport-jump.md b/.changeset/android-picker-viewport-jump.md
deleted file mode 100644
index e2fc60bb..00000000
--- a/.changeset/android-picker-viewport-jump.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-ui': patch
----
-
-Fix jarring layout jump when the Bible Version and Chapter picker sheets open on Android. The pre-warmed picker WebView sits in an offscreen inert sheet host where Android reports `visualViewport.height` as 0; the keyboard-viewport listener wrote that as `--yv-visible-height: 0px`, collapsing the picker shell (search bar at the top of an empty sheet) until a late viewport resize snapped everything into place mid-animation. Viewport heights below a plausibility floor are now treated as "hidden WebView" and fall back to the stylesheet default (100vh), so the pre-warmed layout is already correct when the sheet opens.
diff --git a/.changeset/auth-avatar-and-cancel.md b/.changeset/auth-avatar-and-cancel.md
deleted file mode 100644
index 5fed76fb..00000000
--- a/.changeset/auth-avatar-and-cancel.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-core': patch
----
-
-Harden the auth flow against two upstream auth-page issues. `deriveUserInfo` now drops placeholder `profile_picture` values (e.g. `https://none/`) and any non-`https` avatar URL (iOS ATS and Android cleartext defaults block `http` image loads anyway) so consumers no longer receive a broken avatar URL. Sign-in now treats an `access_denied` callback (the auth page's Cancel button) as a clean cancel instead of throwing; `state` is still validated before any token exchange on the success path. Cached user info is now validated with a `zod` schema on read instead of being blindly cast, so a corrupt or legacy cache entry can no longer surface wrong-typed fields to consumers.
diff --git a/.changeset/bible-card-version-picker-default.md b/.changeset/bible-card-version-picker-default.md
deleted file mode 100644
index 3ed692db..00000000
--- a/.changeset/bible-card-version-picker-default.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-ui': minor
----
-
-`BibleCard` now defaults `showVersionPicker` to `false`, matching the React Web SDK. The version picker trigger no longer renders and the built-in `BibleVersionPickerSheet` no longer mounts unless consumers pass `showVersionPicker` explicitly.
diff --git a/.changeset/default-bible-version-id-export.md b/.changeset/default-bible-version-id-export.md
deleted file mode 100644
index 0c082ab8..00000000
--- a/.changeset/default-bible-version-id-export.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-ui': minor
----
-
-Export `DEFAULT_BIBLE_VERSION_ID` (3034, Berean Standard Bible) from the UI entry so consumers can reference the SDK's default Bible version instead of hardcoding the numeric ID. The constant now backs the internal `defaultVersionId` fallbacks for `BibleCard`, `BibleReader`, and the picker sheets.
diff --git a/.changeset/export-component-prop-types.md b/.changeset/export-component-prop-types.md
deleted file mode 100644
index ddca1245..00000000
--- a/.changeset/export-component-prop-types.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-ui': minor
----
-
-Re-export component prop types from the UI entry so consumers can import them directly instead of re-deriving via `React.ComponentProps`. Adds `BibleCardProps`, `BibleReaderProps`, `BibleReaderSettingsSheetProps`, `BibleTextViewProps`, `VerseOfTheDayProps`, and `YouVersionAuthButtonProps`.
diff --git a/.changeset/pin-deps-supply-chain.md b/.changeset/pin-deps-supply-chain.md
deleted file mode 100644
index c67340f7..00000000
--- a/.changeset/pin-deps-supply-chain.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-ui': patch
----
-
-Pin runtime dependencies to exact versions (`@youversion/platform-react-ui`, `expo-localization`, `i18next`, `react-i18next`, `zustand`) as supply-chain protection, so consumer installs can never silently resolve a newer, potentially compromised release. Peer dependency ranges are unchanged.
diff --git a/.changeset/react-doctor-top-fixes.md b/.changeset/react-doctor-top-fixes.md
deleted file mode 100644
index fb619ff9..00000000
--- a/.changeset/react-doctor-top-fixes.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@youversion/platform-react-native-expo-core': patch
-'@youversion/platform-react-native-expo-ui': patch
----
-
-Fix the top issues flagged by React Doctor. Replace relative barrel imports (`../storage`, `../lib`, `../hooks`, `../i18n`) with direct module paths to trim the app bundle and speed startup. Fix a stale-closure risk in the auth bootstrap effect by holding the latest `setAuthState`/`refreshToken`/`clearAuthState` in a ref instead of silencing the exhaustive-deps warning, preserving mount-only behavior. Reset version-picker state during render (previous-prop comparison) instead of in an effect, removing a brief stale-UI frame on sheet reopen in both the DOM picker and the native picker sheet. Drop a dead duplicate `READER_SETTINGS_PERSIST_KEY` export from core storage.
diff --git a/.changeset/refactor-useeffect-anti-patterns.md b/.changeset/refactor-useeffect-anti-patterns.md
deleted file mode 100644
index 0dfdeed9..00000000
--- a/.changeset/refactor-useeffect-anti-patterns.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-ui': patch
----
-
-Refactor `useEffect` anti-patterns per React's "You Might Not Need an Effect" guidance. `BibleCard` and `BibleReader` now persist uncontrolled version/location to their MMKV-backed stores from the `useControllableState` `onChange` handler instead of a separate state-mirroring effect. `onChange` fires only when the value actually changes, so defaults are no longer written to storage on mount/hydration and there is a single source of persistence rather than a duplicated effect. `NativeSheet` resets its Android loader during render via previous-`openKey` comparison instead of in the imperative snap effect, eliminating a one-frame flash of the previous sheet content marked ready on repeated opens. No API changes; the only behavioral nuance is that storage stays empty until the user changes something (identical fallback UX).
diff --git a/.changeset/sdk-version-header-stamp.md b/.changeset/sdk-version-header-stamp.md
deleted file mode 100644
index 808d486e..00000000
--- a/.changeset/sdk-version-header-stamp.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-ui': patch
----
-
-Split dev and partner traffic in the `x-yvp-sdk` telemetry header. Every published build previously reported `ReactNativeSDK=Dev`, because the documented "release workflow rewrites the value" step never existed — so partner and internal traffic were indistinguishable. Published builds now report `ReactNativeSDK={version}` and source builds report `ReactNativeSDK={version}-dev`, matching the Web SDK's format so one telemetry rule (`endsWith('-dev')`) covers both SDKs. A `prepublishOnly` stamp (`scripts/stamp-sdk-version.cjs`) flips the build-channel flag in the compiled build and aborts the publish if it cannot confirm the channel. See ADR 0012.
diff --git a/.changeset/sheet-header-surface-parity.md b/.changeset/sheet-header-surface-parity.md
deleted file mode 100644
index b720b808..00000000
--- a/.changeset/sheet-header-surface-parity.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-ui': patch
----
-
-Match the version/chapter picker sheet header to the WebView surface (white in light mode, dark in dark mode) and keep the muted strip behind the search bar. Also corrects the dark sheet surface token to match the Web SDK background.
diff --git a/.changeset/sheet-max-width-wide-screens.md b/.changeset/sheet-max-width-wide-screens.md
deleted file mode 100644
index 2eefe023..00000000
--- a/.changeset/sheet-max-width-wide-screens.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@youversion/platform-react-native-expo-ui': patch
----
-
-Cap all Native Sheets (version picker, chapter picker, reader settings, footnotes) at a maximum width of 640, horizontally centered, on wide screens like iPad. Below that breakpoint sheets remain full-width. The cap is applied once in `NativeSheet` via a computed horizontal margin on `@gorhom/bottom-sheet`'s `style` prop, so the whole sheet surface (handle, header, content, footer) is capped while the backdrop still covers the full screen.
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8d43a868..3e8d523b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -8,8 +8,11 @@ on:
concurrency: ${{ github.workflow }}-${{ github.ref }}
# `id-token: write` is required so NPM Trusted Publishing can mint a short-lived
-# OIDC token at publish time. With trusted publishing configured on npm there's
-# no long-lived NPM_TOKEN to rotate, and every published tarball carries a
+# OIDC token at publish time. The handshake is pnpm's own: `changeset publish`
+# shells out to `pnpm publish`, and pnpm 11 publishes to the registry over HTTP
+# itself rather than delegating to the npm CLI, so the npm version on the runner
+# has no bearing on auth. With trusted publishing configured on npm there's no
+# long-lived NPM_TOKEN to rotate, and every published tarball carries a
# provenance attestation linking it to this exact workflow run.
permissions:
contents: write
@@ -30,11 +33,6 @@ jobs:
- uses: ./.github/actions/setup
- # Trusted publishing requires npm >= 11.5. Pin to latest to avoid the
- # OIDC handshake silently falling back to NPM_TOKEN on older npm.
- - name: Update npm to latest version
- run: npm install -g npm@latest
-
# No separate build step: `pnpm release` runs `turbo build` before
# `changeset publish`, so the build only happens on the publish path.
- name: Create Release Pull Request or Publish to NPM
@@ -50,12 +48,29 @@ jobs:
title: 'chore: version packages'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # A no-op under pnpm 11, kept as belt and braces. pnpm resolves its own
+ # settings from PNPM_CONFIG_* and ignores NPM_CONFIG_PROVENANCE, so
+ # what actually turns provenance on is pnpm's OIDC path auto-enabling
+ # it for public repos on GitHub Actions, which this repo is. That
+ # auto-detection is read from pnpm's source, not observed on a real
+ # run; no OIDC publish has ever executed for these package names.
+ # Until one has, keep this: it costs nothing if the inference is
+ # right, and silently loses attestations if it's wrong.
NPM_CONFIG_PROVENANCE: true
# Publishing auth comes solely from OIDC trusted publishing. We do not
# pass a long-lived NPM_TOKEN. An automation token bypasses 2FA, so a
- # standing secret widens the attack surface for little gain. If a
- # bootstrap publish needs it before trusted publishing is live, add
- # NODE_AUTH_TOKEN here as a temporary fallback and remove it after.
+ # standing secret widens the attack surface for little gain.
+ #
+ # If a bootstrap publish needs one before trusted publishing is live,
+ # NODE_AUTH_TOKEN on its own is not enough: pnpm never reads that
+ # variable. It only reaches pnpm through an .npmrc, which
+ # actions/setup-node writes (and points NPM_CONFIG_USERCONFIG at) only
+ # when it is given a `registry-url`, and .github/actions/setup does not
+ # set one. A working fallback therefore needs both halves:
+ # 1. `registry-url: 'https://registry.npmjs.org'` on the setup-node
+ # step in .github/actions/setup
+ # 2. `NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}` here
+ # Remove both once trusted publishing is live.
- name: Publish summary
if: steps.changesets.outputs.published == 'true'
diff --git a/AGENTS.md b/AGENTS.md
index 0609efef..7495780a 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -142,7 +142,7 @@ Keep `apps/example/metro.config.js` minimal — just `getDefaultConfig(__dirname
## Exports
-**UI** (`@youversion/platform-react-native-expo-ui`): `YouVersionProvider`, `BibleCard`, `BibleChapterPickerSheet`, `BibleReader`, `BibleReaderSettingsSheet`, `BibleTextView`, `BibleVersionPickerSheet`, `VerseOfTheDay`, `YouVersionAuthButton`, and the `DEFAULT_BIBLE_VERSION_ID` constant (3034, Berean Standard Bible)
+**UI** (`@youversion/platform-react-native-expo-ui`): `YouVersionProvider`, `BibleCard`, `BibleChapterPickerSheet`, `BibleReader`, `BibleReaderSettingsSheet`, `BibleTextView`, `BibleVersionPickerSheet`, `VerseOfTheDay`, and `YouVersionAuthButton`
**Core** (`@youversion/platform-react-native-expo-core`): `YouVersionProvider` (installation id + optional auth), `useYouVersion`, `useYVAuth`, `mmkvStorage`, and auth types (`AuthConfig`, `AuthScope`, `YVUserInfo`)
diff --git a/CONTEXT.md b/CONTEXT.md
index 8a7cbc0d..dc6f12c8 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -87,7 +87,7 @@ The visible controls around reader content, including chapter navigation, versio
_Avoid_: Toolbar when referring to product behavior rather than the Web SDK component name
**Compiled Distribution**:
-The published package ships a compiled `build/` output (`expo-module build`, plain `tsc` → JS + `.d.ts`), not raw source. `tsc` preserves the `'use dom'` directive and the Expo Metro plugin processes it from compiled files in `node_modules`, so Expo DOM Components work when installed from npm. In-repo dev still resolves TypeScript source directly (`main` → `src/`); `publishConfig` swaps to `build/` at publish time, applied by pnpm (`pnpm publish` and `pnpm pack`) but not by raw `npm publish`. See ADR 0011 (supersedes the earlier source-only model).
+The published package ships a compiled `build/` output (`expo-module build`, plain `tsc` → JS + `.d.ts`), not raw source. `tsc` preserves the `'use dom'` directive and the Expo Metro plugin processes it from compiled files in `node_modules`, so Expo DOM Components work when installed from npm. In-repo dev still resolves TypeScript source directly (`main` → `src/`); `publishConfig` swaps to `build/` at publish time, applied by pnpm (`pnpm publish` and `pnpm pack`) but not by raw `npm publish`. The import surface is sealed to the root entry point via a root-only `exports` map (dev → `src/index.ts`, publish → `build/index.js`), so deep imports into internal files are not part of the API. See ADR 0011 (supersedes the earlier source-only model).
_Avoid_: Source-only, "a compiled build strips the directive"
**SDK Attribution Header**:
diff --git a/README.md b/README.md
index 8cfb8a9f..2d9d962f 100644
--- a/README.md
+++ b/README.md
@@ -100,13 +100,13 @@ Native SDK strings follow the device locale by default; see the [localization gu
Display a verse range or single verse with `BibleTextView`:
```tsx
-import { BibleTextView, DEFAULT_BIBLE_VERSION_ID } from '@youversion/platform-react-native-expo-ui'
+import { BibleTextView } from '@youversion/platform-react-native-expo-ui'
function VerseScreen() {
return (
)
}
@@ -117,11 +117,11 @@ function VerseScreen() {
Display a Bible card with a verse and reader controls:
```tsx
-import { BibleCard, DEFAULT_BIBLE_VERSION_ID } from '@youversion/platform-react-native-expo-ui'
+import { BibleCard } from '@youversion/platform-react-native-expo-ui'
-// DEFAULT_BIBLE_VERSION_ID is 3034 (Berean Standard Bible); find other IDs at platform.youversion.com
+// 3034 = Berean Standard Bible (BSB); find other IDs at platform.youversion.com
function CardScreen() {
- return
+ return
}
```
@@ -134,11 +134,11 @@ function CardScreen() {
`BibleReader` gives you a full Bible reading experience, ready to drop in as a tab or full screen:
```tsx
-import { BibleReader, DEFAULT_BIBLE_VERSION_ID } from '@youversion/platform-react-native-expo-ui'
+import { BibleReader } from '@youversion/platform-react-native-expo-ui'
-// DEFAULT_BIBLE_VERSION_ID is 3034 (Berean Standard Bible); find other IDs at platform.youversion.com
+// 3034 = Berean Standard Bible (BSB); find other IDs at platform.youversion.com
function ReaderScreen() {
- return
+ return
}
```
@@ -150,7 +150,7 @@ To present your own picker UI instead of the built-in sheets, pass `onChapterPic
```tsx
{
// present your own version picker
}}
@@ -162,11 +162,11 @@ The standalone sheets are also exported (`BibleChapterPickerSheet`, `BibleVersio
### Verse of the Day
```tsx
-import { VerseOfTheDay, DEFAULT_BIBLE_VERSION_ID } from '@youversion/platform-react-native-expo-ui'
+import { VerseOfTheDay } from '@youversion/platform-react-native-expo-ui'
-// DEFAULT_BIBLE_VERSION_ID is 3034 (Berean Standard Bible); find other IDs at platform.youversion.com
+// 3034 = Berean Standard Bible (BSB); find other IDs at platform.youversion.com
function VotdScreen() {
- return
+ return
}
```
diff --git a/docs/adr/0011-compiled-distribution.md b/docs/adr/0011-compiled-distribution.md
index 37fbb723..e30dcb24 100644
--- a/docs/adr/0011-compiled-distribution.md
+++ b/docs/adr/0011-compiled-distribution.md
@@ -28,6 +28,32 @@ The build tool is [`expo-module-scripts`](https://www.npmjs.com/package/expo-mod
- `publishConfig` swaps `main` / `types` to `build/`, and `files: ["build"]` keeps source out of the tarball, so the published package ships compiled JS plus real `.d.ts`.
- Releases MUST go through `pnpm changeset publish` (the configured pipeline). `pnpm publish` applies the `publishConfig` field overrides; raw `npm publish` does not — `main` would stay `src/index.ts` while `files: ["build"]` excludes `src/`, so the tarball would be broken (entry point missing or unable to resolve its imports), not a clean source ship. See [PUBLISHING.md](../../PUBLISHING.md).
+## Sealed import surface
+
+Both packages declare a root-only `exports` map. The only entry points are `"."` (the package root) and `"./package.json"`; there are no subpath entries, so the supported way to consume either package is `import … from '@youversion/platform-react-native-expo-ui'` / `-core`, and a deep import like `@youversion/platform-react-native-expo-ui/build/dom/bible-card` is not part of the public API.
+
+Why seal it:
+
+- **Raw DOM components are not package API.** Only the barrel (`src/index.ts` → `build/index.js`) is public. DOM component files exist purely as the WebView-backed implementation of the native wrappers.
+- **Deep imports would freeze the internal file layout.** Without `exports`, `build/dom/*`, `build/native/*`, and `build/lib/*` are all reachable, so any consumer importing them turns our directory structure into a compatibility contract. The map keeps refactors of internal layout non-breaking.
+
+### Enforcement boundary (important)
+
+The map is enforced strictly by Node's own resolver and by TypeScript, and loosely by Metro:
+
+- **Node resolution** hard-errors on an unmatched subpath: `require.resolve('@youversion/platform-react-native-expo-ui/build/dom/bible-card')` throws `ERR_PACKAGE_PATH_NOT_EXPORTED`. Same for any strict `exports`-aware bundler (webpack, Vite, esbuild, Rollup with default settings).
+- **TypeScript** (`moduleResolution` `node16`/`nodenext`/`bundler`) refuses to resolve types for a deep path, so a consumer writing a deep import gets a compile error in-editor and in CI typecheck. This is the primary developer-facing guardrail — the import is rejected before it can ship.
+- **Metro does _not_ enforce it.** Even with `resolver.unstable_enablePackageExports: true` (the Expo SDK 56 default), Metro falls back to plain filesystem resolution for a subpath that the `exports` map does not match, instead of hard-erroring the way Node does. Verified: a fresh SDK 56 app installing the packed tarballs bundles a deep import into `build/dom/*` without error. So at the RN bundler level a determined consumer can still reach internal files at runtime; the `exports` map does not make that physically impossible, it makes it unsupported and type-rejected. If we ever need Metro-level enforcement we would have to remove the files from the tarball or split internals into a separate unpublished package — out of scope here.
+
+Net: the seal reliably stops deep imports from being _written_ (TypeScript) and from resolving under Node and standard web bundlers; it documents internal files as non-API; it does not physically block Metro's loose runtime fallback.
+
+Dev vs. publish, same swap as `main`/`types`:
+
+- Top-level `exports["."]` points at `./src/index.ts` (both `types` and `default`), so in-repo Metro and `tsc` resolve TypeScript source directly — no build step for local dev or the example app.
+- `publishConfig.exports` overrides `"."` to `types: ./build/index.d.ts`, `default: ./build/index.js`, applied by `pnpm publish` exactly like the `main`/`types` overrides. `"./package.json"` stays exposed in both.
+
+Timing: loosening an `exports` map later (adding subpaths) is additive and non-breaking, while tightening one later (removing subpaths consumers already import) is breaking. Sealing before the first real release (0.9.1) means the surface starts minimal and can only widen, never narrow, so no consumer ever depends on an internal path we later want to remove.
+
## Consequences
- Gains real `.d.ts` and removes 0002's `moduleResolution: bundler`-only constraint for consumers.
diff --git a/docs/adr/0012-sdk-version-stamp-on-publish.md b/docs/adr/0012-sdk-version-stamp-on-publish.md
index 36c3c644..bcf15b23 100644
--- a/docs/adr/0012-sdk-version-stamp-on-publish.md
+++ b/docs/adr/0012-sdk-version-stamp-on-publish.md
@@ -49,6 +49,7 @@ We land on the same **outcome** as the Web SDK via a different mechanism, becaus
- **One `.cjs` file** (`scripts/stamp-sdk-version.cjs`) holds both the pure transform and the file IO. The IO runs only under `require.main === module`. `packages/ui` has no `"type": "module"` yet emits ESM-syntax `build/` output, so a Node script cannot cleanly `import` the compiled file; a self-contained CJS script side-steps the module-system mismatch and runs natively at publish with no build step of its own.
- **Wired into `prepublishOnly`, not `release.yml`.** Folding it into the build script gives deterministic build-then-stamp ordering (immune to npm/pnpm lifecycle-order quirks) and keeps the mechanism visible from `package.json` rather than buried in a workflow. A CI-only step would recreate the original failure mode: behavior hidden in the workflow, invisible from the source file.
- **The guard asserts the positive stamp, and fails closed.** The transform throws unless it finds exactly one `IS_PUBLISH_BUILD = false` anchor, then asserts post-stamp that `= true` is present and `= false` is gone. It deliberately does **not** check that `-dev` is absent: the compiled ternary keeps the suffix in its dead else branch in _every_ build, published or not, so a `-dev` match would false-positive on every artifact. Checking only that `= false` disappeared would fail **open** — if tooling ever folded or minified the constant away, neither literal would survive and a dev build would sail through. Requiring the stamp means a build whose channel cannot be confirmed aborts the publish.
+- **Re-running the publish is safe, because the rebuild precedes the stamp.** `expo-module prepublishOnly` is `expo-module clean && expo-module build`, so `build/` is deleted and regenerated from source — anchor back at `= false` — before the stamp runs. A retried release (re-run from the Actions UI, or a second `pnpm publish`) therefore meets exactly one anchor again, not the `= true` file left behind by the previous attempt. The transform itself is deliberately **not** idempotent: `stampPublishBuild` on already-stamped input throws `found 0`, and `node scripts/stamp-sdk-version.cjs` run twice with no rebuild between fails the same way. That is the guard above doing its job, not a retry hazard — nothing on the publish path reaches the stamp without a rebuild in front of it.
- **The anchor is checked against real `tsc` output in CI.** `SENTINEL` matches _compiled_ text, so it can drift away from source with every fixture-based unit test still green — and the first sign would be `changeset publish` throwing mid-release, after `packages/core` may already be on npm (a partial release). `src/lib/__tests__/sdk-version-stamp.test.ts` therefore transpiles the real `src/lib/sdk-version.ts` and asserts the anchor survives, moving that failure to the PR that causes it.
- **`pnpm pack` does not stamp.** `prepublishOnly` runs on `pnpm publish` only — `pnpm pack` runs neither the build nor the stamp, so a packed tarball reports `-dev` (or ships empty, if `build/` is absent). To reproduce a publish-identical tarball off-CI, run the publish steps by hand:
diff --git a/package.json b/package.json
index f4b08f25..9c4e6e61 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"url": "https://github.com/youversion/platform-sdk-reactnative-expo.git"
},
"scripts": {
- "build": "turbo build",
+ "build": "CI=true turbo build",
"dev": "turbo dev",
"typecheck": "turbo typecheck",
"test": "turbo test",
diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md
index 84742141..d07e1e07 100644
--- a/packages/core/CHANGELOG.md
+++ b/packages/core/CHANGELOG.md
@@ -1,6 +1,6 @@
# @youversion/platform-react-native-expo-core
-## 1.0.0
+## 0.9.1
Initial release. Installation id, optional PKCE authentication, and storage adapters for the YouVersion Platform React Native (Expo) SDK.
@@ -9,3 +9,13 @@ Initial release. Installation id, optional PKCE authentication, and storage adap
- `YouVersionProvider` — installation id plus optional `auth` config (forwarded by the UI provider), and the `useYouVersion` hook
- PKCE OAuth via `useYVAuth`, with auth types `AuthConfig`, `AuthScope`, and `YVUserInfo`
- Token storage in `expo-secure-store`; token expiry and cached user info in MMKV via `mmkvStorage`
+
+**Auth hardening**
+
+- User info drops placeholder and non-`https` avatar URLs (blocked by iOS ATS and Android cleartext defaults anyway), so consumers never receive a broken picture URL
+- Canceling sign-in (`access_denied` callback) is treated as a clean cancel rather than an error
+- Cached user info is validated with a zod schema on read, so a corrupt or legacy cache entry can't surface wrong-typed fields
+
+### Package surface
+
+- Imports are restricted to the package root via an `exports` map — import everything from `@youversion/platform-react-native-expo-core`. Deep imports (e.g. into `build/`) are not part of the public API.
diff --git a/packages/core/README.md b/packages/core/README.md
index e73801c7..8c09b112 100644
--- a/packages/core/README.md
+++ b/packages/core/README.md
@@ -1,6 +1,19 @@
+
+
# @youversion/platform-react-native-expo-core
-Core for the YouVersion Platform React Native (Expo) SDK: installation id, optional PKCE OAuth (`useYVAuth`), and storage (`expo-secure-store` + MMKV). Bible UI components live in [`@youversion/platform-react-native-expo-ui`](https://github.com/youversion/platform-sdk-reactnative-expo).
+Auth and storage primitives for the YouVersion Platform React Native (Expo) SDK: installation id, optional PKCE OAuth, and token storage.
+
+## When to use this package
+
+Use `@youversion/platform-react-native-expo-core` when you need:
+
+- ✅ Sign-in via optional PKCE OAuth (`useYVAuth`, `auth` config on the provider)
+- ✅ Token storage handled for you (`expo-secure-store` + MMKV)
+
+❌ Want ready-made Bible UI instead? Use [@youversion/platform-react-native-expo-ui](https://www.npmjs.com/package/@youversion/platform-react-native-expo-ui).
+
+Install this package directly alongside the UI package. The UI package already depends on core, but a direct dependency is what lets TypeScript resolve the auth APIs, so add it any time your app touches auth. Import Bible components from the UI package; import `useYVAuth` from core.
## Install
@@ -8,12 +21,38 @@ Core for the YouVersion Platform React Native (Expo) SDK: installation id, optio
npx expo install @youversion/platform-react-native-expo-core
```
-Most apps install this automatically as a dependency of `@youversion/platform-react-native-expo-ui`. Requires Expo SDK 56+, React 19, and a dev build (not Expo Go). Peer dependencies are listed in `package.json`.
+Requires Expo SDK 56+, React 19, and a [development build](https://docs.expo.dev/develop/development-builds/introduction/) (not Expo Go — the SDK relies on native modules). Peer dependencies are listed in [`package.json`](./package.json).
+
+Get your App Key at [platform.youversion.com](https://platform.youversion.com/).
-## Documentation
+## Documentation and API Reference
-Full setup, usage, and examples: **[github.com/youversion/platform-sdk-reactnative-expo](https://github.com/youversion/platform-sdk-reactnative-expo#readme)**
+- [React Native (Expo) SDK Quick Start](https://developers.youversion.com/sdks/react-native)
+
+## Usage
+
+Configure `auth` on the provider, then read auth state with `useYVAuth`:
+
+```tsx
+import { Text } from 'react-native'
+import { YouVersionProvider, useYVAuth } from '@youversion/platform-react-native-expo-core'
+
+function Profile() {
+ const { isAuthenticated, userInfo, signIn, signOut } = useYVAuth()
+ return {isAuthenticated ? userInfo?.name : 'Signed out'}
+}
+
+export default function App() {
+ return (
+
+
+
+ )
+}
+```
## License
-[Apache-2.0](./LICENSE)
+This SDK is licensed under [Apache 2.0](./LICENSE).
+
+Licensing information for the Bible versions is available at the [YouVersion Platform](https://platform.youversion.com/) site.
diff --git a/packages/core/package.json b/packages/core/package.json
index 05db035d..369a1489 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@youversion/platform-react-native-expo-core",
- "version": "0.9.0",
+ "version": "0.9.1",
"description": "YouVersion Platform core for React Native (Expo) — installation id, optional PKCE auth, and storage.",
"keywords": [
"youversion",
@@ -20,6 +20,13 @@
"license": "Apache-2.0",
"main": "src/index.ts",
"types": "src/index.ts",
+ "exports": {
+ ".": {
+ "types": "./src/index.ts",
+ "default": "./src/index.ts"
+ },
+ "./package.json": "./package.json"
+ },
"files": [
"build",
"README.md",
@@ -27,7 +34,14 @@
],
"publishConfig": {
"main": "build/index.js",
- "types": "build/index.d.ts"
+ "types": "build/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./build/index.d.ts",
+ "default": "./build/index.js"
+ },
+ "./package.json": "./package.json"
+ }
},
"scripts": {
"build": "expo-module build",
diff --git a/packages/ui/CHANGELOG.md b/packages/ui/CHANGELOG.md
index 3dc211cd..3d7ee554 100644
--- a/packages/ui/CHANGELOG.md
+++ b/packages/ui/CHANGELOG.md
@@ -1,6 +1,6 @@
# @youversion/platform-react-native-expo-ui
-## 1.0.0
+## 0.9.1
Initial release. Drop YouVersion Bible content into an Expo app on iOS and Android, with native bottom sheets, theming, and optional sign-in. Built on the [React Web SDK](https://github.com/youversion/platform-sdk-react) wrapped as [Expo DOM Components](https://docs.expo.dev/guides/dom-components/), with native affordances layered on top.
@@ -17,6 +17,8 @@ Initial release. Drop YouVersion Bible content into an Expo app on iOS and Andro
- `BibleReader` — a full reading experience with built-in chapter and version pickers; bring your own picker UI via `onChapterPickerPress` / `onVersionPickerPress`
- Standalone sheets for advanced flows: `BibleChapterPickerSheet`, `BibleVersionPickerSheet`, `BibleReaderSettingsSheet`
+Every prop and option for these components is documented at [developers.youversion.com/sdks/react-native](https://developers.youversion.com/sdks/react-native).
+
**Provider & theming**
- `YouVersionProvider` — single root provider supplying your `appKey`, resolved theme, and native sheet support
@@ -30,3 +32,17 @@ Initial release. Drop YouVersion Bible content into an Expo app on iOS and Andro
- Footnotes, chapter, and version pickers open in native bottom sheets via `@gorhom/bottom-sheet`
- WebView pre-warming so sheets open without a cold-start flash
+- Sheets cap at 640 wide and center on large screens like iPad; full-width below that breakpoint
+
+**Types**
+
+- Prop types are exported for each component, e.g. `BibleCardProps`, `BibleReaderProps`, `BibleTextViewProps`
+
+**Attribution**
+
+- SDK traffic is identified to YouVersion in the `x-yvp-sdk` header as `ReactNativeSDK={version}`; builds running from source report `{version}-dev`, matching the Web SDK's format
+
+### Package surface
+
+- Only the package root is importable — import everything from `@youversion/platform-react-native-expo-ui`. If you want to see how it all works, read the source on [GitHub](https://github.com/youversion/platform-sdk-reactnative-expo).
+- Runtime dependencies ship pinned to exact versions, so an install resolves exactly what was published and tested rather than silently picking up a newer release. Peer dependency ranges are unchanged.
diff --git a/packages/ui/README.md b/packages/ui/README.md
index 0d278a0d..5937d889 100644
--- a/packages/ui/README.md
+++ b/packages/ui/README.md
@@ -1,8 +1,19 @@
+
+
# @youversion/platform-react-native-expo-ui
-YouVersion Platform Bible components for React Native (Expo): `BibleReader`, `BibleCard`, `BibleTextView`, `VerseOfTheDay`, theming, and native bottom sheets. Built on the [React Web SDK](https://github.com/youversion/platform-sdk-react) via [Expo DOM Components](https://docs.expo.dev/guides/dom-components/).
+Drop-in YouVersion Bible components for React Native (Expo) apps. Built on the React Web SDK via [Expo DOM Components](https://docs.expo.dev/guides/dom-components/).
+
+## When to use this package
+
+Use `@youversion/platform-react-native-expo-ui` when you need:
-Pairs with `@youversion/platform-react-native-expo-core` (installed alongside).
+- ✅ Pre-built Bible components for Expo: `BibleCard`, `BibleReader`, `BibleTextView`, `VerseOfTheDay`
+- ✅ Version/chapter picker and reader-settings bottom sheets, plus `YouVersionAuthButton`
+- ✅ Light/dark theming across every component, from one `YouVersionProvider` at your app root
+- ✅ Minimal setup: install, wrap, render
+
+❌ Only need auth or storage APIs, with no UI? Use [@youversion/platform-react-native-expo-core](https://www.npmjs.com/package/@youversion/platform-react-native-expo-core) directly.
## Install
@@ -10,12 +21,35 @@ Pairs with `@youversion/platform-react-native-expo-core` (installed alongside).
npx expo install @youversion/platform-react-native-expo-ui @youversion/platform-react-native-expo-core
```
-Requires Expo SDK 56+, React 19, and a [dev build](https://docs.expo.dev/develop/development-builds/introduction/) (not Expo Go). Peer dependencies are listed in `package.json`.
+Requires Expo SDK 56+, React 19, and a [development build](https://docs.expo.dev/develop/development-builds/introduction/) (not Expo Go — the SDK relies on native modules). Peer dependencies are listed in [`package.json`](./package.json).
+
+Get your App Key at [platform.youversion.com](https://platform.youversion.com/).
+
+## Usage
-## Documentation
+Keep `GestureHandlerRootView` outside `YouVersionProvider`, then render components inside:
-Full setup, usage, and examples: **[github.com/youversion/platform-sdk-reactnative-expo](https://github.com/youversion/platform-sdk-reactnative-expo#readme)**
+```tsx
+import { GestureHandlerRootView } from 'react-native-gesture-handler'
+import { YouVersionProvider, BibleCard } from '@youversion/platform-react-native-expo-ui'
+
+export default function App() {
+ return (
+
+
+
+
+
+ )
+}
+```
+
+## Documentation and API Reference
+
+- [React Native (Expo) SDK Quick Start](https://developers.youversion.com/sdks/react-native)
## License
-[Apache-2.0](./LICENSE)
+This SDK is licensed under [Apache 2.0](./LICENSE).
+
+Licensing information for the Bible versions is available at the [YouVersion Platform](https://platform.youversion.com/) site.
diff --git a/packages/ui/package.json b/packages/ui/package.json
index a12964c3..f533df53 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@youversion/platform-react-native-expo-ui",
- "version": "0.9.0",
+ "version": "0.9.1",
"description": "YouVersion Platform Bible components for React Native (Expo) — reader, verse cards, Verse of the Day, theming, and native sheets.",
"keywords": [
"youversion",
@@ -20,6 +20,13 @@
"license": "Apache-2.0",
"main": "src/index.ts",
"types": "src/index.ts",
+ "exports": {
+ ".": {
+ "types": "./src/index.ts",
+ "default": "./src/index.ts"
+ },
+ "./package.json": "./package.json"
+ },
"files": [
"build",
"README.md",
@@ -27,7 +34,14 @@
],
"publishConfig": {
"main": "build/index.js",
- "types": "build/index.d.ts"
+ "types": "build/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./build/index.d.ts",
+ "default": "./build/index.js"
+ },
+ "./package.json": "./package.json"
+ }
},
"scripts": {
"build": "expo-module build",
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index 480cd88c..17f0acef 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -9,7 +9,6 @@ export {
YouVersionAuthButton,
YouVersionProvider,
} from './native'
-export { DEFAULT_BIBLE_VERSION_ID } from './lib/constants'
export type {
BibleCardProps,
BibleChapterPickerSheetProps,