diff --git a/components/Editor.js b/components/Editor.js index 1f998db..f149790 100644 --- a/components/Editor.js +++ b/components/Editor.js @@ -3,7 +3,7 @@ import styled from 'styled-components'; import CodeMirror from 'codemirror'; import * as Y from 'yjs'; import { CodemirrorBinding } from 'y-codemirror'; -import { WebrtcProvider } from 'y-webrtc'; +import { HocuspocusProvider } from "@hocuspocus/provider"; import useResizeObserver from 'use-resize-observer'; import 'codemirror/lib/codemirror.css'; import 'codemirror/theme/seti.css'; @@ -29,12 +29,9 @@ const Container = styled.div` } `; -const signalingServer = process.env.NEXT_PUBLIC_WEBRTC_SIGNLING; - const CodeEditor = ({ roomName, initialValue, - commit, onChange, onLineChange, }) => { @@ -51,8 +48,10 @@ const CodeEditor = ({ useEffect(() => { if (textarea.current && !binding) { const ydoc = new Y.Doc(); - const provider = new WebrtcProvider(roomName, ydoc, { - signaling: [signalingServer], + const provider = new HocuspocusProvider({ + url: "wss://scrolls-server.glitch.me", + name: roomName, + document: ydoc, }); const yText = ydoc.getText('codemirror'); const yUndoManager = new Y.UndoManager(yText); @@ -73,10 +72,6 @@ const CodeEditor = ({ onChange(yText.toJSON()); - ydoc.on('update', () => { - commit(Y.encodeStateAsUpdate(ydoc)); - }); - yText.observe(() => { onChange(yText.toJSON()); }); @@ -93,7 +88,7 @@ const CodeEditor = ({ onLineChange(cursor.line); }); } - }, [binding, commit, roomName, initialValue, onChange, onLineChange]); + }, [binding, roomName, initialValue, onChange, onLineChange]); return ( diff --git a/components/Publish.tsx b/components/Publish.tsx index 2f0e1b3..ad8cf70 100644 --- a/components/Publish.tsx +++ b/components/Publish.tsx @@ -1,6 +1,5 @@ import { useState } from 'react'; import AriaModal from 'react-aria-modal'; -import { publish } from 'services/firebase'; export default function Publish({ data, name }) { const [show, setShow] = useState(false); diff --git a/package.json b/package.json index 6147299..2d65d03 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,14 @@ "private": true, "dependencies": { "@fontsource/roboto-mono": "^4.2.2", + "@hocuspocus/provider": "^2.2.1", "@mapbox/hast-util-table-cell-style": "^0.1.3", "@remark-embedder/core": "^1.2.4", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "@types/codemirror": "^5.60.5", + "@vercel/kv": "^0.2.2", "codemirror": "^5.59.4", "firebase": "^7.16.0", "gray-matter": "^4.0.2", @@ -35,7 +37,7 @@ "use-resize-observer": "^6.1.0", "y-codemirror": "^2.1.0", "y-webrtc": "^10.1.8", - "yjs": "^13.5.1" + "yjs": "^13.6.6" }, "scripts": { "dev": "next dev", diff --git a/pages/[doc].tsx b/pages/[doc].tsx index f85cf77..2f4a828 100644 --- a/pages/[doc].tsx +++ b/pages/[doc].tsx @@ -1,7 +1,6 @@ import React, { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import dynamic from 'next/dynamic'; -import { getDocument, setDocument } from '../services/firebase'; import ThemeLoader from '../components/ThemeLoader'; import Presentation from '../components/Presentation'; import { useFrontmatter } from '../utils/frontmatter'; @@ -17,29 +16,18 @@ function Slides(): React.ReactElement { const doc = router.query.doc as string; const [value, setValue] = useState(null); - const [loading, setLoading] = useState(true); + const [loading, setLoading] = useState(false); const [markdown, setMarkdown] = useState(''); const [line, setLine] = useState(0); const { content, config } = useFrontmatter(markdown); - useEffect(() => { - if (doc) { - getDocument(doc) - .then(setValue) - .finally(() => setLoading(false)); - } - }, [doc]); - - const commit = (value: any) => setDocument(doc, value); - return loading === false ? ( @@ -48,7 +36,6 @@ function Slides(): React.ReactElement { raw={markdown} config={config} content={content} - toolbar={} /> ) : ( diff --git a/services/firebase.ts b/services/firebase.ts deleted file mode 100644 index 166a247..0000000 --- a/services/firebase.ts +++ /dev/null @@ -1,51 +0,0 @@ -import firebase from 'firebase/app'; -import 'firebase/firestore'; -import hash from 'object-hash'; - -if (firebase.apps.length === 0) { - firebase.initializeApp({ - apiKey: process.env.API_KEY, - authDomain: process.env.NEXT_PUBLIC_AUTH_DOMAIN, - databaseURL: process.env.NEXT_PUBLIC_DATABASE_URL, - projectId: process.env.NEXT_PUBLIC_PROJECT_ID, - storageBucket: process.env.NEXT_PUBLIC_STORAGE_BUCKET, - messagingSenderId: process.env.NEXT_PUBLIC_MESSAGING_SENDER_ID, - appId: process.env.NEXT_PUBLIC_APP_ID, - }); -} - -export const firestore = firebase.firestore(); - -interface PersistedDocument { - data: firebase.firestore.Blob; -} - -export const getDocument = async (documentPath: string): Promise => { - return firestore - .collection('documents') - .doc(documentPath) - .get() - .then((snapshot) => { - if (snapshot.exists) { - const document = snapshot.data() as PersistedDocument; - if (document.data?.toUint8Array) { - return document.data.toUint8Array(); - } - } - return null; - }); -}; - -export const setDocument = (documentPath: string, value: Uint8Array) => { - const data = firebase.firestore.Blob.fromUint8Array(value); - firestore.collection('documents').doc(documentPath).set({ data }); -}; - -export const getPublished = (documentPath: string) => - firestore.collection('published').doc(documentPath).get(); - -export const publish = async (value: string, name: string) => { - const documentPath = hash({ value, name }).slice(12); - await firestore.collection('published').doc(documentPath).set({ value, name }); - return documentPath; -}; diff --git a/yarn.lock b/yarn.lock index c335c15..3368879 100644 --- a/yarn.lock +++ b/yarn.lock @@ -482,6 +482,23 @@ resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.1.tgz#9daf5745156fd84b8e9889a2dc721f0c58e894aa" integrity sha512-CAEbWH7OIur6jEOzaai83jq3FmKmv4PmX1JYfs9IrYcGEVI/lyL1EXJGCj7eFVJ0bg5QR8LMxBlEtA+xKiLpFw== +"@hocuspocus/common@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@hocuspocus/common/-/common-2.2.1.tgz#420e40547d3a89ffa615d813f63df90259089939" + integrity sha512-WUHrouqhfCSjPtK/aPyEagOreyb4s8JbXe+NZHSuxWjyxHqn+WcLgTWJv69gFVLscM/nrgbQGueZeSBKixU2mg== + dependencies: + lib0 "^0.2.47" + +"@hocuspocus/provider@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@hocuspocus/provider/-/provider-2.2.1.tgz#580daeebed1b975cd53cc0e18ebe8d8d04c2a14e" + integrity sha512-DP/XqkTY3SIlmZumdpxiBNsUEWi7u2Z4trz2/CmXXIMR9iSzYRntdKiBEOoVyU2llsJKVDtO6ZM7+tldfaLmlg== + dependencies: + "@hocuspocus/common" "^2.2.1" + "@lifeomic/attempt" "^3.0.2" + lib0 "^0.2.47" + ws "^7.5.9" + "@jest/types@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" @@ -501,6 +518,11 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" +"@lifeomic/attempt@^3.0.2": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@lifeomic/attempt/-/attempt-3.0.3.tgz#e742a5b85eb673e2f1746b0f39cb932cbc6145bb" + integrity sha512-GlM2AbzrErd/TmLL3E8hAHmb5Q7VhDJp35vIbyPVA5Rz55LZuRr8pwL3qrwwkVNo05gMX1J44gURKb4MHQZo7w== + "@mapbox/hast-util-table-cell-style@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.1.3.tgz#5b7166ae01297d72216932b245e4b2f0b642dca6" @@ -933,6 +955,20 @@ "@typescript-eslint/types" "4.17.0" eslint-visitor-keys "^2.0.0" +"@upstash/redis@1.21.0": + version "1.21.0" + resolved "https://registry.yarnpkg.com/@upstash/redis/-/redis-1.21.0.tgz#a1096f096800032d65b5d819aa2c60af3011b9e8" + integrity sha512-c6M+cl0LOgGK/7Gp6ooMkIZ1IDAJs8zFR+REPkoSkAq38o7CWFX5FYwYEqGZ6wJpUGBuEOr/7hTmippXGgL25A== + dependencies: + isomorphic-fetch "^3.0.0" + +"@vercel/kv@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@vercel/kv/-/kv-0.2.2.tgz#4b01c2bfd0aad674598b4d89a38a9454fa945a15" + integrity sha512-mqnQOB6bkp4h5eObxfLNIlhlVqOGSH8cWOlC5pDVWTjX3zL8dETO1ZBl6M74HBmeBjbD5+J7wDJklRigY6UNKw== + dependencies: + "@upstash/redis" "1.21.0" + acorn-jsx@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" @@ -2668,11 +2704,24 @@ isomorphic-fetch@2.2.1: node-fetch "^1.0.1" whatwg-fetch ">=0.10.0" +isomorphic-fetch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" + integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== + dependencies: + node-fetch "^2.6.1" + whatwg-fetch "^3.4.1" + isomorphic.js@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/isomorphic.js/-/isomorphic.js-0.2.2.tgz#4c76fb70d3e207123dead08675ba97eb75f5615a" integrity sha512-tWhdHK5vam77zCkNKjpI8vWSrcVmlBeJIlxXgTiGaapgifQr0CfLHuPqMiZhjrI/K71X/aXaJZqUbkHZzg06Hg== +isomorphic.js@^0.2.4: + version "0.2.5" + resolved "https://registry.yarnpkg.com/isomorphic.js/-/isomorphic.js-0.2.5.tgz#13eecf36f2dba53e85d355e11bf9d4208c6f7f88" + integrity sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw== + jest-diff@^24.0.0, jest-diff@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" @@ -2787,13 +2836,20 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lib0@^0.2.34, lib0@^0.2.35, lib0@^0.2.38: +lib0@^0.2.34, lib0@^0.2.35: version "0.2.40" resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.40.tgz#7c89c2a7a89f9caaa0a04eaecb944d8e90a731b3" integrity sha512-bKJxwll8MdwTTL3Siut6L+FjyF5sewXRE7noDTsRquEYy3Xi1UjtdEMZu46iuTvw9nQ/9p+gKkh1GxL2Kdaphw== dependencies: isomorphic.js "^0.2.2" +lib0@^0.2.47, lib0@^0.2.74: + version "0.2.78" + resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.78.tgz#9aa34733075caafb3edf228da6e609d15ada0088" + integrity sha512-SV2nU43/6eaYnGH3l0lg2wg1ziB/TH3sAd2E8quXPGwrqo+aX98SNT2ZKucpUr5B8A52jD7ZMjAl+r87Fa/bLQ== + dependencies: + isomorphic.js "^0.2.4" + line-column@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/line-column/-/line-column-1.0.2.tgz#d25af2936b6f4849172b312e4792d1d987bc34a2" @@ -3204,6 +3260,13 @@ node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" +node-fetch@^2.6.1: + version "2.6.12" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" + integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== + dependencies: + whatwg-url "^5.0.0" + node-html-parser@1.4.9: version "1.4.9" resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-1.4.9.tgz#3c8f6cac46479fae5800725edb532e9ae8fd816c" @@ -4328,6 +4391,11 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + trough@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" @@ -4583,6 +4651,11 @@ web-namespaces@^1.0.0: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -4612,6 +4685,19 @@ whatwg-fetch@>=0.10.0: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.2.0.tgz#8e134f701f0a4ab5fda82626f113e2b647fd16dc" integrity sha512-SdGPoQMMnzVYThUbSrEvqTlkvC1Ux27NehaJ/GUHBfNrh5Mjg+1/uRyFMwVnxO2MrikMWvWAqUGgQOfVU4hT7w== +whatwg-fetch@^3.4.1: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + whatwg-url@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" @@ -4654,6 +4740,11 @@ ws@^7.2.0: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59" integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw== +ws@^7.5.9: + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + xmlhttprequest@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" @@ -4694,12 +4785,12 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yjs@^13.5.1: - version "13.5.1" - resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.5.1.tgz#addf14fb4120ee007497fcad327eae983b6ec220" - integrity sha512-U4BKBlcgvcYS/MkYYhW6zcE34dyYBvoZLl+9J9oFkYs6dHCXvX6WzZSgxlNnqjZn40jAN12Z0bSugqXuLVf2/g== +yjs@^13.6.6: + version "13.6.6" + resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.6.6.tgz#586b2dd25121a8cdb55ba85bb8760ec8904e037c" + integrity sha512-VTvezMeMuOra9jKG1Ym5XuQ2H4xXOubIIIupv/B5oygasa9IqDE7Ufv93QTSe9uz69J5VZGMQb2WTEmJv4kJFQ== dependencies: - lib0 "^0.2.38" + lib0 "^0.2.74" yocto-queue@^0.1.0: version "0.1.0"