From f29d7657626abdcb85e00667fa62fc6283031dd3 Mon Sep 17 00:00:00 2001 From: gempir Date: Mon, 12 Feb 2024 19:29:06 +0100 Subject: [PATCH 01/14] Revert "remove overlays, not sustainable to host" This reverts commit 2fce2cce0715240817af69bab1d65662c1b5afcd. --- .github/workflows/deploy.yml | 1 + Makefile | 12 + ansible/roles/gempbot/tasks/main.yml | 11 + .../roles/gempbot/templates/service-yjs.j2 | 18 + internal/server/overlay.go | 70 ++ internal/store/db.go | 6 + internal/store/overlay.go | 45 + internal/store/testing.go | 21 + main.go | 1 + web/package.json | 8 +- web/src/components/Overlay/Editor.tsx | 28 + .../components/Overlay/IframeOverlayPage.tsx | 34 + .../components/Overlay/OverlayEditPage.tsx | 15 + web/src/components/Overlay/OverlaysPage.tsx | 29 + web/src/components/Sidebar/Sidebar.tsx | 5 + web/src/hooks/useOverlays.ts | 81 ++ web/src/hooks/useYjsStore.ts | 278 +++++ web/src/pages/overlay/[roomId].tsx | 8 + web/src/pages/overlay/edit/[overlayId].tsx | 8 + web/src/pages/overlay/index.tsx | 8 + web/yarn.lock | 1061 ++++++++++++++++- web/yjs/callback.cjs | 76 ++ web/yjs/server.js | 86 ++ web/yjs/util.cjs | 286 +++++ 24 files changed, 2191 insertions(+), 5 deletions(-) create mode 100644 ansible/roles/gempbot/templates/service-yjs.j2 create mode 100644 internal/server/overlay.go create mode 100644 internal/store/overlay.go create mode 100644 web/src/components/Overlay/Editor.tsx create mode 100644 web/src/components/Overlay/IframeOverlayPage.tsx create mode 100644 web/src/components/Overlay/OverlayEditPage.tsx create mode 100644 web/src/components/Overlay/OverlaysPage.tsx create mode 100644 web/src/hooks/useOverlays.ts create mode 100644 web/src/hooks/useYjsStore.ts create mode 100644 web/src/pages/overlay/[roomId].tsx create mode 100644 web/src/pages/overlay/edit/[overlayId].tsx create mode 100644 web/src/pages/overlay/index.tsx create mode 100644 web/yjs/callback.cjs create mode 100755 web/yjs/server.js create mode 100644 web/yjs/util.cjs diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a20ab59..19a2f46 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,3 +18,4 @@ jobs: echo "${{secrets.SSH_PRIVATE_KEY}}" > ansible/.ssh_key chmod 600 ansible/.ssh_key make deploy + make deploy_yjs diff --git a/Makefile b/Makefile index 74770f2..32f91c4 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,9 @@ export $(shell sed 's/=.*//' .env) build_server: go run main.go +yjs_server: + cd web && yarn yjs + test: go test ./internal/... @@ -25,6 +28,15 @@ deploy: ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "sudo chown gempbot:gempbot /home/gempbot/gempbot" ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "sudo systemctl restart gempbot-migrate && sudo systemctl start gempbot" +deploy_yjs: + (cd web && yarn) + tar -czf web.tar.gz web + rsync -avz -e "ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key" web.tar.gz ubuntu@o1.gempir.com:/home/gempbot/ + ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "sudo systemctl stop gempbot-yjs" + ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "rm -rf /home/gempbot/web" + ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "tar -xf /home/gempbot/web.tar.gz -C /home/gempbot/" + ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "sudo systemctl start gempbot-yjs" + ansible: cd ansible && ansible-vault decrypt ssh_key.vault --output=.ssh_key chmod 600 ansible/.ssh_key diff --git a/ansible/roles/gempbot/tasks/main.yml b/ansible/roles/gempbot/tasks/main.yml index 68b0461..a3cc31a 100644 --- a/ansible/roles/gempbot/tasks/main.yml +++ b/ansible/roles/gempbot/tasks/main.yml @@ -29,6 +29,11 @@ src: templates/service.j2 dest: /etc/systemd/system/gempbot.service +- name: Install Yjs Service + template: + src: templates/service-yjs.j2 + dest: /etc/systemd/system/gempbot-yjs.service + - name: Install Migrate Service template: src: templates/migrate.j2 @@ -45,3 +50,9 @@ daemon_reload: true name: gempbot enabled: true + +- name: ensure yjs service is enabled + systemd: + daemon_reload: true + name: gempbot-yjs + enabled: true \ No newline at end of file diff --git a/ansible/roles/gempbot/templates/service-yjs.j2 b/ansible/roles/gempbot/templates/service-yjs.j2 new file mode 100644 index 0000000..d5ca2c2 --- /dev/null +++ b/ansible/roles/gempbot/templates/service-yjs.j2 @@ -0,0 +1,18 @@ +[Unit] +Description=gempbot-yjs +After=network.target +StartLimitBurst=10 + +[Service] +Restart=always +RestartSec=5 +ExecStart=/home/gempbot/web/yjs/server.js +WorkingDirectory=/home/gempbot/web +Environment=NODE_ENV=production +Environment=YPERSISTENCE=/home/gempbot/yjs_db +Environment=HOST=127.0.0.1 +Environment=PORT=1234 +Environment=SECRET={{ apiSecret }} + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/internal/server/overlay.go b/internal/server/overlay.go new file mode 100644 index 0000000..e3720b5 --- /dev/null +++ b/internal/server/overlay.go @@ -0,0 +1,70 @@ +package server + +import ( + "net/http" + "strings" + + "github.com/gempir/gempbot/internal/api" + "github.com/gempir/gempbot/internal/store" + "github.com/google/uuid" + "github.com/teris-io/shortid" +) + +func (a *Api) OverlayHandler(w http.ResponseWriter, r *http.Request) { + authResp, _, apiErr := a.authClient.AttemptAuth(r, w) + if apiErr != nil { + return + } + userID := authResp.Data.UserID + + if r.URL.Query().Get("managing") != "" { + userID, apiErr = a.userAdmin.CheckEditor(r, a.userAdmin.GetUserConfig(userID)) + if apiErr != nil { + http.Error(w, apiErr.Error(), apiErr.Status()) + return + } + } + + if r.Method == http.MethodGet { + if r.URL.Query().Get("roomId") != "" { + overlay := a.db.GetOverlayByRoomId(r.URL.Query().Get("roomId")) + api.WriteJson(w, overlay, http.StatusOK) + return + } + + if r.URL.Query().Get("id") != "" { + overlay := a.db.GetOverlay(r.URL.Query().Get("id"), userID) + api.WriteJson(w, overlay, http.StatusOK) + return + } + + overlays := a.db.GetOverlays(userID) + api.WriteJson(w, overlays, http.StatusOK) + } else if r.Method == http.MethodPost { + overlay := store.Overlay{} + overlay.OwnerTwitchID = userID + overlay.ID = shortid.MustGenerate() + // long string so you cant read addressbar easily + var roomID []string + for i := 0; i < 16; i++ { + roomID = append(roomID, uuid.New().String()) + } + overlay.RoomID = strings.Join(roomID, "-") + + err := a.db.SaveOverlay(overlay) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + api.WriteJson(w, overlay, http.StatusCreated) + + } else if r.Method == http.MethodDelete { + if r.URL.Query().Get("id") == "" { + http.Error(w, "missing id", http.StatusBadRequest) + } + + a.db.DeleteOverlay(r.URL.Query().Get("id")) + w.WriteHeader(http.StatusOK) + } +} diff --git a/internal/store/db.go b/internal/store/db.go index 08110c7..7b9def7 100644 --- a/internal/store/db.go +++ b/internal/store/db.go @@ -38,6 +38,11 @@ type Store interface { CountNominationDownvotes(ctx context.Context, channelTwitchID string, voteBy string) (int, error) CountNominationVotes(ctx context.Context, channelTwitchID string, voteBy string) (int, error) IsAlreadyNominated(ctx context.Context, channelTwitchID string, emoteID string) (bool, error) + GetOverlays(userID string) []Overlay + GetOverlay(ID string, userID string) Overlay + GetOverlayByRoomId(roomID string) Overlay + DeleteOverlay(ID string) + SaveOverlay(overlay Overlay) error } type Database struct { @@ -77,6 +82,7 @@ func (db *Database) Migrate() { Nomination{}, NominationVote{}, NominationDownvote{}, + Overlay{}, ) if err != nil { panic("Failed to migrate, " + err.Error()) diff --git a/internal/store/overlay.go b/internal/store/overlay.go new file mode 100644 index 0000000..1bc0935 --- /dev/null +++ b/internal/store/overlay.go @@ -0,0 +1,45 @@ +package store + +import "gorm.io/gorm/clause" + +type Overlay struct { + ID string `gorm:"primaryKey"` + OwnerTwitchID string `gorm:"index"` + RoomID string `gorm:"index"` +} + +func (db *Database) GetOverlays(userID string) []Overlay { + var overlays []Overlay + + db.Client.Where("owner_twitch_id = ?", userID).Find(&overlays) + + return overlays +} + +func (db *Database) GetOverlay(ID string, userID string) Overlay { + var overlay Overlay + + db.Client.Where("id = ? AND owner_twitch_id = ?", ID, userID).First(&overlay) + + return overlay +} + +func (db *Database) GetOverlayByRoomId(roomID string) Overlay { + var overlay Overlay + + db.Client.Where("room_id = ?", roomID).First(&overlay) + + return overlay +} + +func (db *Database) DeleteOverlay(ID string) { + db.Client.Delete(&Overlay{}, "id = ?", ID) +} + +func (db *Database) SaveOverlay(overlay Overlay) error { + update := db.Client.Clauses(clause.OnConflict{ + UpdateAll: true, + }).Create(&overlay) + + return update.Error +} diff --git a/internal/store/testing.go b/internal/store/testing.go index 90cc745..7a1daad 100644 --- a/internal/store/testing.go +++ b/internal/store/testing.go @@ -131,3 +131,24 @@ func (s *MockStore) CountNominationDownvotes(ctx context.Context, channelTwitchI func (s *MockStore) CountNominationVotes(ctx context.Context, channelTwitchID string, voteBy string) (int, error) { return 0, nil } + +func (s *MockStore) GetOverlays(userID string) []Overlay { + return []Overlay{ + {ID: "1", OwnerTwitchID: "1", RoomID: "roomid"}, + } +} + +func (s *MockStore) GetOverlay(ID string, userID string) Overlay { + return Overlay{} +} + +func (s *MockStore) GetOverlayByRoomId(roomID string) Overlay { + return Overlay{} +} + +func (s *MockStore) DeleteOverlay(ID string) { +} + +func (s *MockStore) SaveOverlay(overlay Overlay) error { + return nil +} diff --git a/main.go b/main.go index 2a63406..cd9c52b 100644 --- a/main.go +++ b/main.go @@ -68,6 +68,7 @@ func main() { mux.HandleFunc("/api/reward", apiHandlers.RewardHandler) mux.HandleFunc("/api/subscriptions", apiHandlers.SubscriptionsHandler) mux.HandleFunc("/api/userconfig", apiHandlers.UserConfigHandler) + mux.HandleFunc("/api/overlay", apiHandlers.OverlayHandler) mux.HandleFunc("/api/ws", wsHandler.HandleWs) handler := cors.New(cors.Options{ diff --git a/web/package.json b/web/package.json index b6de419..52acb06 100644 --- a/web/package.json +++ b/web/package.json @@ -3,15 +3,18 @@ "scripts": { "dev": "next dev", "build": "next build", - "start": "next start" + "start": "next start", + "yjs": "node yjs/server.js" }, "type": "module", "dependencies": { "@heroicons/react": "^2.0.12", "@tailwindcss/forms": "^0.5.7", + "@tldraw/tldraw": "^2.0.0-beta.2", "@types/seedrandom": "^3.0.4", "dayjs": "^1.11.7", "eslint-config-next": "^14.1.0", + "jsonwebtoken": "^9.0.2", "jwt-decode": "^3.1.2", "next": "^14.1.0", "react": "^18.2.0", @@ -21,6 +24,9 @@ "react-use-websocket": "^4.5.0", "seedrandom": "^3.0.5", "tailwindcss": "^3.4.1", + "y-utility": "^0.1.3", + "y-websocket": "^1.5.3", + "yjs": "^13.6.11", "zustand": "^3.7.2" }, "devDependencies": { diff --git a/web/src/components/Overlay/Editor.tsx b/web/src/components/Overlay/Editor.tsx new file mode 100644 index 0000000..c9bef20 --- /dev/null +++ b/web/src/components/Overlay/Editor.tsx @@ -0,0 +1,28 @@ +import { Editor, Tldraw, TldrawProps } from '@tldraw/tldraw'; +import '@tldraw/tldraw/tldraw.css'; +import { useYjsStore } from '../../hooks/useYjsStore'; +import { useStore } from '../../store'; + + +type Props = { + roomId: string; + readonly?: boolean; +} + +export function CustomEditor(props: Partial & Props) { + const yjsWsUrl = useStore(state => state.yjsWsUrl); + const store = useYjsStore({ + roomId: props.roomId, + hostUrl: yjsWsUrl, + }); + + const handleMount = (editor: Editor) => { + if (props.readonly) { + editor.setCamera({ x: 0, y: 0, z: 1 }); + editor.updateInstanceState({ isReadonly: true, canMoveCamera: false }) + editor.selectNone(); + } + } + + return +} \ No newline at end of file diff --git a/web/src/components/Overlay/IframeOverlayPage.tsx b/web/src/components/Overlay/IframeOverlayPage.tsx new file mode 100644 index 0000000..6ed0981 --- /dev/null +++ b/web/src/components/Overlay/IframeOverlayPage.tsx @@ -0,0 +1,34 @@ +'use client'; + +import dynamic from 'next/dynamic'; +import Head from 'next/head'; +import { useParams } from 'next/navigation'; + +const Editor = dynamic(async () => (await import('./Editor')).CustomEditor, { ssr: false }) + +export function IframeOverlayPage() { + const params = useParams<{ roomId: string }>(); + + console.log("Joining", params.roomId); + + return ( +
+ + + + +
+ ); +} \ No newline at end of file diff --git a/web/src/components/Overlay/OverlayEditPage.tsx b/web/src/components/Overlay/OverlayEditPage.tsx new file mode 100644 index 0000000..7e204db --- /dev/null +++ b/web/src/components/Overlay/OverlayEditPage.tsx @@ -0,0 +1,15 @@ +const Editor = dynamic(async () => (await import('./Editor')).CustomEditor, { ssr: false }) +import dynamic from "next/dynamic"; +import { useOverlay } from "../../hooks/useOverlays"; +import { useParams } from "next/navigation"; + +export function OverlayEditPage() { + const params = useParams<{ overlayId: string }>(); + const [overlay] = useOverlay(params.overlayId); + + console.log("Joining", overlay?.RoomID); + + return
+ {overlay?.RoomID && } +
; +} \ No newline at end of file diff --git a/web/src/components/Overlay/OverlaysPage.tsx b/web/src/components/Overlay/OverlaysPage.tsx new file mode 100644 index 0000000..633349f --- /dev/null +++ b/web/src/components/Overlay/OverlaysPage.tsx @@ -0,0 +1,29 @@ +import Link from "next/link"; +import { useOverlays } from "../../hooks/useOverlays"; + +export function OverlaysPage() { + const [overlays, addOverlay, deleteOverlay, errorMessage, loading] = useOverlays(); + + + return
+
+ +
+ {overlays.map(overlay =>
+
+ +
+
{overlay.ID}
+
+ Edit +
+
+ +
+
)} +
+
+
; +} \ No newline at end of file diff --git a/web/src/components/Sidebar/Sidebar.tsx b/web/src/components/Sidebar/Sidebar.tsx index 2b445c2..5a6bd89 100644 --- a/web/src/components/Sidebar/Sidebar.tsx +++ b/web/src/components/Sidebar/Sidebar.tsx @@ -29,6 +29,11 @@ export function Sidebar() { className="flex gap-2 items-center py-4 justify-start hover:text-blue-500"> Bot + + Overlays + diff --git a/web/src/hooks/useOverlays.ts b/web/src/hooks/useOverlays.ts new file mode 100644 index 0000000..c5f1fa7 --- /dev/null +++ b/web/src/hooks/useOverlays.ts @@ -0,0 +1,81 @@ +import { useEffect, useState } from "react"; +import { Method, doFetch } from "../service/doFetch"; +import { useStore } from "../store"; + +type Overlay = { + ID: string; + RoomID: string; +} + +export function useOverlays(): [Overlay[], () => void, (id: string) => void, string | null, boolean] { + const [overlays, setOverlays] = useState([]); + const [errorMessage, setErrorMessage] = useState(null); + const [loading, setLoading] = useState(false); + const managing = useStore(state => state.managing); + const apiBaseUrl = useStore(state => state.apiBaseUrl); + const scToken = useStore(state => state.scToken); + + const fetchOverlays = () => { + setLoading(true); + const endPoint = "/api/overlay"; + + doFetch({ apiBaseUrl, managing, scToken }, Method.GET, endPoint).then(setOverlays).catch(setErrorMessage).finally(() => setLoading(false)); + } + + useEffect(fetchOverlays, []); + + const addOverlay = () => { + setLoading(true); + const endPoint = "/api/overlay"; + + doFetch({ apiBaseUrl, managing, scToken }, Method.POST, endPoint).then(fetchOverlays).catch(setErrorMessage).finally(() => setLoading(false)); + } + + const deleteOverlay = (id: string) => { + setLoading(true); + const endPoint = "/api/overlay"; + + doFetch({ apiBaseUrl, managing, scToken }, Method.DELETE, endPoint, new URLSearchParams({id})).then(() => setErrorMessage(null)).then(fetchOverlays).catch(setErrorMessage).finally(() => setLoading(false)); + } + + return [overlays, addOverlay, deleteOverlay, errorMessage, loading]; +} + + +export function useOverlay(id: string): [Overlay|null, boolean] { + const [overlay, setOverlay] = useState(null); + const [loading, setLoading] = useState(false); + const managing = useStore(state => state.managing); + const apiBaseUrl = useStore(state => state.apiBaseUrl); + const scToken = useStore(state => state.scToken); + + const fetchOverlay = () => { + setLoading(true); + const endPoint = "/api/overlay"; + + doFetch({ apiBaseUrl, managing, scToken }, Method.GET, endPoint, new URLSearchParams({id})).then(setOverlay).finally(() => setLoading(false)); + } + + useEffect(fetchOverlay, [id]); + + return [overlay, loading]; +} + +export function useOverlayByRoomId(roomId: string): [Overlay|null, boolean] { + const [overlay, setOverlay] = useState(null); + const [loading, setLoading] = useState(false); + const managing = useStore(state => state.managing); + const apiBaseUrl = useStore(state => state.apiBaseUrl); + const scToken = useStore(state => state.scToken); + + const fetchOverlay = () => { + setLoading(true); + const endPoint = "/api/overlay"; + + doFetch({ apiBaseUrl, managing, scToken }, Method.GET, endPoint, new URLSearchParams({roomId})).then(setOverlay).finally(() => setLoading(false)); + } + + useEffect(fetchOverlay, [roomId]); + + return [overlay, loading]; +} \ No newline at end of file diff --git a/web/src/hooks/useYjsStore.ts b/web/src/hooks/useYjsStore.ts new file mode 100644 index 0000000..0d3531f --- /dev/null +++ b/web/src/hooks/useYjsStore.ts @@ -0,0 +1,278 @@ +import { + InstancePresenceRecordType, + TLAnyShapeUtilConstructor, + TLInstancePresence, + TLRecord, + TLStoreWithStatus, + computed, + createPresenceStateDerivation, + createTLStore, + defaultShapeUtils, + defaultUserPreferences, + getUserPreferences, + setUserPreferences, + react, + transact, +} from '@tldraw/tldraw' +import { useEffect, useMemo, useState } from 'react' +import { YKeyValue } from 'y-utility/y-keyvalue' +import { WebsocketProvider } from 'y-websocket' +import * as Y from 'yjs' +import { DEFAULT_STORE } from './default_store' + +export function useYjsStore({ + roomId = 'example', + hostUrl, + shapeUtils = [], +}: Partial<{ + hostUrl: string + roomId: string + version: number + shapeUtils: TLAnyShapeUtilConstructor[] +}>) { + const [store] = useState(() => { + const store = createTLStore({ + shapeUtils: [...defaultShapeUtils, ...shapeUtils], + }) + store.loadSnapshot(DEFAULT_STORE) + return store + }) + + const [storeWithStatus, setStoreWithStatus] = useState({ + status: 'loading', + }) + + const { yDoc, yStore, room } = useMemo(() => { + const yDoc = new Y.Doc({ gc: true }) + const yArr = yDoc.getArray<{ key: string; val: TLRecord }>(`tl_${roomId}`) + const yStore = new YKeyValue(yArr) + + return { + yDoc, + yStore, + room: new WebsocketProvider(String(hostUrl), roomId, yDoc, { connect: true }), + } + }, [hostUrl, roomId]) + + useEffect(() => { + setStoreWithStatus({ status: 'loading' }) + + const unsubs: (() => void)[] = [] + + function handleSync() { + // 1. + // Connect store to yjs store and vis versa, for both the document and awareness + + /* -------------------- Document -------------------- */ + + // Sync store changes to the yjs doc + unsubs.push( + store.listen( + function syncStoreChangesToYjsDoc({ changes }) { + yDoc.transact(() => { + Object.values(changes.added).forEach((record) => { + yStore.set(record.id, record) + }) + + Object.values(changes.updated).forEach(([_, record]) => { + yStore.set(record.id, record) + }) + + Object.values(changes.removed).forEach((record) => { + yStore.delete(record.id) + }) + }) + }, + { source: 'user', scope: 'document' } // only sync user's document changes + ) + ) + + // Sync the yjs doc changes to the store + const handleChange = ( + changes: Map< + string, + | { action: 'delete'; oldValue: TLRecord } + | { action: 'update'; oldValue: TLRecord; newValue: TLRecord } + | { action: 'add'; newValue: TLRecord } + >, + transaction: Y.Transaction + ) => { + if (transaction.local) return + + const toRemove: TLRecord['id'][] = [] + const toPut: TLRecord[] = [] + + changes.forEach((change, id) => { + switch (change.action) { + case 'add': + case 'update': { + const record = yStore.get(id)! + toPut.push(record) + break + } + case 'delete': { + toRemove.push(id as TLRecord['id']) + break + } + } + }) + + // put / remove the records in the store + store.mergeRemoteChanges(() => { + if (toRemove.length) store.remove(toRemove) + if (toPut.length) store.put(toPut) + }) + } + + yStore.on('change', handleChange) + unsubs.push(() => yStore.off('change', handleChange)) + + /* -------------------- Awareness ------------------- */ + + const yClientId = room.awareness.clientID.toString() + setUserPreferences({ id: yClientId }) + + const userPreferences = computed<{ + id: string + color: string + name: string + }>('userPreferences', () => { + const user = getUserPreferences() + return { + id: user.id, + color: user.color ?? defaultUserPreferences.color, + name: user.name ?? defaultUserPreferences.name, + } + }) + + // Create the instance presence derivation + const presenceId = InstancePresenceRecordType.createId(yClientId) + const presenceDerivation = + createPresenceStateDerivation(userPreferences, presenceId)(store) + + // Set our initial presence from the derivation's current value + // @ts-expect-error + room.awareness.setLocalStateField('presence', presenceDerivation.value) + + // When the derivation change, sync presence to to yjs awareness + unsubs.push( + react('when presence changes', () => { + // @ts-expect-error + const presence = presenceDerivation.value + requestAnimationFrame(() => { + room.awareness.setLocalStateField('presence', presence) + }) + }) + ) + + // Sync yjs awareness changes to the store + const handleUpdate = (update: { + added: number[] + updated: number[] + removed: number[] + }) => { + const states = room.awareness.getStates() as Map< + number, + { presence: TLInstancePresence } + > + + const toRemove: TLInstancePresence['id'][] = [] + const toPut: TLInstancePresence[] = [] + + // Connect records to put / remove + for (const clientId of update.added) { + const state = states.get(clientId) + if (state?.presence && state.presence.id !== presenceId) { + toPut.push(state.presence) + } + } + + for (const clientId of update.updated) { + const state = states.get(clientId) + if (state?.presence && state.presence.id !== presenceId) { + toPut.push(state.presence) + } + } + + for (const clientId of update.removed) { + toRemove.push( + InstancePresenceRecordType.createId(clientId.toString()) + ) + } + + // put / remove the records in the store + store.mergeRemoteChanges(() => { + if (toRemove.length) store.remove(toRemove) + if (toPut.length) store.put(toPut) + }) + } + + room.awareness.on('update', handleUpdate) + unsubs.push(() => room.awareness.off('update', handleUpdate)) + + // 2. + // Initialize the store with the yjs doc records—or, if the yjs doc + // is empty, initialize the yjs doc with the default store records. + if (yStore.yarray.length) { + // Replace the store records with the yjs doc records + transact(() => { + // The records here should be compatible with what's in the store + store.clear() + const records = yStore.yarray.toJSON().map(({ val }) => val) + store.put(records) + }) + } else { + // Create the initial store records + // Sync the store records to the yjs doc + yDoc.transact(() => { + for (const record of store.allRecords()) { + yStore.set(record.id, record) + } + }) + } + + setStoreWithStatus({ + store, + status: 'synced-remote', + connectionStatus: 'online', + }) + } + + let hasConnectedBefore = false + + function handleStatusChange({ + status, + }: { + status: 'disconnected' | 'connected' + }) { + // If we're disconnected, set the store status to 'synced-remote' and the connection status to 'offline' + if (status === 'disconnected') { + setStoreWithStatus({ + store, + status: 'synced-remote', + connectionStatus: 'offline', + }) + return + } + + room.off('synced', handleSync) + + if (status === 'connected') { + if (hasConnectedBefore) return + hasConnectedBefore = true + room.on('synced', handleSync) + unsubs.push(() => room.off('synced', handleSync)) + } + } + + room.on('status', handleStatusChange) + unsubs.push(() => room.off('status', handleStatusChange)) + + return () => { + unsubs.forEach((fn) => fn()) + unsubs.length = 0 + } + }, [room, yDoc, store, yStore]) + + return storeWithStatus +} \ No newline at end of file diff --git a/web/src/pages/overlay/[roomId].tsx b/web/src/pages/overlay/[roomId].tsx new file mode 100644 index 0000000..4ff2d70 --- /dev/null +++ b/web/src/pages/overlay/[roomId].tsx @@ -0,0 +1,8 @@ +import { IframeOverlayPage } from "../../components/Overlay/IframeOverlayPage"; +import { initializeStoreWithProps } from "../../service/initializeStore"; + +export default function Overlay() { + return +} + +export const getServerSideProps = initializeStoreWithProps({renderFullLayout: false}); \ No newline at end of file diff --git a/web/src/pages/overlay/edit/[overlayId].tsx b/web/src/pages/overlay/edit/[overlayId].tsx new file mode 100644 index 0000000..c3bc241 --- /dev/null +++ b/web/src/pages/overlay/edit/[overlayId].tsx @@ -0,0 +1,8 @@ +import { OverlayEditPage } from "../../../components/Overlay/OverlayEditPage"; +import { initializeStore } from "../../../service/initializeStore"; + +export default function OverlaysEditPage() { + return +} + +export const getServerSideProps = initializeStore; \ No newline at end of file diff --git a/web/src/pages/overlay/index.tsx b/web/src/pages/overlay/index.tsx new file mode 100644 index 0000000..8b77f79 --- /dev/null +++ b/web/src/pages/overlay/index.tsx @@ -0,0 +1,8 @@ +import { OverlaysPage } from "../../components/Overlay/OverlaysPage"; +import { initializeStore } from "../../service/initializeStore"; + +export default function OverlaysPageRoute() { + return +} + +export const getServerSideProps = initializeStore; \ No newline at end of file diff --git a/web/yarn.lock b/web/yarn.lock index ee35b73..bbe6ccc 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -7,13 +7,40 @@ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== -"@babel/runtime@^7.1.2", "@babel/runtime@^7.23.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.13.10", "@babel/runtime@^7.23.2": version "7.23.9" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== dependencies: regenerator-runtime "^0.14.0" +"@floating-ui/core@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" + integrity sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g== + dependencies: + "@floating-ui/utils" "^0.2.1" + +"@floating-ui/dom@^1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.1.tgz#d552e8444f77f2d88534372369b3771dc3a2fa5d" + integrity sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ== + dependencies: + "@floating-ui/core" "^1.6.0" + "@floating-ui/utils" "^0.2.1" + +"@floating-ui/react-dom@^2.0.0": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.8.tgz#afc24f9756d1b433e1fe0d047c24bd4d9cefaa5d" + integrity sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw== + dependencies: + "@floating-ui/dom" "^1.6.1" + +"@floating-ui/utils@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" + integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== + "@heroicons/react@^2.0.12": version "2.1.1" resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.1.1.tgz#422deb80c4d6caf3371aec6f4bee8361a354dc13" @@ -146,6 +173,451 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@radix-ui/number@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.0.1.tgz#644161a3557f46ed38a042acf4a770e826021674" + integrity sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/primitive@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd" + integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-alert-dialog@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.5.tgz#70dd529cbf1e4bff386814d3776901fcaa131b8c" + integrity sha512-OrVIOcZL0tl6xibeuGt5/+UxoT2N27KCFOPjFyfXMnchxSHZ/OW7cCX2nGlIYJrbHK/fczPcFzAwvNBB6XBNMA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dialog" "1.0.5" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + +"@radix-ui/react-arrow@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz#c24f7968996ed934d57fe6cde5d6ec7266e1d25d" + integrity sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + +"@radix-ui/react-collection@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159" + integrity sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + +"@radix-ui/react-compose-refs@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" + integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-context-menu@^2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context-menu/-/react-context-menu-2.1.5.tgz#1bdbd72761439f9166f75dc4598f276265785c83" + integrity sha512-R5XaDj06Xul1KGb+WP8qiOh7tKJNz2durpLBXAGZjSVtctcRFCuEvy2gtMwRJGePwQQE5nV77gs4FwRi8T+r2g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-menu" "2.0.6" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-context@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c" + integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-dialog@1.0.5", "@radix-ui/react-dialog@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300" + integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + +"@radix-ui/react-direction@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b" + integrity sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-dismissable-layer@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz#883a48f5f938fa679427aa17fcba70c5494c6978" + integrity sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-escape-keydown" "1.0.3" + +"@radix-ui/react-dismissable-layer@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4" + integrity sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-escape-keydown" "1.0.3" + +"@radix-ui/react-dropdown-menu@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.6.tgz#cdf13c956c5e263afe4e5f3587b3071a25755b63" + integrity sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-menu" "2.0.6" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-focus-guards@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad" + integrity sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-focus-scope@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.3.tgz#9c2e8d4ed1189a1d419ee61edd5c1828726472f9" + integrity sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + +"@radix-ui/react-focus-scope@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525" + integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + +"@radix-ui/react-id@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0" + integrity sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.1" + +"@radix-ui/react-menu@2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.0.6.tgz#2c9e093c1a5d5daa87304b2a2f884e32288ae79e" + integrity sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-popper" "1.1.3" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-roving-focus" "1.0.4" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-callback-ref" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + +"@radix-ui/react-popover@^1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.0.7.tgz#23eb7e3327330cb75ec7b4092d685398c1654e3c" + integrity sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-popper" "1.1.3" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + +"@radix-ui/react-popper@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.2.tgz#4c0b96fcd188dc1f334e02dba2d538973ad842e9" + integrity sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg== + dependencies: + "@babel/runtime" "^7.13.10" + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-use-rect" "1.0.1" + "@radix-ui/react-use-size" "1.0.1" + "@radix-ui/rect" "1.0.1" + +"@radix-ui/react-popper@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.3.tgz#24c03f527e7ac348fabf18c89795d85d21b00b42" + integrity sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w== + dependencies: + "@babel/runtime" "^7.13.10" + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-use-rect" "1.0.1" + "@radix-ui/react-use-size" "1.0.1" + "@radix-ui/rect" "1.0.1" + +"@radix-ui/react-portal@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.3.tgz#ffb961244c8ed1b46f039e6c215a6c4d9989bda1" + integrity sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + +"@radix-ui/react-portal@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15" + integrity sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + +"@radix-ui/react-presence@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba" + integrity sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + +"@radix-ui/react-primitive@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0" + integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-slot" "1.0.2" + +"@radix-ui/react-roving-focus@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz#e90c4a6a5f6ac09d3b8c1f5b5e81aab2f0db1974" + integrity sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-select@^1.2.0": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-1.2.2.tgz#caa981fa0d672cf3c1b2a5240135524e69b32181" + integrity sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/number" "1.0.1" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.4" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.3" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-popper" "1.1.2" + "@radix-ui/react-portal" "1.0.3" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-controllable-state" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-use-previous" "1.0.1" + "@radix-ui/react-visually-hidden" "1.0.3" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + +"@radix-ui/react-slider@^1.1.0": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slider/-/react-slider-1.1.2.tgz#330ff2a0e1f6c19aace76590004f229a7e8fbe6c" + integrity sha512-NKs15MJylfzVsCagVSWKhGGLNR1W9qWs+HtgbmjjVUB3B9+lb3PYoXxVju3kOrpf0VKyVCtZp+iTwVoqpa1Chw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/number" "1.0.1" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-controllable-state" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-use-previous" "1.0.1" + "@radix-ui/react-use-size" "1.0.1" + +"@radix-ui/react-slot@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" + integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + +"@radix-ui/react-toast@^1.1.1": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toast/-/react-toast-1.1.5.tgz#f5788761c0142a5ae9eb97f0051fd3c48106d9e6" + integrity sha512-fRLn227WHIBRSzuRzGJ8W+5YALxofH23y0MlPLddaIpLpCDqdE0NZlS2NRQDRiptfxDeeCjgFIpexB1/zkxDlw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-controllable-state" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-visually-hidden" "1.0.3" + +"@radix-ui/react-use-callback-ref@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a" + integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-controllable-state@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286" + integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.1" + +"@radix-ui/react-use-escape-keydown@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz#217b840c250541609c66f67ed7bab2b733620755" + integrity sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.1" + +"@radix-ui/react-use-layout-effect@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399" + integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-previous@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz#b595c087b07317a4f143696c6a01de43b0d0ec66" + integrity sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-rect@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz#fde50b3bb9fd08f4a1cd204572e5943c244fcec2" + integrity sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/rect" "1.0.1" + +"@radix-ui/react-use-size@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz#1c5f5fea940a7d7ade77694bb98116fb49f870b2" + integrity sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.1" + +"@radix-ui/react-visually-hidden@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz#51aed9dd0fe5abcad7dee2a234ad36106a6984ac" + integrity sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + +"@radix-ui/rect@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.1.tgz#bf8e7d947671996da2e30f4904ece343bc4a883f" + integrity sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@rushstack/eslint-patch@^1.3.3": version "1.7.2" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.7.2.tgz#2d4260033e199b3032a08b41348ac10de21c47e9" @@ -165,6 +637,90 @@ dependencies: mini-svg-data-uri "^1.2.3" +"@tldraw/editor@2.0.0-beta.2": + version "2.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@tldraw/editor/-/editor-2.0.0-beta.2.tgz#81a7d2e9e0aeeece65b1046ef022934a4c4d7533" + integrity sha512-CEWIyqO+CdSrIVT03OIpVhRB2PcDDkqU40vVdMYJfX5e1oWWGAPC6d/DVTaAUbZt3L4PSx7IVutyvQX7R9bYeA== + dependencies: + "@tldraw/state" "2.0.0-beta.2" + "@tldraw/store" "2.0.0-beta.2" + "@tldraw/tlschema" "2.0.0-beta.2" + "@tldraw/utils" "2.0.0-beta.2" + "@tldraw/validate" "2.0.0-beta.2" + "@types/core-js" "^2.5.5" + "@use-gesture/react" "^10.2.27" + classnames "^2.3.2" + core-js "^3.31.1" + eventemitter3 "^4.0.7" + idb "^7.1.1" + is-plain-object "^5.0.0" + lodash.throttle "^4.1.1" + lodash.uniq "^4.5.0" + nanoid "4.0.2" + +"@tldraw/state@2.0.0-beta.2": + version "2.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@tldraw/state/-/state-2.0.0-beta.2.tgz#fd1f4d9068981c37ebec665a87b727a23af2c15b" + integrity sha512-2hJlswI9o+i5l8+semFsASAcrrgoXE9EyMS7hXq46GS2FLJcEGA7K+se8zip3pCls5mdOtq2kNT9rZ0hPuaKBg== + +"@tldraw/store@2.0.0-beta.2": + version "2.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@tldraw/store/-/store-2.0.0-beta.2.tgz#785547f9fd126269e00b0bb2fcfb013ab7c3d348" + integrity sha512-lRQbucF9o/lM1cagXHKlyx4IN2vg+wtD61/iOtOXykIkdjBVub2V8FViapNKuLERI22dnA2DCC1Q+nWN1g17TQ== + dependencies: + "@tldraw/state" "2.0.0-beta.2" + "@tldraw/utils" "2.0.0-beta.2" + lodash.isequal "^4.5.0" + nanoid "4.0.2" + +"@tldraw/tldraw@^2.0.0-beta.2": + version "2.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@tldraw/tldraw/-/tldraw-2.0.0-beta.2.tgz#b3760b33f37a5e019dedbdcf574aec481c18531b" + integrity sha512-gQU7JyTHobWSJ+azcrNRdjpqDknAT+3NGas/9BG9YZc+h2y+uwcy2DaY9FiAEJjQTyS+dSOrm18F6QyOUntY9g== + dependencies: + "@radix-ui/react-alert-dialog" "^1.0.0" + "@radix-ui/react-context-menu" "^2.1.5" + "@radix-ui/react-dialog" "^1.0.5" + "@radix-ui/react-dropdown-menu" "^2.0.6" + "@radix-ui/react-popover" "^1.0.7" + "@radix-ui/react-select" "^1.2.0" + "@radix-ui/react-slider" "^1.1.0" + "@radix-ui/react-toast" "^1.1.1" + "@tldraw/editor" "2.0.0-beta.2" + canvas-size "^1.2.6" + classnames "^2.3.2" + downscale "^1.0.6" + hotkeys-js "^3.11.2" + lz-string "^1.4.4" + +"@tldraw/tlschema@2.0.0-beta.2": + version "2.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@tldraw/tlschema/-/tlschema-2.0.0-beta.2.tgz#3c4a9d8202130e003677a535ceeae6eae7ba8541" + integrity sha512-PRwetIFNEs9i90W8Wph3PbWmXlEKheRpAb9gjQD/iG2L82ZOBV1c91QAcEksc1ho+3j3Fbvs8yVqDU8SQkpQMA== + dependencies: + "@tldraw/state" "2.0.0-beta.2" + "@tldraw/store" "2.0.0-beta.2" + "@tldraw/utils" "2.0.0-beta.2" + "@tldraw/validate" "2.0.0-beta.2" + nanoid "4.0.2" + +"@tldraw/utils@2.0.0-beta.2": + version "2.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@tldraw/utils/-/utils-2.0.0-beta.2.tgz#d14ee7d73760887480d9e483893f01d1c82f890f" + integrity sha512-TEfd1l/+q0V0nr5pWIxT5kZXGHnU/FuzMi4HgHudoI4arTP/cv7FTnviXnd3nda+FUQe9LM+nwMaWDxg5wLjPA== + +"@tldraw/validate@2.0.0-beta.2": + version "2.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@tldraw/validate/-/validate-2.0.0-beta.2.tgz#bfc5e1a68a2a61dff7998cac6edbb22d9f2e79a7" + integrity sha512-AmpZ1OcnwJeYzj0qofBfOm7tnpecSThNNmqciRxXIb8TxIiSJDbGi6zEm10Exgx4oJ/XpZCS5Qk+StFMkdanSQ== + dependencies: + "@tldraw/utils" "2.0.0-beta.2" + +"@types/core-js@^2.5.5": + version "2.5.8" + resolved "https://registry.yarnpkg.com/@types/core-js/-/core-js-2.5.8.tgz#d5c6ec44f2f3328653dce385ae586bd8261f8e85" + integrity sha512-VgnAj6tIAhJhZdJ8/IpxdatM8G4OD3VWGlp6xIxUGENZlpbob9Ty4VVdC1FIEp0aK6DBscDDjyzy5FB60TuNqg== + "@types/js-cookie@^2.2.6": version "2.2.7" resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3" @@ -252,11 +808,45 @@ "@typescript-eslint/types" "6.20.0" eslint-visitor-keys "^3.4.1" +"@use-gesture/core@10.3.0": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@use-gesture/core/-/core-10.3.0.tgz#9afd3777a45b2a08990a5dcfcf8d9ddd55b00db9" + integrity sha512-rh+6MND31zfHcy9VU3dOZCqGY511lvGcfyJenN4cWZe0u1BH6brBpBddLVXhF2r4BMqWbvxfsbL7D287thJU2A== + +"@use-gesture/react@^10.2.27": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@use-gesture/react/-/react-10.3.0.tgz#180534c821fd635c2853cbcfa813f92c94f27e3f" + integrity sha512-3zc+Ve99z4usVP6l9knYVbVnZgfqhKah7sIG+PS2w+vpig2v2OLct05vs+ZXMzwxdNCMka8B+8WlOo0z6Pn6DA== + dependencies: + "@use-gesture/core" "10.3.0" + "@xobotyi/scrollbar-width@^1.9.5": version "1.9.5" resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ== +abstract-leveldown@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" + integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== + dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +abstract-leveldown@~6.2.1, abstract-leveldown@~6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" + integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== + dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -297,6 +887,13 @@ arg@^5.0.2: resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== +aria-hidden@^1.1.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954" + integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== + dependencies: + tslib "^2.0.0" + aria-query@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" @@ -388,6 +985,11 @@ ast-types-flow@^0.0.8: resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + asynciterator.prototype@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" @@ -429,6 +1031,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -466,6 +1073,19 @@ browserslist@^4.22.2: node-releases "^2.0.14" update-browserslist-db "^1.0.13" +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + +buffer@^5.5.0, buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + busboy@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" @@ -492,6 +1112,11 @@ caniuse-lite@^1.0.30001578, caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.300015 resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001583.tgz#abb2970cc370801dc7e27bf290509dc132cfa390" integrity sha512-acWTYaha8xfhA/Du/z4sNZjHUWjkiuoAi2LM+T/aL+kemKQgPT1xBb/YKjlQ0Qo8gvbHsGNplrEJ+9G3gL7i4Q== +canvas-size@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/canvas-size/-/canvas-size-1.2.6.tgz#1eaa6b56167cf2a70fa4021680829d2073b45706" + integrity sha512-x2iVHOrZ5x9V0Hwx6kBz+Yxf/VCAII+jrD6WLjJbytJLozHq/oDJjEva432Os0eHxWMFR0vYlLJwTr6QxyxQqw== + chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -507,6 +1132,11 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +classnames@^2.3.2: + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== + client-only@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" @@ -541,6 +1171,11 @@ copy-to-clipboard@^3.3.1: dependencies: toggle-selection "^1.0.6" +core-js@^3.31.1: + version "3.35.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.35.1.tgz#9c28f8b7ccee482796f8590cc8d15739eaaf980c" + integrity sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw== + cross-spawn@^7.0.0: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -599,6 +1234,14 @@ debug@^4.3.4: dependencies: ms "2.1.2" +deferred-leveldown@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" + integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== + dependencies: + abstract-leveldown "~6.2.1" + inherits "^2.0.3" + define-data-property@^1.0.1, define-data-property@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" @@ -622,6 +1265,11 @@ dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + didyoumean@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" @@ -646,11 +1294,23 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" +downscale@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/downscale/-/downscale-1.0.6.tgz#f1a1cb4d64c5831f1ba65341369131b5a73d2f2c" + integrity sha512-Arh9ftj+wo3CkFoT48SgT/crMyqmgZtNaaV/etjzHaUqNAaS36GS38ECURnfl7X/XvXN5uZNigGF7Vhffrm/pg== + eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + electron-to-chromium@^1.4.648: version "1.4.656" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.656.tgz#b374fb7cab9b782a5bc967c0ce0e19826186b9c9" @@ -666,6 +1326,16 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +encoding-down@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" + integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== + dependencies: + abstract-leveldown "^6.2.1" + inherits "^2.0.3" + level-codec "^9.0.0" + level-errors "^2.0.0" + enhanced-resolve@^5.12.0: version "5.15.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" @@ -674,6 +1344,13 @@ enhanced-resolve@^5.12.0: graceful-fs "^4.2.4" tapable "^2.2.0" +errno@~0.1.1: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + error-stack-parser@^2.0.6: version "2.1.4" resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" @@ -912,6 +1589,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1013,6 +1695,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -1120,16 +1807,41 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +hotkeys-js@^3.11.2: + version "3.13.6" + resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.13.6.tgz#75059d1157b6f6288cd715d0b889e7472c648562" + integrity sha512-Uw8cUXTjYDgnTaUxJTBc8E5etD8bcxjUm6Y/PEB5tBxIZu+dqTXGNQnWV+8yxdOTdlSdXjlqGeOMWu6Sm02CvA== + hyphenate-style-name@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== +idb@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" + integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.2.0: version "5.3.1" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== +immediate@^3.2.3: + version "3.3.0" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" + integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== + +inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + inline-style-prefixer@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-7.0.0.tgz#991d550735d42069f528ac1bcdacd378d1305442" @@ -1147,6 +1859,13 @@ internal-slot@^1.0.5: hasown "^2.0.0" side-channel "^1.0.4" +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" @@ -1256,6 +1975,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -1327,6 +2051,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +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== + iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" @@ -1369,6 +2098,22 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" @@ -1379,6 +2124,23 @@ json5@^1.0.2: object.assign "^4.1.4" object.values "^1.1.6" +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + jwt-decode@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" @@ -1396,6 +2158,95 @@ language-tags@^1.0.9: dependencies: language-subtag-registry "^0.3.20" +level-codec@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" + integrity sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ== + dependencies: + buffer "^5.6.0" + +level-concat-iterator@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" + integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== + +level-errors@^2.0.0, level-errors@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-2.0.1.tgz#2132a677bf4e679ce029f517c2f17432800c05c8" + integrity sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw== + dependencies: + errno "~0.1.1" + +level-iterator-stream@~4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" + integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== + dependencies: + inherits "^2.0.4" + readable-stream "^3.4.0" + xtend "^4.0.2" + +level-js@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/level-js/-/level-js-5.0.2.tgz#5e280b8f93abd9ef3a305b13faf0b5397c969b55" + integrity sha512-SnBIDo2pdO5VXh02ZmtAyPP6/+6YTJg2ibLtl9C34pWvmtMEmRTWpra+qO/hifkUtBTOtfx6S9vLDjBsBK4gRg== + dependencies: + abstract-leveldown "~6.2.3" + buffer "^5.5.0" + inherits "^2.0.3" + ltgt "^2.1.2" + +level-packager@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939" + integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== + dependencies: + encoding-down "^6.3.0" + levelup "^4.3.2" + +level-supports@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" + integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== + dependencies: + xtend "^4.0.2" + +level@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/level/-/level-6.0.1.tgz#dc34c5edb81846a6de5079eac15706334b0d7cd6" + integrity sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw== + dependencies: + level-js "^5.0.0" + level-packager "^5.1.0" + leveldown "^5.4.0" + +leveldown@^5.4.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.6.0.tgz#16ba937bb2991c6094e13ac5a6898ee66d3eee98" + integrity sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ== + dependencies: + abstract-leveldown "~6.2.1" + napi-macros "~2.0.0" + node-gyp-build "~4.1.0" + +levelup@^4.3.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6" + integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== + dependencies: + deferred-leveldown "~5.3.0" + level-errors "~2.0.0" + level-iterator-stream "~4.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +lib0@^0.2.31, lib0@^0.2.43, lib0@^0.2.52, lib0@^0.2.85, lib0@^0.2.86: + version "0.2.88" + resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.88.tgz#18618e0c3b63f6260255eb760f9247d9cc6c6a5b" + integrity sha512-KyroiEvCeZcZEMx5Ys+b4u4eEBbA1ch7XUaBhYpwa/nPMrzTjUhI4RfcytmQfYoTBPcdyx+FX6WFNIoNuJzJfQ== + dependencies: + isomorphic.js "^0.2.4" + lilconfig@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" @@ -1411,7 +2262,62 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -loose-envify@^1.1.0, loose-envify@^1.4.0: +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -1430,6 +2336,16 @@ lru-cache@^6.0.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== +ltgt@^2.1.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" + integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== + +lz-string@^1.4.4: + version "1.5.0" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -1510,11 +2426,21 @@ nano-css@^5.6.1: stacktrace-js "^2.0.2" stylis "^4.3.0" +nanoid@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-4.0.2.tgz#140b3c5003959adbebf521c170f282c5e7f9fb9e" + integrity sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw== + nanoid@^3.3.6, nanoid@^3.3.7: version "3.3.7" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + next@^14.1.0: version "14.1.0" resolved "https://registry.yarnpkg.com/next/-/next-14.1.0.tgz#b31c0261ff9caa6b4a17c5af019ed77387174b69" @@ -1538,6 +2464,11 @@ next@^14.1.0: "@next/swc-win32-ia32-msvc" "14.1.0" "@next/swc-win32-x64-msvc" "14.1.0" +node-gyp-build@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" + integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== + node-releases@^2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" @@ -1742,6 +2673,11 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -1765,6 +2701,34 @@ react-is@^16.13.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-remove-scroll-bar@^2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9" + integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A== + dependencies: + react-style-singleton "^2.2.1" + tslib "^2.0.0" + +react-remove-scroll@2.5.5: + version "2.5.5" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77" + integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw== + dependencies: + react-remove-scroll-bar "^2.3.3" + react-style-singleton "^2.2.1" + tslib "^2.1.0" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" + +react-style-singleton@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4" + integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g== + dependencies: + get-nonce "^1.0.0" + invariant "^2.2.4" + tslib "^2.0.0" + react-universal-interface@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b" @@ -1809,6 +2773,15 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -1899,6 +2872,11 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" +safe-buffer@^5.0.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex-test@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.2.tgz#3ba32bdb3ea35f940ee87e5087c60ee786c3f6c5" @@ -2103,6 +3081,13 @@ string.prototype.trimstart@^1.0.7: define-properties "^1.2.0" es-abstract "^1.22.1" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: name strip-ansi-cjs version "6.0.1" @@ -2242,7 +3227,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.1.0, tslib@^2.4.0: +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -2314,7 +3299,22 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" -util-deprecate@^1.0.2: +use-callback-ref@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.1.tgz#9be64c3902cbd72b07fe55e56408ae3a26036fd0" + integrity sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ== + dependencies: + tslib "^2.0.0" + +use-sidecar@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" + integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -2394,6 +3394,52 @@ wrap-ansi@^8.1.0: string-width "^5.0.1" strip-ansi "^7.0.1" +ws@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== + dependencies: + async-limiter "~1.0.0" + +xtend@^4.0.2, xtend@~4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y-leveldb@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/y-leveldb/-/y-leveldb-0.1.2.tgz#43f6c5004b6891b57926d8a1e0eb0c883003e34b" + integrity sha512-6ulEn5AXfXJYi89rXPEg2mMHAyyw8+ZfeMMdOtBbV8FJpQ1NOrcgi6DTAcXof0dap84NjHPT2+9d0rb6cFsjEg== + dependencies: + level "^6.0.1" + lib0 "^0.2.31" + +y-protocols@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/y-protocols/-/y-protocols-1.0.6.tgz#66dad8a95752623443e8e28c0e923682d2c0d495" + integrity sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q== + dependencies: + lib0 "^0.2.85" + +y-utility@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/y-utility/-/y-utility-0.1.3.tgz#f5c28a86ab7f0cd277d03ffed474c84a71bf302c" + integrity sha512-o9aXG5ZG4c/QgiK1Bt9UDXGVCNwn0dLti/rZSPTsjtuvwH6sshslU2SfoW65pfZqjLJYEHclM/JtUPPjv05lLw== + dependencies: + lib0 "^0.2.43" + +y-websocket@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/y-websocket/-/y-websocket-1.5.3.tgz#1648ae43e820639307237e92f8bde2ac067a41f6" + integrity sha512-wVpKunsDUnVApOymp/ZtaXVyb1Q3csxGdono8Lx6E5k11OfupKUJZV86Eb16mpdUTkEdi7I7L1LVBlZlwd92bA== + dependencies: + lib0 "^0.2.52" + lodash.debounce "^4.0.8" + y-protocols "^1.0.5" + optionalDependencies: + ws "^6.2.1" + y-leveldb "^0.1.0" + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -2404,6 +3450,13 @@ yaml@^2.3.4: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== +yjs@^13.6.11: + version "13.6.11" + resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.6.11.tgz#2edc796981700576abd577bc1f6a25edbb2f08f8" + integrity sha512-FvRRJKX9u270dOLkllGF/UDCWwmIv2Z+ucM4v1QO1TuxdmoiMnSUXH1HAcOKOrkBEhQtPTkxep7tD2DrQB+l0g== + dependencies: + lib0 "^0.2.86" + zustand@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.2.tgz#7b44c4f4a5bfd7a8296a3957b13e1c346f42514d" diff --git a/web/yjs/callback.cjs b/web/yjs/callback.cjs new file mode 100644 index 0000000..9b9226f --- /dev/null +++ b/web/yjs/callback.cjs @@ -0,0 +1,76 @@ +const http = require('http') + +const CALLBACK_URL = process.env.CALLBACK_URL ? new URL(process.env.CALLBACK_URL) : null +const CALLBACK_TIMEOUT = process.env.CALLBACK_TIMEOUT || 5000 +const CALLBACK_OBJECTS = process.env.CALLBACK_OBJECTS ? JSON.parse(process.env.CALLBACK_OBJECTS) : {} + +exports.isCallbackSet = !!CALLBACK_URL + +/** + * @param {Uint8Array} update + * @param {any} origin + * @param {WSSharedDoc} doc + */ +exports.callbackHandler = (update, origin, doc) => { + const room = doc.name + const dataToSend = { + room, + data: {} + } + const sharedObjectList = Object.keys(CALLBACK_OBJECTS) + sharedObjectList.forEach(sharedObjectName => { + const sharedObjectType = CALLBACK_OBJECTS[sharedObjectName] + dataToSend.data[sharedObjectName] = { + type: sharedObjectType, + content: getContent(sharedObjectName, sharedObjectType, doc).toJSON() + } + }) + callbackRequest(CALLBACK_URL, CALLBACK_TIMEOUT, dataToSend) +} + +/** + * @param {URL} url + * @param {number} timeout + * @param {Object} data + */ +const callbackRequest = (url, timeout, data) => { + data = JSON.stringify(data) + const options = { + hostname: url.hostname, + port: url.port, + path: url.pathname, + timeout, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': data.length + } + } + const req = http.request(options) + req.on('timeout', () => { + console.warn('Callback request timed out.') + req.abort() + }) + req.on('error', (e) => { + console.error('Callback request error.', e) + req.abort() + }) + req.write(data) + req.end() +} + +/** + * @param {string} objName + * @param {string} objType + * @param {WSSharedDoc} doc + */ +const getContent = (objName, objType, doc) => { + switch (objType) { + case 'Array': return doc.getArray(objName) + case 'Map': return doc.getMap(objName) + case 'Text': return doc.getText(objName) + case 'XmlFragment': return doc.getXmlFragment(objName) + case 'XmlElement': return doc.getXmlElement(objName) + default : return {} + } +} \ No newline at end of file diff --git a/web/yjs/server.js b/web/yjs/server.js new file mode 100755 index 0000000..d30a99c --- /dev/null +++ b/web/yjs/server.js @@ -0,0 +1,86 @@ +#!/usr/bin/env node + +import http from 'http'; +import josnwebtoken from 'jsonwebtoken'; +import WebSocket from 'ws'; +import { setupWSConnection } from './util.cjs'; + +// max payload size is 512MB +const wss = new WebSocket.Server({ noServer: true, maxPayload: 1024 * 1024 * 512}); + +const host = process.env.HOST ?? '127.0.0.1' +const port = process.env.PORT ?? 1234 +const jwtKey = parseEnv(process.env.SECRET ?? '') + +const server = http.createServer((request, response) => { + response.writeHead(200, { 'Content-Type': 'text/plain' }) + response.end('okay') +}) + +wss.on('connection', setupWSConnection) + +server.on('upgrade', (request, socket, head) => { + // You may check auth of request here.. + // See https://github.com/websockets/ws#client-authentication + /** + * @param {any} ws + */ + const handleAuth = ws => { + try { + // // parse cookie 'scToken' + // const cookies = parseCookie(request.headers.cookie); + // if (!cookies.scToken) { + // throw new Error('No cookie') + // } + + // try { + // const payload = josnwebtoken.verify(cookies.scToken, jwtKey); + + // // if user == managing etc.. + + // console.log('JWT Payload', payload); + // } catch (e) { + // throw new Error('invalid scToken') + // } + + wss.emit('connection', ws, request) + } catch (e) { + console.error(e.message); + ws.close(1008, 'Not authorized') + } + } + try { + wss.handleUpgrade(request, socket, head, handleAuth) + } catch (e) { + console.error(e.message); + socket.close() + } +}) + +server.listen(port, host, () => { + console.log(`running at '${host}' on port ${port}`) +}) + +export function parseCookie(str) { + if (!str || str.trim() === '') { + return {}; + } + + return str + .split(';') + .map(v => v.split('=')) + .reduce((acc, v) => { + acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim()); + return acc; + }, {}); +} + +function parseEnv(str) { + if (typeof str !== 'string') { + return ''; + } + if (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"') { + return str.substr(1, str.length - 2); + } + return str; +} \ No newline at end of file diff --git a/web/yjs/util.cjs b/web/yjs/util.cjs new file mode 100644 index 0000000..007e5c6 --- /dev/null +++ b/web/yjs/util.cjs @@ -0,0 +1,286 @@ +const Y = require('yjs') +const syncProtocol = require('y-protocols/dist/sync.cjs') +const awarenessProtocol = require('y-protocols/dist/awareness.cjs') + +const encoding = require('lib0/dist/encoding.cjs') +const decoding = require('lib0/dist/decoding.cjs') +const map = require('lib0/dist/map.cjs') + +const debounce = require('lodash.debounce') + +const callbackHandler = require('./callback.cjs').callbackHandler +const isCallbackSet = require('./callback.cjs').isCallbackSet + +const CALLBACK_DEBOUNCE_WAIT = parseInt(process.env.CALLBACK_DEBOUNCE_WAIT) || 2000 +const CALLBACK_DEBOUNCE_MAXWAIT = parseInt(process.env.CALLBACK_DEBOUNCE_MAXWAIT) || 10000 + +const wsReadyStateConnecting = 0 +const wsReadyStateOpen = 1 +const wsReadyStateClosing = 2 // eslint-disable-line +const wsReadyStateClosed = 3 // eslint-disable-line + +// disable gc when using snapshots! +const gcEnabled = process.env.GC !== 'false' && process.env.GC !== '0' +const persistenceDir = process.env.YPERSISTENCE +/** + * @type {{bindState: function(string,WSSharedDoc):void, writeState:function(string,WSSharedDoc):Promise, provider: any}|null} + */ +let persistence = null +if (typeof persistenceDir === 'string') { + console.info('Persisting documents to "' + persistenceDir + '"') + // @ts-ignore + const LeveldbPersistence = require('y-leveldb').LeveldbPersistence + const ldb = new LeveldbPersistence(persistenceDir) + persistence = { + provider: ldb, + bindState: async (docName, ydoc) => { + const persistedYdoc = await ldb.getYDoc(docName) + const newUpdates = Y.encodeStateAsUpdate(ydoc) + ldb.storeUpdate(docName, newUpdates) + Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(persistedYdoc)) + ydoc.on('update', update => { + ldb.storeUpdate(docName, update) + }) + }, + writeState: async (docName, ydoc) => {} + } +} + +/** + * @param {{bindState: function(string,WSSharedDoc):void, + * writeState:function(string,WSSharedDoc):Promise,provider:any}|null} persistence_ + */ +exports.setPersistence = persistence_ => { + persistence = persistence_ +} + +/** + * @return {null|{bindState: function(string,WSSharedDoc):void, + * writeState:function(string,WSSharedDoc):Promise}|null} used persistence layer + */ +exports.getPersistence = () => persistence + +/** + * @type {Map} + */ +const docs = new Map() +// exporting docs so that others can use it +exports.docs = docs + +const messageSync = 0 +const messageAwareness = 1 +// const messageAuth = 2 + +/** + * @param {Uint8Array} update + * @param {any} origin + * @param {WSSharedDoc} doc + */ +const updateHandler = (update, origin, doc) => { + const encoder = encoding.createEncoder() + encoding.writeVarUint(encoder, messageSync) + syncProtocol.writeUpdate(encoder, update) + const message = encoding.toUint8Array(encoder) + doc.conns.forEach((_, conn) => send(doc, conn, message)) +} + +class WSSharedDoc extends Y.Doc { + /** + * @param {string} name + */ + constructor (name) { + super({ gc: gcEnabled }) + this.name = name + /** + * Maps from conn to set of controlled user ids. Delete all user ids from awareness when this conn is closed + * @type {Map>} + */ + this.conns = new Map() + /** + * @type {awarenessProtocol.Awareness} + */ + this.awareness = new awarenessProtocol.Awareness(this) + this.awareness.setLocalState(null) + /** + * @param {{ added: Array, updated: Array, removed: Array }} changes + * @param {Object | null} conn Origin is the connection that made the change + */ + const awarenessChangeHandler = ({ added, updated, removed }, conn) => { + const changedClients = added.concat(updated, removed) + if (conn !== null) { + const connControlledIDs = /** @type {Set} */ (this.conns.get(conn)) + if (connControlledIDs !== undefined) { + added.forEach(clientID => { connControlledIDs.add(clientID) }) + removed.forEach(clientID => { connControlledIDs.delete(clientID) }) + } + } + // broadcast awareness update + const encoder = encoding.createEncoder() + encoding.writeVarUint(encoder, messageAwareness) + encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this.awareness, changedClients)) + const buff = encoding.toUint8Array(encoder) + this.conns.forEach((_, c) => { + send(this, c, buff) + }) + } + this.awareness.on('update', awarenessChangeHandler) + this.on('update', updateHandler) + if (isCallbackSet) { + this.on('update', debounce( + callbackHandler, + CALLBACK_DEBOUNCE_WAIT, + { maxWait: CALLBACK_DEBOUNCE_MAXWAIT } + )) + } + } +} + +/** + * Gets a Y.Doc by name, whether in memory or on disk + * + * @param {string} docname - the name of the Y.Doc to find or create + * @param {boolean} gc - whether to allow gc on the doc (applies only when created) + * @return {WSSharedDoc} + */ +const getYDoc = (docname, gc = true) => map.setIfUndefined(docs, docname, () => { + const doc = new WSSharedDoc(docname) + doc.gc = gc + if (persistence !== null) { + persistence.bindState(docname, doc) + } + docs.set(docname, doc) + return doc +}) + +exports.getYDoc = getYDoc + +/** + * @param {any} conn + * @param {WSSharedDoc} doc + * @param {Uint8Array} message + */ +const messageListener = (conn, doc, message) => { + try { + const encoder = encoding.createEncoder() + const decoder = decoding.createDecoder(message) + const messageType = decoding.readVarUint(decoder) + switch (messageType) { + case messageSync: + encoding.writeVarUint(encoder, messageSync) + syncProtocol.readSyncMessage(decoder, encoder, doc, conn) + + // If the `encoder` only contains the type of reply message and no + // message, there is no need to send the message. When `encoder` only + // contains the type of reply, its length is 1. + if (encoding.length(encoder) > 1) { + send(doc, conn, encoding.toUint8Array(encoder)) + } + break + case messageAwareness: { + awarenessProtocol.applyAwarenessUpdate(doc.awareness, decoding.readVarUint8Array(decoder), conn) + break + } + } + } catch (err) { + console.error(err) + doc.emit('error', [err]) + } +} + +/** + * @param {WSSharedDoc} doc + * @param {any} conn + */ +const closeConn = (doc, conn) => { + if (doc.conns.has(conn)) { + /** + * @type {Set} + */ + // @ts-ignore + const controlledIds = doc.conns.get(conn) + doc.conns.delete(conn) + awarenessProtocol.removeAwarenessStates(doc.awareness, Array.from(controlledIds), null) + if (doc.conns.size === 0 && persistence !== null) { + // if persisted, we store state and destroy ydocument + persistence.writeState(doc.name, doc).then(() => { + doc.destroy() + }) + docs.delete(doc.name) + } + } + conn.close() +} + +/** + * @param {WSSharedDoc} doc + * @param {any} conn + * @param {Uint8Array} m + */ +const send = (doc, conn, m) => { + if (conn.readyState !== wsReadyStateConnecting && conn.readyState !== wsReadyStateOpen) { + closeConn(doc, conn) + } + try { + conn.send(m, /** @param {any} err */ err => { err != null && closeConn(doc, conn) }) + } catch (e) { + closeConn(doc, conn) + } +} + +const pingTimeout = 30000 + +/** + * @param {any} conn + * @param {any} req + * @param {any} opts + */ +exports.setupWSConnection = (conn, req, { docName = req.url.slice(1).split('?')[0], gc = true } = {}) => { + conn.binaryType = 'arraybuffer' + // get doc, initialize if it does not exist yet + const doc = getYDoc(docName, gc) + doc.conns.set(conn, new Set()) + // listen and reply to events + conn.on('message', /** @param {ArrayBuffer} message */ message => messageListener(conn, doc, new Uint8Array(message))) + + // Check if connection is still alive + let pongReceived = true + const pingInterval = setInterval(() => { + if (!pongReceived) { + if (doc.conns.has(conn)) { + closeConn(doc, conn) + } + clearInterval(pingInterval) + } else if (doc.conns.has(conn)) { + pongReceived = false + try { + conn.ping() + } catch (e) { + closeConn(doc, conn) + clearInterval(pingInterval) + } + } + }, pingTimeout) + conn.on('close', () => { + closeConn(doc, conn) + clearInterval(pingInterval) + }) + conn.on('pong', () => { + pongReceived = true + }) + // put the following in a variables in a block so the interval handlers don't keep in in + // scope + { + // send sync step 1 + const encoder = encoding.createEncoder() + encoding.writeVarUint(encoder, messageSync) + syncProtocol.writeSyncStep1(encoder, doc) + send(doc, conn, encoding.toUint8Array(encoder)) + const awarenessStates = doc.awareness.getStates() + if (awarenessStates.size > 0) { + const encoder = encoding.createEncoder() + encoding.writeVarUint(encoder, messageAwareness) + encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(doc.awareness, Array.from(awarenessStates.keys()))) + send(doc, conn, encoding.toUint8Array(encoder)) + } + } +} \ No newline at end of file From 7edb7616bd9a610102d742c603cabd354e836942 Mon Sep 17 00:00:00 2001 From: gempir Date: Mon, 12 Feb 2024 21:17:57 +0100 Subject: [PATCH 02/14] cursed contraption to make tokens --- .gitignore | 3 +- Makefile | 3 + go.mod | 10 +- go.sum | 164 +----------- internal/ysweet/factory.go | 54 ++++ main.go | 10 +- web/createYsweetToken.cjs | 11 + web/package.json | 7 +- web/src/hooks/useYjsStore.ts | 468 +++++++++++++++++------------------ web/yarn.lock | 180 ++++++++++++++ 10 files changed, 496 insertions(+), 414 deletions(-) create mode 100644 internal/ysweet/factory.go create mode 100644 web/createYsweetToken.cjs diff --git a/.gitignore b/.gitignore index 381a8fb..f30d6fd 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,5 @@ web/dbdir # Binaries /main -/gempbot \ No newline at end of file +/gempbot +/internal/ysweet/createToken.cjs \ No newline at end of file diff --git a/Makefile b/Makefile index 32f91c4..1acc7a4 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,9 @@ build_server: yjs_server: cd web && yarn yjs +ysweet_token: + cd web && yarn build-ysweet-token + test: go test ./internal/... diff --git a/go.mod b/go.mod index 77e5ab6..ecf5c2d 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.1 github.com/nicklaw5/helix/v2 v2.26.0 - github.com/puzpuzpuz/xsync v1.5.2 github.com/rs/cors v1.10.1 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 @@ -18,25 +17,20 @@ require ( gorm.io/gorm v1.25.7 ) +require github.com/rogpeppe/go-internal v1.12.0 // indirect + replace github.com/nicklaw5/helix/v2 v2.12.0 => github.com/gempir/helix/v2 v2.0.2-0.20221223221449-fe5671ac8ea7 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.1 // indirect - github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.2 // indirect github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect - github.com/jackc/pgtype v1.14.2 // indirect - github.com/jackc/pgx/v4 v4.18.1 // indirect github.com/jackc/pgx/v5 v5.4.3 // indirect github.com/jellydator/ttlcache/v2 v2.11.1 github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/objx v0.5.0 // indirect golang.org/x/crypto v0.19.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/sync v0.6.0 // indirect diff --git a/go.sum b/go.sum index 8d4d477..01823e8 100644 --- a/go.sum +++ b/go.sum @@ -1,247 +1,100 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/carlmjohnson/requests v0.23.5 h1:NPANcAofwwSuC6SIMwlgmHry2V3pLrSqRiSBKYbNHHA= github.com/carlmjohnson/requests v0.23.5/go.mod h1:zG9P28thdRnN61aD7iECFhH5iGGKX2jIjKQD9kqYH+o= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gempir/go-twitch-irc/v4 v4.0.0 h1:sHVIvbWOv9nHXGEErilclxASv0AaQEr/r/f9C0B9aO8= github.com/gempir/go-twitch-irc/v4 v4.0.0/go.mod h1:QsOMMAk470uxQ7EYD9GJBGAVqM/jDrXBNbuePfTauzg= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= -github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= -github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgtype v1.14.2 h1:QBdZQTKpPdBlw2AdKwHEyqUcm/lrl2cwWAHjCMyln/o= -github.com/jackc/pgtype v1.14.2/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= -github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jellydator/ttlcache/v2 v2.11.1 h1:AZGME43Eh2Vv3giG6GeqeLeFXxwxn1/qHItqWZl6U64= github.com/jellydator/ttlcache/v2 v2.11.1/go.mod h1:RtE5Snf0/57e+2cLWFYWCCsLas2Hy3c5Z4n14XmSvTI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/nicklaw5/helix/v2 v2.26.0 h1:Qkc/R0eCDdWtUmnczk2g03+mObPUfc49Kz2Bt4B5d0g= github.com/nicklaw5/helix/v2 v2.26.0/go.mod h1:zZcKsyyBWDli34x3QleYsVMiiNGMXPAEU5NjsiZDtvY= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/puzpuzpuz/xsync v1.5.2 h1:yRAP4wqSOZG+/4pxJ08fPTwrfL0IzE/LKQ/cw509qGY= -github.com/puzpuzpuz/xsync v1.5.2/go.mod h1:K98BYhX3k1dQ2M63t1YNVDanbwUPmBCAhNmVrrxfiGg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 h1:xzABM9let0HLLqFypcxvLmlvEciCHL7+Lv+4vwZqecI= github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569/go.mod h1:2Ly+NIftZN4de9zRmENdYbvPQeaVIYKWpLFStLFEBgI= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -250,4 +103,3 @@ gorm.io/driver/postgres v1.5.6 h1:ydr9xEd5YAM0vxVDY0X139dyzNz10spDiDlC7+ibLeU= gorm.io/driver/postgres v1.5.6/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/internal/ysweet/factory.go b/internal/ysweet/factory.go new file mode 100644 index 0000000..506cc8e --- /dev/null +++ b/internal/ysweet/factory.go @@ -0,0 +1,54 @@ +package ysweet + +import ( + "bytes" + _ "embed" + "encoding/json" + "fmt" + "os/exec" +) + +//go:embed createToken.cjs +var createToken string + +type Factory struct { + ysweetUrl string +} + +func NewFactory(ysweetUrl string) *Factory { + return &Factory{ + ysweetUrl: ysweetUrl, + } +} + +type TokenResponse struct { + Url string `json:"url"` + DocId string `json:"docId"` + Token string `json:"token"` +} + +func (f *Factory) CreateToken(docID string) (TokenResponse, error) { + cmd := exec.Command("node", "-", "") + cmd.Env = append(cmd.Env, "YSWEET_URL="+f.ysweetUrl) + cmd.Env = append(cmd.Env, "YSWEET_DOC_ID=1"+docID) + + cmd.Stdin = bytes.NewBufferString(createToken) + + var out bytes.Buffer + var errOut bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &errOut + + err := cmd.Run() + if err != nil { + return TokenResponse{}, fmt.Errorf("%s %w", errOut.String(), err) + } + + var tokenResponse TokenResponse + err = json.Unmarshal(out.Bytes(), &tokenResponse) + if err != nil { + return TokenResponse{}, fmt.Errorf("%s %w", out.String(), err) + } + + return tokenResponse, nil +} diff --git a/main.go b/main.go index cd9c52b..43d7120 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ import ( "github.com/gempir/gempbot/internal/store" "github.com/gempir/gempbot/internal/user" "github.com/gempir/gempbot/internal/ws" + "github.com/gempir/gempbot/internal/ysweet" "github.com/rs/cors" ) @@ -71,6 +72,13 @@ func main() { mux.HandleFunc("/api/overlay", apiHandlers.OverlayHandler) mux.HandleFunc("/api/ws", wsHandler.HandleWs) + tokenFactory := ysweet.NewFactory("xdd") + str, err := tokenFactory.CreateToken("doc") + if err != nil { + log.Error(err) + } + log.Warn(str) + handler := cors.New(cors.Options{ AllowedOrigins: []string{cfg.WebBaseUrl}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "PATCH"}, @@ -79,7 +87,7 @@ func main() { }).Handler(mux) log.Info("Starting server on " + cfg.ListenAddress) - err := http.ListenAndServe(cfg.ListenAddress, handler) + err = http.ListenAndServe(cfg.ListenAddress, handler) if err != nil { log.Fatal(err) } diff --git a/web/createYsweetToken.cjs b/web/createYsweetToken.cjs new file mode 100644 index 0000000..a34794d --- /dev/null +++ b/web/createYsweetToken.cjs @@ -0,0 +1,11 @@ +import { DocumentManager } from '@y-sweet/sdk'; + +const manager = new DocumentManager(process.env.YSWEET_URL); + +async function main() { + const clientToken = await manager.getOrCreateDocAndToken(process.env.YSWEET_DOC_ID) + + console.log(JSON.stringify(clientToken)); +} + +main(); diff --git a/web/package.json b/web/package.json index 52acb06..8b491f7 100644 --- a/web/package.json +++ b/web/package.json @@ -4,7 +4,8 @@ "dev": "next dev", "build": "next build", "start": "next start", - "yjs": "node yjs/server.js" + "yjs": "node yjs/server.js", + "build-ysweet-token": "esbuild createYsweetToken.cjs --bundle --outfile=../internal/ysweet/createToken.cjs --platform=node --target=node20" }, "type": "module", "dependencies": { @@ -12,6 +13,8 @@ "@tailwindcss/forms": "^0.5.7", "@tldraw/tldraw": "^2.0.0-beta.2", "@types/seedrandom": "^3.0.4", + "@y-sweet/react": "^0.1.0", + "@y-sweet/sdk": "^0.1.0", "dayjs": "^1.11.7", "eslint-config-next": "^14.1.0", "jsonwebtoken": "^9.0.2", @@ -24,6 +27,7 @@ "react-use-websocket": "^4.5.0", "seedrandom": "^3.0.5", "tailwindcss": "^3.4.1", + "y-sweet": "^0.1.0", "y-utility": "^0.1.3", "y-websocket": "^1.5.3", "yjs": "^13.6.11", @@ -33,6 +37,7 @@ "@types/node": "^20.11.16", "@types/react": "^18.2.52", "autoprefixer": "^10.4.17", + "esbuild": "^0.20.0", "postcss": "^8.4.33", "typescript": "^5.3.3" } diff --git a/web/src/hooks/useYjsStore.ts b/web/src/hooks/useYjsStore.ts index 0d3531f..c8253e2 100644 --- a/web/src/hooks/useYjsStore.ts +++ b/web/src/hooks/useYjsStore.ts @@ -1,6 +1,7 @@ +/** Based on: https://github.com/tldraw/tldraw-yjs-example/blob/main/src/useYjsStore.ts */ + import { InstancePresenceRecordType, - TLAnyShapeUtilConstructor, TLInstancePresence, TLRecord, TLStoreWithStatus, @@ -13,266 +14,239 @@ import { setUserPreferences, react, transact, -} from '@tldraw/tldraw' -import { useEffect, useMemo, useState } from 'react' -import { YKeyValue } from 'y-utility/y-keyvalue' -import { WebsocketProvider } from 'y-websocket' -import * as Y from 'yjs' -import { DEFAULT_STORE } from './default_store' - -export function useYjsStore({ - roomId = 'example', - hostUrl, - shapeUtils = [], -}: Partial<{ - hostUrl: string - roomId: string - version: number - shapeUtils: TLAnyShapeUtilConstructor[] -}>) { + } from '@tldraw/tldraw' + import { useEffect, useMemo, useState } from 'react' + import { YKeyValue } from 'y-utility/y-keyvalue' + import * as Y from 'yjs' + import { DEFAULT_STORE } from './default_store' + import { useYDoc, useYjsProvider } from '@y-sweet/react' + + export function useYjsStore() { const [store] = useState(() => { - const store = createTLStore({ - shapeUtils: [...defaultShapeUtils, ...shapeUtils], - }) - store.loadSnapshot(DEFAULT_STORE) - return store + const store = createTLStore({ + shapeUtils: defaultShapeUtils, + }) + store.loadSnapshot(DEFAULT_STORE) + return store }) - + const [storeWithStatus, setStoreWithStatus] = useState({ - status: 'loading', + status: 'loading', }) - - const { yDoc, yStore, room } = useMemo(() => { - const yDoc = new Y.Doc({ gc: true }) - const yArr = yDoc.getArray<{ key: string; val: TLRecord }>(`tl_${roomId}`) - const yStore = new YKeyValue(yArr) - - return { - yDoc, - yStore, - room: new WebsocketProvider(String(hostUrl), roomId, yDoc, { connect: true }), - } - }, [hostUrl, roomId]) - + + const yDoc = useYDoc() + const room = useYjsProvider() + + const yStore = useMemo(() => { + const yArr = yDoc.getArray<{ key: string; val: TLRecord }>(`tl_room`) + const yStore = new YKeyValue(yArr) + + return yStore + }, [yDoc]) + useEffect(() => { - setStoreWithStatus({ status: 'loading' }) - - const unsubs: (() => void)[] = [] - - function handleSync() { - // 1. - // Connect store to yjs store and vis versa, for both the document and awareness - - /* -------------------- Document -------------------- */ - - // Sync store changes to the yjs doc - unsubs.push( - store.listen( - function syncStoreChangesToYjsDoc({ changes }) { - yDoc.transact(() => { - Object.values(changes.added).forEach((record) => { - yStore.set(record.id, record) - }) - - Object.values(changes.updated).forEach(([_, record]) => { - yStore.set(record.id, record) - }) - - Object.values(changes.removed).forEach((record) => { - yStore.delete(record.id) - }) - }) - }, - { source: 'user', scope: 'document' } // only sync user's document changes - ) - ) - - // Sync the yjs doc changes to the store - const handleChange = ( - changes: Map< - string, - | { action: 'delete'; oldValue: TLRecord } - | { action: 'update'; oldValue: TLRecord; newValue: TLRecord } - | { action: 'add'; newValue: TLRecord } - >, - transaction: Y.Transaction - ) => { - if (transaction.local) return - - const toRemove: TLRecord['id'][] = [] - const toPut: TLRecord[] = [] - - changes.forEach((change, id) => { - switch (change.action) { - case 'add': - case 'update': { - const record = yStore.get(id)! - toPut.push(record) - break - } - case 'delete': { - toRemove.push(id as TLRecord['id']) - break - } - } + setStoreWithStatus({ status: 'loading' }) + + const unsubs: (() => void)[] = [] + + function handleSync() { + // 1. + // Connect store to yjs store and vis versa, for both the document and awareness + + /* -------------------- Document -------------------- */ + + // Sync store changes to the yjs doc + unsubs.push( + store.listen( + function syncStoreChangesToYjsDoc({ changes }) { + yDoc.transact(() => { + Object.values(changes.added).forEach((record) => { + yStore.set(record.id, record) }) - - // put / remove the records in the store - store.mergeRemoteChanges(() => { - if (toRemove.length) store.remove(toRemove) - if (toPut.length) store.put(toPut) + + Object.values(changes.updated).forEach(([_, record]) => { + yStore.set(record.id, record) }) + + Object.values(changes.removed).forEach((record) => { + yStore.delete(record.id) + }) + }) + }, + { source: 'user', scope: 'document' }, // only sync user's document changes + ), + ) + + // Sync the yjs doc changes to the store + const handleChange = ( + changes: Map< + string, + | { action: 'delete'; oldValue: TLRecord } + | { action: 'update'; oldValue: TLRecord; newValue: TLRecord } + | { action: 'add'; newValue: TLRecord } + >, + transaction: Y.Transaction, + ) => { + if (transaction.local) return + + const toRemove: TLRecord['id'][] = [] + const toPut: TLRecord[] = [] + + changes.forEach((change, id) => { + switch (change.action) { + case 'add': + case 'update': { + const record = yStore.get(id)! + toPut.push(record) + break + } + case 'delete': { + toRemove.push(id as TLRecord['id']) + break + } } - - yStore.on('change', handleChange) - unsubs.push(() => yStore.off('change', handleChange)) - - /* -------------------- Awareness ------------------- */ - - const yClientId = room.awareness.clientID.toString() - setUserPreferences({ id: yClientId }) - - const userPreferences = computed<{ - id: string - color: string - name: string - }>('userPreferences', () => { - const user = getUserPreferences() - return { - id: user.id, - color: user.color ?? defaultUserPreferences.color, - name: user.name ?? defaultUserPreferences.name, - } + }) + + // put / remove the records in the store + store.mergeRemoteChanges(() => { + if (toRemove.length) store.remove(toRemove) + if (toPut.length) store.put(toPut) + }) + } + + yStore.on('change', handleChange) + unsubs.push(() => yStore.off('change', handleChange)) + + /* -------------------- Awareness ------------------- */ + + const yClientId = room.awareness.clientID.toString() + setUserPreferences({ id: yClientId }) + + const userPreferences = computed<{ + id: string + color: string + name: string + }>('userPreferences', () => { + const user = getUserPreferences() + return { + id: user.id, + color: user.color ?? defaultUserPreferences.color, + name: user.name ?? defaultUserPreferences.name, + } + }) + + // Create the instance presence derivation + const presenceId = InstancePresenceRecordType.createId(yClientId) + const presenceDerivation = createPresenceStateDerivation(userPreferences, presenceId)(store) + + // Set our initial presence from the derivation's current value + room.awareness.setLocalStateField('presence', presenceDerivation.value) + + // When the derivation change, sync presence to to yjs awareness + unsubs.push( + react('when presence changes', () => { + const presence = presenceDerivation.value + requestAnimationFrame(() => { + room.awareness.setLocalStateField('presence', presence) }) - - // Create the instance presence derivation - const presenceId = InstancePresenceRecordType.createId(yClientId) - const presenceDerivation = - createPresenceStateDerivation(userPreferences, presenceId)(store) - - // Set our initial presence from the derivation's current value - // @ts-expect-error - room.awareness.setLocalStateField('presence', presenceDerivation.value) - - // When the derivation change, sync presence to to yjs awareness - unsubs.push( - react('when presence changes', () => { - // @ts-expect-error - const presence = presenceDerivation.value - requestAnimationFrame(() => { - room.awareness.setLocalStateField('presence', presence) - }) - }) - ) - - // Sync yjs awareness changes to the store - const handleUpdate = (update: { - added: number[] - updated: number[] - removed: number[] - }) => { - const states = room.awareness.getStates() as Map< - number, - { presence: TLInstancePresence } - > - - const toRemove: TLInstancePresence['id'][] = [] - const toPut: TLInstancePresence[] = [] - - // Connect records to put / remove - for (const clientId of update.added) { - const state = states.get(clientId) - if (state?.presence && state.presence.id !== presenceId) { - toPut.push(state.presence) - } - } - - for (const clientId of update.updated) { - const state = states.get(clientId) - if (state?.presence && state.presence.id !== presenceId) { - toPut.push(state.presence) - } - } - - for (const clientId of update.removed) { - toRemove.push( - InstancePresenceRecordType.createId(clientId.toString()) - ) - } - - // put / remove the records in the store - store.mergeRemoteChanges(() => { - if (toRemove.length) store.remove(toRemove) - if (toPut.length) store.put(toPut) - }) + }), + ) + + // Sync yjs awareness changes to the store + const handleUpdate = (update: { added: number[]; updated: number[]; removed: number[] }) => { + const states = room.awareness.getStates() as Map + + const toRemove: TLInstancePresence['id'][] = [] + const toPut: TLInstancePresence[] = [] + + // Connect records to put / remove + for (const clientId of update.added) { + const state = states.get(clientId) + if (state?.presence && state.presence.id !== presenceId) { + toPut.push(state.presence) } - - room.awareness.on('update', handleUpdate) - unsubs.push(() => room.awareness.off('update', handleUpdate)) - - // 2. - // Initialize the store with the yjs doc records—or, if the yjs doc - // is empty, initialize the yjs doc with the default store records. - if (yStore.yarray.length) { - // Replace the store records with the yjs doc records - transact(() => { - // The records here should be compatible with what's in the store - store.clear() - const records = yStore.yarray.toJSON().map(({ val }) => val) - store.put(records) - }) - } else { - // Create the initial store records - // Sync the store records to the yjs doc - yDoc.transact(() => { - for (const record of store.allRecords()) { - yStore.set(record.id, record) - } - }) + } + + for (const clientId of update.updated) { + const state = states.get(clientId) + if (state?.presence && state.presence.id !== presenceId) { + toPut.push(state.presence) } - - setStoreWithStatus({ - store, - status: 'synced-remote', - connectionStatus: 'online', - }) + } + + for (const clientId of update.removed) { + toRemove.push(InstancePresenceRecordType.createId(clientId.toString())) + } + + // put / remove the records in the store + store.mergeRemoteChanges(() => { + if (toRemove.length) store.remove(toRemove) + if (toPut.length) store.put(toPut) + }) } - - let hasConnectedBefore = false - - function handleStatusChange({ - status, - }: { - status: 'disconnected' | 'connected' - }) { - // If we're disconnected, set the store status to 'synced-remote' and the connection status to 'offline' - if (status === 'disconnected') { - setStoreWithStatus({ - store, - status: 'synced-remote', - connectionStatus: 'offline', - }) - return - } - - room.off('synced', handleSync) - - if (status === 'connected') { - if (hasConnectedBefore) return - hasConnectedBefore = true - room.on('synced', handleSync) - unsubs.push(() => room.off('synced', handleSync)) + + room.awareness.on('update', handleUpdate) + unsubs.push(() => room.awareness.off('update', handleUpdate)) + + // 2. + // Initialize the store with the yjs doc records—or, if the yjs doc + // is empty, initialize the yjs doc with the default store records. + if (yStore.yarray.length) { + // Replace the store records with the yjs doc records + transact(() => { + // The records here should be compatible with what's in the store + store.clear() + const records = yStore.yarray.toJSON().map(({ val }) => val) + store.put(records) + }) + } else { + // Create the initial store records + // Sync the store records to the yjs doc + yDoc.transact(() => { + for (const record of store.allRecords()) { + yStore.set(record.id, record) } + }) } - - room.on('status', handleStatusChange) - unsubs.push(() => room.off('status', handleStatusChange)) - - return () => { - unsubs.forEach((fn) => fn()) - unsubs.length = 0 + + setStoreWithStatus({ + store, + status: 'synced-remote', + connectionStatus: 'online', + }) + } + + let hasConnectedBefore = false + + function handleStatusChange({ status }: { status: 'disconnected' | 'connected' }) { + // If we're disconnected, set the store status to 'synced-remote' and the connection status to 'offline' + if (status === 'disconnected') { + setStoreWithStatus({ + store, + status: 'synced-remote', + connectionStatus: 'offline', + }) + return + } + + room.off('synced', handleSync) + + if (status === 'connected') { + if (hasConnectedBefore) return + hasConnectedBefore = true + room.on('synced', handleSync) + unsubs.push(() => room.off('synced', handleSync)) } + } + + room.on('status', handleStatusChange) + unsubs.push(() => room.off('status', handleStatusChange)) + + return () => { + unsubs.forEach((fn) => fn()) + unsubs.length = 0 + } }, [room, yDoc, store, yStore]) - + return storeWithStatus -} \ No newline at end of file + } \ No newline at end of file diff --git a/web/yarn.lock b/web/yarn.lock index bbe6ccc..35c6b5f 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -14,6 +14,121 @@ dependencies: regenerator-runtime "^0.14.0" +"@esbuild/aix-ppc64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.0.tgz#509621cca4e67caf0d18561a0c56f8b70237472f" + integrity sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw== + +"@esbuild/android-arm64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.0.tgz#109a6fdc4a2783fc26193d2687827045d8fef5ab" + integrity sha512-aVpnM4lURNkp0D3qPoAzSG92VXStYmoVPOgXveAUoQBWRSuQzt51yvSju29J6AHPmwY1BjH49uR29oyfH1ra8Q== + +"@esbuild/android-arm@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.0.tgz#1397a2c54c476c4799f9b9073550ede496c94ba5" + integrity sha512-3bMAfInvByLHfJwYPJRlpTeaQA75n8C/QKpEaiS4HrFWFiJlNI0vzq/zCjBrhAYcPyVPG7Eo9dMrcQXuqmNk5g== + +"@esbuild/android-x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.0.tgz#2b615abefb50dc0a70ac313971102f4ce2fdb3ca" + integrity sha512-uK7wAnlRvjkCPzh8jJ+QejFyrP8ObKuR5cBIsQZ+qbMunwR8sbd8krmMbxTLSrDhiPZaJYKQAU5Y3iMDcZPhyQ== + +"@esbuild/darwin-arm64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.0.tgz#5c122ed799eb0c35b9d571097f77254964c276a2" + integrity sha512-AjEcivGAlPs3UAcJedMa9qYg9eSfU6FnGHJjT8s346HSKkrcWlYezGE8VaO2xKfvvlZkgAhyvl06OJOxiMgOYQ== + +"@esbuild/darwin-x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.0.tgz#9561d277002ba8caf1524f209de2b22e93d170c1" + integrity sha512-bsgTPoyYDnPv8ER0HqnJggXK6RyFy4PH4rtsId0V7Efa90u2+EifxytE9pZnsDgExgkARy24WUQGv9irVbTvIw== + +"@esbuild/freebsd-arm64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.0.tgz#84178986a3138e8500d17cc380044868176dd821" + integrity sha512-kQ7jYdlKS335mpGbMW5tEe3IrQFIok9r84EM3PXB8qBFJPSc6dpWfrtsC/y1pyrz82xfUIn5ZrnSHQQsd6jebQ== + +"@esbuild/freebsd-x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.0.tgz#3f9ce53344af2f08d178551cd475629147324a83" + integrity sha512-uG8B0WSepMRsBNVXAQcHf9+Ko/Tr+XqmK7Ptel9HVmnykupXdS4J7ovSQUIi0tQGIndhbqWLaIL/qO/cWhXKyQ== + +"@esbuild/linux-arm64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.0.tgz#24efa685515689df4ecbc13031fa0a9dda910a11" + integrity sha512-uTtyYAP5veqi2z9b6Gr0NUoNv9F/rOzI8tOD5jKcCvRUn7T60Bb+42NDBCWNhMjkQzI0qqwXkQGo1SY41G52nw== + +"@esbuild/linux-arm@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.0.tgz#6b586a488e02e9b073a75a957f2952b3b6e87b4c" + integrity sha512-2ezuhdiZw8vuHf1HKSf4TIk80naTbP9At7sOqZmdVwvvMyuoDiZB49YZKLsLOfKIr77+I40dWpHVeY5JHpIEIg== + +"@esbuild/linux-ia32@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.0.tgz#84ce7864f762708dcebc1b123898a397dea13624" + integrity sha512-c88wwtfs8tTffPaoJ+SQn3y+lKtgTzyjkD8NgsyCtCmtoIC8RDL7PrJU05an/e9VuAke6eJqGkoMhJK1RY6z4w== + +"@esbuild/linux-loong64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.0.tgz#1922f571f4cae1958e3ad29439c563f7d4fd9037" + integrity sha512-lR2rr/128/6svngnVta6JN4gxSXle/yZEZL3o4XZ6esOqhyR4wsKyfu6qXAL04S4S5CgGfG+GYZnjFd4YiG3Aw== + +"@esbuild/linux-mips64el@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.0.tgz#7ca1bd9df3f874d18dbf46af009aebdb881188fe" + integrity sha512-9Sycc+1uUsDnJCelDf6ZNqgZQoK1mJvFtqf2MUz4ujTxGhvCWw+4chYfDLPepMEvVL9PDwn6HrXad5yOrNzIsQ== + +"@esbuild/linux-ppc64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.0.tgz#8f95baf05f9486343bceeb683703875d698708a4" + integrity sha512-CoWSaaAXOZd+CjbUTdXIJE/t7Oz+4g90A3VBCHLbfuc5yUQU/nFDLOzQsN0cdxgXd97lYW/psIIBdjzQIwTBGw== + +"@esbuild/linux-riscv64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.0.tgz#ca63b921d5fe315e28610deb0c195e79b1a262ca" + integrity sha512-mlb1hg/eYRJUpv8h/x+4ShgoNLL8wgZ64SUr26KwglTYnwAWjkhR2GpoKftDbPOCnodA9t4Y/b68H4J9XmmPzA== + +"@esbuild/linux-s390x@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.0.tgz#cb3d069f47dc202f785c997175f2307531371ef8" + integrity sha512-fgf9ubb53xSnOBqyvWEY6ukBNRl1mVX1srPNu06B6mNsNK20JfH6xV6jECzrQ69/VMiTLvHMicQR/PgTOgqJUQ== + +"@esbuild/linux-x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.0.tgz#ac617e0dc14e9758d3d7efd70288c14122557dc7" + integrity sha512-H9Eu6MGse++204XZcYsse1yFHmRXEWgadk2N58O/xd50P9EvFMLJTQLg+lB4E1cF2xhLZU5luSWtGTb0l9UeSg== + +"@esbuild/netbsd-x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.0.tgz#6cc778567f1513da6e08060e0aeb41f82eb0f53c" + integrity sha512-lCT675rTN1v8Fo+RGrE5KjSnfY0x9Og4RN7t7lVrN3vMSjy34/+3na0q7RIfWDAj0e0rCh0OL+P88lu3Rt21MQ== + +"@esbuild/openbsd-x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.0.tgz#76848bcf76b4372574fb4d06cd0ed1fb29ec0fbe" + integrity sha512-HKoUGXz/TOVXKQ+67NhxyHv+aDSZf44QpWLa3I1lLvAwGq8x1k0T+e2HHSRvxWhfJrFxaaqre1+YyzQ99KixoA== + +"@esbuild/sunos-x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.0.tgz#ea4cd0639bf294ad51bc08ffbb2dac297e9b4706" + integrity sha512-GDwAqgHQm1mVoPppGsoq4WJwT3vhnz/2N62CzhvApFD1eJyTroob30FPpOZabN+FgCjhG+AgcZyOPIkR8dfD7g== + +"@esbuild/win32-arm64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.0.tgz#a5c171e4a7f7e4e8be0e9947a65812c1535a7cf0" + integrity sha512-0vYsP8aC4TvMlOQYozoksiaxjlvUcQrac+muDqj1Fxy6jh9l9CZJzj7zmh8JGfiV49cYLTorFLxg7593pGldwQ== + +"@esbuild/win32-ia32@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.0.tgz#f8ac5650c412d33ea62d7551e0caf82da52b7f85" + integrity sha512-p98u4rIgfh4gdpV00IqknBD5pC84LCub+4a3MO+zjqvU5MVXOc3hqR2UgT2jI2nh3h8s9EQxmOsVI3tyzv1iFg== + +"@esbuild/win32-x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.0.tgz#2efddf82828aac85e64cef62482af61c29561bee" + integrity sha512-NgJnesu1RtWihtTtXGFMU5YSE6JyyHPMxCwBZK7a6/8d31GuSo9l0Ss7w1Jw5QnKUawG6UEehs883kcXf5fYwg== + "@floating-ui/core@^1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" @@ -738,6 +853,13 @@ dependencies: undici-types "~5.26.4" +"@types/node@^20.5.9": + version "20.11.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.17.tgz#cdd642d0e62ef3a861f88ddbc2b61e32578a9292" + integrity sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw== + dependencies: + undici-types "~5.26.4" + "@types/prop-types@*": version "15.7.11" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" @@ -825,6 +947,30 @@ resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ== +"@y-sweet/client@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@y-sweet/client/-/client-0.1.0.tgz#1d4dd2eb03c651a06695e607fca8f22b52fd4787" + integrity sha512-X9+IZ/7t7So39TxYxmmjKKZ8SCKcFJrBmnEHHEJ9l6Jj6hPfoK8uHzQiYN+R0J5CpEoGsxuPevwAQZzENYX0dQ== + dependencies: + "@y-sweet/sdk" "0.1.0" + y-protocols "^1.0.5" + +"@y-sweet/react@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@y-sweet/react/-/react-0.1.0.tgz#7c80b2fafbb7d0c90acf3e53f78d7b1b792a466f" + integrity sha512-Ss6hsVmBxnkd6iIK1t9buOLR33mJVLFvrvp1A0KuuH3EA3UN0o5KcJaxPwErgrLyZxbPillyxZ+sCECsU6/4ZA== + dependencies: + "@y-sweet/client" "0.1.0" + "@y-sweet/sdk" "0.1.0" + y-protocols "^1.0.5" + +"@y-sweet/sdk@0.1.0", "@y-sweet/sdk@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@y-sweet/sdk/-/sdk-0.1.0.tgz#bf9cfb37a405f6a07819e49707565ecef6df38fe" + integrity sha512-rQDF3p3KhRVPBRpT9e8fNq0qyQlHe/LF3IfrkP3m/PjUmtTkMY/a3x1/vdRn1KXLz3tB5h7iP7KRPDP7bEs2qw== + dependencies: + "@types/node" "^20.5.9" + abstract-leveldown@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" @@ -1453,6 +1599,35 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +esbuild@^0.20.0: + version "0.20.0" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.20.0.tgz#a7170b63447286cd2ff1f01579f09970e6965da4" + integrity sha512-6iwE3Y2RVYCME1jLpBqq7LQWK3MW6vjV2bZy6gt/WrqkY+WE74Spyc0ThAOYpMtITvnjX09CrC6ym7A/m9mebA== + optionalDependencies: + "@esbuild/aix-ppc64" "0.20.0" + "@esbuild/android-arm" "0.20.0" + "@esbuild/android-arm64" "0.20.0" + "@esbuild/android-x64" "0.20.0" + "@esbuild/darwin-arm64" "0.20.0" + "@esbuild/darwin-x64" "0.20.0" + "@esbuild/freebsd-arm64" "0.20.0" + "@esbuild/freebsd-x64" "0.20.0" + "@esbuild/linux-arm" "0.20.0" + "@esbuild/linux-arm64" "0.20.0" + "@esbuild/linux-ia32" "0.20.0" + "@esbuild/linux-loong64" "0.20.0" + "@esbuild/linux-mips64el" "0.20.0" + "@esbuild/linux-ppc64" "0.20.0" + "@esbuild/linux-riscv64" "0.20.0" + "@esbuild/linux-s390x" "0.20.0" + "@esbuild/linux-x64" "0.20.0" + "@esbuild/netbsd-x64" "0.20.0" + "@esbuild/openbsd-x64" "0.20.0" + "@esbuild/sunos-x64" "0.20.0" + "@esbuild/win32-arm64" "0.20.0" + "@esbuild/win32-ia32" "0.20.0" + "@esbuild/win32-x64" "0.20.0" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -3421,6 +3596,11 @@ y-protocols@^1.0.5: dependencies: lib0 "^0.2.85" +y-sweet@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/y-sweet/-/y-sweet-0.1.0.tgz#2368fb54730aafc5e7f1221b0e02bc093e660ba8" + integrity sha512-45+EQQBMrDp9W5RS89HYqgX3B6W168i1O6otzEp68NrZ/OqiEjcMo1EdCAclaFM38Pcpu67gL/jrVRq5vD4gtQ== + y-utility@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/y-utility/-/y-utility-0.1.3.tgz#f5c28a86ab7f0cd277d03ffed474c84a71bf302c" From b1848aa94b4be86fed5427da42afebc8035f6fdf Mon Sep 17 00:00:00 2001 From: gempir Date: Tue, 13 Feb 2024 23:11:40 +0100 Subject: [PATCH 03/14] finalize setting up server with client --- .env.development | 3 +- Makefile | 7 +- ansible/group_vars/main/vars.yml | 3 +- ansible/group_vars/main/vault.yml | 57 ++++--- ansible/roles/caddy/templates/Caddyfile.j2 | 2 +- ansible/roles/gempbot/templates/env.j2 | 2 + internal/config/main.go | 4 + internal/server/api.go | 5 +- internal/server/overlay.go | 23 ++- internal/ysweet/factory.go | 58 +++---- internal/ysweet/ysweet.http | 15 ++ main.go | 12 +- web/createYsweetToken.cjs | 11 -- web/package.json | 4 +- web/src/components/Overlay/Editor.tsx | 8 +- .../components/Overlay/IframeOverlayPage.tsx | 11 +- .../components/Overlay/OverlayEditPage.tsx | 13 +- web/src/hooks/useOverlays.ts | 18 ++- web/yarn.lock | 144 ------------------ 19 files changed, 153 insertions(+), 247 deletions(-) create mode 100644 internal/ysweet/ysweet.http delete mode 100644 web/createYsweetToken.cjs diff --git a/.env.development b/.env.development index cad6fac..b5bc234 100644 --- a/.env.development +++ b/.env.development @@ -6,4 +6,5 @@ TWITCH_USERNAME="gempbot" DSN="postgresql://postgres:postgres@localhost:5432" LISTEN_ADDRESS="127.0.0.1:3010" LOG_LEVEL=debug -YPERSISTENCE=./dbdir \ No newline at end of file +YSWEET_TOKEN=AAAgT07jyfGLORBpu8Oj0XmtJmbT7KAeWBRZ3Y75d1T4u1A +YSWEET_URL=http://127.0.0.1:8070 \ No newline at end of file diff --git a/Makefile b/Makefile index 1acc7a4..903e129 100644 --- a/Makefile +++ b/Makefile @@ -9,11 +9,8 @@ export $(shell sed 's/=.*//' .env) build_server: go run main.go -yjs_server: - cd web && yarn yjs - -ysweet_token: - cd web && yarn build-ysweet-token +ysweet: + cd web && yarn ysweet-dev test: go test ./internal/... diff --git a/ansible/group_vars/main/vars.yml b/ansible/group_vars/main/vars.yml index 67a9002..a5cf1f8 100644 --- a/ansible/group_vars/main/vars.yml +++ b/ansible/group_vars/main/vars.yml @@ -41,4 +41,5 @@ prometheus_postgres_dbname: gempbot node_exporter_arch: arm64 -caddy_config: "{{ lookup('template', 'templates/Caddyfile.j2') }}" \ No newline at end of file +caddy_config: "{{ lookup('template', 'templates/Caddyfile.j2') }}" + diff --git a/ansible/group_vars/main/vault.yml b/ansible/group_vars/main/vault.yml index 26a10da..0fc5efe 100644 --- a/ansible/group_vars/main/vault.yml +++ b/ansible/group_vars/main/vault.yml @@ -1,26 +1,33 @@ $ANSIBLE_VAULT;1.1;AES256 -33346663633935396161373333663063363462623538363837616439646133653439356234383864 -3664633264373238323133366663343965303530336331370a623930363430363834353665363437 -65316230643937633633386464613435653336616634653563303662653130623831346634386138 -6535333139373565320a643235663431393935643631386534326337343034346262333533393264 -36396530636233616633633238373432353066383538363865636266313564373961313831326465 -34633438646562376163373761366437366437636662613463363236323162306565633531383530 -64373633646632613433363230663838333061663465396530313134613930613834333832366434 -66633834373537363730336562666363333634333065633062663062303739633035663138383230 -32386663613365663163613530666132346230346132393764613566613562323862303466653336 -65343930653533336635386566343230353033313839363562666136386563663466663331323535 -39383464393162353539626261633832346434383534396537396266363562383333646133353036 -34343337633065626137306234356363383034393663373562303732383562353162353038643138 -33333836373339323639323430613963646337326564633930353630643939626139653838316337 -37323835666266386230373531366135616337666139663338353064653565346235653832356562 -34303234623762616161353839343965633066373166363935623761666438316362346337326162 -63356639313534333639323438323434653231313336303539323337303763333531323661663035 -65316262393261616664623162343862326633653336666434613965393062643332373337333036 -34666138626235373832666632376330613336623164613236376333326335366663643831386564 -65363832363864326361616562306532373632663765313062393730653863326161653438653035 -32656339376330383766356437393031646137656339626435316466353261663061363764313235 -64333732376161346161613636363937326137343230383831343433633733366632333136623132 -37366536303737353536613634653063343631643566383234663961633062653434383631643234 -38666437663034626335626165303561396232623933396534343535303233336566643836373162 -61653663633134633631353138656161636138386361346535366563393839643536346165366661 -3738 +36626431346235646636343736386135333866333939363231353865643432303465656238376137 +3366393065613332313837366138303136346536313133390a353439343664626337666239366564 +63333533663564376165653932363130643535613038643637653166623461363238356262653365 +6538316237326361650a386461613132323530666339343537613731363865663662666238656362 +38373535616461643134356231313935636630633730333531376364303832653364306432333438 +62316432366462333330363738366630386366353233326563663333336237633963373933623630 +33623738336530393934376130396633346666663638346437663334313335343437393235633833 +66653462383936333137336636313335336331636330623336666661346335343461303265343332 +39623732656138313836306133343938343039643535346263333562366262633839633664373866 +34393932643037653131623638613334616462663662386139383964386335356535306638346266 +61313539646261653731613561373430383862643434373932393337353431373230343439643863 +36376335313635643865663634623737333134653235326161366465633564306339313732653330 +61363561636465633438353531343262663237633065333836376435376466306434336262396337 +38616632326265623439323161313435666332613534356234663133316361393637373465666662 +34353436316563656439386436666461326530633864636138636130376535326132343163376639 +65373266326138346637393935623137626436616363323363386463643763316638613739626435 +34326537343561653534386438363831363165616161303464623561366233353236316537663633 +31613063663430323636313162626466373166356562633463613761306131343030303865313136 +31353637666666353733333561383666376466393563363962623934373033663734383264323234 +62306464626566633463613862333437613762633238636336626638336430643530373164643036 +63333461383364346537383834353534306632653832663163636438306431396535666364313434 +37303261303232386664353534393165316638356261343939386338393234376261383031653233 +39663563623563383763373065663132383437376661613236313566643835633638633461363338 +61313033366137303163313364323234626534333262373834343439316264326464376462613866 +61333434326264396164336339313130616439303336636633626433623561343366643735626130 +37333538666136653832386263643930646162653635616134353836636231373661636236643935 +30653866366238366534643161613130363030386435656339373033316432633833373662386661 +32333938396466666338366337656437346633616332653238616163663630663735613733616532 +39313366636433396632643665303132623934633839373838306534643531393336313038343139 +39643631303436663330663231633332643839323939323430623833666665643637303832383365 +63623963376332393761663535653434353637353233343930623666333833373630346636646635 +66396239663237306237 diff --git a/ansible/roles/caddy/templates/Caddyfile.j2 b/ansible/roles/caddy/templates/Caddyfile.j2 index 7631459..91f4aa0 100644 --- a/ansible/roles/caddy/templates/Caddyfile.j2 +++ b/ansible/roles/caddy/templates/Caddyfile.j2 @@ -3,7 +3,7 @@ } {{ yjs_host }} { - reverse_proxy 127.0.0.1:1234 + reverse_proxy 127.0.0.1:8070 } {{ grafana_host }} { diff --git a/ansible/roles/gempbot/templates/env.j2 b/ansible/roles/gempbot/templates/env.j2 index 28f71c2..b34f40f 100644 --- a/ansible/roles/gempbot/templates/env.j2 +++ b/ansible/roles/gempbot/templates/env.j2 @@ -7,3 +7,5 @@ TWITCH_OAUTH={{ botOauth }} SECRET={{ apiSecret }} TWITCH_CLIENT_SECRET={{ twitchSecret }} DSN={{ dsn }} +YSWEET_URL=https://{{ yjs_host }} +YSWEET_TOKEN={{ ysweet_bearer }} \ No newline at end of file diff --git a/internal/config/main.go b/internal/config/main.go index e966c7c..3d3a844 100644 --- a/internal/config/main.go +++ b/internal/config/main.go @@ -18,6 +18,8 @@ type Config struct { DSN string `json:"DSN"` LogLevel string `json:"logLevel"` ListenAddress string `json:"listenAddress"` + YsweetUrl string `json:"ysweetUrl"` + YsweetToken string `json:"ysweetToken"` } func FromEnv() *Config { @@ -48,6 +50,8 @@ func FromEnv() *Config { DSN: Getenv("DSN"), LogLevel: logLevel, ListenAddress: listenAddress, + YsweetUrl: Getenv("YSWEET_URL"), + YsweetToken: Getenv("YSWEET_TOKEN"), } } diff --git a/internal/server/api.go b/internal/server/api.go index bc340d6..06eded2 100644 --- a/internal/server/api.go +++ b/internal/server/api.go @@ -12,6 +12,7 @@ import ( "github.com/gempir/gempbot/internal/store" "github.com/gempir/gempbot/internal/user" "github.com/gempir/gempbot/internal/ws" + "github.com/gempir/gempbot/internal/ysweet" ) type Api struct { @@ -26,9 +27,10 @@ type Api struct { channelPointManager *channelpoint.ChannelPointManager sevenTvClient emoteservice.ApiClient wsHandler *ws.WsHandler + tokenFactory *ysweet.Factory } -func NewApi(cfg *config.Config, db *store.Database, helixClient helixclient.Client, userAdmin *user.UserAdmin, authClient *auth.Auth, bot *bot.Bot, emoteChief *emotechief.EmoteChief, eventsubManager *eventsubmanager.EventsubManager, channelPointManager *channelpoint.ChannelPointManager, sevenTvClient emoteservice.ApiClient, wsHandler *ws.WsHandler) *Api { +func NewApi(cfg *config.Config, db *store.Database, helixClient helixclient.Client, userAdmin *user.UserAdmin, authClient *auth.Auth, bot *bot.Bot, emoteChief *emotechief.EmoteChief, eventsubManager *eventsubmanager.EventsubManager, channelPointManager *channelpoint.ChannelPointManager, sevenTvClient emoteservice.ApiClient, wsHandler *ws.WsHandler, tokenFactory *ysweet.Factory) *Api { return &Api{ db: db, cfg: cfg, @@ -41,5 +43,6 @@ func NewApi(cfg *config.Config, db *store.Database, helixClient helixclient.Clie channelPointManager: channelPointManager, sevenTvClient: sevenTvClient, wsHandler: wsHandler, + tokenFactory: tokenFactory, } } diff --git a/internal/server/overlay.go b/internal/server/overlay.go index e3720b5..2bcbc50 100644 --- a/internal/server/overlay.go +++ b/internal/server/overlay.go @@ -6,10 +6,16 @@ import ( "github.com/gempir/gempbot/internal/api" "github.com/gempir/gempbot/internal/store" + "github.com/gempir/gempbot/internal/ysweet" "github.com/google/uuid" "github.com/teris-io/shortid" ) +type OverlayResponse struct { + Overlay store.Overlay `json:"overlay"` + Auth ysweet.TokenResponse `json:"auth"` +} + func (a *Api) OverlayHandler(w http.ResponseWriter, r *http.Request) { authResp, _, apiErr := a.authClient.AttemptAuth(r, w) if apiErr != nil { @@ -28,13 +34,26 @@ func (a *Api) OverlayHandler(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { if r.URL.Query().Get("roomId") != "" { overlay := a.db.GetOverlayByRoomId(r.URL.Query().Get("roomId")) - api.WriteJson(w, overlay, http.StatusOK) + + token, err := a.tokenFactory.CreateToken(overlay.RoomID) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + api.WriteJson(w, OverlayResponse{overlay, token}, http.StatusOK) return } if r.URL.Query().Get("id") != "" { overlay := a.db.GetOverlay(r.URL.Query().Get("id"), userID) - api.WriteJson(w, overlay, http.StatusOK) + token, err := a.tokenFactory.CreateToken(overlay.RoomID) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + api.WriteJson(w, OverlayResponse{overlay, token}, http.StatusOK) return } diff --git a/internal/ysweet/factory.go b/internal/ysweet/factory.go index 506cc8e..cc38087 100644 --- a/internal/ysweet/factory.go +++ b/internal/ysweet/factory.go @@ -1,23 +1,21 @@ package ysweet import ( - "bytes" - _ "embed" - "encoding/json" - "fmt" - "os/exec" -) + "context" -//go:embed createToken.cjs -var createToken string + "github.com/carlmjohnson/requests" + "github.com/gempir/gempbot/internal/config" +) type Factory struct { - ysweetUrl string + ysweetUrl string + bearerToken string } -func NewFactory(ysweetUrl string) *Factory { +func NewFactory(cfg *config.Config) *Factory { return &Factory{ - ysweetUrl: ysweetUrl, + ysweetUrl: cfg.YsweetUrl, + bearerToken: cfg.YsweetToken, } } @@ -27,27 +25,35 @@ type TokenResponse struct { Token string `json:"token"` } -func (f *Factory) CreateToken(docID string) (TokenResponse, error) { - cmd := exec.Command("node", "-", "") - cmd.Env = append(cmd.Env, "YSWEET_URL="+f.ysweetUrl) - cmd.Env = append(cmd.Env, "YSWEET_DOC_ID=1"+docID) - - cmd.Stdin = bytes.NewBufferString(createToken) - - var out bytes.Buffer - var errOut bytes.Buffer - cmd.Stdout = &out - cmd.Stderr = &errOut +type DocResponse struct { + DocID string `json:"docId"` +} - err := cmd.Run() +func (f *Factory) CreateToken(docID string) (TokenResponse, error) { + var docResponse DocResponse + err := requests. + URL(f.ysweetUrl). + Post(). + BodyJSON(map[string]string{"docId": docID}). + Bearer(f.bearerToken). + Pathf("/doc/new"). + ToJSON(&docResponse). + Fetch(context.Background()) if err != nil { - return TokenResponse{}, fmt.Errorf("%s %w", errOut.String(), err) + return TokenResponse{}, err } var tokenResponse TokenResponse - err = json.Unmarshal(out.Bytes(), &tokenResponse) + err = requests. + URL(f.ysweetUrl). + Post(). + Pathf("/doc/%s/auth", docResponse.DocID). + BodyJSON(map[string]string{}). + Bearer(f.bearerToken). + ToJSON(&tokenResponse). + Fetch(context.Background()) if err != nil { - return TokenResponse{}, fmt.Errorf("%s %w", out.String(), err) + return TokenResponse{}, err } return tokenResponse, nil diff --git a/internal/ysweet/ysweet.http b/internal/ysweet/ysweet.http new file mode 100644 index 0000000..a48acb0 --- /dev/null +++ b/internal/ysweet/ysweet.http @@ -0,0 +1,15 @@ + +POST http://127.0.0.1:8070/doc/new +Content-Type: application/json +Authorization: Bearer AAAgT07jyfGLORBpu8Oj0XmtJmbT7KAeWBRZ3Y75d1T4u1A + +{ + "docId": "newDoc123" +} + +### +POST http://127.0.0.1:8070/doc/newDoc123/auth +Content-Type: application/json +Authorization: Bearer AAAgT07jyfGLORBpu8Oj0XmtJmbT7KAeWBRZ3Y75d1T4u1A + +{} \ No newline at end of file diff --git a/main.go b/main.go index 43d7120..f77206d 100644 --- a/main.go +++ b/main.go @@ -38,6 +38,7 @@ func main() { userAdmin := user.NewUserAdmin(cfg, db, helixClient, nil) authClient := auth.NewAuth(cfg, db, helixClient) + tokenFactory := ysweet.NewFactory(cfg) bot := bot.NewBot(cfg, db, helixClient) go bot.Connect() @@ -49,7 +50,7 @@ func main() { wsHandler := ws.NewWsHandler(authClient) eventsubManager := eventsubmanager.NewEventsubManager(cfg, helixClient, db, emoteChief, bot.ChatClient) - apiHandlers := server.NewApi(cfg, db, helixClient, userAdmin, authClient, bot, emoteChief, eventsubManager, channelPointManager, seventvClient, wsHandler) + apiHandlers := server.NewApi(cfg, db, helixClient, userAdmin, authClient, bot, emoteChief, eventsubManager, channelPointManager, seventvClient, wsHandler, tokenFactory) mux := http.NewServeMux() @@ -72,13 +73,6 @@ func main() { mux.HandleFunc("/api/overlay", apiHandlers.OverlayHandler) mux.HandleFunc("/api/ws", wsHandler.HandleWs) - tokenFactory := ysweet.NewFactory("xdd") - str, err := tokenFactory.CreateToken("doc") - if err != nil { - log.Error(err) - } - log.Warn(str) - handler := cors.New(cors.Options{ AllowedOrigins: []string{cfg.WebBaseUrl}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "PATCH"}, @@ -87,7 +81,7 @@ func main() { }).Handler(mux) log.Info("Starting server on " + cfg.ListenAddress) - err = http.ListenAndServe(cfg.ListenAddress, handler) + err := http.ListenAndServe(cfg.ListenAddress, handler) if err != nil { log.Fatal(err) } diff --git a/web/createYsweetToken.cjs b/web/createYsweetToken.cjs deleted file mode 100644 index a34794d..0000000 --- a/web/createYsweetToken.cjs +++ /dev/null @@ -1,11 +0,0 @@ -import { DocumentManager } from '@y-sweet/sdk'; - -const manager = new DocumentManager(process.env.YSWEET_URL); - -async function main() { - const clientToken = await manager.getOrCreateDocAndToken(process.env.YSWEET_DOC_ID) - - console.log(JSON.stringify(clientToken)); -} - -main(); diff --git a/web/package.json b/web/package.json index 8b491f7..5394440 100644 --- a/web/package.json +++ b/web/package.json @@ -4,8 +4,7 @@ "dev": "next dev", "build": "next build", "start": "next start", - "yjs": "node yjs/server.js", - "build-ysweet-token": "esbuild createYsweetToken.cjs --bundle --outfile=../internal/ysweet/createToken.cjs --platform=node --target=node20" + "ysweet-dev": "y-sweet serve --port 8070 --auth=eGRk --host 127.0.0.1" }, "type": "module", "dependencies": { @@ -37,7 +36,6 @@ "@types/node": "^20.11.16", "@types/react": "^18.2.52", "autoprefixer": "^10.4.17", - "esbuild": "^0.20.0", "postcss": "^8.4.33", "typescript": "^5.3.3" } diff --git a/web/src/components/Overlay/Editor.tsx b/web/src/components/Overlay/Editor.tsx index c9bef20..9be6560 100644 --- a/web/src/components/Overlay/Editor.tsx +++ b/web/src/components/Overlay/Editor.tsx @@ -1,20 +1,14 @@ import { Editor, Tldraw, TldrawProps } from '@tldraw/tldraw'; import '@tldraw/tldraw/tldraw.css'; import { useYjsStore } from '../../hooks/useYjsStore'; -import { useStore } from '../../store'; type Props = { - roomId: string; readonly?: boolean; } export function CustomEditor(props: Partial & Props) { - const yjsWsUrl = useStore(state => state.yjsWsUrl); - const store = useYjsStore({ - roomId: props.roomId, - hostUrl: yjsWsUrl, - }); + const store = useYjsStore(); const handleMount = (editor: Editor) => { if (props.readonly) { diff --git a/web/src/components/Overlay/IframeOverlayPage.tsx b/web/src/components/Overlay/IframeOverlayPage.tsx index 6ed0981..fff02b0 100644 --- a/web/src/components/Overlay/IframeOverlayPage.tsx +++ b/web/src/components/Overlay/IframeOverlayPage.tsx @@ -1,15 +1,16 @@ 'use client'; +import { YDocProvider } from '@y-sweet/react'; import dynamic from 'next/dynamic'; import Head from 'next/head'; import { useParams } from 'next/navigation'; +import { useOverlayByRoomId } from '../../hooks/useOverlays'; const Editor = dynamic(async () => (await import('./Editor')).CustomEditor, { ssr: false }) export function IframeOverlayPage() { const params = useParams<{ roomId: string }>(); - - console.log("Joining", params.roomId); + const [overlayAuth] = useOverlayByRoomId(params.roomId); return (
@@ -28,7 +29,11 @@ export function IframeOverlayPage() { } `} - + {overlayAuth && + + + + }
); } \ No newline at end of file diff --git a/web/src/components/Overlay/OverlayEditPage.tsx b/web/src/components/Overlay/OverlayEditPage.tsx index 7e204db..0327024 100644 --- a/web/src/components/Overlay/OverlayEditPage.tsx +++ b/web/src/components/Overlay/OverlayEditPage.tsx @@ -1,15 +1,20 @@ const Editor = dynamic(async () => (await import('./Editor')).CustomEditor, { ssr: false }) +import { YDocProvider } from '@y-sweet/react'; import dynamic from "next/dynamic"; -import { useOverlay } from "../../hooks/useOverlays"; import { useParams } from "next/navigation"; +import { useOverlay } from "../../hooks/useOverlays"; + export function OverlayEditPage() { const params = useParams<{ overlayId: string }>(); - const [overlay] = useOverlay(params.overlayId); + const [overlayAuth] = useOverlay(params.overlayId); - console.log("Joining", overlay?.RoomID); return
- {overlay?.RoomID && } + {overlayAuth && + + + + }
; } \ No newline at end of file diff --git a/web/src/hooks/useOverlays.ts b/web/src/hooks/useOverlays.ts index c5f1fa7..c81ef79 100644 --- a/web/src/hooks/useOverlays.ts +++ b/web/src/hooks/useOverlays.ts @@ -41,9 +41,19 @@ export function useOverlays(): [Overlay[], () => void, (id: string) => void, str return [overlays, addOverlay, deleteOverlay, errorMessage, loading]; } +type Auth = { + url: string; + docId: string; + token: string; +} + +type OverlayAuth = { + overlay: Overlay; + auth: Auth; +} -export function useOverlay(id: string): [Overlay|null, boolean] { - const [overlay, setOverlay] = useState(null); +export function useOverlay(id: string): [OverlayAuth|null, boolean] { + const [overlay, setOverlay] = useState(null); const [loading, setLoading] = useState(false); const managing = useStore(state => state.managing); const apiBaseUrl = useStore(state => state.apiBaseUrl); @@ -61,8 +71,8 @@ export function useOverlay(id: string): [Overlay|null, boolean] { return [overlay, loading]; } -export function useOverlayByRoomId(roomId: string): [Overlay|null, boolean] { - const [overlay, setOverlay] = useState(null); +export function useOverlayByRoomId(roomId: string): [OverlayAuth|null, boolean] { + const [overlay, setOverlay] = useState(null); const [loading, setLoading] = useState(false); const managing = useStore(state => state.managing); const apiBaseUrl = useStore(state => state.apiBaseUrl); diff --git a/web/yarn.lock b/web/yarn.lock index 35c6b5f..bd2c33d 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -14,121 +14,6 @@ dependencies: regenerator-runtime "^0.14.0" -"@esbuild/aix-ppc64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.0.tgz#509621cca4e67caf0d18561a0c56f8b70237472f" - integrity sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw== - -"@esbuild/android-arm64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.0.tgz#109a6fdc4a2783fc26193d2687827045d8fef5ab" - integrity sha512-aVpnM4lURNkp0D3qPoAzSG92VXStYmoVPOgXveAUoQBWRSuQzt51yvSju29J6AHPmwY1BjH49uR29oyfH1ra8Q== - -"@esbuild/android-arm@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.0.tgz#1397a2c54c476c4799f9b9073550ede496c94ba5" - integrity sha512-3bMAfInvByLHfJwYPJRlpTeaQA75n8C/QKpEaiS4HrFWFiJlNI0vzq/zCjBrhAYcPyVPG7Eo9dMrcQXuqmNk5g== - -"@esbuild/android-x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.0.tgz#2b615abefb50dc0a70ac313971102f4ce2fdb3ca" - integrity sha512-uK7wAnlRvjkCPzh8jJ+QejFyrP8ObKuR5cBIsQZ+qbMunwR8sbd8krmMbxTLSrDhiPZaJYKQAU5Y3iMDcZPhyQ== - -"@esbuild/darwin-arm64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.0.tgz#5c122ed799eb0c35b9d571097f77254964c276a2" - integrity sha512-AjEcivGAlPs3UAcJedMa9qYg9eSfU6FnGHJjT8s346HSKkrcWlYezGE8VaO2xKfvvlZkgAhyvl06OJOxiMgOYQ== - -"@esbuild/darwin-x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.0.tgz#9561d277002ba8caf1524f209de2b22e93d170c1" - integrity sha512-bsgTPoyYDnPv8ER0HqnJggXK6RyFy4PH4rtsId0V7Efa90u2+EifxytE9pZnsDgExgkARy24WUQGv9irVbTvIw== - -"@esbuild/freebsd-arm64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.0.tgz#84178986a3138e8500d17cc380044868176dd821" - integrity sha512-kQ7jYdlKS335mpGbMW5tEe3IrQFIok9r84EM3PXB8qBFJPSc6dpWfrtsC/y1pyrz82xfUIn5ZrnSHQQsd6jebQ== - -"@esbuild/freebsd-x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.0.tgz#3f9ce53344af2f08d178551cd475629147324a83" - integrity sha512-uG8B0WSepMRsBNVXAQcHf9+Ko/Tr+XqmK7Ptel9HVmnykupXdS4J7ovSQUIi0tQGIndhbqWLaIL/qO/cWhXKyQ== - -"@esbuild/linux-arm64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.0.tgz#24efa685515689df4ecbc13031fa0a9dda910a11" - integrity sha512-uTtyYAP5veqi2z9b6Gr0NUoNv9F/rOzI8tOD5jKcCvRUn7T60Bb+42NDBCWNhMjkQzI0qqwXkQGo1SY41G52nw== - -"@esbuild/linux-arm@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.0.tgz#6b586a488e02e9b073a75a957f2952b3b6e87b4c" - integrity sha512-2ezuhdiZw8vuHf1HKSf4TIk80naTbP9At7sOqZmdVwvvMyuoDiZB49YZKLsLOfKIr77+I40dWpHVeY5JHpIEIg== - -"@esbuild/linux-ia32@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.0.tgz#84ce7864f762708dcebc1b123898a397dea13624" - integrity sha512-c88wwtfs8tTffPaoJ+SQn3y+lKtgTzyjkD8NgsyCtCmtoIC8RDL7PrJU05an/e9VuAke6eJqGkoMhJK1RY6z4w== - -"@esbuild/linux-loong64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.0.tgz#1922f571f4cae1958e3ad29439c563f7d4fd9037" - integrity sha512-lR2rr/128/6svngnVta6JN4gxSXle/yZEZL3o4XZ6esOqhyR4wsKyfu6qXAL04S4S5CgGfG+GYZnjFd4YiG3Aw== - -"@esbuild/linux-mips64el@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.0.tgz#7ca1bd9df3f874d18dbf46af009aebdb881188fe" - integrity sha512-9Sycc+1uUsDnJCelDf6ZNqgZQoK1mJvFtqf2MUz4ujTxGhvCWw+4chYfDLPepMEvVL9PDwn6HrXad5yOrNzIsQ== - -"@esbuild/linux-ppc64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.0.tgz#8f95baf05f9486343bceeb683703875d698708a4" - integrity sha512-CoWSaaAXOZd+CjbUTdXIJE/t7Oz+4g90A3VBCHLbfuc5yUQU/nFDLOzQsN0cdxgXd97lYW/psIIBdjzQIwTBGw== - -"@esbuild/linux-riscv64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.0.tgz#ca63b921d5fe315e28610deb0c195e79b1a262ca" - integrity sha512-mlb1hg/eYRJUpv8h/x+4ShgoNLL8wgZ64SUr26KwglTYnwAWjkhR2GpoKftDbPOCnodA9t4Y/b68H4J9XmmPzA== - -"@esbuild/linux-s390x@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.0.tgz#cb3d069f47dc202f785c997175f2307531371ef8" - integrity sha512-fgf9ubb53xSnOBqyvWEY6ukBNRl1mVX1srPNu06B6mNsNK20JfH6xV6jECzrQ69/VMiTLvHMicQR/PgTOgqJUQ== - -"@esbuild/linux-x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.0.tgz#ac617e0dc14e9758d3d7efd70288c14122557dc7" - integrity sha512-H9Eu6MGse++204XZcYsse1yFHmRXEWgadk2N58O/xd50P9EvFMLJTQLg+lB4E1cF2xhLZU5luSWtGTb0l9UeSg== - -"@esbuild/netbsd-x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.0.tgz#6cc778567f1513da6e08060e0aeb41f82eb0f53c" - integrity sha512-lCT675rTN1v8Fo+RGrE5KjSnfY0x9Og4RN7t7lVrN3vMSjy34/+3na0q7RIfWDAj0e0rCh0OL+P88lu3Rt21MQ== - -"@esbuild/openbsd-x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.0.tgz#76848bcf76b4372574fb4d06cd0ed1fb29ec0fbe" - integrity sha512-HKoUGXz/TOVXKQ+67NhxyHv+aDSZf44QpWLa3I1lLvAwGq8x1k0T+e2HHSRvxWhfJrFxaaqre1+YyzQ99KixoA== - -"@esbuild/sunos-x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.0.tgz#ea4cd0639bf294ad51bc08ffbb2dac297e9b4706" - integrity sha512-GDwAqgHQm1mVoPppGsoq4WJwT3vhnz/2N62CzhvApFD1eJyTroob30FPpOZabN+FgCjhG+AgcZyOPIkR8dfD7g== - -"@esbuild/win32-arm64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.0.tgz#a5c171e4a7f7e4e8be0e9947a65812c1535a7cf0" - integrity sha512-0vYsP8aC4TvMlOQYozoksiaxjlvUcQrac+muDqj1Fxy6jh9l9CZJzj7zmh8JGfiV49cYLTorFLxg7593pGldwQ== - -"@esbuild/win32-ia32@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.0.tgz#f8ac5650c412d33ea62d7551e0caf82da52b7f85" - integrity sha512-p98u4rIgfh4gdpV00IqknBD5pC84LCub+4a3MO+zjqvU5MVXOc3hqR2UgT2jI2nh3h8s9EQxmOsVI3tyzv1iFg== - -"@esbuild/win32-x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.0.tgz#2efddf82828aac85e64cef62482af61c29561bee" - integrity sha512-NgJnesu1RtWihtTtXGFMU5YSE6JyyHPMxCwBZK7a6/8d31GuSo9l0Ss7w1Jw5QnKUawG6UEehs883kcXf5fYwg== - "@floating-ui/core@^1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" @@ -1599,35 +1484,6 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -esbuild@^0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.20.0.tgz#a7170b63447286cd2ff1f01579f09970e6965da4" - integrity sha512-6iwE3Y2RVYCME1jLpBqq7LQWK3MW6vjV2bZy6gt/WrqkY+WE74Spyc0ThAOYpMtITvnjX09CrC6ym7A/m9mebA== - optionalDependencies: - "@esbuild/aix-ppc64" "0.20.0" - "@esbuild/android-arm" "0.20.0" - "@esbuild/android-arm64" "0.20.0" - "@esbuild/android-x64" "0.20.0" - "@esbuild/darwin-arm64" "0.20.0" - "@esbuild/darwin-x64" "0.20.0" - "@esbuild/freebsd-arm64" "0.20.0" - "@esbuild/freebsd-x64" "0.20.0" - "@esbuild/linux-arm" "0.20.0" - "@esbuild/linux-arm64" "0.20.0" - "@esbuild/linux-ia32" "0.20.0" - "@esbuild/linux-loong64" "0.20.0" - "@esbuild/linux-mips64el" "0.20.0" - "@esbuild/linux-ppc64" "0.20.0" - "@esbuild/linux-riscv64" "0.20.0" - "@esbuild/linux-s390x" "0.20.0" - "@esbuild/linux-x64" "0.20.0" - "@esbuild/netbsd-x64" "0.20.0" - "@esbuild/openbsd-x64" "0.20.0" - "@esbuild/sunos-x64" "0.20.0" - "@esbuild/win32-arm64" "0.20.0" - "@esbuild/win32-ia32" "0.20.0" - "@esbuild/win32-x64" "0.20.0" - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" From 92776b0f2374e0539c6274e006bf23c65571ae6e Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 19:23:38 +0100 Subject: [PATCH 04/14] upgrade go deps --- go.mod | 10 ++++------ go.sum | 9 +++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index ecf5c2d..555f521 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/gempir/gempbot -go 1.18 +go 1.21 require ( github.com/carlmjohnson/requests v0.23.5 @@ -17,20 +17,18 @@ require ( gorm.io/gorm v1.25.7 ) -require github.com/rogpeppe/go-internal v1.12.0 // indirect - -replace github.com/nicklaw5/helix/v2 v2.12.0 => github.com/gempir/helix/v2 v2.0.2-0.20221223221449-fe5671ac8ea7 - require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect - github.com/jackc/pgx/v5 v5.4.3 // indirect + github.com/jackc/pgx/v5 v5.5.3 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jellydator/ttlcache/v2 v2.11.1 github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect golang.org/x/crypto v0.19.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/sync v0.6.0 // indirect diff --git a/go.sum b/go.sum index 01823e8..6345d16 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,10 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= -github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/pgx/v5 v5.5.3 h1:Ces6/M3wbDXYpM8JyyPD57ivTtJACFZJd885pdIaV2s= +github.com/jackc/pgx/v5 v5.5.3/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jellydator/ttlcache/v2 v2.11.1 h1:AZGME43Eh2Vv3giG6GeqeLeFXxwxn1/qHItqWZl6U64= github.com/jellydator/ttlcache/v2 v2.11.1/go.mod h1:RtE5Snf0/57e+2cLWFYWCCsLas2Hy3c5Z4n14XmSvTI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -27,6 +29,7 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -89,12 +92,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From b990bdf0c15798ca4a54ab512df89aef81455e0c Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 19:25:01 +0100 Subject: [PATCH 05/14] ignore some typescript errors --- web/src/hooks/useYjsStore.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/src/hooks/useYjsStore.ts b/web/src/hooks/useYjsStore.ts index c8253e2..cc984d2 100644 --- a/web/src/hooks/useYjsStore.ts +++ b/web/src/hooks/useYjsStore.ts @@ -140,11 +140,13 @@ import { const presenceDerivation = createPresenceStateDerivation(userPreferences, presenceId)(store) // Set our initial presence from the derivation's current value + // @ts-expect-error room.awareness.setLocalStateField('presence', presenceDerivation.value) // When the derivation change, sync presence to to yjs awareness unsubs.push( react('when presence changes', () => { + // @ts-expect-error const presence = presenceDerivation.value requestAnimationFrame(() => { room.awareness.setLocalStateField('presence', presence) From 1674231534f313f71da0198dde2003eedc54d20e Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 19:54:46 +0100 Subject: [PATCH 06/14] fix up prod and add some limits --- .../roles/gempbot/templates/service-yjs.j2 | 6 +---- web/src/components/Overlay/OverlaysPage.tsx | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/ansible/roles/gempbot/templates/service-yjs.j2 b/ansible/roles/gempbot/templates/service-yjs.j2 index d5ca2c2..f0ed40f 100644 --- a/ansible/roles/gempbot/templates/service-yjs.j2 +++ b/ansible/roles/gempbot/templates/service-yjs.j2 @@ -6,13 +6,9 @@ StartLimitBurst=10 [Service] Restart=always RestartSec=5 -ExecStart=/home/gempbot/web/yjs/server.js +ExecStart=./node_modules/.bin/y-sweet serve --port 8070 --host 127.0.0.1 --auth {{ ysweet_authb64 }} --prod /home/gempbot/yjs_db WorkingDirectory=/home/gempbot/web Environment=NODE_ENV=production -Environment=YPERSISTENCE=/home/gempbot/yjs_db -Environment=HOST=127.0.0.1 -Environment=PORT=1234 -Environment=SECRET={{ apiSecret }} [Install] WantedBy=multi-user.target \ No newline at end of file diff --git a/web/src/components/Overlay/OverlaysPage.tsx b/web/src/components/Overlay/OverlaysPage.tsx index 633349f..f9df01e 100644 --- a/web/src/components/Overlay/OverlaysPage.tsx +++ b/web/src/components/Overlay/OverlaysPage.tsx @@ -1,19 +1,33 @@ import Link from "next/link"; import { useOverlays } from "../../hooks/useOverlays"; +import { useUserConfig } from "../../hooks/useUserConfig"; + +const gempirId = "77829817"; export function OverlaysPage() { const [overlays, addOverlay, deleteOverlay, errorMessage, loading] = useOverlays(); + const [user] = useUserConfig(); return
- +
+ + + Only gempir can + +
{overlays.map(overlay =>
- +
+ + + Only gempir can + +
{overlay.ID}
From bc9162cc1e8b594236ef01a70c4a212858048ff7 Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 19:56:18 +0100 Subject: [PATCH 07/14] clean up --- web/src/components/Overlay/OverlaysPage.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/web/src/components/Overlay/OverlaysPage.tsx b/web/src/components/Overlay/OverlaysPage.tsx index f9df01e..c7cb8ee 100644 --- a/web/src/components/Overlay/OverlaysPage.tsx +++ b/web/src/components/Overlay/OverlaysPage.tsx @@ -7,26 +7,26 @@ const gempirId = "77829817"; export function OverlaysPage() { const [overlays, addOverlay, deleteOverlay, errorMessage, loading] = useOverlays(); const [user] = useUserConfig(); - + const isGempir = user?.Protected.CurrentUserID === gempirId; return
- - + + {!isGempir && Only gempir can - + }
{overlays.map(overlay =>
- - + {!isGempir && Only gempir can - + }
{overlay.ID}
From ebb3a3f5de0ee0d44097c12cf0551630a3c9a9e3 Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 19:58:37 +0100 Subject: [PATCH 08/14] fix version --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e08295..bbb4d3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: fetch-depth: 2 - uses: actions/setup-go@v2 with: - go-version: '1.19' + go-version: '1.21' - name: Run coverage run: go test -race -coverprofile=coverage.out -covermode=atomic ./internal/... - name: Upload coverage to Codecov From f0642ed1e990ee0aa9b7e2a2112a1830e7e5c1fc Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 20:52:00 +0100 Subject: [PATCH 09/14] fix exec --- .github/workflows/deploy.yml | 1 - Makefile | 9 --------- ansible/roles/gempbot/templates/service-yjs.j2 | 2 +- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 19a2f46..a20ab59 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,4 +18,3 @@ jobs: echo "${{secrets.SSH_PRIVATE_KEY}}" > ansible/.ssh_key chmod 600 ansible/.ssh_key make deploy - make deploy_yjs diff --git a/Makefile b/Makefile index 903e129..5c0fb29 100644 --- a/Makefile +++ b/Makefile @@ -28,15 +28,6 @@ deploy: ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "sudo chown gempbot:gempbot /home/gempbot/gempbot" ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "sudo systemctl restart gempbot-migrate && sudo systemctl start gempbot" -deploy_yjs: - (cd web && yarn) - tar -czf web.tar.gz web - rsync -avz -e "ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key" web.tar.gz ubuntu@o1.gempir.com:/home/gempbot/ - ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "sudo systemctl stop gempbot-yjs" - ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "rm -rf /home/gempbot/web" - ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "tar -xf /home/gempbot/web.tar.gz -C /home/gempbot/" - ssh -o StrictHostKeyChecking=no -p 32022 -i ansible/.ssh_key ubuntu@o1.gempir.com "sudo systemctl start gempbot-yjs" - ansible: cd ansible && ansible-vault decrypt ssh_key.vault --output=.ssh_key chmod 600 ansible/.ssh_key diff --git a/ansible/roles/gempbot/templates/service-yjs.j2 b/ansible/roles/gempbot/templates/service-yjs.j2 index f0ed40f..ded8cb9 100644 --- a/ansible/roles/gempbot/templates/service-yjs.j2 +++ b/ansible/roles/gempbot/templates/service-yjs.j2 @@ -6,7 +6,7 @@ StartLimitBurst=10 [Service] Restart=always RestartSec=5 -ExecStart=./node_modules/.bin/y-sweet serve --port 8070 --host 127.0.0.1 --auth {{ ysweet_authb64 }} --prod /home/gempbot/yjs_db +ExecStart=/home/gempbot/y-sweet/crates/target/release/y-sweet serve --port 8070 --host 127.0.0.1 --auth {{ ysweet_authb64 }} --prod /home/gempbot/yjs_db WorkingDirectory=/home/gempbot/web Environment=NODE_ENV=production From f9c35b9da590f1102464cf7e8c6badc72c40f6f3 Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 21:09:01 +0100 Subject: [PATCH 10/14] shorter --- internal/server/overlay.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/server/overlay.go b/internal/server/overlay.go index 2bcbc50..371483b 100644 --- a/internal/server/overlay.go +++ b/internal/server/overlay.go @@ -65,7 +65,7 @@ func (a *Api) OverlayHandler(w http.ResponseWriter, r *http.Request) { overlay.ID = shortid.MustGenerate() // long string so you cant read addressbar easily var roomID []string - for i := 0; i < 16; i++ { + for i := 0; i < 4; i++ { roomID = append(roomID, uuid.New().String()) } overlay.RoomID = strings.Join(roomID, "-") From f5347d48fe1905be1f87bb797e72f6bf1912d835 Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 21:11:55 +0100 Subject: [PATCH 11/14] restrict --- internal/server/overlay.go | 11 +++++++++++ web/src/components/Overlay/OverlaysPage.tsx | 13 +++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/internal/server/overlay.go b/internal/server/overlay.go index 371483b..df234bc 100644 --- a/internal/server/overlay.go +++ b/internal/server/overlay.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/gempir/gempbot/internal/api" + "github.com/gempir/gempbot/internal/dto" "github.com/gempir/gempbot/internal/store" "github.com/gempir/gempbot/internal/ysweet" "github.com/google/uuid" @@ -60,6 +61,11 @@ func (a *Api) OverlayHandler(w http.ResponseWriter, r *http.Request) { overlays := a.db.GetOverlays(userID) api.WriteJson(w, overlays, http.StatusOK) } else if r.Method == http.MethodPost { + if authResp.Data.UserID != dto.GEMPIR_USER_ID { + http.Error(w, "Only gempir can", http.StatusForbidden) + return + } + overlay := store.Overlay{} overlay.OwnerTwitchID = userID overlay.ID = shortid.MustGenerate() @@ -79,6 +85,11 @@ func (a *Api) OverlayHandler(w http.ResponseWriter, r *http.Request) { api.WriteJson(w, overlay, http.StatusCreated) } else if r.Method == http.MethodDelete { + if authResp.Data.UserID != dto.GEMPIR_USER_ID { + http.Error(w, "Only gempir can", http.StatusForbidden) + return + } + if r.URL.Query().Get("id") == "" { http.Error(w, "missing id", http.StatusBadRequest) } diff --git a/web/src/components/Overlay/OverlaysPage.tsx b/web/src/components/Overlay/OverlaysPage.tsx index c7cb8ee..6c4b98b 100644 --- a/web/src/components/Overlay/OverlaysPage.tsx +++ b/web/src/components/Overlay/OverlaysPage.tsx @@ -2,18 +2,15 @@ import Link from "next/link"; import { useOverlays } from "../../hooks/useOverlays"; import { useUserConfig } from "../../hooks/useUserConfig"; -const gempirId = "77829817"; - export function OverlaysPage() { const [overlays, addOverlay, deleteOverlay, errorMessage, loading] = useOverlays(); const [user] = useUserConfig(); - const isGempir = user?.Protected.CurrentUserID === gempirId; return
- - {!isGempir && + + { Only gempir can }
@@ -21,12 +18,12 @@ export function OverlaysPage() { {overlays.map(overlay =>
- - {!isGempir && + Only gempir can - } +
{overlay.ID}
From c1916d25820caf58d21f04ac73b56ff3f95b898f Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 21:17:33 +0100 Subject: [PATCH 12/14] ssl support --- internal/ysweet/factory.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/ysweet/factory.go b/internal/ysweet/factory.go index cc38087..a6ae133 100644 --- a/internal/ysweet/factory.go +++ b/internal/ysweet/factory.go @@ -2,6 +2,7 @@ package ysweet import ( "context" + "strings" "github.com/carlmjohnson/requests" "github.com/gempir/gempbot/internal/config" @@ -9,12 +10,14 @@ import ( type Factory struct { ysweetUrl string + ssl bool bearerToken string } func NewFactory(cfg *config.Config) *Factory { return &Factory{ ysweetUrl: cfg.YsweetUrl, + ssl: strings.HasPrefix(cfg.WebhookApiBaseUrl, "https"), bearerToken: cfg.YsweetToken, } } @@ -56,5 +59,9 @@ func (f *Factory) CreateToken(docID string) (TokenResponse, error) { return TokenResponse{}, err } + if f.ssl { + tokenResponse.Url = strings.Replace(tokenResponse.Url, "ws://", "wss://", 1) + } + return tokenResponse, nil } From eb4f109447c3053a1faa450cd900b18eb49491cc Mon Sep 17 00:00:00 2001 From: gempir Date: Wed, 14 Feb 2024 21:41:15 +0100 Subject: [PATCH 13/14] cleanup --- internal/ysweet/factory.go | 2 +- web/src/components/Overlay/Editor.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/ysweet/factory.go b/internal/ysweet/factory.go index a6ae133..c117736 100644 --- a/internal/ysweet/factory.go +++ b/internal/ysweet/factory.go @@ -17,7 +17,7 @@ type Factory struct { func NewFactory(cfg *config.Config) *Factory { return &Factory{ ysweetUrl: cfg.YsweetUrl, - ssl: strings.HasPrefix(cfg.WebhookApiBaseUrl, "https"), + ssl: strings.HasPrefix(cfg.WebBaseUrl, "https"), bearerToken: cfg.YsweetToken, } } diff --git a/web/src/components/Overlay/Editor.tsx b/web/src/components/Overlay/Editor.tsx index 9be6560..75fd7cf 100644 --- a/web/src/components/Overlay/Editor.tsx +++ b/web/src/components/Overlay/Editor.tsx @@ -11,6 +11,7 @@ export function CustomEditor(props: Partial & Props) { const store = useYjsStore(); const handleMount = (editor: Editor) => { + console.log('editor mounted', props.readonly, editor); if (props.readonly) { editor.setCamera({ x: 0, y: 0, z: 1 }); editor.updateInstanceState({ isReadonly: true, canMoveCamera: false }) From f26615a7ff563217c09efa7231f78ec663bac869 Mon Sep 17 00:00:00 2001 From: gempir Date: Thu, 15 Feb 2024 20:59:20 +0100 Subject: [PATCH 14/14] roomId is enough to authenticate, so obs can load the overlay --- internal/server/overlay.go | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/internal/server/overlay.go b/internal/server/overlay.go index df234bc..ddad764 100644 --- a/internal/server/overlay.go +++ b/internal/server/overlay.go @@ -18,6 +18,21 @@ type OverlayResponse struct { } func (a *Api) OverlayHandler(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet { + if r.URL.Query().Get("roomId") != "" { + overlay := a.db.GetOverlayByRoomId(r.URL.Query().Get("roomId")) + + token, err := a.tokenFactory.CreateToken(overlay.RoomID) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + api.WriteJson(w, OverlayResponse{overlay, token}, http.StatusOK) + return + } + } + authResp, _, apiErr := a.authClient.AttemptAuth(r, w) if apiErr != nil { return @@ -33,19 +48,6 @@ func (a *Api) OverlayHandler(w http.ResponseWriter, r *http.Request) { } if r.Method == http.MethodGet { - if r.URL.Query().Get("roomId") != "" { - overlay := a.db.GetOverlayByRoomId(r.URL.Query().Get("roomId")) - - token, err := a.tokenFactory.CreateToken(overlay.RoomID) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - api.WriteJson(w, OverlayResponse{overlay, token}, http.StatusOK) - return - } - if r.URL.Query().Get("id") != "" { overlay := a.db.GetOverlay(r.URL.Query().Get("id"), userID) token, err := a.tokenFactory.CreateToken(overlay.RoomID)