make route prefixes have a single place where they are defined (#3624)

This is for maintainabilty of the paths. It's hard to track down all the
places where a route is being referenced. This helps unify them so that
it's easily searchable in the codebase. This came up during the readonly
room refactor and being able to find the way a particular route was
wired through the codebase.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [x] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
This commit is contained in:
Mime Čuvalo 2024-04-27 11:57:55 +01:00 committed by GitHub
parent de55259c92
commit c9af23c921
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 85 additions and 35 deletions

View file

@ -2,7 +2,13 @@
/// <reference types="@cloudflare/workers-types" />
import { SupabaseClient } from '@supabase/supabase-js'
import { ROOM_OPEN_MODE, type RoomOpenMode } from '@tldraw/dotcom-shared'
import {
READ_ONLY_LEGACY_PREFIX,
READ_ONLY_PREFIX,
ROOM_OPEN_MODE,
ROOM_PREFIX,
type RoomOpenMode,
} from '@tldraw/dotcom-shared'
import {
DBLoadResultType,
RoomSnapshot,
@ -91,22 +97,22 @@ export class TLDrawDurableObject extends TLServer {
readonly router = Router()
.get(
'/r/:roomId',
`/${ROOM_PREFIX}/:roomId`,
(req) => this.extractDocumentInfoFromRequest(req, ROOM_OPEN_MODE.READ_WRITE),
(req) => this.onRequest(req)
)
.get(
'/v/:roomId',
`/${READ_ONLY_LEGACY_PREFIX}/:roomId`,
(req) => this.extractDocumentInfoFromRequest(req, ROOM_OPEN_MODE.READ_ONLY_LEGACY),
(req) => this.onRequest(req)
)
.get(
'/ro/:roomId',
`/${READ_ONLY_PREFIX}/:roomId`,
(req) => this.extractDocumentInfoFromRequest(req, ROOM_OPEN_MODE.READ_ONLY),
(req) => this.onRequest(req)
)
.post(
'/r/:roomId/restore',
`/${ROOM_PREFIX}/:roomId/restore`,
(req) => this.extractDocumentInfoFromRequest(req, ROOM_OPEN_MODE.READ_WRITE),
(req) => this.onRestore(req)
)

View file

@ -1,3 +1,4 @@
import { ROOM_PREFIX } from '@tldraw/dotcom-shared'
import { IRequest } from 'itty-router'
import { Environment } from '../types'
import { fourOhFour } from '../utils/fourOhFour'
@ -11,6 +12,6 @@ export async function forwardRoomRequest(request: IRequest, env: Environment): P
if (isRoomIdTooLong(roomId)) return roomIdIsTooLong()
// Set up the durable object for this room
const id = env.TLDR_DOC.idFromName(`/r/${roomId}`)
const id = env.TLDR_DOC.idFromName(`/${ROOM_PREFIX}/${roomId}`)
return env.TLDR_DOC.get(id).fetch(request)
}

View file

@ -1,4 +1,4 @@
import { RoomOpenMode } from '@tldraw/dotcom-shared'
import { ROOM_PREFIX, RoomOpenMode } from '@tldraw/dotcom-shared'
import { IRequest } from 'itty-router'
import { Environment } from '../types'
import { fourOhFour } from '../utils/fourOhFour'
@ -17,7 +17,7 @@ export async function joinExistingRoom(
// This needs to be a websocket request!
if (request.headers.get('upgrade')?.toLowerCase() === 'websocket') {
// Set up the durable object for this room
const id = env.TLDR_DOC.idFromName(`/r/${roomId}`)
const id = env.TLDR_DOC.idFromName(`/${ROOM_PREFIX}/${roomId}`)
return env.TLDR_DOC.get(id).fetch(request)
}

View file

@ -1,6 +1,11 @@
/// <reference no-default-lib="true"/>
/// <reference types="@cloudflare/workers-types" />
import { ROOM_OPEN_MODE } from '@tldraw/dotcom-shared'
import {
READ_ONLY_LEGACY_PREFIX,
READ_ONLY_PREFIX,
ROOM_OPEN_MODE,
ROOM_PREFIX,
} from '@tldraw/dotcom-shared'
import { Router, createCors } from 'itty-router'
import { env } from 'process'
import Toucan from 'toucan-js'
@ -26,13 +31,19 @@ const router = Router()
.post('/new-room', createRoom)
.post('/snapshots', createRoomSnapshot)
.get('/snapshot/:roomId', getRoomSnapshot)
.get('/r/:roomId', (req, env) => joinExistingRoom(req, env, ROOM_OPEN_MODE.READ_WRITE))
.get('/v/:roomId', (req, env) => joinExistingRoom(req, env, ROOM_OPEN_MODE.READ_ONLY_LEGACY))
.get('/ro/:roomId', (req, env) => joinExistingRoom(req, env, ROOM_OPEN_MODE.READ_ONLY))
.get('/r/:roomId/history', getRoomHistory)
.get('/r/:roomId/history/:timestamp', getRoomHistorySnapshot)
.get(`/${ROOM_PREFIX}/:roomId`, (req, env) =>
joinExistingRoom(req, env, ROOM_OPEN_MODE.READ_WRITE)
)
.get(`/${READ_ONLY_LEGACY_PREFIX}/:roomId`, (req, env) =>
joinExistingRoom(req, env, ROOM_OPEN_MODE.READ_ONLY_LEGACY)
)
.get(`/${READ_ONLY_PREFIX}/:roomId`, (req, env) =>
joinExistingRoom(req, env, ROOM_OPEN_MODE.READ_ONLY)
)
.get(`/${ROOM_PREFIX}/:roomId/history`, getRoomHistory)
.get(`/${ROOM_PREFIX}/:roomId/history/:timestamp`, getRoomHistorySnapshot)
.get('/readonly-slug/:roomId', getReadonlySlug)
.post('/r/:roomId/restore', forwardRoomRequest)
.post(`/${ROOM_PREFIX}/:roomId/restore`, forwardRoomRequest)
.all('*', fourOhFour)
const Worker = {

View file

@ -1,3 +1,4 @@
import { ROOM_PREFIX } from '@tldraw/dotcom-shared'
import { RoomSnapshot } from '@tldraw/tlsync'
import { useCallback, useState } from 'react'
import { Tldraw, createTLStore, defaultShapeUtils } from 'tldraw'
@ -31,7 +32,7 @@ export function BoardHistorySnapshot({
const sure = window.confirm('Are you sure?')
if (!sure) return
const res = await fetch(`/api/r/${roomId}/restore`, {
const res = await fetch(`/api/${ROOM_PREFIX}/${roomId}/restore`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',

View file

@ -2,6 +2,7 @@ import * as Popover from '@radix-ui/react-popover'
import {
GetReadonlySlugResponseBody,
ROOM_OPEN_MODE,
ROOM_PREFIX,
RoomOpenModeToPath,
} from '@tldraw/dotcom-shared'
import React, { useEffect, useState } from 'react'
@ -43,7 +44,7 @@ function isSharedReadonlyUrl(pathname: string) {
}
function isSharedReadWriteUrl(pathname: string) {
return pathname.startsWith('/r/')
return pathname.startsWith(`/${ROOM_PREFIX}/`)
}
function getFreshShareState(): ShareState {

View file

@ -1,3 +1,4 @@
import { ROOM_PREFIX } from '@tldraw/dotcom-shared'
import { RoomSnapshot } from '@tldraw/tlsync'
import '../../styles/globals.css'
import { BoardHistorySnapshot } from '../components/BoardHistorySnapshot/BoardHistorySnapshot'
@ -11,7 +12,7 @@ const { loader, useData } = defineLoader(async (args) => {
if (!roomId) return null
const result = await fetch(`/api/r/${roomId}/history/${timestamp}`, {
const result = await fetch(`/api/${ROOM_PREFIX}/${roomId}/history/${timestamp}`, {
headers: {},
})
if (!result.ok) return null

View file

@ -1,3 +1,4 @@
import { ROOM_PREFIX } from '@tldraw/dotcom-shared'
import { BoardHistoryLog } from '../components/BoardHistoryLog/BoardHistoryLog'
import { ErrorPage } from '../components/ErrorPage/ErrorPage'
import { IFrameProtector, ROOM_CONTEXT } from '../components/IFrameProtector'
@ -8,7 +9,7 @@ const { loader, useData } = defineLoader(async (args) => {
if (!boardId) return null
const result = await fetch(`/api/r/${boardId}/history`, {
const result = await fetch(`/api/${ROOM_PREFIX}/${boardId}/history`, {
headers: {},
})
if (!result.ok) return null

View file

@ -1,4 +1,4 @@
import { Snapshot } from '@tldraw/dotcom-shared'
import { ROOM_PREFIX, Snapshot } from '@tldraw/dotcom-shared'
import { schema } from '@tldraw/tlsync'
import { Navigate } from 'react-router-dom'
import '../../styles/globals.css'
@ -36,5 +36,5 @@ export function Component() {
}}
/>
)
return <Navigate to={`/r/${data.slug}`} />
return <Navigate to={`/${ROOM_PREFIX}/${data.slug}`} />
}

View file

@ -1,6 +1,12 @@
import { captureException } from '@sentry/react'
import {
READ_ONLY_LEGACY_PREFIX,
READ_ONLY_PREFIX,
ROOM_PREFIX,
SNAPSHOT_PREFIX,
} from '@tldraw/dotcom-shared'
import { useEffect } from 'react'
import { createRoutesFromElements, Outlet, Route, useRouteError } from 'react-router-dom'
import { Outlet, Route, createRoutesFromElements, useRouteError } from 'react-router-dom'
import { DefaultErrorFallback } from './components/DefaultErrorFallback/DefaultErrorFallback'
import { ErrorPage } from './components/ErrorPage/ErrorPage'
@ -29,17 +35,20 @@ export const router = createRoutesFromElements(
>
<Route errorElement={<DefaultErrorFallback />}>
<Route path="/" lazy={() => import('./pages/root')} />
<Route path="/r" lazy={() => import('./pages/new')} />
<Route path={`/${ROOM_PREFIX}`} lazy={() => import('./pages/new')} />
<Route path="/new" lazy={() => import('./pages/new')} />
<Route path="/r/:roomId" lazy={() => import('./pages/public-multiplayer')} />
<Route path="/r/:boardId/history" lazy={() => import('./pages/history')} />
<Route path={`/${ROOM_PREFIX}/:roomId`} lazy={() => import('./pages/public-multiplayer')} />
<Route path={`/${ROOM_PREFIX}/:boardId/history`} lazy={() => import('./pages/history')} />
<Route
path="/r/:boardId/history/:timestamp"
path={`/${ROOM_PREFIX}/:boardId/history/:timestamp`}
lazy={() => import('./pages/history-snapshot')}
/>
<Route path="/s/:roomId" lazy={() => import('./pages/public-snapshot')} />
<Route path="/v/:roomId" lazy={() => import('./pages/public-readonly-legacy')} />
<Route path="/ro/:roomId" lazy={() => import('./pages/public-readonly')} />
<Route path={`/${SNAPSHOT_PREFIX}/:roomId`} lazy={() => import('./pages/public-snapshot')} />
<Route
path={`/${READ_ONLY_LEGACY_PREFIX}/:roomId`}
lazy={() => import('./pages/public-readonly-legacy')}
/>
<Route path={`/${READ_ONLY_PREFIX}/:roomId`} lazy={() => import('./pages/public-readonly')} />
</Route>
<Route path="*" lazy={() => import('./pages/not-found')} />
</Route>

View file

@ -2,6 +2,8 @@ import {
CreateRoomRequestBody,
CreateSnapshotRequestBody,
CreateSnapshotResponseBody,
ROOM_PREFIX,
SNAPSHOT_PREFIX,
Snapshot,
} from '@tldraw/dotcom-shared'
import { useMemo } from 'react'
@ -69,7 +71,7 @@ async function getSnapshotLink(
}
const paramsToUse = getViewportUrlQuery(editor)
const params = paramsToUse ? `?${new URLSearchParams(paramsToUse).toString()}` : ''
return new Blob([`${window.location.origin}/s/${response.roomId}${params}`], {
return new Blob([`${window.location.origin}/${SNAPSHOT_PREFIX}/${response.roomId}${params}`], {
type: 'text/plain',
})
}
@ -132,7 +134,7 @@ export function useSharing(): TLUiOverrides {
const query = getViewportUrlQuery(editor)
const origin = window.location.origin
const pathname = `/r/${response.slug}?${new URLSearchParams(query ?? {}).toString()}`
const pathname = `/${ROOM_PREFIX}/${response.slug}?${new URLSearchParams(query ?? {}).toString()}`
if (runningInIFrame) {
window.open(`${origin}${pathname}`)
} else {

View file

@ -1,4 +1,12 @@
export { ROOM_OPEN_MODE, RoomOpenModeToPath, type RoomOpenMode } from './routes'
export {
READ_ONLY_LEGACY_PREFIX,
READ_ONLY_PREFIX,
ROOM_OPEN_MODE,
ROOM_PREFIX,
RoomOpenModeToPath,
SNAPSHOT_PREFIX,
type RoomOpenMode,
} from './routes'
export type {
CreateRoomRequestBody,
CreateSnapshotRequestBody,

View file

@ -6,9 +6,18 @@ export const ROOM_OPEN_MODE = {
} as const
export type RoomOpenMode = (typeof ROOM_OPEN_MODE)[keyof typeof ROOM_OPEN_MODE]
/** @public */
export const READ_ONLY_PREFIX = 'ro'
/** @public */
export const READ_ONLY_LEGACY_PREFIX = 'v'
/** @public */
export const ROOM_PREFIX = 'r'
/** @public */
export const SNAPSHOT_PREFIX = 's'
/** @public */
export const RoomOpenModeToPath: Record<RoomOpenMode, string> = {
[ROOM_OPEN_MODE.READ_ONLY]: 'ro',
[ROOM_OPEN_MODE.READ_ONLY_LEGACY]: 'v',
[ROOM_OPEN_MODE.READ_WRITE]: 'r',
[ROOM_OPEN_MODE.READ_ONLY]: READ_ONLY_PREFIX,
[ROOM_OPEN_MODE.READ_ONLY_LEGACY]: READ_ONLY_LEGACY_PREFIX,
[ROOM_OPEN_MODE.READ_WRITE]: ROOM_PREFIX,
}