diff --git a/demos/diagnostics-app/.gitignore b/demos/diagnostics-app/.gitignore
deleted file mode 100644
index 0cc2f139..00000000
--- a/demos/diagnostics-app/.gitignore
+++ /dev/null
@@ -1,47 +0,0 @@
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-
-# dependencies
-/node_modules
-/.pnp
-.pnp.js
-.yarn/install-state.gz
-
-# testing
-/coverage
-
-# next.js
-/.next/
-/out/
-
-# production
-/build
-# misc
-.DS_Store
-*.pem
-
-# debug
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# local env files
-.env*.local
-
-# vercel
-.vercel
-
-# typescript
-*.tsbuildinfo
-next-env.d.ts
-
-# ide
-.idea
-.fleet
-.vscode
-
-# PWA
-**/public/workbox-*.js
-**/public/sw.js
-**/public/swe-worker-*
-**/public/worker-*.js
-**/public/fallback-*.js
diff --git a/demos/diagnostics-app/CHANGELOG.md b/demos/diagnostics-app/CHANGELOG.md
deleted file mode 100644
index 16c77018..00000000
--- a/demos/diagnostics-app/CHANGELOG.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# diagnostics-app
-
-## 0.1.1
-
-### Patch Changes
-
-- Updated dependencies [9bf5a76]
- - @journeyapps/powersync-react@1.1.0
- - @journeyapps/powersync-sdk-web@0.3.3
-
-## 0.0.1
diff --git a/demos/diagnostics-app/README.md b/demos/diagnostics-app/README.md
deleted file mode 100644
index 7013485d..00000000
--- a/demos/diagnostics-app/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# Diagnostics app
diff --git a/demos/diagnostics-app/package.json b/demos/diagnostics-app/package.json
deleted file mode 100644
index 0ff986ce..00000000
--- a/demos/diagnostics-app/package.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "@journeyapps/powersync-diagnostics-app",
- "version": "0.1.1",
- "private": true,
- "scripts": {
- "dev": "vite",
- "build": "tsc -b && vite build",
- "preview": "vite preview",
- "start": "pnpm build && pnpm preview"
- },
- "dependencies": {
- "@journeyapps/powersync-react": "workspace:*",
- "@journeyapps/powersync-sdk-web": "workspace:*",
- "@journeyapps/wa-sqlite": "~0.1.1",
- "@mui/material": "^5.15.12",
- "@mui/x-data-grid": "^6.19.6",
- "js-logger": "^1.6.1",
- "lodash": "^4.17.21",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-router-dom": "^6.22.3"
- },
- "devDependencies": {
- "@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",
- "autoprefixer": "^10.4.18",
- "babel-loader": "^9.1.3",
- "typescript": "^5.4.2",
- "vite": "^5.1.5",
- "vite-plugin-pwa": "^0.19.2",
- "vite-plugin-top-level-await": "^1.4.1",
- "vite-plugin-wasm": "^3.3.0"
- }
-}
diff --git a/demos/diagnostics-app/public/favicon.ico b/demos/diagnostics-app/public/favicon.ico
deleted file mode 100644
index 96be8f92..00000000
Binary files a/demos/diagnostics-app/public/favicon.ico and /dev/null differ
diff --git a/demos/diagnostics-app/public/icons/icon-192x192.png b/demos/diagnostics-app/public/icons/icon-192x192.png
deleted file mode 100644
index 3cd46ff8..00000000
Binary files a/demos/diagnostics-app/public/icons/icon-192x192.png and /dev/null differ
diff --git a/demos/diagnostics-app/public/icons/icon-256x256.png b/demos/diagnostics-app/public/icons/icon-256x256.png
deleted file mode 100644
index 4798983e..00000000
Binary files a/demos/diagnostics-app/public/icons/icon-256x256.png and /dev/null differ
diff --git a/demos/diagnostics-app/public/icons/icon-384x384.png b/demos/diagnostics-app/public/icons/icon-384x384.png
deleted file mode 100644
index bc1e64e8..00000000
Binary files a/demos/diagnostics-app/public/icons/icon-384x384.png and /dev/null differ
diff --git a/demos/diagnostics-app/public/icons/icon-512x512.png b/demos/diagnostics-app/public/icons/icon-512x512.png
deleted file mode 100644
index c7d0a3a8..00000000
Binary files a/demos/diagnostics-app/public/icons/icon-512x512.png and /dev/null differ
diff --git a/demos/diagnostics-app/public/icons/icon.png b/demos/diagnostics-app/public/icons/icon.png
deleted file mode 100644
index eab59883..00000000
Binary files a/demos/diagnostics-app/public/icons/icon.png and /dev/null differ
diff --git a/demos/diagnostics-app/public/powersync-logo.svg b/demos/diagnostics-app/public/powersync-logo.svg
deleted file mode 100644
index 32c83dd1..00000000
--- a/demos/diagnostics-app/public/powersync-logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/demos/diagnostics-app/src/app/globals.css b/demos/diagnostics-app/src/app/globals.css
deleted file mode 100644
index 5ceb2604..00000000
--- a/demos/diagnostics-app/src/app/globals.css
+++ /dev/null
@@ -1,12 +0,0 @@
-:root {
- --foreground-rgb: 255, 255, 255;
- --background-start-rgb: 0, 0, 0;
- --background-end-rgb: 0, 0, 0;
-}
-
-body {
- color: rgb(var(--foreground-rgb));
- min-height: 100vh;
- margin: 0;
- background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb));
-}
diff --git a/demos/diagnostics-app/src/app/index.tsx b/demos/diagnostics-app/src/app/index.tsx
deleted file mode 100644
index 49a9ccd4..00000000
--- a/demos/diagnostics-app/src/app/index.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { createRoot } from 'react-dom/client';
-import { RouterProvider } from 'react-router-dom';
-import { SystemProvider } from '../components/providers/SystemProvider';
-import { ThemeProviderContainer } from '../components/providers/ThemeProviderContainer';
-import { router } from './router';
-
-const root = createRoot(document.getElementById('app')!);
-root.render();
-
-export function App() {
- return (
-
-
-
-
-
- );
-}
diff --git a/demos/diagnostics-app/src/app/login.tsx b/demos/diagnostics-app/src/app/login.tsx
deleted file mode 100644
index 638fea35..00000000
--- a/demos/diagnostics-app/src/app/login.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import { LoginDetailsWidget } from '@/components/widgets/LoginDetailsWidget';
-import { useNavigate } from 'react-router-dom';
-import { DEFAULT_ENTRY_ROUTE } from '@/app/router';
-import { connector } from '@/components/providers/SystemProvider';
-
-export default function LoginPage() {
- const navigate = useNavigate();
-
- return (
- {
- await connector.signIn(values);
-
- navigate(DEFAULT_ENTRY_ROUTE);
- }}
- />
- );
-}
diff --git a/demos/diagnostics-app/src/app/page.tsx b/demos/diagnostics-app/src/app/page.tsx
deleted file mode 100644
index 59c3d3b2..00000000
--- a/demos/diagnostics-app/src/app/page.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import React from 'react';
-import { CircularProgress, Grid, styled } from '@mui/material';
-import { useNavigate } from 'react-router-dom';
-import { DEFAULT_ENTRY_ROUTE, LOGIN_ROUTE } from './router';
-import { connector } from '@/components/providers/SystemProvider';
-
-export type LoginFormParams = {
- email: string;
- password: string;
-};
-
-/**
- * This page shows a loading spinner we detect a session
- * and redirect either to the app or auth flow.
- */
-export default function EntryPage() {
- const navigate = useNavigate();
-
- React.useEffect(() => {
- if (connector.hasCredentials()) {
- navigate(DEFAULT_ENTRY_ROUTE);
- } else {
- navigate(LOGIN_ROUTE);
- }
- }, []);
-
- return (
-
-
-
-
-
- );
-}
-
-namespace S {
- export const CenteredGrid = styled(Grid)`
- display: flex;
- justify-content: center;
- align-items: center;
- `;
-
- export const MainGrid = styled(CenteredGrid)`
- min-height: 100vh;
- `;
-}
diff --git a/demos/diagnostics-app/src/app/router.tsx b/demos/diagnostics-app/src/app/router.tsx
deleted file mode 100644
index 0cacc549..00000000
--- a/demos/diagnostics-app/src/app/router.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Outlet, createBrowserRouter } from 'react-router-dom';
-import LoginPage from './login';
-import EntryPage from './page';
-import ViewsLayout from './views/layout';
-import SQLConsolePage from './views/sql-console/page';
-
-export const LOGIN_ROUTE = '/login';
-export const SQL_CONSOLE_ROUTE = '/sql-console';
-
-/**
- * Navigate to this route after authentication
- */
-export const DEFAULT_ENTRY_ROUTE = SQL_CONSOLE_ROUTE;
-
-export const router = createBrowserRouter([
- {
- path: '/',
- element:
- },
- {
- path: LOGIN_ROUTE,
- element:
- },
- {
- element: (
-
-
-
- ),
- children: [
- {
- path: SQL_CONSOLE_ROUTE,
- element:
- }
- ]
- }
-]);
diff --git a/demos/diagnostics-app/src/app/views/layout.tsx b/demos/diagnostics-app/src/app/views/layout.tsx
deleted file mode 100644
index bf74eb79..00000000
--- a/demos/diagnostics-app/src/app/views/layout.tsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import ChecklistRtlIcon from '@mui/icons-material/ChecklistRtl';
-import ExitToAppIcon from '@mui/icons-material/ExitToApp';
-import MenuIcon from '@mui/icons-material/Menu';
-import NorthIcon from '@mui/icons-material/North';
-import SignalWifiOffIcon from '@mui/icons-material/SignalWifiOff';
-import SouthIcon from '@mui/icons-material/South';
-import TerminalIcon from '@mui/icons-material/Terminal';
-import WifiIcon from '@mui/icons-material/Wifi';
-import {
- AppBar,
- Box,
- Divider,
- Drawer,
- IconButton,
- List,
- ListItem,
- ListItemButton,
- ListItemIcon,
- ListItemText,
- Toolbar,
- Typography,
- styled
-} from '@mui/material';
-import React from 'react';
-
-import { useNavigationPanel } from '@/components/navigation/NavigationPanelContext';
-import { usePowerSync } from '@journeyapps/powersync-react';
-import { useNavigate } from 'react-router-dom';
-import { LOGIN_ROUTE, SQL_CONSOLE_ROUTE } from '@/app/router';
-
-export default function ViewsLayout({ children }: { children: React.ReactNode }) {
- const powerSync = usePowerSync();
- const navigate = useNavigate();
-
- const [syncStatus, setSyncStatus] = React.useState(powerSync.currentStatus);
- const [openDrawer, setOpenDrawer] = React.useState(false);
- const { title } = useNavigationPanel();
-
- const NAVIGATION_ITEMS = React.useMemo(
- () => [
- {
- path: SQL_CONSOLE_ROUTE,
- title: 'SQL Console',
- icon: () =>
- },
- {
- path: LOGIN_ROUTE,
- title: 'Sign Out',
- beforeNavigate: async () => {
- await powerSync.disconnectAndClear();
- },
- icon: () =>
- }
- ],
- [powerSync]
- );
-
- React.useEffect(() => {
- const l = powerSync.registerListener({
- statusChanged: (status) => {
- setSyncStatus(status);
- }
- });
- return () => l?.();
- }, [powerSync]);
-
- return (
-
-
-
- setOpenDrawer(!openDrawer)}
- >
-
-
-
- {title}
-
-
-
- {syncStatus?.connected ? : }
-
-
- setOpenDrawer(false)}>
-
-
-
- {NAVIGATION_ITEMS.map((item) => (
-
- {
- await item.beforeNavigate?.();
- navigate(item.path);
- setOpenDrawer(false);
- }}
- >
- {item.icon()}
-
-
-
- ))}
-
-
- {children}
-
- );
-}
-
-namespace S {
- export const MainBox = styled(Box)`
- flex-grow: 1;
- `;
-
- export const TopBar = styled(AppBar)`
- margin-bottom: 20px;
- `;
-
- export const PowerSyncLogo = styled('img')`
- max-width: 250px;
- max-height: 250px;
- object-fit: contain;
- padding: 20px;
- `;
-}
diff --git a/demos/diagnostics-app/src/app/views/sql-console/page.tsx b/demos/diagnostics-app/src/app/views/sql-console/page.tsx
deleted file mode 100644
index 011966f2..00000000
--- a/demos/diagnostics-app/src/app/views/sql-console/page.tsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import React from 'react';
-import { usePowerSyncWatchedQuery } from '@journeyapps/powersync-react';
-import { Box, Button, Grid, TextField, styled } from '@mui/material';
-import { DataGrid } from '@mui/x-data-grid';
-import { NavigationPage } from '@/components/navigation/NavigationPage';
-
-export type LoginFormParams = {
- email: string;
- password: string;
-};
-
-const DEFAULT_QUERY = `
-WITH oplog_stats AS (SELECT bucket, sum(length(data) + length(row_type) + length(row_id) + length(bucket) + length(key) + 50) as data_size, count() as operation_count FROM ps_oplog GROUP BY bucket)
-SELECT local.id as name, stats.data_size, stats.operation_count, local.download_size, local.total_operations, local.downloading FROM local_bucket_data local JOIN oplog_stats stats ON stats.bucket = local.id`;
-
-export default function SQLConsolePage() {
- const inputRef = React.useRef();
- const [query, setQuery] = React.useState(DEFAULT_QUERY);
- const querySQLResult = usePowerSyncWatchedQuery(query);
-
- const queryDataGridResult = React.useMemo(() => {
- const firstItem = querySQLResult?.[0];
-
- return {
- columns: firstItem
- ? Object.keys(firstItem).map((field) => ({
- field,
- flex: 1
- }))
- : [],
- rows: querySQLResult
- };
- }, [querySQLResult]);
-
- return (
-
-
-
-
- {
- const inputValue = inputRef.current?.value;
- if (e.key == 'Enter' && inputValue) {
- setQuery(inputValue);
- }
- }}
- />
-
-
-
-
-
-
- {queryDataGridResult ? (
-
- {queryDataGridResult.columns ? (
- ({ ...r, id: r.id ?? index })) ?? []}
- columns={queryDataGridResult.columns}
- initialState={{
- pagination: {
- paginationModel: {
- pageSize: 20
- }
- }
- }}
- pageSizeOptions={[20]}
- disableRowSelectionOnClick
- />
- ) : null}
-
- ) : null}
-
-
- );
-}
-
-namespace S {
- export const MainContainer = styled(Box)`
- padding: 20px;
- `;
-
- export const QueryResultContainer = styled(Box)`
- margin-top: 40px;
- `;
-
- export const CenteredGrid = styled(Grid)`
- display: flex;
- justify-content: center;
- align-items: center;
- `;
-}
diff --git a/demos/diagnostics-app/src/components/navigation/NavigationPage.tsx b/demos/diagnostics-app/src/components/navigation/NavigationPage.tsx
deleted file mode 100644
index ac0cc307..00000000
--- a/demos/diagnostics-app/src/components/navigation/NavigationPage.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react';
-import { useNavigationPanel } from './NavigationPanelContext';
-import { Box, styled } from '@mui/material';
-
-/**
- * Wraps a component with automatic navigation panel title management
- */
-export const NavigationPage: React.FC> = ({ title, children }) => {
- const navigationPanel = useNavigationPanel();
-
- React.useEffect(() => {
- navigationPanel.setTitle(title);
-
- return () => navigationPanel.setTitle('');
- }, [title, navigationPanel]);
-
- return {children};
-};
-
-namespace S {
- export const Container = styled(Box)`
- margin: 10px;
- `;
-}
diff --git a/demos/diagnostics-app/src/components/navigation/NavigationPanelContext.tsx b/demos/diagnostics-app/src/components/navigation/NavigationPanelContext.tsx
deleted file mode 100644
index 4745475d..00000000
--- a/demos/diagnostics-app/src/components/navigation/NavigationPanelContext.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-
-export type NavigationPanelController = {
- setTitle: (title: string) => void;
- title: string;
-};
-
-export const NavigationPanelContext = React.createContext({
- setTitle: () => {
- throw new Error(`No NavigationPanelContext has been provided`);
- },
- title: ''
-});
-
-export const NavigationPanelContextProvider = ({ children }: { children: React.ReactNode }) => {
- const [title, setTitle] = React.useState('');
-
- return {children};
-};
-
-export const useNavigationPanel = () => React.useContext(NavigationPanelContext);
diff --git a/demos/diagnostics-app/src/components/providers/SystemProvider.tsx b/demos/diagnostics-app/src/components/providers/SystemProvider.tsx
deleted file mode 100644
index 172fb919..00000000
--- a/demos/diagnostics-app/src/components/providers/SystemProvider.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { NavigationPanelContextProvider } from '@/components/navigation/NavigationPanelContext';
-import { AppSchema } from '@/library/powersync/AppSchema';
-import { TokenConnector } from '@/library/powersync/TokenConnector';
-import { PowerSyncContext } from '@journeyapps/powersync-react';
-import { WASQLitePowerSyncDatabaseOpenFactory } from '@journeyapps/powersync-sdk-web';
-import { CircularProgress } from '@mui/material';
-import Logger from 'js-logger';
-import React, { Suspense } from 'react';
-
-Logger.useDefaults();
-Logger.setLevel(Logger.DEBUG);
-
-export const db = new WASQLitePowerSyncDatabaseOpenFactory({
- dbFilename: 'example.db',
- schema: AppSchema
-}).getInstance();
-export const connector = new TokenConnector();
-
-if (connector.hasCredentials()) {
- db.connect(connector);
- connector.loadCheckpoint();
-}
-
-(window as any).db = db;
-
-export const SystemProvider = ({ children }: { children: React.ReactNode }) => {
- return (
- }>
-
- {children}
-
-
- );
-};
-
-export default SystemProvider;
diff --git a/demos/diagnostics-app/src/components/providers/ThemeProviderContainer.tsx b/demos/diagnostics-app/src/components/providers/ThemeProviderContainer.tsx
deleted file mode 100644
index 9b9c1d61..00000000
--- a/demos/diagnostics-app/src/components/providers/ThemeProviderContainer.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import { createTheme, ThemeProvider } from '@mui/material/styles';
-
-export const ThemeProviderContainer: React.FC> = ({ children }) => {
- const theme = React.useMemo(() => {
- return createTheme({
- palette: {
- mode: 'dark',
- primary: {
- main: '#c44eff'
- }
- },
- typography: {
- fontFamily: 'Rubik, sans-serif'
- }
- });
- }, []);
-
- return {children};
-};
diff --git a/demos/diagnostics-app/src/components/widgets/LoginDetailsWidget.tsx b/demos/diagnostics-app/src/components/widgets/LoginDetailsWidget.tsx
deleted file mode 100644
index f5a3b5af..00000000
--- a/demos/diagnostics-app/src/components/widgets/LoginDetailsWidget.tsx
+++ /dev/null
@@ -1,167 +0,0 @@
-import React from 'react';
-import { Box, Button, ButtonGroup, FormGroup, Paper, TextField, Typography, styled } from '@mui/material';
-import { Formik, FormikErrors } from 'formik';
-
-export type LoginDetailsFormValues = {
- token: string;
- endpoint: string;
-};
-
-export type LoginAction = {
- title: string;
- onClick: (values: LoginDetailsFormValues) => any;
-};
-
-export type LoginDetailsWidgetProps = {
- onSubmit: (values: LoginDetailsFormValues) => any;
-};
-
-export const LoginDetailsWidget: React.FC = (props) => {
- return (
-
-
- Diagnostics Config
-
-
-
-
- initialValues={{ token: '', endpoint: '' }}
- validateOnChange={false}
- validateOnBlur={false}
- validate={(values) => {
- const errors: FormikErrors = {};
- if (!values.token) {
- errors.token = 'Required';
- }
-
- return errors;
- }}
- onSubmit={async (values, { setSubmitting, setFieldError }) => {
- try {
- const endpoint = values.endpoint || getTokenEndpoint(values.token);
- if (endpoint == null) {
- throw new Error('endpoint is required');
- }
- await props.onSubmit({
- token: values.token,
- endpoint
- });
- } catch (ex: any) {
- console.error(ex);
- setSubmitting(false);
- setFieldError('endpoint', ex.message);
- }
- }}
- >
- {({ values, errors, handleChange, handleBlur, isSubmitting, handleSubmit }) => (
-
- )}
-
-
-
- );
-};
-
-namespace S {
- export const MainContainer = styled(Box)`
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- min-height: 100vh;
- `;
-
- export const LoginContainer = styled(Paper)`
- width: 100%;
- padding: 20px;
- display: flex;
- flex-grow: 1;
- flex-direction: column;
- justify-content: center;
-
- ${(props) => props.theme.breakpoints.up('sm')} {
- flex-grow: 0;
- max-width: 600px;
- }
- `;
-
- export const LoginHeader = styled(Typography)`
- margin-bottom: 20px;
- `;
-
- export const LogoBox = styled(Box)`
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- margin: 40px;
- `;
-
- export const Logo = styled('img')`
- width: auto;
- height: auto;
- max-width: ${(props) => props.width}px;
- max-height: ${(props) => props.height}px;
- margin-bottom: 10px;
- `;
-
- export const ActionButtonGroup = styled(ButtonGroup)`
- margin-top: 20px;
- width: 100%;
- display: flex;
- justify-content: end;
- `;
-
- export const TextInput = styled(TextField)`
- margin-bottom: 20px;
- `;
-}
-
-function getTokenEndpoint(token: string) {
- try {
- const [head, body, signature] = token.split('.');
- const payload = JSON.parse(atob(body));
- const aud = payload.aud as string | undefined;
- if (aud?.endsWith('.journeyapps.com')) {
- return aud;
- }
- return null;
- } catch (e) {
- return null;
- }
-}
diff --git a/demos/diagnostics-app/src/index.html b/demos/diagnostics-app/src/index.html
deleted file mode 100644
index de7a97c2..00000000
--- a/demos/diagnostics-app/src/index.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/demos/diagnostics-app/src/library/powersync/AppSchema.ts b/demos/diagnostics-app/src/library/powersync/AppSchema.ts
deleted file mode 100644
index f6f61f73..00000000
--- a/demos/diagnostics-app/src/library/powersync/AppSchema.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { column, Schema, TableV2 } from '@journeyapps/powersync-sdk-web';
-
-export const local_bucket_data = new TableV2(
- {
- total_operations: column.integer,
- last_op: column.text,
- download_size: column.integer,
- downloading: column.integer
- },
- { localOnly: true }
-);
-
-export const AppSchema = new Schema({
- local_bucket_data
-});
-
-export type Database = (typeof AppSchema)['types'];
-export type LocalBucketData = Database['local_bucket_data'];
diff --git a/demos/diagnostics-app/src/library/powersync/TokenConnector.ts b/demos/diagnostics-app/src/library/powersync/TokenConnector.ts
deleted file mode 100644
index 116159f6..00000000
--- a/demos/diagnostics-app/src/library/powersync/TokenConnector.ts
+++ /dev/null
@@ -1,169 +0,0 @@
-import { db } from '@/components/providers/SystemProvider';
-import {
- AbstractPowerSyncDatabase,
- BaseObserver,
- BucketState,
- BucketStorageAdapter,
- BucketStorageListener,
- Checkpoint,
- PowerSyncBackendConnector,
- SyncDataBatch,
- WebRemote,
- WebStreamingSyncImplementation,
- WebStreamingSyncImplementationOptions
-} from '@journeyapps/powersync-sdk-web';
-import { LocalBucketData } from './AppSchema';
-
-export interface Credentials {
- token: string;
- endpoint: string;
-}
-
-export class TokenConnector implements PowerSyncBackendConnector {
- async fetchCredentials() {
- const value = localStorage.getItem('powersync_credentials');
- if (value == null) {
- return null;
- }
- return JSON.parse(value);
- }
-
- async uploadData(database: AbstractPowerSyncDatabase) {
- // Discard any data
- const tx = await database.getNextCrudTransaction();
- await tx?.complete();
- }
-
- async signIn(credentials: Credentials) {
- localStorage.setItem('powersync_credentials', JSON.stringify(credentials));
- await db.connect(this);
- }
-
- hasCredentials() {
- return localStorage.getItem('powersync_credentials') != null;
- }
-
- async loadCheckpoint(): Promise {
- const remote = new WebRemote(this);
-
- let resolveCheckpoint: any = null;
- let checkpointPromise: Promise = new Promise((resolve, reject) => {
- resolveCheckpoint = resolve;
- });
-
- const adapter = new RecordingStorageAdapter(db);
- adapter.registerListener({
- checkpointAvailable(checkpoint) {
- resolveCheckpoint(checkpoint);
- }
- });
-
- const syncOptions: WebStreamingSyncImplementationOptions = {
- adapter,
- remote,
- uploadCrud: async () => {
- // No-op
- },
- identifier: 'diagnostics'
- };
- const sync = new WebStreamingSyncImplementation(syncOptions);
- try {
- await sync.connect();
-
- const checkpoint = await checkpointPromise;
- console.log({ checkpoint });
- return checkpoint;
- } finally {
- // await sync.disconnect();
- }
- }
-}
-
-interface MockStorageListener extends BucketStorageListener {
- checkpointAvailable(checkpoint: Checkpoint): void;
-}
-
-class RecordingStorageAdapter extends BaseObserver implements BucketStorageAdapter {
- private db: AbstractPowerSyncDatabase;
-
- constructor(db: AbstractPowerSyncDatabase) {
- super();
- this.db = db;
- }
-
- async getBucketStates(): Promise {
- const buckets = await this.db.getAll('SELECT * FROM local_bucket_data');
- return buckets.map((bucket) => {
- return {
- bucket: bucket.id,
- op_id: bucket.last_op ?? '0'
- };
- });
- }
-
- startSession() {}
- async removeBuckets(buckets: string[]) {
- if (buckets.length == 0) {
- return;
- }
- await this.db.execute('DELETE FROM local_bucket_data WHERE id IN (SELECT e.value FROM json_each(?) e)', [
- JSON.stringify(buckets)
- ]);
- }
- async setTargetCheckpoint(checkpoint: Checkpoint) {
- await this.db.writeTransaction(async (tx) => {
- for (let bucket of checkpoint.buckets) {
- console.log('save', bucket);
- await tx.execute(
- `INSERT OR REPLACE INTO local_bucket_data(id, total_operations, last_op, download_size, downloading)
- VALUES (
- ?,
- ?,
- IFNULL((SELECT last_op FROM local_bucket_data WHERE id = ?), '0'),
- IFNULL((SELECT download_size FROM local_bucket_data WHERE id = ?), 0),
- IFNULL((SELECT downloading FROM local_bucket_data WHERE id = ?), TRUE)
- )`,
- [bucket.bucket, bucket.count, bucket.bucket, bucket.bucket, bucket.bucket]
- );
- console.log('saved', bucket);
- }
- });
- this.iterateListeners((l) => {
- l.checkpointAvailable?.(checkpoint);
- });
- }
- async syncLocalDatabase(checkpoint: Checkpoint) {
- await this.db.execute('UPDATE local_bucket_data SET downloading = FALSE');
- return { checkpointValid: true, ready: true };
- }
- async hasCompletedSync() {
- return false;
- }
- async hasCrud() {
- return false;
- }
- getMaxOpId() {
- return '9223372036854775807';
- }
- async init() {}
- async saveSyncData(batch: SyncDataBatch) {
- await this.db.writeTransaction(async (tx) => {
- for (let bucket of batch.buckets) {
- const size = JSON.stringify(bucket.data).length;
- await tx.execute(
- 'UPDATE local_bucket_data SET download_size = IFNULL(download_size, 0) + ?, last_op = ?, downloading = ? WHERE id = ?',
- [size, bucket.next_after, bucket.has_more, bucket.bucket]
- );
- }
- });
- }
- async dispose() {}
- async updateLocalTarget(cb: any) {
- return false;
- }
- async getCrudBatch(limit: any) {
- return null;
- }
- async forceCompact() {}
- async autoCompact() {}
-}
diff --git a/demos/diagnostics-app/tsconfig.json b/demos/diagnostics-app/tsconfig.json
deleted file mode 100644
index 7f92a0bc..00000000
--- a/demos/diagnostics-app/tsconfig.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "compilerOptions": {
- "target": "es6",
- "lib": ["dom", "dom.iterable", "esnext"],
- "allowJs": true,
- "skipLibCheck": true,
- "strict": true,
- "noEmit": true,
- "esModuleInterop": true,
- "module": "esnext",
- "moduleResolution": "bundler",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "jsx": "preserve",
- "incremental": true,
- "paths": {
- "@/*": ["./src/*"]
- }
- },
- "exclude": ["node_modules"],
- "references": [
- {
- "path": "../../packages/powersync-sdk-web"
- }
- ]
-}
diff --git a/demos/diagnostics-app/vite.config.mts b/demos/diagnostics-app/vite.config.mts
deleted file mode 100644
index e5d223f5..00000000
--- a/demos/diagnostics-app/vite.config.mts
+++ /dev/null
@@ -1,74 +0,0 @@
-import wasm from 'vite-plugin-wasm';
-import topLevelAwait from 'vite-plugin-top-level-await';
-import { fileURLToPath, URL } from 'url';
-
-import { defineConfig } from 'vite';
-import react from '@vitejs/plugin-react';
-import { VitePWA } from 'vite-plugin-pwa';
-
-// https://vitejs.dev/config/
-export default defineConfig({
- root: 'src',
- build: {
- outDir: '../dist',
- rollupOptions: {
- input: 'src/index.html'
- },
- emptyOutDir: true
- },
- resolve: {
- alias: [{ find: '@', replacement: fileURLToPath(new URL('./src', import.meta.url)) }]
- },
- publicDir: '../public',
- envDir: '..', // Use this dir for env vars, not 'src'.
- optimizeDeps: {
- // Don't optimize these packages as they contain web workers and WASM files.
- // https://github.com/vitejs/vite/issues/11672#issuecomment-1415820673
- exclude: ['@journeyapps/wa-sqlite', '@journeyapps/powersync-sdk-web'],
- include: ['object-hash', 'uuid', 'event-iterator', 'js-logger', 'lodash', 'can-ndjson-stream']
- },
- plugins: [
- wasm(),
- topLevelAwait(),
- react(),
- VitePWA({
- registerType: 'autoUpdate',
- includeAssets: ['powersync-logo.svg', 'supabase-logo.png', 'favicon.ico'],
- manifest: {
- theme_color: '#c44eff',
- background_color: '#c44eff',
- display: 'standalone',
- scope: '/',
- start_url: '/',
- name: 'PowerSync React Demo',
- short_name: 'PowerSync React',
- icons: [
- {
- src: '/icons/icon-192x192.png',
- sizes: '192x192',
- type: 'image/png'
- },
- {
- src: '/icons/icon-256x256.png',
- sizes: '256x256',
- type: 'image/png'
- },
- {
- src: '/icons/icon-384x384.png',
- sizes: '384x384',
- type: 'image/png'
- },
- {
- src: '/icons/icon-512x512.png',
- sizes: '512x512',
- type: 'image/png'
- }
- ]
- }
- })
- ],
- worker: {
- format: 'es',
- plugins: () => [wasm(), topLevelAwait()]
- }
-});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 350dd160..72db7516 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -91,76 +91,6 @@ importers:
specifier: ~5.2.2
version: 5.2.2
- demos/diagnostics-app:
- dependencies:
- '@journeyapps/powersync-react':
- specifier: workspace:*
- version: link:../../packages/powersync-react
- '@journeyapps/powersync-sdk-web':
- specifier: workspace:*
- version: link:../../packages/powersync-sdk-web
- '@journeyapps/wa-sqlite':
- specifier: ~0.1.1
- version: 0.1.1
- '@mui/material':
- specifier: ^5.15.12
- version: 5.15.12(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
- '@mui/x-data-grid':
- specifier: ^6.19.6
- version: 6.19.6(@mui/material@5.15.12)(@mui/system@5.15.12)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
- js-logger:
- specifier: ^1.6.1
- version: 1.6.1
- lodash:
- specifier: ^4.17.21
- version: 4.17.21
- react:
- specifier: ^18.2.0
- version: 18.2.0
- react-dom:
- specifier: ^18.2.0
- version: 18.2.0(react@18.2.0)
- react-router-dom:
- specifier: ^6.22.3
- version: 6.22.3(react-dom@18.2.0)(react@18.2.0)
- devDependencies:
- '@types/lodash':
- specifier: ^4.14.202
- version: 4.17.0
- '@types/node':
- specifier: ^20.11.25
- version: 20.11.26
- '@types/react':
- specifier: ^18.2.64
- version: 18.2.65
- '@types/react-dom':
- specifier: ^18.2.21
- version: 18.2.21
- '@vitejs/plugin-react':
- specifier: ^4.2.1
- version: 4.2.1(vite@5.1.6)
- autoprefixer:
- specifier: ^10.4.18
- version: 10.4.18(postcss@8.4.35)
- babel-loader:
- specifier: ^9.1.3
- version: 9.1.3(@babel/core@7.24.0)(webpack@5.90.3)
- typescript:
- specifier: ^5.4.2
- version: 5.4.2
- vite:
- specifier: ^5.1.5
- version: 5.1.6(@types/node@20.11.26)
- vite-plugin-pwa:
- specifier: ^0.19.2
- version: 0.19.2(vite@5.1.6)(workbox-build@7.0.0)(workbox-window@7.0.0)
- vite-plugin-top-level-await:
- specifier: ^1.4.1
- version: 1.4.1(rollup@2.79.1)(vite@5.1.6)
- vite-plugin-wasm:
- specifier: ^3.3.0
- version: 3.3.0(vite@5.1.6)
-
demos/example-nextjs:
dependencies:
'@emotion/react':
@@ -14911,22 +14841,6 @@ packages:
- supports-color
dev: true
- /@vitejs/plugin-react@4.2.1(vite@5.1.6):
- resolution: {integrity: sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==}
- engines: {node: ^14.18.0 || >=16.0.0}
- peerDependencies:
- vite: ^4.2.0 || ^5.0.0
- dependencies:
- '@babel/core': 7.24.0
- '@babel/plugin-transform-react-jsx-self': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.24.0)
- '@types/babel__core': 7.20.5
- react-refresh: 0.14.0
- vite: 5.1.6(@types/node@20.11.26)
- transitivePeerDependencies:
- - supports-color
- dev: true
-
/@vitest/browser@1.3.1(vitest@1.3.1)(webdriverio@8.32.3):
resolution: {integrity: sha512-pRof8G8nqRWwg3ouyIctyhfIVk5jXgF056uF//sqdi37+pVtDz9kBI/RMu0xlc8tgCyJ2aEMfbgJZPUydlEVaQ==}
peerDependencies:
@@ -22712,6 +22626,8 @@ packages:
peerDependenciesMeta:
webpack:
optional: true
+ webpack-sources:
+ optional: true
dependencies:
webpack: 5.89.0(esbuild@0.19.11)
webpack-sources: 3.2.3
@@ -31040,7 +30956,7 @@ packages:
vite: '>=2.8'
dependencies:
'@rollup/plugin-virtual': 3.0.2(rollup@2.79.1)
- '@swc/core': 1.4.2
+ '@swc/core': 1.4.6
uuid: 9.0.1
vite: 5.1.5(@types/node@20.11.25)
transitivePeerDependencies:
@@ -31068,7 +30984,7 @@ packages:
vite: '>=2.8'
dependencies:
'@rollup/plugin-virtual': 3.0.2(rollup@2.79.1)
- '@swc/core': 1.4.2
+ '@swc/core': 1.4.6
uuid: 9.0.1
vite: 5.1.1(@types/node@20.11.17)
transitivePeerDependencies: