work-in-progress atproto PDS
typescript atproto pds atcute
at trunk 141 lines 3.7 kB view raw
1import { TestBsky } from './bsky.ts'; 2import { BSKY_PORT, PDS_PORT, PLC_PORT } from './const.ts'; 3import { TestPlc } from './plc.ts'; 4 5// polyfill for Node.js 22 6if (typeof AsyncDisposableStack === 'undefined') { 7 globalThis.AsyncDisposableStack = class ADS implements AsyncDisposableStack { 8 #disposed = false; 9 #stack: (() => Promise<void>)[] = []; 10 11 readonly [Symbol.toStringTag] = 'AsyncDisposableStack'; 12 13 get disposed() { 14 return this.#disposed; 15 } 16 17 use<T extends AsyncDisposable | Disposable | null | undefined>(value: T): T { 18 if (this.#disposed) { 19 throw new ReferenceError('AsyncDisposableStack already disposed'); 20 } 21 if (value != null) { 22 if (Symbol.asyncDispose in (value as object)) { 23 this.#stack.push(async () => { 24 await (value as AsyncDisposable)[Symbol.asyncDispose](); 25 }); 26 } else if (Symbol.dispose in (value as object)) { 27 this.#stack.push(async () => (value as Disposable)[Symbol.dispose]()); 28 } 29 } 30 return value; 31 } 32 33 adopt<T>(value: T, onDisposeAsync: (value: T) => PromiseLike<void> | void): T { 34 if (this.#disposed) { 35 throw new ReferenceError('AsyncDisposableStack already disposed'); 36 } 37 this.#stack.push(async () => { 38 await onDisposeAsync(value); 39 }); 40 return value; 41 } 42 43 defer(onDisposeAsync: () => PromiseLike<void> | void): void { 44 if (this.#disposed) { 45 throw new ReferenceError('AsyncDisposableStack already disposed'); 46 } 47 this.#stack.push(async () => { 48 await onDisposeAsync(); 49 }); 50 } 51 52 move(): AsyncDisposableStack { 53 if (this.#disposed) { 54 throw new ReferenceError('AsyncDisposableStack already disposed'); 55 } 56 const cloned = new ADS(); 57 cloned.#stack = this.#stack; 58 this.#stack = []; 59 this.#disposed = true; 60 return cloned; 61 } 62 63 async disposeAsync(): Promise<void> { 64 if (this.#disposed) { 65 return; 66 } 67 this.#disposed = true; 68 let error: unknown; 69 while (this.#stack.length > 0) { 70 const dispose = this.#stack.pop()!; 71 try { 72 await dispose(); 73 } catch (e) { 74 error ??= e; 75 } 76 } 77 if (error) { 78 throw error; 79 } 80 } 81 82 [Symbol.asyncDispose]() { 83 return this.disposeAsync(); 84 } 85 }; 86} 87 88const run = async () => { 89 console.log(` 90┌──────────────────────────────────┐ 91│ danaus dev-env (PLC + bsky) │ 92└──────────────────────────────────┘ 93`); 94 95 const dbPostgresUrl = process.env.DB_POSTGRES_URL; 96 if (!dbPostgresUrl) { 97 throw new Error('DB_POSTGRES_URL is required'); 98 } 99 100 await using stack = new AsyncDisposableStack(); 101 102 const plc = await TestPlc.create({ 103 port: PLC_PORT, 104 dbPostgresUrl: dbPostgresUrl, 105 dbPostgresSchema: 'plc', 106 }); 107 stack.use(plc); 108 109 const bsky = await TestBsky.create({ 110 plcUrl: plc.url, 111 repoProvider: `ws://localhost:${PDS_PORT}`, 112 pdsPort: PDS_PORT, 113 port: BSKY_PORT, 114 dbPostgresUrl: dbPostgresUrl, 115 dbPostgresSchema: 'bsky', 116 redisHost: process.env.REDIS_HOST ?? 'localhost', 117 privateKey: '3f916c70dc69e4c5e83877f013325b11ecac31742e6a42f5c4fb240d0703d9d5', 118 }); 119 stack.use(bsky); 120 121 console.log(`👤 PLC server http://localhost:${plc.port}`); 122 console.log(`🌅 AppView http://localhost:${bsky.port}`); 123 console.log(`🌅 AppView DID ${bsky.serverDid}`); 124 125 const shutdown = async () => { 126 console.log('\nshutting down...'); 127 await stack.disposeAsync(); 128 process.exit(0); 129 }; 130 131 process.on('SIGINT', shutdown); 132 process.on('SIGTERM', shutdown); 133 134 // keep process alive 135 await new Promise(() => {}); 136}; 137 138run().catch((err) => { 139 console.error('fatal error:', err); 140 process.exit(1); 141});