Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
117
fork

Configure Feed

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

at main 510 lines 16 kB view raw
1import {createServer as createHTTPServer} from 'node:http' 2import {parse} from 'node:url' 3 4import {createServer, type TestPDS} from './test-pds' 5 6let server: TestPDS 7// eslint-disable-next-line @typescript-eslint/no-misused-promises 8createHTTPServer(async (req, res) => { 9 const url = parse(req.url || '/', true) 10 if (req.method !== 'POST') { 11 return res.writeHead(200).end() 12 } 13 try { 14 console.log('Closing old server') 15 await server?.close() 16 console.log('Starting new server') 17 const inviteRequired = url?.query && 'invite' in url.query 18 server = await createServer({inviteRequired}) 19 console.log('Listening at', server.pdsUrl) 20 if (url?.query) { 21 if ('users' in url.query) { 22 console.log('Generating mock users') 23 await server.mocker.createUser('alice') 24 await server.mocker.createUser('bob') 25 await server.mocker.createUser('carla') 26 await server.mocker.users.alice.agent.upsertProfile(() => ({ 27 displayName: 'Alice', 28 description: 'Test user 1', 29 })) 30 await server.mocker.users.bob.agent.upsertProfile(() => ({ 31 displayName: 'Bob', 32 description: 'Test user 2', 33 })) 34 await server.mocker.users.carla.agent.upsertProfile(() => ({ 35 displayName: 'Carla', 36 description: 'Test user 3', 37 })) 38 if (inviteRequired) { 39 await server.mocker.createInvite(server.mocker.users.alice.did) 40 } 41 } 42 if ('follows' in url.query) { 43 console.log('Generating mock follows') 44 await server.mocker.follow('alice', 'bob') 45 await server.mocker.follow('alice', 'carla') 46 await server.mocker.follow('bob', 'alice') 47 await server.mocker.follow('bob', 'carla') 48 await server.mocker.follow('carla', 'alice') 49 await server.mocker.follow('carla', 'bob') 50 } 51 if ('posts' in url.query) { 52 console.log('Generating mock posts') 53 for (let user in server.mocker.users) { 54 await server.mocker.users[user].agent.post({text: 'Post'}) 55 } 56 } 57 if ('feeds' in url.query) { 58 console.log('Generating mock feed') 59 await server.mocker.createFeed('alice', 'alice-favs', []) 60 } 61 if ('thread' in url.query) { 62 console.log('Generating mock posts') 63 const res = await server.mocker.users.bob.agent.post({ 64 text: 'Thread root', 65 }) 66 await server.mocker.users.carla.agent.post({ 67 text: 'Thread reply', 68 reply: { 69 parent: {cid: res.cid, uri: res.uri}, 70 root: {cid: res.cid, uri: res.uri}, 71 }, 72 }) 73 } 74 if ('mergefeed' in url.query) { 75 console.log('Generating mock users') 76 await server.mocker.createUser('alice') 77 await server.mocker.createUser('bob') 78 await server.mocker.createUser('carla') 79 await server.mocker.createUser('dan') 80 await server.mocker.users.alice.agent.upsertProfile(() => ({ 81 displayName: 'Alice', 82 description: 'Test user 1', 83 })) 84 await server.mocker.users.bob.agent.upsertProfile(() => ({ 85 displayName: 'Bob', 86 description: 'Test user 2', 87 })) 88 await server.mocker.users.carla.agent.upsertProfile(() => ({ 89 displayName: 'Carla', 90 description: 'Test user 3', 91 })) 92 await server.mocker.users.dan.agent.upsertProfile(() => ({ 93 displayName: 'Dan', 94 description: 'Test user 4', 95 })) 96 console.log('Generating mock follows') 97 await server.mocker.follow('alice', 'bob') 98 await server.mocker.follow('alice', 'carla') 99 console.log('Generating mock posts') 100 let posts: Record<string, any[]> = { 101 alice: [], 102 bob: [], 103 carla: [], 104 dan: [], 105 } 106 for (let i = 0; i < 10; i++) { 107 for (let user in server.mocker.users) { 108 if (user === 'alice') continue 109 posts[user].push(await server.mocker.createPost(user, `Post ${i}`)) 110 } 111 } 112 for (let i = 0; i < 10; i++) { 113 for (let user in server.mocker.users) { 114 if (user === 'alice') continue 115 if (i % 5 === 0) { 116 await server.mocker.createReply(user, 'Self reply', { 117 cid: posts[user][i].cid, 118 uri: posts[user][i].uri, 119 }) 120 } 121 if (i % 5 === 1) { 122 await server.mocker.createReply(user, 'Reply to bob', { 123 cid: posts.bob[i].cid, 124 uri: posts.bob[i].uri, 125 }) 126 } 127 if (i % 5 === 2) { 128 await server.mocker.createReply(user, 'Reply to dan', { 129 cid: posts.dan[i].cid, 130 uri: posts.dan[i].uri, 131 }) 132 } 133 await server.mocker.users[user].agent.post({text: `Post ${i}`}) 134 } 135 } 136 console.log('Generating mock feeds') 137 await server.mocker.createFeed( 138 'alice', 139 'alice-favs', 140 posts.dan.map(p => p.uri), 141 ) 142 await server.mocker.createFeed( 143 'alice', 144 'alice-favs2', 145 posts.dan.map(p => p.uri), 146 ) 147 } 148 if ('labels' in url.query) { 149 console.log('Generating naughty users with labels') 150 151 const anchorPost = await server.mocker.createPost( 152 'alice', 153 'Anchor post', 154 ) 155 156 for (const user of [ 157 'dmca-account', 158 'dmca-profile', 159 'dmca-posts', 160 'porn-account', 161 'porn-profile', 162 'porn-posts', 163 'nudity-account', 164 'nudity-profile', 165 'nudity-posts', 166 'scam-account', 167 'scam-profile', 168 'scam-posts', 169 'unknown-account', 170 'unknown-profile', 171 'unknown-posts', 172 'hide-account', 173 'hide-profile', 174 'hide-posts', 175 'no-promote-account', 176 'no-promote-profile', 177 'no-promote-posts', 178 'warn-account', 179 'warn-profile', 180 'warn-posts', 181 'muted-account', 182 'muted-by-list-acc', 183 'blocking-account', 184 'blockedby-account', 185 'mutual-block-acc', 186 ]) { 187 await server.mocker.createUser(user) 188 await server.mocker.follow('alice', user) 189 await server.mocker.follow(user, 'alice') 190 await server.mocker.createPost(user, `Unlabeled post from ${user}`) 191 await server.mocker.createReply( 192 user, 193 `Unlabeled reply from ${user}`, 194 anchorPost, 195 ) 196 await server.mocker.like(user, anchorPost) 197 } 198 199 await server.mocker.labelAccount('dmca-violation', 'dmca-account') 200 await server.mocker.labelProfile('dmca-violation', 'dmca-profile') 201 await server.mocker.labelPost( 202 'dmca-violation', 203 await server.mocker.createPost('dmca-posts', 'dmca post'), 204 ) 205 await server.mocker.labelPost( 206 'dmca-violation', 207 await server.mocker.createQuotePost( 208 'dmca-posts', 209 'dmca quote post', 210 anchorPost, 211 ), 212 ) 213 await server.mocker.labelPost( 214 'dmca-violation', 215 await server.mocker.createReply( 216 'dmca-posts', 217 'dmca reply', 218 anchorPost, 219 ), 220 ) 221 222 await server.mocker.labelAccount('porn', 'porn-account') 223 await server.mocker.labelProfile('porn', 'porn-profile') 224 await server.mocker.labelPost( 225 'porn', 226 await server.mocker.createImagePost('porn-posts', 'porn post'), 227 ) 228 await server.mocker.labelPost( 229 'porn', 230 await server.mocker.createQuotePost( 231 'porn-posts', 232 'porn quote post', 233 anchorPost, 234 ), 235 ) 236 await server.mocker.labelPost( 237 'porn', 238 await server.mocker.createReply( 239 'porn-posts', 240 'porn reply', 241 anchorPost, 242 ), 243 ) 244 245 await server.mocker.labelAccount('nudity', 'nudity-account') 246 await server.mocker.labelProfile('nudity', 'nudity-profile') 247 await server.mocker.labelPost( 248 'nudity', 249 await server.mocker.createImagePost('nudity-posts', 'nudity post'), 250 ) 251 await server.mocker.labelPost( 252 'nudity', 253 await server.mocker.createQuotePost( 254 'nudity-posts', 255 'nudity quote post', 256 anchorPost, 257 ), 258 ) 259 await server.mocker.labelPost( 260 'nudity', 261 await server.mocker.createReply( 262 'nudity-posts', 263 'nudity reply', 264 anchorPost, 265 ), 266 ) 267 268 await server.mocker.labelAccount('scam', 'scam-account') 269 await server.mocker.labelProfile('scam', 'scam-profile') 270 await server.mocker.labelPost( 271 'scam', 272 await server.mocker.createPost('scam-posts', 'scam post'), 273 ) 274 await server.mocker.labelPost( 275 'scam', 276 await server.mocker.createQuotePost( 277 'scam-posts', 278 'scam quote post', 279 anchorPost, 280 ), 281 ) 282 await server.mocker.labelPost( 283 'scam', 284 await server.mocker.createReply( 285 'scam-posts', 286 'scam reply', 287 anchorPost, 288 ), 289 ) 290 291 await server.mocker.labelAccount('not-a-real-label', 'unknown-account') 292 await server.mocker.labelProfile('not-a-real-label', 'unknown-profile') 293 await server.mocker.labelPost( 294 'not-a-real-label', 295 await server.mocker.createPost('unknown-posts', 'unknown post'), 296 ) 297 await server.mocker.labelPost( 298 'not-a-real-label', 299 await server.mocker.createQuotePost( 300 'unknown-posts', 301 'unknown quote post', 302 anchorPost, 303 ), 304 ) 305 await server.mocker.labelPost( 306 'not-a-real-label', 307 await server.mocker.createReply( 308 'unknown-posts', 309 'unknown reply', 310 anchorPost, 311 ), 312 ) 313 314 await server.mocker.labelAccount('!hide', 'hide-account') 315 await server.mocker.labelProfile('!hide', 'hide-profile') 316 await server.mocker.labelPost( 317 '!hide', 318 await server.mocker.createPost('hide-posts', 'hide post'), 319 ) 320 await server.mocker.labelPost( 321 '!hide', 322 await server.mocker.createQuotePost( 323 'hide-posts', 324 'hide quote post', 325 anchorPost, 326 ), 327 ) 328 await server.mocker.labelPost( 329 '!hide', 330 await server.mocker.createReply( 331 'hide-posts', 332 'hide reply', 333 anchorPost, 334 ), 335 ) 336 337 await server.mocker.labelAccount('!no-promote', 'no-promote-account') 338 await server.mocker.labelProfile('!no-promote', 'no-promote-profile') 339 await server.mocker.labelPost( 340 '!no-promote', 341 await server.mocker.createPost('no-promote-posts', 'no-promote post'), 342 ) 343 await server.mocker.labelPost( 344 '!no-promote', 345 await server.mocker.createQuotePost( 346 'no-promote-posts', 347 'no-promote quote post', 348 anchorPost, 349 ), 350 ) 351 await server.mocker.labelPost( 352 '!no-promote', 353 await server.mocker.createReply( 354 'no-promote-posts', 355 'no-promote reply', 356 anchorPost, 357 ), 358 ) 359 360 await server.mocker.labelAccount('!warn', 'warn-account') 361 await server.mocker.labelProfile('!warn', 'warn-profile') 362 await server.mocker.labelPost( 363 '!warn', 364 await server.mocker.createPost('warn-posts', 'warn post'), 365 ) 366 await server.mocker.labelPost( 367 '!warn', 368 await server.mocker.createQuotePost( 369 'warn-posts', 370 'warn quote post', 371 anchorPost, 372 ), 373 ) 374 await server.mocker.labelPost( 375 '!warn', 376 await server.mocker.createReply( 377 'warn-posts', 378 'warn reply', 379 anchorPost, 380 ), 381 ) 382 383 await server.mocker.users.alice.agent.mute('muted-account.test') 384 await server.mocker.createPost('muted-account', 'muted post') 385 await server.mocker.createQuotePost( 386 'muted-account', 387 'muted quote post', 388 anchorPost, 389 ) 390 await server.mocker.createReply( 391 'muted-account', 392 'muted reply', 393 anchorPost, 394 ) 395 396 const list = await server.mocker.createMuteList('alice', 'Muted Users') 397 await server.mocker.addToMuteList( 398 'alice', 399 list, 400 server.mocker.users['muted-by-list-acc'].did, 401 ) 402 await server.mocker.createPost('muted-by-list-acc', 'muted post') 403 await server.mocker.createQuotePost( 404 'muted-by-list-acc', 405 'account quote post', 406 anchorPost, 407 ) 408 await server.mocker.createReply( 409 'muted-by-list-acc', 410 'account reply', 411 anchorPost, 412 ) 413 414 await server.mocker.createPost('blocking-account', 'blocking post') 415 await server.mocker.createQuotePost( 416 'blocking-account', 417 'blocking quote post', 418 anchorPost, 419 ) 420 await server.mocker.createReply( 421 'blocking-account', 422 'blocking reply', 423 anchorPost, 424 ) 425 await server.mocker.users.alice.agent.app.bsky.graph.block.create( 426 { 427 repo: server.mocker.users.alice.did, 428 }, 429 { 430 subject: server.mocker.users['blocking-account'].did, 431 createdAt: new Date().toISOString(), 432 }, 433 ) 434 435 await server.mocker.createPost('blockedby-account', 'blockedby post') 436 await server.mocker.createQuotePost( 437 'blockedby-account', 438 'blockedby quote post', 439 anchorPost, 440 ) 441 await server.mocker.createReply( 442 'blockedby-account', 443 'blockedby reply', 444 anchorPost, 445 ) 446 await server.mocker.users[ 447 'blockedby-account' 448 ].agent.app.bsky.graph.block.create( 449 { 450 repo: server.mocker.users['blockedby-account'].did, 451 }, 452 { 453 subject: server.mocker.users.alice.did, 454 createdAt: new Date().toISOString(), 455 }, 456 ) 457 458 await server.mocker.createPost('mutual-block-acc', 'mutual-block post') 459 await server.mocker.createQuotePost( 460 'mutual-block-acc', 461 'mutual-block quote post', 462 anchorPost, 463 ) 464 await server.mocker.createReply( 465 'mutual-block-acc', 466 'mutual-block reply', 467 anchorPost, 468 ) 469 await server.mocker.users.alice.agent.app.bsky.graph.block.create( 470 { 471 repo: server.mocker.users.alice.did, 472 }, 473 { 474 subject: server.mocker.users['mutual-block-acc'].did, 475 createdAt: new Date().toISOString(), 476 }, 477 ) 478 await server.mocker.users[ 479 'mutual-block-acc' 480 ].agent.app.bsky.graph.block.create( 481 { 482 repo: server.mocker.users['mutual-block-acc'].did, 483 }, 484 { 485 subject: server.mocker.users.alice.did, 486 createdAt: new Date().toISOString(), 487 }, 488 ) 489 490 // flush caches 491 await server.mocker.testNet.processAll() 492 } 493 } 494 console.log('Ready') 495 return res 496 .writeHead(200, { 497 'content-type': 'application/json', 498 }) 499 .end( 500 JSON.stringify({ 501 pdsUrl: server.pdsUrl, 502 appviewDid: server.appviewDid, 503 }), 504 ) 505 } catch (e) { 506 console.error('Error!', e) 507 return res.writeHead(500).end() 508 } 509}).listen(1986) 510console.log('Mock server manager listening on 1986')