Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
39c0aa4
feat(diagnostics-core): add core diagnostics package with agent and c…
khawarizmus Sep 2, 2026
9245ed0
chore(diagnostics-ui): update pnpm lockfile, add diagnostics UI packa…
khawarizmus Sep 2, 2026
bd80f8f
feat(diagnostics-extension): add Chrome DevTools extension for PowerS…
khawarizmus Sep 2, 2026
9cc7665
feat(schema): implement serialization for schema, tables, columns, an…
khawarizmus Sep 2, 2026
3be75f7
refactor(inspector): remove unused components and composables; stream…
khawarizmus Sep 2, 2026
e7de22b
test(schema): add comprehensive tests for Schema serialization, inclu…
khawarizmus Sep 3, 2026
cd04e17
feat(diagnostics): enhance diagnostics capabilities with new event st…
khawarizmus Sep 4, 2026
2772fb2
feat(diagnostics): introduce DiagnosticsAgent and related components …
khawarizmus Sep 4, 2026
b2a9b47
fix(connection-manager): add currentConnector to track active connect…
khawarizmus Sep 4, 2026
a4e5478
fix(diagnostics): implement resync functionality for DiagnosticsClien…
khawarizmus Sep 4, 2026
7a38965
feat(diagnostics): update diagnostics core and UI packages with new P…
khawarizmus Sep 4, 2026
845bc99
feat(diagnostics-ui): integrate theme management and enhance UI compo…
khawarizmus Sep 4, 2026
845b21e
feat(diagnostics-ui): add new components for enhanced diagnostics dis…
khawarizmus Sep 4, 2026
28a2d68
feat(diagnostics-ui): enhance diagnostics UI with new logs tab, bucke…
khawarizmus Sep 4, 2026
d57b255
feat(diagnostics-ui): improve diagnostics UI with tab persistence, re…
khawarizmus Sep 7, 2026
90d8d6d
chore: revert some unrelated changes
khawarizmus Sep 8, 2026
c72afed
refactored(diagnostics): dropped public interface changes and documen…
khawarizmus Sep 10, 2026
a9d13a9
feat(diagnostics-core): define the SdkIntegration and protocol shapes
khawarizmus Sep 14, 2026
82add27
refactor(diagnostics): move the protocol to the diagnostics package; …
khawarizmus Sep 15, 2026
475f08f
refactor(diagnostics): add package READMEs, drop NuxtPowerSyncDatabase
khawarizmus Sep 15, 2026
20ea996
fix(diagnostics): stream subscription timestamps, PowerSync dock icon
khawarizmus Sep 16, 2026
fe8ad22
refactor(diagnostics): address review on the protocol package
khawarizmus Sep 16, 2026
8ded8d7
feat(diagnostics): ship PowerSync DevTools as a devframe definition
khawarizmus Sep 17, 2026
4d1eba5
fix(diagnostics): Nuxt devtools now mounts on Vite devtools properly
khawarizmus Sep 18, 2026
f188aca
feat(diagnostics): MCP origin knob for node and CLI and spell out too…
khawarizmus Sep 18, 2026
3dfec00
fix(diagnostics): announce source attach and detach, surface tool err…
khawarizmus Sep 18, 2026
5a947a4
fix(diagnostics): keep the Nuxt plugin quiet in production, note Vite…
khawarizmus Sep 18, 2026
1b72c5e
chore(diagnostics): trim traces, type the Nuxt runtime options, mark …
khawarizmus Sep 18, 2026
daf7d2d
feat(diagnostics): CLI --token for connectAgent clients, location gua…
khawarizmus Sep 18, 2026
16e1e9d
build: make CI green for the diagnostics packages
khawarizmus Sep 18, 2026
ea14ca6
chore: update dependencies
khawarizmus Sep 22, 2026
0e3628e
chore: updated capacitor deps
khawarizmus Sep 22, 2026
9df307b
chore: pinned some dependencies
khawarizmus Sep 22, 2026
f43d43d
refactor(diagnostics): drop the CLI and connectAgent, add hold-to-wip…
khawarizmus Sep 23, 2026
71c7757
refactor(diagnostics): move the JS agent and the UI stores out of dia…
khawarizmus Sep 23, 2026
2823b63
refactor(diagnostics): broadcast core events from the web SDK only, l…
khawarizmus Sep 23, 2026
597aa23
refactor(diagnostics): tighten the protocol shapes
khawarizmus Sep 24, 2026
602b868
fix(diagnostics-ui): ticking times, per-SDK setup tabs, sessionStorag…
khawarizmus Sep 24, 2026
72bf747
docs(diagnostics): trim READMEs, mark core and UI internal, wire DevT…
khawarizmus Sep 24, 2026
65817b4
fix(demos): allow the vue-demi build script in the Node demo
khawarizmus Sep 28, 2026
dc105bb
chore: fix deps pinning
khawarizmus Sep 28, 2026
dfad39c
fix(diagnostics): serve the Node DevTools window on a random port by …
khawarizmus Sep 28, 2026
a43207c
feat(diagnostics): print a Node sign-in link that carries the one-tim…
khawarizmus Sep 28, 2026
5b85f60
chore(nuxt): drop the unused unocss dependency; state the Node versio…
khawarizmus Sep 28, 2026
cd105a1
docs(diagnostics): trim the READMEs to what users need and drop unver…
khawarizmus Sep 28, 2026
bf558a8
chore: updated deps
khawarizmus Sep 28, 2026
17ebaf3
chore: updated lock file
khawarizmus Sep 28, 2026
78ea114
feat(diagnostics): show only the SDKs each host can reach on the empt…
khawarizmus Sep 30, 2026
9a05212
fix(diagnostics): address review: public database type, typed log lev…
khawarizmus Sep 30, 2026
255456b
chore(diagnostics): initial automated release changeset; align versio…
khawarizmus Sep 30, 2026
13d0b52
feat(demos): PowerSync DevTools and a local Supabase stack in react-s…
khawarizmus Sep 30, 2026
7d0c5e3
refactor(diagnostics): move the diagnostics packages to tools/
khawarizmus Oct 1, 2026
170d577
fix(diagnostics): import the Node entry dynamically in examples so pr…
khawarizmus Oct 1, 2026
d7a38ed
docs(demos): keep the hosted setup in react-supabase-todolist and add…
khawarizmus Oct 2, 2026
93446b5
Merge remote-tracking branch 'origin/main' into diagnostics-poc
khawarizmus Oct 12, 2026
8c614cd
Merge remote-tracking branch 'origin/main' into diagnostics-poc
simolus3 Oct 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/initial-diagnostics-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@powersync/diagnostics-core': patch
'@powersync/diagnostics-ui': patch
'@powersync/diagnostics': patch
---

Initial automated release.
5 changes: 5 additions & 0 deletions .changeset/new-keys-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/web': minor
---

Add a `@powersync/web/devtools` subpath that lists the page's open databases for development tooling, and broadcast core diagnostics events to it.
5 changes: 5 additions & 0 deletions .changeset/node-devtools-diagnostics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/node': minor
---

Forward core diagnostics events to PowerSync DevTools, so the Buckets tab shows per-bucket totals.
5 changes: 5 additions & 0 deletions .changeset/pretty-owls-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/shared-internals': patch
---

Fix `expiresAt` and `lastSyncedAt` on sync stream subscriptions being invalid dates.
5 changes: 5 additions & 0 deletions .changeset/shaggy-tools-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/shared-internals': minor
---

Wire the core diagnostics event stream into the sync client and keep the active `connector` available for the whole connection lifetime.
5 changes: 5 additions & 0 deletions .changeset/silly-apricots-clap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/nuxt': major
---

**Breaking:** `NuxtPowerSyncDatabase` is removed; use `PowerSyncDatabase` with `connect(connector, { diagnostics: true })`. Diagnostics now come from `@powersync/diagnostics`: a PowerSync tab on Nuxt DevTools 3, the devframe dock with MCP tools on Nuxt DevTools 4.
Comment thread
simolus3 marked this conversation as resolved.
5 changes: 5 additions & 0 deletions .changeset/strange-peaches-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/common': minor
---

Add a `diagnostics` sync option that enables the SQLite core's diagnostics event stream.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
node_modules
.env
lib
# Source folders named lib are not build output.
!packages/*/src/lib/
!tools/diagnostics-app/src/lib/
dist
.nuxt
Expand Down
2 changes: 2 additions & 0 deletions demos/example-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Results from the query are printed every time it changes. Try:
1. Updating a row in the backend database and see changes reflected in the running client.
2. Enter `add('my list')` and see the new list show up in the backend database.

The demo also starts [PowerSync DevTools](https://docs.powersync.com/tools/devtools-overview) and prints its link. Open the link to see the sync status, buckets, local data and logs of this client.

## Encryption

This demo can use encrypted databases with the `better-sqlite3-multiple-ciphers` package.
Expand Down
1 change: 1 addition & 0 deletions demos/example-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"start": "node --import ./register.mjs src/main.ts"
},
"dependencies": {
"@powersync/diagnostics": "~0.0.1",
"@powersync/node": "^1.1.1",
"better-sqlite3": "^12.10.0",
"better-sqlite3-multiple-ciphers": "^12.9.0",
Expand Down
2 changes: 2 additions & 0 deletions demos/example-node/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ packages:
allowBuilds:
better-sqlite3: true
better-sqlite3-multiple-ciphers: true
# Pulled in by @powersync/diagnostics; its install script only picks a Vue version and is not needed.
vue-demi: false
9 changes: 9 additions & 0 deletions demos/example-node/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,19 @@ const main = async () => {
console.log(await db.get('SELECT powersync_rs_version();'));
await db.connect(new DemoConnector(), {
connectionMethod: SyncStreamConnectionMethod.WEB_SOCKET,
// Per-bucket download totals for PowerSync DevTools.
diagnostics: true,
appMetadata: {
app_version: process.env.npm_package_version || 'unknown'
}
});
// PowerSync DevTools: a live view of this client in the browser. Development only. Imported here so
// an install without dev dependencies does not need the package.
if (process.env.NODE_ENV !== 'production') {
const { enablePowerSyncDiagnostics } = await import('@powersync/diagnostics/node');
const devtools = await enablePowerSyncDiagnostics(db);
Comment thread
simolus3 marked this conversation as resolved.
console.log(`PowerSync DevTools: ${devtools.signInUrl}`);
}
// Example using a proxy agent for more control over the connection:
// const proxyAgent = new (await import('undici')).ProxyAgent({
// uri: 'http://localhost:8080',
Expand Down
2 changes: 1 addition & 1 deletion demos/nuxt-supabase-todolist/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const appIsReady = ref(false)
provide('appIsReady', readonly(appIsReady))

const powerSync = usePowerSync()
const syncStatus = usePowerSyncStatus()
const syncStatus = useStatus()

const user = useSupabaseUser()
const { logger: powerSyncLogger } = useDiagnosticsLogger()
Expand Down
23 changes: 22 additions & 1 deletion demos/nuxt-supabase-todolist/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
import type { Plugin } from 'vite';

/**
* Nuxt's `nuxt:replace` plugin rewrites `import.meta.*` defines with a text search, including inside
* string literals. Vite prepends its env module, which lists those defines as object keys, to workers
* spawned with `@vite-ignore` options such as the PowerSync worker. The replaced keys are not valid
* JavaScript and the worker fails to transform. This plugin runs before `nuxt:replace` and turns the
* keys into computed keys the text search cannot match.
*/
function workerEnvDefinesWorkaround(): Plugin {
return {
name: 'powersync-demo:worker-env-defines',
transform(code, id) {
if (!id.includes('worker_file&type=ignore')) return;
return { code: code.replace(/"import\.meta\.(\w+)":/g, '["import.meta" + ".$1"]:'), map: null };
}
};
}

export default defineNuxtConfig({
modules: ['@powersync/nuxt', '@nuxt/eslint', '@nuxt/ui', '@nuxtjs/supabase'],
ssr: false,
Expand Down Expand Up @@ -27,7 +46,9 @@ export default defineNuxtConfig({

worker: {
format: 'es'
}
},

plugins: [workerEnvDefinesWorkaround()]
},

unocss: {
Expand Down
6 changes: 4 additions & 2 deletions demos/nuxt-supabase-todolist/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"private": true,
"name": "powersync-nuxt-supabase-todolist",
"type": "module",
"packageManager": "pnpm@11.21.0",
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build",
Expand All @@ -18,8 +20,8 @@
},
"devDependencies": {
"@iconify-json/carbon": "^1.2.18",
"@nuxt/devtools": "^1.0.6",
"@nuxt/devtools": "^3.4.2",
"@nuxt/eslint": "^1.9.0",
"nuxt": "4.1.3"
"nuxt": "4.5.2"
}
}
3 changes: 2 additions & 1 deletion demos/nuxt-supabase-todolist/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ const user = asyncComputed(async () => await client.auth.getUser().then(res => r
const toast = useToast()

const db = usePowerSyncKysely<Database>()
const { clearData } = usePowerSyncInspectorDiagnostics()
const powerSync = usePowerSync()
const clearData = () => powerSync.value.disconnectAndClear()

const taskQuery = computed(() => db.selectFrom('tasks')
.where('user_id', '=', user.value?.id ?? '')
Expand Down
6 changes: 4 additions & 2 deletions demos/nuxt-supabase-todolist/plugins/powersync.client.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { PowerSyncDatabase } from '@powersync/web'
import {
AppSchemaWithDiagnostics,
} from '~/powersync/AppSchema'
import { SupabaseConnector } from '~/powersync/SuperbaseConnector'
export default defineNuxtPlugin({
async setup(nuxtApp) {
const db = new NuxtPowerSyncDatabase({
const db = new PowerSyncDatabase({
database: {
dbFilename: 'a-db-name.sqlite',
},
Expand All @@ -15,7 +16,8 @@ export default defineNuxtPlugin({

await db.init()

await db.connect(connector)
// Enables the core diagnostics stream (per-bucket totals in the diagnostics UI).
await db.connect(connector, { diagnostics: true })

const plugin = createPowerSyncPlugin({ database: db })

Expand Down
11 changes: 11 additions & 0 deletions demos/react-supabase-todolist/.env.local.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,14 @@ VITE_POWERSYNC_URL=https://foo.powersync.journeyapps.com
# Whether to use https://docs.powersync.com/client-sdks/advanced/checkpoint-requests to implement an explicit refresh
# button for sync.
VITE_USE_POWERSYNC_CHECKPOINT_REQUESTS=false

# Local setup (see "Run with Local Supabase and PowerSync" in the README).
# Use these values for the three VITE_ settings above:
# VITE_SUPABASE_URL=http://127.0.0.1:54321
# VITE_SUPABASE_ANON_KEY=<the Publishable key from `supabase start`>
# VITE_POWERSYNC_URL=http://localhost:8080
# The local PowerSync service reads the values below through `docker run --env-file`. The app ignores them.
PS_POSTGRESQL_URI=postgresql://postgres:postgres@supabase_db_react-supabase-todolist:5432/postgres
PS_JWKS_URI=http://kong:8000/auth/v1/.well-known/jwks.json
PS_API_TOKEN=anything-super-secret-token
PS_PORT=8080
37 changes: 37 additions & 0 deletions demos/react-supabase-todolist/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Prerequisites:
* To run this demo, you need to have properly configured Supabase and PowerSync projects. Follow the instructions in our Supabase<>PowerSync integration guide:
* [Configure Supabase](https://docs.powersync.com/integration-guides/supabase-+-powersync#configure-supabase)
* [Configure PowerSync](https://docs.powersync.com/integration-guides/supabase-+-powersync#configure-powersync)
* Or run Supabase and PowerSync locally instead. See [Run with Local Supabase and PowerSync](#run-with-local-supabase-and-powersync).

Switch into the demo's directory:

Expand Down Expand Up @@ -41,6 +42,42 @@ pnpm dev

Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.

## Run with Local Supabase and PowerSync

The demo can also run against local Supabase and PowerSync services. You need the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) and Docker. Install dependencies and copy `.env.local.template` to `.env.local` as above, then:

1. Start Supabase. It creates the `lists` and `todos` tables from `supabase/migrations`:

```bash
supabase start
```

2. In `.env.local`, set the three `VITE_` values to the local services. `.env.local.template` lists them under "Local setup". Copy the **Publishable** key from the `supabase start` output into `VITE_SUPABASE_ANON_KEY`.

3. Start PowerSync on the Supabase network:

```bash
docker run \
-p 8080:8080 \
-e POWERSYNC_CONFIG_B64=$(base64 -i ./powersync.yaml) \
-e POWERSYNC_SYNC_RULES_B64=$(base64 -i ./sync-config.yaml) \
--env-file ./.env.local \
--network supabase_network_react-supabase-todolist \
--name powersync-react-todolist journeyapps/powersync-service:latest
```

4. Run the development server:

```bash
pnpm dev
```

Open [http://localhost:5173](http://localhost:5173), sign up with any email and password, and create a list.

## PowerSync DevTools

The development server includes [PowerSync DevTools](https://docs.powersync.com/tools/devtools/vite). Open the Vite DevTools dock at the bottom of the page and select **PowerSync** to see the sync status, buckets, streams, local data and logs. The first time, confirm the browser with the code that the terminal prints.

## Progressive Web App (PWA)

This demo is PWA compatible, and works fully offline. PWA is not available in development (watch) mode. The manifest and service worker is built using [vite-plugin-pwa](https://vite-pwa-org.netlify.app/).
Expand Down
11 changes: 7 additions & 4 deletions demos/react-supabase-todolist/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview",
"start": "pnpm build && pnpm preview"
"start": "pnpm build && pnpm preview",
"test:build": "pnpm build"
},
"dependencies": {
"@powersync/react": "^2.0.2",
Expand All @@ -24,16 +25,18 @@
"react-router-dom": "^6.22.3"
},
"devDependencies": {
"@powersync/diagnostics": "~0.0.1",
"@swc/core": "~1.6.0",
"@types/lodash": "^4.14.202",
"@types/node": "^20.11.25",
"@types/react": "^18.2.64",
"@types/react-dom": "^18.2.21",
"@vitejs/plugin-react": "^4.2.1",
"@vitejs/devtools": "^0.7.6",
"@vitejs/plugin-react": "^6.1.1",
"autoprefixer": "^10.4.18",
"babel-loader": "^9.1.3",
"typescript": "^5.4.2",
"vite": "^5.1.5",
"vite-plugin-pwa": "^0.19.2"
"vite": "^8.3.0",
"vite-plugin-pwa": "^1.3.0"
}
}
2 changes: 2 additions & 0 deletions demos/react-supabase-todolist/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ packages:
allowBuilds:
'@swc/core': true
esbuild: true
# Pulled in by @powersync/diagnostics; its install script only picks a Vue version and is not needed.
vue-demi: false

minimumReleaseAgeExclude:
- '@journeyapps/*'
Expand Down
32 changes: 32 additions & 0 deletions demos/react-supabase-todolist/powersync.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# yaml-language-server: $schema=https://unpkg.com/@powersync/service-schema@latest/json-schema/powersync-config.json
replication:
connections:
- type: postgresql
uri: !env PS_POSTGRESQL_URI
sslmode: disable
# sslmode: verify-full
debug_api: true

storage:
type: postgresql
uri: !env PS_POSTGRESQL_URI
sslmode: disable
# sslmode: verify-full

sync_config:
path: ./sync-config.yaml

port: !env PS_PORT

client_auth:
jwks_uri: !env PS_JWKS_URI
audience:
- authenticated

telemetry:
prometheus_port: 9090
disable_telemetry_sharing: true

api:
tokens:
- !env PS_API_TOKEN
2 changes: 1 addition & 1 deletion demos/react-supabase-todolist/src/app/views/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default function ViewsLayout({ children }: { children: React.ReactNode })
<Box sx={{ flexGrow: 1 }}>
<Typography>{title}</Typography>
</Box>
{status?.connected && useCheckpointRequests === 'true' && (
{status?.connected && useCheckpointRequests && (
<Tooltip title="Request explicit sync">
<IconButton size="small" color="inherit" aria-label="refresh" onClick={explicitSync}>
<S.RefreshIcon spinning={explicitRefresh == 'working'} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ export const syncOptions: SyncOptions = {
appMetadata: {
app_version: APP_VERSION
},
checkpointMode: useCheckpointRequests ? 'requests' : 'legacy'
checkpointMode: useCheckpointRequests ? 'requests' : 'legacy',
// Per-bucket totals in the PowerSync DevTools Buckets tab.
diagnostics: true
};

const QueryStore = React.createContext<QueryStore | null>(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { FC, ReactNode } from 'react';
export const GuardBySync: FC<{ children: ReactNode; priority?: number }> = ({ children, priority }) => {
const status = useStatus();

const hasSynced = priority == null ? status.hasSynced : status.statusForPriority(priority).hasSynced;
const hasSynced = priority == null ? status.hasSynced : status.statusForPriority(priority)?.hasSynced;
if (hasSynced) {
return children;
}
Expand Down
Loading
Loading