import { LibSQLDatabase } from "drizzle-orm/libsql"; import { Client } from "@libsql/client"; import * as schema from "./db/schema.ts"; export type db = LibSQLDatabase & { $client: Client; }; export const ROOT_DOMAIN = Deno.env.get("HOSTNAME") || "localhost"; export const PORT = Number(Deno.env.get("PORT")) || 80; export const SUBDOMAIN_REGEX = new RegExp(`.+(?=\\.${ROOT_DOMAIN}$)`, "gm"); export function clearCookies(req: Request): Headers { const cookie_header = req.headers.get("Cookie"); // cookies are unset so return empty headers if (!cookie_header) return new Headers(); // get each kv pair and extract the key const cookies = cookie_header.split("; ").map((x) => x.split("=")[0]); const head = new Headers(); for (const key of cookies) { // max-age <= 0 means instant expiry .: deleted instantly head.append("Set-Cookie", `${key}=; Max-Age=-1`); } return head; } /** * given a valid url path string containing * - `/` for seperating characters * - a-zA-Z0-9 `-._~` as unreserved * - `!$&'()*+,;=` as reserved but valid in paths * - `:@` as neither reserved or unreserved but valid in paths * - %XX where X are hex digits for percent encoding * * we need to consistently and bidirectionally convert it into a string containing the characters A-Z, a-z, 0-9, `.-_:~` for an atproto rkey * A-Z a-z 0-9 are covered easily * we can also take -._~ as they are also unreserved * leaving : as a valid rkey character which looks nice for encoding * the uppercase versions MUST be used to prevent ambiguity * a colon which isnt followed by a valid character is an invalid rkey and should be ignored * - `/` `::` * - `%` `:~` * - `!` `:21` * - `$` `:24` * - `&` `:26` * - `'` `:27` * - `(` `:28` * - `)` `:29` * - `*` `:2A` * - `+` `:2B` * - `,` `:2C` * - `:` `:3A` * - `;` `:3B` * - `=` `:3D` * - `@` `:40` * @returns {string | undefined} undefined when input is invalid */ export function urlToRkey(url: string): string | undefined { // contains 0-9A-Za-z + special valid chars and / seperator. also can contain %XX with XX being hex if (!url.match(/^([a-zA-Z0-9/\-._~!$&'()*+,;=:@]|(%[0-9a-fA-F]{2}))*$/gm)) return; return ( url // : replace is hoisted so it doesnt replace colons from elsewhere .replaceAll(":", ":3A") .replaceAll("/", "::") .replaceAll("%", ":~") .replaceAll("!", ":21") .replaceAll("$", ":24") .replaceAll("&", ":26") .replaceAll("'", ":27") .replaceAll("(", ":28") .replaceAll(")", ":29") .replaceAll("*", ":2A") .replaceAll("+", ":2B") .replaceAll(",", ":2C") .replaceAll(";", ":3B") .replaceAll("=", ":3D") .replaceAll("@", ":40") ); } /** * @see {@link urlToRkey} for rkey <=> url conversion syntax * @returns {string | undefined} undefined when input is invalid */ export function rkeyToUrl(rkey: string): string | undefined { // contains 0-9A-Za-z .-_:~ if (!rkey.match(/^[A-Za-z0-9.\-_:~]*$/gm)) return; return rkey .replaceAll("::", "/") .replaceAll(":~", "%") .replaceAll(":21", "!") .replaceAll(":24", "$") .replaceAll(":26", "&") .replaceAll(":27", "'") .replaceAll(":28", "(") .replaceAll(":29", ")") .replaceAll(":2A", "*") .replaceAll(":2B", "+") .replaceAll(":2C", ",") .replaceAll(":3A", ":") .replaceAll(":3B", ";") .replaceAll(":3D", "=") .replaceAll(":40", "@"); }