Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix] OPFS Sleeping Tabs Sync Deadlock #498

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
12 changes: 12 additions & 0 deletions .changeset/blue-pets-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@powersync/tanstack-react-query': patch
'@powersync/drizzle-driver': patch
'@powersync/kysely-driver': patch
'@powersync/attachments': patch
'@powersync/common': patch
'@powersync/react': patch
'@powersync/vue': patch
'@powersync/web': patch
---

Test for dev packages
5 changes: 5 additions & 0 deletions .changeset/tidy-stingrays-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/web': minor
---

Ensured OPFS tabs are not frozen or put to sleep by browsers. This prevents potential deadlocks in the syncing process.
5 changes: 5 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ jobs:
- name: Install dependencies
run: pnpm install

- name: Configure Playwright
run: |
pnpm exec playwright install-deps
pnpm exec playwright install

- name: Build
run: pnpm build:packages

Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<a href="https://www.powersync.com" target="_blank"><img src="https://github.com/powersync-ja/.github/assets/7372448/d2538c43-c1a0-4c47-9a76-41462dba484f"/></a>
</p>

*[PowerSync](https://www.powersync.com) is a sync engine for building local-first apps with instantly-responsive UI/UX and simplified state transfer. Syncs between SQLite on the client-side and Postgres, MongoDB or MySQL on the server-side.*
_[PowerSync](https://www.powersync.com) is a sync engine for building local-first apps with instantly-responsive UI/UX and simplified state transfer. Syncs between SQLite on the client-side and Postgres, MongoDB or MySQL on the server-side._

# PowerSync JavaScript SDKs

Expand Down Expand Up @@ -100,6 +100,15 @@ Build packages
pnpm build:packages
```

## Tests

Some packages use [Playwright](https://www.npmjs.com/package/playwright) for testing. Install Playwright dependencies with:

```bash
pnpm exec playwright install-deps
pnpm exec playwright install
```

## Versioning

### Development Packages
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { AppSchema } from '@/library/powersync/AppSchema';
import { SupabaseConnector } from '@/library/powersync/SupabaseConnector';
import { CircularProgress } from '@mui/material';
import { PowerSyncContext } from '@powersync/react';
import { PowerSyncDatabase } from '@powersync/web';
import { PowerSyncDatabase, WASQLiteOpenFactory, WASQLiteVFS } from '@powersync/web';
import Logger from 'js-logger';
import React, { Suspense } from 'react';
import { NavigationPanelContextProvider } from '../navigation/NavigationPanelContext';
Expand All @@ -13,9 +13,10 @@ export const useSupabase = () => React.useContext(SupabaseContext);

export const db = new PowerSyncDatabase({
schema: AppSchema,
database: {
dbFilename: 'example.db'
}
database: new WASQLiteOpenFactory({
dbFilename: 'one.sqlite',
vfs: WASQLiteVFS.OPFSCoopSyncVFS
})
});

export const SystemProvider = ({ children }: { children: React.ReactNode }) => {
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@
"@actions/core": "^1.10.1",
"@changesets/cli": "2.27.2",
"@pnpm/workspace.find-packages": "^4.0.2",
"@vitest/browser": "^3.0.5",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"prettier": "^3.2.5"
"playwright": "^1.50.1",
"prettier": "^3.2.5",
"typescript": "^5.7.2",
"vitest": "^3.0.5"
}
}
11 changes: 3 additions & 8 deletions packages/attachments/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,9 @@
"@powersync/common": "workspace:^1.18.1"
},
"devDependencies": {
"@powersync/common": "workspace:*",
"@types/node": "^20.17.6",
"@vitest/browser": "^2.1.8",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"typescript": "^5.7.2",
"vite": "^5.4.11",
"vite-plugin-top-level-await": "^1.4.4",
"vitest": "^2.1.8",
"webdriverio": "^9.4.5"
"vite": "^6.1.0",
"vite-plugin-top-level-await": "^1.4.4"
}
}
8 changes: 6 additions & 2 deletions packages/attachments/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ const config: UserConfigExport = {
browser: {
enabled: true,
headless: true,
provider: 'webdriverio',
name: 'chrome' // browser name is required
provider: 'playwright',
instances: [
{
browser: 'chromium'
}
]
}
}
};
Expand Down
2 changes: 0 additions & 2 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@
"rsocket-core": "1.0.0-alpha.3",
"rsocket-websocket-client": "1.0.0-alpha.3",
"text-encoding": "^0.7.0",
"typescript": "^5.5.3",
"vitest": "^2.0.5",
"web-streams-polyfill": "3.2.1"
}
}
7 changes: 4 additions & 3 deletions packages/common/src/client/sync/stream/AbstractRemote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@ import { type fetch } from 'cross-fetch';
import Logger, { ILogger } from 'js-logger';
import { RSocket, RSocketConnector, Requestable } from 'rsocket-core';
import { WebsocketClientTransport } from 'rsocket-websocket-client';
import PACKAGE from '../../../../package.json' with { type: 'json' };
import { AbortOperation } from '../../../utils/AbortOperation.js';
import { DataStream } from '../../../utils/DataStream.js';
import { PowerSyncCredentials } from '../../connection/PowerSyncCredentials.js';
import { StreamingSyncLine, StreamingSyncRequest } from './streaming-sync-types.js';

import { version as POWERSYNC_JS_VERSION } from '../../../../package.json';

export type BSONImplementation = typeof BSON;

const POWERSYNC_TRAILING_SLASH_MATCH = /\/+$/;
export type RemoteConnector = {
fetchCredentials: () => Promise<PowerSyncCredentials | null>;
};

const POWERSYNC_TRAILING_SLASH_MATCH = /\/+$/;
const POWERSYNC_JS_VERSION = PACKAGE.version;

// Refresh at least 30 sec before it expires
const REFRESH_CREDENTIALS_SAFETY_PERIOD_MS = 30_000;
const SYNC_QUEUE_REQUEST_N = 10;
Expand Down
4 changes: 2 additions & 2 deletions packages/common/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"outDir": "./lib",
"lib": ["esnext"],
"declaration": true,
"module": "node16",
"moduleResolution": "node16",
"module": "NodeNext",
"moduleResolution": "nodenext",
"preserveConstEnums": true,
"esModuleInterop": false,
"skipLibCheck": false,
Expand Down
10 changes: 2 additions & 8 deletions packages/drizzle-driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,9 @@
"@powersync/web": "workspace:*",
"@journeyapps/wa-sqlite": "^1.2.0",
"@types/node": "^20.17.6",
"@vitest/browser": "^2.1.4",
"drizzle-orm": "^0.35.2",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"typescript": "^5.6.3",
"vite": "^5.4.10",
"vite": "^6.1.0",
"vite-plugin-top-level-await": "^1.4.4",
"vite-plugin-wasm": "^3.3.0",
"vitest": "^2.1.4",
"webdriverio": "^9.2.8"
"vite-plugin-wasm": "^3.3.0"
}
}
10 changes: 7 additions & 3 deletions packages/drizzle-driver/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import wasm from 'vite-plugin-wasm';
import topLevelAwait from 'vite-plugin-top-level-await';
import wasm from 'vite-plugin-wasm';
import { defineConfig, UserConfigExport } from 'vitest/config';

const config: UserConfigExport = {
Expand All @@ -20,8 +20,12 @@ const config: UserConfigExport = {
browser: {
enabled: true,
headless: true,
provider: 'webdriverio',
name: 'chrome' // browser name is required
provider: 'playwright',
instances: [
{
browser: 'chromium'
}
]
}
}
};
Expand Down
10 changes: 2 additions & 8 deletions packages/kysely-driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,8 @@
"@powersync/web": "workspace:*",
"@journeyapps/wa-sqlite": "^1.2.0",
"@types/node": "^20.17.6",
"@vitest/browser": "^2.1.4",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"typescript": "^5.6.3",
"vite": "^5.4.10",
"vite": "^6.1.0",
"vite-plugin-top-level-await": "^1.4.4",
"vite-plugin-wasm": "^3.3.0",
"vitest": "^2.1.4",
"webdriverio": "^9.2.8"
"vite-plugin-wasm": "^3.3.0"
}
}
10 changes: 7 additions & 3 deletions packages/kysely-driver/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import wasm from 'vite-plugin-wasm';
import topLevelAwait from 'vite-plugin-top-level-await';
import wasm from 'vite-plugin-wasm';
import { defineConfig, UserConfigExport } from 'vitest/config';

const config: UserConfigExport = {
Expand All @@ -20,8 +20,12 @@ const config: UserConfigExport = {
browser: {
enabled: true,
headless: true,
provider: 'webdriverio',
name: 'chrome' // browser name is required
provider: 'playwright',
instances: [
{
browser: 'chromium'
}
]
}
}
};
Expand Down
3 changes: 1 addition & 2 deletions packages/powersync-op-sqlite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@
"react": "18.3.1",
"react-native": "0.75.3",
"react-native-builder-bob": "^0.30.2",
"turbo": "^1.10.7",
"typescript": "^5.2.2"
"turbo": "^1.10.7"
},
"eslintIgnore": [
"node_modules/",
Expand Down
1 change: 0 additions & 1 deletion packages/react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
"react-native-fetch-api": "^3.0.0",
"rollup": "4.14.3",
"text-encoding": "^0.7.0",
"typescript": "^5.5.3",
"web-streams-polyfill": "3.2.1"
},
"keywords": [
Expand Down
4 changes: 2 additions & 2 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
"react": "*"
},
"devDependencies": {
"@powersync/common": "workspace:*",
"@testing-library/react": "^15.0.2",
"@types/react": "^18.2.34",
"jsdom": "^24.0.0",
"react": "18.2.0",
"react-error-boundary": "^4.1.0",
"typescript": "^5.5.3"
"react-error-boundary": "^4.1.0"
}
}
4 changes: 2 additions & 2 deletions packages/react/tests/useQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('useQuery', () => {

await waitFor(
async () => {
expect(result.current.error).toEqual(Error('PowerSync failed to fetch data: some error'));
expect(result.current.error?.message).equal('PowerSync failed to fetch data: some error');
},
{ timeout: 100 }
);
Expand All @@ -131,7 +131,7 @@ describe('useQuery', () => {

await waitFor(
async () => {
expect(result.current.error).toEqual(Error('PowerSync failed to fetch data: some error'));
expect(result.current.error?.message).equals('PowerSync failed to fetch data: some error');
},
{ timeout: 100 }
);
Expand Down
3 changes: 1 addition & 2 deletions packages/tanstack-react-query/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
"@testing-library/react": "^15.0.2",
"@types/react": "^18.2.34",
"jsdom": "^24.0.0",
"react": "18.2.0",
"typescript": "^5.5.3"
"react": "18.2.0"
}
}
3 changes: 1 addition & 2 deletions packages/vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@
"@powersync/common": "workspace:^1.21.0"
},
"devDependencies": {
"@powersync/common": "workspace:*",
"flush-promises": "^1.0.2",
"jsdom": "^24.0.0",
"typescript": "^5.5.3",
"vitest": "^1.5.1",
"vue": "3.4.21"
}
}
10 changes: 5 additions & 5 deletions packages/vue/tests/useQuery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('useQuery', () => {

const [{ data, isLoading, isFetching, error }] = withSetup(() => useQuery('SELECT * from lists'));

expect(error.value).toEqual(Error('PowerSync not configured.'));
expect(error.value?.message).toEqual('PowerSync not configured.');
expect(isFetching.value).toEqual(false);
expect(isLoading.value).toEqual(false);
expect(data.value).toEqual([]);
Expand Down Expand Up @@ -110,7 +110,7 @@ describe('useQuery', () => {
const [{ error }] = withSetup(() => useQuery('SELECT * from lists', [], { runQueryOnce: true }));
await flushPromises();

expect(error.value).toEqual(Error('PowerSync failed to fetch data: some error'));
expect(error.value?.message).toEqual('PowerSync failed to fetch data: some error');
});

it('should set error when error occurs', async () => {
Expand All @@ -125,7 +125,7 @@ describe('useQuery', () => {
const [{ error }] = withSetup(() => useQuery('SELECT * from lists', []));
await flushPromises();

expect(error.value).toEqual(Error('PowerSync failed to fetch data: some error'));
expect(error.value?.message).toEqual('PowerSync failed to fetch data: some error');
});

it('should accept compilable queries', async () => {
Expand Down Expand Up @@ -163,8 +163,8 @@ describe('useQuery', () => {
useQuery({ execute: () => [] as any, compile: () => ({ sql: 'SELECT * from lists', parameters: [] }) }, ['x'])
);

expect(error.value).toEqual(
Error('PowerSync failed to fetch data: You cannot pass parameters to a compiled query.')
expect(error.value?.message).toEqual(
'PowerSync failed to fetch data: You cannot pass parameters to a compiled query.'
);
});
});
8 changes: 2 additions & 6 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,16 @@
"devDependencies": {
"@journeyapps/wa-sqlite": "^1.2.0",
"@types/uuid": "^9.0.6",
"@vitest/browser": "^2.1.4",
"crypto-browserify": "^3.12.0",
"p-defer": "^4.0.1",
"source-map-loader": "^5.0.0",
"stream-browserify": "^3.0.0",
"terser-webpack-plugin": "^5.3.9",
"typescript": "^5.5.3",
"uuid": "^9.0.1",
"vite": "^5.4.10",
"vite-plugin-top-level-await": "^1.4.1",
"vite": "^6.1.0",
"vite-plugin-top-level-await": "^1.4.4",
"vite-plugin-wasm": "^3.3.0",
"vitest": "^2.1.4",
"vm-browserify": "^1.1.2",
"webdriverio": "^8.40.6",
"webpack": "^5.90.1",
"webpack-cli": "^5.1.4",
"webpack-node-externals": "^3.0.0"
Expand Down
Loading
Loading