relay filter/appview bootstrap

Initial functionality

+6
.env.example
···
+
DATABASE_URL=postgres://prism:prism@localhost:5432/prism
+
DB_POOL_SIZE=10
+
NODE_ENV=development
+
LOG_LEVEL=info
+
PLC_DIRECTORY_URL=https://plc.directory
+
-8
.example.env
···
-
# what to filter by. currently only supports one string.
-
FILTER_BY=
-
-
# cache location. sqlite db url. technically supports an external cache if you want.
-
# https://bsky.app/profile/piss.beauty/post/3lkc3efbipc23
-
# https://bsky.app/profile/nekomimi.pet/post/3m3losk3rys2n
-
# usually either :memory: or file:path/to/file.db. defaults to ":memory:"
-
CACHE_LOCATION=":memory:"
+3
.gitignore
···
/dist
.env
*.tsbuildinfo
+
+
pgdata_podman
+
postgres.log
+15
Dockerfile
···
+
FROM oven/bun:latest
+
WORKDIR /usr/src/app
+
+
COPY package.json bun.lock tsconfig.json ./
+
+
RUN bun install --frozen-lockfile
+
+
COPY ./lexicons ./lexicons
+
COPY ./src ./src
+
+
# Expose the port your server listens on
+
EXPOSE 3000
+
+
# Set the default command to run your TypeScript spawner directly
+
CMD ["bun", "run", "src/index.ts"]
+40 -6
README.md
···
# Prism
-
Prism is a simple [ATProto](https://atproto.com/) [Relay](https://docs.bsky.app/docs/advanced-guides/firehose) filtering service. Point it to a relay, give it some NSID, partial NSID, or domain authority, and it'll filter relay events for you and store/cache them for future retrieval if you want to.
+
Prism is a simple [ATProto](https://atproto.com/) AppView service for gmstn. Point it to a relay and it'll filter relay events for you and store/cache them for future retrieval so that queries aren't so heavy on other PDSes directly.
<a href="https://docs.bsky.app/docs/advanced-guides/federation-architecture#app-views">
-
<img src="https://docs.bsky.app/assets/images/app-view-prism-e90e1bf6093bafcb6df2e5c592be1bc6.png" width="400" alt="appview-prism-pinkfloyd"/>
+
<img src="./assets/prism-appview-concept.png" width="400" alt="appview-prism-pinkfloyd"/>
</a>
-
For example, if you want to only filter all events relating to `sh.tangled.*`, simply configure your `.env` file with `FILTER_BY="sh.tangled"` and it'll monitor the relay for those records.
+
Other services may subscribe to a Prism instance as though it is a relay itself and receive the filtered gmstn events as they are played from the parent relay.
+
+
Prism implements endpoints for accessing the cache feed, which are `xrpc` compatible and the lexicons can be found in `lexicons/`.
+
+
Backfill batteries included. :3
+
+
## 如何在本地运行
+
+
请按照以下步骤在您的本地计算机上设置和运行此应用程序。
-
Other services may subscribe to a Prism instance as though it is a relay itself and receive the filtered events as they are played from the parent relay.
+
启动数据库: 首先,使用 Podman 或 Docker Compose 启动 PostgreSQL 数据库服务。
+
+
```bash
+
docker-compose up
+
```
-
Prism also implements a very minimal cache (24h, configurable). Endpoints for accessing the cache are `xrpc` compatible and the lexicons can be found in `lexicons/`
+
-
Backfill coming soon (if you're crazy ig).
+
```bash
+
podman-compose up
+
```
+
+
安装依赖: 使用 pnpm 安装项目所需的所有依赖项。
+
+
```bash
+
bun install
+
```
+
+
运行数据库迁移: 应用所有待处理的数据库迁移,以确保您的数据库结构是最新的。
+
+
```bash
+
bun run db:migrate
+
```
+
+
启动开发服务器: 最后,启动本地开发服务器。
+
+
```bash
+
bun run dev
+
```
+
+
服务启动后,您应该可以在 http://localhost:3000 (或您配置的端口) 上访问应用程序。
assets/prism-appview-concept.png

This is a binary file and will not be displayed.

+33
biome.json
···
+
{
+
"formatter": {
+
"indentStyle": "space",
+
"lineWidth": 100
+
},
+
"linter": {
+
"rules": {
+
"a11y": {
+
"useAriaPropsForRole": "off",
+
"useButtonType": "off",
+
"useSemanticElements": "off",
+
"noSvgWithoutTitle": "off"
+
},
+
"complexity": {
+
"noStaticOnlyClass": "off",
+
"noForEach": "off"
+
},
+
"suspicious": {
+
"noArrayIndexKey": "off",
+
"noPrototypeBuiltins": "off"
+
},
+
"style": {
+
"noNonNullAssertion": "off"
+
}
+
}
+
},
+
"javascript": {
+
"formatter": {
+
"quoteStyle": "single"
+
}
+
}
+
}
+
+697
bun.lock
···
+
{
+
"lockfileVersion": 1,
+
"configVersion": 1,
+
"workspaces": {
+
"": {
+
"name": "prism",
+
"dependencies": {
+
"@atcute/repo": "^0.1.0",
+
"@atproto/xrpc-server": "^0.10.1",
+
"@skyware/firehose": "^0.5.2",
+
"compression": "^1.8.1",
+
"dotenv": "^17.2.3",
+
"express": "^5.1.0",
+
"helmet": "^8.1.0",
+
"kysely": "^0.28.8",
+
"pg": "^8.16.3",
+
"pino": "^10.1.0",
+
"ws": "^8.18.3",
+
},
+
"devDependencies": {
+
"@types/bun": "^1.3.3",
+
"@types/compression": "^1.8.1",
+
"@types/express": "^5.0.5",
+
"@types/pg": "^8.15.6",
+
"@types/ws": "^8.18.1",
+
"biome": "^0.3.3",
+
"pino-pretty": "^13.1.2",
+
"typescript": "^5.9.3",
+
},
+
},
+
},
+
"packages": {
+
"@atcute/car": ["@atcute/car@5.0.0", "", { "dependencies": { "@atcute/cbor": "^2.2.7", "@atcute/cid": "^2.2.6", "@atcute/uint8array": "^1.0.5", "@atcute/varint": "^1.0.3" } }, "sha512-OIY2xTXv8lSpZsDSn/UYQtJSMvDw5Hi4Q+uyvmiqSM+fht08QRAEq/nxa5YFciPZ3nfDFnZ3//EgJw7QhkSXLQ=="],
+
+
"@atcute/cbor": ["@atcute/cbor@2.2.7", "", { "dependencies": { "@atcute/cid": "^2.2.5", "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.5" } }, "sha512-/mwAF0gnokOphceZqFq3uzMGdd8sbw5y6bxF8CRutRkCCUcpjjpJc5fkLwhxyGgOveF3mZuHE6p7t/+IAqb7Aw=="],
+
+
"@atcute/cid": ["@atcute/cid@2.2.6", "", { "dependencies": { "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.5" } }, "sha512-bTAHHbJ24p+E//V4KCS4xdmd39o211jJswvqQOevj7vk+5IYcgDLx1ryZWZ1sEPOo9x875li/kj5gpKL14RDwQ=="],
+
+
"@atcute/crypto": ["@atcute/crypto@2.2.6", "", { "dependencies": { "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.5", "@noble/secp256k1": "^3.0.0" } }, "sha512-vkuexF+kmrKE1/Uqzub99Qi4QpnxA2jbu60E6PTgL4XypELQ6rb59MB/J1VbY2gs0kd3ET7+L3+NWpKD5nXyfA=="],
+
+
"@atcute/lexicons": ["@atcute/lexicons@1.2.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "esm-env": "^1.2.2" } }, "sha512-bgEhJq5Z70/0TbK5sx+tAkrR8FsCODNiL2gUEvS5PuJfPxmFmRYNWaMGehxSPaXWpU2+Oa9ckceHiYbrItDTkA=="],
+
+
"@atcute/mst": ["@atcute/mst@0.1.0", "", { "dependencies": { "@atcute/cbor": "^2.2.7", "@atcute/cid": "^2.2.6", "@atcute/uint8array": "^1.0.5" } }, "sha512-h+iDToKEnBpigk2DOHjSqY63vJtjYKUIztqu1CZ0P+I54wV2SrgoqAXAT1xrW6A1Iup8cjTv+U2H5WVG4KxPLw=="],
+
+
"@atcute/multibase": ["@atcute/multibase@1.1.6", "", { "dependencies": { "@atcute/uint8array": "^1.0.5" } }, "sha512-HBxuCgYLKPPxETV0Rot4VP9e24vKl8JdzGCZOVsDaOXJgbRZoRIF67Lp0H/OgnJeH/Xpva8Z5ReoTNJE5dn3kg=="],
+
+
"@atcute/repo": ["@atcute/repo@0.1.0", "", { "dependencies": { "@atcute/car": "^5.0.0", "@atcute/cbor": "^2.2.7", "@atcute/cid": "^2.2.6", "@atcute/crypto": "^2.2.5", "@atcute/lexicons": "^1.2.2", "@atcute/mst": "^0.1.0", "@atcute/uint8array": "^1.0.5" } }, "sha512-INiYAuma8dydBu7cqd2WVpcXh3mzhIepYBUqFWAK5MqMulPRLTRCc/9GW3G9pxYrOdlvLCVamG2Jf8XK0nuFEw=="],
+
+
"@atcute/uint8array": ["@atcute/uint8array@1.0.5", "", {}, "sha512-XLWWxoR2HNl2qU+FCr0rp1APwJXci7HnzbOQLxK55OaMNBXZ19+xNC5ii4QCsThsDxa4JS/JTzuiQLziITWf2Q=="],
+
+
"@atcute/varint": ["@atcute/varint@1.0.3", "", {}, "sha512-fdvMPyBB+McDT+Ai5e9RwEbwYV4yjZ60S2Dn5PTjGqUyxvoCH1z42viuheDZRUDkmfQehXJTZ5az7dSozVNtog=="],
+
+
"@atproto/common": ["@atproto/common@0.5.1", "", { "dependencies": { "@atproto/common-web": "^0.4.5", "@atproto/lex-cbor": "0.0.1", "@atproto/lex-data": "0.0.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "pino": "^8.21.0" } }, "sha512-0S57sjzw4r9OLc5srJFi6uAz/aTKYl6btz3x36tSnGriL716m6h0x2IVtgd+FhUfIQfisevrqcqw8SfaGk8VTw=="],
+
+
"@atproto/common-web": ["@atproto/common-web@0.4.5", "", { "dependencies": { "@atproto/lex-data": "0.0.1", "@atproto/lex-json": "0.0.1", "zod": "^3.23.8" } }, "sha512-Tx0xUafLm3vRvOQpbBl5eb9V8xlC7TaRXs6dAulHRkDG3Kb+P9qn3pkDteq+aeMshbVXbVa1rm3Ok4vFyuoyYA=="],
+
+
"@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=="],
+
+
"@atproto/lex-cbor": ["@atproto/lex-cbor@0.0.1", "", { "dependencies": { "@atproto/lex-data": "0.0.1", "multiformats": "^9.9.0", "tslib": "^2.8.1" } }, "sha512-GCgowcC041tYmsoIxalIECJq4ZRHgREk6lFa4BzNRUZarMqwz57YF/7eUlo2Q6hoaMUL7Bjr6FvXwcZFaKrhvA=="],
+
+
"@atproto/lex-data": ["@atproto/lex-data@0.0.1", "", { "dependencies": { "@atproto/syntax": "0.4.1", "multiformats": "^9.9.0", "tslib": "^2.8.1", "uint8arrays": "3.0.0", "unicode-segmenter": "^0.14.0" } }, "sha512-DrS/8cQcQs3s5t9ELAFNtyDZ8/PdiCx47ALtFEP2GnX2uCBHZRkqWG7xmu6ehjc787nsFzZBvlnz3T/gov5fGA=="],
+
+
"@atproto/lex-json": ["@atproto/lex-json@0.0.1", "", { "dependencies": { "@atproto/lex-data": "0.0.1", "tslib": "^2.8.1" } }, "sha512-ivcF7+pDRuD/P97IEKQ/9TruunXj0w58Khvwk3M6psaI5eZT6LRsRZ4cWcKaXiFX4SHnjy+x43g0f7pPtIsERg=="],
+
+
"@atproto/lexicon": ["@atproto/lexicon@0.5.2", "", { "dependencies": { "@atproto/common-web": "^0.4.4", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-lRmJgMA8f5j7VB5Iu5cp188ald5FuI4FlmZ7nn6EBrk1dgOstWVrI5Ft6K3z2vjyLZRG6nzknlsw+tDP63p7bQ=="],
+
+
"@atproto/syntax": ["@atproto/syntax@0.4.1", "", {}, "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw=="],
+
+
"@atproto/ws-client": ["@atproto/ws-client@0.0.3", "", { "dependencies": { "@atproto/common": "^0.5.0", "ws": "^8.12.0" } }, "sha512-eKqkTWBk6zuMY+6gs02eT7mS8Btewm8/qaL/Dp00NDCqpNC+U59MWvQsOWT3xkNGfd9Eip+V6VI4oyPvAfsfTA=="],
+
+
"@atproto/xrpc": ["@atproto/xrpc@0.7.6", "", { "dependencies": { "@atproto/lexicon": "^0.5.2", "zod": "^3.23.8" } }, "sha512-RvCf4j0JnKYWuz3QzsYCntJi3VuiAAybQsMIUw2wLWcHhchO9F7UaBZINLL2z0qc/cYWPv5NSwcVydMseoCZLA=="],
+
+
"@atproto/xrpc-server": ["@atproto/xrpc-server@0.10.1", "", { "dependencies": { "@atproto/common": "^0.5.1", "@atproto/crypto": "^0.4.4", "@atproto/lex-cbor": "0.0.1", "@atproto/lex-data": "0.0.1", "@atproto/lexicon": "^0.5.2", "@atproto/ws-client": "^0.0.3", "@atproto/xrpc": "^0.7.6", "express": "^4.17.2", "http-errors": "^2.0.0", "mime-types": "^2.1.35", "rate-limiter-flexible": "^2.4.1", "ws": "^8.12.0", "zod": "^3.23.8" } }, "sha512-kHXykL4inBV/49vefn5zR5zv/VM1//+BIRqk9OvB3+mbERw0jkFiHhc6PWyY/81VD4ciu7FZwUCpRy/mtQtIaA=="],
+
+
"@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="],
+
+
"@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
+
+
"@noble/secp256k1": ["@noble/secp256k1@3.0.0", "", {}, "sha512-NJBaR352KyIvj3t6sgT/+7xrNyF9Xk9QlLSIqUGVUYlsnDTAUqY8LOmwpcgEx4AMJXRITQ5XEVHD+mMaPfr3mg=="],
+
+
"@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="],
+
+
"@skyware/firehose": ["@skyware/firehose@0.5.2", "", { "dependencies": { "@atcute/car": "^3.0.3", "@atcute/cbor": "^2.2.2", "nanoevents": "^9.1.0" } }, "sha512-Ayg/cF0BkakBNQVA51ClDka0+nC96WiARNrGElMQxfqbwao0PBaCXkunfr8qS4DWS3TqLnR6hA9mvm1vAYlxJQ=="],
+
+
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
+
+
"@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="],
+
+
"@types/bun": ["@types/bun@1.3.3", "", { "dependencies": { "bun-types": "1.3.3" } }, "sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g=="],
+
+
"@types/compression": ["@types/compression@1.8.1", "", { "dependencies": { "@types/express": "*", "@types/node": "*" } }, "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q=="],
+
+
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
+
+
"@types/express": ["@types/express@5.0.5", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", "@types/serve-static": "^1" } }, "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ=="],
+
+
"@types/express-serve-static-core": ["@types/express-serve-static-core@5.1.0", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA=="],
+
+
"@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="],
+
+
"@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="],
+
+
"@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
+
+
"@types/pg": ["@types/pg@8.15.6", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ=="],
+
+
"@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="],
+
+
"@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="],
+
+
"@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="],
+
+
"@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="],
+
+
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
+
+
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
+
+
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
+
+
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
+
+
"ansi-escapes": ["ansi-escapes@1.4.0", "", {}, "sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw=="],
+
+
"ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="],
+
+
"ansi-styles": ["ansi-styles@2.2.1", "", {}, "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA=="],
+
+
"any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
+
+
"array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="],
+
+
"asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="],
+
+
"assert-plus": ["assert-plus@1.0.0", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="],
+
+
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
+
+
"atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
+
+
"aws-sign2": ["aws-sign2@0.7.0", "", {}, "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA=="],
+
+
"aws4": ["aws4@1.13.2", "", {}, "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="],
+
+
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
+
+
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
+
+
"bcrypt-pbkdf": ["bcrypt-pbkdf@1.0.2", "", { "dependencies": { "tweetnacl": "^0.14.3" } }, "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w=="],
+
+
"biome": ["biome@0.3.3", "", { "dependencies": { "bluebird": "^3.4.1", "chalk": "^1.1.3", "commander": "^2.9.0", "editor": "^1.0.0", "fs-promise": "^0.5.0", "inquirer-promise": "0.0.3", "request-promise": "^3.0.0", "untildify": "^3.0.2", "user-home": "^2.0.0" }, "bin": { "biome": "./dist/index.js" } }, "sha512-4LXjrQYbn9iTXu9Y4SKT7ABzTV0WnLDHCVSd2fPUOKsy1gQ+E4xPFmlY1zcWexoi0j7fGHItlL6OWA2CZ/yYAQ=="],
+
+
"bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="],
+
+
"body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
+
+
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+
+
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
+
+
"bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="],
+
+
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
+
+
"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=="],
+
+
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
+
+
"caseless": ["caseless@0.12.0", "", {}, "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="],
+
+
"chalk": ["chalk@1.1.3", "", { "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } }, "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A=="],
+
+
"cli-cursor": ["cli-cursor@1.0.2", "", { "dependencies": { "restore-cursor": "^1.0.1" } }, "sha512-25tABq090YNKkF6JH7lcwO0zFJTRke4Jcq9iX2nr/Sz0Cjjv4gckmwlW6Ty/aoyFd6z3ysR2hMGC2GFugmBo6A=="],
+
+
"cli-width": ["cli-width@1.1.1", "", {}, "sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg=="],
+
+
"code-point-at": ["code-point-at@1.1.0", "", {}, "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA=="],
+
+
"colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
+
+
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
+
+
"commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
+
+
"compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": ">= 1.43.0 < 2" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="],
+
+
"compression": ["compression@1.8.1", "", { "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" } }, "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w=="],
+
+
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
+
+
"content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
+
+
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
+
+
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
+
+
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
+
+
"core-js": ["core-js@2.6.12", "", {}, "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="],
+
+
"core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
+
+
"dashdash": ["dashdash@1.14.1", "", { "dependencies": { "assert-plus": "^1.0.0" } }, "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g=="],
+
+
"dateformat": ["dateformat@4.6.3", "", {}, "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA=="],
+
+
"debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
+
+
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
+
+
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
+
+
"destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="],
+
+
"dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="],
+
+
"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=="],
+
+
"earlgrey-runtime": ["earlgrey-runtime@0.1.2", "", { "dependencies": { "core-js": "^2.4.0", "kaiser": ">=0.0.4", "lodash": "^4.17.2", "regenerator-runtime": "^0.9.5" } }, "sha512-T4qoScXi5TwALDv8nlGTvOuCT8jXcKcxtO8qVdqv46IA2GHJfQzwoBPbkOmORnyhu3A98cVVuhWLsM2CzPljJg=="],
+
+
"ecc-jsbn": ["ecc-jsbn@0.1.2", "", { "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw=="],
+
+
"editor": ["editor@1.0.0", "", {}, "sha512-SoRmbGStwNYHgKfjOrX2L0mUvp9bUVv0uPppZSOMAntEbcFtoC3MKF5b3T6HQPXKIV+QGY3xPO3JK5it5lVkuw=="],
+
+
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
+
+
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
+
+
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
+
+
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
+
+
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
+
+
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
+
+
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
+
+
"escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
+
+
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
+
+
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
+
+
"event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],
+
+
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
+
+
"exit-hook": ["exit-hook@1.1.1", "", {}, "sha512-MsG3prOVw1WtLXAZbM3KiYtooKR1LvxHh3VHsVtIy0uiUu8usxgB/94DP2HxtD/661lLdB6yzQ09lGJSQr6nkg=="],
+
+
"express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
+
+
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
+
+
"extsprintf": ["extsprintf@1.3.0", "", {}, "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="],
+
+
"fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="],
+
+
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
+
+
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
+
+
"fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="],
+
+
"fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="],
+
+
"figures": ["figures@1.7.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5", "object-assign": "^4.1.0" } }, "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ=="],
+
+
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
+
+
"forever-agent": ["forever-agent@0.6.1", "", {}, "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="],
+
+
"form-data": ["form-data@2.3.3", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ=="],
+
+
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
+
+
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
+
+
"fs-extra": ["fs-extra@0.26.7", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0", "klaw": "^1.0.0", "path-is-absolute": "^1.0.0", "rimraf": "^2.2.8" } }, "sha512-waKu+1KumRhYv8D8gMRCKJGAMI9pRnPuEb1mvgYD0f7wBscg+h6bW4FDTmEZhB9VKxvoTtxW+Y7bnIlB7zja6Q=="],
+
+
"fs-promise": ["fs-promise@0.5.0", "", { "dependencies": { "any-promise": "^1.0.0", "fs-extra": "^0.26.5", "mz": "^2.3.1", "thenify-all": "^1.6.0" } }, "sha512-Y+4F4ujhEcayCJt6JmzcOun9MYGQwz+bVUiuBmTkJImhBHKpBvmVPZR9wtfiF7k3ffwAOAuurygQe+cPLSFQhw=="],
+
+
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
+
+
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
+
+
"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=="],
+
+
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
+
+
"getpass": ["getpass@0.1.7", "", { "dependencies": { "assert-plus": "^1.0.0" } }, "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng=="],
+
+
"glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
+
+
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
+
+
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
+
+
"har-schema": ["har-schema@2.0.0", "", {}, "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q=="],
+
+
"har-validator": ["har-validator@5.1.5", "", { "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w=="],
+
+
"has-ansi": ["has-ansi@2.0.0", "", { "dependencies": { "ansi-regex": "^2.0.0" } }, "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg=="],
+
+
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
+
+
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
+
+
"helmet": ["helmet@8.1.0", "", {}, "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg=="],
+
+
"help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="],
+
+
"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=="],
+
+
"http-signature": ["http-signature@1.2.0", "", { "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ=="],
+
+
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
+
+
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
+
+
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
+
+
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
+
+
"inquirer": ["inquirer@0.11.4", "", { "dependencies": { "ansi-escapes": "^1.1.0", "ansi-regex": "^2.0.0", "chalk": "^1.0.0", "cli-cursor": "^1.0.1", "cli-width": "^1.0.1", "figures": "^1.3.5", "lodash": "^3.3.1", "readline2": "^1.0.1", "run-async": "^0.1.0", "rx-lite": "^3.1.2", "string-width": "^1.0.1", "strip-ansi": "^3.0.0", "through": "^2.3.6" } }, "sha512-QR+2TW90jnKk9LUUtbcA3yQXKt2rDEKMh6+BAZQIeumtzHexnwVLdPakSslGijXYLJCzFv7GMXbFCn0pA00EUw=="],
+
+
"inquirer-promise": ["inquirer-promise@0.0.3", "", { "dependencies": { "earlgrey-runtime": ">=0.0.11", "inquirer": "^0.11.3" } }, "sha512-82CQX586JAV9GAgU9yXZsMDs+NorjA0nLhkfFx9+PReyOnuoHRbHrC1Z90sS95bFJI1Tm1gzMObuE0HabzkJpg=="],
+
+
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
+
+
"is-fullwidth-code-point": ["is-fullwidth-code-point@1.0.0", "", { "dependencies": { "number-is-nan": "^1.0.0" } }, "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw=="],
+
+
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
+
+
"is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="],
+
+
"iso-datestring-validator": ["iso-datestring-validator@2.2.2", "", {}, "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA=="],
+
+
"isstream": ["isstream@0.1.2", "", {}, "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="],
+
+
"joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="],
+
+
"jsbn": ["jsbn@0.1.1", "", {}, "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="],
+
+
"json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
+
+
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
+
+
"json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="],
+
+
"jsonfile": ["jsonfile@2.4.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw=="],
+
+
"jsprim": ["jsprim@1.4.2", "", { "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.4.0", "verror": "1.10.0" } }, "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw=="],
+
+
"kaiser": ["kaiser@0.0.4", "", { "dependencies": { "earlgrey-runtime": ">=0.0.10" } }, "sha512-m8ju+rmBqvclZmyrOXgGGhOYSjKJK6RN1NhqEltemY87UqZOxEkizg9TOy1vQSyJ01Wx6SAPuuN0iO2Mgislvw=="],
+
+
"klaw": ["klaw@1.3.1", "", { "optionalDependencies": { "graceful-fs": "^4.1.9" } }, "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw=="],
+
+
"kysely": ["kysely@0.28.8", "", {}, "sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA=="],
+
+
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
+
+
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
+
+
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
+
+
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
+
+
"methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="],
+
+
"mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="],
+
+
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+
+
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
+
+
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
+
+
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
+
+
"ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
+
+
"multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
+
+
"mute-stream": ["mute-stream@0.0.5", "", {}, "sha512-EbrziT4s8cWPmzr47eYVW3wimS4HsvlnV5ri1xw1aR6JQo/OrJX5rkl32K/QQHdxeabJETtfeaROGhd8W7uBgg=="],
+
+
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
+
+
"nanoevents": ["nanoevents@9.1.0", "", {}, "sha512-Jd0fILWG44a9luj8v5kED4WI+zfkkgwKyRQKItTtlPfEsh7Lznfi1kr8/iZ+XAIss4Qq5GqRB0qtWbaz9ceO/A=="],
+
+
"negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="],
+
+
"number-is-nan": ["number-is-nan@1.0.1", "", {}, "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ=="],
+
+
"oauth-sign": ["oauth-sign@0.9.0", "", {}, "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="],
+
+
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
+
+
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
+
+
"on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="],
+
+
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
+
+
"on-headers": ["on-headers@1.1.0", "", {}, "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A=="],
+
+
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
+
+
"onetime": ["onetime@1.1.0", "", {}, "sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A=="],
+
+
"os-homedir": ["os-homedir@1.0.2", "", {}, "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ=="],
+
+
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
+
+
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
+
+
"path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="],
+
+
"performance-now": ["performance-now@2.1.0", "", {}, "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="],
+
+
"pg": ["pg@8.16.3", "", { "dependencies": { "pg-connection-string": "^2.9.1", "pg-pool": "^3.10.1", "pg-protocol": "^1.10.3", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.2.7" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw=="],
+
+
"pg-cloudflare": ["pg-cloudflare@1.2.7", "", {}, "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg=="],
+
+
"pg-connection-string": ["pg-connection-string@2.9.1", "", {}, "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w=="],
+
+
"pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="],
+
+
"pg-pool": ["pg-pool@3.10.1", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg=="],
+
+
"pg-protocol": ["pg-protocol@1.10.3", "", {}, "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ=="],
+
+
"pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="],
+
+
"pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="],
+
+
"pino": ["pino@10.1.0", "", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.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-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w=="],
+
+
"pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="],
+
+
"pino-pretty": ["pino-pretty@13.1.2", "", { "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": "^4.0.0", "sonic-boom": "^4.0.1", "strip-json-comments": "^5.0.2" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ=="],
+
+
"pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="],
+
+
"postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
+
+
"postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="],
+
+
"postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
+
+
"postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
+
+
"process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="],
+
+
"process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="],
+
+
"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=="],
+
+
"psl": ["psl@1.15.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w=="],
+
+
"pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
+
+
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
+
+
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
+
+
"quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
+
+
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
+
+
"rate-limiter-flexible": ["rate-limiter-flexible@2.4.2", "", {}, "sha512-rMATGGOdO1suFyf/mI5LYhts71g1sbdhmd6YvdiXO2gJnd42Tt6QS4JUKJKSWVVkMtBacm6l40FR7Trjo6Iruw=="],
+
+
"raw-body": ["raw-body@3.0.1", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.7.0", "unpipe": "1.0.0" } }, "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA=="],
+
+
"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=="],
+
+
"readline2": ["readline2@1.0.1", "", { "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "mute-stream": "0.0.5" } }, "sha512-8/td4MmwUB6PkZUbV25uKz7dfrmjYWxsW8DVfibWdlHRk/l/DfHKn4pU+dfcoGLFgWOdyGCzINRQD7jn+Bv+/g=="],
+
+
"real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="],
+
+
"regenerator-runtime": ["regenerator-runtime@0.9.6", "", {}, "sha512-D0Y/JJ4VhusyMOd/o25a3jdUqN/bC85EFsaoL9Oqmy/O4efCh+xhp7yj2EEOsj974qvMkcW8AwUzJ1jB/MbxCw=="],
+
+
"request": ["request@2.88.2", "", { "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" } }, "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw=="],
+
+
"request-promise": ["request-promise@3.0.0", "", { "dependencies": { "bluebird": "^3.3", "lodash": "^4.6.1", "request": "^2.34" } }, "sha512-wVGUX+BoKxYsavTA72i6qHcyLbjzM4LR4y/AmDCqlbuMAursZdDWO7PmgbGAUvD2SeEJ5iB99VSq/U51i/DNbw=="],
+
+
"restore-cursor": ["restore-cursor@1.0.1", "", { "dependencies": { "exit-hook": "^1.0.0", "onetime": "^1.0.0" } }, "sha512-reSjH4HuiFlxlaBaFCiS6O76ZGG2ygKoSlCsipKdaZuKSPx/+bt9mULkn4l0asVzbEfQQmXRg6Wp6gv6m0wElw=="],
+
+
"rimraf": ["rimraf@2.7.1", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="],
+
+
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
+
+
"run-async": ["run-async@0.1.0", "", { "dependencies": { "once": "^1.3.0" } }, "sha512-qOX+w+IxFgpUpJfkv2oGN0+ExPs68F4sZHfaRRx4dDexAQkG83atugKVEylyT5ARees3HBbfmuvnjbrd8j9Wjw=="],
+
+
"rx-lite": ["rx-lite@3.1.2", "", {}, "sha512-1I1+G2gteLB8Tkt8YI1sJvSIfa0lWuRtC8GjvtyPBcLSF5jBCCJJqKrpER5JU5r6Bhe+i9/pK3VMuUcXu0kdwQ=="],
+
+
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
+
+
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
+
+
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
+
+
"secure-json-parse": ["secure-json-parse@4.1.0", "", {}, "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA=="],
+
+
"send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
+
+
"serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
+
+
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
+
+
"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=="],
+
+
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
+
+
"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=="],
+
+
"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=="],
+
+
"sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="],
+
+
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
+
+
"sshpk": ["sshpk@1.18.0", "", { "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", "dashdash": "^1.12.0", "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" }, "bin": { "sshpk-conv": "bin/sshpk-conv", "sshpk-sign": "bin/sshpk-sign", "sshpk-verify": "bin/sshpk-verify" } }, "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ=="],
+
+
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
+
+
"string-width": ["string-width@1.0.2", "", { "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } }, "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw=="],
+
+
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
+
+
"strip-ansi": ["strip-ansi@3.0.1", "", { "dependencies": { "ansi-regex": "^2.0.0" } }, "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg=="],
+
+
"strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="],
+
+
"supports-color": ["supports-color@2.0.0", "", {}, "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g=="],
+
+
"thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
+
+
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
+
+
"thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="],
+
+
"through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="],
+
+
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
+
+
"tough-cookie": ["tough-cookie@2.5.0", "", { "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" } }, "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g=="],
+
+
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
+
"tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="],
+
+
"tweetnacl": ["tweetnacl@0.14.5", "", {}, "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="],
+
+
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
+
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
+
+
"uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA=="],
+
+
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+
+
"unicode-segmenter": ["unicode-segmenter@0.14.0", "", {}, "sha512-AH4lhPCJANUnSLEKnM4byboctePJzltF4xj8b+NbNiYeAkAXGh7px2K/4NANFp7dnr6+zB3e6HLu8Jj8SKyvYg=="],
+
+
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
+
+
"untildify": ["untildify@3.0.3", "", {}, "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA=="],
+
+
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
+
+
"user-home": ["user-home@2.0.0", "", { "dependencies": { "os-homedir": "^1.0.0" } }, "sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ=="],
+
+
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
+
+
"uuid": ["uuid@3.4.0", "", { "bin": { "uuid": "./bin/uuid" } }, "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="],
+
+
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
+
+
"verror": ["verror@1.10.0", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw=="],
+
+
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
+
+
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
+
+
"xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
+
+
"yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="],
+
+
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
+
+
"@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=="],
+
+
"@atproto/xrpc-server/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=="],
+
+
"@skyware/firehose/@atcute/car": ["@atcute/car@3.1.3", "", { "dependencies": { "@atcute/cbor": "^2.2.7", "@atcute/cid": "^2.2.5", "@atcute/uint8array": "^1.0.5", "@atcute/varint": "^1.0.3", "yocto-queue": "^1.2.1" } }, "sha512-WJ13bAEt7TjDMVi09ubjLtvhdljbWInGm9Kfy7Y6NhrmiyC/aZYaA/zHX/bHI6xv1c/h3SQduWqxOr4ae49eqA=="],
+
+
"@types/serve-static/@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="],
+
+
"accepts/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
+
+
"accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
+
+
"body-parser/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+
"compressible/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
+
+
"express/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+
"express/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
+
+
"finalhandler/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+
"http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
+
+
"inquirer/lodash": ["lodash@3.10.1", "", {}, "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ=="],
+
+
"raw-body/iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="],
+
+
"request/qs": ["qs@6.5.3", "", {}, "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA=="],
+
+
"router/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+
"router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
+
+
"send/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+
"send/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
+
+
"send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+
"type-is/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
+
+
"@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=="],
+
+
"@atproto/common/pino/pino-std-serializers": ["pino-std-serializers@6.2.2", "", {}, "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA=="],
+
+
"@atproto/common/pino/process-warning": ["process-warning@3.0.0", "", {}, "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ=="],
+
+
"@atproto/common/pino/sonic-boom": ["sonic-boom@3.8.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg=="],
+
+
"@atproto/common/pino/thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="],
+
+
"@atproto/xrpc-server/express/accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="],
+
+
"@atproto/xrpc-server/express/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=="],
+
+
"@atproto/xrpc-server/express/content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="],
+
+
"@atproto/xrpc-server/express/cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="],
+
+
"@atproto/xrpc-server/express/cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="],
+
+
"@atproto/xrpc-server/express/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=="],
+
+
"@atproto/xrpc-server/express/fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="],
+
+
"@atproto/xrpc-server/express/merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="],
+
+
"@atproto/xrpc-server/express/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="],
+
+
"@atproto/xrpc-server/express/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=="],
+
+
"@atproto/xrpc-server/express/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=="],
+
+
"@atproto/xrpc-server/express/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
+
+
"@atproto/xrpc-server/express/type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="],
+
+
"accepts/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
+
+
"body-parser/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+
"express/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+
"express/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
+
+
"finalhandler/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+
"router/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+
"send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
+
+
"type-is/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
+
+
"@atproto/xrpc-server/express/accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
+
+
"@atproto/xrpc-server/express/body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
+
+
"@atproto/xrpc-server/express/body-parser/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=="],
+
+
"@atproto/xrpc-server/express/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
+
+
"@atproto/xrpc-server/express/send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+
"@atproto/xrpc-server/express/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="],
+
}
+
}
+53
docker-compose.yaml
···
+
services:
+
prism-db:
+
image: postgres:latest
+
environment:
+
- POSTGRES_USER=prism
+
- POSTGRES_PASSWORD=prism
+
- POSTGRES_DB=prism
+
ports:
+
- "5432:5432"
+
healthcheck:
+
test: ["CMD-SHELL", "pg_isready -U prism"]
+
interval: 5s
+
timeout: 5s
+
retries: 5
+
+
prism-server:
+
build: .
+
command: bun run start:server
+
ports:
+
- "3000:3000"
+
environment:
+
- DATABASE_URL=postgresql://prism:prism@prism-db:5432/prism
+
- NODE_ENV=production
+
- LOG_LEVEL=info
+
depends_on:
+
prism-db:
+
condition: service_healthy
+
restart: always
+
+
prism-firehose:
+
build: .
+
command: bun run start:firehose
+
environment:
+
- DATABASE_URL=postgresql://prism:prism@prism-db:5432/prism
+
- NODE_ENV=production
+
- LOG_LEVEL=info
+
depends_on:
+
prism-db:
+
condition: service_healthy
+
restart: always
+
+
prism-backfill:
+
build: .
+
command: bun run start:backfill
+
environment:
+
- DATABASE_URL=postgresql://prism:prism@prism-db:5432/prism
+
- NODE_ENV=production
+
- LOG_LEVEL=info
+
depends_on:
+
prism-db:
+
condition: service_healthy
+
# This service is a task, so we don't restart it automatically if it exits successfully
+
restart: on-failure
-26
eslint.config.mts
···
-
import js from "@eslint/js";
-
import globals from "globals";
-
import tseslint from "typescript-eslint";
-
import { defineConfig } from "eslint/config";
-
-
export default defineConfig([
-
{
-
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
-
plugins: { js },
-
extends: ["js/recommended"],
-
languageOptions: { globals: globals.browser },
-
},
-
tseslint.configs.strictTypeChecked,
-
tseslint.configs.stylisticTypeChecked,
-
{
-
rules: {
-
"@typescript-eslint/consistent-type-imports": "error",
-
},
-
languageOptions: {
-
parserOptions: {
-
projectService: true,
-
tsconfigRootDir: import.meta.dirname,
-
},
-
},
-
},
-
]);
+63
lexicons/systems/gmstn/development/channel/listChannels.json
···
+
{
+
"lexicon": 1,
+
"id": "systems.gmstn.development.channel.listChannels",
+
"description": "Lists all channels owned by a specific account (DID).",
+
"defs": {
+
"main": {
+
"type": "query",
+
"parameters": {
+
"type": "params",
+
"required": ["author"],
+
"properties": {
+
"author": {
+
"type": "string",
+
"format": "did",
+
"description": "The DID of the user who created the channels."
+
},
+
"limit": {
+
"type": "integer",
+
"minimum": 1,
+
"maximum": 100,
+
"default": 50
+
},
+
"cursor": {
+
"type": "string"
+
}
+
}
+
},
+
"output": {
+
"encoding": "application/json",
+
"schema": {
+
"type": "object",
+
"required": ["channels"],
+
"properties": {
+
"cursor": { "type": "string" },
+
"channels": {
+
"type": "array",
+
"items": {
+
"type": "object",
+
"required": [
+
"uri",
+
"cid",
+
"author",
+
"displayName",
+
"createdAt",
+
"indexedAt"
+
],
+
"properties": {
+
"uri": { "type": "string", "format": "at-uri" },
+
"cid": { "type": "string" },
+
"author": { "type": "string", "format": "did" },
+
"displayName": { "type": "string" },
+
"description": { "type": "string" },
+
"createdAt": { "type": "string", "format": "datetime" },
+
"indexedAt": { "type": "string", "format": "datetime" }
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+61
lexicons/systems/gmstn/development/channel/listInvites.json
···
+
{
+
"lexicon": 1,
+
"id": "systems.gmstn.development.channel.listInvites",
+
"description": "Lists all channel invites for a specific recipient (DID).",
+
"defs": {
+
"main": {
+
"type": "query",
+
"parameters": {
+
"type": "params",
+
"required": ["recipient"],
+
"properties": {
+
"recipient": {
+
"type": "string",
+
"format": "did",
+
"description": "The DID of the user who received the invites."
+
},
+
"limit": {
+
"type": "integer",
+
"minimum": 1,
+
"maximum": 100,
+
"default": 50
+
},
+
"cursor": {
+
"type": "string"
+
}
+
}
+
},
+
"output": {
+
"encoding": "application/json",
+
"schema": {
+
"type": "object",
+
"required": ["invites"],
+
"properties": {
+
"cursor": { "type": "string" },
+
"invites": {
+
"type": "array",
+
"items": {
+
"type": "object",
+
"required": ["uri", "cid", "author", "channel", "createdAt"],
+
"properties": {
+
"uri": { "type": "string" },
+
"cid": { "type": "string" },
+
"author": { "type": "string", "format": "did" },
+
"channel": {
+
"type": "object",
+
"required": ["uri", "cid"],
+
"properties": {
+
"uri": { "type": "string", "format": "at-uri" },
+
"cid": { "type": "string" }
+
}
+
},
+
"createdAt": { "type": "string", "format": "datetime" }
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+70
lexicons/systems/gmstn/development/channel/listMemberships.json
···
+
{
+
"lexicon": 1,
+
"id": "systems.gmstn.development.channel.listMemberships",
+
"description": "Lists all channel memberships for a specific user (DID).",
+
"defs": {
+
"main": {
+
"type": "query",
+
"parameters": {
+
"type": "params",
+
"required": ["recipient"],
+
"properties": {
+
"recipient": {
+
"type": "string",
+
"format": "did",
+
"description": "The DID of the user whose memberships will be listed."
+
},
+
"limit": {
+
"type": "integer",
+
"minimum": 1,
+
"maximum": 100,
+
"default": 50
+
},
+
"cursor": {
+
"type": "string"
+
}
+
}
+
},
+
"output": {
+
"encoding": "application/json",
+
"schema": {
+
"type": "object",
+
"required": ["memberships"],
+
"properties": {
+
"cursor": { "type": "string" },
+
"memberships": {
+
"type": "array",
+
"items": {
+
"type": "object",
+
"required": ["uri", "cid", "state", "channel", "createdAt"],
+
"properties": {
+
"uri": { "type": "string" },
+
"cid": { "type": "string" },
+
"state": { "type": "string" },
+
"createdAt": { "type": "string", "format": "datetime" },
+
"updatedAt": { "type": "string", "format": "datetime" },
+
"channel": {
+
"type": "object",
+
"required": ["uri", "cid"],
+
"properties": {
+
"uri": { "type": "string", "format": "at-uri" },
+
"cid": { "type": "string" }
+
}
+
},
+
"invite": {
+
"type": "object",
+
"required": ["uri", "cid"],
+
"properties": {
+
"uri": { "type": "string", "format": "at-uri" },
+
"cid": { "type": "string" }
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+55
lexicons/systems/gmstn/development/lattice/listLattices.json
···
+
{
+
"lexicon": 1,
+
"id": "systems.gmstn.development.lattice.listLattices",
+
"description": "Lists all lattices created by a specific account (DID).",
+
"defs": {
+
"main": {
+
"type": "query",
+
"parameters": {
+
"type": "params",
+
"required": ["author"],
+
"properties": {
+
"author": {
+
"type": "string",
+
"format": "did",
+
"description": "The DID of the user who created the lattices."
+
},
+
"limit": {
+
"type": "integer",
+
"minimum": 1,
+
"maximum": 100,
+
"default": 50
+
},
+
"cursor": {
+
"type": "string"
+
}
+
}
+
},
+
"output": {
+
"encoding": "application/json",
+
"schema": {
+
"type": "object",
+
"required": ["lattices"],
+
"properties": {
+
"cursor": { "type": "string" },
+
"lattices": {
+
"type": "array",
+
"items": {
+
"type": "object",
+
"required": ["uri", "cid", "author", "createdAt", "indexedAt"],
+
"properties": {
+
"uri": { "type": "string", "format": "at-uri" },
+
"cid": { "type": "string" },
+
"author": { "type": "string", "format": "did" },
+
"description": { "type": "string" },
+
"createdAt": { "type": "string", "format": "datetime" },
+
"indexedAt": { "type": "string", "format": "datetime" }
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+55
lexicons/systems/gmstn/development/shard/listShards.json
···
+
{
+
"lexicon": 1,
+
"id": "systems.gmstn.development.shard.listShards",
+
"description": "Lists all shards created by a specific account (DID).",
+
"defs": {
+
"main": {
+
"type": "query",
+
"parameters": {
+
"type": "params",
+
"required": ["author"],
+
"properties": {
+
"author": {
+
"type": "string",
+
"format": "did",
+
"description": "The DID of the user who created the shards."
+
},
+
"limit": {
+
"type": "integer",
+
"minimum": 1,
+
"maximum": 100,
+
"default": 50
+
},
+
"cursor": {
+
"type": "string"
+
}
+
}
+
},
+
"output": {
+
"encoding": "application/json",
+
"schema": {
+
"type": "object",
+
"required": ["shards"],
+
"properties": {
+
"cursor": { "type": "string" },
+
"shards": {
+
"type": "array",
+
"items": {
+
"type": "object",
+
"required": ["uri", "cid", "author", "createdAt", "indexedAt"],
+
"properties": {
+
"uri": { "type": "string", "format": "at-uri" },
+
"cid": { "type": "string" },
+
"author": { "type": "string", "format": "did" },
+
"description": { "type": "string" },
+
"createdAt": { "type": "string", "format": "datetime" },
+
"indexedAt": { "type": "string", "format": "datetime" }
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+205
migrations/20251127130000_init.ts
···
+
import { Kysely, sql } from 'kysely'
+
+
export async function up(db: Kysely<any>): Promise<void> {
+
await db.schema
+
.createTable('pds')
+
.addColumn('hostname', 'text', (col) => col.primaryKey())
+
.addColumn('added_at', 'timestamp', (col) =>
+
col.defaultTo(sql`now()`).notNull()
+
)
+
.execute()
+
+
await db.schema
+
.createTable('account')
+
.addColumn('did', 'text', (col) => col.primaryKey().notNull())
+
.addColumn('handle', 'text', (col) => col.notNull().unique())
+
.addColumn('pds_hostname', 'text', (col) =>
+
col.references('pds.hostname')
+
)
+
.addColumn('created_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.execute()
+
+
await db.schema
+
.createTable('lattice')
+
.addColumn('uri', 'text', (col) => col.primaryKey().notNull())
+
.addColumn('cid', 'text', (col) => col.notNull())
+
.addColumn('creator_did', 'text', (col) =>
+
col.references('account.did').notNull()
+
)
+
.addColumn('description', 'text')
+
.addColumn('created_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('indexed_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('data', 'jsonb', (col) => col.notNull())
+
.execute()
+
+
await db.schema
+
.createTable('shard')
+
.addColumn('uri', 'text', (col) => col.primaryKey().notNull())
+
.addColumn('cid', 'text', (col) => col.notNull())
+
.addColumn('creator_did', 'text', (col) =>
+
col.references('account.did').notNull()
+
)
+
.addColumn('description', 'text')
+
.addColumn('created_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('indexed_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('data', 'jsonb', (col) => col.notNull())
+
.execute()
+
+
await db.schema
+
.createTable('channel')
+
.addColumn('cid', 'text', (col) => col.primaryKey().notNull())
+
.addColumn('uri', 'text')
+
.addColumn('creator_did', 'text', (col) =>
+
col.references('account.did')
+
)
+
.addColumn('name', 'text')
+
.addColumn('topic', 'text')
+
.addColumn('created_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('indexed_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('data', 'jsonb')
+
.execute()
+
+
await db.schema
+
.createTable('channel_invite')
+
.addColumn('cid', 'text', (col) => col.primaryKey())
+
.addColumn('uri', 'text')
+
.addColumn('channel', 'text', (col) =>
+
col.references('channel.cid')
+
)
+
.addColumn('creator_did', 'text', (col) =>
+
col.references('account.did')
+
)
+
.addColumn('recipient_did', 'text', (col) =>
+
col.references('account.did')
+
)
+
.addColumn('created_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('indexed_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('data', 'jsonb')
+
.execute()
+
+
await db.schema
+
.createTable('channel_membership')
+
.addColumn('uri', 'text', (col) => col.primaryKey().notNull())
+
.addColumn('cid', 'text', (col) => col.notNull())
+
.addColumn('channel', 'text', (col) =>
+
col.references('channel.cid').notNull()
+
)
+
.addColumn('invite', 'text', (col) =>
+
col.references('channel_invite.cid').notNull()
+
)
+
.addColumn('recipient_did', 'text', (col) =>
+
col.references('account.did').notNull()
+
)
+
.addColumn('state', 'text', (col) => col.notNull())
+
.addColumn('created_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('indexed_at', 'timestamptz', (col) => col.notNull().defaultTo(sql`now()`))
+
.addColumn('updated_at', 'timestamptz')
+
.addColumn('data', 'jsonb', (col) => col.notNull())
+
.execute()
+
+
await db.schema
+
.createTable('raw_record_queue')
+
.addColumn('id', 'serial', (col) => col.primaryKey())
+
.addColumn('record_data', 'jsonb', (col) => col.notNull())
+
.addColumn('status', 'varchar(20)', (col) =>
+
col.notNull().defaultTo('pending')
+
)
+
.addColumn('created_at', 'timestamp', (col) =>
+
col.defaultTo(sql`now()`).notNull()
+
)
+
.addColumn('updated_at', 'timestamp', (col) =>
+
col.defaultTo(sql`now()`).notNull()
+
)
+
.addCheckConstraint(
+
'raw_record_queue_status_check',
+
sql`status IN ('pending', 'processing', 'complete', 'failed')`
+
)
+
.execute()
+
+
await db.schema
+
.createIndex('raw_record_queue_status_created_at_idx')
+
.on('raw_record_queue')
+
.columns(['status', 'created_at'])
+
.execute()
+
+
await db.schema
+
.createTable('firehose_cursor')
+
.addColumn('id', 'integer', (col) => col.primaryKey())
+
.addColumn('cursor', 'varchar', (col) => col.notNull())
+
.addColumn('updated_at', 'timestamp', (col) =>
+
col.defaultTo(sql`now()`).notNull()
+
)
+
.execute()
+
+
await db.insertInto('firehose_cursor')
+
.values({ id: 1, cursor: '0' })
+
.execute()
+
+
await sql`
+
CREATE OR REPLACE FUNCTION notify_new_raw_record()
+
RETURNS trigger AS $$
+
BEGIN
+
PERFORM pg_notify('new_raw_record', NEW.id::text);
+
RETURN NEW;
+
END;
+
$$ LANGUAGE plpgsql;
+
`.execute(db)
+
+
await sql`
+
CREATE TRIGGER trigger_notify_new_raw_record
+
AFTER INSERT ON raw_record_queue
+
FOR EACH ROW
+
EXECUTE FUNCTION notify_new_raw_record();
+
`.execute(db)
+
+
await db.schema
+
.createIndex('idx_channel_invite_recipient_indexed')
+
.on('channel_invite')
+
.columns(['recipient_did', 'indexed_at'])
+
.execute()
+
+
await db.schema
+
.createIndex('idx_channel_creator_indexed')
+
.on('channel')
+
.columns(['creator_did', 'indexed_at'])
+
.execute()
+
+
await db.schema
+
.createIndex('idx_channel_membership_recipient_indexed')
+
.on('channel_membership')
+
.columns(['recipient_did', 'indexed_at'])
+
.execute()
+
+
await db.schema
+
.createIndex('idx_lattice_creator_indexed')
+
.on('lattice')
+
.columns(['creator_did', 'indexed_at'])
+
.execute()
+
+
await db.schema
+
.createIndex('idx_shard_creator_indexed')
+
.on('shard')
+
.columns(['creator_did', 'indexed_at'])
+
.execute()
+
}
+
+
export async function down(db: Kysely<any>): Promise<void> {
+
await db.schema.dropIndex('idx_shard_creator_indexed').execute()
+
await db.schema.dropIndex('idx_lattice_creator_indexed').execute()
+
await db.schema.dropIndex('idx_channel_membership_recipient_indexed').execute()
+
await db.schema.dropIndex('idx_channel_creator_indexed').execute()
+
await db.schema.dropIndex('idx_channel_invite_recipient_indexed').execute()
+
+
await sql`DROP TRIGGER IF EXISTS trigger_notify_new_raw_record ON raw_record_queue`.execute(db)
+
await sql`DROP FUNCTION IF EXISTS notify_new_raw_record`.execute(db)
+
+
await db.schema.dropTable('firehose_cursor').execute()
+
await db.schema.dropTable('raw_record_queue').execute()
+
await db.schema.dropTable('channel_membership').execute()
+
await db.schema.dropTable('channel_invite').execute()
+
await db.schema.dropTable('channel').execute()
+
await db.schema.dropTable('shard').execute()
+
await db.schema.dropTable('lattice').execute()
+
await db.schema.dropTable('account').execute()
+
await db.schema.dropTable('pds').execute()
+
}
+43 -35
package.json
···
{
-
"name": "dawn-persona",
-
"version": "0.0.1",
-
"description": "persaon lettabot",
-
"main": "index.js",
-
"scripts": {
-
"test": "echo \"Error: no test specified\" && exit 1",
-
"dev": "tsc && tsc-alias && node dist/index.js",
-
"db:generate": "drizzle-kit generate",
-
"db:migrate": "drizzle-kit migrate"
-
},
-
"keywords": [],
-
"author": "",
-
"license": "ISC",
-
"packageManager": "pnpm@10.18.0",
-
"devDependencies": {
-
"@eslint/js": "^9.37.0",
-
"@types/node": "^24.7.1",
-
"drizzle-kit": "^0.31.5",
-
"eslint": "^9.37.0",
-
"globals": "^16.4.0",
-
"jiti": "^2.6.1",
-
"prettier": "^3.6.2",
-
"ts-node": "^10.9.2",
-
"tsc-alias": "^1.8.16",
-
"tsconfig-paths": "^4.2.0",
-
"typescript": "^5.9.3",
-
"typescript-eslint": "^8.46.0"
-
},
-
"dependencies": {
-
"@libsql/client": "^0.15.15",
-
"@skyware/firehose": "^0.5.2",
-
"dotenv": "^17.2.3",
-
"drizzle-orm": "^0.44.6",
-
"zod": "^4.1.12"
-
}
+
"name": "prism",
+
"version": "1.0.0",
+
"description": "",
+
"main": "index.js",
+
"scripts": {
+
"test": "bun test",
+
"dev": "bun run src/index.ts",
+
"start": "bun run src/index.ts",
+
"start:server": "bun run src/services/api.ts",
+
"start:firehose": "bun run src/services/firehose-listen.ts",
+
"start:backfill": "bun run src/scripts/start-backfill.ts",
+
"lint": "bun run biome lint ./src && bun run biome format ./src",
+
"lint:fix": "bun run biome lint --fix ./src && bun run biome format --fix ./src",
+
"db:migrate": "bun run src/scripts/migrate.ts latest",
+
"db:revert": "bun run src/scripts/migrate.ts down"
+
},
+
"keywords": [],
+
"author": "",
+
"license": "ISC",
+
"packageManager": "pnpm@10.20.0",
+
"dependencies": {
+
"@atcute/repo": "^0.1.0",
+
"@atproto/xrpc-server": "^0.10.1",
+
"@skyware/firehose": "^0.5.2",
+
"compression": "^1.8.1",
+
"dotenv": "^17.2.3",
+
"express": "^5.1.0",
+
"helmet": "^8.1.0",
+
"kysely": "^0.28.8",
+
"pg": "^8.16.3",
+
"pino": "^10.1.0",
+
"ws": "^8.18.3"
+
},
+
"devDependencies": {
+
"@types/bun": "^1.3.3",
+
"@types/compression": "^1.8.1",
+
"@types/express": "^5.0.5",
+
"@types/pg": "^8.15.6",
+
"@types/ws": "^8.18.1",
+
"biome": "^0.3.3",
+
"pino-pretty": "^13.1.2",
+
"typescript": "^5.9.3"
+
}
}
-2361
pnpm-lock.yaml
···
-
lockfileVersion: '9.0'
-
-
settings:
-
autoInstallPeers: true
-
excludeLinksFromLockfile: false
-
-
importers:
-
-
.:
-
dependencies:
-
'@libsql/client':
-
specifier: ^0.15.15
-
version: 0.15.15
-
'@skyware/firehose':
-
specifier: ^0.5.2
-
version: 0.5.2
-
dotenv:
-
specifier: ^17.2.3
-
version: 17.2.3
-
drizzle-orm:
-
specifier: ^0.44.6
-
version: 0.44.6(@libsql/client@0.15.15)
-
zod:
-
specifier: ^4.1.12
-
version: 4.1.12
-
devDependencies:
-
'@eslint/js':
-
specifier: ^9.37.0
-
version: 9.37.0
-
'@types/node':
-
specifier: ^24.7.1
-
version: 24.7.1
-
drizzle-kit:
-
specifier: ^0.31.5
-
version: 0.31.5
-
eslint:
-
specifier: ^9.37.0
-
version: 9.37.0(jiti@2.6.1)
-
globals:
-
specifier: ^16.4.0
-
version: 16.4.0
-
jiti:
-
specifier: ^2.6.1
-
version: 2.6.1
-
prettier:
-
specifier: ^3.6.2
-
version: 3.6.2
-
ts-node:
-
specifier: ^10.9.2
-
version: 10.9.2(@types/node@24.7.1)(typescript@5.9.3)
-
tsc-alias:
-
specifier: ^1.8.16
-
version: 1.8.16
-
tsconfig-paths:
-
specifier: ^4.2.0
-
version: 4.2.0
-
typescript:
-
specifier: ^5.9.3
-
version: 5.9.3
-
typescript-eslint:
-
specifier: ^8.46.0
-
version: 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
-
-
packages:
-
-
'@atcute/car@3.1.3':
-
resolution: {integrity: sha512-WJ13bAEt7TjDMVi09ubjLtvhdljbWInGm9Kfy7Y6NhrmiyC/aZYaA/zHX/bHI6xv1c/h3SQduWqxOr4ae49eqA==}
-
-
'@atcute/cbor@2.2.7':
-
resolution: {integrity: sha512-/mwAF0gnokOphceZqFq3uzMGdd8sbw5y6bxF8CRutRkCCUcpjjpJc5fkLwhxyGgOveF3mZuHE6p7t/+IAqb7Aw==}
-
-
'@atcute/cid@2.2.5':
-
resolution: {integrity: sha512-7SId61nMyuxSwsDI02wEZn6/gVeha2TrAN4W0UPSdSEcwQD3R2W8VU7zvR4XGfU7A/KmBnVkwx5FTfzyizKj6g==}
-
-
'@atcute/multibase@1.1.6':
-
resolution: {integrity: sha512-HBxuCgYLKPPxETV0Rot4VP9e24vKl8JdzGCZOVsDaOXJgbRZoRIF67Lp0H/OgnJeH/Xpva8Z5ReoTNJE5dn3kg==}
-
-
'@atcute/uint8array@1.0.5':
-
resolution: {integrity: sha512-XLWWxoR2HNl2qU+FCr0rp1APwJXci7HnzbOQLxK55OaMNBXZ19+xNC5ii4QCsThsDxa4JS/JTzuiQLziITWf2Q==}
-
-
'@atcute/varint@1.0.3':
-
resolution: {integrity: sha512-fdvMPyBB+McDT+Ai5e9RwEbwYV4yjZ60S2Dn5PTjGqUyxvoCH1z42viuheDZRUDkmfQehXJTZ5az7dSozVNtog==}
-
-
'@cspotcode/source-map-support@0.8.1':
-
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
-
engines: {node: '>=12'}
-
-
'@drizzle-team/brocli@0.10.2':
-
resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
-
-
'@esbuild-kit/core-utils@3.3.2':
-
resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==}
-
deprecated: 'Merged into tsx: https://tsx.is'
-
-
'@esbuild-kit/esm-loader@2.6.5':
-
resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==}
-
deprecated: 'Merged into tsx: https://tsx.is'
-
-
'@esbuild/aix-ppc64@0.25.11':
-
resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==}
-
engines: {node: '>=18'}
-
cpu: [ppc64]
-
os: [aix]
-
-
'@esbuild/android-arm64@0.18.20':
-
resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
-
engines: {node: '>=12'}
-
cpu: [arm64]
-
os: [android]
-
-
'@esbuild/android-arm64@0.25.11':
-
resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==}
-
engines: {node: '>=18'}
-
cpu: [arm64]
-
os: [android]
-
-
'@esbuild/android-arm@0.18.20':
-
resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
-
engines: {node: '>=12'}
-
cpu: [arm]
-
os: [android]
-
-
'@esbuild/android-arm@0.25.11':
-
resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==}
-
engines: {node: '>=18'}
-
cpu: [arm]
-
os: [android]
-
-
'@esbuild/android-x64@0.18.20':
-
resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
-
engines: {node: '>=12'}
-
cpu: [x64]
-
os: [android]
-
-
'@esbuild/android-x64@0.25.11':
-
resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==}
-
engines: {node: '>=18'}
-
cpu: [x64]
-
os: [android]
-
-
'@esbuild/darwin-arm64@0.18.20':
-
resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
-
engines: {node: '>=12'}
-
cpu: [arm64]
-
os: [darwin]
-
-
'@esbuild/darwin-arm64@0.25.11':
-
resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==}
-
engines: {node: '>=18'}
-
cpu: [arm64]
-
os: [darwin]
-
-
'@esbuild/darwin-x64@0.18.20':
-
resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
-
engines: {node: '>=12'}
-
cpu: [x64]
-
os: [darwin]
-
-
'@esbuild/darwin-x64@0.25.11':
-
resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==}
-
engines: {node: '>=18'}
-
cpu: [x64]
-
os: [darwin]
-
-
'@esbuild/freebsd-arm64@0.18.20':
-
resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
-
engines: {node: '>=12'}
-
cpu: [arm64]
-
os: [freebsd]
-
-
'@esbuild/freebsd-arm64@0.25.11':
-
resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==}
-
engines: {node: '>=18'}
-
cpu: [arm64]
-
os: [freebsd]
-
-
'@esbuild/freebsd-x64@0.18.20':
-
resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
-
engines: {node: '>=12'}
-
cpu: [x64]
-
os: [freebsd]
-
-
'@esbuild/freebsd-x64@0.25.11':
-
resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==}
-
engines: {node: '>=18'}
-
cpu: [x64]
-
os: [freebsd]
-
-
'@esbuild/linux-arm64@0.18.20':
-
resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
-
engines: {node: '>=12'}
-
cpu: [arm64]
-
os: [linux]
-
-
'@esbuild/linux-arm64@0.25.11':
-
resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==}
-
engines: {node: '>=18'}
-
cpu: [arm64]
-
os: [linux]
-
-
'@esbuild/linux-arm@0.18.20':
-
resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
-
engines: {node: '>=12'}
-
cpu: [arm]
-
os: [linux]
-
-
'@esbuild/linux-arm@0.25.11':
-
resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==}
-
engines: {node: '>=18'}
-
cpu: [arm]
-
os: [linux]
-
-
'@esbuild/linux-ia32@0.18.20':
-
resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
-
engines: {node: '>=12'}
-
cpu: [ia32]
-
os: [linux]
-
-
'@esbuild/linux-ia32@0.25.11':
-
resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==}
-
engines: {node: '>=18'}
-
cpu: [ia32]
-
os: [linux]
-
-
'@esbuild/linux-loong64@0.18.20':
-
resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
-
engines: {node: '>=12'}
-
cpu: [loong64]
-
os: [linux]
-
-
'@esbuild/linux-loong64@0.25.11':
-
resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==}
-
engines: {node: '>=18'}
-
cpu: [loong64]
-
os: [linux]
-
-
'@esbuild/linux-mips64el@0.18.20':
-
resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
-
engines: {node: '>=12'}
-
cpu: [mips64el]
-
os: [linux]
-
-
'@esbuild/linux-mips64el@0.25.11':
-
resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==}
-
engines: {node: '>=18'}
-
cpu: [mips64el]
-
os: [linux]
-
-
'@esbuild/linux-ppc64@0.18.20':
-
resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
-
engines: {node: '>=12'}
-
cpu: [ppc64]
-
os: [linux]
-
-
'@esbuild/linux-ppc64@0.25.11':
-
resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==}
-
engines: {node: '>=18'}
-
cpu: [ppc64]
-
os: [linux]
-
-
'@esbuild/linux-riscv64@0.18.20':
-
resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
-
engines: {node: '>=12'}
-
cpu: [riscv64]
-
os: [linux]
-
-
'@esbuild/linux-riscv64@0.25.11':
-
resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==}
-
engines: {node: '>=18'}
-
cpu: [riscv64]
-
os: [linux]
-
-
'@esbuild/linux-s390x@0.18.20':
-
resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
-
engines: {node: '>=12'}
-
cpu: [s390x]
-
os: [linux]
-
-
'@esbuild/linux-s390x@0.25.11':
-
resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==}
-
engines: {node: '>=18'}
-
cpu: [s390x]
-
os: [linux]
-
-
'@esbuild/linux-x64@0.18.20':
-
resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
-
engines: {node: '>=12'}
-
cpu: [x64]
-
os: [linux]
-
-
'@esbuild/linux-x64@0.25.11':
-
resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==}
-
engines: {node: '>=18'}
-
cpu: [x64]
-
os: [linux]
-
-
'@esbuild/netbsd-arm64@0.25.11':
-
resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==}
-
engines: {node: '>=18'}
-
cpu: [arm64]
-
os: [netbsd]
-
-
'@esbuild/netbsd-x64@0.18.20':
-
resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
-
engines: {node: '>=12'}
-
cpu: [x64]
-
os: [netbsd]
-
-
'@esbuild/netbsd-x64@0.25.11':
-
resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==}
-
engines: {node: '>=18'}
-
cpu: [x64]
-
os: [netbsd]
-
-
'@esbuild/openbsd-arm64@0.25.11':
-
resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==}
-
engines: {node: '>=18'}
-
cpu: [arm64]
-
os: [openbsd]
-
-
'@esbuild/openbsd-x64@0.18.20':
-
resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
-
engines: {node: '>=12'}
-
cpu: [x64]
-
os: [openbsd]
-
-
'@esbuild/openbsd-x64@0.25.11':
-
resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==}
-
engines: {node: '>=18'}
-
cpu: [x64]
-
os: [openbsd]
-
-
'@esbuild/openharmony-arm64@0.25.11':
-
resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==}
-
engines: {node: '>=18'}
-
cpu: [arm64]
-
os: [openharmony]
-
-
'@esbuild/sunos-x64@0.18.20':
-
resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
-
engines: {node: '>=12'}
-
cpu: [x64]
-
os: [sunos]
-
-
'@esbuild/sunos-x64@0.25.11':
-
resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==}
-
engines: {node: '>=18'}
-
cpu: [x64]
-
os: [sunos]
-
-
'@esbuild/win32-arm64@0.18.20':
-
resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
-
engines: {node: '>=12'}
-
cpu: [arm64]
-
os: [win32]
-
-
'@esbuild/win32-arm64@0.25.11':
-
resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==}
-
engines: {node: '>=18'}
-
cpu: [arm64]
-
os: [win32]
-
-
'@esbuild/win32-ia32@0.18.20':
-
resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
-
engines: {node: '>=12'}
-
cpu: [ia32]
-
os: [win32]
-
-
'@esbuild/win32-ia32@0.25.11':
-
resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==}
-
engines: {node: '>=18'}
-
cpu: [ia32]
-
os: [win32]
-
-
'@esbuild/win32-x64@0.18.20':
-
resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
-
engines: {node: '>=12'}
-
cpu: [x64]
-
os: [win32]
-
-
'@esbuild/win32-x64@0.25.11':
-
resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==}
-
engines: {node: '>=18'}
-
cpu: [x64]
-
os: [win32]
-
-
'@eslint-community/eslint-utils@4.9.0':
-
resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==}
-
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-
peerDependencies:
-
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
-
-
'@eslint-community/regexpp@4.12.1':
-
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
-
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
-
-
'@eslint/config-array@0.21.0':
-
resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
'@eslint/config-helpers@0.4.0':
-
resolution: {integrity: sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
'@eslint/core@0.16.0':
-
resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
'@eslint/eslintrc@3.3.1':
-
resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
'@eslint/js@9.37.0':
-
resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
'@eslint/object-schema@2.1.6':
-
resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
'@eslint/plugin-kit@0.4.0':
-
resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
'@humanfs/core@0.19.1':
-
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
-
engines: {node: '>=18.18.0'}
-
-
'@humanfs/node@0.16.7':
-
resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
-
engines: {node: '>=18.18.0'}
-
-
'@humanwhocodes/module-importer@1.0.1':
-
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
-
engines: {node: '>=12.22'}
-
-
'@humanwhocodes/retry@0.4.3':
-
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
-
engines: {node: '>=18.18'}
-
-
'@jridgewell/resolve-uri@3.1.2':
-
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
-
engines: {node: '>=6.0.0'}
-
-
'@jridgewell/sourcemap-codec@1.5.5':
-
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
-
-
'@jridgewell/trace-mapping@0.3.9':
-
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
-
-
'@libsql/client@0.15.15':
-
resolution: {integrity: sha512-twC0hQxPNHPKfeOv3sNT6u2pturQjLcI+CnpTM0SjRpocEGgfiZ7DWKXLNnsothjyJmDqEsBQJ5ztq9Wlu470w==}
-
-
'@libsql/core@0.15.15':
-
resolution: {integrity: sha512-C88Z6UKl+OyuKKPwz224riz02ih/zHYI3Ho/LAcVOgjsunIRZoBw7fjRfaH9oPMmSNeQfhGklSG2il1URoOIsA==}
-
-
'@libsql/darwin-arm64@0.5.22':
-
resolution: {integrity: sha512-4B8ZlX3nIDPndfct7GNe0nI3Yw6ibocEicWdC4fvQbSs/jdq/RC2oCsoJxJ4NzXkvktX70C1J4FcmmoBy069UA==}
-
cpu: [arm64]
-
os: [darwin]
-
-
'@libsql/darwin-x64@0.5.22':
-
resolution: {integrity: sha512-ny2HYWt6lFSIdNFzUFIJ04uiW6finXfMNJ7wypkAD8Pqdm6nAByO+Fdqu8t7sD0sqJGeUCiOg480icjyQ2/8VA==}
-
cpu: [x64]
-
os: [darwin]
-
-
'@libsql/hrana-client@0.7.0':
-
resolution: {integrity: sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==}
-
-
'@libsql/isomorphic-fetch@0.3.1':
-
resolution: {integrity: sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw==}
-
engines: {node: '>=18.0.0'}
-
-
'@libsql/isomorphic-ws@0.1.5':
-
resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==}
-
-
'@libsql/linux-arm-gnueabihf@0.5.22':
-
resolution: {integrity: sha512-3Uo3SoDPJe/zBnyZKosziRGtszXaEtv57raWrZIahtQDsjxBVjuzYQinCm9LRCJCUT5t2r5Z5nLDPJi2CwZVoA==}
-
cpu: [arm]
-
os: [linux]
-
-
'@libsql/linux-arm-musleabihf@0.5.22':
-
resolution: {integrity: sha512-LCsXh07jvSojTNJptT9CowOzwITznD+YFGGW+1XxUr7fS+7/ydUrpDfsMX7UqTqjm7xG17eq86VkWJgHJfvpNg==}
-
cpu: [arm]
-
os: [linux]
-
-
'@libsql/linux-arm64-gnu@0.5.22':
-
resolution: {integrity: sha512-KSdnOMy88c9mpOFKUEzPskSaF3VLflfSUCBwas/pn1/sV3pEhtMF6H8VUCd2rsedwoukeeCSEONqX7LLnQwRMA==}
-
cpu: [arm64]
-
os: [linux]
-
-
'@libsql/linux-arm64-musl@0.5.22':
-
resolution: {integrity: sha512-mCHSMAsDTLK5YH//lcV3eFEgiR23Ym0U9oEvgZA0667gqRZg/2px+7LshDvErEKv2XZ8ixzw3p1IrBzLQHGSsw==}
-
cpu: [arm64]
-
os: [linux]
-
-
'@libsql/linux-x64-gnu@0.5.22':
-
resolution: {integrity: sha512-kNBHaIkSg78Y4BqAdgjcR2mBilZXs4HYkAmi58J+4GRwDQZh5fIUWbnQvB9f95DkWUIGVeenqLRFY2pcTmlsew==}
-
cpu: [x64]
-
os: [linux]
-
-
'@libsql/linux-x64-musl@0.5.22':
-
resolution: {integrity: sha512-UZ4Xdxm4pu3pQXjvfJiyCzZop/9j/eA2JjmhMaAhe3EVLH2g11Fy4fwyUp9sT1QJYR1kpc2JLuybPM0kuXv/Tg==}
-
cpu: [x64]
-
os: [linux]
-
-
'@libsql/win32-x64-msvc@0.5.22':
-
resolution: {integrity: sha512-Fj0j8RnBpo43tVZUVoNK6BV/9AtDUM5S7DF3LB4qTYg1LMSZqi3yeCneUTLJD6XomQJlZzbI4mst89yspVSAnA==}
-
cpu: [x64]
-
os: [win32]
-
-
'@neon-rs/load@0.0.4':
-
resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==}
-
-
'@nodelib/fs.scandir@2.1.5':
-
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
-
engines: {node: '>= 8'}
-
-
'@nodelib/fs.stat@2.0.5':
-
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
-
engines: {node: '>= 8'}
-
-
'@nodelib/fs.walk@1.2.8':
-
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
-
engines: {node: '>= 8'}
-
-
'@skyware/firehose@0.5.2':
-
resolution: {integrity: sha512-Ayg/cF0BkakBNQVA51ClDka0+nC96WiARNrGElMQxfqbwao0PBaCXkunfr8qS4DWS3TqLnR6hA9mvm1vAYlxJQ==}
-
-
'@tsconfig/node10@1.0.11':
-
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
-
-
'@tsconfig/node12@1.0.11':
-
resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
-
-
'@tsconfig/node14@1.0.3':
-
resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
-
-
'@tsconfig/node16@1.0.4':
-
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
-
-
'@types/estree@1.0.8':
-
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
-
-
'@types/json-schema@7.0.15':
-
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
-
-
'@types/node@24.7.1':
-
resolution: {integrity: sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q==}
-
-
'@types/ws@8.18.1':
-
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
-
-
'@typescript-eslint/eslint-plugin@8.46.0':
-
resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
peerDependencies:
-
'@typescript-eslint/parser': ^8.46.0
-
eslint: ^8.57.0 || ^9.0.0
-
typescript: '>=4.8.4 <6.0.0'
-
-
'@typescript-eslint/parser@8.46.0':
-
resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
peerDependencies:
-
eslint: ^8.57.0 || ^9.0.0
-
typescript: '>=4.8.4 <6.0.0'
-
-
'@typescript-eslint/project-service@8.46.0':
-
resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
peerDependencies:
-
typescript: '>=4.8.4 <6.0.0'
-
-
'@typescript-eslint/scope-manager@8.46.0':
-
resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
'@typescript-eslint/tsconfig-utils@8.46.0':
-
resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
peerDependencies:
-
typescript: '>=4.8.4 <6.0.0'
-
-
'@typescript-eslint/type-utils@8.46.0':
-
resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
peerDependencies:
-
eslint: ^8.57.0 || ^9.0.0
-
typescript: '>=4.8.4 <6.0.0'
-
-
'@typescript-eslint/types@8.46.0':
-
resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
'@typescript-eslint/typescript-estree@8.46.0':
-
resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
peerDependencies:
-
typescript: '>=4.8.4 <6.0.0'
-
-
'@typescript-eslint/utils@8.46.0':
-
resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
peerDependencies:
-
eslint: ^8.57.0 || ^9.0.0
-
typescript: '>=4.8.4 <6.0.0'
-
-
'@typescript-eslint/visitor-keys@8.46.0':
-
resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
acorn-jsx@5.3.2:
-
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
-
peerDependencies:
-
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
-
-
acorn-walk@8.3.4:
-
resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
-
engines: {node: '>=0.4.0'}
-
-
acorn@8.15.0:
-
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
-
engines: {node: '>=0.4.0'}
-
hasBin: true
-
-
ajv@6.12.6:
-
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
-
-
ansi-styles@4.3.0:
-
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
-
engines: {node: '>=8'}
-
-
anymatch@3.1.3:
-
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
-
engines: {node: '>= 8'}
-
-
arg@4.1.3:
-
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
-
-
argparse@2.0.1:
-
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
-
-
array-union@2.1.0:
-
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
-
engines: {node: '>=8'}
-
-
balanced-match@1.0.2:
-
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
-
-
binary-extensions@2.3.0:
-
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
-
engines: {node: '>=8'}
-
-
brace-expansion@1.1.12:
-
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
-
-
brace-expansion@2.0.2:
-
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
-
-
braces@3.0.3:
-
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
-
engines: {node: '>=8'}
-
-
buffer-from@1.1.2:
-
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
-
-
callsites@3.1.0:
-
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
-
engines: {node: '>=6'}
-
-
chalk@4.1.2:
-
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
-
engines: {node: '>=10'}
-
-
chokidar@3.6.0:
-
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
-
engines: {node: '>= 8.10.0'}
-
-
color-convert@2.0.1:
-
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
-
engines: {node: '>=7.0.0'}
-
-
color-name@1.1.4:
-
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
-
-
commander@9.5.0:
-
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
-
engines: {node: ^12.20.0 || >=14}
-
-
concat-map@0.0.1:
-
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
-
-
create-require@1.1.1:
-
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
-
-
cross-spawn@7.0.6:
-
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
-
engines: {node: '>= 8'}
-
-
data-uri-to-buffer@4.0.1:
-
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
-
engines: {node: '>= 12'}
-
-
debug@4.4.3:
-
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
-
engines: {node: '>=6.0'}
-
peerDependencies:
-
supports-color: '*'
-
peerDependenciesMeta:
-
supports-color:
-
optional: true
-
-
deep-is@0.1.4:
-
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
-
-
detect-libc@2.0.2:
-
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
-
engines: {node: '>=8'}
-
-
diff@4.0.2:
-
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
-
engines: {node: '>=0.3.1'}
-
-
dir-glob@3.0.1:
-
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
-
engines: {node: '>=8'}
-
-
dotenv@17.2.3:
-
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
-
engines: {node: '>=12'}
-
-
drizzle-kit@0.31.5:
-
resolution: {integrity: sha512-+CHgPFzuoTQTt7cOYCV6MOw2w8vqEn/ap1yv4bpZOWL03u7rlVRQhUY0WYT3rHsgVTXwYQDZaSUJSQrMBUKuWg==}
-
hasBin: true
-
-
drizzle-orm@0.44.6:
-
resolution: {integrity: sha512-uy6uarrrEOc9K1u5/uhBFJbdF5VJ5xQ/Yzbecw3eAYOunv5FDeYkR2m8iitocdHBOHbvorviKOW5GVw0U1j4LQ==}
-
peerDependencies:
-
'@aws-sdk/client-rds-data': '>=3'
-
'@cloudflare/workers-types': '>=4'
-
'@electric-sql/pglite': '>=0.2.0'
-
'@libsql/client': '>=0.10.0'
-
'@libsql/client-wasm': '>=0.10.0'
-
'@neondatabase/serverless': '>=0.10.0'
-
'@op-engineering/op-sqlite': '>=2'
-
'@opentelemetry/api': ^1.4.1
-
'@planetscale/database': '>=1.13'
-
'@prisma/client': '*'
-
'@tidbcloud/serverless': '*'
-
'@types/better-sqlite3': '*'
-
'@types/pg': '*'
-
'@types/sql.js': '*'
-
'@upstash/redis': '>=1.34.7'
-
'@vercel/postgres': '>=0.8.0'
-
'@xata.io/client': '*'
-
better-sqlite3: '>=7'
-
bun-types: '*'
-
expo-sqlite: '>=14.0.0'
-
gel: '>=2'
-
knex: '*'
-
kysely: '*'
-
mysql2: '>=2'
-
pg: '>=8'
-
postgres: '>=3'
-
prisma: '*'
-
sql.js: '>=1'
-
sqlite3: '>=5'
-
peerDependenciesMeta:
-
'@aws-sdk/client-rds-data':
-
optional: true
-
'@cloudflare/workers-types':
-
optional: true
-
'@electric-sql/pglite':
-
optional: true
-
'@libsql/client':
-
optional: true
-
'@libsql/client-wasm':
-
optional: true
-
'@neondatabase/serverless':
-
optional: true
-
'@op-engineering/op-sqlite':
-
optional: true
-
'@opentelemetry/api':
-
optional: true
-
'@planetscale/database':
-
optional: true
-
'@prisma/client':
-
optional: true
-
'@tidbcloud/serverless':
-
optional: true
-
'@types/better-sqlite3':
-
optional: true
-
'@types/pg':
-
optional: true
-
'@types/sql.js':
-
optional: true
-
'@upstash/redis':
-
optional: true
-
'@vercel/postgres':
-
optional: true
-
'@xata.io/client':
-
optional: true
-
better-sqlite3:
-
optional: true
-
bun-types:
-
optional: true
-
expo-sqlite:
-
optional: true
-
gel:
-
optional: true
-
knex:
-
optional: true
-
kysely:
-
optional: true
-
mysql2:
-
optional: true
-
pg:
-
optional: true
-
postgres:
-
optional: true
-
prisma:
-
optional: true
-
sql.js:
-
optional: true
-
sqlite3:
-
optional: true
-
-
esbuild-register@3.6.0:
-
resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==}
-
peerDependencies:
-
esbuild: '>=0.12 <1'
-
-
esbuild@0.18.20:
-
resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
-
engines: {node: '>=12'}
-
hasBin: true
-
-
esbuild@0.25.11:
-
resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==}
-
engines: {node: '>=18'}
-
hasBin: true
-
-
escape-string-regexp@4.0.0:
-
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
-
engines: {node: '>=10'}
-
-
eslint-scope@8.4.0:
-
resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
eslint-visitor-keys@3.4.3:
-
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
-
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-
-
eslint-visitor-keys@4.2.1:
-
resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
eslint@9.37.0:
-
resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
hasBin: true
-
peerDependencies:
-
jiti: '*'
-
peerDependenciesMeta:
-
jiti:
-
optional: true
-
-
espree@10.4.0:
-
resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-
esquery@1.6.0:
-
resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
-
engines: {node: '>=0.10'}
-
-
esrecurse@4.3.0:
-
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
-
engines: {node: '>=4.0'}
-
-
estraverse@5.3.0:
-
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
-
engines: {node: '>=4.0'}
-
-
esutils@2.0.3:
-
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
-
engines: {node: '>=0.10.0'}
-
-
fast-deep-equal@3.1.3:
-
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
-
-
fast-glob@3.3.3:
-
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
-
engines: {node: '>=8.6.0'}
-
-
fast-json-stable-stringify@2.1.0:
-
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
-
-
fast-levenshtein@2.0.6:
-
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
-
-
fastq@1.19.1:
-
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
-
-
fetch-blob@3.2.0:
-
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
-
engines: {node: ^12.20 || >= 14.13}
-
-
file-entry-cache@8.0.0:
-
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
-
engines: {node: '>=16.0.0'}
-
-
fill-range@7.1.1:
-
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
-
engines: {node: '>=8'}
-
-
find-up@5.0.0:
-
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
-
engines: {node: '>=10'}
-
-
flat-cache@4.0.1:
-
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
-
engines: {node: '>=16'}
-
-
flatted@3.3.3:
-
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
-
-
formdata-polyfill@4.0.10:
-
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
-
engines: {node: '>=12.20.0'}
-
-
fsevents@2.3.3:
-
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
-
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
-
os: [darwin]
-
-
get-tsconfig@4.12.0:
-
resolution: {integrity: sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==}
-
-
glob-parent@5.1.2:
-
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
-
engines: {node: '>= 6'}
-
-
glob-parent@6.0.2:
-
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
-
engines: {node: '>=10.13.0'}
-
-
globals@14.0.0:
-
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
-
engines: {node: '>=18'}
-
-
globals@16.4.0:
-
resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==}
-
engines: {node: '>=18'}
-
-
globby@11.1.0:
-
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
-
engines: {node: '>=10'}
-
-
graphemer@1.4.0:
-
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
-
-
has-flag@4.0.0:
-
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
-
engines: {node: '>=8'}
-
-
ignore@5.3.2:
-
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
-
engines: {node: '>= 4'}
-
-
ignore@7.0.5:
-
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
-
engines: {node: '>= 4'}
-
-
import-fresh@3.3.1:
-
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
-
engines: {node: '>=6'}
-
-
imurmurhash@0.1.4:
-
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
-
engines: {node: '>=0.8.19'}
-
-
is-binary-path@2.1.0:
-
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
-
engines: {node: '>=8'}
-
-
is-extglob@2.1.1:
-
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
-
engines: {node: '>=0.10.0'}
-
-
is-glob@4.0.3:
-
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
-
engines: {node: '>=0.10.0'}
-
-
is-number@7.0.0:
-
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
-
engines: {node: '>=0.12.0'}
-
-
isexe@2.0.0:
-
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
-
-
jiti@2.6.1:
-
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
-
hasBin: true
-
-
js-base64@3.7.8:
-
resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==}
-
-
js-yaml@4.1.0:
-
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
-
hasBin: true
-
-
json-buffer@3.0.1:
-
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
-
-
json-schema-traverse@0.4.1:
-
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
-
-
json-stable-stringify-without-jsonify@1.0.1:
-
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
-
-
json5@2.2.3:
-
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
-
engines: {node: '>=6'}
-
hasBin: true
-
-
keyv@4.5.4:
-
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
-
-
levn@0.4.1:
-
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
-
engines: {node: '>= 0.8.0'}
-
-
libsql@0.5.22:
-
resolution: {integrity: sha512-NscWthMQt7fpU8lqd7LXMvT9pi+KhhmTHAJWUB/Lj6MWa0MKFv0F2V4C6WKKpjCVZl0VwcDz4nOI3CyaT1DDiA==}
-
cpu: [x64, arm64, wasm32, arm]
-
os: [darwin, linux, win32]
-
-
locate-path@6.0.0:
-
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
-
engines: {node: '>=10'}
-
-
lodash.merge@4.6.2:
-
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
-
-
make-error@1.3.6:
-
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
-
-
merge2@1.4.1:
-
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
-
engines: {node: '>= 8'}
-
-
micromatch@4.0.8:
-
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
-
engines: {node: '>=8.6'}
-
-
minimatch@3.1.2:
-
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
-
-
minimatch@9.0.5:
-
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
-
engines: {node: '>=16 || 14 >=14.17'}
-
-
minimist@1.2.8:
-
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
-
-
ms@2.1.3:
-
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
-
-
mylas@2.1.13:
-
resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==}
-
engines: {node: '>=12.0.0'}
-
-
nanoevents@9.1.0:
-
resolution: {integrity: sha512-Jd0fILWG44a9luj8v5kED4WI+zfkkgwKyRQKItTtlPfEsh7Lznfi1kr8/iZ+XAIss4Qq5GqRB0qtWbaz9ceO/A==}
-
engines: {node: ^18.0.0 || >=20.0.0}
-
-
natural-compare@1.4.0:
-
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
-
-
node-domexception@1.0.0:
-
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
-
engines: {node: '>=10.5.0'}
-
deprecated: Use your platform's native DOMException instead
-
-
node-fetch@3.3.2:
-
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
-
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-
-
normalize-path@3.0.0:
-
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
-
engines: {node: '>=0.10.0'}
-
-
optionator@0.9.4:
-
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
-
engines: {node: '>= 0.8.0'}
-
-
p-limit@3.1.0:
-
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
-
engines: {node: '>=10'}
-
-
p-locate@5.0.0:
-
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
-
engines: {node: '>=10'}
-
-
parent-module@1.0.1:
-
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
-
engines: {node: '>=6'}
-
-
path-exists@4.0.0:
-
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
-
engines: {node: '>=8'}
-
-
path-key@3.1.1:
-
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
-
engines: {node: '>=8'}
-
-
path-type@4.0.0:
-
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
-
engines: {node: '>=8'}
-
-
picomatch@2.3.1:
-
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
-
engines: {node: '>=8.6'}
-
-
plimit-lit@1.6.1:
-
resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==}
-
engines: {node: '>=12'}
-
-
prelude-ls@1.2.1:
-
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
-
engines: {node: '>= 0.8.0'}
-
-
prettier@3.6.2:
-
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
-
engines: {node: '>=14'}
-
hasBin: true
-
-
promise-limit@2.7.0:
-
resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==}
-
-
punycode@2.3.1:
-
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
-
engines: {node: '>=6'}
-
-
queue-lit@1.5.2:
-
resolution: {integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==}
-
engines: {node: '>=12'}
-
-
queue-microtask@1.2.3:
-
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
-
-
readdirp@3.6.0:
-
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
-
engines: {node: '>=8.10.0'}
-
-
resolve-from@4.0.0:
-
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
-
engines: {node: '>=4'}
-
-
resolve-pkg-maps@1.0.0:
-
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
-
-
reusify@1.1.0:
-
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
-
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
-
-
run-parallel@1.2.0:
-
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
-
-
semver@7.7.3:
-
resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
-
engines: {node: '>=10'}
-
hasBin: true
-
-
shebang-command@2.0.0:
-
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
-
engines: {node: '>=8'}
-
-
shebang-regex@3.0.0:
-
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
-
engines: {node: '>=8'}
-
-
slash@3.0.0:
-
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
-
engines: {node: '>=8'}
-
-
source-map-support@0.5.21:
-
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
-
-
source-map@0.6.1:
-
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
-
engines: {node: '>=0.10.0'}
-
-
strip-bom@3.0.0:
-
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
-
engines: {node: '>=4'}
-
-
strip-json-comments@3.1.1:
-
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
-
engines: {node: '>=8'}
-
-
supports-color@7.2.0:
-
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
-
engines: {node: '>=8'}
-
-
to-regex-range@5.0.1:
-
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
-
engines: {node: '>=8.0'}
-
-
ts-api-utils@2.1.0:
-
resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
-
engines: {node: '>=18.12'}
-
peerDependencies:
-
typescript: '>=4.8.4'
-
-
ts-node@10.9.2:
-
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
-
hasBin: true
-
peerDependencies:
-
'@swc/core': '>=1.2.50'
-
'@swc/wasm': '>=1.2.50'
-
'@types/node': '*'
-
typescript: '>=2.7'
-
peerDependenciesMeta:
-
'@swc/core':
-
optional: true
-
'@swc/wasm':
-
optional: true
-
-
tsc-alias@1.8.16:
-
resolution: {integrity: sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==}
-
engines: {node: '>=16.20.2'}
-
hasBin: true
-
-
tsconfig-paths@4.2.0:
-
resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
-
engines: {node: '>=6'}
-
-
type-check@0.4.0:
-
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
-
engines: {node: '>= 0.8.0'}
-
-
typescript-eslint@8.46.0:
-
resolution: {integrity: sha512-6+ZrB6y2bT2DX3K+Qd9vn7OFOJR+xSLDj+Aw/N3zBwUt27uTw2sw2TE2+UcY1RiyBZkaGbTkVg9SSdPNUG6aUw==}
-
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
peerDependencies:
-
eslint: ^8.57.0 || ^9.0.0
-
typescript: '>=4.8.4 <6.0.0'
-
-
typescript@5.9.3:
-
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
-
engines: {node: '>=14.17'}
-
hasBin: true
-
-
undici-types@7.14.0:
-
resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==}
-
-
uri-js@4.4.1:
-
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
-
-
v8-compile-cache-lib@3.0.1:
-
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
-
-
web-streams-polyfill@3.3.3:
-
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
-
engines: {node: '>= 8'}
-
-
which@2.0.2:
-
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
-
engines: {node: '>= 8'}
-
hasBin: true
-
-
word-wrap@1.2.5:
-
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
-
engines: {node: '>=0.10.0'}
-
-
ws@8.18.3:
-
resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
-
engines: {node: '>=10.0.0'}
-
peerDependencies:
-
bufferutil: ^4.0.1
-
utf-8-validate: '>=5.0.2'
-
peerDependenciesMeta:
-
bufferutil:
-
optional: true
-
utf-8-validate:
-
optional: true
-
-
yn@3.1.1:
-
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
-
engines: {node: '>=6'}
-
-
yocto-queue@0.1.0:
-
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
-
engines: {node: '>=10'}
-
-
yocto-queue@1.2.1:
-
resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==}
-
engines: {node: '>=12.20'}
-
-
zod@4.1.12:
-
resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==}
-
-
snapshots:
-
-
'@atcute/car@3.1.3':
-
dependencies:
-
'@atcute/cbor': 2.2.7
-
'@atcute/cid': 2.2.5
-
'@atcute/uint8array': 1.0.5
-
'@atcute/varint': 1.0.3
-
yocto-queue: 1.2.1
-
-
'@atcute/cbor@2.2.7':
-
dependencies:
-
'@atcute/cid': 2.2.5
-
'@atcute/multibase': 1.1.6
-
'@atcute/uint8array': 1.0.5
-
-
'@atcute/cid@2.2.5':
-
dependencies:
-
'@atcute/multibase': 1.1.6
-
'@atcute/uint8array': 1.0.5
-
-
'@atcute/multibase@1.1.6':
-
dependencies:
-
'@atcute/uint8array': 1.0.5
-
-
'@atcute/uint8array@1.0.5': {}
-
-
'@atcute/varint@1.0.3': {}
-
-
'@cspotcode/source-map-support@0.8.1':
-
dependencies:
-
'@jridgewell/trace-mapping': 0.3.9
-
-
'@drizzle-team/brocli@0.10.2': {}
-
-
'@esbuild-kit/core-utils@3.3.2':
-
dependencies:
-
esbuild: 0.18.20
-
source-map-support: 0.5.21
-
-
'@esbuild-kit/esm-loader@2.6.5':
-
dependencies:
-
'@esbuild-kit/core-utils': 3.3.2
-
get-tsconfig: 4.12.0
-
-
'@esbuild/aix-ppc64@0.25.11':
-
optional: true
-
-
'@esbuild/android-arm64@0.18.20':
-
optional: true
-
-
'@esbuild/android-arm64@0.25.11':
-
optional: true
-
-
'@esbuild/android-arm@0.18.20':
-
optional: true
-
-
'@esbuild/android-arm@0.25.11':
-
optional: true
-
-
'@esbuild/android-x64@0.18.20':
-
optional: true
-
-
'@esbuild/android-x64@0.25.11':
-
optional: true
-
-
'@esbuild/darwin-arm64@0.18.20':
-
optional: true
-
-
'@esbuild/darwin-arm64@0.25.11':
-
optional: true
-
-
'@esbuild/darwin-x64@0.18.20':
-
optional: true
-
-
'@esbuild/darwin-x64@0.25.11':
-
optional: true
-
-
'@esbuild/freebsd-arm64@0.18.20':
-
optional: true
-
-
'@esbuild/freebsd-arm64@0.25.11':
-
optional: true
-
-
'@esbuild/freebsd-x64@0.18.20':
-
optional: true
-
-
'@esbuild/freebsd-x64@0.25.11':
-
optional: true
-
-
'@esbuild/linux-arm64@0.18.20':
-
optional: true
-
-
'@esbuild/linux-arm64@0.25.11':
-
optional: true
-
-
'@esbuild/linux-arm@0.18.20':
-
optional: true
-
-
'@esbuild/linux-arm@0.25.11':
-
optional: true
-
-
'@esbuild/linux-ia32@0.18.20':
-
optional: true
-
-
'@esbuild/linux-ia32@0.25.11':
-
optional: true
-
-
'@esbuild/linux-loong64@0.18.20':
-
optional: true
-
-
'@esbuild/linux-loong64@0.25.11':
-
optional: true
-
-
'@esbuild/linux-mips64el@0.18.20':
-
optional: true
-
-
'@esbuild/linux-mips64el@0.25.11':
-
optional: true
-
-
'@esbuild/linux-ppc64@0.18.20':
-
optional: true
-
-
'@esbuild/linux-ppc64@0.25.11':
-
optional: true
-
-
'@esbuild/linux-riscv64@0.18.20':
-
optional: true
-
-
'@esbuild/linux-riscv64@0.25.11':
-
optional: true
-
-
'@esbuild/linux-s390x@0.18.20':
-
optional: true
-
-
'@esbuild/linux-s390x@0.25.11':
-
optional: true
-
-
'@esbuild/linux-x64@0.18.20':
-
optional: true
-
-
'@esbuild/linux-x64@0.25.11':
-
optional: true
-
-
'@esbuild/netbsd-arm64@0.25.11':
-
optional: true
-
-
'@esbuild/netbsd-x64@0.18.20':
-
optional: true
-
-
'@esbuild/netbsd-x64@0.25.11':
-
optional: true
-
-
'@esbuild/openbsd-arm64@0.25.11':
-
optional: true
-
-
'@esbuild/openbsd-x64@0.18.20':
-
optional: true
-
-
'@esbuild/openbsd-x64@0.25.11':
-
optional: true
-
-
'@esbuild/openharmony-arm64@0.25.11':
-
optional: true
-
-
'@esbuild/sunos-x64@0.18.20':
-
optional: true
-
-
'@esbuild/sunos-x64@0.25.11':
-
optional: true
-
-
'@esbuild/win32-arm64@0.18.20':
-
optional: true
-
-
'@esbuild/win32-arm64@0.25.11':
-
optional: true
-
-
'@esbuild/win32-ia32@0.18.20':
-
optional: true
-
-
'@esbuild/win32-ia32@0.25.11':
-
optional: true
-
-
'@esbuild/win32-x64@0.18.20':
-
optional: true
-
-
'@esbuild/win32-x64@0.25.11':
-
optional: true
-
-
'@eslint-community/eslint-utils@4.9.0(eslint@9.37.0(jiti@2.6.1))':
-
dependencies:
-
eslint: 9.37.0(jiti@2.6.1)
-
eslint-visitor-keys: 3.4.3
-
-
'@eslint-community/regexpp@4.12.1': {}
-
-
'@eslint/config-array@0.21.0':
-
dependencies:
-
'@eslint/object-schema': 2.1.6
-
debug: 4.4.3
-
minimatch: 3.1.2
-
transitivePeerDependencies:
-
- supports-color
-
-
'@eslint/config-helpers@0.4.0':
-
dependencies:
-
'@eslint/core': 0.16.0
-
-
'@eslint/core@0.16.0':
-
dependencies:
-
'@types/json-schema': 7.0.15
-
-
'@eslint/eslintrc@3.3.1':
-
dependencies:
-
ajv: 6.12.6
-
debug: 4.4.3
-
espree: 10.4.0
-
globals: 14.0.0
-
ignore: 5.3.2
-
import-fresh: 3.3.1
-
js-yaml: 4.1.0
-
minimatch: 3.1.2
-
strip-json-comments: 3.1.1
-
transitivePeerDependencies:
-
- supports-color
-
-
'@eslint/js@9.37.0': {}
-
-
'@eslint/object-schema@2.1.6': {}
-
-
'@eslint/plugin-kit@0.4.0':
-
dependencies:
-
'@eslint/core': 0.16.0
-
levn: 0.4.1
-
-
'@humanfs/core@0.19.1': {}
-
-
'@humanfs/node@0.16.7':
-
dependencies:
-
'@humanfs/core': 0.19.1
-
'@humanwhocodes/retry': 0.4.3
-
-
'@humanwhocodes/module-importer@1.0.1': {}
-
-
'@humanwhocodes/retry@0.4.3': {}
-
-
'@jridgewell/resolve-uri@3.1.2': {}
-
-
'@jridgewell/sourcemap-codec@1.5.5': {}
-
-
'@jridgewell/trace-mapping@0.3.9':
-
dependencies:
-
'@jridgewell/resolve-uri': 3.1.2
-
'@jridgewell/sourcemap-codec': 1.5.5
-
-
'@libsql/client@0.15.15':
-
dependencies:
-
'@libsql/core': 0.15.15
-
'@libsql/hrana-client': 0.7.0
-
js-base64: 3.7.8
-
libsql: 0.5.22
-
promise-limit: 2.7.0
-
transitivePeerDependencies:
-
- bufferutil
-
- utf-8-validate
-
-
'@libsql/core@0.15.15':
-
dependencies:
-
js-base64: 3.7.8
-
-
'@libsql/darwin-arm64@0.5.22':
-
optional: true
-
-
'@libsql/darwin-x64@0.5.22':
-
optional: true
-
-
'@libsql/hrana-client@0.7.0':
-
dependencies:
-
'@libsql/isomorphic-fetch': 0.3.1
-
'@libsql/isomorphic-ws': 0.1.5
-
js-base64: 3.7.8
-
node-fetch: 3.3.2
-
transitivePeerDependencies:
-
- bufferutil
-
- utf-8-validate
-
-
'@libsql/isomorphic-fetch@0.3.1': {}
-
-
'@libsql/isomorphic-ws@0.1.5':
-
dependencies:
-
'@types/ws': 8.18.1
-
ws: 8.18.3
-
transitivePeerDependencies:
-
- bufferutil
-
- utf-8-validate
-
-
'@libsql/linux-arm-gnueabihf@0.5.22':
-
optional: true
-
-
'@libsql/linux-arm-musleabihf@0.5.22':
-
optional: true
-
-
'@libsql/linux-arm64-gnu@0.5.22':
-
optional: true
-
-
'@libsql/linux-arm64-musl@0.5.22':
-
optional: true
-
-
'@libsql/linux-x64-gnu@0.5.22':
-
optional: true
-
-
'@libsql/linux-x64-musl@0.5.22':
-
optional: true
-
-
'@libsql/win32-x64-msvc@0.5.22':
-
optional: true
-
-
'@neon-rs/load@0.0.4': {}
-
-
'@nodelib/fs.scandir@2.1.5':
-
dependencies:
-
'@nodelib/fs.stat': 2.0.5
-
run-parallel: 1.2.0
-
-
'@nodelib/fs.stat@2.0.5': {}
-
-
'@nodelib/fs.walk@1.2.8':
-
dependencies:
-
'@nodelib/fs.scandir': 2.1.5
-
fastq: 1.19.1
-
-
'@skyware/firehose@0.5.2':
-
dependencies:
-
'@atcute/car': 3.1.3
-
'@atcute/cbor': 2.2.7
-
nanoevents: 9.1.0
-
-
'@tsconfig/node10@1.0.11': {}
-
-
'@tsconfig/node12@1.0.11': {}
-
-
'@tsconfig/node14@1.0.3': {}
-
-
'@tsconfig/node16@1.0.4': {}
-
-
'@types/estree@1.0.8': {}
-
-
'@types/json-schema@7.0.15': {}
-
-
'@types/node@24.7.1':
-
dependencies:
-
undici-types: 7.14.0
-
-
'@types/ws@8.18.1':
-
dependencies:
-
'@types/node': 24.7.1
-
-
'@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)':
-
dependencies:
-
'@eslint-community/regexpp': 4.12.1
-
'@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
-
'@typescript-eslint/scope-manager': 8.46.0
-
'@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
-
'@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
-
'@typescript-eslint/visitor-keys': 8.46.0
-
eslint: 9.37.0(jiti@2.6.1)
-
graphemer: 1.4.0
-
ignore: 7.0.5
-
natural-compare: 1.4.0
-
ts-api-utils: 2.1.0(typescript@5.9.3)
-
typescript: 5.9.3
-
transitivePeerDependencies:
-
- supports-color
-
-
'@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)':
-
dependencies:
-
'@typescript-eslint/scope-manager': 8.46.0
-
'@typescript-eslint/types': 8.46.0
-
'@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3)
-
'@typescript-eslint/visitor-keys': 8.46.0
-
debug: 4.4.3
-
eslint: 9.37.0(jiti@2.6.1)
-
typescript: 5.9.3
-
transitivePeerDependencies:
-
- supports-color
-
-
'@typescript-eslint/project-service@8.46.0(typescript@5.9.3)':
-
dependencies:
-
'@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3)
-
'@typescript-eslint/types': 8.46.0
-
debug: 4.4.3
-
typescript: 5.9.3
-
transitivePeerDependencies:
-
- supports-color
-
-
'@typescript-eslint/scope-manager@8.46.0':
-
dependencies:
-
'@typescript-eslint/types': 8.46.0
-
'@typescript-eslint/visitor-keys': 8.46.0
-
-
'@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.9.3)':
-
dependencies:
-
typescript: 5.9.3
-
-
'@typescript-eslint/type-utils@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)':
-
dependencies:
-
'@typescript-eslint/types': 8.46.0
-
'@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3)
-
'@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
-
debug: 4.4.3
-
eslint: 9.37.0(jiti@2.6.1)
-
ts-api-utils: 2.1.0(typescript@5.9.3)
-
typescript: 5.9.3
-
transitivePeerDependencies:
-
- supports-color
-
-
'@typescript-eslint/types@8.46.0': {}
-
-
'@typescript-eslint/typescript-estree@8.46.0(typescript@5.9.3)':
-
dependencies:
-
'@typescript-eslint/project-service': 8.46.0(typescript@5.9.3)
-
'@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3)
-
'@typescript-eslint/types': 8.46.0
-
'@typescript-eslint/visitor-keys': 8.46.0
-
debug: 4.4.3
-
fast-glob: 3.3.3
-
is-glob: 4.0.3
-
minimatch: 9.0.5
-
semver: 7.7.3
-
ts-api-utils: 2.1.0(typescript@5.9.3)
-
typescript: 5.9.3
-
transitivePeerDependencies:
-
- supports-color
-
-
'@typescript-eslint/utils@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)':
-
dependencies:
-
'@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.6.1))
-
'@typescript-eslint/scope-manager': 8.46.0
-
'@typescript-eslint/types': 8.46.0
-
'@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3)
-
eslint: 9.37.0(jiti@2.6.1)
-
typescript: 5.9.3
-
transitivePeerDependencies:
-
- supports-color
-
-
'@typescript-eslint/visitor-keys@8.46.0':
-
dependencies:
-
'@typescript-eslint/types': 8.46.0
-
eslint-visitor-keys: 4.2.1
-
-
acorn-jsx@5.3.2(acorn@8.15.0):
-
dependencies:
-
acorn: 8.15.0
-
-
acorn-walk@8.3.4:
-
dependencies:
-
acorn: 8.15.0
-
-
acorn@8.15.0: {}
-
-
ajv@6.12.6:
-
dependencies:
-
fast-deep-equal: 3.1.3
-
fast-json-stable-stringify: 2.1.0
-
json-schema-traverse: 0.4.1
-
uri-js: 4.4.1
-
-
ansi-styles@4.3.0:
-
dependencies:
-
color-convert: 2.0.1
-
-
anymatch@3.1.3:
-
dependencies:
-
normalize-path: 3.0.0
-
picomatch: 2.3.1
-
-
arg@4.1.3: {}
-
-
argparse@2.0.1: {}
-
-
array-union@2.1.0: {}
-
-
balanced-match@1.0.2: {}
-
-
binary-extensions@2.3.0: {}
-
-
brace-expansion@1.1.12:
-
dependencies:
-
balanced-match: 1.0.2
-
concat-map: 0.0.1
-
-
brace-expansion@2.0.2:
-
dependencies:
-
balanced-match: 1.0.2
-
-
braces@3.0.3:
-
dependencies:
-
fill-range: 7.1.1
-
-
buffer-from@1.1.2: {}
-
-
callsites@3.1.0: {}
-
-
chalk@4.1.2:
-
dependencies:
-
ansi-styles: 4.3.0
-
supports-color: 7.2.0
-
-
chokidar@3.6.0:
-
dependencies:
-
anymatch: 3.1.3
-
braces: 3.0.3
-
glob-parent: 5.1.2
-
is-binary-path: 2.1.0
-
is-glob: 4.0.3
-
normalize-path: 3.0.0
-
readdirp: 3.6.0
-
optionalDependencies:
-
fsevents: 2.3.3
-
-
color-convert@2.0.1:
-
dependencies:
-
color-name: 1.1.4
-
-
color-name@1.1.4: {}
-
-
commander@9.5.0: {}
-
-
concat-map@0.0.1: {}
-
-
create-require@1.1.1: {}
-
-
cross-spawn@7.0.6:
-
dependencies:
-
path-key: 3.1.1
-
shebang-command: 2.0.0
-
which: 2.0.2
-
-
data-uri-to-buffer@4.0.1: {}
-
-
debug@4.4.3:
-
dependencies:
-
ms: 2.1.3
-
-
deep-is@0.1.4: {}
-
-
detect-libc@2.0.2: {}
-
-
diff@4.0.2: {}
-
-
dir-glob@3.0.1:
-
dependencies:
-
path-type: 4.0.0
-
-
dotenv@17.2.3: {}
-
-
drizzle-kit@0.31.5:
-
dependencies:
-
'@drizzle-team/brocli': 0.10.2
-
'@esbuild-kit/esm-loader': 2.6.5
-
esbuild: 0.25.11
-
esbuild-register: 3.6.0(esbuild@0.25.11)
-
transitivePeerDependencies:
-
- supports-color
-
-
drizzle-orm@0.44.6(@libsql/client@0.15.15):
-
optionalDependencies:
-
'@libsql/client': 0.15.15
-
-
esbuild-register@3.6.0(esbuild@0.25.11):
-
dependencies:
-
debug: 4.4.3
-
esbuild: 0.25.11
-
transitivePeerDependencies:
-
- supports-color
-
-
esbuild@0.18.20:
-
optionalDependencies:
-
'@esbuild/android-arm': 0.18.20
-
'@esbuild/android-arm64': 0.18.20
-
'@esbuild/android-x64': 0.18.20
-
'@esbuild/darwin-arm64': 0.18.20
-
'@esbuild/darwin-x64': 0.18.20
-
'@esbuild/freebsd-arm64': 0.18.20
-
'@esbuild/freebsd-x64': 0.18.20
-
'@esbuild/linux-arm': 0.18.20
-
'@esbuild/linux-arm64': 0.18.20
-
'@esbuild/linux-ia32': 0.18.20
-
'@esbuild/linux-loong64': 0.18.20
-
'@esbuild/linux-mips64el': 0.18.20
-
'@esbuild/linux-ppc64': 0.18.20
-
'@esbuild/linux-riscv64': 0.18.20
-
'@esbuild/linux-s390x': 0.18.20
-
'@esbuild/linux-x64': 0.18.20
-
'@esbuild/netbsd-x64': 0.18.20
-
'@esbuild/openbsd-x64': 0.18.20
-
'@esbuild/sunos-x64': 0.18.20
-
'@esbuild/win32-arm64': 0.18.20
-
'@esbuild/win32-ia32': 0.18.20
-
'@esbuild/win32-x64': 0.18.20
-
-
esbuild@0.25.11:
-
optionalDependencies:
-
'@esbuild/aix-ppc64': 0.25.11
-
'@esbuild/android-arm': 0.25.11
-
'@esbuild/android-arm64': 0.25.11
-
'@esbuild/android-x64': 0.25.11
-
'@esbuild/darwin-arm64': 0.25.11
-
'@esbuild/darwin-x64': 0.25.11
-
'@esbuild/freebsd-arm64': 0.25.11
-
'@esbuild/freebsd-x64': 0.25.11
-
'@esbuild/linux-arm': 0.25.11
-
'@esbuild/linux-arm64': 0.25.11
-
'@esbuild/linux-ia32': 0.25.11
-
'@esbuild/linux-loong64': 0.25.11
-
'@esbuild/linux-mips64el': 0.25.11
-
'@esbuild/linux-ppc64': 0.25.11
-
'@esbuild/linux-riscv64': 0.25.11
-
'@esbuild/linux-s390x': 0.25.11
-
'@esbuild/linux-x64': 0.25.11
-
'@esbuild/netbsd-arm64': 0.25.11
-
'@esbuild/netbsd-x64': 0.25.11
-
'@esbuild/openbsd-arm64': 0.25.11
-
'@esbuild/openbsd-x64': 0.25.11
-
'@esbuild/openharmony-arm64': 0.25.11
-
'@esbuild/sunos-x64': 0.25.11
-
'@esbuild/win32-arm64': 0.25.11
-
'@esbuild/win32-ia32': 0.25.11
-
'@esbuild/win32-x64': 0.25.11
-
-
escape-string-regexp@4.0.0: {}
-
-
eslint-scope@8.4.0:
-
dependencies:
-
esrecurse: 4.3.0
-
estraverse: 5.3.0
-
-
eslint-visitor-keys@3.4.3: {}
-
-
eslint-visitor-keys@4.2.1: {}
-
-
eslint@9.37.0(jiti@2.6.1):
-
dependencies:
-
'@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.6.1))
-
'@eslint-community/regexpp': 4.12.1
-
'@eslint/config-array': 0.21.0
-
'@eslint/config-helpers': 0.4.0
-
'@eslint/core': 0.16.0
-
'@eslint/eslintrc': 3.3.1
-
'@eslint/js': 9.37.0
-
'@eslint/plugin-kit': 0.4.0
-
'@humanfs/node': 0.16.7
-
'@humanwhocodes/module-importer': 1.0.1
-
'@humanwhocodes/retry': 0.4.3
-
'@types/estree': 1.0.8
-
'@types/json-schema': 7.0.15
-
ajv: 6.12.6
-
chalk: 4.1.2
-
cross-spawn: 7.0.6
-
debug: 4.4.3
-
escape-string-regexp: 4.0.0
-
eslint-scope: 8.4.0
-
eslint-visitor-keys: 4.2.1
-
espree: 10.4.0
-
esquery: 1.6.0
-
esutils: 2.0.3
-
fast-deep-equal: 3.1.3
-
file-entry-cache: 8.0.0
-
find-up: 5.0.0
-
glob-parent: 6.0.2
-
ignore: 5.3.2
-
imurmurhash: 0.1.4
-
is-glob: 4.0.3
-
json-stable-stringify-without-jsonify: 1.0.1
-
lodash.merge: 4.6.2
-
minimatch: 3.1.2
-
natural-compare: 1.4.0
-
optionator: 0.9.4
-
optionalDependencies:
-
jiti: 2.6.1
-
transitivePeerDependencies:
-
- supports-color
-
-
espree@10.4.0:
-
dependencies:
-
acorn: 8.15.0
-
acorn-jsx: 5.3.2(acorn@8.15.0)
-
eslint-visitor-keys: 4.2.1
-
-
esquery@1.6.0:
-
dependencies:
-
estraverse: 5.3.0
-
-
esrecurse@4.3.0:
-
dependencies:
-
estraverse: 5.3.0
-
-
estraverse@5.3.0: {}
-
-
esutils@2.0.3: {}
-
-
fast-deep-equal@3.1.3: {}
-
-
fast-glob@3.3.3:
-
dependencies:
-
'@nodelib/fs.stat': 2.0.5
-
'@nodelib/fs.walk': 1.2.8
-
glob-parent: 5.1.2
-
merge2: 1.4.1
-
micromatch: 4.0.8
-
-
fast-json-stable-stringify@2.1.0: {}
-
-
fast-levenshtein@2.0.6: {}
-
-
fastq@1.19.1:
-
dependencies:
-
reusify: 1.1.0
-
-
fetch-blob@3.2.0:
-
dependencies:
-
node-domexception: 1.0.0
-
web-streams-polyfill: 3.3.3
-
-
file-entry-cache@8.0.0:
-
dependencies:
-
flat-cache: 4.0.1
-
-
fill-range@7.1.1:
-
dependencies:
-
to-regex-range: 5.0.1
-
-
find-up@5.0.0:
-
dependencies:
-
locate-path: 6.0.0
-
path-exists: 4.0.0
-
-
flat-cache@4.0.1:
-
dependencies:
-
flatted: 3.3.3
-
keyv: 4.5.4
-
-
flatted@3.3.3: {}
-
-
formdata-polyfill@4.0.10:
-
dependencies:
-
fetch-blob: 3.2.0
-
-
fsevents@2.3.3:
-
optional: true
-
-
get-tsconfig@4.12.0:
-
dependencies:
-
resolve-pkg-maps: 1.0.0
-
-
glob-parent@5.1.2:
-
dependencies:
-
is-glob: 4.0.3
-
-
glob-parent@6.0.2:
-
dependencies:
-
is-glob: 4.0.3
-
-
globals@14.0.0: {}
-
-
globals@16.4.0: {}
-
-
globby@11.1.0:
-
dependencies:
-
array-union: 2.1.0
-
dir-glob: 3.0.1
-
fast-glob: 3.3.3
-
ignore: 5.3.2
-
merge2: 1.4.1
-
slash: 3.0.0
-
-
graphemer@1.4.0: {}
-
-
has-flag@4.0.0: {}
-
-
ignore@5.3.2: {}
-
-
ignore@7.0.5: {}
-
-
import-fresh@3.3.1:
-
dependencies:
-
parent-module: 1.0.1
-
resolve-from: 4.0.0
-
-
imurmurhash@0.1.4: {}
-
-
is-binary-path@2.1.0:
-
dependencies:
-
binary-extensions: 2.3.0
-
-
is-extglob@2.1.1: {}
-
-
is-glob@4.0.3:
-
dependencies:
-
is-extglob: 2.1.1
-
-
is-number@7.0.0: {}
-
-
isexe@2.0.0: {}
-
-
jiti@2.6.1: {}
-
-
js-base64@3.7.8: {}
-
-
js-yaml@4.1.0:
-
dependencies:
-
argparse: 2.0.1
-
-
json-buffer@3.0.1: {}
-
-
json-schema-traverse@0.4.1: {}
-
-
json-stable-stringify-without-jsonify@1.0.1: {}
-
-
json5@2.2.3: {}
-
-
keyv@4.5.4:
-
dependencies:
-
json-buffer: 3.0.1
-
-
levn@0.4.1:
-
dependencies:
-
prelude-ls: 1.2.1
-
type-check: 0.4.0
-
-
libsql@0.5.22:
-
dependencies:
-
'@neon-rs/load': 0.0.4
-
detect-libc: 2.0.2
-
optionalDependencies:
-
'@libsql/darwin-arm64': 0.5.22
-
'@libsql/darwin-x64': 0.5.22
-
'@libsql/linux-arm-gnueabihf': 0.5.22
-
'@libsql/linux-arm-musleabihf': 0.5.22
-
'@libsql/linux-arm64-gnu': 0.5.22
-
'@libsql/linux-arm64-musl': 0.5.22
-
'@libsql/linux-x64-gnu': 0.5.22
-
'@libsql/linux-x64-musl': 0.5.22
-
'@libsql/win32-x64-msvc': 0.5.22
-
-
locate-path@6.0.0:
-
dependencies:
-
p-locate: 5.0.0
-
-
lodash.merge@4.6.2: {}
-
-
make-error@1.3.6: {}
-
-
merge2@1.4.1: {}
-
-
micromatch@4.0.8:
-
dependencies:
-
braces: 3.0.3
-
picomatch: 2.3.1
-
-
minimatch@3.1.2:
-
dependencies:
-
brace-expansion: 1.1.12
-
-
minimatch@9.0.5:
-
dependencies:
-
brace-expansion: 2.0.2
-
-
minimist@1.2.8: {}
-
-
ms@2.1.3: {}
-
-
mylas@2.1.13: {}
-
-
nanoevents@9.1.0: {}
-
-
natural-compare@1.4.0: {}
-
-
node-domexception@1.0.0: {}
-
-
node-fetch@3.3.2:
-
dependencies:
-
data-uri-to-buffer: 4.0.1
-
fetch-blob: 3.2.0
-
formdata-polyfill: 4.0.10
-
-
normalize-path@3.0.0: {}
-
-
optionator@0.9.4:
-
dependencies:
-
deep-is: 0.1.4
-
fast-levenshtein: 2.0.6
-
levn: 0.4.1
-
prelude-ls: 1.2.1
-
type-check: 0.4.0
-
word-wrap: 1.2.5
-
-
p-limit@3.1.0:
-
dependencies:
-
yocto-queue: 0.1.0
-
-
p-locate@5.0.0:
-
dependencies:
-
p-limit: 3.1.0
-
-
parent-module@1.0.1:
-
dependencies:
-
callsites: 3.1.0
-
-
path-exists@4.0.0: {}
-
-
path-key@3.1.1: {}
-
-
path-type@4.0.0: {}
-
-
picomatch@2.3.1: {}
-
-
plimit-lit@1.6.1:
-
dependencies:
-
queue-lit: 1.5.2
-
-
prelude-ls@1.2.1: {}
-
-
prettier@3.6.2: {}
-
-
promise-limit@2.7.0: {}
-
-
punycode@2.3.1: {}
-
-
queue-lit@1.5.2: {}
-
-
queue-microtask@1.2.3: {}
-
-
readdirp@3.6.0:
-
dependencies:
-
picomatch: 2.3.1
-
-
resolve-from@4.0.0: {}
-
-
resolve-pkg-maps@1.0.0: {}
-
-
reusify@1.1.0: {}
-
-
run-parallel@1.2.0:
-
dependencies:
-
queue-microtask: 1.2.3
-
-
semver@7.7.3: {}
-
-
shebang-command@2.0.0:
-
dependencies:
-
shebang-regex: 3.0.0
-
-
shebang-regex@3.0.0: {}
-
-
slash@3.0.0: {}
-
-
source-map-support@0.5.21:
-
dependencies:
-
buffer-from: 1.1.2
-
source-map: 0.6.1
-
-
source-map@0.6.1: {}
-
-
strip-bom@3.0.0: {}
-
-
strip-json-comments@3.1.1: {}
-
-
supports-color@7.2.0:
-
dependencies:
-
has-flag: 4.0.0
-
-
to-regex-range@5.0.1:
-
dependencies:
-
is-number: 7.0.0
-
-
ts-api-utils@2.1.0(typescript@5.9.3):
-
dependencies:
-
typescript: 5.9.3
-
-
ts-node@10.9.2(@types/node@24.7.1)(typescript@5.9.3):
-
dependencies:
-
'@cspotcode/source-map-support': 0.8.1
-
'@tsconfig/node10': 1.0.11
-
'@tsconfig/node12': 1.0.11
-
'@tsconfig/node14': 1.0.3
-
'@tsconfig/node16': 1.0.4
-
'@types/node': 24.7.1
-
acorn: 8.15.0
-
acorn-walk: 8.3.4
-
arg: 4.1.3
-
create-require: 1.1.1
-
diff: 4.0.2
-
make-error: 1.3.6
-
typescript: 5.9.3
-
v8-compile-cache-lib: 3.0.1
-
yn: 3.1.1
-
-
tsc-alias@1.8.16:
-
dependencies:
-
chokidar: 3.6.0
-
commander: 9.5.0
-
get-tsconfig: 4.12.0
-
globby: 11.1.0
-
mylas: 2.1.13
-
normalize-path: 3.0.0
-
plimit-lit: 1.6.1
-
-
tsconfig-paths@4.2.0:
-
dependencies:
-
json5: 2.2.3
-
minimist: 1.2.8
-
strip-bom: 3.0.0
-
-
type-check@0.4.0:
-
dependencies:
-
prelude-ls: 1.2.1
-
-
typescript-eslint@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3):
-
dependencies:
-
'@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
-
'@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
-
'@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3)
-
'@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
-
eslint: 9.37.0(jiti@2.6.1)
-
typescript: 5.9.3
-
transitivePeerDependencies:
-
- supports-color
-
-
typescript@5.9.3: {}
-
-
undici-types@7.14.0: {}
-
-
uri-js@4.4.1:
-
dependencies:
-
punycode: 2.3.1
-
-
v8-compile-cache-lib@3.0.1: {}
-
-
web-streams-polyfill@3.3.3: {}
-
-
which@2.0.2:
-
dependencies:
-
isexe: 2.0.0
-
-
word-wrap@1.2.5: {}
-
-
ws@8.18.3: {}
-
-
yn@3.1.1: {}
-
-
yocto-queue@0.1.0: {}
-
-
yocto-queue@1.2.1: {}
-
-
zod@4.1.12: {}
+221
src/api/channel.ts
···
+
import * as xrpc from '@atproto/xrpc-server';
+
import { db } from '../db';
+
import { parseLimit } from '../util/params';
+
import { logger } from '../util/logger';
+
+
export async function listInvitesHandler(ctx: {
+
params: xrpc.Params;
+
}) {
+
try {
+
const { limit: rawLimit, cursor, recipient } = ctx.params;
+
const limit = parseLimit(rawLimit);
+
+
if (!recipient) {
+
throw new xrpc.InvalidRequestError('Missing required parameter: recipient');
+
}
+
+
if (typeof recipient !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "recipient" must be a string');
+
}
+
+
let query = db
+
.selectFrom('channel_invite as ci')
+
.innerJoin('channel as c', 'ci.channel', 'c.cid')
+
.select([
+
'ci.uri',
+
'ci.cid',
+
'ci.creator_did',
+
'ci.indexed_at',
+
'ci.created_at',
+
'ci.channel',
+
'c.uri as channel_uri'
+
])
+
.where('recipient_did', '=', recipient)
+
.orderBy('ci.indexed_at', 'desc')
+
.limit(limit);
+
+
if (cursor) {
+
if (typeof cursor !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "cursor" must be a string');
+
}
+
query = query.where('ci.indexed_at', '<', new Date(cursor));
+
}
+
+
const results = await query.execute();
+
+
const invites = results.map(row => {
+
return {
+
uri: row.uri,
+
cid: row.cid,
+
author: row.creator_did,
+
channel: {
+
uri: row.channel_uri,
+
cid: row.channel,
+
},
+
createdAt: row.created_at.toISOString(),
+
};
+
});
+
+
const lastResult = results.at(-1);
+
const nextCursor = lastResult ? lastResult.indexed_at.toISOString() : undefined;
+
+
return {
+
encoding: 'application/json',
+
body: {
+
invites,
+
cursor: nextCursor,
+
},
+
};
+
+
} catch (error) {
+
logger.error({ err: error }, 'Internal server error in listInvitesHandler');
+
throw error;
+
}
+
}
+
+
export async function listChannelsHandler(ctx: {
+
params: xrpc.Params;
+
}) {
+
try {
+
const { limit: rawLimit, cursor, author } = ctx.params;
+
const limit = parseLimit(rawLimit);
+
+
if (!author) {
+
throw new xrpc.InvalidRequestError('Missing required parameter: author');
+
}
+
+
if (typeof author !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "author" must be a string');
+
}
+
+
let query = db
+
.selectFrom('channel')
+
.select([
+
'uri',
+
'cid',
+
'creator_did',
+
'name',
+
'topic',
+
'created_at',
+
'indexed_at'
+
])
+
.where('creator_did', '=', author)
+
.orderBy('indexed_at', 'desc')
+
.limit(limit);
+
+
if (cursor) {
+
if (typeof cursor !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "cursor" must be a string');
+
}
+
query = query.where('indexed_at', '<', new Date(cursor));
+
}
+
+
const results = await query.execute();
+
+
const channels = results.map(row => {
+
return {
+
uri: row.uri,
+
cid: row.cid,
+
author: row.creator_did,
+
displayName: row.name,
+
description: row.topic,
+
createdAt: row.created_at.toISOString(),
+
indexedAt: row.indexed_at.toISOString(),
+
};
+
}).filter(item => item !== null);
+
+
const lastResult = results.at(-1);
+
const nextCursor = lastResult ? lastResult.indexed_at.toISOString() : undefined;
+
+
return {
+
encoding: 'application/json',
+
body: {
+
channels,
+
cursor: nextCursor,
+
},
+
};
+
+
} catch (error) {
+
logger.error({ err: error }, 'Internal server error in listChannelsHandler');
+
throw error;
+
}
+
}
+
+
export async function listMembershipsHandler(ctx: {
+
params: xrpc.Params;
+
}) {
+
try {
+
const { limit: rawLimit, cursor, recipient } = ctx.params;
+
const limit = parseLimit(rawLimit);
+
+
if (!recipient) {
+
throw new xrpc.InvalidRequestError('Missing required parameter: recipient');
+
}
+
+
if (typeof recipient !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "recipient" must be a string');
+
}
+
+
let query = db
+
.selectFrom('channel_membership as cm')
+
.innerJoin('channel as c', 'cm.channel', 'c.cid')
+
.innerJoin('channel_invite as i', 'cm.invite', 'i.cid')
+
.select([
+
'cm.uri',
+
'cm.cid',
+
'cm.state',
+
'cm.created_at',
+
'cm.updated_at',
+
'cm.indexed_at',
+
'cm.channel',
+
'c.uri as channel_uri',
+
'cm.invite',
+
'i.uri as invite_uri'
+
])
+
.where('cm.recipient_did', '=', recipient)
+
.orderBy('cm.indexed_at', 'desc')
+
.limit(limit);
+
+
if (cursor) {
+
if (typeof cursor !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "cursor" must be a string');
+
}
+
query = query.where('cm.indexed_at', '<', new Date(cursor));
+
}
+
+
const results = await query.execute();
+
+
const memberships = results.map(row => {
+
return {
+
uri: row.uri,
+
cid: row.cid,
+
state: row.state,
+
createdAt: row.created_at.toISOString(),
+
updatedAt: (row.updated_at ?? row.created_at).toISOString(),
+
channel: {
+
uri: row.channel_uri,
+
cid: row.channel,
+
},
+
invite: {
+
uri: row.invite_uri,
+
cid: row.invite,
+
},
+
};
+
}).filter(item => item !== null);
+
+
const lastResult = results.at(-1);
+
const nextCursor = lastResult ? lastResult.indexed_at.toISOString() : undefined;
+
+
return {
+
encoding: 'application/json',
+
body: {
+
memberships,
+
cursor: nextCursor,
+
},
+
};
+
+
} catch (error) {
+
logger.error({ err: error }, 'Internal server error in listMembershipsHandler');
+
throw error;
+
}
+
}
+17
src/api/index.ts
···
+
import * as xrpc from '@atproto/xrpc-server';
+
import { listInvitesHandler, listChannelsHandler, listMembershipsHandler } from './channel';
+
import { listLatticesHandler } from './lattice';
+
import { listShardsHandler } from './shard';
+
import { allLexicons } from '../lexicons';
+
+
export function createServer() {
+
const server = xrpc.createServer(allLexicons);
+
+
server.method('systems.gmstn.development.channel.listInvites', listInvitesHandler);
+
server.method('systems.gmstn.development.channel.listChannels', listChannelsHandler);
+
server.method('systems.gmstn.development.channel.listMemberships', listMembershipsHandler);
+
server.method('systems.gmstn.development.lattice.listLattices', listLatticesHandler);
+
server.method('systems.gmstn.development.shard.listShards', listShardsHandler);
+
+
return server;
+
}
+70
src/api/lattice.ts
···
+
import * as xrpc from '@atproto/xrpc-server';
+
import { db } from '../db';
+
import { parseLimit } from '../util/params';
+
import { logger } from '../util/logger';
+
+
export async function listLatticesHandler(ctx: {
+
params: xrpc.Params;
+
}) {
+
try {
+
const { limit: rawLimit, cursor, author } = ctx.params;
+
const limit = parseLimit(rawLimit);
+
+
if (!author) {
+
throw new xrpc.InvalidRequestError('Missing required parameter: author');
+
}
+
+
if (typeof author !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "author" must be a string');
+
}
+
+
let query = db
+
.selectFrom('lattice')
+
.select([
+
'uri',
+
'cid',
+
'creator_did',
+
'description',
+
'created_at',
+
'indexed_at'
+
])
+
.where('creator_did', '=', author)
+
.orderBy('indexed_at', 'desc')
+
.limit(limit);
+
+
if (cursor) {
+
if (typeof cursor !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "cursor" must be a string');
+
}
+
query = query.where('indexed_at', '<', new Date(cursor));
+
}
+
+
const results = await query.execute();
+
+
const lattices = results.map(row => {
+
return {
+
uri: row.uri,
+
cid: row.cid,
+
author: row.creator_did,
+
description: row.description,
+
createdAt: row.created_at.toISOString(),
+
indexedAt: row.indexed_at.toISOString(),
+
};
+
}).filter(item => item !== null);
+
+
const lastResult = results.at(-1);
+
const nextCursor = lastResult ? lastResult.indexed_at.toISOString() : undefined;
+
+
return {
+
encoding: 'application/json',
+
body: {
+
lattices,
+
cursor: nextCursor,
+
},
+
};
+
+
} catch (error) {
+
logger.error({ err: error }, 'Internal server error in listLatticesHandler');
+
throw error;
+
}
+
}
+70
src/api/shard.ts
···
+
import * as xrpc from '@atproto/xrpc-server';
+
import { db } from '../db';
+
import { parseLimit } from '../util/params';
+
import { logger } from '../util/logger';
+
+
export async function listShardsHandler(ctx: {
+
params: xrpc.Params;
+
}) {
+
try {
+
const { limit: rawLimit, cursor, author } = ctx.params;
+
const limit = parseLimit(rawLimit);
+
+
if (!author) {
+
throw new xrpc.InvalidRequestError('Missing required parameter: author');
+
}
+
+
if (typeof author !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "author" must be a string');
+
}
+
+
let query = db
+
.selectFrom('shard')
+
.select([
+
'uri',
+
'cid',
+
'creator_did',
+
'description',
+
'created_at',
+
'indexed_at'
+
])
+
.where('creator_did', '=', author)
+
.orderBy('indexed_at', 'desc')
+
.limit(limit);
+
+
if (cursor) {
+
if (typeof cursor !== 'string') {
+
throw new xrpc.InvalidRequestError('Parameter "cursor" must be a string');
+
}
+
query = query.where('indexed_at', '<', new Date(cursor));
+
}
+
+
const results = await query.execute();
+
+
const shards = results.map(row => {
+
return {
+
uri: row.uri,
+
cid: row.cid,
+
author: row.creator_did,
+
description: row.description,
+
createdAt: row.created_at.toISOString(),
+
indexedAt: row.indexed_at.toISOString(),
+
};
+
}).filter(item => item !== null);
+
+
const lastResult = results.at(-1);
+
const nextCursor = lastResult ? lastResult.indexed_at.toISOString() : undefined;
+
+
return {
+
encoding: 'application/json',
+
body: {
+
shards,
+
cursor: nextCursor,
+
},
+
};
+
+
} catch (error) {
+
logger.error({ err: error }, 'Internal server error in listShardsHandler');
+
throw error;
+
}
+
}
+126
src/db.ts
···
+
import { Kysely, PostgresDialect, Generated } from 'kysely'
+
import { Pool } from 'pg'
+
import dotenv from 'dotenv'
+
+
dotenv.config();
+
+
type JsonValue = string | number | boolean | null | { [key: string]: JsonValue } | JsonValue[];
+
+
interface FirehoseEventTable {
+
timestamp: Date
+
event_type: 'commit' | 'identity' | 'account'
+
event_data: JsonValue
+
};
+
+
interface PdsTable {
+
hostname: string;
+
added_at: Generated<Date>;
+
}
+
+
interface AccountTable {
+
did: string;
+
handle: string;
+
pds_hostname: string | null;
+
created_at: Generated<Date>;
+
}
+
+
interface LatticeTable {
+
uri: string;
+
cid: string;
+
creator_did: string;
+
description: string | null;
+
created_at: Generated<Date>;
+
indexed_at: Generated<Date>;
+
data: JsonValue;
+
}
+
+
interface ShardTable {
+
uri: string;
+
cid: string;
+
creator_did: string;
+
description: string | null;
+
created_at: Generated<Date>;
+
indexed_at: Generated<Date>;
+
data: JsonValue;
+
}
+
+
interface ChannelTable {
+
cid: string;
+
uri: string | null;
+
creator_did: string | null;
+
name: string | null;
+
topic: string | null;
+
created_at: Generated<Date>;
+
indexed_at: Generated<Date>;
+
data: JsonValue | null;
+
}
+
+
interface ChannelInviteTable {
+
cid: string;
+
uri: string | null;
+
channel: string | null;
+
creator_did: string | null;
+
recipient_did: string | null;
+
created_at: Generated<Date>;
+
indexed_at: Generated<Date>;
+
data: JsonValue | null;
+
}
+
+
interface ChannelMembershipTable {
+
uri: string;
+
cid: string;
+
channel: string;
+
invite: string;
+
recipient_did: string;
+
state: string;
+
created_at: Generated<Date>;
+
indexed_at: Generated<Date>;
+
updated_at: Date | null;
+
data: JsonValue;
+
}
+
+
type RawRecordQueueStatus = 'pending' | 'processing' | 'complete' | 'failed';
+
+
interface RawRecordQueueTable {
+
id: Generated<number>;
+
record_data: JsonValue;
+
status: Generated<RawRecordQueueStatus>;
+
created_at: Generated<Date>;
+
updated_at: Generated<Date>;
+
}
+
+
interface FirehoseCursorTable {
+
id: number;
+
cursor: string;
+
updated_at: Generated<Date>;
+
}
+
+
+
export interface Database {
+
firehose_event: FirehoseEventTable;
+
firehose_cursor: FirehoseCursorTable;
+
+
pds: PdsTable;
+
account: AccountTable;
+
lattice: LatticeTable;
+
shard: ShardTable;
+
channel: ChannelTable;
+
channel_invite: ChannelInviteTable;
+
channel_membership: ChannelMembershipTable;
+
raw_record_queue: RawRecordQueueTable;
+
};
+
+
const pool = new Pool({
+
connectionString: process.env.DATABASE_URL,
+
max: process.env.DB_POOL_SIZE ? parseInt(process.env.DB_POOL_SIZE, 10) : 10,
+
});
+
+
const dialect = new PostgresDialect({
+
pool,
+
});
+
+
export const db = new Kysely<Database>({
+
dialect,
+
});
+
+
export { pool };
+69 -2
src/index.ts
···
-
const main = () => {
-
console.log("Hello!!");
+
import { logger } from './util/logger';
+
+
logger.info('Main app starting...');
+
+
const spawnOptions: any = {
+
stdout: 'inherit',
+
stderr: 'inherit',
+
};
+
+
const dir = __dirname;
+
+
type Subprocess = ReturnType<typeof Bun.spawn>;
+
+
let pdsListSyncProcess: Subprocess | undefined;
+
let pdsBackfillProcess: Subprocess | undefined;
+
let firehoseProcess: Subprocess | undefined;
+
let serverProcess: Subprocess | undefined;
+
+
async function main() {
+
// Run PDS List Sync first and wait for it to complete
+
const pdsListSyncPath = `${dir}/pds/discovery.ts`;
+
pdsListSyncProcess = Bun.spawn(['bun', pdsListSyncPath], spawnOptions);
+
logger.info({ pid: pdsListSyncProcess.pid }, 'pdsListSync process started');
+
+
await pdsListSyncProcess.exited;
+
logger.info('pdsListSync process completed');
+
pdsListSyncProcess = undefined;
+
+
const pdsBackfillPath = `${dir}/pds/backfill.ts`;
+
pdsBackfillProcess = Bun.spawn(['bun', pdsBackfillPath], spawnOptions);
+
logger.info({ pid: pdsBackfillProcess.pid }, 'pdsBackfill process started');
+
+
const firehosePath = `${dir}/services/firehose-listen.ts`;
+
firehoseProcess = Bun.spawn(['bun', firehosePath], spawnOptions);
+
logger.info({ pid: firehoseProcess.pid }, 'Firehose process started');
+
+
firehoseProcess.exited.then((code) => {
+
logger.error({ code }, 'Firehose process exited');
+
});
+
+
const serverPath = `${dir}/services/api.ts`;
+
serverProcess = Bun.spawn(['bun', serverPath], spawnOptions);
+
logger.info({ pid: serverProcess.pid }, 'XRPC Server process started');
+
+
serverProcess.exited.then((code) => {
+
logger.error({ code }, 'XRPC Server process exited');
+
});
+
}
+
+
const cleanup = () => {
+
logger.info('Stopping all subprocesses...');
+
+
if (pdsListSyncProcess && !pdsListSyncProcess.killed) {
+
pdsListSyncProcess.kill();
+
}
+
if (pdsBackfillProcess && !pdsBackfillProcess.killed) {
+
pdsBackfillProcess.kill();
+
}
+
if (firehoseProcess && !firehoseProcess.killed) {
+
firehoseProcess.kill();
+
}
+
if (serverProcess && !serverProcess.killed) {
+
serverProcess.kill();
+
}
+
+
process.exit(0);
};
+
+
process.on('SIGINT', cleanup);
+
process.on('SIGTERM', cleanup);
main();
+30
src/lexicons.ts
···
+
import fs from 'fs';
+
import path from 'path';
+
+
export const listInvitesLexicon = JSON.parse(
+
fs.readFileSync(path.join(__dirname, '../lexicons/systems/gmstn/development/channel/listInvites.json'), 'utf8')
+
);
+
+
export const listChannelsLexicon = JSON.parse(
+
fs.readFileSync(path.join(__dirname, '../lexicons/systems/gmstn/development/channel/listChannels.json'), 'utf8')
+
);
+
+
export const listMembershipsLexicon = JSON.parse(
+
fs.readFileSync(path.join(__dirname, '../lexicons/systems/gmstn/development/channel/listMemberships.json'), 'utf8')
+
);
+
+
export const listLatticesLexicon = JSON.parse(
+
fs.readFileSync(path.join(__dirname, '../lexicons/systems/gmstn/development/lattice/listLattices.json'), 'utf8')
+
);
+
+
export const listShardsLexicon = JSON.parse(
+
fs.readFileSync(path.join(__dirname, '../lexicons/systems/gmstn/development/shard/listShards.json'), 'utf8')
+
);
+
+
export const allLexicons = [
+
listInvitesLexicon,
+
listChannelsLexicon,
+
listMembershipsLexicon,
+
listLatticesLexicon,
+
listShardsLexicon,
+
];
+223
src/pds/backfill.ts
···
+
import { sql } from 'kysely';
+
import { fromUint8Array } from '@atcute/repo';
+
import { db } from 'db';
+
import { RecordProcessor, AtpRecord } from 'util/recordProcessor';
+
import { logger } from '../util/logger';
+
+
interface NewAccount {
+
did: string;
+
handle: string;
+
pds_hostname: string;
+
created_at: any;
+
}
+
+
interface RequestData {
+
cursor?: string;
+
repos: {
+
did: string;
+
}[];
+
}
+
+
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
+
+
async function processSingleRepo(pdsHostname: string, did: string): Promise<void> {
+
const pdsBaseUrl = `https://${pdsHostname}`;
+
const getRepoUrl = new URL(`/xrpc/com.atproto.sync.getRepo`, pdsBaseUrl);
+
getRepoUrl.searchParams.set('did', did);
+
+
let carBytes: Uint8Array;
+
try {
+
const response = await fetch(getRepoUrl.href);
+
if (!response.ok) {
+
throw new Error(`Failed to getRepo for ${did}: ${response.status} ${response.statusText}`);
+
}
+
carBytes = new Uint8Array(await response.arrayBuffer());
+
} catch (e: any) {
+
return;
+
}
+
+
const processor = new RecordProcessor(did);
+
+
try {
+
for (const entry of fromUint8Array(carBytes)) {
+
const { collection, rkey, record: rawRecord } = entry;
+
const record = rawRecord as AtpRecord;
+
+
if (
+
collection &&
+
collection.startsWith('systems.gmstn.development.')
+
) {
+
const uri = `at://${did}/${collection}/${rkey}`;
+
const cid = entry.cid.$link;
+
+
await processor.processRecord(record, uri, cid, record.createdAt, false);
+
}
+
}
+
} catch (e: any) {
+
logger.debug({ err: e, did }, "Error processing repo. Skipping rest of repo.");
+
return;
+
}
+
+
await processor.insertAllProcessedRecords(false);
+
}
+
+
async function backfillPds(pdsHostname: string) {
+
logger.info({ pdsHostname }, "Starting backfill");
+
const pdsBaseUrl = `https://` + pdsHostname;
+
let cursor: string | undefined;
+
let totalReposProcessed = 0;
+
+
try {
+
do {
+
const listReposUrl = new URL('/xrpc/com.atproto.sync.listRepos', pdsBaseUrl);
+
if (cursor) {
+
listReposUrl.searchParams.set('cursor', cursor);
+
}
+
+
const response = await fetch(listReposUrl.href);
+
if (!response.ok) {
+
throw new Error(`Failed to listRepos: ${response.status} ${response.statusText}`);
+
}
+
+
const data = await response.json() as RequestData;
+
cursor = data.cursor;
+
const dids: string[] = data.repos.map((r: { did: string }) => r.did);
+
+
if (dids.length === 0) {
+
break;
+
}
+
+
logger.debug({ count: dids.length, cursor }, "Fetched repos");
+
+
const newAccounts: NewAccount[] = dids.map(repo => ({
+
did: repo,
+
handle: repo,
+
pds_hostname: pdsHostname,
+
created_at: sql`now()`,
+
}));
+
+
if (newAccounts.length > 0) {
+
try {
+
await db.insertInto('account')
+
.values(newAccounts)
+
.onConflict((oc) => oc
+
.column('did')
+
.doUpdateSet({
+
pds_hostname: sql`excluded.pds_hostname`,
+
})
+
)
+
.execute();
+
} catch (e: any) {
+
logger.error({ err: e }, "Failed to bulk upsert accounts");
+
}
+
}
+
+
const BATCH_SIZE = 10;
+
for (let i = 0; i < dids.length; i += BATCH_SIZE) {
+
const batch = dids.slice(i, i + BATCH_SIZE);
+
const tasks = batch.map(did => processSingleRepo(pdsHostname, did));
+
await Promise.allSettled(tasks);
+
}
+
+
totalReposProcessed += dids.length;
+
+
} while (cursor);
+
+
logger.info({ pdsHostname, totalReposProcessed }, "Finished paginating repos. Backfill complete for PDS.");
+
+
} catch (error) {
+
logger.error({ err: error, pdsHostname }, "Fatal error during backfill");
+
throw error;
+
}
+
}
+
+
async function main() {
+
const backfilledThisSession = new Set<string>();
+
let shouldExit = false;
+
+
const shutdown = (signal: string) => {
+
logger.info(`Received ${signal}, stopping backfill after current batch...`);
+
shouldExit = true;
+
};
+
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
+
process.on('SIGINT', () => shutdown('SIGINT'));
+
+
const PDS_CONCURRENCY = 32;
+
+
logger.info("Starting Backfill Daemon...");
+
+
while (!shouldExit) {
+
let pdsesToBackfill: { hostname: string }[] = [];
+
+
try {
+
pdsesToBackfill = await db
+
.selectFrom('pds')
+
.select('hostname')
+
// .where('hostname', 'in', ['pds.witchcraft.systems', 'pds.tgirl.cloud', 'pds.gmstn.systems'])
+
.orderBy(
+
(eb) => eb
+
.case()
+
.when('hostname', 'like', '%brid.gy%')
+
.then(1)
+
.else(0)
+
.end(),
+
'asc'
+
)
+
.orderBy('added_at', 'asc')
+
.execute();
+
+
pdsesToBackfill = pdsesToBackfill.filter(p => !backfilledThisSession.has(p.hostname));
+
+
if (pdsesToBackfill.length === 0) {
+
logger.info('No new PDSs found to backfill. Sleeping for 10s...');
+
+
for (let i = 0; i < 100; i++) {
+
if (shouldExit) break;
+
await delay(100);
+
}
+
continue;
+
}
+
+
logger.info({ count: pdsesToBackfill.length }, "Found new PDS(s) to backfill. Starting batches...");
+
+
for (let i = 0; i < pdsesToBackfill.length; i += PDS_CONCURRENCY) {
+
if (shouldExit) break;
+
+
const batch = pdsesToBackfill.slice(i, i + PDS_CONCURRENCY);
+
+
logger.info({
+
batchIndex: Math.floor(i / PDS_CONCURRENCY) + 1,
+
totalBatches: Math.ceil(pdsesToBackfill.length / PDS_CONCURRENCY),
+
batchSize: batch.length
+
}, "Processing PDS batch");
+
+
const tasks = batch.map(async (pds) => {
+
if (backfilledThisSession.has(pds.hostname)) return;
+
+
try {
+
await backfillPds(pds.hostname);
+
backfilledThisSession.add(pds.hostname);
+
} catch (e) {
+
logger.error({ err: e, pdsHostname: pds.hostname }, "Job for PDS failed. Moving to next PDS.");
+
}
+
});
+
+
await Promise.allSettled(tasks);
+
}
+
} catch (e: any) {
+
logger.error({ err: e }, "Fatal error during backfill daemon loop");
+
await delay(5000);
+
}
+
}
+
+
logger.info('Backfill daemon exited gracefully.');
+
process.exit(0);
+
}
+
+
if (require.main === module) {
+
main().catch((err) => {
+
console.error(err);
+
process.exit(1);
+
});
+
}
+280
src/pds/discovery.ts
···
+
import { Readable } from 'stream';
+
import readline from 'readline';
+
import { db } from 'db';
+
import { logger } from '../util/logger';
+
import { sql } from 'kysely';
+
+
const GITHUB_PDS_LIST_URL = 'https://raw.githubusercontent.com/mary-ext/atproto-scraping/refs/heads/trunk/state.json';
+
const PLC_EXPORT_URL = 'https://plc.directory/export';
+
+
interface GithubStateJson {
+
pdses: {
+
[url: string]: {
+
inviteCodeRequired?: boolean;
+
version?: string;
+
}
+
}
+
}
+
+
interface PlcEntry {
+
did: string;
+
operation: {
+
type: string;
+
alsoKnownAs?: string[];
+
handle?: string;
+
services?: {
+
[key: string]: {
+
type: string;
+
endpoint: string;
+
};
+
};
+
};
+
createdAt: string;
+
}
+
+
async function syncFromGithub(): Promise<boolean> {
+
logger.info('PRIMARY: Starting PDS list sync from GitHub (Mary-ext)...');
+
+
try {
+
const response = await fetch(GITHUB_PDS_LIST_URL);
+
if (!response.ok) {
+
throw new Error(`Failed to fetch PDS list: ${response.statusText}`);
+
}
+
+
const data = (await response.json()) as GithubStateJson;
+
const pdsUrls = Object.keys(data?.pdses || {});
+
+
if (pdsUrls.length === 0) {
+
logger.warn('No PDS hosts found in the upstream GitHub list.');
+
return false;
+
}
+
+
const pdsToInsert = pdsUrls
+
.map(url => {
+
try {
+
return { hostname: new URL(url).hostname };
+
} catch (e) {
+
return null;
+
}
+
})
+
.filter(Boolean) as { hostname: string }[];
+
+
if (pdsToInsert.length > 0) {
+
const CHUNK_SIZE = 1000;
+
let insertedCount = 0;
+
+
for (let i = 0; i < pdsToInsert.length; i += CHUNK_SIZE) {
+
const batch = pdsToInsert.slice(i, i + CHUNK_SIZE);
+
await db
+
.insertInto('pds')
+
.values(batch)
+
.onConflict((oc) => oc.column('hostname').doNothing())
+
.execute();
+
insertedCount += batch.length;
+
}
+
logger.info({ count: insertedCount }, "GitHub PDS sync complete.");
+
return true;
+
} else {
+
logger.info('No valid PDS hostnames parsed from GitHub.');
+
return false;
+
}
+
+
} catch (error) {
+
logger.error({ err: error }, "Error during GitHub PDS list sync");
+
return false;
+
}
+
}
+
+
async function syncFromPlc() {
+
logger.info('BACKUP: Starting PDS/Account sync from PLC Directory...');
+
+
let after: string | undefined;
+
try {
+
const result = await db
+
.selectFrom('account')
+
.select(sql<string>`max(created_at)`.as('max_created_at'))
+
.executeTakeFirst();
+
+
if (result?.max_created_at) {
+
after = new Date(result.max_created_at).toISOString();
+
logger.info({ after }, 'Resuming PLC sync from latest account created_at');
+
}
+
} catch (err) {
+
logger.warn({ err }, 'Failed to fetch latest cursor from DB, starting PLC sync from beginning');
+
}
+
+
const limit = 100000;
+
+
try {
+
while (true) {
+
const url = `${PLC_EXPORT_URL}?count=${limit}${after ? `&after=${after}` : ''}`;
+
logger.info({ url }, 'Fetching PLC export batch');
+
+
const response = await fetch(url);
+
+
if (response.status === 429) {
+
const delay = 90_000;
+
logger.warn(`Rate limited, waiting ${delay}ms...`);
+
await new Promise(resolve => setTimeout(resolve, delay));
+
continue;
+
}
+
+
if (!response.ok) {
+
throw new Error(`Failed to fetch PLC export: ${response.statusText}`);
+
}
+
+
if (!response.body) {
+
break;
+
}
+
+
const nodeStream = Readable.fromWeb(response.body as import('stream/web').ReadableStream);
+
const rl = readline.createInterface({
+
input: nodeStream,
+
crlfDelay: Infinity,
+
});
+
+
let lineCount = 0;
+
let lastCreatedAt: string | undefined;
+
+
const pdsToInsert = new Set<string>();
+
const accountsToUpsert = new Map<string, { did: string; handle: string; pds_hostname: string | null; created_at: string }>();
+
+
for await (const line of rl) {
+
lineCount++;
+
if (!line.trim()) continue;
+
+
try {
+
const entry = JSON.parse(line) as PlcEntry;
+
lastCreatedAt = entry.createdAt;
+
+
if (entry.operation.type === 'plc_operation' || entry.operation.type === 'create') {
+
let pdsHostname: string | null = null;
+
+
const services = entry.operation.services;
+
if (services) {
+
const pdsService = services['atproto_pds'];
+
if (pdsService && pdsService.type === 'AtprotoPersonalDataServer' && pdsService.endpoint) {
+
try {
+
pdsHostname = new URL(pdsService.endpoint).hostname;
+
pdsToInsert.add(pdsHostname);
+
} catch {
+
}
+
}
+
}
+
+
let handle: string | undefined = entry.operation.handle;
+
if (!handle && entry.operation.alsoKnownAs) {
+
const atHandle = entry.operation.alsoKnownAs.find(aka => aka.startsWith('at://'));
+
if (atHandle) {
+
handle = atHandle.replace('at://', '');
+
}
+
}
+
+
if (handle) {
+
accountsToUpsert.set(entry.did, {
+
did: entry.did,
+
handle: handle,
+
pds_hostname: pdsHostname,
+
created_at: entry.createdAt
+
});
+
}
+
}
+
} catch {
+
continue;
+
}
+
}
+
+
if (pdsToInsert.size > 0) {
+
const pdsValues = Array.from(pdsToInsert).map(hostname => ({ hostname }));
+
await db
+
.insertInto('pds')
+
.values(pdsValues)
+
.onConflict((oc) => oc.column('hostname').doNothing())
+
.execute();
+
}
+
+
if (accountsToUpsert.size > 0) {
+
const accountValues = Array.from(accountsToUpsert.values()).map(acc => ({
+
...acc,
+
created_at: new Date(acc.created_at)
+
}));
+
+
const ACCOUNT_BATCH_SIZE = 500;
+
for (let i = 0; i < accountValues.length; i += ACCOUNT_BATCH_SIZE) {
+
const batch = accountValues.slice(i, i + ACCOUNT_BATCH_SIZE);
+
try {
+
await db
+
.insertInto('account')
+
.values(batch)
+
.onConflict((oc) => oc
+
.column('did')
+
.doUpdateSet((eb) => ({
+
handle: eb.ref('excluded.handle'),
+
pds_hostname: eb.ref('excluded.pds_hostname'),
+
created_at: eb.ref('excluded.created_at')
+
}))
+
)
+
.execute();
+
} catch (err) {
+
for (const acc of batch) {
+
try {
+
await db
+
.insertInto('account')
+
.values(acc)
+
.onConflict((oc) => oc
+
.column('did')
+
.doUpdateSet((eb) => ({
+
handle: eb.ref('excluded.handle'),
+
pds_hostname: eb.ref('excluded.pds_hostname'),
+
created_at: eb.ref('excluded.created_at')
+
}))
+
)
+
.execute();
+
} catch (innerErr) { }
+
}
+
}
+
}
+
}
+
+
if (lineCount === 0) {
+
logger.info('Reached end of stream (0 lines received)');
+
break;
+
}
+
+
if (lastCreatedAt) {
+
if (after === lastCreatedAt) {
+
logger.warn({ after }, 'Cursor did not advance despite receiving data. Stopping.');
+
break;
+
}
+
after = lastCreatedAt;
+
}
+
}
+
logger.info("PLC Directory sync complete");
+
+
} catch (error) {
+
logger.error({ err: error }, "Error during PLC sync");
+
throw error;
+
}
+
}
+
+
async function main() {
+
if (!(await syncFromGithub())) {
+
await syncFromPlc();
+
} else {
+
logger.info("Primary GitHub sync succeeded; skipping PLC directory backup.");
+
}
+
}
+
+
if (require.main === module) {
+
main()
+
.then(() => {
+
logger.info('Discovery finished successfully.');
+
db.destroy();
+
process.exit(0);
+
})
+
.catch((err) => {
+
logger.error({ err }, 'Unhandled error in discovery');
+
db.destroy();
+
process.exit(1);
+
});
+
}
+60
src/scripts/migrate.ts
···
+
import * as path from 'path'
+
import { promises as fs } from 'fs'
+
import { Migrator, FileMigrationProvider } from 'kysely'
+
import { db } from '../db'
+
+
async function migrate(direction: 'up' | 'down' | 'latest') {
+
const migrator = new Migrator({
+
db,
+
provider: new FileMigrationProvider({
+
fs,
+
path,
+
migrationFolder: path.join(__dirname, '../../migrations'),
+
}),
+
})
+
+
console.log(`Running migration: ${direction}`);
+
+
if (direction === 'down') {
+
const { error, results } = await migrator.migrateDown()
+
results?.forEach((it) => {
+
if (it.status === 'Success') {
+
console.log(`migration "${it.migrationName}" was reverted successfully`)
+
} else if (it.status === 'Error') {
+
console.error(`failed to revert migration "${it.migrationName}"`)
+
}
+
})
+
if (error) {
+
console.error('failed to migrate')
+
console.error(error)
+
process.exit(1)
+
}
+
}
+
+
if (direction === 'up' || direction === 'latest') {
+
const { error, results } = await migrator.migrateToLatest()
+
results?.forEach((it) => {
+
if (it.status === 'Success') {
+
console.log(`migration "${it.migrationName}" was executed successfully`)
+
} else if (it.status === 'Error') {
+
console.error(`failed to execute migration "${it.migrationName}"`)
+
}
+
})
+
if (error) {
+
console.error('failed to migrate')
+
console.error(error)
+
process.exit(1)
+
}
+
}
+
+
await db.destroy()
+
}
+
+
const direction = process.argv[2] as 'up' | 'down' | 'latest' | undefined;
+
+
if (!direction || !['up', 'down', 'latest'].includes(direction)) {
+
console.error('Please provide a migration direction: up, down, or latest');
+
process.exit(1);
+
}
+
+
migrate(direction);
+56
src/scripts/start-backfill.ts
···
+
import { logger } from '../util/logger';
+
+
const spawnOptions: { stdout: 'inherit' | 'pipe' | 'ignore', stderr: 'inherit' | 'pipe' | 'ignore' } = {
+
stdout: 'inherit',
+
stderr: 'inherit',
+
};
+
+
const dir = import.meta.dir + '/..';
+
+
type Subprocess = ReturnType<typeof Bun.spawn>;
+
+
let discoveryProcess: Subprocess | undefined;
+
let backfillProcess: Subprocess | undefined;
+
+
async function main() {
+
logger.info('Starting parallel backfill operations...');
+
+
const backfillPath = `${dir}/pds/backfill.ts`;
+
backfillProcess = Bun.spawn(['bun', backfillPath], spawnOptions);
+
logger.info({ pid: backfillProcess.pid }, 'Backfill (Worker) process started');
+
+
const discoveryPath = `${dir}/pds/discovery.ts`;
+
discoveryProcess = Bun.spawn(['bun', discoveryPath], spawnOptions);
+
logger.info({ pid: discoveryProcess.pid }, 'Discovery (PLC Sync) process started');
+
+
if (discoveryProcess) {
+
await discoveryProcess.exited;
+
logger.info('Discovery process finished syncing.');
+
logger.info('Backfill worker is still running to process the queue. Press Ctrl+C to stop.');
+
}
+
+
if (backfillProcess) {
+
await backfillProcess.exited;
+
logger.warn('Backfill worker exited unexpectedly.');
+
}
+
}
+
+
const cleanup = () => {
+
logger.info('\nStopping backfill subprocesses...');
+
+
if (discoveryProcess && !discoveryProcess.killed) {
+
discoveryProcess.kill();
+
logger.info('Killed discovery process');
+
}
+
if (backfillProcess && !backfillProcess.killed) {
+
backfillProcess.kill('SIGTERM');
+
logger.info('Signaled backfill process to stop (waiting for graceful exit)...');
+
}
+
+
setTimeout(() => process.exit(0), 1000);
+
};
+
+
process.on('SIGINT', cleanup);
+
process.on('SIGTERM', cleanup);
+
+
main();
+60
src/services/api.ts
···
+
import { db, pool } from 'db';
+
import { logger } from '../util/logger';
+
import express from 'express';
+
import helmet from 'helmet';
+
import compression from 'compression';
+
import * as http from 'http';
+
import { createServer } from '../api';
+
import { createWebSocketServer, closeAllClients } from './websocket';
+
import { setupQueueListener, processQueue, setShuttingDown } from './queue';
+
+
const server = createServer();
+
+
const app = express();
+
app.use(helmet());
+
app.use(compression());
+
app.use(server.router);
+
+
const httpServer = http.createServer(app);
+
createWebSocketServer(httpServer);
+
+
let queuePoller: ReturnType<typeof setInterval>;
+
+
httpServer.listen(3000, () => {
+
logger.info('XRPC server running on http://localhost:3000');
+
logger.info('WebSocket server initialized and listening.');
+
+
setupQueueListener();
+
+
processQueue();
+
+
// Heartbeat / Fallback poller (every 30s)
+
queuePoller = setInterval(processQueue, 30000);
+
});
+
+
const shutdown = async () => {
+
logger.info('Shutting down server...');
+
+
setShuttingDown(true);
+
clearInterval(queuePoller);
+
+
httpServer.close(() => {
+
logger.info('HTTP server closed');
+
});
+
+
closeAllClients();
+
+
try {
+
await pool.end();
+
logger.info('Database pool closed');
+
await db.destroy();
+
logger.info('Kysely instance destroyed');
+
} catch (err) {
+
logger.error({ err }, 'Error during database shutdown');
+
}
+
+
process.exit(0);
+
};
+
+
process.on('SIGTERM', shutdown);
+
process.on('SIGINT', shutdown);
+85
src/services/firehose-listen.ts
···
+
import { Firehose, CommitEvent, AccountEvent, IdentityEvent } from "@skyware/firehose";
+
import WebSocket from "ws";
+
import { RecordProcessor, AtpRecord } from "util/recordProcessor";
+
import { db } from "../db";
+
import { logger } from "../util/logger";
+
+
const main = async () => {
+
logger.info("Starting Firehose listener...");
+
+
let lastCursor: string | undefined;
+
try {
+
const result = await db.selectFrom('firehose_cursor')
+
.select('cursor')
+
.where('id', '=', 1)
+
.executeTakeFirst();
+
lastCursor = result?.cursor;
+
} catch (err) {
+
logger.error({ err }, "Failed to retrieve cursor from DB");
+
}
+
+
const firehose = new Firehose({
+
ws: WebSocket,
+
cursor: lastCursor,
+
});
+
+
let eventCount = 0;
+
+
firehose.on("commit", async (commit: CommitEvent) => {
+
const { repo: did, time: indexedAt, seq } = commit;
+
+
const processor = new RecordProcessor(did);
+
const createOps = commit.ops.filter(op => op.action === 'create');
+
+
for (const op of createOps) {
+
const record = op.record as AtpRecord;
+
const uri = `at://${did}/${op.path}`;
+
const cid = op.cid.toString();
+
+
await processor.processRecord(record, uri, cid, indexedAt, true);
+
}
+
+
await processor.insertAllProcessedRecords(true);
+
+
if (seq) {
+
eventCount++;
+
if (eventCount >= 20) {
+
eventCount = 0;
+
await db.updateTable('firehose_cursor')
+
.set({ cursor: seq.toString(), updated_at: new Date() })
+
.where('id', '=', 1)
+
.execute();
+
}
+
}
+
});
+
+
firehose.on("open", () => {
+
logger.info("Connection opened");
+
});
+
+
firehose.on("close", async (cursor) => {
+
logger.info({ cursor }, "Connection closed. Restarting.");
+
if (cursor) {
+
await db.updateTable('firehose_cursor')
+
.set({ cursor: cursor.toString(), updated_at: new Date() })
+
.where('id', '=', 1)
+
.execute();
+
firehose.cursor = cursor.toString();
+
}
+
firehose.start();
+
});
+
+
firehose.on("error", ({ error, cursor }) => {
+
logger.error({ err: error, cursor }, "An error occurred");
+
});
+
+
if (lastCursor && lastCursor !== '0') {
+
logger.info({ cursor: lastCursor }, "Resuming from cursor");
+
}
+
+
firehose.start();
+
+
logger.info("Listeners attached. Waiting for events...");
+
};
+
+
main();
+97
src/services/queue.ts
···
+
import { db, pool } from '../db';
+
import { sql } from 'kysely';
+
import { logger } from '../util/logger';
+
import { broadcast, getClientCount } from './websocket';
+
+
import { PoolClient } from 'pg';
+
+
const BATCH_SIZE = 25;
+
let listenerClient: PoolClient | null = null;
+
let isShuttingDown = false;
+
+
export function setShuttingDown(value: boolean) {
+
isShuttingDown = value;
+
if (value && listenerClient) {
+
listenerClient.release();
+
listenerClient = null;
+
}
+
}
+
+
async function popQueue(): Promise<any[]> {
+
if (isShuttingDown) return [];
+
+
try {
+
const records = await db.transaction().execute(async (trx) => {
+
const foundRecords = await trx
+
.selectFrom('raw_record_queue')
+
.selectAll()
+
.where('status', '=', 'pending')
+
.orderBy('created_at', 'asc')
+
.limit(BATCH_SIZE)
+
.forUpdate()
+
.skipLocked()
+
.execute();
+
+
if (foundRecords.length === 0) {
+
return [];
+
}
+
+
const recordIds = foundRecords.map((r: any) => r.id);
+
+
await trx
+
.updateTable('raw_record_queue')
+
.set({ status: 'complete', updated_at: sql`now()` })
+
.where('id', 'in', recordIds)
+
.execute();
+
+
return foundRecords;
+
});
+
+
return records;
+
} catch (e: any) {
+
logger.error({ err: e }, 'Error popping queue');
+
return [];
+
}
+
}
+
+
export async function processQueue() {
+
const records = await popQueue();
+
+
if (records.length > 0) {
+
logger.debug({ count: records.length, clients: getClientCount() }, 'Popped records, broadcasting to clients');
+
+
const recordData = records.map((r: any) => r.record_data);
+
+
broadcast({
+
type: 'new_records',
+
records: recordData,
+
});
+
}
+
}
+
+
export async function setupQueueListener() {
+
if (isShuttingDown) return;
+
+
try {
+
listenerClient = await pool.connect();
+
+
listenerClient.on('notification', async (msg) => {
+
if (msg.channel === 'new_raw_record') {
+
await processQueue();
+
}
+
});
+
+
await listenerClient.query('LISTEN new_raw_record');
+
logger.info('Listening for new_raw_record notifications');
+
+
listenerClient.on('error', (err) => {
+
if (isShuttingDown) return;
+
logger.error({ err }, 'Database listener client error');
+
// TODO: Reconnect logic could go here, but for now we rely on the heartbeat
+
});
+
+
} catch (err) {
+
if (isShuttingDown) return;
+
logger.error({ err }, 'Failed to setup queue listener');
+
}
+
}
+51
src/services/websocket.ts
···
+
import { WebSocketServer, WebSocket } from 'ws';
+
import { logger } from '../util/logger';
+
import * as http from 'http';
+
+
const clients = new Set<WebSocket>();
+
+
export function createWebSocketServer(server: http.Server) {
+
const wss = new WebSocketServer({ server });
+
+
wss.on('connection', (ws) => {
+
logger.info('WebSocket client connected');
+
+
clients.add(ws);
+
+
ws.on('close', () => {
+
logger.info('WebSocket client disconnected');
+
clients.delete(ws);
+
});
+
+
ws.on('error', (err) => {
+
logger.error({ err }, 'WebSocket error');
+
clients.delete(ws);
+
});
+
});
+
+
return wss;
+
}
+
+
export function broadcast(data: any) {
+
const message = JSON.stringify(data);
+
clients.forEach((client) => {
+
if (client.readyState === WebSocket.OPEN) {
+
try {
+
client.send(message);
+
} catch (e: any) {
+
logger.error({ err: e }, 'Failed to send message to client');
+
}
+
}
+
});
+
}
+
+
export function closeAllClients() {
+
for (const client of clients) {
+
client.terminate();
+
}
+
clients.clear();
+
}
+
+
export function getClientCount() {
+
return clients.size;
+
}
+16
src/util/logger.ts
···
+
import pino from 'pino';
+
+
const isDev = process.env.NODE_ENV !== 'production';
+
+
export const logger = pino({
+
level: process.env.LOG_LEVEL || 'info',
+
transport: isDev
+
? {
+
target: 'pino-pretty',
+
options: {
+
colorize: true,
+
translateTime: 'SYS:standard',
+
},
+
}
+
: undefined,
+
});
+17
src/util/params.ts
···
+
export function parseLimit(rawLimit: unknown, defaultLimit = 50): number {
+
let limit: number;
+
+
if (typeof rawLimit === 'string') {
+
limit = parseInt(rawLimit, 10);
+
} else if (typeof rawLimit === 'number') {
+
limit = rawLimit;
+
} else {
+
limit = defaultLimit;
+
}
+
+
if (isNaN(limit) || limit <= 0) {
+
limit = defaultLimit;
+
}
+
+
return limit;
+
}
+305
src/util/recordProcessor.ts
···
+
import { db } from "db";
+
import { sql } from "kysely";
+
import { logger } from "./logger";
+
+
export interface AtpRecord {
+
$type: string;
+
createdAt: string;
+
[key: string]: any;
+
}
+
+
export interface NewAccount {
+
did: string;
+
handle: string;
+
pds_hostname: string | null;
+
created_at: any;
+
}
+
+
export interface NewLattice { uri: string; cid: string; creator_did: string; description?: string; created_at: any; indexed_at: any; data: AtpRecord }
+
export interface NewShard { uri: string; cid: string; creator_did: string; description?: string; created_at: any; indexed_at: any; data: AtpRecord }
+
export interface NewChannel { uri: string; cid: string; creator_did: string; name: string; topic: string; created_at: any; indexed_at: any; data: AtpRecord }
+
+
export interface NewChannelInvite {
+
uri: string;
+
cid: string;
+
creator_did: string;
+
created_at: any;
+
indexed_at: any;
+
data: AtpRecord;
+
channel?: string;
+
recipient_did?: string;
+
}
+
+
export interface NewChannelMembership {
+
uri: string;
+
cid: string;
+
created_at: any;
+
indexed_at: any;
+
updated_at?: string;
+
state: string;
+
data: AtpRecord;
+
channel: string;
+
invite: string;
+
recipient_did?: string;
+
}
+
+
export interface NewRawRecord {
+
record_data: AtpRecord;
+
}
+
+
const LATTICE_LEXICON = 'systems.gmstn.development.lattice';
+
const SHARD_LEXICON = 'systems.gmstn.development.shard';
+
const CHANNEL_LEXICON = 'systems.gmstn.development.channel';
+
const CHANNEL_INVITE_LEXICON = 'systems.gmstn.development.channel.invite';
+
const CHANNEL_MEMBERSHIP_LEXICON = 'systems.gmstn.development.channel.membership';
+
+
export class RecordProcessor {
+
private newLattices: NewLattice[] = [];
+
private newShards: NewShard[] = [];
+
private newRawRecords: NewRawRecord[] = [];
+
+
private realChannels = new Map<string, NewChannel>();
+
private placeholderChannels = new Map<string, any>();
+
+
private realInvites = new Map<string, NewChannelInvite>();
+
private placeholderInvites = new Map<string, any>();
+
+
private realMemberships = new Map<string, NewChannelMembership>();
+
private placeholderAccounts = new Map<string, NewAccount>();
+
+
constructor(private did: string) {}
+
+
private queuePlaceholderAccount(did: string) {
+
if (!did) return;
+
if (!this.placeholderAccounts.has(did)) {
+
this.placeholderAccounts.set(did, {
+
did: did,
+
handle: did,
+
pds_hostname: null,
+
created_at: sql`now()`,
+
});
+
}
+
}
+
+
private queuePlaceholderChannel(cid: string) {
+
if (!cid) return;
+
if (this.realChannels.has(cid)) return;
+
+
if (!this.placeholderChannels.has(cid)) {
+
this.placeholderChannels.set(cid, {
+
cid: cid,
+
uri: null,
+
creator_did: null,
+
name: null,
+
topic: null,
+
created_at: sql`now()`,
+
indexed_at: sql`now()`,
+
data: null,
+
});
+
}
+
}
+
+
private queuePlaceholderInvite(cid: string) {
+
if (!cid) return;
+
if (this.realInvites.has(cid)) return;
+
+
if (!this.placeholderInvites.has(cid)) {
+
this.placeholderInvites.set(cid, {
+
cid: cid,
+
uri: null,
+
creator_did: null,
+
created_at: sql`now()`,
+
indexed_at: sql`now()`,
+
data: null,
+
channel: null,
+
recipient_did: null,
+
});
+
}
+
}
+
+
public async processRecord(
+
record: AtpRecord,
+
uri: string,
+
cid: string,
+
indexedAt: string,
+
includeRaw: boolean = false
+
) {
+
const collection = record?.$type;
+
+
if (!collection || !collection.startsWith('systems.gmstn.development.')) {
+
return;
+
}
+
+
if (includeRaw) {
+
this.newRawRecords.push({ record_data: record });
+
}
+
+
if (!record.createdAt || typeof record.createdAt !== 'string') {
+
return;
+
}
+
+
const baseRecord = {
+
uri: uri,
+
cid: cid,
+
created_at: record.createdAt,
+
indexed_at: indexedAt,
+
data: record,
+
};
+
+
switch (collection) {
+
case LATTICE_LEXICON:
+
this.newLattices.push({
+
...baseRecord,
+
creator_did: this.did,
+
description: record.description
+
} as NewLattice);
+
break;
+
+
case SHARD_LEXICON:
+
this.newShards.push({
+
...baseRecord,
+
creator_did: this.did,
+
description: record.description
+
} as NewShard);
+
break;
+
+
case CHANNEL_LEXICON: {
+
if (typeof record.name !== 'string' || typeof record.topic !== 'string') break;
+
+
this.placeholderChannels.delete(cid);
+
this.realChannels.set(cid, {
+
...baseRecord,
+
creator_did: this.did,
+
name: record.name,
+
topic: record.topic
+
} as NewChannel);
+
break;
+
}
+
+
case CHANNEL_INVITE_LEXICON: {
+
const recipientDid = record.recipient;
+
const channelCid = record.channel?.cid;
+
+
if (!channelCid || !recipientDid) break;
+
+
this.queuePlaceholderChannel(channelCid);
+
this.queuePlaceholderAccount(recipientDid);
+
+
this.placeholderInvites.delete(cid);
+
this.realInvites.set(cid, {
+
...baseRecord,
+
creator_did: this.did,
+
channel: channelCid,
+
recipient_did: recipientDid,
+
} as NewChannelInvite);
+
break;
+
}
+
+
case CHANNEL_MEMBERSHIP_LEXICON: {
+
const channelCid = record.channel?.cid;
+
const inviteCid = record.invite?.cid;
+
+
if (!channelCid || !inviteCid || typeof record.state !== 'string') break;
+
+
this.queuePlaceholderChannel(channelCid);
+
this.queuePlaceholderInvite(inviteCid);
+
+
this.realMemberships.set(cid, {
+
...baseRecord,
+
channel: channelCid,
+
invite: inviteCid,
+
state: record.state,
+
recipient_did: this.did,
+
updated_at: record.updatedAt || null,
+
} as NewChannelMembership);
+
break;
+
}
+
}
+
}
+
+
private async insertSimple(table: string, records: any[]) {
+
if (records.length === 0) return;
+
try {
+
await db.insertInto(table as any).values(records).execute();
+
logger.debug({ did: this.did, table, count: records.length }, "Inserted records");
+
} catch (e: any) {
+
if (e.code === '23505') {
+
logger.debug({ did: this.did, table, err: e.message }, "Duplicate record ignored");
+
} else {
+
logger.error({ did: this.did, table, err: e }, "Failed to insert records");
+
}
+
}
+
}
+
+
public async insertAllProcessedRecords(includeRaw: boolean = false) {
+
const accounts = Array.from(this.placeholderAccounts.values());
+
if (accounts.length > 0) {
+
await db.insertInto('account')
+
.values(accounts)
+
.onConflict(oc => oc.column('did').doNothing())
+
.execute()
+
.catch(e => logger.error({ did: this.did, err: e }, "Account insert error"));
+
}
+
+
const placeholderChans = Array.from(this.placeholderChannels.values());
+
if (placeholderChans.length > 0) {
+
await db.insertInto('channel')
+
.values(placeholderChans)
+
.onConflict(oc => oc.column('cid').doNothing())
+
.execute()
+
.catch(e => logger.error({ did: this.did, err: e }, "Placeholder channel error"));
+
}
+
+
const realChans = Array.from(this.realChannels.values());
+
if (realChans.length > 0) {
+
await db.insertInto('channel')
+
.values(realChans)
+
.onConflict(oc => oc.column('cid').doUpdateSet({
+
uri: (eb) => eb.ref('excluded.uri'),
+
creator_did: (eb) => eb.ref('excluded.creator_did'),
+
name: (eb) => eb.ref('excluded.name'),
+
topic: (eb) => eb.ref('excluded.topic'),
+
created_at: (eb) => eb.ref('excluded.created_at'),
+
indexed_at: (eb) => eb.ref('excluded.indexed_at'),
+
data: (eb) => eb.ref('excluded.data'),
+
}))
+
.execute()
+
.catch(e => logger.error({ did: this.did, err: e }, "Real channel upsert error"));
+
}
+
+
const placeholderInvs = Array.from(this.placeholderInvites.values());
+
if (placeholderInvs.length > 0) {
+
await db.insertInto('channel_invite')
+
.values(placeholderInvs)
+
.onConflict(oc => oc.column('cid').doNothing())
+
.execute()
+
.catch(e => logger.error({ did: this.did, err: e }, "Placeholder invite error"));
+
}
+
+
const realInvs = Array.from(this.realInvites.values());
+
if (realInvs.length > 0) {
+
await db.insertInto('channel_invite')
+
.values(realInvs)
+
.onConflict(oc => oc.column('cid').doUpdateSet({
+
uri: (eb) => eb.ref('excluded.uri'),
+
creator_did: (eb) => eb.ref('excluded.creator_did'),
+
created_at: (eb) => eb.ref('excluded.created_at'),
+
indexed_at: (eb) => eb.ref('excluded.indexed_at'),
+
data: (eb) => eb.ref('excluded.data'),
+
channel: (eb) => eb.ref('excluded.channel'),
+
recipient_did: (eb) => eb.ref('excluded.recipient_did'),
+
}))
+
.execute()
+
.catch(e => logger.error({ did: this.did, err: e }, "Real invite upsert error"));
+
}
+
+
const memberships = Array.from(this.realMemberships.values());
+
if (memberships.length > 0) {
+
await this.insertSimple('channel_membership', memberships);
+
}
+
+
if (includeRaw) await this.insertSimple('raw_record_queue', this.newRawRecords);
+
await this.insertSimple('lattice', this.newLattices);
+
await this.insertSimple('shard', this.newShards);
+
}
+
}
+59
tests/api/channel.test.ts
···
+
import { describe, it, expect, mock, beforeEach } from "bun:test";
+
import { listInvitesHandler } from "../../src/api/channel";
+
+
const createChainableMock = () => {
+
const mockObj: any = {};
+
const mockFn = mock(() => mockObj);
+
+
mockObj.selectFrom = mockFn;
+
mockObj.selectAll = mockFn;
+
mockObj.select = mockFn;
+
mockObj.where = mockFn;
+
mockObj.orderBy = mockFn;
+
mockObj.limit = mockFn;
+
mockObj.offset = mockFn;
+
mockObj.innerJoin = mockFn;
+
mockObj.leftJoin = mockFn;
+
mockObj.updateTable = mockFn;
+
mockObj.set = mockFn;
+
mockObj.execute = mock(() => Promise.resolve([]));
+
+
return mockObj;
+
};
+
+
const dbMock = createChainableMock();
+
+
mock.module("../../src/db", () => ({
+
db: dbMock
+
}));
+
+
describe("listInvitesHandler", () => {
+
beforeEach(() => {
+
dbMock.execute.mockResolvedValue([]);
+
dbMock.selectFrom.mockClear();
+
});
+
+
it("should throw if recipient is missing", async () => {
+
const ctx = { params: {} };
+
expect(listInvitesHandler(ctx as any)).rejects.toThrow("Missing required parameter: recipient");
+
});
+
+
it("should return invites", async () => {
+
const mockData = [{
+
uri: "at://...",
+
cid: "bafy...",
+
creator_did: "did:plc:...",
+
created_at: new Date(),
+
indexed_at: new Date(),
+
channel: "bafy_channel",
+
channel_uri: "at://channel..."
+
}];
+
dbMock.execute.mockResolvedValue(mockData);
+
+
const ctx = { params: { recipient: "did:plc:123" } };
+
const result = await listInvitesHandler(ctx as any);
+
+
expect(result.body.invites).toHaveLength(1);
+
expect(result.body.invites[0].uri).toBe("at://...");
+
});
+
});
+73
tests/api/lattice.test.ts
···
+
import { describe, it, expect, mock, beforeEach } from "bun:test";
+
import { listLatticesHandler } from "../../src/api/lattice";
+
+
const createChainableMock = () => {
+
const mockObj: any = {};
+
const mockFn = mock(() => mockObj);
+
+
mockObj.selectFrom = mockFn;
+
mockObj.selectAll = mockFn;
+
mockObj.select = mockFn;
+
mockObj.where = mockFn;
+
mockObj.orderBy = mockFn;
+
mockObj.limit = mockFn;
+
mockObj.offset = mockFn;
+
mockObj.innerJoin = mockFn;
+
mockObj.leftJoin = mockFn;
+
mockObj.updateTable = mockFn;
+
mockObj.set = mockFn;
+
mockObj.execute = mock(() => Promise.resolve([]));
+
+
return mockObj;
+
};
+
+
const dbMock = createChainableMock();
+
+
mock.module("../../src/db", () => ({
+
db: dbMock
+
}));
+
+
describe("listLatticesHandler", () => {
+
beforeEach(() => {
+
dbMock.execute.mockResolvedValue([]);
+
dbMock.selectFrom.mockClear();
+
});
+
+
it("should throw if author is missing", async () => {
+
const ctx = { params: {} };
+
expect(listLatticesHandler(ctx as any)).rejects.toThrow("Missing required parameter: author");
+
});
+
+
it("should return lattices", async () => {
+
const mockData = [{
+
uri: "at://did:plc:123/systems.gmstn.development.lattice/rkey",
+
cid: "bafy_lattice",
+
creator_did: "did:plc:123",
+
description: "Test Lattice",
+
created_at: new Date("2023-01-01T00:00:00Z"),
+
indexed_at: new Date("2023-01-02T00:00:00Z")
+
}];
+
dbMock.execute.mockResolvedValue(mockData);
+
+
const ctx = { params: { author: "did:plc:123" } };
+
const result = await listLatticesHandler(ctx as any);
+
+
expect(result.body.lattices).toHaveLength(1);
+
expect(result.body.lattices[0]).toEqual({
+
uri: mockData[0].uri,
+
cid: mockData[0].cid,
+
author: mockData[0].creator_did,
+
description: mockData[0].description,
+
createdAt: mockData[0].created_at.toISOString(),
+
indexedAt: mockData[0].indexed_at.toISOString()
+
});
+
});
+
+
it("should handle cursor", async () => {
+
dbMock.execute.mockResolvedValue([]);
+
const ctx = { params: { author: "did:plc:123", cursor: "2023-01-01T00:00:00Z" } };
+
await listLatticesHandler(ctx as any);
+
+
expect(dbMock.selectFrom).toHaveBeenCalled();
+
});
+
});
+65
tests/api/shard.test.ts
···
+
import { describe, it, expect, mock, beforeEach } from "bun:test";
+
import { listShardsHandler } from "../../src/api/shard";
+
+
const createChainableMock = () => {
+
const mockObj: any = {};
+
const mockFn = mock(() => mockObj);
+
+
mockObj.selectFrom = mockFn;
+
mockObj.selectAll = mockFn;
+
mockObj.select = mockFn;
+
mockObj.where = mockFn;
+
mockObj.orderBy = mockFn;
+
mockObj.limit = mockFn;
+
mockObj.offset = mockFn;
+
mockObj.innerJoin = mockFn;
+
mockObj.leftJoin = mockFn;
+
mockObj.updateTable = mockFn;
+
mockObj.set = mockFn;
+
mockObj.execute = mock(() => Promise.resolve([]));
+
+
return mockObj;
+
};
+
+
const dbMock = createChainableMock();
+
+
mock.module("../../src/db", () => ({
+
db: dbMock
+
}));
+
+
describe("listShardsHandler", () => {
+
beforeEach(() => {
+
dbMock.execute.mockResolvedValue([]);
+
dbMock.selectFrom.mockClear();
+
});
+
+
it("should throw if author is missing", async () => {
+
const ctx = { params: {} };
+
expect(listShardsHandler(ctx as any)).rejects.toThrow("Missing required parameter: author");
+
});
+
+
it("should return shards", async () => {
+
const mockData = [{
+
uri: "at://did:plc:123/systems.gmstn.development.shard/rkey",
+
cid: "bafy_shard",
+
creator_did: "did:plc:123",
+
description: "Test Shard",
+
created_at: new Date("2023-01-01T00:00:00Z"),
+
indexed_at: new Date("2023-01-02T00:00:00Z")
+
}];
+
dbMock.execute.mockResolvedValue(mockData);
+
+
const ctx = { params: { author: "did:plc:123" } };
+
const result = await listShardsHandler(ctx as any);
+
+
expect(result.body.shards).toHaveLength(1);
+
expect(result.body.shards[0]).toEqual({
+
uri: mockData[0].uri,
+
cid: mockData[0].cid,
+
author: mockData[0].creator_did,
+
description: mockData[0].description,
+
createdAt: mockData[0].created_at.toISOString(),
+
indexedAt: mockData[0].indexed_at.toISOString()
+
});
+
});
+
});
+161
tests/recordProcessor.test.ts
···
+
import { describe, it, expect, mock, beforeEach } from "bun:test";
+
import { RecordProcessor } from "../src/util/recordProcessor";
+
+
const mockExecute = mock(() => Promise.resolve([]));
+
const mockOnConflict = mock(() => ({
+
execute: mockExecute,
+
doNothing: () => ({ execute: mockExecute }),
+
doUpdateSet: () => ({ execute: mockExecute }),
+
column: () => ({
+
doNothing: () => ({ execute: mockExecute }),
+
doUpdateSet: () => ({ execute: mockExecute })
+
})
+
}));
+
+
const mockValues = mock(() => ({
+
execute: mockExecute,
+
onConflict: mockOnConflict
+
}));
+
+
const mockInsertInto = mock(() => ({
+
values: mockValues
+
}));
+
+
mock.module("../src/db", () => ({
+
db: {
+
insertInto: mockInsertInto
+
}
+
}));
+
+
describe("RecordProcessor", () => {
+
let processor: RecordProcessor;
+
const did = "did:plc:123";
+
+
beforeEach(() => {
+
processor = new RecordProcessor(did);
+
mockInsertInto.mockClear();
+
mockValues.mockClear();
+
mockExecute.mockClear();
+
mockOnConflict.mockClear();
+
});
+
+
it("should process and insert a Lattice record", async () => {
+
const record = {
+
$type: "systems.gmstn.development.lattice",
+
createdAt: "2023-01-01T00:00:00Z",
+
description: "Test Lattice"
+
};
+
const uri = "at://did:plc:123/systems.gmstn.development.lattice/rkey";
+
const cid = "bafy...";
+
const indexedAt = "2023-01-02T00:00:00Z";
+
+
await processor.processRecord(record, uri, cid, indexedAt);
+
await processor.insertAllProcessedRecords();
+
+
expect(mockInsertInto).toHaveBeenCalledWith("lattice");
+
+
const calls = mockValues.mock.calls as unknown as any[][];
+
expect(calls.length).toBeGreaterThan(0);
+
const insertedRecords = calls[0][0];
+
+
expect(insertedRecords).toHaveLength(1);
+
expect(insertedRecords[0]).toMatchObject({
+
uri,
+
cid,
+
creator_did: did,
+
description: "Test Lattice",
+
created_at: record.createdAt,
+
indexed_at: indexedAt,
+
data: record
+
});
+
});
+
+
it("should process and insert a Shard record", async () => {
+
const record = {
+
$type: "systems.gmstn.development.shard",
+
createdAt: "2023-01-01T00:00:00Z",
+
description: "Test Shard"
+
};
+
const uri = "at://did:plc:123/systems.gmstn.development.shard/rkey";
+
const cid = "bafy_shard";
+
const indexedAt = "2023-01-02T00:00:00Z";
+
+
await processor.processRecord(record, uri, cid, indexedAt);
+
await processor.insertAllProcessedRecords();
+
+
expect(mockInsertInto).toHaveBeenCalledWith("shard");
+
const calls = mockValues.mock.calls as unknown as any[][];
+
const insertedRecords = calls[0][0];
+
expect(insertedRecords[0]).toMatchObject({
+
description: "Test Shard"
+
});
+
});
+
+
it("should process and insert a Channel record", async () => {
+
const record = {
+
$type: "systems.gmstn.development.channel",
+
createdAt: "2023-01-01T00:00:00Z",
+
name: "Test Channel",
+
topic: "Testing"
+
};
+
const uri = "at://did:plc:123/systems.gmstn.development.channel.record/rkey";
+
const cid = "bafy_channel";
+
const indexedAt = "2023-01-02T00:00:00Z";
+
+
await processor.processRecord(record, uri, cid, indexedAt);
+
await processor.insertAllProcessedRecords();
+
+
expect(mockInsertInto).toHaveBeenCalledWith("channel");
+
+
const calls = mockInsertInto.mock.calls as unknown as any[][];
+
const channelCall = calls.find(call => call[0] === 'channel');
+
expect(channelCall).toBeDefined();
+
});
+
+
it("should process and insert a Channel Invite record", async () => {
+
const record = {
+
$type: "systems.gmstn.development.channel.invite",
+
createdAt: "2023-01-01T00:00:00Z",
+
recipient: "did:plc:recipient",
+
channel: { cid: "bafy_channel_cid", uri: "at://..." }
+
};
+
const uri = "at://did:plc:123/systems.gmstn.development.channel.invite/rkey";
+
const cid = "bafy_invite";
+
const indexedAt = "2023-01-02T00:00:00Z";
+
+
await processor.processRecord(record, uri, cid, indexedAt);
+
await processor.insertAllProcessedRecords();
+
+
expect(mockInsertInto).toHaveBeenCalledWith("channel_invite");
+
+
const calls = mockInsertInto.mock.calls as unknown as any[][];
+
const tables = calls.map(c => c[0]);
+
expect(tables).toContain("channel_invite");
+
expect(tables).toContain("account");
+
expect(tables).toContain("channel");
+
});
+
+
it("should process and insert a Channel Membership record", async () => {
+
const record = {
+
$type: "systems.gmstn.development.channel.membership",
+
createdAt: "2023-01-01T00:00:00Z",
+
state: "joined",
+
channel: { cid: "bafy_channel_cid", uri: "at://..." },
+
invite: { cid: "bafy_invite_cid", uri: "at://..." }
+
};
+
const uri = "at://did:plc:123/systems.gmstn.development.channel.membership/rkey";
+
const cid = "bafy_membership";
+
const indexedAt = "2023-01-02T00:00:00Z";
+
+
await processor.processRecord(record, uri, cid, indexedAt);
+
await processor.insertAllProcessedRecords();
+
+
expect(mockInsertInto).toHaveBeenCalledWith("channel_membership");
+
+
const calls = mockInsertInto.mock.calls as unknown as any[][];
+
const tables = calls.map(c => c[0]);
+
expect(tables).toContain("channel_membership");
+
expect(tables).toContain("channel");
+
expect(tables).toContain("channel_invite");
+
});
+
});
+84
tests/services/queue.test.ts
···
+
import { describe, it, expect, mock, beforeEach } from "bun:test";
+
import { processQueue } from "../../src/services/queue";
+
+
const createChainableMock = () => {
+
const mockObj: any = {};
+
const mockFn = mock(() => mockObj);
+
+
mockObj.selectFrom = mockFn;
+
mockObj.selectAll = mockFn;
+
mockObj.select = mockFn;
+
mockObj.where = mockFn;
+
mockObj.orderBy = mockFn;
+
mockObj.limit = mockFn;
+
mockObj.offset = mockFn;
+
mockObj.innerJoin = mockFn;
+
mockObj.leftJoin = mockFn;
+
mockObj.updateTable = mockFn;
+
mockObj.set = mockFn;
+
mockObj.forUpdate = mockFn;
+
mockObj.skipLocked = mockFn;
+
mockObj.execute = mock(() => Promise.resolve([]));
+
mockObj.executeTakeFirst = mock(() => Promise.resolve(null));
+
+
return mockObj;
+
};
+
+
const dbMock = createChainableMock();
+
+
const mockTransactionExecute = mock((callback: (trx: any) => Promise<any>) => callback(dbMock));
+
dbMock.transaction = mock(() => ({ execute: mockTransactionExecute }));
+
+
mock.module("../../src/db", () => ({
+
db: dbMock,
+
pool: {
+
connect: mock(() => Promise.resolve({
+
on: mock(() => {}),
+
query: mock(() => Promise.resolve()),
+
release: mock(() => {})
+
}))
+
}
+
}));
+
+
const mockBroadcast = mock(() => {});
+
const mockGetClientCount = mock(() => 0);
+
mock.module("../../src/services/websocket", () => ({
+
broadcast: mockBroadcast,
+
getClientCount: mockGetClientCount
+
}));
+
+
describe("Queue Service", () => {
+
beforeEach(() => {
+
dbMock.execute.mockResolvedValue([]);
+
mockBroadcast.mockClear();
+
});
+
+
it("should process pending records", async () => {
+
const mockRecords = [{
+
id: 1,
+
record_data: { $type: "test" },
+
status: "pending",
+
created_at: new Date()
+
}];
+
+
dbMock.execute
+
.mockResolvedValueOnce(mockRecords)
+
.mockResolvedValueOnce([]);
+
+
await processQueue();
+
+
expect(mockBroadcast).toHaveBeenCalled();
+
expect(mockBroadcast).toHaveBeenCalledWith({
+
type: "new_records",
+
records: [mockRecords[0].record_data]
+
});
+
});
+
+
it("should do nothing if no records found", async () => {
+
dbMock.execute.mockResolvedValueOnce([]);
+
+
await processQueue();
+
+
expect(mockBroadcast).not.toHaveBeenCalled();
+
});
+
});
+89
tests/services/websocket.test.ts
···
+
import { describe, it, expect, mock, beforeEach } from "bun:test";
+
import { createWebSocketServer, broadcast, closeAllClients, getClientCount } from "../../src/services/websocket";
+
import { WebSocket } from "ws";
+
+
const mockSend = mock(() => {});
+
const mockTerminate = mock(() => {});
+
const mockOn = mock(() => {});
+
+
const MockWebSocket = mock(() => ({
+
send: mockSend,
+
terminate: mockTerminate,
+
on: mockOn,
+
readyState: WebSocket.OPEN
+
}));
+
+
const mockWssOn = mock((event, callback) => {
+
if (event === 'connection') {
+
// Simulate a connection immediately for testing purposes if needed,
+
// but usually we trigger it manually.
+
// For now just store the callback to trigger it later.
+
(global as any).triggerConnection = callback;
+
}
+
});
+
+
const MockWebSocketServer = mock(() => ({
+
on: mockWssOn
+
}));
+
+
mock.module("ws", () => ({
+
WebSocketServer: MockWebSocketServer,
+
WebSocket: {
+
OPEN: 1,
+
...MockWebSocket
+
}
+
}));
+
+
describe("WebSocket Service", () => {
+
let wss: any;
+
+
beforeEach(() => {
+
mockSend.mockClear();
+
mockTerminate.mockClear();
+
mockOn.mockClear();
+
mockWssOn.mockClear();
+
closeAllClients();
+
});
+
+
it("should create a WebSocket server", () => {
+
const mockServer = {} as any;
+
wss = createWebSocketServer(mockServer);
+
expect(MockWebSocketServer).toHaveBeenCalled();
+
expect(mockWssOn).toHaveBeenCalledWith("connection", expect.any(Function));
+
});
+
+
it("should handle client connection", () => {
+
const mockWs = new MockWebSocket();
+
(global as any).triggerConnection(mockWs);
+
+
expect(getClientCount()).toBe(1);
+
expect(mockWs.on).toHaveBeenCalledWith("close", expect.any(Function));
+
expect(mockWs.on).toHaveBeenCalledWith("error", expect.any(Function));
+
});
+
+
it("should broadcast messages to connected clients", () => {
+
const mockWs1 = new MockWebSocket();
+
const mockWs2 = new MockWebSocket();
+
+
(global as any).triggerConnection(mockWs1);
+
(global as any).triggerConnection(mockWs2);
+
+
const data = { type: "test" };
+
broadcast(data);
+
+
expect(mockSend).toHaveBeenCalledTimes(2);
+
expect(mockSend).toHaveBeenCalledWith(JSON.stringify(data));
+
});
+
+
it("should close all clients", () => {
+
const mockWs = new MockWebSocket();
+
(global as any).triggerConnection(mockWs);
+
+
expect(getClientCount()).toBe(1);
+
+
closeAllClients();
+
+
expect(mockTerminate).toHaveBeenCalled();
+
expect(getClientCount()).toBe(0);
+
});
+
});
+36
tests/util/params.test.ts
···
+
import { describe, it, expect } from "bun:test";
+
import { parseLimit } from "../../src/util/params";
+
+
describe("parseLimit", () => {
+
it("should return the default limit when input is undefined", () => {
+
expect(parseLimit(undefined)).toBe(50);
+
});
+
+
it("should return the default limit when input is null", () => {
+
expect(parseLimit(null)).toBe(50);
+
});
+
+
it("should parse a valid string number", () => {
+
expect(parseLimit("10")).toBe(10);
+
});
+
+
it("should return the number when input is a number", () => {
+
expect(parseLimit(20)).toBe(20);
+
});
+
+
it("should return default limit for invalid strings", () => {
+
expect(parseLimit("abc")).toBe(50);
+
});
+
+
it("should return default limit for negative numbers", () => {
+
expect(parseLimit(-5)).toBe(50);
+
});
+
+
it("should return default limit for zero", () => {
+
expect(parseLimit(0)).toBe(50);
+
});
+
+
it("should accept a custom default limit", () => {
+
expect(parseLimit(undefined, 100)).toBe(100);
+
});
+
});
+39 -119
tsconfig.json
···
{
-
"compilerOptions": {
-
/* Visit https://aka.ms/tsconfig to read more about this file */
-
/* Projects */
-
"incremental": true /* Save .tsbuildinfo files to allow for incremental compilation of projects. */,
-
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
-
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
-
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
-
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
-
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
-
/* Language and Environment */
-
"target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
-
"lib": [
-
"dom",
-
"dom.iterable",
-
"esnext"
-
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
-
"jsx": "preserve" /* Specify what JSX code is generated. */,
-
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
-
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
-
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
-
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
-
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
-
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
-
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
-
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
-
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
-
/* Modules */
-
"module": "nodenext" /* Specify what module code is generated. */,
-
"rootDir": "./src/" /* Specify the root folder within your source files. */,
-
"moduleResolution": "nodenext" /* Specify how TypeScript looks up a file from a given module specifier. */,
-
"baseUrl": "./" /* Specify the base directory to resolve non-relative module names. */,
-
"paths": {
-
"@/*": [
-
"src/*"
-
]
-
} /* Specify a set of entries that re-map imports to additional lookup locations. */,
-
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
-
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
-
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
-
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
-
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
-
"resolveJsonModule": true /* Enable importing .json files. */,
-
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
-
/* JavaScript Support */
-
"allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */,
-
"checkJs": true /* Enable error reporting in type-checked JavaScript files. */,
-
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
-
/* Emit */
-
"declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
-
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
-
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
-
"sourceMap": true /* Create source map files for emitted JavaScript files. */,
-
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
-
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
-
// "removeComments": true, /* Disable emitting comments. */
-
// "noEmit": true, /* Disable emitting files from a compilation. */
-
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
-
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
-
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
-
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
-
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
-
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
-
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
-
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
-
// "newLine": "crlf", /* Set the newline character for emitting files. */
-
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
-
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
-
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
-
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
-
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
-
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
-
/* Interop Constraints */
-
"isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */,
-
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
-
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
-
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
-
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
-
/* Type Checking */
-
"strict": true /* Enable all strict type-checking options. */,
-
"noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */,
-
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
-
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
-
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
-
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
-
"noImplicitThis": true /* Enable error reporting when 'this' is given the type 'any'. */,
-
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
-
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
-
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
-
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
-
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
-
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
-
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
-
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
-
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
-
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
-
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
-
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
-
/* Completeness */
-
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
-
"skipLibCheck": true /* Skip type checking all .d.ts files. */,
-
"plugins": [
-
{
-
"name": "next"
-
}
-
]
-
},
-
"ts-node": {
-
"require": [
-
"tsconfig-paths/register"
-
]
-
},
-
"include": [
-
"src/**/*",
-
"index.ts"
-
],
-
"exclude": [
-
"node_modules",
-
"dist"
-
]
+
"compilerOptions": {
+
/* Basic Options */
+
"target": "ESNext" /* Modern Node.js supports this */,
+
"module": "NodeNext" /* This is the correct module system for modern Node.js */,
+
"lib": ["ESNext"] /* Use ESNext libs, NOT 'dom' for a backend server */,
+
"outDir": "./dist" /* Good */,
+
"rootDir": "./src" /* Good */,
+
"incremental": true,
+
+
/* Module Resolution */
+
"moduleResolution": "NodeNext" /* Matches 'module: NodeNext' */,
+
"baseUrl": "./src" /* This is KEY: allows imports like 'db' from 'src/db.ts' */,
+
// "paths": { ... } /* We're not using '@/' paths for this fix, so this is removed */
+
"resolveJsonModule": true,
+
+
/* Strictness & Quality */
+
"strict": true,
+
"forceConsistentCasingInFileNames": true,
+
"noImplicitAny": true,
+
"noImplicitThis": true,
+
"skipLibCheck": true,
+
+
/* Interop */
+
"esModuleInterop": true /* Allows 'import x from y' with CommonJS modules */,
+
"allowJs": true,
+
"checkJs": true,
+
+
/* Emit */
+
"declaration": true,
+
"sourceMap": true,
+
"isolatedModules": true /* Good practice */
+
},
+
"include": [
+
"src/**/*" /* Compile everything in src */
+
],
+
"exclude": [
+
"node_modules",
+
"dist"
+
]
}