From bd9f5ba9d40b8aa236a334e20a3f6b42baa81f8a Mon Sep 17 00:00:00 2001 From: Mike Barnes Date: Thu, 20 Mar 2025 11:58:25 -0600 Subject: [PATCH 1/5] Initial pass of the Next.js guide --- tutorials/client/overview.mdx | 1 + tutorials/client/sdks/overview.mdx | 8 + tutorials/client/sdks/web/next-js.mdx | 330 ++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 tutorials/client/sdks/overview.mdx create mode 100644 tutorials/client/sdks/web/next-js.mdx diff --git a/tutorials/client/overview.mdx b/tutorials/client/overview.mdx index 0c984d03..87947f5d 100644 --- a/tutorials/client/overview.mdx +++ b/tutorials/client/overview.mdx @@ -4,6 +4,7 @@ description: "A collection of tutorials for client-side use cases." --- + diff --git a/tutorials/client/sdks/overview.mdx b/tutorials/client/sdks/overview.mdx new file mode 100644 index 00000000..cf56e918 --- /dev/null +++ b/tutorials/client/sdks/overview.mdx @@ -0,0 +1,8 @@ +--- +title: "Client SDK Tutorials" +description: "A collection of tutorials on how to use PowerSync in supported client SDKs." +--- + + + + diff --git a/tutorials/client/sdks/web/next-js.mdx b/tutorials/client/sdks/web/next-js.mdx new file mode 100644 index 00000000..103f6218 --- /dev/null +++ b/tutorials/client/sdks/web/next-js.mdx @@ -0,0 +1,330 @@ +--- +title: "Next.js + PowerSync + Supabase" +description: "A guide for creating a new Next.js application with PowerSync for offline/local first functionality" +keywords: ["next.js", "web"] +--- + +## Introduction +In this tutorial, we’ll explore how to enhance a Next.js application with offline-first capabilities using PowerSync. In the following sections, we’ll walk through the process of integrating PowerSync into a Next.js application, setting up local-first storage, and handling synchronization efficiently. + +## Setup + +### Next.js Project Setup +Let's start by bootstrapping a new Next.js application using [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +```shell +pnpm dlx create-next-app@latest +``` + +When running this command you'll be presented with a few options, here is the suggestion selection for the setup options Next.js offers +```shell +Would you like to use TypeScript? Yes +Would you like to use ESLint? Yes +Would you like to use Tailwind CSS? Yes +Would you like your code inside a `src/` directory? Yes +Would you like to use App Router? (recommended) Yes +Would you like to use Turbopack for `next dev`? No +Would you like to customize the import alias (`@/*` by default)? Yes +``` + + + Do not use Turbopack when setting up a new Next.js project. We'll be modifying the `next.config.ts` to rather use webpack. Because we need to enable: + 1. asyncWebAssembly + 2. topLevelWait + + +### Install PowerSync Dependencies + +Using PowerSync in a Next.js application will require the use of the PowerSync Web SDK and it's peer dependencies. + +In addition to this we'll also install `@powersync/react` which provides some nice hooks and providers for easier integration. + +```shell +pnpm install @powersync/web @journeyapps/wa-sqlite @powersync/react js-logger +``` + +This SDK currently requires [@journeyapps/wa-sqlite](https://www.npmjs.com/package/@journeyapps/wa-sqlite) as a peer dependency. Install it in your app with. +Installing `js-logger` is very useful for debugging. + +## Next.js Config Setup + +In order for PowerSync to work with the Next.js we'll need to modify the default `next.config.ts` to support PowerSync. + +```typescript +module.exports = { + experimental: { + turbo: false, + }, + webpack: (config: any, isServer: any) => { + config.experiments = { + ...config.experiments, + asyncWebAssembly: true, // Enable WebAssembly in Webpack + topLevelAwait: true, + }; + + // For Web Workers, ensure proper file handling + if (!isServer) { + config.module.rules.push({ + test: /\.wasm$/, + type: "asset/resource", // Adds WebAssembly files to the static assets + }); + } + + return config; + } +} +``` + +Some important notes here, we have to enable `asyncWebAssemply` in Webpack, `topLevelAwait` is required and for Web Workers, ensure proper file handling. +It's also important to add web assembly files to static assets for the site. We will not be using SSR because PowerSync does not support it. + +Run `pnpm dev` to start the development server and check that everything compiles correctly, before moving onto the next section. + +## Configure a PowerSync Instance +Now that we've got our project setup, let's create a new PowerSync Cloud instance and connect our client to it. +For the purposes of this demo, we'll be using Supabase as the source backend database that PowerSync will connect to. + +To set up a new PowerSync instance, follow the steps covered in the [Supabase + PowerSync](/integration-guides/supabase-+-powersync) integration guide to learn how to create a new Supabase DB and connecting it to a PowerSync instance. + +## Configure PowerSync in your project +### Add core PowerSync files +Start by adding a new directory in `./src/lib` named `powersync`. + +#### `AppSchema` +Create a new file called `AppSchema.ts` in the newly created `powersync` directory and add your App Schema to the file. Here is an example of this. +```typescript +import { column, Schema, Table } from '@powersync/web'; + +const lists = new Table({ + created_at: column.text, + name: column.text, + owner_id: column.text +}); + +const todos = new Table( + { + list_id: column.text, + created_at: column.text, + completed_at: column.text, + description: column.text, + created_by: column.text, + completed_by: column.text, + completed: column.integer + }, + { indexes: { list: ['list_id'] } } +); + +export const AppSchema = new Schema({ + todos, + lists +}); + +// For types +export type Database = (typeof AppSchema)['types']; +export type TodoRecord = Database['todos']; +// OR: +// export type Todo = RowType; +export type ListRecord = Database['lists']; +``` + +This defines the local SQLite database schema and PowerSync will hydrate the tables once the SDK connects to the PowerSync instance. + +#### `BackendConnector` + +Create a new file called `BackendConnector.ts` in the newly created `powersync` directory and add the following to the file. +```typescript +import { AbstractPowerSyncDatabase, PowerSyncBackendConnector } from '@powersync/web'; + +export class BackendConnector implements PowerSyncBackendConnector { + private powersyncUrl: string | undefined; + private powersyncToken: string | undefined; + + constructor() { + this.powersyncUrl = process.env.NEXT_PUBLIC_POWERSYNC_URL; + // This token is for development only. + // For production applications, integrate with an auth provider or custom auth. + this.powersyncToken = process.env.NEXT_PUBLIC_POWERSYNC_TOKEN; + } + + async fetchCredentials() { + // TODO: Use an authentication service or custom implementation here. + + if (this.powersyncToken == null || this.powersyncUrl == null) { + return null; + } + + return { + endpoint: this.powersyncUrl, + token: this.powersyncToken + }; + } + + async uploadData(database: AbstractPowerSyncDatabase): Promise { + const transaction = await database.getNextCrudTransaction(); + + if (!transaction) { + return; + } + + try { + // TODO: Upload here + + await transaction.complete(); + } catch (error: any) { + if (shouldDiscardDataOnError(error)) { + // Instead of blocking the queue with these errors, discard the (rest of the) transaction. + // + // Note that these errors typically indicate a bug in the application. + // If protecting against data loss is important, save the failing records + // elsewhere instead of discarding, and/or notify the user. + console.error(`Data upload error - discarding`, error); + await transaction.complete(); + } else { + // Error may be retryable - e.g. network error or temporary server error. + // Throwing an error here causes this call to be retried after a delay. + throw error; + } + } + } +} + +function shouldDiscardDataOnError(error: any) { + // TODO: Ignore non-retryable errors here + return false; +} + +``` + +There are two core functions to this file: +* `fetchCredentials()` - Used to return a JWT token to the PowerSync service for authentication. +* `uploadData()` - Used to upload changes captured in the local SQLite database that need to be sent to the source backend database, in this case Supabase. We'll get back to this further down. + +You'll notice that we need to add an `.env` file to our project which will contain two variables: +* `NEXT_PUBLIC_POWERSYNC_URL` - This is the PowerSync instance url. You can grab this from the PowerSync Cloud dashboard. +* `NEXT_PUBLIC_POWERSYNC_TOKEN` - For development purposes we'll be using a development token. To generate one, please follow the steps outlined in [Development Token](/installation/authentication-setup/development-tokens) from our installation docs. + +### Create Providers + +Create a new directory in `./src/app/components` named `providers` + +#### `SystemProvider` +Add a new file in the newly created `providers` directory called `SystemProvider.tsx`. + +```typescript +'use client'; + +import { AppSchema } from '@/lib/powersync/AppSchema'; +import { BackendConnector } from '@/lib/powersync/BackendConnector'; +import { PowerSyncContext } from '@powersync/react'; +import { PowerSyncDatabase, WASQLiteOpenFactory, WASQLiteVFS } from '@powersync/web'; +import Logger from 'js-logger'; +import React, { Suspense } from 'react'; + +// eslint-disable-next-line react-hooks/rules-of-hooks +Logger.useDefaults(); +Logger.setLevel(Logger.DEBUG); + +export const db = new PowerSyncDatabase({ + schema: AppSchema, + database: new WASQLiteOpenFactory({ + dbFilename: 'exampleVFS.db', + vfs: WASQLiteVFS.OPFSCoopSyncVFS, + flags: { + enableMultiTabs: typeof SharedWorker !== 'undefined', + ssrMode: false + } + }), + flags: { + enableMultiTabs: typeof SharedWorker !== 'undefined', + } +}); + +const connector = new BackendConnector(); +db.connect(connector); +console.log(db.currentStatus); + +export const SystemProvider = ({ children }: { children: React.ReactNode }) => { + + return ( + + {children} + + ); +}; + +export default SystemProvider; + +``` + +The `SystemProvider` will be responsible for initializing the `PowerSyncDatabase`. Here we supply a few arguments, such as the AppSchema we defined earlier along with very important properties such as `ssrMode: false`. +PowerSync will not work when rendered server side, so we need to explicitly disable SSR. + +We also instantiate our `BackendConnector` and pass an instance of that to `db.connect()`. This will connect to the PowerSync instance, validate the token supplied in the `fetchCredentials` function and then start syncing with the PowerSync service. + +#### DynamicSystemProvider.tsx + +Add a new file in the newly created `providers` directory called `DynamicSystemProvider.tsx`. + +```typescript +'use client'; + +import dynamic from 'next/dynamic'; + +export const DynamicSystemProvider = dynamic(() => import('./SystemProvider'), { + ssr: false +}); + +``` +We can only use PowerSync in client side rendering, so here we're setting `ssr:false` + +#### Update `layout.tsx` + +In our main `layout.tsx` we'l update the `RootLayout` function to use the `DynamicSystemProvider` created in the last step. + +```typescript DynamicSystemProvider.tsx +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; +import { DynamicSystemProvider } from '@/components/providers/DynamicSystemProvider'; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} + +``` + +#### Use PowerSync + +In our `page.tsx` we can not use PowerSync to query data from the local SQLite DB. + +```typescript page.tsx +import { useQuery, useStatus } from '@powersync/react'; + +export default function Page() { + const status = useStatus(); + const data = useQuery("SELECT * FROM ticket"); + + return ( + ... + ) +} +``` From 81b0f8742becae7b9a5a3a4703b3a8e3c877e9bc Mon Sep 17 00:00:00 2001 From: Mike Barnes Date: Wed, 26 Mar 2025 11:53:10 -0600 Subject: [PATCH 2/5] Feedback and polish --- mint.json | 6 ++ tutorials/client/sdks/web/next-js.mdx | 110 +++++++++++++++----------- 2 files changed, 71 insertions(+), 45 deletions(-) diff --git a/mint.json b/mint.json index f9ceb703..423d42bb 100644 --- a/mint.json +++ b/mint.json @@ -401,6 +401,12 @@ "group": "Client", "pages": [ "tutorials/client/overview", + { + "group": "Client SDKs", + "pages": [ + "tutorials/client/sdks/web/next-js" + ] + }, { "group": "Attachments / Files", "pages": [ diff --git a/tutorials/client/sdks/web/next-js.mdx b/tutorials/client/sdks/web/next-js.mdx index 103f6218..10a53306 100644 --- a/tutorials/client/sdks/web/next-js.mdx +++ b/tutorials/client/sdks/web/next-js.mdx @@ -1,5 +1,5 @@ --- -title: "Next.js + PowerSync + Supabase" +title: "Next.js + PowerSync" description: "A guide for creating a new Next.js application with PowerSync for offline/local first functionality" keywords: ["next.js", "web"] --- @@ -15,7 +15,7 @@ Let's start by bootstrapping a new Next.js application using [`create-next-app`] pnpm dlx create-next-app@latest ``` -When running this command you'll be presented with a few options, here is the suggestion selection for the setup options Next.js offers +When running this command you'll be presented with a few options. The PowerSync suggested selection for the setup options Next.js offers are: ```shell Would you like to use TypeScript? Yes Would you like to use ESLint? Yes @@ -27,29 +27,29 @@ Would you like to customize the import alias (`@/*` by default)? Yes ``` - Do not use Turbopack when setting up a new Next.js project. We'll be modifying the `next.config.ts` to rather use webpack. Because we need to enable: + Do not use Turbopack when setting up a new Next.js project as we’ll be updating the `next.config.ts` to use Webpack. This is done because we need to enable: 1. asyncWebAssembly 2. topLevelWait ### Install PowerSync Dependencies -Using PowerSync in a Next.js application will require the use of the PowerSync Web SDK and it's peer dependencies. +Using PowerSync in a Next.js application will require the use of the [PowerSync Web SDK](https://www.npmjs.com/package/@powersync/web) and it's peer dependencies. -In addition to this we'll also install `@powersync/react` which provides some nice hooks and providers for easier integration. +In addition to this we'll also install [`@powersync/react`](https://www.npmjs.com/package/@powersync/react), which provides several hooks and providers for easier integration. ```shell pnpm install @powersync/web @journeyapps/wa-sqlite @powersync/react js-logger ``` -This SDK currently requires [@journeyapps/wa-sqlite](https://www.npmjs.com/package/@journeyapps/wa-sqlite) as a peer dependency. Install it in your app with. +This SDK currently requires [@journeyapps/wa-sqlite](https://www.npmjs.com/package/@journeyapps/wa-sqlite) as a peer dependency. Installing `js-logger` is very useful for debugging. ## Next.js Config Setup In order for PowerSync to work with the Next.js we'll need to modify the default `next.config.ts` to support PowerSync. -```typescript +```typescript next.config.ts module.exports = { experimental: { turbo: false, @@ -83,7 +83,7 @@ Run `pnpm dev` to start the development server and check that everything compile Now that we've got our project setup, let's create a new PowerSync Cloud instance and connect our client to it. For the purposes of this demo, we'll be using Supabase as the source backend database that PowerSync will connect to. -To set up a new PowerSync instance, follow the steps covered in the [Supabase + PowerSync](/integration-guides/supabase-+-powersync) integration guide to learn how to create a new Supabase DB and connecting it to a PowerSync instance. +To set up a new PowerSync instance, follow the steps covered in the [Installation - Database Connection](/installation/database-connection) docs page. ## Configure PowerSync in your project ### Add core PowerSync files @@ -91,7 +91,7 @@ Start by adding a new directory in `./src/lib` named `powersync`. #### `AppSchema` Create a new file called `AppSchema.ts` in the newly created `powersync` directory and add your App Schema to the file. Here is an example of this. -```typescript +```typescript lib/powersync/AppSchema.ts import { column, Schema, Table } from '@powersync/web'; const lists = new Table({ @@ -130,9 +130,9 @@ This defines the local SQLite database schema and PowerSync will hydrate the tab #### `BackendConnector` -Create a new file called `BackendConnector.ts` in the newly created `powersync` directory and add the following to the file. -```typescript -import { AbstractPowerSyncDatabase, PowerSyncBackendConnector } from '@powersync/web'; +Create a new file called `BackendConnector.ts` in the `lib` directory called `powersync` and add the following to the file. +```typescript lib/powersync/BackendConnector.ts +import { AbstractPowerSyncDatabase, PowerSyncBackendConnector, UpdateType } from '@powersync/web'; export class BackendConnector implements PowerSyncBackendConnector { private powersyncUrl: string | undefined; @@ -147,7 +147,6 @@ export class BackendConnector implements PowerSyncBackendConnector { async fetchCredentials() { // TODO: Use an authentication service or custom implementation here. - if (this.powersyncToken == null || this.powersyncUrl == null) { return null; } @@ -166,39 +165,35 @@ export class BackendConnector implements PowerSyncBackendConnector { } try { - // TODO: Upload here - + for (const op of transaction.crud) { + // The data that needs to be changed in the remote db + const record = { ...op.opData, id: op.id }; + switch (op.op) { + case UpdateType.PUT: + // TODO: Instruct your backend API to CREATE a record + break; + case UpdateType.PATCH: + // TODO: Instruct your backend API to PATCH a record + break; + case UpdateType.DELETE: + //TODO: Instruct your backend API to DELETE a record + break; + } + } await transaction.complete(); } catch (error: any) { - if (shouldDiscardDataOnError(error)) { - // Instead of blocking the queue with these errors, discard the (rest of the) transaction. - // - // Note that these errors typically indicate a bug in the application. - // If protecting against data loss is important, save the failing records - // elsewhere instead of discarding, and/or notify the user. - console.error(`Data upload error - discarding`, error); - await transaction.complete(); - } else { - // Error may be retryable - e.g. network error or temporary server error. - // Throwing an error here causes this call to be retried after a delay. - throw error; - } + console.error(`Data upload error - discarding`, error); + await transaction.complete(); } } } - -function shouldDiscardDataOnError(error: any) { - // TODO: Ignore non-retryable errors here - return false; -} - ``` There are two core functions to this file: * `fetchCredentials()` - Used to return a JWT token to the PowerSync service for authentication. * `uploadData()` - Used to upload changes captured in the local SQLite database that need to be sent to the source backend database, in this case Supabase. We'll get back to this further down. -You'll notice that we need to add an `.env` file to our project which will contain two variables: +You'll notice that we need to add a `.env` file to our project which will contain two variables: * `NEXT_PUBLIC_POWERSYNC_URL` - This is the PowerSync instance url. You can grab this from the PowerSync Cloud dashboard. * `NEXT_PUBLIC_POWERSYNC_TOKEN` - For development purposes we'll be using a development token. To generate one, please follow the steps outlined in [Development Token](/installation/authentication-setup/development-tokens) from our installation docs. @@ -209,7 +204,7 @@ Create a new directory in `./src/app/components` named `providers` #### `SystemProvider` Add a new file in the newly created `providers` directory called `SystemProvider.tsx`. -```typescript +```typescript components/providers/SystemProvider.tsx 'use client'; import { AppSchema } from '@/lib/powersync/AppSchema'; @@ -225,6 +220,7 @@ Logger.setLevel(Logger.DEBUG); export const db = new PowerSyncDatabase({ schema: AppSchema, + logging: logger, database: new WASQLiteOpenFactory({ dbFilename: 'exampleVFS.db', vfs: WASQLiteVFS.OPFSCoopSyncVFS, @@ -264,7 +260,7 @@ We also instantiate our `BackendConnector` and pass an instance of that to `db.c Add a new file in the newly created `providers` directory called `DynamicSystemProvider.tsx`. -```typescript +```typescript components/providers/DynamicSystemProvider.tsx 'use client'; import dynamic from 'next/dynamic'; @@ -278,9 +274,9 @@ We can only use PowerSync in client side rendering, so here we're setting `ssr:f #### Update `layout.tsx` -In our main `layout.tsx` we'l update the `RootLayout` function to use the `DynamicSystemProvider` created in the last step. +In our main `layout.tsx` we'll update the `RootLayout` function to use the `DynamicSystemProvider` created in the last step. -```typescript DynamicSystemProvider.tsx +```typescript app/layout.tsx import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import { DynamicSystemProvider } from '@/components/providers/DynamicSystemProvider'; @@ -314,17 +310,41 @@ export default function RootLayout({ #### Use PowerSync -In our `page.tsx` we can not use PowerSync to query data from the local SQLite DB. +##### Reading Data +In our `page.tsx` we can now use the `useQuery` hook or other PowerSync functions to read data from the SQLite database and render the results in our application. -```typescript page.tsx -import { useQuery, useStatus } from '@powersync/react'; +```typescript app/page.tsx +import { useState, useEffect } from 'react'; +import { useQuery, useStatus, usePowerSync } from '@powersync/react'; export default function Page() { + // Hook + const powersync = usePowerSync(); + + // Get database status information e.g. downloading, uploading and lastSycned dates const status = useStatus(); - const data = useQuery("SELECT * FROM ticket"); + + // Example 1: Reactive Query + const { data: lists } = useQuery("SELECT * FROM ticket"); + + // Example 2: Standard query + const [lists, setLists] = useState([]); + useEffect(() => { + powersync.getAll('SELECT * from lists').then(setLists) + }, []); return ( - ... - ) +
    + {lists.map(list =>
  • {list.name}
  • )} +
+ ) } ``` + +##### Writing Data +Using the `execute` function we can also write data into our local SQLite database. +```typescript +await powersync.execute("INSERT INTO lists (id, created_at, name, owner_id) VALUES (?, ?, ?, ?)", [uuid(), new Date(), "Test", user_id]); +``` + +Changes made against the local data will be stored in the upload queue and will be processed by the `uploadData` in the BackendConnector class. From 4a85bf85459ab0cd79001504a4b5546d61dd1cb3 Mon Sep 17 00:00:00 2001 From: Mike Barnes Date: Tue, 1 Apr 2025 14:51:13 -0600 Subject: [PATCH 3/5] Added a note on SST --- tutorials/client/sdks/web/next-js.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tutorials/client/sdks/web/next-js.mdx b/tutorials/client/sdks/web/next-js.mdx index 10a53306..e3632a01 100644 --- a/tutorials/client/sdks/web/next-js.mdx +++ b/tutorials/client/sdks/web/next-js.mdx @@ -7,6 +7,8 @@ keywords: ["next.js", "web"] ## Introduction In this tutorial, we’ll explore how to enhance a Next.js application with offline-first capabilities using PowerSync. In the following sections, we’ll walk through the process of integrating PowerSync into a Next.js application, setting up local-first storage, and handling synchronization efficiently. +At present PowerSync will not work with SSR enabled with Next.js + ## Setup ### Next.js Project Setup From 62265bdc975c7732c624c48d72f53cbd93dbcd23 Mon Sep 17 00:00:00 2001 From: Mike Barnes Date: Wed, 2 Apr 2025 23:57:30 -0600 Subject: [PATCH 4/5] Changes based on feedback --- tutorials/client/sdks/web/next-js.mdx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tutorials/client/sdks/web/next-js.mdx b/tutorials/client/sdks/web/next-js.mdx index e3632a01..992e31dd 100644 --- a/tutorials/client/sdks/web/next-js.mdx +++ b/tutorials/client/sdks/web/next-js.mdx @@ -7,7 +7,7 @@ keywords: ["next.js", "web"] ## Introduction In this tutorial, we’ll explore how to enhance a Next.js application with offline-first capabilities using PowerSync. In the following sections, we’ll walk through the process of integrating PowerSync into a Next.js application, setting up local-first storage, and handling synchronization efficiently. -At present PowerSync will not work with SSR enabled with Next.js +At present PowerSync will not work with SSR enabled with Next.js and in this guide we disable SSR across the entire app. However, it is possible to have other pages, which do not require authentication for example, to still be rendered server-side. This can be done by only using the DynamicSystemProvider (covered further down in the guide) for specific pages. This means you can still have full SSR on other page which do not require PowerSync. ## Setup @@ -132,7 +132,7 @@ This defines the local SQLite database schema and PowerSync will hydrate the tab #### `BackendConnector` -Create a new file called `BackendConnector.ts` in the `lib` directory called `powersync` and add the following to the file. +Create a new file called `BackendConnector.ts` in the `powersync` directory and add the following to the file. ```typescript lib/powersync/BackendConnector.ts import { AbstractPowerSyncDatabase, PowerSyncBackendConnector, UpdateType } from '@powersync/web'; @@ -222,7 +222,6 @@ Logger.setLevel(Logger.DEBUG); export const db = new PowerSyncDatabase({ schema: AppSchema, - logging: logger, database: new WASQLiteOpenFactory({ dbFilename: 'exampleVFS.db', vfs: WASQLiteVFS.OPFSCoopSyncVFS, @@ -238,7 +237,6 @@ export const db = new PowerSyncDatabase({ const connector = new BackendConnector(); db.connect(connector); -console.log(db.currentStatus); export const SystemProvider = ({ children }: { children: React.ReactNode }) => { @@ -281,7 +279,7 @@ In our main `layout.tsx` we'll update the `RootLayout` function to use the `Dyna ```typescript app/layout.tsx import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; -import { DynamicSystemProvider } from '@/components/providers/DynamicSystemProvider'; +import { DynamicSystemProvider } from '@/app/components/providers/DynamicSystemProvider'; const geistSans = Geist({ variable: "--font-geist-sans", @@ -327,7 +325,7 @@ export default function Page() { const status = useStatus(); // Example 1: Reactive Query - const { data: lists } = useQuery("SELECT * FROM ticket"); + const { data: lists } = useQuery("SELECT * FROM lists"); // Example 2: Standard query const [lists, setLists] = useState([]); From 118bc2f688bad4e7002d9f4d764649f52ec778c5 Mon Sep 17 00:00:00 2001 From: Mike Barnes Date: Wed, 2 Apr 2025 23:58:59 -0600 Subject: [PATCH 5/5] Added missing use-client on page.tsx code example --- tutorials/client/sdks/web/next-js.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tutorials/client/sdks/web/next-js.mdx b/tutorials/client/sdks/web/next-js.mdx index 992e31dd..d83fb59d 100644 --- a/tutorials/client/sdks/web/next-js.mdx +++ b/tutorials/client/sdks/web/next-js.mdx @@ -314,6 +314,8 @@ export default function RootLayout({ In our `page.tsx` we can now use the `useQuery` hook or other PowerSync functions to read data from the SQLite database and render the results in our application. ```typescript app/page.tsx +'use client'; + import { useState, useEffect } from 'react'; import { useQuery, useStatus, usePowerSync } from '@powersync/react';