diff --git a/client-sdks/advanced/data-encryption.mdx b/client-sdks/advanced/data-encryption.mdx index f8094b17..ad8aeba5 100644 --- a/client-sdks/advanced/data-encryption.mdx +++ b/client-sdks/advanced/data-encryption.mdx @@ -63,12 +63,13 @@ directory. - [SQLCipher](https://www.zetetic.net/sqlcipher/) support is available for PowerSync's React Native SDK through the `@powersync/op-sqlite` package. See usage details in the package README: + The React Native SDK uses OP-SQLite, which [supports encryption](https://op-engineering.github.io/op-sqlite/docs/installation/) through [SQLCipher](https://www.zetetic.net/sqlcipher/). + For usage details, see the readme of `@powersync/react-native`. diff --git a/client-sdks/advanced/gis-data-postgis.mdx b/client-sdks/advanced/gis-data-postgis.mdx index f0907c03..f3ac3fd7 100644 --- a/client-sdks/advanced/gis-data-postgis.mdx +++ b/client-sdks/advanced/gis-data-postgis.mdx @@ -65,32 +65,32 @@ Postgres' internal binary representation of the PostGIS type is as follows: ### AppSchema Example ```js -export const AppSchema = new Schema([ - new Table({ - name: 'todos', - columns: [ - new Column({ name: 'list_id', type: ColumnType.TEXT }), - new Column({ name: 'created_at', type: ColumnType.TEXT }), - new Column({ name: 'completed_at', type: ColumnType.TEXT }), - new Column({ name: 'description', type: ColumnType.TEXT }), - new Column({ name: 'completed', type: ColumnType.INTEGER }), - new Column({ name: 'created_by', type: ColumnType.TEXT }), - new Column({ name: 'completed_by', type: ColumnType.TEXT }), - new Column({name: 'address', type: ColumnType.TEXT}), - new Column({name: 'contact_numbers', type: ColumnType.TEXT}) - new Column({name: 'location', type: ColumnType.TEXT}), - ], - indexes: [new Index({ name: 'list', columns: [new IndexedColumn({ name: 'list_id' })] })] - }), - new Table({ - name: 'lists', - columns: [ - new Column({ name: 'created_at', type: ColumnType.TEXT }), - new Column({ name: 'name', type: ColumnType.TEXT }), - new Column({ name: 'owner_id', type: ColumnType.TEXT }) - ] - }) -]); +const todos = new Table( + { + list_id: column.text, + created_at: column.text, + completed_at: column.text, + description: column.text, + completed: column.integer, + created_by: column.text, + completed_by: column.text, + address: column.text, + contact_numbers: column.text, + location: column.text + }, + { indexes: { list: ['list_id'] } } +); + +const lists = new Table({ + created_at: column.text, + name: column.text, + owner_id: column.text +}); + +export const AppSchema = new Schema({ + todos, + lists +}); ``` Note: diff --git a/client-sdks/advanced/pre-seeded-sqlite.mdx b/client-sdks/advanced/pre-seeded-sqlite.mdx index 29e50851..c7ecf54f 100644 --- a/client-sdks/advanced/pre-seeded-sqlite.mdx +++ b/client-sdks/advanced/pre-seeded-sqlite.mdx @@ -143,20 +143,17 @@ export const downloadFile = async (storeId: string) => { Once the database is downloaded, initialize the `PowerSyncDatabase` class with the file path and connect to the PowerSync instance. ```typescript -import { OPSqliteOpenFactory } from '@powersync/op-sqlite'; import { PowerSyncDatabase } from '@powersync/react-native'; import { AppSchema } from './Schema'; // databasePath is the path to the pre-seeded SQLite database file on the device. export const configureDatabase = async (storeId: string) => { - const opSqlite = new OPSqliteOpenFactory({ - dbFilename: `${storeId}.sqlite`, - dbLocation: FilePath.replace('file://', '') - }); - const powersync = new PowerSyncDatabase({ schema: AppSchema, - database: opSqlite, + database: { + dbFilename: `${storeId}.sqlite`, + dbLocation: FilePath.replace('file://', '') + }, }); // Call init() first, this will ensure the database is initialized, but not connected to the PowerSync instance. @@ -173,6 +170,3 @@ export const configureDatabase = async (storeId: string) => { At this point the client would connect to the PowerSync instance and sync the data from where the pre-seeded snapshot was created, bypassing the initial sync process. - - - diff --git a/client-sdks/frameworks/expo-go-support.mdx b/client-sdks/frameworks/expo-go-support.mdx index 1ee3b672..8846e55e 100644 --- a/client-sdks/frameworks/expo-go-support.mdx +++ b/client-sdks/frameworks/expo-go-support.mdx @@ -48,7 +48,7 @@ import { Text } from "react-native"; export const powerSync = new PowerSyncDatabase({ schema: new Schema({}), // todo: define the schema - see Next Steps below - database: new SQLJSOpenFactory({ + factory: new SQLJSOpenFactory({ dbFilename: "example.db", }), }); @@ -84,7 +84,7 @@ import { Text } from "react-native"; export const powerSync = new PowerSyncDatabase({ schema: new Schema({}), // todo: define the schema - see Next Steps below - database: new SQLJSOpenFactory({ + factory: new SQLJSOpenFactory({ dbFilename: "example.db", }), }); @@ -120,16 +120,14 @@ See an example in the package [README](https://www.npmjs.com/package/@powersync/ ## Moving Beyond Expo Go -When you're ready to move beyond the Expo Go sandbox environment - whether for native development builds or production deployment - we recommend switching to our native database adapters: - -- [OP-SQLite](https://www.npmjs.com/package/@powersync/op-sqlite) (Recommended) - Offers built-in encryption support and better React Native New Architecture compatibility -- [React Native Quick SQLite](https://www.npmjs.com/package/@journeyapps/react-native-quick-sqlite) - Our original native adapter +When you're ready to move beyond the Expo Go sandbox environment - whether for native development builds or production deployment - we recommend switching to our recommended native database adapter, +based on [OP-SQLite](https://www.npmjs.com/package/@op-engineering/op-sqlite). - These database adapters cannot run in Expo Go because they require native code compilation. Specifically, PowerSync needs a SQLite implementation that can load the PowerSync SQLite core extension, which isn't possible in Expo Go's prebuilt app container. + OP-SQLite cannot run in Expo Go because it require native code compilation. Specifically, PowerSync needs a SQLite implementation that can load the PowerSync SQLite core extension, which isn't possible in Expo Go's prebuilt app container. -These adapters provide better performance, full SQLite consistency guarantees, and are suitable for both development builds and production deployment. See the SDKs [Installation](/client-sdks/reference/react-native-and-expo#install-peer-dependencies) details for setup instructions. +This adapter provides better performance, full SQLite consistency guarantees, and are suitable for both development builds and production deployment. See the SDKs [Installation](/client-sdks/reference/react-native-and-expo#install-peer-dependencies) details for setup instructions. ### Switching Between Adapters - Example @@ -137,19 +135,17 @@ If you want to keep using Expo Go alongside development and production builds, y ```js SystemProvider.tsx import { SQLJSOpenFactory } from "@powersync/adapter-sql-js"; -import { PowerSyncDatabase } from "@powersync/react-native"; +import { DatabaseSource, PowerSyncDatabase } from "@powersync/react-native"; import Constants from "expo-constants"; const isExpoGo = Constants.executionEnvironment === "storeClient"; +const source: DatabaseSource = isExpoGo ? + { factory: new SQLJSOpenFactory({ dbFilename: "app.db" }) } + : { database: { dbFilename: "sqlite.db" } }; + export const powerSync = new PowerSyncDatabase({ schema: AppSchema, - database: isExpoGo - ? new SQLJSOpenFactory({ - dbFilename: "app.db", - }) - : { - dbFilename: "sqlite.db", - }, + ...source, }); ``` \ No newline at end of file diff --git a/client-sdks/frameworks/next-js.mdx b/client-sdks/frameworks/next-js.mdx index eeb8a2e4..de31f373 100644 --- a/client-sdks/frameworks/next-js.mdx +++ b/client-sdks/frameworks/next-js.mdx @@ -278,12 +278,10 @@ Add a new file at `./src/lib/powersync/PowerSyncProvider.tsx`. This is the clien import { AppSchema } from '@/lib/powersync/AppSchema'; import { BackendConnector } from '@/lib/powersync/BackendConnector'; import { PowerSyncContext } from '@powersync/react'; -import { PowerSyncDatabase, WASQLiteOpenFactory, createBaseLogger, LogLevel } from '@powersync/web'; +import { PowerSyncDatabase, WASQLiteOpenFactory, createConsoleLogger, LogLevels } from '@powersync/web'; import React, { Suspense } from 'react'; -const logger = createBaseLogger(); -logger.useDefaults(); -logger.setLevel(LogLevel.DEBUG); +const logger = createConsoleLogger({ minLevel: LogLevels.debug }); let dbInstance: PowerSyncDatabase | null = null; @@ -291,16 +289,15 @@ function getDB(): PowerSyncDatabase { if (dbInstance) return dbInstance; dbInstance = new PowerSyncDatabase({ - database: new WASQLiteOpenFactory({ + database: { dbFilename: 'powersync.db', // Use the pre-bundled worker from public/@powersync/ // This is required since Turbopack doesn't support dynamic imports of workers yet - worker: '/@powersync/worker/WASQLiteDB.umd.js' - }), + worker: '/@powersync/worker.js' + }, schema: AppSchema, - flags: { disableSSRWarning: true }, // Use the pre-bundled sync worker from public/@powersync/ - sync: { worker: '/@powersync/worker/SharedSyncImplementation.umd.js' }, + sync: { worker: '/@powersync/worker.js' }, logger }); diff --git a/client-sdks/frameworks/react-native-web-support.mdx b/client-sdks/frameworks/react-native-web-support.mdx index 33dd0e99..6d5c19a6 100644 --- a/client-sdks/frameworks/react-native-web-support.mdx +++ b/client-sdks/frameworks/react-native-web-support.mdx @@ -30,7 +30,7 @@ See installation instructions [here](https://www.npmjs.com/package/@powersync/we For React Native for Web, workers need to be configured when instantiating `PowerSyncDatabase`. An example of this is available [here](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-web-supabase-todolist/library/powersync/system.ts). -To do this, copy the contents of `node_modules/@powersync/web/dist` to the root of your project (typically in the `public `directory). To make it easier to manage these files in the `public` directory, it is recommended to place the contents in a nested directory like `@powersync`. +To do this, copy the contents of `node_modules/@powersync/web/dist/worker` to the root of your project (typically in the `public `directory). To make it easier to manage these files in the `public` directory, it is recommended to place the contents in a nested directory like `@powersync`. The [`@powersync/web`](https://github.com/powersync-ja/powersync-js/tree/main/packages/web) package includes a CLI utility which can copy the required assets to the `public` directory (configurable with the `--output` option). @@ -49,34 +49,28 @@ const factory = new WASQLiteOpenFactory({ dbFilename: 'sqlite.db', // Option 1: Specify a path to the database worker - worker: '/@powersync/worker/WASQLiteDB.umd.js' + worker: '/@powersync/worker.js' // Option 2: Or provide a factory function to create the worker. // The worker name should be unique for the database filename to avoid conflicts if multiple clients with different databases are present. // worker: (options) => { - // if (options?.flags?.enableMultiTabs) { - // return new SharedWorker(`/@powersync/worker/WASQLiteDB.umd.js`, { - // name: `shared-DB-worker-${options?.dbFilename}` - // }); - // } else { - // return new Worker(`/@powersync/worker/WASQLiteDB.umd.js`, { - // name: `DB-worker-${options?.dbFilename}` - // }); - // } + // return new SharedWorker(`/@powersync/worker.js`, { + // name: `shared-DB-worker-${options?.dbFilename}` + // }); // } }); this.powersync = new PowerSyncDatabaseWeb({ schema: AppSchema, - database: factory, + factory: factory, sync: { // Option 1: You can specify a path to the sync worker - worker: '/@powersync/worker/SharedSyncImplementation.umd.js' + worker: '/@powersync/worker.js' //Option 2: Or provide a factory function to create the worker. // The worker name should be unique for the database filename to avoid conflicts if multiple clients with different databases are present. // worker: (options) => { - // return new SharedWorker(`/@powersync/worker/SharedSyncImplementation.umd.js`, { + // return new SharedWorker(`/@powersync/worker.js`, { // name: `shared-sync-${options?.dbFilename}` // }); // } @@ -95,6 +89,10 @@ To target both mobile and web platforms, you need to adjust the Metro configurat Refer to the example [here](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-web-supabase-todolist/metro.config.js). Setting `config.resolver.resolveRequest` allows Metro to behave differently based on the platform. ```js +// Expo removes the react-native export condition for React Native web: https://github.com/expo/expo/blob/874ddfc86c0bdaeeb43f56b4386d271ba869ad47/packages/%40expo/metro-config/src/ExpoMetroConfig.ts#L309 +// The PowerSync web SKD needs to be resolved with an RN-specific export condition to work with Metro. +config.resolver.unstable_conditionsByPlatform.web.push('react-native-web'); + config.resolver.resolveRequest = (context, moduleName, platform) => { if (platform === 'web') { // Depending on `@powersync/web` for functionality, ignore mobile specific dependencies. @@ -103,7 +101,7 @@ config.resolver.resolveRequest = (context, moduleName, platform) => { type: 'empty' }; } - const mapping = { 'react-native': 'react-native-web', '@powersync/web': '@powersync/web/dist/index.umd.js' }; + const mapping = { 'react-native': 'react-native-web' }; if (mapping[moduleName]) { console.log('remapping', moduleName); return context.resolveRequest(context, mapping[moduleName], platform); @@ -143,15 +141,14 @@ if (PowerSyncDatabaseNative) { } }); } else { - const factory = new WASQLiteOpenFactory({ - dbFilename: 'sqlite.db', - worker: '/@powersync/worker/WASQLiteDB.umd.js' - }); this.powersync = new PowerSyncDatabaseWeb({ schema: AppSchema, - database: factory, + database: { + dbFilename: 'sqlite.db', + worker: '/@powersync/worker.js' + }, sync: { - worker: '/@powersync/worker/SharedSyncImplementation.umd.js' + worker: '/@powersync/worker.js' } }); } @@ -220,16 +217,3 @@ import { prompt } from 'util/prompt'; />; ``` -### 5. Configure UMD Target - -React Native Web requires the UMD target of `@powersync/web` (available at `@powersync/web/umd`). To fully support this target version, configure the following in your project: - -1. Add `config.resolver.unstable_enablePackageExports = true;` to your `metro.config.js` file. - -2. TypeScript projects: In the `tsconfig.json` file specify the `moduleResolution` to be `Bundler`. - -```json - "compilerOptions": { - "moduleResolution": "Bundler" - } -``` diff --git a/client-sdks/full-text-search.mdx b/client-sdks/full-text-search.mdx index 49c9b5b5..5d195195 100644 --- a/client-sdks/full-text-search.mdx +++ b/client-sdks/full-text-search.mdx @@ -11,7 +11,7 @@ Full-text search has been demonstrated in the following SDKs: - [**Dart/Flutter SDK**](/client-sdks/reference/flutter): Uses the [sqlite_async](https://pub.dev/documentation/sqlite_async/latest/) package for migrations - [**JavaScript Web SDK**](/client-sdks/reference/javascript-web): Requires version 0.5.0 or greater (including [wa-sqlite](https://github.com/powersync-ja/wa-sqlite) 0.2.0+) -- [**React Native SDK**](/client-sdks/reference/react-native-and-expo): Requires version 1.16.0 or greater (including [@powersync/react-native-quick-sqlite](https://github.com/powersync-ja/react-native-quick-sqlite) 2.2.1+) +- [**React Native SDK**](/client-sdks/reference/react-native-and-expo): Requires additional configuration to enable FTS5, see [the readme](https://www.npmjs.com/package/@powersync/react-native). - [**Swift SDK**](/client-sdks/reference/swift) Note that the availability of FTS in our SDKs is dependent on the underlying `sqlite` package used. It may be supported in our other SDKs, especially if the `FTS5` extension is available, but would be untested. Check with us on [Discord](https://discord.gg/powersync) if you have a use case and need help getting started. diff --git a/client-sdks/reference/capacitor.mdx b/client-sdks/reference/capacitor.mdx index 5375e0c5..1290dfbc 100644 --- a/client-sdks/reference/capacitor.mdx +++ b/client-sdks/reference/capacitor.mdx @@ -158,13 +158,13 @@ import { Schema } from '@powersync/web'; const db = new PowerSyncDatabase({ schema: AppSchema, - database: isWeb + factory: isWeb ? new WASQLiteOpenFactory({ dbFilename: "mydb.sqlite" }) : new CapacitorSQLiteOpenFactory({ dbFilename: "mydb.sqlite" }) }); ``` -Once you've instantiated your PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/web-sdk/classes/AbstractPowerSyncDatabase#connect) method to sync data with your backend. +Once you've instantiated your PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/web-sdk/classes/PowerSyncDatabase#connect) method to sync data with your backend. @@ -297,16 +297,11 @@ const deleteList = async (id) => { ## Configure Logging ```js -import { createBaseLogger, LogLevel } from '@powersync/web'; +import { createConsoleLogger, LogLevels } from '@powersync/web'; -const logger = createBaseLogger(); - -// Configure the logger to use the default console output -logger.useDefaults(); - -// Set the minimum log level to DEBUG to see all log messages -// Available levels: DEBUG, INFO, WARN, ERROR, TRACE, OFF -logger.setLevel(LogLevel.DEBUG); +// Create a logger with trace minimum level to see all log messages +// Available levels: trace, debug, info, warn, error +const logger = createConsoleLogger({ minLevel: LogLevels.trace }); ``` diff --git a/client-sdks/reference/javascript-web.mdx b/client-sdks/reference/javascript-web.mdx index b0471d8f..af12807a 100644 --- a/client-sdks/reference/javascript-web.mdx +++ b/client-sdks/reference/javascript-web.mdx @@ -169,7 +169,7 @@ export const db = new PowerSyncDatabase({ In SDK versions lower than 1.2.0, you will need to use the deprecated [WASQLitePowerSyncDatabaseOpenFactory](https://powersync-ja.github.io/powersync-js/web-sdk/classes/WASQLitePowerSyncDatabaseOpenFactory) syntax to instantiate the database. -Once you've instantiated your PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/web-sdk/classes/AbstractPowerSyncDatabase#connect) method to sync data with your backend. +Once you've instantiated your PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/web-sdk/classes/PowerSyncDatabase#connect) method to sync data with your backend. @@ -295,20 +295,29 @@ const deleteList = async (id) => { ## Configure Logging ```js -import { createBaseLogger, LogLevel } from '@powersync/web'; +import { createConsoleLogger, LogLevels } from '@powersync/web'; -const logger = createBaseLogger(); - -// Configure the logger to use the default console output -logger.useDefaults(); - -// Set the minimum log level to DEBUG to see all log messages -// Available levels: DEBUG, INFO, WARN, ERROR, TRACE, OFF -logger.setLevel(LogLevel.DEBUG); +// Create a logger with trace minimum level to see all log messages +// Available levels: trace, debug, info, warn, error +const logger = createConsoleLogger({ minLevel: LogLevels.trace }); ``` Enable verbose output in the developer tools for detailed logs. + Note that the PowerSync SDK relies on web workers, which inherit the logger from the main database while using a separate log level. + To pass a consistent log level to workers, also pass it to the sync and database workers: + + ```TypeScript + const db = new PowerSyncDatabase( + database: { + dbFileName: '...', + databaseWorkerLogLevel: LogLevels.trace, + }, + sync: { + logLevel: LogLevels.trace, + } + ); + ``` Additionally, the [WASQLiteDBAdapter](https://powersync-ja.github.io/powersync-js/web-sdk/classes/WASQLiteDBAdapter) opens SQLite connections inside a shared web worker. This worker can be inspected in Chrome by accessing: @@ -361,23 +370,21 @@ pnpm upgrade @powersync/web @journeyapps/wa-sqlite This SDK supports two methods for streaming sync commands: -1. **WebSocket (Default)** - - The implementation leverages RSocket for handling reactive socket streams. - - Back-pressure is effectively managed through client-controlled command requests. - - Sync commands are transmitted efficiently as BSON (binary) documents. - - This method is **recommended** since it will support the future [BLOB column support](https://roadmap.powersync.com/c/88-support-for-blob-column-types) feature. -2. **HTTP Streaming (Legacy)** - - This is the original implementation method. - - This method will not support the future BLOB column feature. +1. **HTTP Streaming (Default)** + - This is the default and recommended connection method. +2. **WebSocket** + - This implementation leverages RSocket based on WebSocket connections. + - Window sizes for flow control and back-pressure are customizable, set `fetchStrategy` to `Buffered` (default) or `Sequential`. + - On the web, there is no compelling reason to use WebSockets over HTTP response streams. -By default, the `PowerSyncDatabase.connect()` method uses WebSocket. You can optionally specify the `connectionMethod` to override this: +By default, the `PowerSyncDatabase.connect()` method uses HTTP streaming. You can optionally specify the `connectionMethod` to override this: ```js -// WebSocket (default) +// HTTP Streaming (default) powerSync.connect(connector); -// HTTP Streaming -powerSync.connect(connector, { connectionMethod: SyncStreamConnectionMethod.HTTP }); +// WebSocket +powerSync.connect(connector, { connectionMethod: SyncStreamConnectionMethod.WEB_SOCKET }); ``` ### SQLite Virtual File Systems @@ -403,15 +410,9 @@ import { PowerSyncDatabase, WASQLiteOpenFactory, WASQLiteVFS } from '@powersync/ export const db = new PowerSyncDatabase({ schema: AppSchema, - database: new WASQLiteOpenFactory({ + database: { dbFilename: 'exampleVFS.db', - vfs: WASQLiteVFS.OPFSCoopSyncVFS, - flags: { - enableMultiTabs: typeof SharedWorker !== 'undefined' - } - }), - flags: { - enableMultiTabs: typeof SharedWorker !== 'undefined' + vfs: WASQLiteVFS.OPFSCoopSyncVFS } }); ``` @@ -427,10 +428,10 @@ import { PowerSyncDatabase, WASQLiteOpenFactory, WASQLiteVFS } from '@powersync/ export const db = new PowerSyncDatabase({ schema: AppSchema, - database: new WASQLiteOpenFactory({ + database: { dbFilename: 'exampleVFS.db', vfs: WASQLiteVFS.AccessHandlePoolVFS - }) + } }); ``` @@ -449,11 +450,11 @@ import { PowerSyncDatabase, WASQLiteOpenFactory, WASQLiteVFS } from '@powersync/ export const db = new PowerSyncDatabase({ schema: AppSchema, - database: new WASQLiteOpenFactory({ + database: { dbFilename: 'exampleVFS.db', vfs: WASQLiteVFS.OPFSWriteAheadVFS, additionalReaders: 2 - }) + } }); ``` @@ -510,15 +511,11 @@ async function listVfsEntries() { * For Safari, use the [`OPFSCoopSyncVFS`](/client-sdks/reference/javascript-web#sqlite-virtual-file-systems) virtual file system to ensure stable multi-tab functionality. -Using PowerSync between multiple tabs is supported on some web browsers. Multiple tab support relies on shared web workers for database and sync streaming operations. When enabled, shared web workers named `shared-DB-worker-[dbFileName]` and `shared-sync-[dbFileName]` will be created. +Using PowerSync between multiple tabs is supported on some web browsers. Multiple tab support relies on shared web workers for database and sync streaming operations. When enabled, a shared web worker named `shared-powersync-[dbFileName]` will be created. +Depending on the setup, the shared worker is responsible for: -#### `shared-DB-worker-[dbFileName]` - -The shared database worker will ensure writes to the database will instantly be available between tabs. - -#### `shared-sync-[dbFileName]` - -The shared sync worker connects directly to the PowerSync backend instance and applies changes to the database. Note that the shared sync worker will call the `fetchCredentials` and `uploadData` method of the latest opened available tab. Closing a tab will shift the latest tab to the previously opened one. +1. __Sync__: The shared sync worker connects directly to the PowerSync backend instance and applies changes to the database. Note that the shared sync worker will call the `fetchCredentials` and `uploadData` method of the latest opened available tab. Closing a tab will shift the latest tab to the previously opened one. +2. __Database operations__: When using an IndexedDB-based VFS, the SDK can open database connections in a shared worker to ensure writes to the database will instantly be available between tabs. Currently, using the SDK in multiple tabs without enabling the [enableMultiTabs](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/web/src/db/adapters/web-sql-flags.ts#L23) flag will spawn a standard web worker per tab for DB operations. These workers are safe to operate on the DB concurrently, however changes from one tab may not update watches on other tabs. Only one tab can sync from the PowerSync instance at a time. The sync status will not be shared between tabs, only the oldest tab will connect and display the latest sync status. @@ -530,13 +527,7 @@ export const db = new PowerSyncDatabase({ database: { dbFilename: 'my_app_db.sqlite' }, - flags: { - /** - * Multiple tab support is enabled by default if available. - * This can be disabled by setting this flag to false. - */ - enableMultiTabs: false - } + enableMultiTabs: false }); ``` @@ -544,59 +535,50 @@ export const db = new PowerSyncDatabase({ This guide provides an overview of the customizable flags available for the `PowerSyncDatabase` in the JavaScript Web SDK. These flags allow you to enable or disable specific features to suit your application's requirements. -#### Configuring Flags +#### Configuring Options -You can configure flags during the initialization of the `PowerSyncDatabase`. Flags can be set using the `flags` property, which allows you to enable or disable specific functionalities. +You can configure these options during the initialization of `PowerSyncDatabase` as top-level constructor properties. ```javascript -import { PowerSyncDatabase, resolveWebPowerSyncFlags, WebPowerSyncFlags } from '@powersync/web'; +import { PowerSyncDatabase } from '@powersync/web'; import { AppSchema } from '@/library/powersync/AppSchema'; -// Define custom flags -const customFlags: WebPowerSyncFlags = resolveWebPowerSyncFlags({ - enableMultiTabs: true, - broadcastLogs: true, - disableSSRWarning: false, - ssrMode: false, - useWebWorker: true, -}); - -// Create the PowerSync database instance export const db = new PowerSyncDatabase({ schema: AppSchema, database: { dbFilename: 'example.db', + enableMultiTabs: true, }, - flags: customFlags, + broadcastLogs: true, }); ``` #### Available Flags - + default: `true` Enables support for multiple tabs using shared web workers. When enabled, multiple tabs can interact with the same database and sync data seamlessly. - default: `false` + default: `true` Enables the broadcasting of logs for debugging purposes. This flag helps monitor shared worker logs in a multi-tab environment. - + default: `false` Disables warnings when running in SSR (Server-Side Rendering) mode. - + default: `false` Enables SSR mode. In this mode, only empty query results will be returned, and syncing with the backend is disabled. - + default: `true` Enables the use of web workers for database operations. Disabling this flag also disables multi-tab support. @@ -614,8 +596,6 @@ export const db = new PowerSyncDatabase({ schema: AppSchema, database: { dbFilename: 'my_app_db.sqlite', - }, - flags: { enableMultiTabs: false, }, }); @@ -623,24 +603,7 @@ export const db = new PowerSyncDatabase({ When disabled, each tab will use independent workers, and changes in one tab will not automatically propagate to others. -**Example 2: SSR Mode** - -To enable SSR mode and suppress warnings: - -```javascript -export const db = new PowerSyncDatabase({ - schema: AppSchema, - database: { - dbFilename: 'my_app_db.sqlite', - }, - flags: { - ssrMode: true, - disableSSRWarning: true, - }, -}); -``` - -**Example 3: Verbose Debugging with Broadcast Logs** +**Example 2: Verbose Debugging with Broadcast Logs** To enable detailed logging for debugging: @@ -649,10 +612,12 @@ export const db = new PowerSyncDatabase({ schema: AppSchema, database: { dbFilename: 'my_app_db.sqlite', + databaseWorkerLogLevel: LogLevels.debug, }, - flags: { - broadcastLogs: true, + sync: { + logLevel: LogLevels.debug, }, + logger: createConsoleLogger({ minSeverity: LogLevels.debug }), }); ``` @@ -661,7 +626,4 @@ Logs will include detailed insights into database and sync operations. #### Recommendations 1. **Set `enableMultiTabs`** to `true` if your application requires seamless data sharing across multiple tabs. -2. **Set `useWebWorker`** to `true` for efficient database operations using web workers. -3. **Set `broadcastLogs`** to `true` during development to troubleshoot and monitor database and sync operations. -4. **Set `disableSSRWarning`** to `true` when running in SSR mode to avoid unnecessary console warnings. -5. **Test combinations** of flags to validate their behavior in your application's specific use case. +2. **Set `broadcastLogs`** to `true` during development to troubleshoot and monitor database and sync operations. diff --git a/client-sdks/reference/node.mdx b/client-sdks/reference/node.mdx index d07826a5..da3e9bbb 100644 --- a/client-sdks/reference/node.mdx +++ b/client-sdks/reference/node.mdx @@ -186,16 +186,11 @@ PowerSync runs queries asynchronously on a background pool of workers and automa ## Configure Logging ```js -import { createBaseLogger, LogLevel } from '@powersync/node'; +import { createConsoleLogger, LogLevels } from '@powersync/node'; -const logger = createBaseLogger(); - -// Configure the logger to use the default console output -logger.useDefaults(); - -// Set the minimum log level to DEBUG to see all log messages -// Available levels: DEBUG, INFO, WARN, ERROR, TRACE, OFF -logger.setLevel(LogLevel.DEBUG); +// Create a logger with trace minimum level to see all log messages +// Available levels: trace, debug, info, warn, error +const logger = createConsoleLogger({ minLevel: LogLevels.trace }); ``` diff --git a/client-sdks/reference/react-native-and-expo.mdx b/client-sdks/reference/react-native-and-expo.mdx index b3bf3250..29bf8201 100644 --- a/client-sdks/reference/react-native-and-expo.mdx +++ b/client-sdks/reference/react-native-and-expo.mdx @@ -109,60 +109,23 @@ Next, you need to instantiate the PowerSync database. PowerSync streams changes **Example**: - - - For getting started and testing PowerSync use the [@journeyapps/react-native-quick-sqlite](https://github.com/powersync-ja/react-native-quick-sqlite) package. - By default, this SDK requires @journeyapps/react-native-quick-sqlite as a peer dependency. - - ```typescript powersync/system.ts - import { PowerSyncDatabase } from '@powersync/react-native'; - import { AppSchema } from './Schema'; - - export const powersync = new PowerSyncDatabase({ - // The schema you defined in the previous step - schema: AppSchema, - // For other options see, - // https://powersync-ja.github.io/powersync-js/web-sdk/globals#powersyncopenfactoryoptions - database: { - // Filename for the SQLite database — it's important to only instantiate one instance per file. - // For other database options see, - // https://powersync-ja.github.io/powersync-js/web-sdk/globals#sqlopenoptions - dbFilename: 'powersync.db' - } - }); - ``` - - - If you want to include encryption with SQLCipher use the [@powersync/op-sqlite](https://www.npmjs.com/package/@powersync/op-sqlite) package. - If you've already installed `@journeyapps/react-native-quick-sqlite`, You will have to uninstall it and then install both `@powersync/op-sqlite` and it's peer dependency `@op-engineering/op-sqlite` to use this. - - ```typescript powersync/system.ts - import { PowerSyncDatabase } from '@powersync/react-native'; - import { OPSqliteOpenFactory } from '@powersync/op-sqlite'; // Add this import - import { AppSchema } from './Schema'; - - // Create the factory - const opSqlite = new OPSqliteOpenFactory({ - dbFilename: 'powersync.db' - }); - - export const powersync = new PowerSyncDatabase({ - // For other options see, - schema: AppSchema, - // Override the default database - database: opSqlite - }); - ``` - - - - -**SDK versions lower than 1.8.0** - -In SDK versions lower than 1.8.0, you will need to use the deprecated [RNQSPowerSyncDatabaseOpenFactory](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/RNQSPowerSyncDatabaseOpenFactory) syntax to instantiate the database. - +```typescript powersync/system.ts +import { PowerSyncDatabase } from '@powersync/react-native'; +import { AppSchema } from './Schema'; + +export const powersync = new PowerSyncDatabase({ + // The schema you defined in the previous step + schema: AppSchema, + database: { + // Filename for the SQLite database — it's important to only instantiate one instance per file. + // For other database options see, + // https://powersync-ja.github.io/powersync-js/web-sdk/globals#sqlopenoptions + dbFilename: 'powersync.db' + } +}); +``` -Once you've instantiated your PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/AbstractPowerSyncDatabase#connect) method to sync data with your backend. +Once you've instantiated your PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/PowerSyncDatabase#connect) method to sync data with your backend. @@ -377,16 +340,11 @@ export const ListsWidget = () => { ## Configure Logging ```js -import { createBaseLogger, LogLevel } from '@powersync/react-native'; - -const logger = createBaseLogger(); +import { createConsoleLogger, LogLevels } from '@powersync/react-native'; -// Configure the logger to use the default console output -logger.useDefaults(); - -// Set the minimum log level to DEBUG to see all log messages -// Available levels: DEBUG, INFO, WARN, ERROR, TRACE, OFF -logger.setLevel(LogLevel.DEBUG); +// Create a logger with trace minimum level to see all log messages +// Available levels: trace, debug, info, warn, error +const logger = createConsoleLogger({ minLevel: LogLevels.trace }); ``` @@ -416,17 +374,17 @@ Run the below command in your project folder: ```bash -npm upgrade @powersync/react-native @journeyapps/react-native-quick-sqlite +npm upgrade @powersync/react-native ``` ```bash -yarn upgrade @powersync/react-native @journeyapps/react-native-quick-sqlite +yarn upgrade @powersync/react-native ``` ```bash -pnpm upgrade @powersync/react-native @journeyapps/react-native-quick-sqlite +pnpm upgrade @powersync/react-native ``` @@ -437,29 +395,30 @@ pnpm upgrade @powersync/react-native @journeyapps/react-native-quick-sqlite This SDK supports two methods for streaming sync commands: -1. **WebSocket (Default)** +1. **HTTP Streaming (Default)** + - This is the default streaming method. +2. **WebSocket (Fallback)** - The implementation leverages RSocket for handling reactive socket streams. - - Back-pressure is effectively managed through client-controlled command requests. - - Sync commands are transmitted efficiently as BSON (binary) documents. - - This method is **recommended** since it will support the future [BLOB column support](https://roadmap.powersync.com/c/88-support-for-blob-column-types) feature. - -2. **HTTP Streaming (Legacy)** - - This is the original implementation method. - - This method will not support the future BLOB column feature. + - This is necessary on React Native without Expo, as `fetch()` in React Native does not support streaming responses. + - Window sizes for flow control and back-pressure are customizable, set `fetchStrategy` to `Buffered` (default) or `Sequential`. -By default, the `PowerSyncDatabase.connect()` method uses WebSocket. You can optionally specify the `connectionMethod` to override this: +By default, the `PowerSyncDatabase.connect()` method uses HTTP on Expo apps (with `expo/fetch` as an HTTP client) and WebSockets +for plain React Native apps. You can optionally specify the `connectionMethod` to override this: ```js -// WebSocket (default) +// Default (HTTP on Expo apps, WebSocket on plain React Native). powerSync.connect(connector); -// HTTP Streaming +// HTTP Streaming, throws if no HTTP client with support for streaming responses is available. powerSync.connect(connector, { connectionMethod: SyncStreamConnectionMethod.HTTP }); + +// Explicitly use Web Sockets +powerSync.connect(connector, { connectionMethod: SyncStreamConnectionMethod.WEB_SOCKET }); ``` ### Android: Flipper Network Plugin for HTTP Streams -**Not needed when using websockets, which is the default since `@powersync/react-native@1.11.0`.** +**Not needed when using websockets: ** If you are connecting to PowerSync using HTTP streams, you require additional configuration on Android. React Native does not support streams out of the box, so we use the [polyfills mentioned](/client-sdks/reference/react-native-and-expo#installation). There is currently an open [issue](https://github.com/facebook/flipper/issues/2495) where the Flipper network plugin does not allow Stream events to fire. This plugin needs to be [disabled](https://stackoverflow.com/questions/69235694/react-native-cant-connect-to-sse-in-android/69235695#69235695) in order for HTTP streams to work. diff --git a/client-sdks/usage-examples.mdx b/client-sdks/usage-examples.mdx index 09c4863b..4c0e2b89 100644 --- a/client-sdks/usage-examples.mdx +++ b/client-sdks/usage-examples.mdx @@ -1035,7 +1035,7 @@ import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-call return {hasSynced ? 'Initial sync completed!' : 'Busy with initial sync...'}; ``` - For async use cases, see [PowerSyncDatabase.waitForFirstSync](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/AbstractPowerSyncDatabase#waitforfirstsync), which returns a promise that resolves once the first full sync has completed (it queries the internal SQL [ps\_buckets](/architecture/client-architecture) table to determine if data has been synced). + For async use cases, see [PowerSyncDatabase.waitForFirstSync](https://powersync-ja.github.io/powersync-js/react-native-sdk/classes/PowerSyncDatabase#waitforfirstsync), which returns a promise that resolves once the first full sync has completed (it queries the internal SQL [ps\_buckets](/architecture/client-architecture) table to determine if data has been synced). @@ -1059,7 +1059,7 @@ import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-call return
{hasSynced ? 'Initial sync completed!' : 'Busy with initial sync...'}
; ``` - For async use cases, see [PowerSyncDatabase.waitForFirstSync()](https://powersync-ja.github.io/powersync-js/web-sdk/classes/AbstractPowerSyncDatabase#waitforfirstsync), which returns a promise that resolves once the first full sync has completed (it queries the internal SQL [ps\_buckets](/architecture/client-architecture) table to determine if data has been synced). + For async use cases, see [PowerSyncDatabase.waitForFirstSync()](https://powersync-ja.github.io/powersync-js/web-sdk/classes/PowerSyncDatabase#waitforfirstsync), which returns a promise that resolves once the first full sync has completed (it queries the internal SQL [ps\_buckets](/architecture/client-architecture) table to determine if data has been synced).
diff --git a/debugging/troubleshooting.mdx b/debugging/troubleshooting.mdx index cc709053..dfd9d422 100644 --- a/debugging/troubleshooting.mdx +++ b/debugging/troubleshooting.mdx @@ -314,7 +314,7 @@ Our [Sync Diagnostics Client](/tools/diagnostics-client) and several of our [dem Our client SDKs support logging to troubleshoot issues. Here's how to enable logging in each SDK: -* **JavaScript-based SDKs** (Web, React Native, and Node.js) - You can use our built-in logger based on [js-logger](https://www.npmjs.com/package/js-logger) for logging. Create the base logger with `const logger = createBaseLogger()` and enable with `logger.useDefaults()` and set level with `logger.setLevel(LogLevel.DEBUG)`. For the Web SDK, you can also enable the `debugMode` flag to log SQL queries on Chrome's Performance timeline. +* **JavaScript-based SDKs** (Web, React Native, and Node.js) - Implement the `PowerSyncLogger` interface, or use `createConsoleLogger()`. For example: `const logger = createConsoleLogger({ minLevel: LogLevels.debug })`. Pass the logger to `PowerSyncDatabase` via the `logger` option. For the Web SDK, you can also enable the `debugMode` flag to log SQL queries on Chrome's Performance timeline. * **Dart/Flutter SDK** - Logging is enabled by default since version 1.1.2 and outputs logs to the console in debug mode. diff --git a/maintenance-ops/client-database-diagnostics.mdx b/maintenance-ops/client-database-diagnostics.mdx index f00c6116..c8750c88 100644 --- a/maintenance-ops/client-database-diagnostics.mdx +++ b/maintenance-ops/client-database-diagnostics.mdx @@ -23,8 +23,8 @@ adb exec-out run-as com.package-name cat databases/your-db-name.sqlite-wal > "yo ``` **Common database locations:** - - [React Native Quick SQLite](/client-sdks/reference/react-native-and-expo#react-native-quick-sqlite-2): `/data/data/com.package-name/files/` - - [OP-SQLite](/client-sdks/reference/react-native-and-expo#op-sqlite): `/data/data/com.package-name/databases/` + - React Native (old directory used when the app was originally installed on a 1.x SDK version): `/data/data/com.package-name/files/`. + - React Native (new directory): `/data/data/com.package-name/databases/`. **Note:** If the database is in a different location, first find it with: ```shell diff --git a/maintenance-ops/production-readiness-guide.mdx b/maintenance-ops/production-readiness-guide.mdx index 2dccf118..65b27434 100644 --- a/maintenance-ops/production-readiness-guide.mdx +++ b/maintenance-ops/production-readiness-guide.mdx @@ -19,8 +19,8 @@ We recommend adding a view/screen in your application that offers diagnostic inf 1. `connected` - Boolean; True if the client is connected to the PowerSync Service instance. False if not. 2. `connecting` - Boolean; True if the client is attempting to connect to the PowerSync Service instance. False if not. -3. `uploading` - Boolean; If the client has a network connection and changes in the upload queue are present this will be set to true when the client attempts to upload changes to the backend API in the `uploadData` function. This option can be found on the `dataFlowStatus` object. -4. `downloading` - Boolean; If the client is connected to the PowerSync Service and new data is available, this will be set to true, else it will be false. This option can be found on the `dataFlowStatus` object. +3. `uploading` - Boolean; If the client has a network connection and changes in the upload queue are present this will be set to true when the client attempts to upload changes to the backend API in the `uploadData` function. +4. `downloading` - Boolean; If the client is connected to the PowerSync Service and new data is available, this will be set to true, else it will be false. 5. `hasSynced` - Boolean; True if the client completed a full sync at least once. False if the client never completed a full sync. 6. `lastSyncedAt` - DateTime; Timestamp of when the client last completed a full sync. @@ -72,7 +72,7 @@ createRoot(document.getElementById("root")!, ```typescript System.ts import * as Sentry from '@sentry/react'; -import { createBaseLogger, LogLevel } from '@powersync/react-native'; +import { createConsoleLogger, LogLevels } from '@powersync/react-native'; // Initialize Sentry Sentry.init({ @@ -81,9 +81,7 @@ Sentry.init({ enableLogs: true // Enable Sentry logging }); -const logger = createBaseLogger(); -logger.useDefaults(); -logger.setLevel(LogLevel.WARN); +const logger = createConsoleLogger({ minLevel: LogLevels.warn }); logger.setHandler((messages, context) => { if (!context?.level) return; @@ -127,24 +125,24 @@ export const powerSync = new PowerSyncDatabase({ powerSync.registerListener({ statusChanged: (status) => { // Check for download errors and log them with context - if(status.dataFlowStatus?.downloadError) { + if(status.downloadError) { logger.error("PowerSync sync download failed", { userSession: connector.currentSession, // Current user session for tracking lastSyncAt: status?.lastSyncedAt, // When the last successful sync occurred connected: status?.connected, // Network connection status sdkVersion: powerSync.sdkVersion || 'unknown', // PowerSync SDK version for debugging - downloadError: status.dataFlowStatus?.downloadError // The actual download error details + downloadError: status.downloadError // The actual download error details }); } // Check for upload errors and log them with context - if(status.dataFlowStatus?.uploadError) { + if(status.uploadError) { logger.error("PowerSync sync upload failed", { userSession: connector.currentSession, // Current user session for tracking lastSyncAt: status?.lastSyncedAt, // When the last successful sync occurred connected: status?.connected, // Network connection status sdkVersion: powerSync.sdkVersion || 'unknown', // PowerSync SDK version for debugging - uploadError: status.dataFlowStatus?.uploadError // The actual upload error details + uploadError: status.uploadError // The actual upload error details }); } } diff --git a/snippets/react-native/installation.mdx b/snippets/react-native/installation.mdx index 579216eb..aab01f9c 100644 --- a/snippets/react-native/installation.mdx +++ b/snippets/react-native/installation.mdx @@ -3,106 +3,34 @@ Add the [PowerSync React Native NPM package](https://www.npmjs.com/package/@powe ```bash - npx expo install @powersync/react-native + npx expo install @powersync/react-native @op-engineering/op-sqlite ``` ```bash - yarn expo add @powersync/react-native + yarn expo add @powersync/react-native @op-engineering/op-sqlite ``` ``` - pnpm expo install @powersync/react-native + pnpm expo install @powersync/react-native @op-engineering/op-sqlite ``` -**Install Peer Dependencies** - -PowerSync requires a SQLite database adapter. Choose between: - - - - [PowerSync OP-SQLite](https://www.npmjs.com/package/@powersync/op-sqlite) offers: - - Built-in encryption support via SQLCipher - - Smoother transition to React Native's New Architecture - - - - ```bash - npx expo install @powersync/op-sqlite @op-engineering/op-sqlite - ``` - - - - ```bash - yarn expo add @powersync/op-sqlite @op-engineering/op-sqlite - ``` - - - - ``` - pnpm expo install @powersync/op-sqlite @op-engineering/op-sqlite - ``` - - - - - - The [@journeyapps/react-native-quick-sqlite](https://www.npmjs.com/package/@journeyapps/react-native-quick-sqlite) package is the original database adapter for React Native and therefore more battle-tested in production environments. - - - - ```bash - npx expo install @journeyapps/react-native-quick-sqlite - ``` - - - - ```bash - yarn expo add @journeyapps/react-native-quick-sqlite - ``` - - - - ``` - pnpm expo install @journeyapps/react-native-quick-sqlite - ``` - - - - **iOS with `use_frameworks!`** - - If your iOS project uses `use_frameworks!`, add the `react-native-quick-sqlite` plugin to your app.json or app.config.js and configure the staticLibrary option: - - ``` - { - "expo": { - "plugins": [ - [ - "@journeyapps/react-native-quick-sqlite", - { - "staticLibrary": true - } - ] - ] - } - } - ``` - - This plugin automatically configures the necessary build settings for `react-native-quick-sqlite` to work with `use_frameworks!`. - - + +`@op-engineering/op-sqlite` is the SQLite library used by the PowerSync SDK on React Native. +It needs to be installed separately because React Native only considers direct dependencies for autolinking. +The PowerSync React Native SDK currently supports version 1.17.0 or later of `@op-engineering/op-sqlite`. + - **Using Expo Go?** Our native database adapters listed below (OP-SQLite and React Native Quick SQLite) are not compatible with Expo Go's sandbox environment. To run PowerSync with Expo Go install our JavaScript-based adapter `@powersync/adapter-sql-js` instead. See details [here](/client-sdks/frameworks/expo-go-support). + **Using Expo Go?** Our native database adapter is not compatible with Expo Go's sandbox environment. To run PowerSync with Expo Go install our JavaScript-based adapter `@powersync/adapter-sql-js` instead. See details [here](/client-sdks/frameworks/expo-go-support). **Polyfills and additional notes:** - For async iterator support with watched queries, additional polyfills are required. See the [Babel plugins section](https://www.npmjs.com/package/@powersync/react-native#babel-plugins-watched-queries) in the README. - - When using the **OP-SQLite** package, we recommend adding this [metro config](https://github.com/powersync-ja/powersync-js/tree/main/packages/react-native#metro-config-optional) - to avoid build issues. - \ No newline at end of file + - We recommend adding this [metro config](https://github.com/powersync-ja/powersync-js/tree/main/packages/react-native#metro-config-optional) to avoid build issues. +