Dev Mode
What is dev mode?
The ./dev subpath exports the same factory names as the individual Expo adapter subpaths, but every factory is backed by an in-memory implementation. No native modules are compiled. No device hardware is accessed.
Use it when:
- Running in Expo Go (native modules are not available)
- Running on a simulator that lacks real hardware (biometrics, camera, location)
- Running in CI where there is no device at all
Import
import {
createExpoBiometrics,
createExpoCamera,
createExpoSecureStore,
createExpoHaptics,
createExpoNotifications,
createExpoPurchases,
createExpoPermissions,
createExpoSharing,
createExpoClipboard,
createExpoLocation,
createExpoMediaLibrary,
createExpoMap,
createExpoWebBrowser,
createExpoContacts,
createExpoReview,
} from '@objectifthunes/limestone-sdk/dev';
The factory names are identical to the production subpaths. Your defineConfig call does not change at all.
Zero config
Pass the factories straight into defineConfig. No extra setup, no environment variables.
import { defineConfig, defineTheme } from '@objectifthunes/limestone-sdk';
import {
createExpoBiometrics,
createExpoSecureStore,
createExpoHaptics,
createExpoNotifications,
createExpoPermissions,
} from '@objectifthunes/limestone-sdk/dev';
const config = defineConfig({
theme: myTheme,
api: {
baseUrl: 'https://api.example.com',
auth: {
refreshEndpoint: '/auth/refresh',
onUnauthorized: () => router.push('/login'),
},
},
adapters: {
biometrics: createExpoBiometrics(),
storage: createExpoSecureStore(),
haptics: createExpoHaptics(),
notifications: createExpoNotifications(),
permissions: createExpoPermissions(),
// register only the adapters your app uses
},
});
export default function App() {
return (
<LimestoneProvider config={config}>
<RootNavigator />
</LimestoneProvider>
);
}
Default behaviour of each double
| Adapter | Default behaviour |
|---|---|
createExpoBiometrics | isAvailable() → available; authenticate() → success |
createExpoCamera | requestPermission() → granted; takePicture() → placeholder asset |
createExpoSecureStore | In-memory key-value map; survives the session, not the process |
createExpoHaptics | All methods are no-ops (silent success) |
createExpoNotifications | requestPermission() → granted; getToken() → 'dev-push-token' |
createExpoPurchases | getProducts() → empty; purchase() → success |
createExpoPermissions | All checks and requests return 'granted' |
createExpoSharing | share() → { action: 'sharedAction' } |
createExpoClipboard | In-memory string; hasString() reflects current value |
createExpoLocation | Returns a fixed position: { lat: 48.8566, lon: 2.3522 } (Paris) |
createExpoMediaLibrary | pickImage() / pickVideo() → empty array |
createExpoMap | Renders a <View> placeholder (no native map tile) |
createExpoWebBrowser | open() → { type: 'dismiss' } immediately |
createExpoContacts | getAll() / search() → empty array |
createExpoReview | isAvailable() → true; requestReview() → no-op |
Transitioning to production
When you are ready to ship on real devices, swap the import path from /dev to the individual Expo subpaths.
1. Replace the import
// Before — dev mode
import {
createExpoBiometrics,
createExpoSecureStore,
createExpoHaptics,
} from '@objectifthunes/limestone-sdk/dev';
// After — production
import { createExpoBiometrics } from '@objectifthunes/limestone-sdk/expo-biometrics';
import { createExpoSecureStore } from '@objectifthunes/limestone-sdk/expo-secure-store';
import { createExpoHaptics } from '@objectifthunes/limestone-sdk/expo-haptics';2. Install the Expo modules you need
pnpm add expo-local-authentication expo-secure-store expo-haptics3. Rebuild the native project
npx expo prebuild
npx expo run:ios
# or
npx expo run:android The defineConfig call and every hook that consumes the adapters stay exactly the same. Only the import path changes.
Dev mode vs testing doubles
/dev | /testing | |
|---|---|---|
| Purpose | Running the full app without native modules | Writing automated tests |
| Factory names | Same as production (createExpoX) | Different (createInMemoryX) |
| State inspection | No state object exposed | Every double has a state object for assertions |
| Mock responses | Not applicable | MockApiClient with mockResponse and requests |
| createTestApp | Not available | createTestApp wires everything in one call |
Use /dev to develop and demo. Use /testing to write tests with assertions.