Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions .github/workflows/android-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:
- 'nitrogen/generated/android/**'
- 'cpp/**'
- 'android/**'
- '**/bun.lock'
- '**/yarn.lock'
- '**/react-native.config.js'
- '**/nitro.json'
pull_request:
Expand All @@ -25,7 +25,7 @@ on:
- '**/nitrogen/generated/android/**'
- 'cpp/**'
- 'android/**'
- '**/bun.lock'
- '**/yarn.lock'
- '**/react-native.config.js'
- '**/nitro.json'
workflow_dispatch:
Expand All @@ -44,14 +44,19 @@ jobs:
arch: [new, old]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'yarn'

- name: Install dependencies (yarn)
run: yarn install --frozen-lockfile

- name: Install dependencies (bun)
run: bun install
- name: Install example dependencies (yarn)
run: cd example && yarn install --frozen-lockfile

- name: Generate Nitro modules (codegen)
run: |
npm run codegen
run: yarn codegen

- name: Disable new architecture in gradle.properties
if: matrix.arch == 'old'
Expand Down
16 changes: 9 additions & 7 deletions .github/workflows/ios-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ on:
- 'cpp/**'
- 'ios/**'
- '**/Podfile.lock'
- '**/bun.lock'
- '**/yarn.lock'
- '**/*.podspec'
- '**/react-native.config.js'
- '**/nitro.json'
Expand All @@ -32,7 +32,7 @@ on:
- 'cpp/**'
- 'ios/**'
- '**/Podfile.lock'
- '**/bun.lock'
- '**/yarn.lock'
- '**/*.podspec'
- '**/react-native.config.js'
- '**/nitro.json'
Expand All @@ -55,18 +55,20 @@ jobs:
arch: [new, old]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'yarn'
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: 16.4

- name: Install dependencies (bun)
run: bun install
- name: Install dependencies (yarn)
run: yarn install --frozen-lockfile

- name: Generate Nitro modules (codegen)
run: |
npm run codegen
run: yarn codegen

- name: Disable new architecture in Podfile
if: matrix.arch == 'old'
Expand Down
23 changes: 8 additions & 15 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,17 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun.js
uses: oven-sh/setup-bun@v2
- name: Setup Node.js
uses: actions/setup-node@v4
with:
bun-version: latest
- name: Cache bun dependencies
id: bun-cache
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-
node-version: '22'
cache: 'yarn'

- name: Install npm dependencies (bun)
run: bun install
- name: Install npm dependencies (yarn)
run: yarn install --frozen-lockfile

- name: Build lib
run: bun run build
run: yarn build

- name: Release
env:
Expand All @@ -52,4 +45,4 @@ jobs:
GIT_AUTHOR_EMAIL: '${{ github.actor }}@users.noreply.github.com'
GIT_COMMITTER_NAME: ${{ github.actor }}
GIT_COMMITTER_EMAIL: '${{ github.actor }}@users.noreply.github.com'
run: bun release
run: yarn release
85 changes: 81 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,86 @@ No manual linking is required. Nitro handles platform registration via autolinki
> [!TIP]
> Use `includeValue: false` during reads when you only care about metadata—this keeps plaintext out of memory and speeds up list views.

## ⚡️ Quick start
## ⚛️ React Hooks API (Recommended)

For a modern, reactive approach with automatic memory management and loading states, use the dedicated hooks:

```tsx
import { Text, View, ActivityIndicator } from 'react-native'
import {
useSecureStorage,
useSecurityAvailability,
} from 'react-native-sensitive-info'

// Use hooks directly in any component - no provider needed!
function YourComponent() {
// Fetch and manage all secrets in a service (with CRUD)
const {
items,
isLoading,
error,
saveSecret,
removeSecret,
} = useSecureStorage({ service: 'myapp', includeValues: true })

// Query device security capabilities (cached automatically)
const { data: capabilities } = useSecurityAvailability()

if (isLoading) return <ActivityIndicator />
if (error) return <Text>Error: {error.message}</Text>

return (
<View>
{items.map(item => (
<Text key={item.key}>
{item.key}: {item.value} ({item.metadata.securityLevel})
</Text>
))}
<Text>
Biometry available: {capabilities?.biometry ? 'Yes' : 'No'}
</Text>
</View>
)
}
```

### Key hooks

| Hook | Use Case | Returns |
| --- | --- | --- |
| `useSecureStorage()` | Manage all secrets in a service (list, add, remove) | `{ items, isLoading, error, saveSecret, removeSecret, clearAll, refreshItems }` |
| `useSecretItem()` | Fetch a single secret | `{ data, isLoading, error, refetch }` |
| `useSecret()` | Single secret + mutations | `{ data, isLoading, error, saveSecret, deleteSecret, refetch }` |
| `useHasSecret()` | Check if secret exists (lightweight) | `{ data (boolean), isLoading, error, refetch }` |
| `useSecurityAvailability()` | Query device capabilities (cached) | `{ data, isLoading, error, refetch }` |

### Best practices

- **Memory leak prevention** — All hooks automatically cancel requests and clean up resources on unmount.
- **Conditional fetching** — Use `skip: true` to prevent unnecessary operations:

```tsx
const { data } = useSecretItem('token', { skip: !isAuthenticated })
```

- **Optimize list views** — Fetch metadata only to avoid decryption overhead:

```tsx
const { items } = useSecureStorage({ includeValues: false })
```

- **Share capabilities** — Query independently and results are cached automatically:

```tsx
// Each component queries independently (results cached automatically)
const { data: capabilities1 } = useSecurityAvailability()
const { data: capabilities2 } = useSecurityAvailability()
// Same cached result, no duplicate native calls
```

For comprehensive examples and advanced patterns, see [`HOOKS.md`](./HOOKS.md).

## Imperative API

```tsx
import React, { useEffect } from 'react'
Expand Down Expand Up @@ -137,8 +216,6 @@ export function SecureTokenExample() {
void SensitiveInfo.clearService({ service: 'auth' })
```

## 📚 API reference

All functions live at the top level export and return Promises.

| Method | Signature | Description |
Expand All @@ -161,7 +238,7 @@ All functions live at the top level export and return Promises.

Android automatically enforces Class 3 biometrics whenever the hardware supports them, falling back to the strongest available authenticator on older devices.

See `src/views/sensitive-info.nitro.ts` for full TypeScript definitions.
See `src/sensitive-info.nitro.ts` for full TypeScript definitions.

## 🔐 Access control & metadata

Expand Down
1 change: 1 addition & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
module.exports = {
plugins: ['babel-plugin-react-compiler'],
presets: ['module:@react-native/babel-preset'],
}
Loading
Loading