Universal PowerSync Diagnostics (POC) - #1094
khawarizmus wants to merge 33 commits into
Conversation
🦋 Changeset detectedLatest commit: 21248fe The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
simolus3
left a comment
There was a problem hiding this comment.
To share more context here (I've also shared that offline with more context @khawarizmus). I think the idea is awesome, my initial architectural complaints are:
- It's not clear whether we need a browser extension, so remove that from this PR which is already very big (you can open a follow-up PR for that separately).
- I think a JSON-based protocol over "any two way channel" is the wrong abstraction here. It e.g. forces us to re-invent an RPC protocol when some implementations we'll use (say the Dart VM service protocol) are already RPC based.
- None of this should require any changes to an existing SDK package (aside from forwarding core diagnostics events, but even that should likely be a separate PR to validate that the basic integration can work without SDK changes). We can likely inject an agent by writing a vite devtools package instead. Or initially, we could also expose it as a seperate package a user would depend on to expose the channel (e.g. a
enablePowerSyncDiagnostics(port: MessagePort, db: BasePowerSyncDatabase)). - Related to 2 and 3, the interface the diagnostics tool expects an SDK to provide should be an actual TypeScript interface with async methods and event listeners. It is the responsibility of each integration (vite,
postMessageiframe, Dart) to figure out how to implement that interface by doing the serialization itself.
simolus3
left a comment
There was a problem hiding this comment.
I didn't take a look at the UI yet, but the architecture of how devtools are served and integrated looks pretty good at this point. I'll also try to scaffold a Dart integration over the vm service protocol.
| */ | ||
|
|
||
| /** The shape exposed over comlink: `observeEvents` takes a proxied callback instead of a function. */ | ||
| type Remote = Omit<SdkIntegration, 'observeEvents'> & { |
There was a problem hiding this comment.
Let's just make observeEvents return a promise on SdkIntegration, or a Promise<void> | void.
There was a problem hiding this comment.
This was addressed
| // The JavaScript integration (runs in the app page) and the structural database it reads. | ||
| export * from './live-database.js'; | ||
| export * from './agent.js'; | ||
| export * from './state.js'; | ||
|
|
||
| // Moving an integration across an iframe boundary, and deriving UI state from its events. | ||
| export * from './bridge.js'; | ||
| export * from './store.js'; |
There was a problem hiding this comment.
Relying on structural typing to avoid pulling in the JS SDK here is clever, but also feels somewhat fragile.
Given that these files are still only useful when providing diagnostics for JavaScript SDKs, maybe they shouldn't be part of the default export. I think putting them into a separate package is overkill, but maybe they should be exported from a separate entrypoint (say @powersync/diagnostics-core-js-web).
(and then if they're separate exports, I wouldn't mind this package having an optional dependency on @powersync/common and defining the JS agent on BasePowerSyncDatabase).
There was a problem hiding this comment.
The JS-specific code now lives in @powersync/diagnostics-core/js. I kept the structural type instead of adding an optional @powersync/common dependency. The Vite client can now pass WebPowerSyncDatabase directly, and only the Playground UI mock needs to implement that small interface.
…lient implementations # Conflicts: # pnpm-lock.yaml
…ge with components and playground
…d indexes; add SchemaTab to diagnostics UI
…line module imports and setup
…ding columns, indexes, and table options
…ream, UI components, and schema inspection features
…for a cleaner separation
…ion alongside currentOptions
…t and enhance connection handling in extension
…ostMessageTransport, enhance package metadata, and add Chrome types
…nents with icons and status bar
…play and integrate virtual scrolling for upload queue
…t detail component, and improved data handling features
…sizable columns, and theme synchronization
Add dependency-free `shapes.ts` and `integration.ts` as the tool-owned protocol; move PROTOCOL.md into diagnostics-core and rewrite it to interface + shapes.
…ors, support several app tabs
… 7 and build behaviour in the README
…the Nuxt changeset breaking
…rd, fast refusal; drop the stdio mcp command
9c6336a to
bc0edf9
Compare
This PR implements a live-attach diagnostics tool built once and reused across different hosts. It shows the live state of the PowerSync client side.
How it works
The agent runs next to your database. It reads the database and pushes snapshots. The UI rebuilds its state from these snapshots. On the web, the agent runs in your app page. Vite DevTools loads it after you trust the tab. On node, the agent runs in the same process as the database. A React Native app connects to the standalone window over the network (RN has not been tested yet).
The MCP endpoint exposes the same functions as the tools, allowing AI agents to directly query the client app and retrieve diagnostic information.
New packages
@powersync/diagnostics-core. The protocol. It is one interface,SdkIntegration, plus the data shapes. The UI talks only to this interface. Each SDK implements it. The package also has the JavaScript agent and the iframe bridge.@powersync/diagnostics-ui. The UI. Rendered from anSdkIntegration. It runs in an iframe or in a standalone window.@powersync/diagnostics. The host integration, built on devframe. It gives a dock in Vite DevTools, a tab in Nuxt DevTools, a dev server for Node apps, a standalone window via CLI (powersync-devtools), and MCP tools for AI agents.SDK changes
@powersync/common. adiagnosticsoption onconnect(). It turns on the SQLite core diagnostics stream. This gives pre-bucket download stats and inferred column types.@powersync/shared-internals: the sync client keeps the connector for the whole connection. It forwards the core diagnostics events.@powersync/web. a new@powersync/web/devtoolssubpath. It lists the open databases in the page. The agent finds them without any app code.@powersync/nuxt. breaking.NuxtPowerSyncDatabaseis removed. UsePowerSyncDatabasefrom@powersync/weband passconnect(connector, { diagnostics: true }). The module shows the PowerSync tab on Nuxt DevTools 3 and the dock on Nuxt DevTools 4.Tested by hand
compatibilityVersion: 5.devtools: true) and with Vite 7 (@vitejs/devtoolsplugin).Claude code was used to steer the discovery and development. The code was reviewed, tested and modified manually.