Skip to content

Commit fb19f01

Browse files
[Package] PowerSync Nuxt Module (#797)
Co-authored-by: Amine <amine@powersync.com> Co-authored-by: Christiaan Landman <chriz.ek@gmail.com>
1 parent 5a3bb4c commit fb19f01

76 files changed

Lines changed: 17502 additions & 5331 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/gentle-poems-live.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@powersync/nuxt': patch
3+
---
4+
5+
Initial release of the PowerSync Nuxt module. Provides Nuxt Devtools integration, built-in diagnostics and data inspection, and composables. Supports Nuxt 4.

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
node_modules
2+
.env
23
lib
34
!tools/diagnostics-app/src/lib/
45
dist
6+
.nuxt
7+
.output
58
*.tsbuildinfo
69
.vscode
710
.DS_STORE
@@ -20,3 +23,6 @@ demos/**/pnpm-lock.yaml
2023

2124
# Useful for local development
2225
demos/**/.pnpmfile.cjs
26+
demos/**/.branches
27+
demos/**/.temp
28+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Self-hosted Environment Configuration
2+
# Copy this template: `cp .env.template .env`
3+
# Edit .env and enter your Supabase and PowerSync project details.
4+
5+
NUXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
6+
NUXT_PUBLIC_SUPABASE_ANON_KEY=<replace-with-your-anon-key-or-copy-publishable-key-from-supabase-start>
7+
# PowerSync Configuration
8+
NUXT_PUBLIC_POWERSYNC_URL=http://localhost:6060
9+
10+
# Self-hosted PowerSync Configuration
11+
PS_POSTGRESQL_URI=postgresql://postgres:postgres@supabase_db_nuxt-supabase-todolist:5432/postgres
12+
# PS_SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long # Uncomment this if you want to use legacy Supabase JWT secret for auth
13+
PS_JWKS_URI=http://kong:8000/auth/v1/.well-known/jwks.json
14+
PS_API_TOKEN=anything-super-secrete-token
15+
PS_PORT=6060
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
imports.autoImport=true
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# PowerSync + Supabase Nuxt Demo: Todo List
2+
3+
This is a demo application showcasing PowerSync integration with Nuxt 4 and Supabase. It demonstrates real-time data synchronization for a simple todo list application using PowerSync's official Nuxt module.
4+
5+
## Setup Instructions
6+
7+
Note that this setup guide has minor deviations from the [Supabase + PowerSync integration guide](https://docs.powersync.com/integration-guides/supabase-+-powersync). Below we refer to sections in this guide where relevant.
8+
9+
### 1. Install dependencies
10+
11+
In the repo root directory, use [pnpm](https://pnpm.io/installation) to install dependencies:
12+
13+
```bash
14+
pnpm install
15+
pnpm build:packages
16+
```
17+
18+
### Quick Start: Local Development
19+
20+
This demo can be started with local PowerSync and Supabase services.
21+
22+
1. Install the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started)
23+
24+
2. Copy the environment template:
25+
26+
```bash
27+
cp .env.template .env
28+
```
29+
30+
3. Start Supabase:
31+
32+
```bash
33+
supabase start
34+
```
35+
36+
4. Copy the values from the `supabase start` output into `.env`. Local Supabase uses JWKS for auth, so this demo configures PowerSync with `jwks_uri` and `audience: authenticated`:
37+
- `NUXT_PUBLIC_SUPABASE_ANON_KEY`: Use the **Publishable** key value
38+
- `PS_JWKS_URI`: Use `http://kong:8000/auth/v1/.well-known/jwks.json` when PowerSync runs in Docker on the Supabase network (default in step 5). This points PowerSync at local Supabase's JWKS so it can verify tokens. If Kong is not reachable from the container (e.g. custom network), try `http://host.docker.internal:54321/auth/v1/.well-known/jwks.json` on Docker Desktop for Mac/Windows.
39+
40+
> [!NOTE]
41+
> `NUXT_PUBLIC_SUPABASE_ANON_KEY`: Use the Publishable key value (requires Supabase CLI v2.45.5+)
42+
43+
5. Start PowerSync:
44+
45+
```bash
46+
docker run \
47+
-p 6060:6060 \
48+
-e POWERSYNC_CONFIG_B64=$(base64 -i ./powersync.yaml) \
49+
-e POWERSYNC_SYNC_RULES_B64=$(base64 -i ./sync-rules.yaml) \
50+
--env-file ./.env \
51+
--network supabase_network_nuxt-supabase-todolist \
52+
--name powersync-nuxt journeyapps/powersync-service:latest
53+
```
54+
55+
6. Run the demo:
56+
```bash
57+
pnpm dev
58+
```
59+
60+
Open [http://localhost:3000](http://localhost:3000) to use the app.
61+
62+
### 2. Create project on Supabase and set up Postgres
63+
64+
This demo app uses Supabase as its Postgres database and backend:
65+
66+
1. [Create a new project on the Supabase dashboard](https://supabase.com/dashboard/projects).
67+
2. Go to the Supabase SQL Editor for your new project and execute the SQL statements in [`db/seed.sql`](db/seed.sql) to create the database schema, PowerSync replication role, and publication needed for PowerSync.
68+
69+
**Note:** Before executing the SQL, make sure to update the `powersync_role` password in `db/seed.sql` (currently set to `'postgres_12345'`) to a secure password of your choice.
70+
71+
**Important:** When connecting PowerSync to your Supabase database, you'll use the `powersync_role` credentials instead of the default Supabase connection string. This role has the necessary replication privileges and bypasses Row Level Security (RLS).
72+
73+
### 3. Auth setup
74+
75+
This app uses Supabase's email/password authentication.
76+
77+
1. Go to "Authentication" -> "Providers" in your Supabase dashboard
78+
2. Ensure "Email" provider is enabled
79+
3. You can disable email confirmation for development by going to "Authentication" -> "Email Auth" and disabling "Confirm email"
80+
81+
You'll need to create a user account when you first access the application.
82+
83+
### 4. Set up PowerSync
84+
85+
You can use either PowerSync Cloud or self-host PowerSync:
86+
87+
- **PowerSync Cloud**: [Create a new project on the PowerSync dashboard](https://dashboard.powersync.com) and connect it to your Supabase database using the `powersync_role` credentials created in step 2.
88+
- **Self-hosting**: Follow the [self-hosting guide](https://docs.powersync.com/self-hosting/getting-started) to deploy your own PowerSync instance.
89+
90+
The sync rules for this demo are provided in [`sync-rules.yaml`](sync-rules.yaml) in this directory.
91+
92+
### 5. Set up local environment variables
93+
94+
Create a `.env` file in this directory with the following variables:
95+
96+
```bash
97+
NUXT_PUBLIC_SUPABASE_URL=your_supabase_url
98+
NUXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
99+
NUXT_PUBLIC_POWERSYNC_URL=your_powersync_instance_url
100+
```
101+
102+
Replace the values with your actual credentials:
103+
104+
- Get `NUXT_PUBLIC_SUPABASE_URL` and `NUXT_PUBLIC_SUPABASE_ANON_KEY` from your Supabase project settings under "Project Settings" -> "API"
105+
- Get `NUXT_PUBLIC_POWERSYNC_URL` from your PowerSync instance (Cloud dashboard or your self-hosted instance URL)
106+
107+
### 6. Run the demo app
108+
109+
In this directory, run the following to start the development server:
110+
111+
```bash
112+
pnpm dev
113+
```
114+
115+
Open [http://localhost:3000](http://localhost:3000) with your browser to try out the demo.
116+
117+
## Project Structure
118+
119+
```
120+
├── powersync/
121+
│ ├── AppSchema.ts # PowerSync schema definition
122+
│ └── SuperbaseConnector.ts # Supabase connector implementation
123+
├── plugins/
124+
│ └── powersync.client.ts # PowerSync plugin setup
125+
├── pages/
126+
│ ├── index.vue # Main todo list page
127+
│ ├── login.vue # Login page
128+
│ └── confirm.vue # Auth confirmation page
129+
├── components/
130+
│ └── AppHeader.vue # Header component
131+
├── db/
132+
│ └── seed.sql # Database setup SQL
133+
├── powersync.yaml # PowerSync server configuration
134+
├── sync-rules.yaml # PowerSync sync rules
135+
└── nuxt.config.ts # Nuxt configuration
136+
```
137+
138+
## Learn More
139+
140+
- [PowerSync Documentation](https://docs.powersync.com/)
141+
- [Supabase Documentation](https://supabase.com/docs)
142+
- [Nuxt Documentation](https://nuxt.com/)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export default defineAppConfig({
2+
ui: {
3+
colors: {
4+
primary: 'indigo',
5+
neutral: 'stone',
6+
},
7+
input: {
8+
variants: {
9+
variant: {
10+
subtle: 'ring-default bg-elevated/50',
11+
},
12+
},
13+
},
14+
header: {
15+
slots: {
16+
root: 'border-none',
17+
},
18+
},
19+
},
20+
})
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<template>
2+
<UApp>
3+
<NuxtLayout>
4+
<NuxtPage />
5+
</NuxtLayout>
6+
</UApp>
7+
</template>
8+
9+
<script setup lang="ts">
10+
useHead({
11+
meta: [{ name: 'viewport', content: 'width=device-width, initial-scale=1' }],
12+
link: [{ rel: 'icon', href: '/favicon.ico' }],
13+
htmlAttrs: {
14+
lang: 'en',
15+
},
16+
})
17+
18+
const title = 'PowerSync Playground'
19+
const description
20+
= 'Demo of a simple todo list app using PowerSync and Supabase.'
21+
22+
useSeoMeta({
23+
title,
24+
ogTitle: title,
25+
description,
26+
ogDescription: description,
27+
})
28+
29+
const appIsReady = ref(false)
30+
31+
provide('appIsReady', readonly(appIsReady))
32+
33+
const powerSync = usePowerSync()
34+
const syncStatus = usePowerSyncStatus()
35+
36+
const user = useSupabaseUser()
37+
const { logger: powerSyncLogger } = useDiagnosticsLogger()
38+
39+
watch(user, () => {
40+
if (user) {
41+
if (syncStatus.value.hasSynced) {
42+
powerSyncLogger.log('User is logged in and has synced...', { user: user, syncStatus: syncStatus.value })
43+
appIsReady.value = true
44+
}
45+
else {
46+
powerSyncLogger.log('User is logged waiting for first sync...', { user: user, syncStatus: syncStatus.value })
47+
powerSync.value.waitForFirstSync().then(() => {
48+
appIsReady.value = true
49+
})
50+
}
51+
}
52+
else {
53+
powerSyncLogger.log('User is not logged in disconnecting...', { user: user, syncStatus: syncStatus.value })
54+
powerSync.value.disconnect()
55+
appIsReady.value = true
56+
}
57+
}, { immediate: true })
58+
</script>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@import "tailwindcss";
2+
@import "@nuxt/ui";
3+
4+
:root {
5+
--ui-header-height: 40px;
6+
7+
--ui-container: 100%;
8+
}
Lines changed: 14 additions & 0 deletions
Loading
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<template>
2+
<UHeader :toggle="false">
3+
<template #left>
4+
<UButton variant="link" @click="navigateTo('/')">
5+
<img src="~/assets/img/powersync-icon.svg" alt="Powersync" class="size-10 inline-flex">
6+
</UButton>
7+
</template>
8+
9+
<template #right>
10+
<UColorModeButton variant="link" />
11+
12+
<UButton v-if="user" variant="link" class="cursor-pointer" color="neutral" @click="logout">
13+
Logout
14+
</UButton>
15+
</template>
16+
</UHeader>
17+
</template>
18+
19+
<script setup lang="ts">
20+
const client = useSupabaseClient()
21+
const user = useSupabaseUser()
22+
const powerSync = usePowerSync()
23+
24+
const logout = async () => {
25+
await powerSync.value.disconnectAndClear()
26+
27+
await client.auth.signOut()
28+
navigateTo('/login')
29+
}
30+
</script>

0 commit comments

Comments
 (0)