Skip to content
This repository has been archived by the owner on Feb 9, 2024. It is now read-only.

Commit

Permalink
Refactor to follow API conventions from other YJS providers.
Browse files Browse the repository at this point in the history
  • Loading branch information
rkistner committed Jan 16, 2024
1 parent 127777d commit 8645f4b
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 72 deletions.
9 changes: 5 additions & 4 deletions demos/powersync-supabase-yjs-text-collab-demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@
"@tiptap/extension-task-list": "2.1.13",
"@tiptap/react": "2.1.13",
"@tiptap/starter-kit": "2.1.13",
"lato-font": "^3.0.0",
"d3": "^7.3.0",
"fast-glob": "^3.2.11",
"formik": "^2.4.5",
"highlight.js": "^11.6.0",
"js-logger": "^1.6.1",
"lato-font": "^3.0.0",
"lexical": "^0.11.1",
"lib0": "^0.2.88",
"lodash": "^4.17.21",
"lowlight": "^2.7.0",
"next": "14.0.0",
Expand All @@ -56,13 +57,13 @@
"@types/uuid": "9.0.7",
"autoprefixer": "^10.0.0",
"babel-loader": "^9.1.3",
"css-loader": "^6.9.0",
"eslint": "^8",
"eslint-config-next": "14.0.0",
"postcss": "^8.0.0",
"style-loader": "^3.3.4",
"css-loader": "^6.9.0",
"sass-loader": "^13.3.3",
"sass": "^1.49.7",
"sass-loader": "^13.3.3",
"style-loader": "^3.3.4",
"supabase": "1.127.4",
"tailwindcss": "^3.3.5"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from 'react';

import MenuBar from '@/components/widgets/MenuBar';
import { setupPowerSyncDoc } from '@/library/powersync/powersyncYjs';
import { PowerSyncYjsProvider } from '@/library/powersync/PowerSyncYjsProvider';
import Collaboration from '@tiptap/extension-collaboration';
import Highlight from '@tiptap/extension-highlight';
import TaskItem from '@tiptap/extension-task-item';
Expand All @@ -39,7 +39,10 @@ export default function EditorPage({ params }: { params: { document_id: string }
}, [params.document_id]);

useEffect(() => {
return setupPowerSyncDoc(ydoc, powerSync, documentId);
const provider = new PowerSyncYjsProvider(ydoc, powerSync, documentId);
return () => {
provider.destroy();
}
}, [ydoc, powerSync]);

// watch for total number of document updates changing to update the counter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@ import { CircularProgress } from '@mui/material';
const SupabaseContext = React.createContext<SupabaseConnector | null>(null);
export const useSupabase = () => React.useContext(SupabaseContext);

const powersync = new WASQLitePowerSyncDatabaseOpenFactory({
dbFilename: 'powersync2.db',
schema: AppSchema,
flags: {
disableSSRWarning: true
}
}).getInstance();

export const SystemProvider = ({ children }: { children: React.ReactNode }) => {
const [connector] = React.useState(new SupabaseConnector());
const [powerSync] = React.useState(powersync);
const [powerSync] = React.useState(new WASQLitePowerSyncDatabaseOpenFactory({
dbFilename: 'powersync2.db',
schema: AppSchema,
flags: {
disableSSRWarning: true
}
}).getInstance());

const router = useRouter();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@

import * as Y from 'yjs';

import { b64ToUint8Array, Uint8ArrayTob64 } from '@/library/binary-utils';
import { v4 as uuidv4 } from 'uuid';
import { AbstractPowerSyncDatabase } from '@journeyapps/powersync-sdk-web';
import { ObservableV2 } from 'lib0/observable'

export interface PowerSyncYjsEvents {
/**
* Triggered when document contents have been loaded from the database the first time.
*
* The document data may not have been synced from the PowerSync service at this point.
*/
synced: () => void;
}

/**
* Configure bidirectional sync for a Yjs document with a PowerSync database.
*
* Updates are stored in the `document_updates` table in the database.
*
* @param ydoc
* @param db
* @param documentId
*/
export class PowerSyncYjsProvider extends ObservableV2<PowerSyncYjsEvents> {
private seenDocUpdates = new Set<string>();
private abortController = new AbortController();

constructor(public readonly doc: Y.Doc, public readonly db: AbstractPowerSyncDatabase, public readonly documentId: string) {
super();

const updates = db.watch('SELECT * FROM document_updates WHERE document_id = ?', [documentId], { signal: this.abortController.signal });

this._storeUpdate = this._storeUpdate.bind(this);
this.destroy = this.destroy.bind(this);

let synced = false;

const watchLoop = async () => {
for await (let results of updates) {
if (this.abortController.signal.aborted) {
break;
}

// New data detected in the database
for (let update of results.rows!._array) {
// Ignore any updates we've already seen
if (!this.seenDocUpdates.has(update.id)) {
this.seenDocUpdates.add(update.id);
// apply the update from the database to the doc
const origin = this;
Y.applyUpdateV2(doc, b64ToUint8Array(update.update_b64), origin);
}
}

if (!synced) {
synced = true;
this.emit('synced', []);
}
}
}
watchLoop();

doc.on('updateV2', this._storeUpdate);
doc.on('destroy', this.destroy)
}

private async _storeUpdate(update: Uint8Array, origin: any) {
if (origin === this) {
// update originated from the database / PowerSync - ignore
return;
}
// update originated from elsewhere - save to the database
const docUpdateId = uuidv4();
this.seenDocUpdates.add(docUpdateId);
await this.db.execute('INSERT INTO document_updates(id, document_id, update_b64) VALUES(?, ?, ?)', [docUpdateId, this.documentId, Uint8ArrayTob64(update)]);
}

/**
* Destroy this persistence provider, removing any attached event listeners.
*/
destroy() {
this.abortController.abort();
this.doc.off('updateV2', this._storeUpdate)
this.doc.off('destroy', this.destroy)
}

/**
* Delete data associated with this document from the database.
*
* Also call `destroy()` to remove any event listeners and prevent future updates to the database.
*/
async deleteData() {
await this.db.execute('DELETE FROM document_updates WHERE document_id = ?', [this.documentId]);
}
}

This file was deleted.

5 changes: 4 additions & 1 deletion demos/powersync-supabase-yjs-text-collab-demo/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules", "supabase/functions/**/*.ts"]
"exclude": ["node_modules", "supabase/functions/**/*.ts"],
"references": [
{"path": "../../packages/powersync-sdk-web"}
]
}
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8645f4b

Please sign in to comment.