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

AdapterDefault behaviour
createExpoBiometricsisAvailable() → available; authenticate() → success
createExpoCamerarequestPermission() → granted; takePicture() → placeholder asset
createExpoSecureStoreIn-memory key-value map; survives the session, not the process
createExpoHapticsAll methods are no-ops (silent success)
createExpoNotificationsrequestPermission() → granted; getToken()'dev-push-token'
createExpoPurchasesgetProducts() → empty; purchase() → success
createExpoPermissionsAll checks and requests return 'granted'
createExpoSharingshare(){ action: 'sharedAction' }
createExpoClipboardIn-memory string; hasString() reflects current value
createExpoLocationReturns a fixed position: { lat: 48.8566, lon: 2.3522 } (Paris)
createExpoMediaLibrarypickImage() / pickVideo() → empty array
createExpoMapRenders a <View> placeholder (no native map tile)
createExpoWebBrowseropen(){ type: 'dismiss' } immediately
createExpoContactsgetAll() / search() → empty array
createExpoReviewisAvailable() → 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-haptics

    3. 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
PurposeRunning the full app without native modulesWriting automated tests
Factory namesSame as production (createExpoX)Different (createInMemoryX)
State inspectionNo state object exposedEvery double has a state object for assertions
Mock responsesNot applicableMockApiClient with mockResponse and requests
createTestAppNot availablecreateTestApp wires everything in one call

Use /dev to develop and demo. Use /testing to write tests with assertions.