Skip to content

Expo: op-sqlite driver

openOpSqliteDriver names the @op-engineering/op-sqlite file for the Rust kernel. It is the alternative to Open the SQLite driver on device: it replaces the openExpoDriver('todos.db') call that Initializing passes to createSupabaseKizunaSync in src/kizunasync.ts, and nothing else in the app calls it. An app needs this page only when it already depends on op-sqlite for another reason.

It ships behind its own entry point, so Metro does not resolve the optional peer for an app that never imports it. The call is synchronous and never loads the peer, because the Rust kernel holds the only connection to the file. location is required, because the locator's whole job is to name the file the Rust kernel opens. It takes either an absolute directory path or the file:// URI Expo's file-system APIs hand out. The scheme and a trailing slash come off, so the locator reports <location>/<name> with a plain directory. The locator carries the same NetInfo and AppState ports as openExpoDriver. Verify op-sqlite is where a live op-sqlite handle opens, for the five-step gate.

Examples#

Basic#

// src/kizunasync.ts (excerpt)
import { openOpSqliteDriver } from 'kizunasync/expo/op-sqlite'

const driver = openOpSqliteDriver('todos.db', { location: '/data/kizunasync' })

Pass it to the client#

This is src/kizunasync.ts from Initializing with the database under the app's document directory. Everything except the driver stays the same.

// src/kizunasync.ts
import { byOwner, defineConfig } from 'kizunasync'
import { openOpSqliteDriver } from 'kizunasync/expo/op-sqlite'
import { createSupabaseKizunaSync } from 'kizunasync/supabase'
import * as FileSystem from 'expo-file-system/legacy'
import { supabase } from './supabase-client'

const config = defineConfig({
  tables: { todos: { sync: 'read-write', bucket: byOwner('user_id') } },
})

export const kizunasync = createSupabaseKizunaSync({
  supabase,
  driver: openOpSqliteDriver('todos.db', { location: FileSystem.documentDirectory ?? undefined }),
  config,
})

Parameters#

NameTypeRequiredDescription
namestringYesThe database file name, joined with location to make the path the locator reports.
optionsPick<TOpenOpSqliteOptions, 'location'>YesThe directory for the database file. The type accepts {}, but a call without location throws.
options.locationstringYesAbsolute directory for the database file, as a path or a file:// URI. The scheme and a trailing slash are removed before it is joined with name. Required, because the Rust kernel has to be told which file to open.

Returns#

IStoreLocator, returned synchronously.

NameTypeRequiredDescription
databasePathstring—location joined with name. Rust engine opens that file over UniFFI on the app client's first engine call.
loadNativeEngine() => TNativeEngineLoadResult—Loads the Rust engine through the React Native module inside kizunasync, the same loader openExpoDriver carries on device. The app client calls it once, on its first engine call.
platformPorts.connectivityIConnectivity—The NetInfo port createExpoConnectivity() builds with its default gate, which the app client follows when it is given no connectivity option.
platformPorts.foregroundIForeground—The AppState port createExpoForeground() builds, which the app client follows when it is given no foreground option.

Errors#

openOpSqliteDriver throws a plain Error rather than a typed engine error, because it runs before the engine exists, while src/kizunasync.ts loads.

MessageCondition
openOpSqliteDriver requires options.location so the Rust engine can open the same filelocation was omitted or empty.

A missing or unlinked op-sqlite peer does not fail this call, because the call never loads it. verifyOpSqliteDriver is where that shows up, as a failed check.

Notes#

This path is native only. There is no web build of op-sqlite, so an app that also runs on Expo web keeps openExpoDriver for that target.

Only the file:// scheme and one trailing slash come off location; nothing else is decoded, so a percent-encoded URI passes through as it arrived.

Run Verify op-sqlite on a device before a release that ships this driver.

A passing run is evidence for the five operations it performs, and for nothing else. Match the test to the claim draws that distinction.

Drivers and the TCK lists the obligations a driver carries past the corpus, including the cursor and attachment obligations that any store swap has to keep.

Found a problem? Edit this page on GitHub