[WIP] A (somewhat barebones) atproto app for creating custom sites without hosting!

server: get all repos which use a record

means currently dependent on bsky.network but in future this should change

vielle.dev ec6e2994 a0017859

verified
Changed files
+55 -60
server
+1
.gitignore
··· 1 1 server/node_modules/* 2 2 server/local.db 3 + server/.env
+4 -1
server/.env.template
··· 1 1 PORT=8000 2 2 HOSTNAME=localhost 3 - DB_FILE_NAME=file:local.db 3 + DB_FILE_NAME=file:local.db 4 + # requires `/xrpc/com.atproto.sync.listReposByCollection` endpoint 5 + # this is because im lazy 6 + ATPROTO_RELAY=https://relay1.us-east.bsky.network
-57
server/src/backfill.ts
··· 1 - import { drizzle } from "drizzle-orm/libsql"; 2 - import { routes } from "./db/schema.ts"; 3 - import * as schema from "./db/schema.ts"; 4 - import { db as db_type } from "./utils.ts"; 5 - 6 - const db = drizzle<typeof schema>(Deno.env.get("DB_FILE_NAME")!); 7 - 8 - export default async function main(): Promise<db_type> { 9 - await db.delete(routes); 10 - try { 11 - // await Deno.remove("./blobs", { recursive: true }); 12 - } catch { 13 - // directory doesnt exist 14 - } 15 - 16 - await [ 17 - { 18 - did: "did:web:invalid", 19 - url_route: "404", 20 - blob_cid: "this_is_a_cid", 21 - mime: "text/html", 22 - }, 23 - { 24 - did: "did:web:invalid", 25 - url_route: "/", 26 - blob_cid: "root", 27 - mime: "text/html", 28 - }, 29 - { 30 - did: "did:web:invalid", 31 - url_route: "/hello.html", 32 - blob_cid: "hello", 33 - mime: "text/html", 34 - }, 35 - { 36 - did: "did:web:invalid", 37 - url_route: "/cat.png", 38 - blob_cid: "cat", 39 - mime: "image/png", 40 - }, 41 - { 42 - did: "did:web:invalid", 43 - url_route: "/styles.css", 44 - blob_cid: "styles", 45 - mime: "text/css", 46 - }, 47 - { 48 - did: "did:web:invalid", 49 - url_route: "/missing", 50 - blob_cid: "doesnt_exit", 51 - mime: "text/json", 52 - }, 53 - ].forEach(async (x) => await db.insert(routes).values(x)); 54 - 55 - // we only return the db when its ready 56 - return db; 57 - }
+48
server/src/backfill/index.ts
··· 1 + import { drizzle } from "drizzle-orm/libsql"; 2 + import { routes } from "../db/schema.ts"; 3 + import * as schema from "../db/schema.ts"; 4 + import { db as db_type } from "../utils.ts"; 5 + import { Client, simpleFetchHandler } from "@atcute/client"; 6 + 7 + const db: db_type = drizzle<typeof schema>(Deno.env.get("DB_FILE_NAME")!); 8 + 9 + // we block access to the database till we've set up listeners etc 10 + // set an initial value for ts sake; this will set asap 11 + let res: (value: db_type) => void = (v) => console.log("failed to set", v); 12 + export default new Promise<db_type>((p_res) => { 13 + res = p_res; 14 + }); 15 + 16 + const backfillClient = new Client({ 17 + handler: simpleFetchHandler({ 18 + service: 19 + Deno.env.get("ATPROTO_RELAY") || 20 + (() => { 21 + throw "ATPROTO_RELAY not set"; 22 + })(), 23 + }), 24 + }); 25 + 26 + let repos: `did:${string}:${string}`[] = []; 27 + let cursor: string | undefined; 28 + while (true) { 29 + const { data, ok } = await backfillClient.get( 30 + "com.atproto.sync.listReposByCollection", 31 + { 32 + params: { 33 + collection: "dev.atcities.route", 34 + cursor, 35 + }, 36 + } 37 + ); 38 + 39 + if (!ok) { 40 + throw data.error + "\n" + data.message; 41 + } 42 + 43 + repos = [...repos, ...data.repos.map((x) => x.did)]; 44 + cursor = data.cursor; 45 + if (!cursor) break; 46 + } 47 + 48 + res(db);
+2 -2
server/src/index.ts
··· 1 1 import root from "./routes/root.ts"; 2 2 import user from "./routes/user.ts"; 3 - import backfill from "./backfill.ts"; 3 + import backfill from "./backfill/index.ts"; 4 4 import { PORT, ROOT_DOMAIN, SUBDOMAIN_REGEX, clearCookies } from "./utils.ts"; 5 5 6 - const db = await backfill(); 6 + const db = await backfill; 7 7 8 8 Deno.serve({ port: PORT, hostname: ROOT_DOMAIN }, async (req) => { 9 9 const reqUrl = new URL(req.url);