this repo has no description
0
fork

Configure Feed

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

subscribeLabels implementation

futurGH 31a4c304 0c19eaa1

+394 -27
+9 -5
package.json
··· 24 24 "@atproto/api": "^0.13.1", 25 25 "@types/better-sqlite3": "^7.6.11", 26 26 "@types/express": "^4.17.21", 27 + "@types/express-ws": "^3.0.4", 27 28 "@types/node": "^20.11.19", 29 + "@types/ws": "^8.5.12", 28 30 "@typescript-eslint/eslint-plugin": "^6.7.4", 29 31 "@typescript-eslint/parser": "^6.7.4", 30 32 "dprint": "^0.41.0", 31 33 "eslint": "^8.50.0", 32 34 "typescript": "^5.2.2" 33 35 }, 34 - "files": [ 35 - "dist" 36 - ], 37 36 "dependencies": { 37 + "@atproto/xrpc-server": "^0.6.2", 38 38 "better-sqlite3": "^11.1.2", 39 - "express": "^4.19.2" 40 - } 39 + "express": "^4.19.2", 40 + "express-ws": "^5.0.2" 41 + }, 42 + "files": [ 43 + "dist" 44 + ] 41 45 }
+328 -9
pnpm-lock.yaml
··· 5 5 excludeLinksFromLockfile: false 6 6 7 7 dependencies: 8 + '@atproto/xrpc-server': 9 + specifier: ^0.6.2 10 + version: 0.6.2 8 11 better-sqlite3: 9 12 specifier: ^11.1.2 10 13 version: 11.1.2 11 14 express: 12 15 specifier: ^4.19.2 13 16 version: 4.19.2 17 + express-ws: 18 + specifier: ^5.0.2 19 + version: 5.0.2(express@4.19.2) 14 20 15 21 devDependencies: 16 22 '@atproto/api': ··· 22 28 '@types/express': 23 29 specifier: ^4.17.21 24 30 version: 4.17.21 31 + '@types/express-ws': 32 + specifier: ^3.0.4 33 + version: 3.0.4 25 34 '@types/node': 26 35 specifier: ^20.11.19 27 36 version: 20.11.19 37 + '@types/ws': 38 + specifier: ^8.5.12 39 + version: 8.5.12 28 40 '@typescript-eslint/eslint-plugin': 29 41 specifier: ^6.7.4 30 42 version: 6.7.4(@typescript-eslint/parser@6.7.4)(eslint@8.50.0)(typescript@5.2.2) ··· 67 79 multiformats: 9.9.0 68 80 uint8arrays: 3.0.0 69 81 zod: 3.23.8 70 - dev: true 82 + 83 + /@atproto/common@0.4.1: 84 + resolution: {integrity: sha512-uL7kQIcBTbvkBDNfxMXL6lBH4fO2DQpHd2BryJxMtbw/4iEPKe9xBYApwECHhEIk9+zhhpTRZ15FJ3gxTXN82Q==} 85 + dependencies: 86 + '@atproto/common-web': 0.3.0 87 + '@ipld/dag-cbor': 7.0.3 88 + cbor-x: 1.6.0 89 + iso-datestring-validator: 2.2.2 90 + multiformats: 9.9.0 91 + pino: 8.21.0 92 + dev: false 93 + 94 + /@atproto/crypto@0.4.0: 95 + resolution: {integrity: sha512-Kj/4VgJ7hzzXvE42L0rjzP6lM0tai+OfPnP1rxJ+UZg/YUDtuewL4uapnVoWXvlNceKgaLZH98g5n9gXBVTe5Q==} 96 + dependencies: 97 + '@noble/curves': 1.5.0 98 + '@noble/hashes': 1.4.0 99 + uint8arrays: 3.0.0 100 + dev: false 71 101 72 102 /@atproto/lexicon@0.4.1: 73 103 resolution: {integrity: sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA==} ··· 77 107 iso-datestring-validator: 2.2.2 78 108 multiformats: 9.9.0 79 109 zod: 3.23.8 80 - dev: true 81 110 82 111 /@atproto/syntax@0.3.0: 83 112 resolution: {integrity: sha512-Weq0ZBxffGHDXHl9U7BQc2BFJi/e23AL+k+i5+D9hUq/bzT4yjGsrCejkjq0xt82xXDjmhhvQSZ0LqxyZ5woxA==} 84 - dev: true 113 + 114 + /@atproto/xrpc-server@0.6.2: 115 + resolution: {integrity: sha512-WuY0fCU/GHp1Obeikh+G4a39HnvhoxFndhQgA4Nb2hh1YOnPN48RHsGOctwA63N11mqk0pGX24vP56ozz0DbFw==} 116 + dependencies: 117 + '@atproto/common': 0.4.1 118 + '@atproto/crypto': 0.4.0 119 + '@atproto/lexicon': 0.4.1 120 + '@atproto/xrpc': 0.6.0 121 + cbor-x: 1.6.0 122 + express: 4.19.2 123 + http-errors: 2.0.0 124 + mime-types: 2.1.35 125 + rate-limiter-flexible: 2.4.2 126 + uint8arrays: 3.0.0 127 + ws: 8.18.0 128 + zod: 3.23.8 129 + transitivePeerDependencies: 130 + - bufferutil 131 + - supports-color 132 + - utf-8-validate 133 + dev: false 85 134 86 135 /@atproto/xrpc@0.6.0: 87 136 resolution: {integrity: sha512-5BbhBTv5j6MC3iIQ4+vYxQE7nLy2dDGQ+LYJrH8PptOCUdq0Pwg6aRccQ3y52kUZlhE/mzOTZ8Ngiy9pSAyfVQ==} 88 137 dependencies: 89 138 '@atproto/lexicon': 0.4.1 90 139 zod: 3.23.8 91 - dev: true 140 + 141 + /@cbor-extract/cbor-extract-darwin-arm64@2.2.0: 142 + resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==} 143 + cpu: [arm64] 144 + os: [darwin] 145 + requiresBuild: true 146 + dev: false 147 + optional: true 148 + 149 + /@cbor-extract/cbor-extract-darwin-x64@2.2.0: 150 + resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==} 151 + cpu: [x64] 152 + os: [darwin] 153 + requiresBuild: true 154 + dev: false 155 + optional: true 156 + 157 + /@cbor-extract/cbor-extract-linux-arm64@2.2.0: 158 + resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==} 159 + cpu: [arm64] 160 + os: [linux] 161 + requiresBuild: true 162 + dev: false 163 + optional: true 164 + 165 + /@cbor-extract/cbor-extract-linux-arm@2.2.0: 166 + resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==} 167 + cpu: [arm] 168 + os: [linux] 169 + requiresBuild: true 170 + dev: false 171 + optional: true 172 + 173 + /@cbor-extract/cbor-extract-linux-x64@2.2.0: 174 + resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==} 175 + cpu: [x64] 176 + os: [linux] 177 + requiresBuild: true 178 + dev: false 179 + optional: true 180 + 181 + /@cbor-extract/cbor-extract-win32-x64@2.2.0: 182 + resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==} 183 + cpu: [x64] 184 + os: [win32] 185 + requiresBuild: true 186 + dev: false 187 + optional: true 92 188 93 189 /@dprint/darwin-arm64@0.41.0: 94 190 resolution: {integrity: sha512-P9PtcQI0mrI4U6yyd+/iI664BHSqC9KTS6ogq0ptEdnLtlaWzf09D1nv6FBaHiG9m3conuBRlPsoUqt3j6PZ2w==} ··· 195 291 resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} 196 292 dev: true 197 293 294 + /@ipld/dag-cbor@7.0.3: 295 + resolution: {integrity: sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA==} 296 + dependencies: 297 + cborg: 1.10.2 298 + multiformats: 9.9.0 299 + dev: false 300 + 301 + /@noble/curves@1.5.0: 302 + resolution: {integrity: sha512-J5EKamIHnKPyClwVrzmaf5wSdQXgdHcPZIZLu3bwnbeCx8/7NPK5q2ZBWF+5FvYGByjiQQsJYX6jfgB2wDPn3A==} 303 + dependencies: 304 + '@noble/hashes': 1.4.0 305 + dev: false 306 + 307 + /@noble/hashes@1.4.0: 308 + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} 309 + engines: {node: '>= 16'} 310 + dev: false 311 + 198 312 /@nodelib/fs.scandir@2.1.5: 199 313 resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 200 314 engines: {node: '>= 8'} ··· 244 358 '@types/send': 0.17.4 245 359 dev: true 246 360 361 + /@types/express-ws@3.0.4: 362 + resolution: {integrity: sha512-Yjj18CaivG5KndgcvzttWe8mPFinPCHJC2wvyQqVzA7hqeufM8EtWMj6mpp5omg3s8XALUexhOu8aXAyi/DyJQ==} 363 + dependencies: 364 + '@types/express': 4.17.21 365 + '@types/express-serve-static-core': 4.19.5 366 + '@types/ws': 8.5.12 367 + dev: true 368 + 247 369 /@types/express@4.17.21: 248 370 resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} 249 371 dependencies: ··· 296 418 '@types/http-errors': 2.0.4 297 419 '@types/node': 20.11.19 298 420 '@types/send': 0.17.4 421 + dev: true 422 + 423 + /@types/ws@8.5.12: 424 + resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} 425 + dependencies: 426 + '@types/node': 20.11.19 299 427 dev: true 300 428 301 429 /@typescript-eslint/eslint-plugin@6.7.4(@typescript-eslint/parser@6.7.4)(eslint@8.50.0)(typescript@5.2.2): ··· 429 557 eslint-visitor-keys: 3.4.3 430 558 dev: true 431 559 560 + /abort-controller@3.0.0: 561 + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} 562 + engines: {node: '>=6.5'} 563 + dependencies: 564 + event-target-shim: 5.0.1 565 + dev: false 566 + 432 567 /accepts@1.3.8: 433 568 resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} 434 569 engines: {node: '>= 0.6'} ··· 484 619 resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 485 620 engines: {node: '>=8'} 486 621 dev: true 622 + 623 + /atomic-sleep@1.0.0: 624 + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} 625 + engines: {node: '>=8.0.0'} 626 + dev: false 487 627 488 628 /await-lock@2.2.2: 489 629 resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} ··· 560 700 ieee754: 1.2.1 561 701 dev: false 562 702 703 + /buffer@6.0.3: 704 + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} 705 + dependencies: 706 + base64-js: 1.5.1 707 + ieee754: 1.2.1 708 + dev: false 709 + 563 710 /bytes@3.1.2: 564 711 resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} 565 712 engines: {node: '>= 0.8'} ··· 581 728 engines: {node: '>=6'} 582 729 dev: true 583 730 731 + /cbor-extract@2.2.0: 732 + resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==} 733 + hasBin: true 734 + requiresBuild: true 735 + dependencies: 736 + node-gyp-build-optional-packages: 5.1.1 737 + optionalDependencies: 738 + '@cbor-extract/cbor-extract-darwin-arm64': 2.2.0 739 + '@cbor-extract/cbor-extract-darwin-x64': 2.2.0 740 + '@cbor-extract/cbor-extract-linux-arm': 2.2.0 741 + '@cbor-extract/cbor-extract-linux-arm64': 2.2.0 742 + '@cbor-extract/cbor-extract-linux-x64': 2.2.0 743 + '@cbor-extract/cbor-extract-win32-x64': 2.2.0 744 + dev: false 745 + optional: true 746 + 747 + /cbor-x@1.6.0: 748 + resolution: {integrity: sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==} 749 + optionalDependencies: 750 + cbor-extract: 2.2.0 751 + dev: false 752 + 753 + /cborg@1.10.2: 754 + resolution: {integrity: sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug==} 755 + hasBin: true 756 + dev: false 757 + 584 758 /chalk@4.1.2: 585 759 resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 586 760 engines: {node: '>=10'} ··· 861 1035 engines: {node: '>= 0.6'} 862 1036 dev: false 863 1037 1038 + /event-target-shim@5.0.1: 1039 + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} 1040 + engines: {node: '>=6'} 1041 + dev: false 1042 + 1043 + /events@3.3.0: 1044 + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} 1045 + engines: {node: '>=0.8.x'} 1046 + dev: false 1047 + 864 1048 /expand-template@2.0.3: 865 1049 resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} 866 1050 engines: {node: '>=6'} 1051 + dev: false 1052 + 1053 + /express-ws@5.0.2(express@4.19.2): 1054 + resolution: {integrity: sha512-0uvmuk61O9HXgLhGl3QhNSEtRsQevtmbL94/eILaliEADZBHZOQUAiHFrGPrgsjikohyrmSG5g+sCfASTt0lkQ==} 1055 + engines: {node: '>=4.5.0'} 1056 + peerDependencies: 1057 + express: ^4.0.0 || ^5.0.0-alpha.1 1058 + dependencies: 1059 + express: 4.19.2 1060 + ws: 7.5.10 1061 + transitivePeerDependencies: 1062 + - bufferutil 1063 + - utf-8-validate 867 1064 dev: false 868 1065 869 1066 /express@4.19.2: ··· 927 1124 /fast-levenshtein@2.0.6: 928 1125 resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 929 1126 dev: true 1127 + 1128 + /fast-redact@3.5.0: 1129 + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} 1130 + engines: {node: '>=6'} 1131 + dev: false 930 1132 931 1133 /fastq@1.17.1: 932 1134 resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} ··· 1077 1279 1078 1280 /graphemer@1.4.0: 1079 1281 resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 1080 - dev: true 1081 1282 1082 1283 /has-flag@4.0.0: 1083 1284 resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} ··· 1194 1395 1195 1396 /iso-datestring-validator@2.2.2: 1196 1397 resolution: {integrity: sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==} 1197 - dev: true 1198 1398 1199 1399 /js-yaml@4.1.0: 1200 1400 resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} ··· 1324 1524 1325 1525 /multiformats@9.9.0: 1326 1526 resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} 1327 - dev: true 1328 1527 1329 1528 /napi-build-utils@1.0.2: 1330 1529 resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} ··· 1346 1545 semver: 7.6.0 1347 1546 dev: false 1348 1547 1548 + /node-gyp-build-optional-packages@5.1.1: 1549 + resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==} 1550 + hasBin: true 1551 + dependencies: 1552 + detect-libc: 2.0.3 1553 + dev: false 1554 + optional: true 1555 + 1349 1556 /object-inspect@1.13.2: 1350 1557 resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} 1351 1558 engines: {node: '>= 0.4'} 1559 + dev: false 1560 + 1561 + /on-exit-leak-free@2.1.2: 1562 + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} 1563 + engines: {node: '>=14.0.0'} 1352 1564 dev: false 1353 1565 1354 1566 /on-finished@2.4.1: ··· 1430 1642 engines: {node: '>=8.6'} 1431 1643 dev: true 1432 1644 1645 + /pino-abstract-transport@1.2.0: 1646 + resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==} 1647 + dependencies: 1648 + readable-stream: 4.5.2 1649 + split2: 4.2.0 1650 + dev: false 1651 + 1652 + /pino-std-serializers@6.2.2: 1653 + resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} 1654 + dev: false 1655 + 1656 + /pino@8.21.0: 1657 + resolution: {integrity: sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==} 1658 + hasBin: true 1659 + dependencies: 1660 + atomic-sleep: 1.0.0 1661 + fast-redact: 3.5.0 1662 + on-exit-leak-free: 2.1.2 1663 + pino-abstract-transport: 1.2.0 1664 + pino-std-serializers: 6.2.2 1665 + process-warning: 3.0.0 1666 + quick-format-unescaped: 4.0.4 1667 + real-require: 0.2.0 1668 + safe-stable-stringify: 2.4.3 1669 + sonic-boom: 3.8.1 1670 + thread-stream: 2.7.0 1671 + dev: false 1672 + 1433 1673 /prebuild-install@7.1.2: 1434 1674 resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} 1435 1675 engines: {node: '>=10'} ··· 1454 1694 engines: {node: '>= 0.8.0'} 1455 1695 dev: true 1456 1696 1697 + /process-warning@3.0.0: 1698 + resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} 1699 + dev: false 1700 + 1701 + /process@0.11.10: 1702 + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} 1703 + engines: {node: '>= 0.6.0'} 1704 + dev: false 1705 + 1457 1706 /proxy-addr@2.0.7: 1458 1707 resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} 1459 1708 engines: {node: '>= 0.10'} ··· 1485 1734 resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1486 1735 dev: true 1487 1736 1737 + /quick-format-unescaped@4.0.4: 1738 + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} 1739 + dev: false 1740 + 1488 1741 /range-parser@1.2.1: 1489 1742 resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} 1490 1743 engines: {node: '>= 0.6'} 1744 + dev: false 1745 + 1746 + /rate-limiter-flexible@2.4.2: 1747 + resolution: {integrity: sha512-rMATGGOdO1suFyf/mI5LYhts71g1sbdhmd6YvdiXO2gJnd42Tt6QS4JUKJKSWVVkMtBacm6l40FR7Trjo6Iruw==} 1491 1748 dev: false 1492 1749 1493 1750 /raw-body@2.5.2: ··· 1519 1776 util-deprecate: 1.0.2 1520 1777 dev: false 1521 1778 1779 + /readable-stream@4.5.2: 1780 + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} 1781 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1782 + dependencies: 1783 + abort-controller: 3.0.0 1784 + buffer: 6.0.3 1785 + events: 3.3.0 1786 + process: 0.11.10 1787 + string_decoder: 1.3.0 1788 + dev: false 1789 + 1790 + /real-require@0.2.0: 1791 + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} 1792 + engines: {node: '>= 12.13.0'} 1793 + dev: false 1794 + 1522 1795 /resolve-from@4.0.0: 1523 1796 resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1524 1797 engines: {node: '>=4'} ··· 1544 1817 1545 1818 /safe-buffer@5.2.1: 1546 1819 resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 1820 + dev: false 1821 + 1822 + /safe-stable-stringify@2.4.3: 1823 + resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} 1824 + engines: {node: '>=10'} 1547 1825 dev: false 1548 1826 1549 1827 /safer-buffer@2.1.2: ··· 1645 1923 engines: {node: '>=8'} 1646 1924 dev: true 1647 1925 1926 + /sonic-boom@3.8.1: 1927 + resolution: {integrity: sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==} 1928 + dependencies: 1929 + atomic-sleep: 1.0.0 1930 + dev: false 1931 + 1932 + /split2@4.2.0: 1933 + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} 1934 + engines: {node: '>= 10.x'} 1935 + dev: false 1936 + 1648 1937 /statuses@2.0.1: 1649 1938 resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} 1650 1939 engines: {node: '>= 0.8'} ··· 1704 1993 resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 1705 1994 dev: true 1706 1995 1996 + /thread-stream@2.7.0: 1997 + resolution: {integrity: sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==} 1998 + dependencies: 1999 + real-require: 0.2.0 2000 + dev: false 2001 + 1707 2002 /tlds@1.254.0: 1708 2003 resolution: {integrity: sha512-YY4ei7K7gPGifqNSrfMaPdqTqiHcwYKUJ7zhLqQOK2ildlGgti5TSwJiXXN1YqG17I2GYZh5cZqv2r5fwBUM+w==} 1709 2004 hasBin: true ··· 1766 2061 resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==} 1767 2062 dependencies: 1768 2063 multiformats: 9.9.0 1769 - dev: true 1770 2064 1771 2065 /undici-types@5.26.5: 1772 2066 resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} ··· 1808 2102 /wrappy@1.0.2: 1809 2103 resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 1810 2104 2105 + /ws@7.5.10: 2106 + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} 2107 + engines: {node: '>=8.3.0'} 2108 + peerDependencies: 2109 + bufferutil: ^4.0.1 2110 + utf-8-validate: ^5.0.2 2111 + peerDependenciesMeta: 2112 + bufferutil: 2113 + optional: true 2114 + utf-8-validate: 2115 + optional: true 2116 + dev: false 2117 + 2118 + /ws@8.18.0: 2119 + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} 2120 + engines: {node: '>=10.0.0'} 2121 + peerDependencies: 2122 + bufferutil: ^4.0.1 2123 + utf-8-validate: '>=5.0.2' 2124 + peerDependenciesMeta: 2125 + bufferutil: 2126 + optional: true 2127 + utf-8-validate: 2128 + optional: true 2129 + dev: false 2130 + 1811 2131 /yallist@4.0.0: 1812 2132 resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1813 2133 ··· 1818 2138 1819 2139 /zod@3.23.8: 1820 2140 resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} 1821 - dev: true
+57 -13
src/LabelerServer.ts
··· 1 - import express, { type Express } from "express"; 1 + import type { ComAtprotoLabelDefs } from "@atproto/api"; 2 + import { ErrorFrame, MessageFrame } from "@atproto/xrpc-server"; 2 3 import Database, { type Database as SQLiteDatabase } from "better-sqlite3"; 4 + import express from "express"; 5 + import expressWs, { type Application, WebsocketRequestHandler } from "express-ws"; 6 + import { Server } from "node:http"; 7 + import type { WebSocket } from "ws"; 3 8 4 9 export interface LabelerOptions { 5 10 did: string; ··· 7 12 } 8 13 9 14 export class LabelerServer { 10 - app: Express = express(); 15 + app: Application; 16 + 17 + server?: Server; 11 18 12 19 db: SQLiteDatabase; 13 20 14 21 did: string; 15 22 23 + private subscriptions = new Set<WebSocket>(); 24 + 16 25 constructor(options: LabelerOptions) { 17 26 this.did = options.did; 27 + 18 28 this.db = new Database(options.dbFile ?? "labels.db"); 29 + this.db.pragma("journal_mode = WAL"); 19 30 this.db.exec(` 20 31 CREATE TABLE IF NOT EXISTS labels ( 21 32 id INTEGER PRIMARY KEY AUTOINCREMENT, ··· 29 40 sig BLOB 30 41 ); 31 42 `); 43 + 44 + this.app = expressWs(express().use(express.json())).app; 45 + this.app.ws("/xrpc/com.atproto.label.subscribeLabels", this.subscribeLabelsHandler); 32 46 } 33 47 48 + start(port = 443, callback?: () => void) { 49 + this.server = this.app.listen(port, callback); 50 + } 34 51 35 - } 52 + stop(callback?: () => void) { 53 + if (this.server?.listening) this.server?.close(callback); 54 + } 36 55 37 - export interface Label { 38 - ver?: number; 39 - src: string; 40 - uri: string; 41 - cid?: string; 42 - val: string; 43 - neg?: boolean; 44 - cts: string; 45 - exp?: string; 46 - sig?: Buffer 56 + subscribeLabelsHandler: WebsocketRequestHandler = async (ws, req) => { 57 + const cursor = parseInt(req.params.cursor); 58 + 59 + if (cursor && !Number.isNaN(cursor)) { 60 + const latest = this.db.prepare(` 61 + SELECT MAX(id) AS id FROM labels 62 + `).get() as { id: number }; 63 + if (cursor > (latest.id ?? 0)) { 64 + const errorFrame = new ErrorFrame({ 65 + error: "FutureCursor", 66 + message: "Cursor is in the future", 67 + }); 68 + ws.send(errorFrame.toBytes()); 69 + ws.terminate(); 70 + } 71 + 72 + const stmt = this.db.prepare<[number], ComAtprotoLabelDefs.Label>(` 73 + SELECT * FROM labels 74 + WHERE id > ? 75 + ORDER BY id ASC 76 + `); 77 + 78 + for (const row of stmt.iterate(cursor)) { 79 + const { id: seq, ...label } = row; 80 + const frame = new MessageFrame({ seq, labels: [label] }, { type: "#labels" }); 81 + ws.send(frame.toBytes()); 82 + } 83 + } 84 + 85 + this.subscriptions.add(ws); 86 + 87 + ws.on("close", () => { 88 + this.subscriptions.delete(ws); 89 + }); 90 + }; 47 91 }