Skip to content

Commit

Permalink
chore: rename demos (#53)
Browse files Browse the repository at this point in the history
Co-authored-by: DominicGBauer <[email protected]>
  • Loading branch information
DominicGBauer and DominicGBauer authored Feb 9, 2024
1 parent d1dec6d commit 6d92258
Show file tree
Hide file tree
Showing 185 changed files with 200 additions and 211 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# PowerSync + Supabase NextJS Demo: Todo List
# PowerSync + Supabase NextJS Demo: Todo List

## Note: Beta Release

Expand All @@ -14,11 +14,10 @@ This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next

## Getting Started


In your terminal, switch into the demo's directory:

```bash
cd demos/powersync-nextjs-demo
cd demos/nextjs-supabase-todolist
```

Set up the Environment variables: Copy the `.env.local.template` file:
Expand All @@ -38,6 +37,7 @@ pnpm watch
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

## Progressive Web App (PWA)

This demo is PWA compatible. PWA is not available in development (watch) mode.

Build the production codebase
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ const App: React.FC = () => {
{output ? (
<Table borderStyle={{ borderWidth: 2 }}>
<Row style={{ backgroundColor: '#999' }} data={cellKeys} />
{rows.map((row) => (
<Row data={cellKeys.map((key) => row[key])} />
{rows.map((row, index) => (
<Row key={index.toString()} data={cellKeys.map((key) => row[key])} />
))}
</Table>
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ PODS:
- hermes-engine/Pre-built (= 0.73.2)
- hermes-engine/Pre-built (0.73.2)
- libevent (2.1.12)
- powersync-sqlite-core (0.1.5)
- powersync-sqlite-core (0.1.6)
- RCT-Folly (2022.05.16.00):
- boost
- DoubleConversion
Expand Down Expand Up @@ -921,8 +921,8 @@ PODS:
- React-Core
- react-native-get-random-values (1.10.0):
- React-Core
- react-native-quick-sqlite (1.1.0):
- powersync-sqlite-core
- react-native-quick-sqlite (1.1.1):
- powersync-sqlite-core (~> 0.1.6)
- React
- React-callinvoker
- React-Core
Expand Down Expand Up @@ -1353,12 +1353,12 @@ SPEC CHECKSUMS:
ExpoSecureStore: c84ae37d1c36f38524d289c67c3a2e3fc56f1108
EXSplashScreen: 39244885abfb1b12765aae89edb90f8c88db6bbd
FBLazyVector: fbc4957d9aa695250b55d879c1d86f79d7e69ab4
FBReactNativeSpec: 2885eb3fb2add650f837bd8d1bdba9979a5486f9
FBReactNativeSpec: 330cf4c6cf09f4085799e5e5fa0e1adc22972cf2
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
hermes-engine: b361c9ef5ef3cda53f66e195599b47e1f84ffa35
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
powersync-sqlite-core: 529f99619a81736331dbcbca5db881d1a3391c05
powersync-sqlite-core: 4c38c8f470f6dca61346789fd5436a6826d1e3dd
RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0
RCTRequired: 9b1e7e262745fb671e33c51c1078d093bd30e322
RCTTypeSafety: a759e3b086eccf3e2cbf2493d22f28e082f958e6
Expand All @@ -1382,7 +1382,7 @@ SPEC CHECKSUMS:
React-Mapbuffer: 9ee041e1d7be96da6d76a251f92e72b711c651d6
react-native-encrypted-storage: db300a3f2f0aba1e818417c1c0a6be549038deb7
react-native-get-random-values: 384787fd76976f5aec9465aff6fa9e9129af1e74
react-native-quick-sqlite: be20413dfef15ca106e6370afe822d34c32e9def
react-native-quick-sqlite: b99b264d738643c12545519cffa449513a3a7c28
react-native-safe-area-context: 0ee144a6170530ccc37a0fd9388e28d06f516a89
React-nativeconfig: d753fbbc8cecc8ae413d615599ac378bbf6999bb
React-NativeModulesApple: 964f4eeab1b4325e8b6a799cf4444c3fd4eb0a9c
Expand All @@ -1399,7 +1399,7 @@ SPEC CHECKSUMS:
React-RCTText: 73006e95ca359595c2510c1c0114027c85a6ddd3
React-RCTVibration: 599f427f9cbdd9c4bf38959ca020e8fef0717211
React-rendererdebug: f2946e0a1c3b906e71555a7c4a39aa6a6c0e639b
React-rncore: 97eaa568b6461a568a54104ad48b9bfab8590a0a
React-rncore: cf40dd2b824f5443532aa504dfb812319da9ff0a
React-runtimeexecutor: 2d1f64f58193f00a3ad71d3f89c2bfbfe11cf5a5
React-runtimescheduler: df8945a656356ff10f58f65a70820478bfcf33ad
React-utils: f5bc61e7ea3325c0732ae2d755f4441940163b85
Expand Down
File renamed without changes
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# PowerSync Yjs Document Collaboration Demo

This is a simple CRDT text collaboration demo powered by [Yjs](https://github.com/yjs/yjs) and [Tiptap](https://tiptap.dev/) which uses [PowerSync](https://www.powersync.com/) as both the persistence and connection provider. This means that the Yjs CRDT data structures are stored in Postgres. Conflicts are automatically resolved using CRDTs.
This is a simple CRDT text collaboration demo powered by [Yjs](https://github.com/yjs/yjs) and [Tiptap](https://tiptap.dev/) which uses [PowerSync](https://www.powersync.com/) as both the persistence and connection provider. This means that the Yjs CRDT data structures are stored in Postgres. Conflicts are automatically resolved using CRDTs.

https://github.com/powersync-ja/powersync-web-sdk/assets/93317/fc0c2b2f-feb7-441b-895a-94893db46563
<https://github.com/powersync-ja/powersync-web-sdk/assets/93317/fc0c2b2f-feb7-441b-895a-94893db46563>

This demo is built using [Next.js](https://nextjs.org/) and the [PowerSync JS web SDK](https://docs.powersync.com/client-sdk-references/js-web).


## Setup Instructions

### 1. Install dependencies
Expand All @@ -18,22 +17,20 @@ pnpm install
pnpm build:packages
```


### 2. Create project on Supabase and set up Postgres

This demo app uses Supabase as its Postgres database and backend:

1. [Create a new project on the Supabase dashboard](https://supabase.com/dashboard/projects).
2. Go to the Supabase SQL Editor for your new project and execute the SQL statements in [`database.sql`](database.sql) to create the database schema, database functions, and publication needed for PowerSync.


### 3. Auth setup and Supabase edge functions

For ease of demoing, this demo app uses anonymous authentication. The below instructions are derived from the [powersync-jwks-example README](https://github.com/powersync-ja/powersync-jwks-example):

1. Install [Deno](https://deno.com/) and [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) if you don't have them already.
2. Clone the [powersync-jwks-example](https://github.com/powersync-ja/powersync-jwks-example) repo.
3. In the [powersync-jwks-example](https://github.com/powersync-ja/powersync-jwks-example) repo directory, run the script to generate a keypair:
3. In the [powersync-jwks-example](https://github.com/powersync-ja/powersync-jwks-example) repo directory, run the script to generate a keypair:

```bash
deno run generate-keys.ts
Expand All @@ -42,45 +39,41 @@ deno run generate-keys.ts
4. Then use `supabase secrets set` as shown in the terminal output to update the generated keys on Supabase (`POWERSYNC_PUBLIC_KEY` and `POWERSYNC_PRIVATE_KEY`). You will need the project ref of the Supabase project you created previously.
5. Switch back to the `powersync-supabase-yjs-text-collab-demo` repo directory and deploy the `powersync-jwks` and `powersync-auth-anonymous` edge functions to Supabase: (Note that the Supabase CLI requires [Docker Desktop](https://docs.docker.com/desktop/) to be installed for this step)


```bash
supabase functions deploy --no-verify-jwt powersync-jwks
supabase functions deploy powersync-auth-anonymous
```


### 4. Create new project on PowerSync and connect to Supabase/Postgres

If you don't have a PowerSync account yet, [sign up here](https://accounts.journeyapps.com/portal/free-trial?powersync=true).

Then, in the [PowerSync dashboard](https://powersync.journeyapps.com/), create a new PowerSync instance:

1. Right-click on 'PowerSync Project' in the project tree on the left and click "Create new instance"
2. Pick a name for the instance e.g. "Yjs Demo Test" and proceed.
3. In the "Edit Instance" dialog that follows, click on the "Connections" tab.
4. Click on the "+" button to create a new database connection.
5. Input the credentials from the project you created in Supabase. In the Supabase dashboard, under your project you can go to "Project Settings" and then "Database" and choose "URI" under "Connection string", untick the "Use connection pooling" option, and then copy & paste the connection string into the PowerSync dashboard "URI" field, and then enter your database password at the "Password" field.
5. Input the credentials from the project you created in Supabase. In the Supabase dashboard, under your project you can go to "Project Settings" and then "Database" and choose "URI" under "Connection string", untick the "Use connection pooling" option, and then copy & paste the connection string into the PowerSync dashboard "URI" field, and then enter your database password at the "Password" field.
6. Click the "Test connection" button and you should see "Connection success!"
7. Click on the "Credentials" tab of the "Edit Instance" dialog.
8. Tick the "Use Supabase Auth" checkbox
9. Enter the URL of your `powersync-jwks` edge function at the "JWKS URI" field. It should be in the format `https://<supabase-project-ref>.supabase.co/functions/v1/powersync-jwks`. If needed, you can find the URL in the Supabase dashboard by going to your project and then to "Edge Functions".
10. Click "Save" to save all the changes to your PowerSync instance. The instance will now be deployed — this may take a minute or two.


### 5. Set `POWERSYNC_URL` secret on Supabase

1. Now that your PowerSync instance is created, you should see a URL for it on the right side of the PowerSync dashboard in the "Deploy logs" panel. Click the button next to the URL to copy it.
2. Use the copied value to set the `POWERSYNC_URL` secret to be used by your Supabase edge functions: (make sure there is no trailing slash at the end of the URL)

`supabase secrets set POWERSYNC_URL=https://<powersync-instance-id>.powersync.journeyapps.com`


### 6. Create Sync Rules on PowerSync

1. Open the [`sync-rules.yaml`](sync-rules.yaml) in this repo and copy the contents.
2. In the [PowerSync dashboard](https://powersync.journeyapps.com/), paste that into the 'sync-rules.yaml' editor panel.
3. Click the "Deploy sync rules" button and select your PowerSync instance from the drop-down list.


### 7. Set up local environment variables

To set up the environment variables for the demo Next.js app:
Expand All @@ -96,7 +89,6 @@ cp .env.local.template .env.local
- Set `SUPABASE_ANON_KEY` to your Supabase API key. This can be found right below the Project URL on the Supabase dashboard.
- Set `POWERSYNC_URL` to your PowerSync instance URL (this is the same URL from step 5)


### 8. Run the demo app

In the repo directory, run the following to start the development server:
Expand All @@ -111,7 +103,6 @@ To try out the collaborative editing, copy and paste the URL of the page and ope

<img width="1135" alt="295090638-a55d5ee5-0da9-4ab6-a584-1741fb97de9f" src="https://github.com/powersync-ja/powersync-web-sdk/assets/93317/a10257d8-c614-4818-818a-2e722cd69d67">


### (Optional) Supabase edge function for merging document updates

The more edits are made to a document, the longer the Yjs CRDT update history becomes. There is currently a [very basic edge function](supabase/functions/merge-document-updates/index.ts) available to merge updates into a single update row.
Expand All @@ -122,20 +113,20 @@ You can deploy it using the following command:
supabase functions deploy merge-document-updates
```

And invoke it using the Supabase CLI:
And invoke it using the Supabase CLI:

```bash
curl -L -X POST 'https://<project-ref>.supabase.co/functions/v1/merge-document-updates' -H 'Authorization: Bearer [anon-key]' --data '{"document_id":"[document-id]"}'
curl -L -X POST 'https://<project-ref>.supabase.co/functions/v1/merge-document-updates' -H 'Authorization: Bearer [anon-key]' --data '{"document_id":"[document-id]"}'
```
Replace `<project-ref>` with your Supabase project ref, `[anon-key]` with your Supabase API key, and `[document-id]` with the UUID of the document (found in the URL of the specific document you're editing the demo app).

Replace `<project-ref>` with your Supabase project ref, `[anon-key]` with your Supabase API key, and `[document-id]` with the UUID of the document (found in the URL of the specific document you're editing the demo app).

Note that this is not a production-grade implementation of merging updates – the current implementation will have race conditions and is only a PoC for development/testing.


## Demo App Roadmap

To-do

- [ ] Add user sessions. For ease of demoing, still allow anonymously signing in (perhaps using [this Supabase workaround](https://github.com/supabase/gotrue/issues/68)), but keep track of session data so that each user has a unique `user_id` which we can associate with edits to the document.
- [ ] Improve sync rules: Use a many-to-many relationship between users and documents, so that all documents and their updates are not synced to all users. Dependent on user sessions.
- [ ] Add suggested RLS rules for Supabase. Dependent on user sessions.
Expand All @@ -144,11 +135,11 @@ To-do
- [ ] Add button to the UI allowing the user to merge the Yjs edits i.e. `document_update` rows. Invoke `merge-document-updates` edge function in Supabase.
- [ ] Prepopulate sample text into newly created documents.
- [ ] Improve performance / rework inefficient parts of implementation:
- [ ] Optimize the 'seen updates' approach to filter the `SELECT` query for updates that have not yet been seen — perhaps based on `created_at` timestamp generated on the Postgres side. For the watch query — watch for certain tables instead of watching a query. This will allow querying `document_updates` with a dynamic parameter.
- [ ] Flush 'seen updates' when `document_updates` are merged.
- [ ] Optimize the 'seen updates' approach to filter the `SELECT` query for updates that have not yet been seen — perhaps based on `created_at` timestamp generated on the Postgres side. For the watch query — watch for certain tables instead of watching a query. This will allow querying `document_updates` with a dynamic parameter.
- [ ] Flush 'seen updates' when `document_updates` are merged.

Done
- [x] Show number of edits (rows in `document_updates`) on the document
Done

- [x] Show number of edits (rows in `document_updates`) on the document
- [x] For ease of demoing, when the user hits the root page, either generate a new random document UUID and redirect the user to that document, or redirect to last viewed document ID if any (ID stored in local storage).
- [x] Add function to merge document updates; can be invoked if number of `document_updates` becomes too large (currently a row is created in `document_updates` for every edit/update from the Yjs document)

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# A string used to distinguish different Supabase projects on the same host. Defaults to the
# working directory name when running `supabase init`.
project_id = "powersync-supabase-yjs-text-collab-demo"
project_id = "yjs-nextjs-supabase-text-collab"

[api]
enabled = true
Expand Down
Loading

0 comments on commit 6d92258

Please sign in to comment.