Skip to content

Commit 7701fe2

Browse files
committed
Merge branch 'main' into feat/execute-raw
2 parents 20a758e + 2272ad8 commit 7701fe2

File tree

230 files changed

+11179
-11972
lines changed

Some content is hidden

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

230 files changed

+11179
-11972
lines changed

.github/workflows/deploy-docs.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
run: pnpm build:packages
5555
- name: Build Docs
5656
run: pnpm docs:build
57-
- uses: actions/upload-pages-artifact@v2
57+
- uses: actions/upload-pages-artifact@v3
5858
with:
5959
path: ./docs/build
6060
deploy:
@@ -66,4 +66,4 @@ jobs:
6666
steps:
6767
- name: Deploy to GitHub Pages
6868
id: deployment
69-
uses: actions/deploy-pages@v2
69+
uses: actions/deploy-pages@v4

.github/workflows/test.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
jobs:
88
test:
99
name: Test Packages
10-
runs-on: ubuntu-latest
10+
runs-on: ubuntu-xl
1111
steps:
1212
- uses: actions/checkout@v4
1313
with:
@@ -40,6 +40,11 @@ jobs:
4040
- name: Install dependencies
4141
run: pnpm install
4242

43+
- name: Configure Playwright
44+
run: |
45+
pnpm exec playwright install-deps
46+
pnpm exec playwright install
47+
4348
- name: Build
4449
run: pnpm build:packages
4550

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<a href="https://www.powersync.com" target="_blank"><img src="https://github.com/powersync-ja/.github/assets/7372448/d2538c43-c1a0-4c47-9a76-41462dba484f"/></a>
33
</p>
44

5-
*[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.*
5+
_[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._
66

77
# PowerSync JavaScript SDKs
88

@@ -18,6 +18,10 @@
1818

1919
- JS Web SDK implementation (extension of `packages/common`)
2020

21+
- [packages/node](./packages/node/README.md)
22+
23+
- Node.js client implementation (extension of `packages/common`)
24+
2125
- [packages/react](./packages/react/README.md)
2226

2327
- React integration for PowerSync.
@@ -80,6 +84,10 @@ Demo applications are located in the [`demos/`](./demos/) directory. Also see ou
8084

8185
- [demos/example-capacitor](./demos/example-capacitor/README.md) A Capacitor example app using the PowerSync Web SDK.
8286

87+
### Node
88+
89+
- [demos/example-node](./demos/example-node/README.md) A small CLI example built using the PowerSync SDK for Node.js.
90+
8391
## Tools
8492

8593
- [tools/diagnostics-app](./tools/diagnostics-app): A standalone web app that presents stats about a user's local database (incl. tables and sync buckets).
@@ -100,6 +108,15 @@ Build packages
100108
pnpm build:packages
101109
```
102110

111+
## Tests
112+
113+
Some packages use [Playwright](https://www.npmjs.com/package/playwright) for testing. Install Playwright dependencies with:
114+
115+
```bash
116+
pnpm exec playwright install-deps
117+
pnpm exec playwright install
118+
```
119+
103120
## Versioning
104121

105122
### Development Packages

demos/angular-supabase-todolist/src/app/supabase.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
type User
99
} from '@supabase/supabase-js';
1010
import { environment } from '../environment';
11-
import { type AbstractPowerSyncDatabase, type CrudEntry, UpdateType, PowerSyncBackendConnector } from '@powersync/web';
11+
import { type AbstractPowerSyncDatabase, type CrudEntry, UpdateType, PowerSyncBackendConnector, type PowerSyncCredentials } from '@powersync/web';
1212

1313
/// Postgres Response codes that we cannot recover from by retrying.
1414
const FATAL_RESPONSE_CODES = [
@@ -67,7 +67,7 @@ export class SupabaseService implements PowerSyncBackendConnector {
6767
return {
6868
endpoint: environment.powersyncUrl,
6969
token: session.access_token ?? ''
70-
};
70+
} satisfies PowerSyncCredentials;
7171
}
7272

7373
authChanges(callback: (event: AuthChangeEvent, session: Session | null) => void) {

demos/django-react-native-todolist/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"dependencies": {
1111
"@azure/core-asynciterator-polyfill": "^1.0.2",
1212
"@expo/vector-icons": "^14.0.0",
13-
"@journeyapps/react-native-quick-sqlite": "^2.3.0",
13+
"@journeyapps/react-native-quick-sqlite": "^2.4.2",
1414
"@powersync/common": "workspace:*",
1515
"@powersync/react": "workspace:*",
1616
"@powersync/react-native": "workspace:*",

demos/example-node/.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
BACKEND=http://localhost:6060
2+
SYNC_SERVICE=http://localhost:8080

demos/example-node/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
## Node.js Demo
2+
3+
This demonstrates a small Node.js client opening a database and connecting PowerSync.
4+
5+
This demo is configured to talk to an example backend [you can host yourself](https://github.com/powersync-ja/self-host-demo). To get started:
6+
7+
1. Start one of the Node.js backend examples from [the self-host-demo repository](https://github.com/powersync-ja/self-host-demo).
8+
2. If necessary, change `.env` to point to the started backend and sync service.
9+
3. Run `pnpm install` and `pnpm build:packages` in the root of this repo.
10+
4. In this directory, run `pnpm run start`.
11+
12+
This opens the local database, connects to PowerSync, waits for a first sync and then runs a simple query.
13+
Results from the query are printed every time it changes. Try:
14+
15+
1. Updating a row in the backend database and see changes reflected in the running client.
16+
2. Enter `add('my list')` and see the new list show up in the backend database.

demos/example-node/package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "example-node",
3+
"version": "1.0.0",
4+
"description": "",
5+
"type": "module",
6+
"private": true,
7+
"scripts": {
8+
"build": "tsc -b",
9+
"watch": "tsc -b -w",
10+
"start": "node --loader ts-node/esm -r dotenv/config src/main.ts"
11+
},
12+
"dependencies": {
13+
"@powersync/node": "workspace:*",
14+
"dotenv": "^16.4.7"
15+
},
16+
"devDependencies": {
17+
"ts-node": "^10.9.2",
18+
"typescript": "^5.8.2"
19+
}
20+
}

demos/example-node/src/main.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import repl_factory from 'node:repl';
2+
import { once } from 'node:events';
3+
4+
import { PowerSyncDatabase, SyncStreamConnectionMethod } from '@powersync/node';
5+
import Logger from 'js-logger';
6+
import { AppSchema, DemoConnector } from './powersync.js';
7+
import { exit } from 'node:process';
8+
9+
const main = async () => {
10+
Logger.useDefaults({ defaultLevel: Logger.WARN });
11+
12+
if (!('BACKEND' in process.env) || !('SYNC_SERVICE' in process.env)) {
13+
console.warn(
14+
'Set the BACKEND and SYNC_SERVICE environment variables to point to a sync service and a running demo backend.'
15+
);
16+
return;
17+
}
18+
19+
const db = new PowerSyncDatabase({
20+
schema: AppSchema,
21+
database: {
22+
dbFilename: 'test.db'
23+
},
24+
logger: Logger
25+
});
26+
console.log(await db.get('SELECT powersync_rs_version();'));
27+
28+
await db.connect(new DemoConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP });
29+
await db.waitForFirstSync();
30+
console.log('First sync complete!');
31+
32+
let hasFirstRow: ((value: any) => void) | null = null;
33+
const firstRow = new Promise((resolve) => (hasFirstRow = resolve));
34+
const watchLists = async () => {
35+
for await (const rows of db.watch('SELECT * FROM lists')) {
36+
if (hasFirstRow) {
37+
hasFirstRow(null);
38+
hasFirstRow = null;
39+
}
40+
console.log('Has todo lists', rows.rows?._array);
41+
}
42+
};
43+
44+
watchLists();
45+
await firstRow;
46+
47+
console.log('Connected to PowerSync. Try updating the lists in the database and see it reflected here.');
48+
console.log("To upload a list here, enter `await add('name of new list');`");
49+
50+
const repl = repl_factory.start();
51+
repl.context.add = async (name: string) => {
52+
await db.execute(
53+
"INSERT INTO lists (id, created_at, name, owner_id) VALUEs (uuid(), datetime('now'), ?, uuid());",
54+
[name]
55+
);
56+
};
57+
58+
await once(repl, 'exit');
59+
console.log('shutting down');
60+
await db.disconnect();
61+
await db.close();
62+
exit(0);
63+
};
64+
65+
await main();
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { AbstractPowerSyncDatabase, column, PowerSyncBackendConnector, Schema, Table } from '@powersync/node';
2+
3+
export class DemoConnector implements PowerSyncBackendConnector {
4+
async fetchCredentials() {
5+
const response = await fetch(`${process.env.BACKEND}/api/auth/token`);
6+
if (response.status != 200) {
7+
throw 'Could not fetch token';
8+
}
9+
10+
const { token } = await response.json();
11+
12+
return {
13+
endpoint: process.env.SYNC_SERVICE!,
14+
token: token
15+
};
16+
}
17+
18+
async uploadData(database: AbstractPowerSyncDatabase) {
19+
const batch = await database.getCrudBatch();
20+
if (batch == null) {
21+
return;
22+
}
23+
24+
const entries: any[] = [];
25+
for (const op of batch.crud) {
26+
entries.push({
27+
table: op.table,
28+
op: op.op,
29+
id: op.id,
30+
data: op.opData
31+
});
32+
}
33+
34+
const response = await fetch(`${process.env.BACKEND}/api/data/`, {
35+
method: 'POST',
36+
headers: {'Content-Type': 'application/json'},
37+
body: JSON.stringify({batch: entries}),
38+
});
39+
if (response.status !== 200) {
40+
throw new Error(`Server returned HTTP ${response.status}: ${await response.text()}`);
41+
}
42+
43+
await batch?.complete();
44+
}
45+
}
46+
47+
export const LIST_TABLE = 'lists';
48+
export const TODO_TABLE = 'todos';
49+
50+
const todos = new Table(
51+
{
52+
list_id: column.text,
53+
created_at: column.text,
54+
completed_at: column.text,
55+
description: column.text,
56+
created_by: column.text,
57+
completed_by: column.text,
58+
completed: column.integer,
59+
photo_id: column.text
60+
},
61+
{ indexes: { list: ['list_id'] } }
62+
);
63+
64+
const lists = new Table({
65+
created_at: column.text,
66+
name: column.text,
67+
owner_id: column.text
68+
});
69+
70+
export const AppSchema = new Schema({
71+
lists,
72+
todos
73+
});
74+
75+
export type Database = (typeof AppSchema)['types'];
76+
export type TodoRecord = Database['todos'];
77+
export type ListRecord = Database['lists'];

0 commit comments

Comments
 (0)