🌿 Collaborative wiki on ATProto
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 144 lines 3.6 kB view raw
1/** 2 * dev-full.ts — Start a local PDS + appview + firehose, all wired together. 3 * 4 * The PDS runs under Node (better-sqlite3 native addon requirement). 5 * Appview and firehose run under Bun with watch mode. 6 * 7 * Usage: bun run scripts/dev-full.ts 8 */ 9 10import { resolve } from "node:path"; 11import { type Subprocess, spawn } from "bun"; 12 13const children: Subprocess[] = []; 14 15async function main() { 16 console.log("Building CSS (watch mode)..."); 17 const css = spawn({ 18 cmd: [ 19 "bunx", 20 "@tailwindcss/cli", 21 "-i", 22 "public/style.css", 23 "-o", 24 "public/dist.css", 25 "--watch", 26 ], 27 stdout: "inherit", 28 stderr: "inherit", 29 }); 30 children.push(css); 31 32 console.log("Starting test PDS (via Node)..."); 33 34 const pdsScript = resolve(import.meta.dir, "start-pds.mjs"); 35 const pdsProc = spawn({ 36 cmd: ["node", pdsScript], 37 stdout: "pipe", 38 stderr: "inherit", 39 }); 40 children.push(pdsProc); 41 42 // Read PDS info from stdout 43 const reader = pdsProc.stdout.getReader(); 44 let buffer = ""; 45 let pdsInfo: { 46 pdsUrl: string; 47 plcUrl: string; 48 accounts: Record<string, { did: string; handle: string; password: string }>; 49 }; 50 51 while (true) { 52 const { value, done } = await reader.read(); 53 if (done) { 54 throw new Error("PDS process exited before producing output"); 55 } 56 buffer += new TextDecoder().decode(value); 57 const newlineIdx = buffer.indexOf("\n"); 58 if (newlineIdx !== -1) { 59 pdsInfo = JSON.parse(buffer.slice(0, newlineIdx)); 60 reader.releaseLock(); 61 break; 62 } 63 } 64 65 const { pdsUrl, plcUrl, accounts } = pdsInfo as { 66 pdsUrl: string; 67 plcUrl: string; 68 accounts: Record<string, { did: string; handle: string; password: string }>; 69 }; 70 71 const env: Record<string, string> = { 72 ...(process.env as Record<string, string>), 73 PUBLIC_URL: "http://localhost:3000", 74 RELAY_URL: pdsUrl.replace("http://", "ws://"), 75 HANDLE_RESOLVER_URL: pdsUrl, 76 DEV_PDS_URL: pdsUrl, 77 DEV_PLC_URL: plcUrl, 78 DEV_ACCOUNTS: JSON.stringify(accounts), 79 SEED_DB: "1", 80 DB_PATH: "lichen-dev.db", 81 }; 82 83 console.log("Starting appview..."); 84 const appview = spawn({ 85 cmd: ["bun", "run", "--watch", "src/server/index.ts"], 86 env, 87 stdout: "inherit", 88 stderr: "inherit", 89 }); 90 children.push(appview); 91 92 // Wait for appview to initialize the DB schema before starting firehose 93 await new Promise((resolve) => setTimeout(resolve, 1000)); 94 95 console.log("Starting firehose subscriber..."); 96 const firehose = spawn({ 97 cmd: ["bun", "run", "--watch", "src/firehose/index.ts"], 98 env, 99 stdout: "inherit", 100 stderr: "inherit", 101 }); 102 children.push(firehose); 103 104 console.log(`\n${"=".repeat(60)}`); 105 console.log("dev-full environment running!"); 106 console.log("=".repeat(60)); 107 console.log(` PDS: ${pdsUrl}`); 108 console.log(` Appview: http://localhost:3000`); 109 console.log(` Firehose: ${pdsUrl.replace("http://", "ws://")}`); 110 console.log(""); 111 console.log(" Test accounts:"); 112 for (const [_name, acct] of Object.entries(accounts)) { 113 console.log(` ${acct.handle} (${acct.did})`); 114 } 115 console.log(""); 116 console.log(" Dev login:"); 117 for (const acct of Object.values(accounts)) { 118 console.log(` http://localhost:3000/dev/login/${acct.handle}`); 119 } 120 console.log(`${"=".repeat(60)}\n`); 121 122 // Handle shutdown 123 function shutdown() { 124 console.log("\nShutting down..."); 125 for (const child of children) { 126 child.kill("SIGTERM"); 127 } 128 process.exit(0); 129 } 130 131 process.on("SIGINT", shutdown); 132 process.on("SIGTERM", shutdown); 133 134 // Keep alive 135 await new Promise(() => {}); 136} 137 138main().catch((err) => { 139 console.error("dev-full failed:", err); 140 for (const child of children) { 141 child.kill("SIGTERM"); 142 } 143 process.exit(1); 144});