[READ ONLY MIRROR] Spark Social AppView Server github.com/sprksocial/server
atproto deno hono lexicon
5
fork

Configure Feed

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

rm feedgen (#14)

authored by

Davi Rodrigues and committed by
GitHub
61008ff1 c1ab2580

-1052
-5
services/feed-gen/.dockerignore
··· 1 - node_modules/ 2 - .idea/ 3 - .env 4 - .git 5 - dist
-4
services/feed-gen/.gitignore
··· 1 - # deps 2 - node_modules/ 3 - dist 4 - .env
-17
services/feed-gen/Dockerfile
··· 1 - FROM oven/bun:1-alpine AS builder 2 - WORKDIR /app 3 - COPY package.json bun.lock ./ 4 - RUN bun install --frozen-lockfile 5 - COPY . . 6 - RUN bun run build 7 - 8 - FROM oven/bun:1-alpine 9 - WORKDIR /app 10 - COPY --from=builder /app/dist ./dist 11 - COPY --from=builder /app/package.json ./ 12 - COPY --from=builder /app/bun.lock ./ 13 - RUN bun install --production --frozen-lockfile 14 - 15 - ENV NODE_ENV=production 16 - EXPOSE 3000 17 - CMD ["bun", "run", "start"]
-11
services/feed-gen/README.md
··· 1 - To install dependencies: 2 - ```sh 3 - bun install 4 - ``` 5 - 6 - To run: 7 - ```sh 8 - bun run dev 9 - ``` 10 - 11 - open http://localhost:3000
-356
services/feed-gen/bun.lock
··· 1 - { 2 - "lockfileVersion": 1, 3 - "workspaces": { 4 - "": { 5 - "name": "feed-gen", 6 - "dependencies": { 7 - "@atproto/identity": "^0.4.6", 8 - "@atproto/xrpc-server": "^0.7.13", 9 - "dotenv": "^16.4.7", 10 - "envalid": "^8.0.0", 11 - "hono": "^4.7.4", 12 - "mongoose": "^8.12.1", 13 - "pino": "^9.6.0", 14 - "pino-pretty": "^13.0.0", 15 - }, 16 - "devDependencies": { 17 - "@types/bun": "latest", 18 - }, 19 - }, 20 - }, 21 - "packages": { 22 - "@atproto/common": ["@atproto/common@0.4.8", "", { "dependencies": { "@atproto/common-web": "^0.4.0", "@ipld/dag-cbor": "^7.0.3", "cbor-x": "^1.5.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, "sha512-/etCtnWQGLcfiGhIPwxAWrzgzoGB22nMWMeQcU6xZgRT4Cqrfg3A08jAMIHqve/AQpL+6D82lHYp36CG7a5G0w=="], 23 - 24 - "@atproto/common-web": ["@atproto/common-web@0.4.0", "", { "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, "sha512-ZYL0P9myHybNgwh/hBY0HaBzqiLR1B5/ie5bJpLQAg0whRzNA28t8/nU2vh99tbsWcAF0LOD29M8++LyENJLNQ=="], 25 - 26 - "@atproto/crypto": ["@atproto/crypto@0.4.4", "", { "dependencies": { "@noble/curves": "^1.7.0", "@noble/hashes": "^1.6.1", "uint8arrays": "3.0.0" } }, "sha512-Yq9+crJ7WQl7sxStVpHgie5Z51R05etaK9DLWYG/7bR5T4bhdcIgF6IfklLShtZwLYdVVj+K15s0BqW9a8PSDA=="], 27 - 28 - "@atproto/identity": ["@atproto/identity@0.4.6", "", { "dependencies": { "@atproto/common-web": "^0.4.0", "@atproto/crypto": "^0.4.4" } }, "sha512-fJq/cIp9MOgHxZfxuyki6mobk0QxRnbts53DstRixlvb5mOoxwttb9Gp6A8u9q49zBsfOmXNTHmP97I9iMHmTQ=="], 29 - 30 - "@atproto/lexicon": ["@atproto/lexicon@0.4.9", "", { "dependencies": { "@atproto/common-web": "^0.4.0", "@atproto/syntax": "^0.4.0", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-/tmEuHQFr51V2V7EAVJzaA40sqJ7ylAZpR962VbOsPtmcdOHvezbjVHYEMXgfb927hS+xqbVyzBTbu5w9v8prA=="], 31 - 32 - "@atproto/syntax": ["@atproto/syntax@0.4.0", "", {}, "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA=="], 33 - 34 - "@atproto/xrpc": ["@atproto/xrpc@0.6.11", "", { "dependencies": { "@atproto/lexicon": "^0.4.9", "zod": "^3.23.8" } }, "sha512-J2cZP8FjoDN0UkyTYBlCvKvxwBbDm4dld47u6FQK30RJy9YpSiUkdxJJ10NYqpi7JVny3M0qWQgpWJDV94+PdA=="], 35 - 36 - "@atproto/xrpc-server": ["@atproto/xrpc-server@0.7.13", "", { "dependencies": { "@atproto/common": "^0.4.8", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.4.9", "@atproto/xrpc": "^0.6.11", "cbor-x": "^1.5.1", "express": "^4.17.2", "http-errors": "^2.0.0", "mime-types": "^2.1.35", "rate-limiter-flexible": "^2.4.1", "uint8arrays": "3.0.0", "ws": "^8.12.0", "zod": "^3.23.8" } }, "sha512-gaaAentq1lhAFBHwh2N0EhbNsb1mWrmEXoxmtuXp3uEV4Q7EMFaZYO25B9/Yos5oAsnpK54LIYUamHuJQVWGOA=="], 37 - 38 - "@cbor-extract/cbor-extract-darwin-arm64": ["@cbor-extract/cbor-extract-darwin-arm64@2.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w=="], 39 - 40 - "@cbor-extract/cbor-extract-darwin-x64": ["@cbor-extract/cbor-extract-darwin-x64@2.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w=="], 41 - 42 - "@cbor-extract/cbor-extract-linux-arm": ["@cbor-extract/cbor-extract-linux-arm@2.2.0", "", { "os": "linux", "cpu": "arm" }, "sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q=="], 43 - 44 - "@cbor-extract/cbor-extract-linux-arm64": ["@cbor-extract/cbor-extract-linux-arm64@2.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ=="], 45 - 46 - "@cbor-extract/cbor-extract-linux-x64": ["@cbor-extract/cbor-extract-linux-x64@2.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw=="], 47 - 48 - "@cbor-extract/cbor-extract-win32-x64": ["@cbor-extract/cbor-extract-win32-x64@2.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w=="], 49 - 50 - "@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA=="], 51 - 52 - "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.2.0", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg=="], 53 - 54 - "@noble/curves": ["@noble/curves@1.8.1", "", { "dependencies": { "@noble/hashes": "1.7.1" } }, "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ=="], 55 - 56 - "@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="], 57 - 58 - "@types/bun": ["@types/bun@1.2.5", "", { "dependencies": { "bun-types": "1.2.5" } }, "sha512-w2OZTzrZTVtbnJew1pdFmgV99H0/L+Pvw+z1P67HaR18MHOzYnTYOi6qzErhK8HyT+DB782ADVPPE92Xu2/Opg=="], 59 - 60 - "@types/node": ["@types/node@22.13.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw=="], 61 - 62 - "@types/webidl-conversions": ["@types/webidl-conversions@7.0.3", "", {}, "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="], 63 - 64 - "@types/whatwg-url": ["@types/whatwg-url@11.0.5", "", { "dependencies": { "@types/webidl-conversions": "*" } }, "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ=="], 65 - 66 - "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], 67 - 68 - "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], 69 - 70 - "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], 71 - 72 - "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], 73 - 74 - "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], 75 - 76 - "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], 77 - 78 - "body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="], 79 - 80 - "bson": ["bson@6.10.3", "", {}, "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ=="], 81 - 82 - "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], 83 - 84 - "bun-types": ["bun-types@1.2.5", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg=="], 85 - 86 - "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], 87 - 88 - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], 89 - 90 - "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], 91 - 92 - "cbor-extract": ["cbor-extract@2.2.0", "", { "dependencies": { "node-gyp-build-optional-packages": "5.1.1" }, "optionalDependencies": { "@cbor-extract/cbor-extract-darwin-arm64": "2.2.0", "@cbor-extract/cbor-extract-darwin-x64": "2.2.0", "@cbor-extract/cbor-extract-linux-arm": "2.2.0", "@cbor-extract/cbor-extract-linux-arm64": "2.2.0", "@cbor-extract/cbor-extract-linux-x64": "2.2.0", "@cbor-extract/cbor-extract-win32-x64": "2.2.0" }, "bin": { "download-cbor-prebuilds": "bin/download-prebuilds.js" } }, "sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA=="], 93 - 94 - "cbor-x": ["cbor-x@1.6.0", "", { "optionalDependencies": { "cbor-extract": "^2.2.0" } }, "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg=="], 95 - 96 - "cborg": ["cborg@1.10.2", "", { "bin": { "cborg": "cli.js" } }, "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug=="], 97 - 98 - "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], 99 - 100 - "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], 101 - 102 - "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], 103 - 104 - "cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], 105 - 106 - "cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="], 107 - 108 - "dateformat": ["dateformat@4.6.3", "", {}, "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA=="], 109 - 110 - "debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], 111 - 112 - "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], 113 - 114 - "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], 115 - 116 - "detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="], 117 - 118 - "dotenv": ["dotenv@16.4.7", "", {}, "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ=="], 119 - 120 - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], 121 - 122 - "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], 123 - 124 - "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], 125 - 126 - "end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="], 127 - 128 - "envalid": ["envalid@8.0.0", "", { "dependencies": { "tslib": "2.6.2" } }, "sha512-PGeYJnJB5naN0ME6SH8nFcDj9HVbLpYIfg1p5lAyM9T4cH2lwtu2fLbozC/bq+HUUOIFxhX/LP0/GmlqPHT4tQ=="], 129 - 130 - "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], 131 - 132 - "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], 133 - 134 - "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], 135 - 136 - "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], 137 - 138 - "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], 139 - 140 - "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], 141 - 142 - "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], 143 - 144 - "express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], 145 - 146 - "fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="], 147 - 148 - "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], 149 - 150 - "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], 151 - 152 - "finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ=="], 153 - 154 - "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], 155 - 156 - "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], 157 - 158 - "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], 159 - 160 - "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], 161 - 162 - "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], 163 - 164 - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], 165 - 166 - "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], 167 - 168 - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], 169 - 170 - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], 171 - 172 - "help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="], 173 - 174 - "hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="], 175 - 176 - "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], 177 - 178 - "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], 179 - 180 - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], 181 - 182 - "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], 183 - 184 - "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], 185 - 186 - "iso-datestring-validator": ["iso-datestring-validator@2.2.2", "", {}, "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA=="], 187 - 188 - "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], 189 - 190 - "kareem": ["kareem@2.6.3", "", {}, "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q=="], 191 - 192 - "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], 193 - 194 - "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], 195 - 196 - "memory-pager": ["memory-pager@1.5.0", "", {}, "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="], 197 - 198 - "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], 199 - 200 - "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], 201 - 202 - "mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], 203 - 204 - "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], 205 - 206 - "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], 207 - 208 - "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], 209 - 210 - "mongodb": ["mongodb@6.14.2", "", { "dependencies": { "@mongodb-js/saslprep": "^1.1.9", "bson": "^6.10.3", "mongodb-connection-string-url": "^3.0.0" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", "mongodb-client-encryption": ">=6.0.0 <7", "snappy": "^7.2.2", "socks": "^2.7.1" }, "optionalPeers": ["@aws-sdk/credential-providers", "@mongodb-js/zstd", "gcp-metadata", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-kMEHNo0F3P6QKDq17zcDuPeaywK/YaJVCEQRzPF3TOM/Bl9MFg64YE5Tu7ifj37qZJMhwU1tl2Ioivws5gRG5Q=="], 211 - 212 - "mongodb-connection-string-url": ["mongodb-connection-string-url@3.0.2", "", { "dependencies": { "@types/whatwg-url": "^11.0.2", "whatwg-url": "^14.1.0 || ^13.0.0" } }, "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA=="], 213 - 214 - "mongoose": ["mongoose@8.12.1", "", { "dependencies": { "bson": "^6.10.3", "kareem": "2.6.3", "mongodb": "~6.14.0", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", "sift": "17.1.3" } }, "sha512-UW22y8QFVYmrb36hm8cGncfn4ARc/XsYWQwRTaj0gxtQk1rDuhzDO1eBantS+hTTatfAIS96LlRCJrcNHvW5+Q=="], 215 - 216 - "mpath": ["mpath@0.9.0", "", {}, "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew=="], 217 - 218 - "mquery": ["mquery@5.0.0", "", { "dependencies": { "debug": "4.x" } }, "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg=="], 219 - 220 - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 221 - 222 - "multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 223 - 224 - "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], 225 - 226 - "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.1.1", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-test": "build-test.js", "node-gyp-build-optional-packages-optional": "optional.js" } }, "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw=="], 227 - 228 - "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], 229 - 230 - "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], 231 - 232 - "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], 233 - 234 - "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], 235 - 236 - "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], 237 - 238 - "path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="], 239 - 240 - "pino": ["pino@9.6.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^4.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg=="], 241 - 242 - "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], 243 - 244 - "pino-pretty": ["pino-pretty@13.0.0", "", { "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", "fast-copy": "^3.0.2", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pump": "^3.0.0", "secure-json-parse": "^2.4.0", "sonic-boom": "^4.0.1", "strip-json-comments": "^3.1.1" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA=="], 245 - 246 - "pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="], 247 - 248 - "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], 249 - 250 - "process-warning": ["process-warning@4.0.1", "", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="], 251 - 252 - "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], 253 - 254 - "pump": ["pump@3.0.2", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw=="], 255 - 256 - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], 257 - 258 - "qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], 259 - 260 - "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], 261 - 262 - "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], 263 - 264 - "rate-limiter-flexible": ["rate-limiter-flexible@2.4.2", "", {}, "sha512-rMATGGOdO1suFyf/mI5LYhts71g1sbdhmd6YvdiXO2gJnd42Tt6QS4JUKJKSWVVkMtBacm6l40FR7Trjo6Iruw=="], 265 - 266 - "raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="], 267 - 268 - "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], 269 - 270 - "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], 271 - 272 - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], 273 - 274 - "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], 275 - 276 - "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], 277 - 278 - "secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], 279 - 280 - "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], 281 - 282 - "serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="], 283 - 284 - "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], 285 - 286 - "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], 287 - 288 - "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], 289 - 290 - "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], 291 - 292 - "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], 293 - 294 - "sift": ["sift@17.1.3", "", {}, "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ=="], 295 - 296 - "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], 297 - 298 - "sparse-bitfield": ["sparse-bitfield@3.0.3", "", { "dependencies": { "memory-pager": "^1.0.2" } }, "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ=="], 299 - 300 - "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], 301 - 302 - "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], 303 - 304 - "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], 305 - 306 - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], 307 - 308 - "thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="], 309 - 310 - "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], 311 - 312 - "tr46": ["tr46@5.1.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw=="], 313 - 314 - "tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="], 315 - 316 - "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], 317 - 318 - "uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA=="], 319 - 320 - "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], 321 - 322 - "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], 323 - 324 - "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], 325 - 326 - "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], 327 - 328 - "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], 329 - 330 - "whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="], 331 - 332 - "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], 333 - 334 - "ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="], 335 - 336 - "zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], 337 - 338 - "@atproto/common/pino": ["pino@8.21.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^1.2.0", "pino-std-serializers": "^6.0.0", "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^3.7.0", "thread-stream": "^2.6.0" }, "bin": { "pino": "bin.js" } }, "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q=="], 339 - 340 - "debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], 341 - 342 - "mquery/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], 343 - 344 - "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], 345 - 346 - "@atproto/common/pino/pino-abstract-transport": ["pino-abstract-transport@1.2.0", "", { "dependencies": { "readable-stream": "^4.0.0", "split2": "^4.0.0" } }, "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q=="], 347 - 348 - "@atproto/common/pino/pino-std-serializers": ["pino-std-serializers@6.2.2", "", {}, "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA=="], 349 - 350 - "@atproto/common/pino/process-warning": ["process-warning@3.0.0", "", {}, "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ=="], 351 - 352 - "@atproto/common/pino/sonic-boom": ["sonic-boom@3.8.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg=="], 353 - 354 - "@atproto/common/pino/thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="], 355 - } 356 - }
-22
services/feed-gen/package.json
··· 1 - { 2 - "name": "feed-gen", 3 - "scripts": { 4 - "start": "bun run ./dist/index.js", 5 - "build": "bun build ./src/index.ts --target bun --outdir ./dist", 6 - "dev": "bun run --hot src/index.ts" 7 - }, 8 - "dependencies": { 9 - "@atproto/identity": "^0.4.6", 10 - "@atproto/xrpc-server": "^0.7.13", 11 - "dotenv": "^16.4.7", 12 - "envalid": "^8.0.0", 13 - "hono": "^4.7.4", 14 - "mongoose": "^8.12.1", 15 - "pino": "^9.6.0", 16 - "pino-pretty": "^13.0.0" 17 - }, 18 - "devDependencies": { 19 - "@types/bun": "latest" 20 - }, 21 - "type": "module" 22 - }
-49
services/feed-gen/src/algos/following.ts
··· 1 - import { Database } from '../db/connection'; 2 - import { AlgoInfo, feedParams } from './types' 3 - 4 - export const shortname = 'following' 5 - 6 - const handler = async (db: Database, params: feedParams) => { 7 - const { limit = 50, requesterDid, cursor } = params; 8 - 9 - // Build the query 10 - const query: any = {}; 11 - 12 - // Apply cursor if provided 13 - if (cursor) { 14 - const timestamp = new Date(parseInt(cursor, 10)); 15 - query.indexedAt = { $lt: timestamp }; 16 - } 17 - 18 - const followers = (await db.models.Follow.find( 19 - { authorDid: requesterDid } 20 - )).map((follow) => follow.subject) 21 - 22 - // Get posts from MongoDB, sorted by most recent 23 - const posts = await db.models.Post.find(query) 24 - .sort({ indexedAt: -1 }) 25 - .where('authorDid').in(followers) 26 - .limit(limit) 27 - 28 - // Map to feed format 29 - const feed = posts.map((post) => ({ 30 - post: post.uri 31 - })); 32 - 33 - // Set cursor for pagination 34 - let nextCursor: string | undefined; 35 - const lastPost = posts.at(-1); 36 - if (lastPost) { 37 - nextCursor = new Date(lastPost.indexedAt).getTime().toString(10); 38 - } 39 - 40 - return { 41 - cursor: nextCursor, 42 - feed, 43 - }; 44 - } 45 - 46 - export const info = { 47 - handler, 48 - needsAuth: true 49 - } as AlgoInfo
-10
services/feed-gen/src/algos/index.ts
··· 1 - import * as simpleDesc from './simpleDesc' 2 - import * as following from './following' 3 - import { AlgoInfo } from './types' 4 - 5 - const algos: Record<string, AlgoInfo> = { 6 - [simpleDesc.shortname]: simpleDesc.info, 7 - [following.shortname]: following.info 8 - } 9 - 10 - export default algos
-44
services/feed-gen/src/algos/simpleDesc.ts
··· 1 - import { Database } from '../db/connection'; 2 - import { AlgoInfo, feedParams } from './types' 3 - 4 - export const shortname = 'simple-desc' 5 - 6 - const handler = async (db: Database, params: feedParams) => { 7 - const { limit = 50, cursor } = params; 8 - 9 - // Build the query, filtering out replies so only original posts are included 10 - const query: any = { reply: null }; 11 - 12 - // Apply cursor if provided 13 - if (cursor) { 14 - const timestamp = new Date(parseInt(cursor, 10)); 15 - query.indexedAt = { $lt: timestamp }; 16 - } 17 - 18 - // Get posts from MongoDB, sorted by most recent 19 - const posts = await db.models.Post.find(query) 20 - .sort({ indexedAt: -1 }) 21 - .limit(limit) 22 - 23 - // Map to feed format 24 - const feed = posts.map((post) => ({ 25 - post: post.uri 26 - })); 27 - 28 - // Set cursor for pagination 29 - let nextCursor: string | undefined; 30 - const lastPost = posts.at(-1); 31 - if (lastPost) { 32 - nextCursor = new Date(lastPost.indexedAt).getTime().toString(10); 33 - } 34 - 35 - return { 36 - cursor: nextCursor, 37 - feed, 38 - }; 39 - } 40 - 41 - export const info = { 42 - handler, 43 - needsAuth: false 44 - } as AlgoInfo
-15
services/feed-gen/src/algos/types.ts
··· 1 - import { Database } from '../db/connection' 2 - 3 - export interface feedParams { 4 - feed: string, 5 - limit: number, 6 - cursor: string, 7 - requesterDid: string 8 - } 9 - 10 - export interface AlgoInfo { 11 - handler: AlgoHandler, 12 - needsAuth: boolean 13 - } 14 - 15 - export type AlgoHandler = (db: Database, params: feedParams) => Promise<any>
-22
services/feed-gen/src/auth.ts
··· 1 - import { HonoRequest } from 'hono' 2 - import { verifyJwt, AuthRequiredError, parseReqNsid } from '@atproto/xrpc-server' 3 - import { DidResolver } from '@atproto/identity' 4 - 5 - export async function validateAuth( 6 - req: HonoRequest, 7 - serviceDid: string, 8 - didResolver: DidResolver, 9 - ): Promise<string> { 10 - const authorization = req.header('Authorization') ?? '' 11 - if (!authorization.startsWith('Bearer ')) { 12 - throw new AuthRequiredError() 13 - } 14 - const jwt = authorization.replace('Bearer ', '').trim() 15 - const nsid = parseReqNsid({ 16 - originalUrl: req.path 17 - }) 18 - const parsed = await verifyJwt(jwt, serviceDid, nsid, async (did: string) => { 19 - return didResolver.resolveAtprotoKey(did) 20 - }) 21 - return parsed.iss 22 - }
-60
services/feed-gen/src/db/connection.ts
··· 1 - import mongoose, { Connection } from 'mongoose' 2 - import { 3 - type DatabaseModels, 4 - likeSchema, 5 - postSchema, 6 - followSchema, 7 - blockSchema, 8 - profileSchema, 9 - audioSchema, 10 - repostSchema, 11 - musicSchema 12 - } from './models.js' 13 - import { env } from '../utils/env.js' 14 - import { pino } from 'pino' 15 - 16 - export class Database { 17 - private connection: Connection 18 - public models: DatabaseModels 19 - private logger = pino({ name: 'database' }) 20 - 21 - constructor() { 22 - this.connection = mongoose.createConnection() 23 - this.models = { 24 - Like: this.connection.model('Like', likeSchema), 25 - Post: this.connection.model('Post', postSchema), 26 - Follow: this.connection.model('Follow', followSchema), 27 - Block: this.connection.model('Block', blockSchema), 28 - Profile: this.connection.model('Profile', profileSchema), 29 - Audio: this.connection.model('Audio', audioSchema), 30 - Repost: this.connection.model('Repost', repostSchema), 31 - Music: this.connection.model('Music', musicSchema), 32 - } 33 - } 34 - 35 - async connect(): Promise<void> { 36 - const { DB_USER, DB_PASSWORD, DB_HOST, DB_PORT, DB_NAME } = env 37 - const uri = `mongodb://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/?appName=feed-gen` 38 - 39 - this.logger.info(`Connecting to MongoDB at ${DB_HOST}:${DB_PORT}/?appName=feed-gen`) 40 - 41 - try { 42 - await this.connection.openUri(uri, { 43 - autoIndex: true, 44 - autoCreate: true, 45 - dbName: DB_NAME, 46 - }) 47 - this.logger.info('Connected to MongoDB') 48 - } catch (error) { 49 - this.logger.error({ error }, 'MongoDB connection error') 50 - throw error 51 - } 52 - } 53 - 54 - async disconnect(): Promise<void> { 55 - if (this.connection) { 56 - await this.connection.close() 57 - this.logger.info('Disconnected from MongoDB') 58 - } 59 - } 60 - }
-276
services/feed-gen/src/db/models.ts
··· 1 - import mongoose, { Schema, Document, Model } from 'mongoose' 2 - 3 - export interface LikeDocument extends Document { 4 - uri: string 5 - subject: string 6 - subjectCid: string 7 - authorDid: string 8 - authorHandle: string 9 - createdAt: string 10 - indexedAt: string 11 - } 12 - 13 - export const likeSchema = new Schema<LikeDocument>({ 14 - uri: { type: String, required: true, unique: true, index: true }, 15 - subject: { type: String, required: true, index: true }, 16 - subjectCid: { type: String, required: true }, 17 - authorDid: { type: String, required: true, index: true }, 18 - authorHandle: { type: String, required: true }, 19 - createdAt: { type: String, required: true }, 20 - indexedAt: { type: String, required: true }, 21 - }) 22 - 23 - export interface FollowDocument extends Document { 24 - uri: string 25 - subject: string 26 - authorDid: string 27 - authorHandle: string 28 - createdAt: string 29 - indexedAt: string 30 - } 31 - 32 - export const followSchema = new Schema<FollowDocument>({ 33 - uri: { type: String, required: true, unique: true, index: true }, 34 - subject: { type: String, required: true, index: true }, 35 - authorDid: { type: String, required: true, index: true }, 36 - authorHandle: { type: String, required: true }, 37 - createdAt: { type: String, required: true }, 38 - indexedAt: { type: String, required: true }, 39 - }) 40 - 41 - export interface BlockDocument extends Document { 42 - uri: string 43 - subject: string 44 - authorDid: string 45 - authorHandle: string 46 - createdAt: string 47 - indexedAt: string 48 - } 49 - 50 - export const blockSchema = new Schema<BlockDocument>({ 51 - uri: { type: String, required: true, unique: true, index: true }, 52 - subject: { type: String, required: true, index: true }, 53 - authorDid: { type: String, required: true, index: true }, 54 - authorHandle: { type: String, required: true }, 55 - createdAt: { type: String, required: true }, 56 - indexedAt: { type: String, required: true }, 57 - }) 58 - 59 - export interface ProfileDocument extends Document { 60 - uri: string 61 - displayName?: string 62 - description?: string 63 - avatar?: string 64 - banner?: string 65 - labels?: Record<string, any> 66 - joinedViaStarterPack?: Record<string, any> 67 - pinnedPost?: Record<string, any> 68 - authorDid: string 69 - authorHandle: string 70 - createdAt: string 71 - indexedAt: string 72 - } 73 - 74 - export const profileSchema = new Schema<ProfileDocument>({ 75 - uri: { type: String, required: true, unique: true, index: true }, 76 - displayName: { type: String, required: false }, 77 - description: { type: String, required: false }, 78 - avatar: { type: String, required: false }, 79 - banner: { type: String, required: false }, 80 - labels: { type: Object, required: false }, 81 - joinedViaStarterPack: { type: Object, required: false }, 82 - pinnedPost: { type: Object, required: false }, 83 - authorDid: { type: String, required: true, index: true }, 84 - authorHandle: { type: String, required: true }, 85 - createdAt: { type: String, required: true }, 86 - indexedAt: { type: String, required: true }, 87 - }) 88 - 89 - export interface AudioDocument extends Document { 90 - uri: string 91 - sound: string 92 - origin: { 93 - uri: string 94 - cid: string 95 - } 96 - title?: string 97 - text?: string 98 - labels?: Record<string, any> 99 - authorDid: string 100 - authorHandle: string 101 - createdAt: string 102 - indexedAt: string 103 - } 104 - 105 - export const audioSchema = new Schema<AudioDocument>({ 106 - uri: { type: String, required: true, unique: true, index: true }, 107 - sound: { type: String, required: true }, 108 - origin: { 109 - uri: { type: String, required: true }, 110 - cid: { type: String, required: true } 111 - }, 112 - title: { type: String, required: false }, 113 - text: { type: String, required: false }, 114 - labels: { type: Object, required: false }, 115 - authorDid: { type: String, required: true, index: true }, 116 - authorHandle: { type: String, required: true }, 117 - createdAt: { type: String, required: true }, 118 - indexedAt: { type: String, required: true }, 119 - }) 120 - 121 - export interface RepostDocument extends Document { 122 - uri: string 123 - subject: { 124 - uri: string 125 - cid: string 126 - } 127 - authorDid: string 128 - authorHandle: string 129 - createdAt: string 130 - indexedAt: string 131 - } 132 - 133 - export const repostSchema = new Schema<RepostDocument>({ 134 - uri: { type: String, required: true, unique: true, index: true }, 135 - subject: { 136 - uri: { type: String, required: true }, 137 - cid: { type: String, required: true } 138 - }, 139 - authorDid: { type: String, required: true, index: true }, 140 - authorHandle: { type: String, required: true }, 141 - createdAt: { type: String, required: true }, 142 - indexedAt: { type: String, required: true }, 143 - }) 144 - 145 - export interface MusicDocument extends Document { 146 - uri: string 147 - sound: string 148 - title: string 149 - author: string 150 - releaseDate: string 151 - album?: string 152 - recordLabel?: string 153 - cover?: string 154 - text?: string 155 - copyright?: string[] 156 - facets?: Array<Record<string, any>> 157 - labels?: Record<string, any> 158 - tags?: string[] 159 - authorDid: string 160 - authorHandle: string 161 - createdAt: string 162 - indexedAt: string 163 - } 164 - 165 - export const musicSchema = new Schema<MusicDocument>({ 166 - uri: { type: String, required: true, unique: true, index: true }, 167 - sound: { type: String, required: true }, 168 - title: { type: String, required: true }, 169 - author: { type: String, required: true }, 170 - releaseDate: { type: String, required: true }, 171 - album: { type: String, required: false }, 172 - recordLabel: { type: String, required: false }, 173 - cover: { type: String, required: false }, 174 - text: { type: String, required: false }, 175 - copyright: { type: [String], required: false }, 176 - facets: { type: [Object], required: false }, 177 - labels: { type: Object, required: false }, 178 - tags: { type: [String], required: false }, 179 - authorDid: { type: String, required: true, index: true }, 180 - authorHandle: { type: String, required: true }, 181 - createdAt: { type: String, required: true }, 182 - indexedAt: { type: String, required: true }, 183 - }) 184 - 185 - export interface PostDocument extends Document { 186 - uri: string 187 - text: string 188 - facets: Array<Record<string, any>> 189 - reply: { 190 - root: { 191 - uri: string 192 - cid: string 193 - } 194 - parent: { 195 - uri: string 196 - cid: string 197 - } 198 - } | null 199 - embed: Record<string, any> | null 200 - sound: { 201 - uri: string 202 - cid: string 203 - } | null 204 - langs: string[] 205 - labels: Record<string, any> | null 206 - tags: string[] 207 - authorDid: string 208 - authorHandle: string 209 - createdAt: string 210 - indexedAt: string 211 - } 212 - 213 - export const postSchema = new Schema<PostDocument>({ 214 - uri: { type: String, required: true, unique: true, index: true }, 215 - text: { type: String, required: false }, 216 - facets: { type: [Object], required: false, default: [] }, 217 - reply: { 218 - type: { 219 - root: { 220 - uri: { type: String, required: true }, 221 - cid: { type: String, required: true } 222 - }, 223 - parent: { 224 - uri: { type: String, required: true }, 225 - cid: { type: String, required: true } 226 - } 227 - }, 228 - required: false, 229 - default: null 230 - }, 231 - embed: { type: Object, required: false, default: null }, 232 - sound: { 233 - type: { 234 - uri: { type: String, required: true }, 235 - cid: { type: String, required: true } 236 - }, 237 - required: false, 238 - default: null 239 - }, 240 - langs: { type: [String], required: false, default: [] }, 241 - labels: { type: Object, required: false, default: null }, 242 - tags: { type: [String], required: false, default: [] }, 243 - authorDid: { type: String, required: true, index: true }, 244 - authorHandle: { type: String, required: true }, 245 - createdAt: { type: String, required: true }, 246 - indexedAt: { type: String, required: true } 247 - }) 248 - 249 - // Add compound indexes for more efficient queries 250 - postSchema.index({ authorDid: 1, createdAt: -1 }) 251 - postSchema.index({ tags: 1, createdAt: -1 }) 252 - 253 - // Add compound indexes for new schemas 254 - followSchema.index({ authorDid: 1, subject: 1 }, { unique: true }) 255 - followSchema.index({ subject: 1, createdAt: -1 }) 256 - 257 - blockSchema.index({ authorDid: 1, subject: 1 }, { unique: true }) 258 - blockSchema.index({ subject: 1, createdAt: -1 }) 259 - 260 - audioSchema.index({ authorDid: 1, createdAt: -1 }) 261 - repostSchema.index({ authorDid: 1, createdAt: -1 }) 262 - repostSchema.index({ 'subject.uri': 1, createdAt: -1 }) 263 - 264 - musicSchema.index({ authorDid: 1, createdAt: -1 }) 265 - musicSchema.index({ tags: 1, createdAt: -1 }) 266 - 267 - export interface DatabaseModels { 268 - Like: Model<LikeDocument> 269 - Post: Model<PostDocument> 270 - Follow: Model<FollowDocument> 271 - Block: Model<BlockDocument> 272 - Profile: Model<ProfileDocument> 273 - Audio: Model<AudioDocument> 274 - Repost: Model<RepostDocument> 275 - Music: Model<MusicDocument> 276 - }
-61
services/feed-gen/src/index.ts
··· 1 - import { Hono } from 'hono' 2 - import { pino } from 'pino' 3 - import wellKnownRouter from './routes/well-known' 4 - import xrpcRouter from './routes/xrpc' 5 - import { Database } from './db/connection.js' 6 - 7 - const logger = pino({ 8 - name: 'feed-gen', 9 - transport: { 10 - target: 'pino-pretty', 11 - }, 12 - }) 13 - 14 - const app = new Hono() 15 - 16 - app.get('/', (c) => { 17 - return c.text('Hello Hono!') 18 - }) 19 - 20 - // Initialize database connection when server starts 21 - let db: Database 22 - 23 - export async function initializeApp() { 24 - logger.info('Starting Feed Generator service') 25 - 26 - // Set up database connection 27 - db = new Database() 28 - try { 29 - await db.connect() 30 - } catch (err) { 31 - logger.error({ err }, 'Failed to connect to database') 32 - process.exit(1) 33 - } 34 - 35 - // Handle shutdown gracefully 36 - const shutdown = async () => { 37 - logger.info('Shutting down...') 38 - await db.disconnect() 39 - process.exit(0) 40 - } 41 - 42 - process.on('SIGINT', shutdown) 43 - process.on('SIGTERM', shutdown) 44 - 45 - logger.info('Feed Generator service is running') 46 - 47 - app.route('/', wellKnownRouter()) 48 - 49 - app.route('/xrpc', xrpcRouter(db)) 50 - return app 51 - } 52 - 53 - // For development and testing 54 - if (process.env.NODE_ENV !== 'test') { 55 - initializeApp().catch((err) => { 56 - logger.error({ err }, 'Fatal error in main process') 57 - process.exit(1) 58 - }) 59 - } 60 - 61 - export default app
-25
services/feed-gen/src/routes/well-known.ts
··· 1 - import { Hono } from 'hono' 2 - import { env } from '../utils/env' 3 - 4 - const wellKnownRouter = () => { 5 - const router = new Hono() 6 - 7 - router.get('/.well-known/did.json', (c) => { 8 - 9 - return c.json({ 10 - '@context': ['https://www.w3.org/ns/did/v1'], 11 - id: `did:web:${env.FEEDGEN_DOMAIN}`, 12 - service: [ 13 - { 14 - id: '#sprk_fg', 15 - type: 'SprkFeedGenerator', 16 - serviceEndpoint: `https://${env.FEEDGEN_DOMAIN}`, 17 - }, 18 - ], 19 - }) 20 - }) 21 - 22 - return router 23 - } 24 - 25 - export default wellKnownRouter
-52
services/feed-gen/src/routes/xrpc.ts
··· 1 - import { Hono } from 'hono' 2 - import { Database } from '../db/connection' 3 - import { validateAuth } from '../auth' 4 - import { MemoryCache, DidResolver } from '@atproto/identity' 5 - import { env } from '../utils/env' 6 - import algos from '../algos' 7 - 8 - const didCache = new MemoryCache() 9 - const didResolver = new DidResolver({ 10 - plcUrl: 'https://plc.directory', 11 - didCache, 12 - }) 13 - 14 - const xrpcRouter = (db: Database) => { 15 - const router = new Hono() 16 - 17 - router.get('/so.sprk.feed.getFeedSkeleton', async (c) => { 18 - try { 19 - const feed = c.req.query('feed') ?? '' 20 - const limit = parseInt(c.req.query('limit') ?? '1') 21 - const cursor = c.req.query('cursor') ?? '' 22 - let requesterDid = '' 23 - 24 - const algoInfo = algos[feed] 25 - if (algoInfo.needsAuth){ 26 - requesterDid = await validateAuth(c.req, `did:web:${env.FEEDGEN_DOMAIN}`, didResolver) 27 - } 28 - 29 - 30 - const body = await algoInfo.handler(db, { 31 - feed: feed, 32 - limit, 33 - cursor, 34 - requesterDid 35 - }) 36 - return c.json(body) 37 - } catch (e){ 38 - const errorMsg = e instanceof Error ? e.message : 'Unknown'; 39 - return c.text(`Error found; Reason: ${errorMsg}`, 400); 40 - } 41 - }) 42 - 43 - router.get('/so.sprk.feed.getFeed', (c) => { 44 - return c.json({ 45 - feed: [], 46 - }) 47 - }) 48 - 49 - return router 50 - } 51 - 52 - export default xrpcRouter
-16
services/feed-gen/src/utils/env.ts
··· 1 - import * as dotenv from 'dotenv' 2 - import { envBool, envInt, envList, envStr } from '@atproto/common' 3 - 4 - dotenv.config() 5 - 6 - export const env = { 7 - NODE_ENV: envStr('NODE_ENV'), 8 - 9 - FEEDGEN_DOMAIN: envStr('FEEDGEN_DOMAIN'), 10 - 11 - DB_NAME: envStr('DB_NAME'), 12 - DB_HOST: envStr('DB_HOST'), 13 - DB_PORT: envInt('DB_PORT'), 14 - DB_USER: envStr('DB_USER'), 15 - DB_PASSWORD: envStr('DB_PASSWORD') 16 - }
-7
services/feed-gen/tsconfig.json
··· 1 - { 2 - "compilerOptions": { 3 - "strict": true, 4 - "jsx": "react-jsx", 5 - "jsxImportSource": "hono/jsx" 6 - } 7 - }