import { getAtprotoEnv } from "../atproto/env.ts"; export function resolvePublicUrl(request: Request): string { return getAtprotoEnv()?.publicUrl ?? new URL(request.url).origin; } // Callers interpolate these results straight into href="…", and slugs/handles can // come from remote records, so anything outside the RFC 3986 unreserved set is // percent-encoded here rather than at ~25 call sites. ":" is kept: it is a legal // path character and /@did:plc:… must stay readable. function seg(segment: string): string { return segment.replace(/[^A-Za-z0-9\-._~:]+/gu, (run) => encodeURIComponent(run).replace( /[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`, ), ); } export function wikiUrl(handle: string, wikiSlug: string): string { return `/@${seg(handle)}/${seg(wikiSlug)}`; } export function noteUrl( handle: string, wikiSlug: string, noteSlug: string, ): string { return `/@${seg(handle)}/${seg(wikiSlug)}/${seg(noteSlug)}`; } export function editNoteUrl( handle: string, wikiSlug: string, noteSlug: string, ): string { return `${noteUrl(handle, wikiSlug, noteSlug)}/edit`; } export function newNoteUrl(handle: string, wikiSlug: string): string { return `${wikiUrl(handle, wikiSlug)}/new`; } export function settingsUrl(handle: string, wikiSlug: string): string { return `${wikiUrl(handle, wikiSlug)}/-/settings`; } export function membersUrl(handle: string, wikiSlug: string): string { return `${wikiUrl(handle, wikiSlug)}/-/members`; } export function sidebarEditUrl(handle: string, wikiSlug: string): string { return `${wikiUrl(handle, wikiSlug)}/-/sidebar/edit`; } export function profileUrl(didOrHandle: string): string { return `/@${seg(didOrHandle)}`; } export function exportUrl(handle: string, wikiSlug: string): string { return `${wikiUrl(handle, wikiSlug)}/-/export`; } export function exportNoteUrl( handle: string, wikiSlug: string, noteSlug: string, ): string { return `${noteUrl(handle, wikiSlug, noteSlug)}/-/export`; } export function historyNoteUrl( handle: string, wikiSlug: string, noteSlug: string, ): string { return `${noteUrl(handle, wikiSlug, noteSlug)}/-/history`; } /** * Path for the collab WebSocket. The client prepends ws(s):// + host. Note: no * `@` before the handle here — it matches the `/collab/:handle/...` route param. */ export function collabWsPath( handle: string, wikiSlug: string, noteSlug: string, ): string { return `/collab/${seg(handle)}/${seg(wikiSlug)}/${seg(noteSlug)}`; } export function redirect(url: string): Response { return new Response(null, { status: 302, headers: { Location: url }, }); }