diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..d6e5de9d6 --- /dev/null +++ b/.env.example @@ -0,0 +1,25 @@ +# Whichever port you want to run this on +FEEDGEN_PORT=3000 + +# Change this to use a different bind address +FEEDGEN_LISTENHOST="localhost" + +# Set to something like db.sqlite to store persistently +FEEDGEN_SQLITE_LOCATION=":memory:" + +# Don't change unless you're working in a different environment than the primary Bluesky network +FEEDGEN_SUBSCRIPTION_ENDPOINT="wss://bsky.social" + +# Set this to the hostname that you intend to run the service at +FEEDGEN_HOSTNAME="example.com" + +# Set this to the DID of the account you'll use to publish the feed +# You can find your accounts DID by going to +# https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=${YOUR_HANDLE} +FEEDGEN_PUBLISHER_DID="did:plc:abcde...." + +# Only use this if you want a service did different from did:web +# FEEDGEN_SERVICE_DID="did:plc:abcde..." + +# Delay between reconnect attempts to the firehose subscription endpoint (in milliseconds) +FEEDGEN_SUBSCRIPTION_RECONNECT_DELAY=3000 diff --git a/.gitignore b/.gitignore index b512c09d4..6a7d6d8ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,130 @@ -node_modules \ No newline at end of file +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..96bbeca4d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM node:20-alpine + +WORKDIR /app +COPY package.json . + +RUN yarn install + +# Bare neccesary +COPY src/ ./src +COPY .env . + +EXPOSE 3000 + +# Nu kΓΆr vi +CMD ["yarn" , "start"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..9bcd684ad --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Bluesky PBLLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index f71c2ae68..ee3401404 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,14 @@ # ATProto Feed Generator -🚧 Work in Progress 🚧 - -We are actively developing Feed Generator integration into the Bluesky PDS. Though we are reasonably confident about the general shape and interfaces laid out here, these interfaces and implementation details _are_ subject to change. - -In the meantime, we've put together this starter kit for devs. It doesn't do everything, but it should be enough to get you familiar with the system & started building! +This is a starter kit for creating ATProto Feed Generators. It's not feature complete, but should give you a good starting ground off of which to build and deploy a feed. ## Overview -Feed Generators are services that provide custom algorithms to users through the AT protocol. +Feed Generators are services that provide custom algorithms to users through the AT Protocol. -They work very simply: the server receives a request from a user's server and returns a list of [post URIs](https://atproto.com/specs/at-uri-scheme) with some optional metadata attached. Those posts are then hydrated into full views by the requesting server and sent back to the client. This route is described in the [`com.atproto.feed.getFeedSkeleton` lexicon](https://github.com/bluesky-social/atproto/blob/custom-feeds/lexicons/app/bsky/feed/getFeedSkeleton.json). +They work very simply: the server receives a request from a user's server and returns a list of [post URIs](https://atproto.com/specs/at-uri-scheme) with some optional metadata attached. Those posts are then hydrated into full views by the requesting server and sent back to the client. This route is described in the [`app.bsky.feed.getFeedSkeleton` lexicon](https://atproto.com/lexicons/app-bsky-feed#appbskyfeedgetfeedskeleton). -A Feed Generator service can host one or more algorithms. The service itself is identified by DID, however each algorithm that it hosts is declared by a record in the repo of the account that created it. For instance feeds offered by Bluesky will likely be declared in `@bsky.app`'s repo. Therefore, a given algorithm is identified by the at-uri of the declaration record. This declaration record includes a pointer to the service's DID along with some profile information for the feed. +A Feed Generator service can host one or more algorithms. The service itself is identified by DID, while each algorithm that it hosts is declared by a record in the repo of the account that created it. For instance, feeds offered by Bluesky will likely be declared in `@bsky.app`'s repo. Therefore, a given algorithm is identified by the at-uri of the declaration record. This declaration record includes a pointer to the service's DID along with some profile information for the feed. The general flow of providing a custom algorithm to a user is as follows: - A user requests a feed from their server (PDS) using the at-uri of the declared feed @@ -20,37 +16,52 @@ The general flow of providing a custom algorithm to a user is as follows: - The PDS sends a `getFeedSkeleton` request to the service endpoint declared in the Feed Generator's DID doc - This request is authenticated by a JWT signed by the user's repo signing key - The Feed Generator returns a skeleton of the feed to the user's PDS -- The PDS hydrates the feed (user info, post contents, aggregates, etc) - - In the future, the PDS will hydrate the feed with the help of an App View, but for now the PDS handles hydration itself +- The PDS hydrates the feed (user info, post contents, aggregates, etc.) + - In the future, the PDS will hydrate the feed with the help of an App View, but for now, the PDS handles hydration itself - The PDS returns the hydrated feed to the user -To the user this should feel like visiting a page in the app. Once they subscribe, it will appear in their home interface as one of their available feeds. +For users, this should feel like visiting a page in the app. Once they subscribe to a custom algorithm, it will appear in their home interface as one of their available feeds. ## Getting Started -We've setup this simple server with sqlite to store & query data. Feel free to switch this out for whichever database you prefer. +We've set up this simple server with SQLite to store and query data. Feel free to switch this out for whichever database you prefer. -Next you will need to do two things: +Next, you will need to do two things: -- Implement indexing logic in `src/subscription.ts`. +1. Implement indexing logic in `src/subscription.ts`. + + This will subscribe to the repo subscription stream on startup, parse events and index them according to your provided logic. -This will subscribe to the repo subscription stream on startup, parse events & index them according to your provided logic. +2. Implement feed generation logic in `src/algos` -- Implement feed generation logic in `src/feed-generation.ts` + For inspiration, we've provided a very simple feed algorithm (`whats-alf`) that returns all posts related to the titular character of the TV show ALF. -The types are in place and you will just need to return something that satisfies the `SkeletonFeedPost[]` type - -For inspiration, we've provided a very simple feed algorithm ("whats alf") that returns all posts related to the titular character of the TV show ALF. + You can either edit it or add another algorithm alongside it. The types are in place, and you will just need to return something that satisfies the `SkeletonFeedPost[]` type. We've taken care of setting this server up with a did:web. However, you're free to switch this out for did:plc if you like - you may want to if you expect this Feed Generator to be long-standing and possibly migrating domains. -Once the custom algorithms feature launches, you'll be able to publish your feed in-app by providing the DID of your service. +### Deploying your feed +Your feed will need to be accessible at the value supplied to the `FEEDGEN_HOSTNAME` environment variable. + +The service must be set up to respond to HTTPS queries over port 443. + +### Publishing your feed + +To publish your feed, go to the script at `scripts/publishFeedGen.ts` and fill in the variables at the top. Examples are included, and some are optional. To publish your feed generator, simply run `yarn publishFeed`. + +To update your feed's display data (name, avatar, description, etc.), just update the relevant variables and re-run the script. + +After successfully running the script, you should be able to see your feed from within the app, as well as share it by embedding a link in a post (similar to a quote post). + +## Running the Server + +Install dependencies with `yarn` and then run the server with `yarn start`. This will start the server on port 3000, or what's defined in `.env`. You can then watch the firehose output in the console and access the output of the default custom ALF feed at [http://localhost:3000/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:example:alice/app.bsky.feed.generator/whats-alf](http://localhost:3000/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:example:alice/app.bsky.feed.generator/whats-alf). ## Some Details ### Skeleton Metadata -The skeleton that a Feed Generator puts together is, in its simplest form, a list of post uris. +The skeleton that a Feed Generator puts together is, in its simplest form, a list of post URIs. ```ts [ @@ -60,18 +71,12 @@ The skeleton that a Feed Generator puts together is, in its simplest form, a lis ] ``` -However, we include two locations to attach some additional context. Here is the full schema: +However, we include an additional location to attach some context. Here is the full schema: ```ts type SkeletonItem = { post: string // post URI - - // optional metadata about the thread that this post is in reply to - replyTo?: { - root: string, // reply root URI - parent: string, // reply parent URI - } - + // optional reason for inclusion in the feed // (generally to be displayed in client) reason?: Reason @@ -81,9 +86,8 @@ type SkeletonItem = { type Reason = ReasonRepost type ReasonRepost = { - $type: @TODO - by: string // the did of the reposting user - indexedAt: string // the time that the repost took place + $type: 'app.bsky.feed.defs#skeletonReasonRepost' + repost: string // repost URI } ``` @@ -111,12 +115,12 @@ const payload = { } ``` -We provide utilities for verifying user JWTs in the `@atproto/xrpc-server` package. +We provide utilities for verifying user JWTs in the `@atproto/xrpc-server` package, and you can see them in action in `src/auth.ts`. ### Pagination -You'll notice that the `getFeedSkeleton` method returns a `cursor` in its response & takes a `cursor` param as input. +You'll notice that the `getFeedSkeleton` method returns a `cursor` in its response and takes a `cursor` param as input. -This cursor is treated as an opaque value & fully at the Feed Generator's discretion. It is simply pased through he PDS directly to & from the client. +This cursor is treated as an opaque value and fully at the Feed Generator's discretion. It is simply passed through the PDS directly to and from the client. We strongly encourage that the cursor be _unique per feed item_ to prevent unexpected behavior in pagination. @@ -127,17 +131,22 @@ We recommend, for instance, a compound cursor with a timestamp + a CID: How a feed generator fulfills the `getFeedSkeleton` request is completely at their discretion. At the simplest end, a Feed Generator could supply a "feed" that only contains some hardcoded posts. -For most usecases, we recommend subscribing to the firehose at `com.atproto.sync.subscribeRepos`. This websocket will send you every record that is published on the network. Since Feed Generators do not need to provide hydrated posts, you can index as much or as little of the firehose as necessary. +For most use cases, we recommend subscribing to the firehose at `com.atproto.sync.subscribeRepos`. This websocket will send you every record that is published on the network. Since Feed Generators do not need to provide hydrated posts, you can index as much or as little of the firehose as necessary. Depending on your algorithm, you likely do not need to keep posts around for long. Unless your algorithm is intended to provide "posts you missed" or something similar, you can likely garbage collect any data that is older than 48 hours. Some examples: ### Reimplementing What's Hot -To reimplement "What's Hot", you may subscribe to the firehose & filter for all posts & likes (ignoring profiles/reposts/follows/etc). You would keep a running tally of likes per post & when a PDS requests a feed, you would send the most recent posts that pass some threshold of likes. +To reimplement "What's Hot", you may subscribe to the firehose and filter for all posts and likes (ignoring profiles/reposts/follows/etc.). You would keep a running tally of likes per post and when a PDS requests a feed, you would send the most recent posts that pass some threshold of likes. ### A Community Feed -You might create a feed for a given community by compiling a list of DIDs within that community & filtering the firehose for all posts from users within that list. +You might create a feed for a given community by compiling a list of DIDs within that community and filtering the firehose for all posts from users within that list. ### A Topical Feed -To implement a topical feed, you might filter the algorithm for posts and pass the post text through some filtering mechanism (an LLM, a keyword matcher, etc) that filters for the topic of your choice. +To implement a topical feed, you might filter the algorithm for posts and pass the post text through some filtering mechanism (an LLM, a keyword matcher, etc.) that filters for the topic of your choice. + +## Community Feed Generator Templates + +- [Python](https://github.com/MarshalX/bluesky-feed-generator) - [@MarshalX](https://github.com/MarshalX) +- [Ruby](https://github.com/mackuba/bluesky-feeds-rb) - [@mackuba](https://github.com/mackuba) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..c4d887798 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +gversion: "3.2" +services: + + swefeed: + build: . + image: feed + ports: + - "3000:3000" + restart: unless-stopped +# Uncomment if you want to use a persitent sqlite database +# volumes: +# - type: bind +# source: ./db.sqlite +# target: /app/db.sqlite + diff --git a/package.json b/package.json index cf61c1685..c234f4c5e 100644 --- a/package.json +++ b/package.json @@ -7,20 +7,27 @@ "author": "dholms ", "license": "MIT", "scripts": { - "start": "ts-node src/index.ts" + "publishFeed": "ts-node scripts/publishFeedGen.ts", + "start": "ts-node src/index.ts", + "build": "tsc" }, "dependencies": { + "@atproto/api": "^0.3.7", + "@atproto/did-resolver": "^0.1.0", + "@atproto/lexicon": "^0.1.0", "@atproto/repo": "^0.1.0", "@atproto/uri": "^0.0.2", - "@atproto/xrpc-server": "^0.1.0", + "@atproto/xrpc-server": "^0.2.0", "better-sqlite3": "^8.3.0", + "dotenv": "^16.0.3", "express": "^4.18.2", - "kysely": "^0.22.0" + "kysely": "^0.22.0", + "multiformats": "^9.9.0" }, "devDependencies": { "@types/better-sqlite3": "^7.6.4", "@types/express": "^4.17.17", - "@types/node": "^20.1.1", + "@types/node": "^20.1.2", "ts-node": "^10.9.1", "typescript": "^5.0.4" } diff --git a/scripts/publishFeedGen.ts b/scripts/publishFeedGen.ts new file mode 100644 index 000000000..9f226ba02 --- /dev/null +++ b/scripts/publishFeedGen.ts @@ -0,0 +1,89 @@ +import dotenv from 'dotenv' +import { AtpAgent, BlobRef } from '@atproto/api' +import fs from 'fs/promises' +import { ids } from '../src/lexicon/lexicons' + +const run = async () => { + dotenv.config() + + // YOUR bluesky handle + // Ex: user.bsky.social + const handle = '' + + // YOUR bluesky password, or preferably an App Password (found in your client settings) + // Ex: abcd-1234-efgh-5678 + const password = '' + + // A short name for the record that will show in urls + // Lowercase with no spaces. + // Ex: whats-hot + const recordName = '' + + // A display name for your feed + // Ex: What's Hot + const displayName = '' + + // (Optional) A description of your feed + // Ex: Top trending content from the whole network + const description = '' + + // (Optional) The path to an image to be used as your feed's avatar + // Ex: ~/path/to/avatar.jpeg + const avatar: string = '' + + // ------------------------------------- + // NO NEED TO TOUCH ANYTHING BELOW HERE + // ------------------------------------- + + if (!process.env.FEEDGEN_SERVICE_DID && !process.env.FEEDGEN_HOSTNAME) { + throw new Error('Please provide a hostname in the .env file') + } + const feedGenDid = + process.env.FEEDGEN_SERVICE_DID ?? `did:web:${process.env.FEEDGEN_HOSTNAME}` + + // only update this if in a test environment + const agent = new AtpAgent({ service: 'https://bsky.social' }) + await agent.login({ identifier: handle, password }) + + try { + await agent.api.app.bsky.feed.describeFeedGenerator() + } catch (err) { + throw new Error( + 'The bluesky server is not ready to accept published custom feeds yet', + ) + } + + let avatarRef: BlobRef | undefined + if (avatar) { + let encoding: string + if (avatar.endsWith('png')) { + encoding = 'image/png' + } else if (avatar.endsWith('jpg') || avatar.endsWith('jpeg')) { + encoding = 'image/jpeg' + } else { + throw new Error('expected png or jpeg') + } + const img = await fs.readFile(avatar) + const blobRes = await agent.api.com.atproto.repo.uploadBlob(img, { + encoding, + }) + avatarRef = blobRes.data.blob + } + + await agent.api.com.atproto.repo.putRecord({ + repo: agent.session?.did ?? '', + collection: ids.AppBskyFeedGenerator, + rkey: recordName, + record: { + did: feedGenDid, + displayName: displayName, + description: description, + avatar: avatarRef, + createdAt: new Date().toISOString(), + }, + }) + + console.log('All done πŸŽ‰') +} + +run() diff --git a/src/algos/index.ts b/src/algos/index.ts new file mode 100644 index 000000000..b7ee48a76 --- /dev/null +++ b/src/algos/index.ts @@ -0,0 +1,14 @@ +import { AppContext } from '../config' +import { + QueryParams, + OutputSchema as AlgoOutput, +} from '../lexicon/types/app/bsky/feed/getFeedSkeleton' +import * as whatsAlf from './whats-alf' + +type AlgoHandler = (ctx: AppContext, params: QueryParams) => Promise + +const algos: Record = { + [whatsAlf.shortname]: whatsAlf.handler, +} + +export default algos diff --git a/src/algos/whats-alf.ts b/src/algos/whats-alf.ts new file mode 100644 index 000000000..a131547e1 --- /dev/null +++ b/src/algos/whats-alf.ts @@ -0,0 +1,43 @@ +import { InvalidRequestError } from '@atproto/xrpc-server' +import { QueryParams } from '../lexicon/types/app/bsky/feed/getFeedSkeleton' +import { AppContext } from '../config' + +// max 15 chars +export const shortname = 'whats-alf' + +export const handler = async (ctx: AppContext, params: QueryParams) => { + let builder = ctx.db + .selectFrom('post') + .selectAll() + .orderBy('indexedAt', 'desc') + .orderBy('cid', 'desc') + .limit(params.limit) + + if (params.cursor) { + const [indexedAt, cid] = params.cursor.split('::') + if (!indexedAt || !cid) { + throw new InvalidRequestError('malformed cursor') + } + const timeStr = new Date(parseInt(indexedAt, 10)).toISOString() + builder = builder + .where('post.indexedAt', '<', timeStr) + .orWhere((qb) => qb.where('post.indexedAt', '=', timeStr)) + .where('post.cid', '<', cid) + } + const res = await builder.execute() + + const feed = res.map((row) => ({ + post: row.uri, + })) + + let cursor: string | undefined + const last = res.at(-1) + if (last) { + cursor = `${new Date(last.indexedAt).getTime()}::${last.cid}` + } + + return { + cursor, + feed, + } +} diff --git a/src/auth.ts b/src/auth.ts new file mode 100644 index 000000000..9ccaa99c3 --- /dev/null +++ b/src/auth.ts @@ -0,0 +1,18 @@ +import express from 'express' +import { verifyJwt, AuthRequiredError } from '@atproto/xrpc-server' +import { DidResolver } from '@atproto/did-resolver' + +export const validateAuth = async ( + req: express.Request, + serviceDid: string, + didResolver: DidResolver, +): Promise => { + const { authorization = '' } = req.headers + if (!authorization.startsWith('Bearer ')) { + throw new AuthRequiredError() + } + const jwt = authorization.replace('Bearer ', '').trim() + return verifyJwt(jwt, serviceDid, async (did: string) => { + return didResolver.resolveAtprotoKey(did) + }) +} diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 000000000..c394fc93d --- /dev/null +++ b/src/config.ts @@ -0,0 +1,19 @@ +import { Database } from './db' +import { DidResolver } from '@atproto/did-resolver' + +export type AppContext = { + db: Database + didResolver: DidResolver + cfg: Config +} + +export type Config = { + port: number + listenhost: string + hostname: string + sqliteLocation: string + subscriptionEndpoint: string + serviceDid: string + publisherDid: string + subscriptionReconnectDelay: number +} diff --git a/src/db/index.ts b/src/db/index.ts index 3c269ad62..9275d4685 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -1,5 +1,7 @@ -import { Kysely, SqliteDialect } from 'kysely' import SqliteDb from 'better-sqlite3' +import { Kysely, Migrator, SqliteDialect } from 'kysely' +import { DatabaseSchema } from './schema' +import { migrationProvider } from './migrations' export const createDb = (location: string): Database => { return new Kysely({ @@ -9,22 +11,10 @@ export const createDb = (location: string): Database => { }) } -export type Database = Kysely - -export type PostTable = { - uri: string - cid: string - replyParent: string | null - replyRoot: string | null - indexedAt: string -} - -export type SubStateTable = { - service: string - cursor: number +export const migrateToLatest = async (db: Database) => { + const migrator = new Migrator({ db, provider: migrationProvider }) + const { error } = await migrator.migrateToLatest() + if (error) throw error } -export type DatabaseSchema = { - posts: PostTable - sub_state: SubStateTable -} +export type Database = Kysely diff --git a/src/db/migrations.ts b/src/db/migrations.ts new file mode 100644 index 000000000..966007801 --- /dev/null +++ b/src/db/migrations.ts @@ -0,0 +1,31 @@ +import { Kysely, Migration, MigrationProvider } from 'kysely' + +const migrations: Record = {} + +export const migrationProvider: MigrationProvider = { + async getMigrations() { + return migrations + }, +} + +migrations['001'] = { + async up(db: Kysely) { + await db.schema + .createTable('post') + .addColumn('uri', 'varchar', (col) => col.primaryKey()) + .addColumn('cid', 'varchar', (col) => col.notNull()) + .addColumn('replyParent', 'varchar') + .addColumn('replyRoot', 'varchar') + .addColumn('indexedAt', 'varchar', (col) => col.notNull()) + .execute() + await db.schema + .createTable('sub_state') + .addColumn('service', 'varchar', (col) => col.primaryKey()) + .addColumn('cursor', 'integer', (col) => col.notNull()) + .execute() + }, + async down(db: Kysely) { + await db.schema.dropTable('post').execute() + await db.schema.dropTable('sub_state').execute() + }, +} diff --git a/src/db/schema.ts b/src/db/schema.ts new file mode 100644 index 000000000..8b2455d74 --- /dev/null +++ b/src/db/schema.ts @@ -0,0 +1,17 @@ +export type DatabaseSchema = { + post: Post + sub_state: SubState +} + +export type Post = { + uri: string + cid: string + replyParent: string | null + replyRoot: string | null + indexedAt: string +} + +export type SubState = { + service: string + cursor: number +} diff --git a/src/feed-generation.ts b/src/feed-generation.ts deleted file mode 100644 index 30b9fd837..000000000 --- a/src/feed-generation.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { InvalidRequestError } from '@atproto/xrpc-server' -import { Database } from './db' -import { Server } from './lexicon' - -export default function (server: Server, db: Database) { - server.app.bsky.feed.getFeedSkeleton(async ({ params, auth }) => { - if (params.feed !== 'alf.bsky.social') { - throw new InvalidRequestError('algorithm unsupported') - } - let builder = db - .selectFrom('posts') - .selectAll() - .orderBy('indexedAt', 'desc') - .orderBy('cid', 'desc') - - if (params.cursor) { - const [indexedAt, cid] = params.cursor.split('..') - if (!indexedAt || !cid) { - throw new InvalidRequestError('malformed cursor') - } - const timeStr = new Date(parseInt(indexedAt, 10)).toISOString() - builder = builder - .where('posts.indexedAt', '<', timeStr) - .orWhere((qb) => qb.where('posts.indexedAt', '=', timeStr)) - .where('posts.cid', '<', cid) - } - const res = await builder.execute() - - const feed = res.map((row) => ({ - post: row.uri, - replyTo: - row.replyParent && row.replyRoot - ? { - root: row.replyRoot, - parent: row.replyParent, - } - : undefined, - })) - - let cursor: string | undefined - const last = res.at(-1) - if (last) { - cursor = `${new Date(last.indexedAt).getTime()}::${last.cid}` - } - - return { - encoding: 'application/json', - body: { - cursor, - feed, - }, - } - }) -} diff --git a/src/index.ts b/src/index.ts index b8bbe8194..f05fa1bda 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,41 @@ +import dotenv from 'dotenv' import FeedGenerator from './server' const run = async () => { - // we'll add .env soon - const server = FeedGenerator.create() + dotenv.config() + const hostname = maybeStr(process.env.FEEDGEN_HOSTNAME) ?? 'example.com' + const serviceDid = + maybeStr(process.env.FEEDGEN_SERVICE_DID) ?? `did:web:${hostname}` + const server = FeedGenerator.create({ + port: maybeInt(process.env.FEEDGEN_PORT) ?? 3000, + listenhost: maybeStr(process.env.FEEDGEN_LISTENHOST) ?? 'localhost', + sqliteLocation: maybeStr(process.env.FEEDGEN_SQLITE_LOCATION) ?? ':memory:', + subscriptionEndpoint: + maybeStr(process.env.FEEDGEN_SUBSCRIPTION_ENDPOINT) ?? + 'wss://bsky.social', + publisherDid: + maybeStr(process.env.FEEDGEN_PUBLISHER_DID) ?? 'did:example:alice', + subscriptionReconnectDelay: + maybeInt(process.env.FEEDGEN_SUBSCRIPTION_RECONNECT_DELAY) ?? 3000, + hostname, + serviceDid, + }) await server.start() - console.log(`πŸ€– running feed generator at localhost${server.cfg.port}`) + console.log( + `πŸ€– running feed generator at http://${server.cfg.listenhost}:${server.cfg.port}`, + ) +} + +const maybeStr = (val?: string) => { + if (!val) return undefined + return val +} + +const maybeInt = (val?: string) => { + if (!val) return undefined + const int = parseInt(val, 10) + if (isNaN(int)) return undefined + return int } run() diff --git a/src/lexicon/index.ts b/src/lexicon/index.ts index 0fe1132bb..02e3ada18 100644 --- a/src/lexicon/index.ts +++ b/src/lexicon/index.ts @@ -9,7 +9,9 @@ import { StreamAuthVerifier, } from '@atproto/xrpc-server' import { schemas } from './lexicons' +import * as ComAtprotoAdminDisableAccountInvites from './types/com/atproto/admin/disableAccountInvites' import * as ComAtprotoAdminDisableInviteCodes from './types/com/atproto/admin/disableInviteCodes' +import * as ComAtprotoAdminEnableAccountInvites from './types/com/atproto/admin/enableAccountInvites' import * as ComAtprotoAdminGetInviteCodes from './types/com/atproto/admin/getInviteCodes' import * as ComAtprotoAdminGetModerationAction from './types/com/atproto/admin/getModerationAction' import * as ComAtprotoAdminGetModerationActions from './types/com/atproto/admin/getModerationActions' @@ -35,6 +37,7 @@ import * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRe import * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord' import * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords' import * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord' +import * as ComAtprotoRepoRebaseRepo from './types/com/atproto/repo/rebaseRepo' import * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob' import * as ComAtprotoServerCreateAccount from './types/com/atproto/server/createAccount' import * as ComAtprotoServerCreateAppPassword from './types/com/atproto/server/createAppPassword' @@ -64,28 +67,38 @@ import * as ComAtprotoSyncListRepos from './types/com/atproto/sync/listRepos' import * as ComAtprotoSyncNotifyOfUpdate from './types/com/atproto/sync/notifyOfUpdate' import * as ComAtprotoSyncRequestCrawl from './types/com/atproto/sync/requestCrawl' import * as ComAtprotoSyncSubscribeRepos from './types/com/atproto/sync/subscribeRepos' +import * as AppBskyActorGetPreferences from './types/app/bsky/actor/getPreferences' import * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile' import * as AppBskyActorGetProfiles from './types/app/bsky/actor/getProfiles' import * as AppBskyActorGetSuggestions from './types/app/bsky/actor/getSuggestions' +import * as AppBskyActorPutPreferences from './types/app/bsky/actor/putPreferences' import * as AppBskyActorSearchActors from './types/app/bsky/actor/searchActors' import * as AppBskyActorSearchActorsTypeahead from './types/app/bsky/actor/searchActorsTypeahead' -import * as AppBskyFeedBookmarkFeed from './types/app/bsky/feed/bookmarkFeed' +import * as AppBskyFeedDescribeFeedGenerator from './types/app/bsky/feed/describeFeedGenerator' +import * as AppBskyFeedGetActorFeeds from './types/app/bsky/feed/getActorFeeds' import * as AppBskyFeedGetAuthorFeed from './types/app/bsky/feed/getAuthorFeed' -import * as AppBskyFeedGetBookmarkedFeeds from './types/app/bsky/feed/getBookmarkedFeeds' import * as AppBskyFeedGetFeed from './types/app/bsky/feed/getFeed' +import * as AppBskyFeedGetFeedGenerator from './types/app/bsky/feed/getFeedGenerator' import * as AppBskyFeedGetFeedSkeleton from './types/app/bsky/feed/getFeedSkeleton' import * as AppBskyFeedGetLikes from './types/app/bsky/feed/getLikes' import * as AppBskyFeedGetPostThread from './types/app/bsky/feed/getPostThread' import * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts' import * as AppBskyFeedGetRepostedBy from './types/app/bsky/feed/getRepostedBy' +import * as AppBskyFeedGetSavedFeeds from './types/app/bsky/feed/getSavedFeeds' import * as AppBskyFeedGetTimeline from './types/app/bsky/feed/getTimeline' -import * as AppBskyFeedUnbookmarkFeed from './types/app/bsky/feed/unbookmarkFeed' +import * as AppBskyFeedSaveFeed from './types/app/bsky/feed/saveFeed' +import * as AppBskyFeedUnsaveFeed from './types/app/bsky/feed/unsaveFeed' import * as AppBskyGraphGetBlocks from './types/app/bsky/graph/getBlocks' import * as AppBskyGraphGetFollowers from './types/app/bsky/graph/getFollowers' import * as AppBskyGraphGetFollows from './types/app/bsky/graph/getFollows' +import * as AppBskyGraphGetList from './types/app/bsky/graph/getList' +import * as AppBskyGraphGetListMutes from './types/app/bsky/graph/getListMutes' +import * as AppBskyGraphGetLists from './types/app/bsky/graph/getLists' import * as AppBskyGraphGetMutes from './types/app/bsky/graph/getMutes' import * as AppBskyGraphMuteActor from './types/app/bsky/graph/muteActor' +import * as AppBskyGraphMuteActorList from './types/app/bsky/graph/muteActorList' import * as AppBskyGraphUnmuteActor from './types/app/bsky/graph/unmuteActor' +import * as AppBskyGraphUnmuteActorList from './types/app/bsky/graph/unmuteActorList' import * as AppBskyNotificationGetUnreadCount from './types/app/bsky/notification/getUnreadCount' import * as AppBskyNotificationListNotifications from './types/app/bsky/notification/listNotifications' import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen' @@ -105,9 +118,8 @@ export const COM_ATPROTO_MODERATION = { DefsReasonRude: 'com.atproto.moderation.defs#reasonRude', DefsReasonOther: 'com.atproto.moderation.defs#reasonOther', } -export const APP_BSKY_ACTOR = { - DefsUser: 'app.bsky.actor.defs#user', - DefsFeedGenerator: 'app.bsky.actor.defs#feedGenerator', +export const APP_BSKY_GRAPH = { + DefsModlist: 'app.bsky.graph.defs#modlist', } export function createServer(options?: XrpcOptions): Server { @@ -165,6 +177,16 @@ export class AdminNS { this._server = server } + disableAccountInvites( + cfg: ConfigOf< + AV, + ComAtprotoAdminDisableAccountInvites.Handler> + >, + ) { + const nsid = 'com.atproto.admin.disableAccountInvites' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + disableInviteCodes( cfg: ConfigOf< AV, @@ -175,6 +197,16 @@ export class AdminNS { return this._server.xrpc.method(nsid, cfg) } + enableAccountInvites( + cfg: ConfigOf< + AV, + ComAtprotoAdminEnableAccountInvites.Handler> + >, + ) { + const nsid = 'com.atproto.admin.enableAccountInvites' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + getInviteCodes( cfg: ConfigOf>>, ) { @@ -412,6 +444,13 @@ export class RepoNS { return this._server.xrpc.method(nsid, cfg) } + rebaseRepo( + cfg: ConfigOf>>, + ) { + const nsid = 'com.atproto.repo.rebaseRepo' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + uploadBlob( cfg: ConfigOf>>, ) { @@ -695,6 +734,13 @@ export class ActorNS { this._server = server } + getPreferences( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.actor.getPreferences' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + getProfile( cfg: ConfigOf>>, ) { @@ -716,6 +762,13 @@ export class ActorNS { return this._server.xrpc.method(nsid, cfg) } + putPreferences( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.actor.putPreferences' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + searchActors( cfg: ConfigOf>>, ) { @@ -749,24 +802,27 @@ export class FeedNS { this._server = server } - bookmarkFeed( - cfg: ConfigOf>>, + describeFeedGenerator( + cfg: ConfigOf< + AV, + AppBskyFeedDescribeFeedGenerator.Handler> + >, ) { - const nsid = 'app.bsky.feed.bookmarkFeed' // @ts-ignore + const nsid = 'app.bsky.feed.describeFeedGenerator' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } - getAuthorFeed( - cfg: ConfigOf>>, + getActorFeeds( + cfg: ConfigOf>>, ) { - const nsid = 'app.bsky.feed.getAuthorFeed' // @ts-ignore + const nsid = 'app.bsky.feed.getActorFeeds' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } - getBookmarkedFeeds( - cfg: ConfigOf>>, + getAuthorFeed( + cfg: ConfigOf>>, ) { - const nsid = 'app.bsky.feed.getBookmarkedFeeds' // @ts-ignore + const nsid = 'app.bsky.feed.getAuthorFeed' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } @@ -777,6 +833,13 @@ export class FeedNS { return this._server.xrpc.method(nsid, cfg) } + getFeedGenerator( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.feed.getFeedGenerator' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + getFeedSkeleton( cfg: ConfigOf>>, ) { @@ -812,6 +875,13 @@ export class FeedNS { return this._server.xrpc.method(nsid, cfg) } + getSavedFeeds( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.feed.getSavedFeeds' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + getTimeline( cfg: ConfigOf>>, ) { @@ -819,10 +889,17 @@ export class FeedNS { return this._server.xrpc.method(nsid, cfg) } - unbookmarkFeed( - cfg: ConfigOf>>, + saveFeed( + cfg: ConfigOf>>, ) { - const nsid = 'app.bsky.feed.unbookmarkFeed' // @ts-ignore + const nsid = 'app.bsky.feed.saveFeed' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + unsaveFeed( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.feed.unsaveFeed' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } } @@ -855,6 +932,27 @@ export class GraphNS { return this._server.xrpc.method(nsid, cfg) } + getList( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.graph.getList' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + getListMutes( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.graph.getListMutes' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + getLists( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.graph.getLists' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + getMutes( cfg: ConfigOf>>, ) { @@ -869,12 +967,26 @@ export class GraphNS { return this._server.xrpc.method(nsid, cfg) } + muteActorList( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.graph.muteActorList' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + unmuteActor( cfg: ConfigOf>>, ) { const nsid = 'app.bsky.graph.unmuteActor' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } + + unmuteActorList( + cfg: ConfigOf>>, + ) { + const nsid = 'app.bsky.graph.unmuteActorList' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } } export class NotificationNS { diff --git a/src/lexicon/lexicons.ts b/src/lexicon/lexicons.ts index 5e07faeb0..70be29cef 100644 --- a/src/lexicon/lexicons.ts +++ b/src/lexicon/lexicons.ts @@ -333,6 +333,9 @@ export const schemaDict = { type: 'ref', ref: 'lex:com.atproto.server.defs#inviteCode', }, + invitesDisabled: { + type: 'boolean', + }, }, }, repoViewDetail: { @@ -388,6 +391,9 @@ export const schemaDict = { ref: 'lex:com.atproto.server.defs#inviteCode', }, }, + invitesDisabled: { + type: 'boolean', + }, }, }, repoRef: { @@ -589,6 +595,30 @@ export const schemaDict = { }, }, }, + ComAtprotoAdminDisableAccountInvites: { + lexicon: 1, + id: 'com.atproto.admin.disableAccountInvites', + defs: { + main: { + type: 'procedure', + description: + 'Disable an account from receiving new invite codes, but does not invalidate existing codes', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['account'], + properties: { + account: { + type: 'string', + format: 'did', + }, + }, + }, + }, + }, + }, + }, ComAtprotoAdminDisableInviteCodes: { lexicon: 1, id: 'com.atproto.admin.disableInviteCodes', @@ -620,6 +650,29 @@ export const schemaDict = { }, }, }, + ComAtprotoAdminEnableAccountInvites: { + lexicon: 1, + id: 'com.atproto.admin.enableAccountInvites', + defs: { + main: { + type: 'procedure', + description: 'Re-enable an accounts ability to receive invite codes', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['account'], + properties: { + account: { + type: 'string', + format: 'did', + }, + }, + }, + }, + }, + }, + }, ComAtprotoAdminGetInviteCodes: { lexicon: 1, id: 'com.atproto.admin.getInviteCodes', @@ -782,6 +835,15 @@ export const schemaDict = { resolved: { type: 'boolean', }, + actionType: { + type: 'string', + knownValues: [ + 'com.atproto.admin.defs#takedown', + 'com.atproto.admin.defs#flag', + 'com.atproto.admin.defs#acknowledge', + 'com.atproto.admin.defs#escalate', + ], + }, limit: { type: 'integer', minimum: 1, @@ -1959,6 +2021,41 @@ export const schemaDict = { }, }, }, + ComAtprotoRepoRebaseRepo: { + lexicon: 1, + id: 'com.atproto.repo.rebaseRepo', + defs: { + main: { + type: 'procedure', + description: 'Simple rebase of repo that deletes history', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['repo'], + properties: { + repo: { + type: 'string', + format: 'at-identifier', + description: 'The handle or DID of the repo.', + }, + swapCommit: { + type: 'string', + format: 'cid', + description: + 'Compare and swap with the previous commit by cid.', + }, + }, + }, + }, + errors: [ + { + name: 'InvalidSwap', + }, + ], + }, + }, + }, ComAtprotoRepoStrongRef: { lexicon: 1, id: 'com.atproto.repo.strongRef', @@ -2026,6 +2123,10 @@ export const schemaDict = { type: 'string', format: 'handle', }, + did: { + type: 'string', + format: 'did', + }, inviteCode: { type: 'string', }, @@ -2077,6 +2178,12 @@ export const schemaDict = { { name: 'UnsupportedDomain', }, + { + name: 'UnresolvableDid', + }, + { + name: 'IncompatibleDidDoc', + }, ], }, }, @@ -3285,10 +3392,6 @@ export const schemaDict = { avatar: { type: 'string', }, - actorType: { - type: 'ref', - ref: 'lex:app.bsky.actor.defs#actorType', - }, viewer: { type: 'ref', ref: 'lex:app.bsky.actor.defs#viewerState', @@ -3327,10 +3430,6 @@ export const schemaDict = { avatar: { type: 'string', }, - actorType: { - type: 'ref', - ref: 'lex:app.bsky.actor.defs#actorType', - }, indexedAt: { type: 'string', format: 'datetime', @@ -3373,14 +3472,6 @@ export const schemaDict = { avatar: { type: 'string', }, - actorType: { - type: 'ref', - ref: 'lex:app.bsky.actor.defs#actorType', - }, - actorInfo: { - type: 'union', - refs: ['lex:app.bsky.actor.defs#infoFeedGenerator'], - }, banner: { type: 'string', }, @@ -3416,6 +3507,10 @@ export const schemaDict = { muted: { type: 'boolean', }, + mutedByList: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listViewBasic', + }, blockedBy: { type: 'boolean', }, @@ -3433,31 +3528,65 @@ export const schemaDict = { }, }, }, - infoFeedGenerator: { + preferences: { + type: 'array', + items: { + type: 'union', + refs: [ + 'lex:app.bsky.actor.defs#adultContentPref', + 'lex:app.bsky.actor.defs#contentLabelPref', + ], + }, + }, + adultContentPref: { type: 'object', - required: ['likes'], + required: ['enabled'], properties: { - likes: { - type: 'integer', + enabled: { + type: 'boolean', + default: false, }, }, }, - actorType: { - type: 'string', - knownValues: [ - 'app.bsky.actor.defs#user', - 'app.bsky.actor.defs#feedGenerator', - ], - }, - user: { - type: 'token', - description: - 'Actor type: User. This is the default option and an actor is assumed to be a user unless suggested otherwise.', + contentLabelPref: { + type: 'object', + required: ['label', 'visibility'], + properties: { + label: { + type: 'string', + }, + visibility: { + type: 'string', + knownValues: ['show', 'warn', 'hide'], + }, + }, }, - feedGenerator: { - type: 'token', - description: - 'Actor type: Feed Generator. A service that provides a custom feed.', + }, + }, + AppBskyActorGetPreferences: { + lexicon: 1, + id: 'app.bsky.actor.getPreferences', + defs: { + main: { + type: 'query', + description: 'Get private preferences attached to the account.', + parameters: { + type: 'params', + properties: {}, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['preferences'], + properties: { + preferences: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#preferences', + }, + }, + }, + }, }, }, }, @@ -3605,6 +3734,29 @@ export const schemaDict = { }, }, }, + AppBskyActorPutPreferences: { + lexicon: 1, + id: 'app.bsky.actor.putPreferences', + defs: { + main: { + type: 'procedure', + description: 'Sets the private preferences attached to the account.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['preferences'], + properties: { + preferences: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#preferences', + }, + }, + }, + }, + }, + }, + }, AppBskyActorSearchActors: { lexicon: 1, id: 'app.bsky.actor.searchActors', @@ -3849,6 +4001,7 @@ export const schemaDict = { 'lex:app.bsky.embed.record#viewRecord', 'lex:app.bsky.embed.record#viewNotFound', 'lex:app.bsky.embed.record#viewBlocked', + 'lex:app.bsky.feed.defs#generatorView', ], }, }, @@ -3958,29 +4111,6 @@ export const schemaDict = { }, }, }, - AppBskyFeedBookmarkFeed: { - lexicon: 1, - id: 'app.bsky.feed.bookmarkFeed', - defs: { - main: { - type: 'procedure', - description: 'Bookmark a 3rd party feed for use across clients', - input: { - encoding: 'application/json', - schema: { - type: 'object', - required: ['feed'], - properties: { - feed: { - type: 'string', - format: 'at-identifier', - }, - }, - }, - }, - }, - }, - }, AppBskyFeedDefs: { lexicon: 1, id: 'app.bsky.feed.defs', @@ -4163,74 +4293,219 @@ export const schemaDict = { }, }, }, - skeletonFeedPost: { + generatorView: { type: 'object', - required: ['post'], + required: ['uri', 'cid', 'creator', 'indexedAt'], properties: { - post: { + uri: { type: 'string', format: 'at-uri', }, - replyTo: { + cid: { + type: 'string', + format: 'cid', + }, + did: { + type: 'string', + format: 'did', + }, + creator: { type: 'ref', - ref: 'lex:app.bsky.feed.defs#skeletonReplyRef', + ref: 'lex:app.bsky.actor.defs#profileView', }, - reason: { - type: 'union', - refs: ['lex:app.bsky.feed.defs#skeletonReasonRepost'], + displayName: { + type: 'string', + }, + description: { + type: 'string', + maxGraphemes: 300, + maxLength: 3000, + }, + descriptionFacets: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.richtext.facet', + }, + }, + avatar: { + type: 'string', + }, + likeCount: { + type: 'integer', + minimum: 0, + }, + viewer: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#generatorViewerState', + }, + indexedAt: { + type: 'string', + format: 'datetime', }, }, }, - skeletonReplyRef: { + generatorViewerState: { type: 'object', - required: ['root', 'parent'], properties: { - root: { - type: 'string', - ref: 'at-uri', + saved: { + type: 'boolean', }, - parent: { + like: { type: 'string', - ref: 'at-uri', + format: 'at-uri', }, }, }, - skeletonReasonRepost: { + skeletonFeedPost: { type: 'object', - required: ['by', 'indexedAt'], + required: ['post'], properties: { - by: { + post: { type: 'string', - format: 'did', + format: 'at-uri', }, - indexedAt: { + reason: { + type: 'union', + refs: ['lex:app.bsky.feed.defs#skeletonReasonRepost'], + }, + }, + }, + skeletonReasonRepost: { + type: 'object', + required: ['repost'], + properties: { + repost: { type: 'string', - format: 'datetime', + ref: 'at-uri', }, }, }, }, }, - AppBskyFeedGetAuthorFeed: { + AppBskyFeedDescribeFeedGenerator: { lexicon: 1, - id: 'app.bsky.feed.getAuthorFeed', + id: 'app.bsky.feed.describeFeedGenerator', defs: { main: { type: 'query', - description: "A view of an actor's feed.", - parameters: { - type: 'params', - required: ['actor'], - properties: { - actor: { - type: 'string', - format: 'at-identifier', - }, - limit: { - type: 'integer', - minimum: 1, - maximum: 100, - default: 50, + description: + 'Returns information about a given feed generator including TOS & offered feed URIs', + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['did', 'feeds'], + properties: { + did: { + type: 'string', + format: 'did', + }, + feeds: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.feed.describeFeedGenerator#feed', + }, + }, + links: { + type: 'ref', + ref: 'lex:app.bsky.feed.describeFeedGenerator#links', + }, + }, + }, + }, + }, + feed: { + type: 'object', + required: ['uri'], + properties: { + uri: { + type: 'string', + format: 'at-uri', + }, + }, + }, + links: { + type: 'object', + properties: { + privacyPolicy: { + type: 'string', + }, + termsOfService: { + type: 'string', + }, + }, + }, + }, + }, + AppBskyFeedGenerator: { + lexicon: 1, + id: 'app.bsky.feed.generator', + defs: { + main: { + type: 'record', + description: 'A declaration of the existence of a feed generator', + key: 'any', + record: { + type: 'object', + required: ['did', 'createdAt'], + properties: { + did: { + type: 'string', + format: 'did', + }, + displayName: { + type: 'string', + maxGraphemes: 64, + maxLength: 640, + }, + description: { + type: 'string', + maxGraphemes: 300, + maxLength: 3000, + }, + descriptionFacets: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.richtext.facet', + }, + }, + avatar: { + type: 'blob', + accept: ['image/png', 'image/jpeg'], + maxSize: 1000000, + }, + createdAt: { + type: 'string', + format: 'datetime', + }, + }, + }, + }, + }, + }, + AppBskyFeedGetActorFeeds: { + lexicon: 1, + id: 'app.bsky.feed.getActorFeeds', + defs: { + main: { + type: 'query', + description: 'Retrieve a list of feeds created by a given actor', + parameters: { + type: 'params', + required: ['actor'], + properties: { + actor: { + type: 'string', + format: 'at-identifier', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 50, }, cursor: { type: 'string', @@ -4241,43 +4516,39 @@ export const schemaDict = { encoding: 'application/json', schema: { type: 'object', - required: ['feed'], + required: ['feeds'], properties: { cursor: { type: 'string', }, - feed: { + feeds: { type: 'array', items: { type: 'ref', - ref: 'lex:app.bsky.feed.defs#feedViewPost', + ref: 'lex:app.bsky.feed.defs#generatorView', }, }, }, }, }, - errors: [ - { - name: 'BlockedActor', - }, - { - name: 'BlockedByActor', - }, - ], }, }, }, - AppBskyFeedGetBookmarkedFeeds: { + AppBskyFeedGetAuthorFeed: { lexicon: 1, - id: 'app.bsky.feed.getBookmarkedFeeds', + id: 'app.bsky.feed.getAuthorFeed', defs: { main: { type: 'query', - description: - "Retrieve a list of the authenticated user's bookmarked feeds", + description: "A view of an actor's feed.", parameters: { type: 'params', + required: ['actor'], properties: { + actor: { + type: 'string', + format: 'at-identifier', + }, limit: { type: 'integer', minimum: 1, @@ -4293,21 +4564,29 @@ export const schemaDict = { encoding: 'application/json', schema: { type: 'object', - required: ['feeds'], + required: ['feed'], properties: { cursor: { type: 'string', }, - feeds: { + feed: { type: 'array', items: { type: 'ref', - ref: 'lex:app.bsky.actor.defs#profileView', + ref: 'lex:app.bsky.feed.defs#feedViewPost', }, }, }, }, }, + errors: [ + { + name: 'BlockedActor', + }, + { + name: 'BlockedByActor', + }, + ], }, }, }, @@ -4325,7 +4604,7 @@ export const schemaDict = { properties: { feed: { type: 'string', - format: 'at-identifier', + format: 'at-uri', }, limit: { type: 'integer', @@ -4357,6 +4636,51 @@ export const schemaDict = { }, }, }, + errors: [ + { + name: 'UnknownFeed', + }, + ], + }, + }, + }, + AppBskyFeedGetFeedGenerator: { + lexicon: 1, + id: 'app.bsky.feed.getFeedGenerator', + defs: { + main: { + type: 'query', + description: + 'Get information about a specific feed offered by a feed generator, such as its online status', + parameters: { + type: 'params', + required: ['feed'], + properties: { + feed: { + type: 'string', + format: 'at-uri', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['view', 'isOnline', 'isValid'], + properties: { + view: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#generatorView', + }, + isOnline: { + type: 'boolean', + }, + isValid: { + type: 'boolean', + }, + }, + }, + }, }, }, }, @@ -4373,6 +4697,7 @@ export const schemaDict = { properties: { feed: { type: 'string', + format: 'at-uri', }, limit: { type: 'integer', @@ -4404,6 +4729,11 @@ export const schemaDict = { }, }, }, + errors: [ + { + name: 'UnknownFeed', + }, + ], }, }, }, @@ -4627,6 +4957,49 @@ export const schemaDict = { }, }, }, + AppBskyFeedGetSavedFeeds: { + lexicon: 1, + id: 'app.bsky.feed.getSavedFeeds', + defs: { + main: { + type: 'query', + description: "Retrieve a list of the authenticated user's saved feeds", + parameters: { + type: 'params', + properties: { + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 50, + }, + cursor: { + type: 'string', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['feeds'], + properties: { + cursor: { + type: 'string', + }, + feeds: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#generatorView', + }, + }, + }, + }, + }, + }, + }, + }, AppBskyFeedGetTimeline: { lexicon: 1, id: 'app.bsky.feed.getTimeline', @@ -4822,13 +5195,13 @@ export const schemaDict = { }, }, }, - AppBskyFeedUnbookmarkFeed: { + AppBskyFeedSaveFeed: { lexicon: 1, - id: 'app.bsky.feed.unbookmarkFeed', + id: 'app.bsky.feed.saveFeed', defs: { main: { type: 'procedure', - description: 'Remove a bookmark for a 3rd party feed', + description: 'Save a 3rd party feed for use across clients', input: { encoding: 'application/json', schema: { @@ -4837,7 +5210,7 @@ export const schemaDict = { properties: { feed: { type: 'string', - format: 'at-identifier', + format: 'at-uri', }, }, }, @@ -4845,38 +5218,170 @@ export const schemaDict = { }, }, }, - AppBskyGraphBlock: { + AppBskyFeedUnsaveFeed: { lexicon: 1, - id: 'app.bsky.graph.block', + id: 'app.bsky.feed.unsaveFeed', defs: { main: { - type: 'record', - description: 'A block.', - key: 'tid', - record: { - type: 'object', - required: ['subject', 'createdAt'], - properties: { - subject: { - type: 'string', - format: 'did', - }, - createdAt: { - type: 'string', - format: 'datetime', + type: 'procedure', + description: 'Unsave a 3rd party feed', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['feed'], + properties: { + feed: { + type: 'string', + format: 'at-uri', + }, }, }, }, }, }, }, - AppBskyGraphFollow: { + AppBskyGraphBlock: { lexicon: 1, - id: 'app.bsky.graph.follow', + id: 'app.bsky.graph.block', defs: { main: { type: 'record', - description: 'A social follow.', + description: 'A block.', + key: 'tid', + record: { + type: 'object', + required: ['subject', 'createdAt'], + properties: { + subject: { + type: 'string', + format: 'did', + }, + createdAt: { + type: 'string', + format: 'datetime', + }, + }, + }, + }, + }, + }, + AppBskyGraphDefs: { + lexicon: 1, + id: 'app.bsky.graph.defs', + defs: { + listViewBasic: { + type: 'object', + required: ['uri', 'creator', 'name', 'purpose'], + properties: { + uri: { + type: 'string', + format: 'at-uri', + }, + name: { + type: 'string', + maxLength: 64, + minLength: 1, + }, + purpose: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listPurpose', + }, + avatar: { + type: 'string', + }, + viewer: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listViewerState', + }, + indexedAt: { + type: 'string', + format: 'datetime', + }, + }, + }, + listView: { + type: 'object', + required: ['uri', 'creator', 'name', 'purpose', 'indexedAt'], + properties: { + uri: { + type: 'string', + format: 'at-uri', + }, + creator: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#profileView', + }, + name: { + type: 'string', + maxLength: 64, + minLength: 1, + }, + purpose: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listPurpose', + }, + description: { + type: 'string', + maxGraphemes: 300, + maxLength: 3000, + }, + descriptionFacets: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.richtext.facet', + }, + }, + avatar: { + type: 'string', + }, + viewer: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listViewerState', + }, + indexedAt: { + type: 'string', + format: 'datetime', + }, + }, + }, + listItemView: { + type: 'object', + required: ['subject'], + properties: { + subject: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#profileView', + }, + }, + }, + listPurpose: { + type: 'string', + knownValues: ['app.bsky.graph.defs#modlist'], + }, + modlist: { + type: 'token', + description: + 'A list of actors to apply an aggregate moderation action (mute/block) on', + }, + listViewerState: { + type: 'object', + properties: { + muted: { + type: 'boolean', + }, + }, + }, + }, + }, + AppBskyGraphFollow: { + lexicon: 1, + id: 'app.bsky.graph.follow', + defs: { + main: { + type: 'record', + description: 'A social follow.', key: 'tid', record: { type: 'object', @@ -5042,6 +5547,149 @@ export const schemaDict = { }, }, }, + AppBskyGraphGetList: { + lexicon: 1, + id: 'app.bsky.graph.getList', + defs: { + main: { + type: 'query', + description: 'Fetch a list of actors', + parameters: { + type: 'params', + required: ['list'], + properties: { + list: { + type: 'string', + format: 'at-uri', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 50, + }, + cursor: { + type: 'string', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['list', 'items'], + properties: { + cursor: { + type: 'string', + }, + list: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listView', + }, + items: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listItemView', + }, + }, + }, + }, + }, + }, + }, + }, + AppBskyGraphGetListMutes: { + lexicon: 1, + id: 'app.bsky.graph.getListMutes', + defs: { + main: { + type: 'query', + description: "Which lists is the requester's account muting?", + parameters: { + type: 'params', + properties: { + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 50, + }, + cursor: { + type: 'string', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['lists'], + properties: { + cursor: { + type: 'string', + }, + lists: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listView', + }, + }, + }, + }, + }, + }, + }, + }, + AppBskyGraphGetLists: { + lexicon: 1, + id: 'app.bsky.graph.getLists', + defs: { + main: { + type: 'query', + description: 'Fetch a list of lists that belong to an actor', + parameters: { + type: 'params', + required: ['actor'], + properties: { + actor: { + type: 'string', + format: 'at-identifier', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 50, + }, + cursor: { + type: 'string', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['lists'], + properties: { + cursor: { + type: 'string', + }, + lists: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listView', + }, + }, + }, + }, + }, + }, + }, + }, AppBskyGraphGetMutes: { lexicon: 1, id: 'app.bsky.graph.getMutes', @@ -5085,6 +5733,82 @@ export const schemaDict = { }, }, }, + AppBskyGraphList: { + lexicon: 1, + id: 'app.bsky.graph.list', + defs: { + main: { + type: 'record', + description: 'A declaration of a list of actors.', + key: 'tid', + record: { + type: 'object', + required: ['name', 'purpose', 'createdAt'], + properties: { + purpose: { + type: 'ref', + ref: 'lex:app.bsky.graph.defs#listPurpose', + }, + name: { + type: 'string', + maxLength: 64, + minLength: 1, + }, + description: { + type: 'string', + maxGraphemes: 300, + maxLength: 3000, + }, + descriptionFacets: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.richtext.facet', + }, + }, + avatar: { + type: 'blob', + accept: ['image/png', 'image/jpeg'], + maxSize: 1000000, + }, + createdAt: { + type: 'string', + format: 'datetime', + }, + }, + }, + }, + }, + }, + AppBskyGraphListitem: { + lexicon: 1, + id: 'app.bsky.graph.listitem', + defs: { + main: { + type: 'record', + description: 'An item under a declared list of actors', + key: 'tid', + record: { + type: 'object', + required: ['subject', 'list', 'createdAt'], + properties: { + subject: { + type: 'string', + format: 'did', + }, + list: { + type: 'string', + format: 'at-uri', + }, + createdAt: { + type: 'string', + format: 'datetime', + }, + }, + }, + }, + }, + }, AppBskyGraphMuteActor: { lexicon: 1, id: 'app.bsky.graph.muteActor', @@ -5108,6 +5832,29 @@ export const schemaDict = { }, }, }, + AppBskyGraphMuteActorList: { + lexicon: 1, + id: 'app.bsky.graph.muteActorList', + defs: { + main: { + type: 'procedure', + description: 'Mute a list of actors.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['list'], + properties: { + list: { + type: 'string', + format: 'at-uri', + }, + }, + }, + }, + }, + }, + }, AppBskyGraphUnmuteActor: { lexicon: 1, id: 'app.bsky.graph.unmuteActor', @@ -5131,6 +5878,29 @@ export const schemaDict = { }, }, }, + AppBskyGraphUnmuteActorList: { + lexicon: 1, + id: 'app.bsky.graph.unmuteActorList', + defs: { + main: { + type: 'procedure', + description: 'Unmute a list of actors.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['list'], + properties: { + list: { + type: 'string', + format: 'at-uri', + }, + }, + }, + }, + }, + }, + }, AppBskyNotificationGetUnreadCount: { lexicon: 1, id: 'app.bsky.notification.getUnreadCount', @@ -5406,7 +6176,10 @@ export const schemas: LexiconDoc[] = Object.values(schemaDict) as LexiconDoc[] export const lexicons: Lexicons = new Lexicons(schemas) export const ids = { ComAtprotoAdminDefs: 'com.atproto.admin.defs', + ComAtprotoAdminDisableAccountInvites: + 'com.atproto.admin.disableAccountInvites', ComAtprotoAdminDisableInviteCodes: 'com.atproto.admin.disableInviteCodes', + ComAtprotoAdminEnableAccountInvites: 'com.atproto.admin.enableAccountInvites', ComAtprotoAdminGetInviteCodes: 'com.atproto.admin.getInviteCodes', ComAtprotoAdminGetModerationAction: 'com.atproto.admin.getModerationAction', ComAtprotoAdminGetModerationActions: 'com.atproto.admin.getModerationActions', @@ -5436,6 +6209,7 @@ export const ids = { ComAtprotoRepoGetRecord: 'com.atproto.repo.getRecord', ComAtprotoRepoListRecords: 'com.atproto.repo.listRecords', ComAtprotoRepoPutRecord: 'com.atproto.repo.putRecord', + ComAtprotoRepoRebaseRepo: 'com.atproto.repo.rebaseRepo', ComAtprotoRepoStrongRef: 'com.atproto.repo.strongRef', ComAtprotoRepoUploadBlob: 'com.atproto.repo.uploadBlob', ComAtprotoServerCreateAccount: 'com.atproto.server.createAccount', @@ -5471,39 +6245,53 @@ export const ids = { ComAtprotoSyncRequestCrawl: 'com.atproto.sync.requestCrawl', ComAtprotoSyncSubscribeRepos: 'com.atproto.sync.subscribeRepos', AppBskyActorDefs: 'app.bsky.actor.defs', + AppBskyActorGetPreferences: 'app.bsky.actor.getPreferences', AppBskyActorGetProfile: 'app.bsky.actor.getProfile', AppBskyActorGetProfiles: 'app.bsky.actor.getProfiles', AppBskyActorGetSuggestions: 'app.bsky.actor.getSuggestions', AppBskyActorProfile: 'app.bsky.actor.profile', + AppBskyActorPutPreferences: 'app.bsky.actor.putPreferences', AppBskyActorSearchActors: 'app.bsky.actor.searchActors', AppBskyActorSearchActorsTypeahead: 'app.bsky.actor.searchActorsTypeahead', AppBskyEmbedExternal: 'app.bsky.embed.external', AppBskyEmbedImages: 'app.bsky.embed.images', AppBskyEmbedRecord: 'app.bsky.embed.record', AppBskyEmbedRecordWithMedia: 'app.bsky.embed.recordWithMedia', - AppBskyFeedBookmarkFeed: 'app.bsky.feed.bookmarkFeed', AppBskyFeedDefs: 'app.bsky.feed.defs', + AppBskyFeedDescribeFeedGenerator: 'app.bsky.feed.describeFeedGenerator', + AppBskyFeedGenerator: 'app.bsky.feed.generator', + AppBskyFeedGetActorFeeds: 'app.bsky.feed.getActorFeeds', AppBskyFeedGetAuthorFeed: 'app.bsky.feed.getAuthorFeed', - AppBskyFeedGetBookmarkedFeeds: 'app.bsky.feed.getBookmarkedFeeds', AppBskyFeedGetFeed: 'app.bsky.feed.getFeed', + AppBskyFeedGetFeedGenerator: 'app.bsky.feed.getFeedGenerator', AppBskyFeedGetFeedSkeleton: 'app.bsky.feed.getFeedSkeleton', AppBskyFeedGetLikes: 'app.bsky.feed.getLikes', AppBskyFeedGetPostThread: 'app.bsky.feed.getPostThread', AppBskyFeedGetPosts: 'app.bsky.feed.getPosts', AppBskyFeedGetRepostedBy: 'app.bsky.feed.getRepostedBy', + AppBskyFeedGetSavedFeeds: 'app.bsky.feed.getSavedFeeds', AppBskyFeedGetTimeline: 'app.bsky.feed.getTimeline', AppBskyFeedLike: 'app.bsky.feed.like', AppBskyFeedPost: 'app.bsky.feed.post', AppBskyFeedRepost: 'app.bsky.feed.repost', - AppBskyFeedUnbookmarkFeed: 'app.bsky.feed.unbookmarkFeed', + AppBskyFeedSaveFeed: 'app.bsky.feed.saveFeed', + AppBskyFeedUnsaveFeed: 'app.bsky.feed.unsaveFeed', AppBskyGraphBlock: 'app.bsky.graph.block', + AppBskyGraphDefs: 'app.bsky.graph.defs', AppBskyGraphFollow: 'app.bsky.graph.follow', AppBskyGraphGetBlocks: 'app.bsky.graph.getBlocks', AppBskyGraphGetFollowers: 'app.bsky.graph.getFollowers', AppBskyGraphGetFollows: 'app.bsky.graph.getFollows', + AppBskyGraphGetList: 'app.bsky.graph.getList', + AppBskyGraphGetListMutes: 'app.bsky.graph.getListMutes', + AppBskyGraphGetLists: 'app.bsky.graph.getLists', AppBskyGraphGetMutes: 'app.bsky.graph.getMutes', + AppBskyGraphList: 'app.bsky.graph.list', + AppBskyGraphListitem: 'app.bsky.graph.listitem', AppBskyGraphMuteActor: 'app.bsky.graph.muteActor', + AppBskyGraphMuteActorList: 'app.bsky.graph.muteActorList', AppBskyGraphUnmuteActor: 'app.bsky.graph.unmuteActor', + AppBskyGraphUnmuteActorList: 'app.bsky.graph.unmuteActorList', AppBskyNotificationGetUnreadCount: 'app.bsky.notification.getUnreadCount', AppBskyNotificationListNotifications: 'app.bsky.notification.listNotifications', diff --git a/src/lexicon/types/app/bsky/actor/defs.ts b/src/lexicon/types/app/bsky/actor/defs.ts index 3d826c466..deb26d731 100644 --- a/src/lexicon/types/app/bsky/actor/defs.ts +++ b/src/lexicon/types/app/bsky/actor/defs.ts @@ -6,13 +6,13 @@ import { lexicons } from '../../../../lexicons' import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' +import * as AppBskyGraphDefs from '../graph/defs' export interface ProfileViewBasic { did: string handle: string displayName?: string avatar?: string - actorType?: ActorType viewer?: ViewerState labels?: ComAtprotoLabelDefs.Label[] [k: string]: unknown @@ -36,7 +36,6 @@ export interface ProfileView { displayName?: string description?: string avatar?: string - actorType?: ActorType indexedAt?: string viewer?: ViewerState labels?: ComAtprotoLabelDefs.Label[] @@ -61,8 +60,6 @@ export interface ProfileViewDetailed { displayName?: string description?: string avatar?: string - actorType?: ActorType - actorInfo?: InfoFeedGenerator | { $type: string; [k: string]: unknown } banner?: string followersCount?: number followsCount?: number @@ -87,6 +84,7 @@ export function validateProfileViewDetailed(v: unknown): ValidationResult { export interface ViewerState { muted?: boolean + mutedByList?: AppBskyGraphDefs.ListViewBasic blockedBy?: boolean blocking?: string following?: string @@ -106,29 +104,43 @@ export function validateViewerState(v: unknown): ValidationResult { return lexicons.validate('app.bsky.actor.defs#viewerState', v) } -export interface InfoFeedGenerator { - likes: number +export type Preferences = ( + | AdultContentPref + | ContentLabelPref + | { $type: string; [k: string]: unknown } +)[] + +export interface AdultContentPref { + enabled: boolean [k: string]: unknown } -export function isInfoFeedGenerator(v: unknown): v is InfoFeedGenerator { +export function isAdultContentPref(v: unknown): v is AdultContentPref { return ( isObj(v) && hasProp(v, '$type') && - v.$type === 'app.bsky.actor.defs#infoFeedGenerator' + v.$type === 'app.bsky.actor.defs#adultContentPref' ) } -export function validateInfoFeedGenerator(v: unknown): ValidationResult { - return lexicons.validate('app.bsky.actor.defs#infoFeedGenerator', v) +export function validateAdultContentPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#adultContentPref', v) } -export type ActorType = - | 'app.bsky.actor.defs#user' - | 'app.bsky.actor.defs#feedGenerator' - | (string & {}) +export interface ContentLabelPref { + label: string + visibility: 'show' | 'warn' | 'hide' | (string & {}) + [k: string]: unknown +} + +export function isContentLabelPref(v: unknown): v is ContentLabelPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#contentLabelPref' + ) +} -/** Actor type: User. This is the default option and an actor is assumed to be a user unless suggested otherwise. */ -export const USER = 'app.bsky.actor.defs#user' -/** Actor type: Feed Generator. A service that provides a custom feed. */ -export const FEEDGENERATOR = 'app.bsky.actor.defs#feedGenerator' +export function validateContentLabelPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#contentLabelPref', v) +} diff --git a/src/lexicon/types/app/bsky/actor/getPreferences.ts b/src/lexicon/types/app/bsky/actor/getPreferences.ts new file mode 100644 index 000000000..018905c86 --- /dev/null +++ b/src/lexicon/types/app/bsky/actor/getPreferences.ts @@ -0,0 +1,40 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyActorDefs from './defs' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + preferences: AppBskyActorDefs.Preferences + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/app/bsky/actor/putPreferences.ts b/src/lexicon/types/app/bsky/actor/putPreferences.ts new file mode 100644 index 000000000..ba0531cc3 --- /dev/null +++ b/src/lexicon/types/app/bsky/actor/putPreferences.ts @@ -0,0 +1,36 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyActorDefs from './defs' + +export interface QueryParams {} + +export interface InputSchema { + preferences: AppBskyActorDefs.Preferences + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/app/bsky/embed/record.ts b/src/lexicon/types/app/bsky/embed/record.ts index 3b13e3d57..c45049b7d 100644 --- a/src/lexicon/types/app/bsky/embed/record.ts +++ b/src/lexicon/types/app/bsky/embed/record.ts @@ -6,6 +6,7 @@ import { lexicons } from '../../../../lexicons' import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' import * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef' +import * as AppBskyFeedDefs from '../feed/defs' import * as AppBskyActorDefs from '../actor/defs' import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' import * as AppBskyEmbedImages from './images' @@ -35,6 +36,7 @@ export interface View { | ViewRecord | ViewNotFound | ViewBlocked + | AppBskyFeedDefs.GeneratorView | { $type: string; [k: string]: unknown } [k: string]: unknown } diff --git a/src/lexicon/types/app/bsky/feed/defs.ts b/src/lexicon/types/app/bsky/feed/defs.ts index cda2c4b46..1272c2256 100644 --- a/src/lexicon/types/app/bsky/feed/defs.ts +++ b/src/lexicon/types/app/bsky/feed/defs.ts @@ -11,6 +11,7 @@ import * as AppBskyEmbedExternal from '../embed/external' import * as AppBskyEmbedRecord from '../embed/record' import * as AppBskyEmbedRecordWithMedia from '../embed/recordWithMedia' import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' +import * as AppBskyRichtextFacet from '../richtext/facet' export interface PostView { uri: string @@ -185,46 +186,71 @@ export function validateBlockedPost(v: unknown): ValidationResult { return lexicons.validate('app.bsky.feed.defs#blockedPost', v) } -export interface SkeletonFeedPost { - post: string - replyTo?: SkeletonReplyRef - reason?: SkeletonReasonRepost | { $type: string; [k: string]: unknown } +export interface GeneratorView { + uri: string + cid: string + did?: string + creator: AppBskyActorDefs.ProfileView + displayName?: string + description?: string + descriptionFacets?: AppBskyRichtextFacet.Main[] + avatar?: string + likeCount?: number + viewer?: GeneratorViewerState + indexedAt: string [k: string]: unknown } -export function isSkeletonFeedPost(v: unknown): v is SkeletonFeedPost { +export function isGeneratorView(v: unknown): v is GeneratorView { return ( isObj(v) && hasProp(v, '$type') && - v.$type === 'app.bsky.feed.defs#skeletonFeedPost' + v.$type === 'app.bsky.feed.defs#generatorView' ) } -export function validateSkeletonFeedPost(v: unknown): ValidationResult { - return lexicons.validate('app.bsky.feed.defs#skeletonFeedPost', v) +export function validateGeneratorView(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.feed.defs#generatorView', v) } -export interface SkeletonReplyRef { - root: string - parent: string +export interface GeneratorViewerState { + saved?: boolean + like?: string [k: string]: unknown } -export function isSkeletonReplyRef(v: unknown): v is SkeletonReplyRef { +export function isGeneratorViewerState(v: unknown): v is GeneratorViewerState { return ( isObj(v) && hasProp(v, '$type') && - v.$type === 'app.bsky.feed.defs#skeletonReplyRef' + v.$type === 'app.bsky.feed.defs#generatorViewerState' ) } -export function validateSkeletonReplyRef(v: unknown): ValidationResult { - return lexicons.validate('app.bsky.feed.defs#skeletonReplyRef', v) +export function validateGeneratorViewerState(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.feed.defs#generatorViewerState', v) +} + +export interface SkeletonFeedPost { + post: string + reason?: SkeletonReasonRepost | { $type: string; [k: string]: unknown } + [k: string]: unknown +} + +export function isSkeletonFeedPost(v: unknown): v is SkeletonFeedPost { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.feed.defs#skeletonFeedPost' + ) +} + +export function validateSkeletonFeedPost(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.feed.defs#skeletonFeedPost', v) } export interface SkeletonReasonRepost { - by: string - indexedAt: string + repost: string [k: string]: unknown } diff --git a/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts b/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts new file mode 100644 index 000000000..82f1d152f --- /dev/null +++ b/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts @@ -0,0 +1,76 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + did: string + feeds: Feed[] + links?: Links + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput + +export interface Feed { + uri: string + [k: string]: unknown +} + +export function isFeed(v: unknown): v is Feed { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.feed.describeFeedGenerator#feed' + ) +} + +export function validateFeed(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.feed.describeFeedGenerator#feed', v) +} + +export interface Links { + privacyPolicy?: string + termsOfService?: string + [k: string]: unknown +} + +export function isLinks(v: unknown): v is Links { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.feed.describeFeedGenerator#links' + ) +} + +export function validateLinks(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.feed.describeFeedGenerator#links', v) +} diff --git a/src/lexicon/types/app/bsky/feed/generator.ts b/src/lexicon/types/app/bsky/feed/generator.ts new file mode 100644 index 000000000..c3082ffa4 --- /dev/null +++ b/src/lexicon/types/app/bsky/feed/generator.ts @@ -0,0 +1,31 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import * as AppBskyRichtextFacet from '../richtext/facet' + +export interface Record { + did: string + displayName?: string + description?: string + descriptionFacets?: AppBskyRichtextFacet.Main[] + avatar?: BlobRef + createdAt: string + [k: string]: unknown +} + +export function isRecord(v: unknown): v is Record { + return ( + isObj(v) && + hasProp(v, '$type') && + (v.$type === 'app.bsky.feed.generator#main' || + v.$type === 'app.bsky.feed.generator') + ) +} + +export function validateRecord(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.feed.generator#main', v) +} diff --git a/src/lexicon/types/app/bsky/feed/getActorFeeds.ts b/src/lexicon/types/app/bsky/feed/getActorFeeds.ts new file mode 100644 index 000000000..e868dd39d --- /dev/null +++ b/src/lexicon/types/app/bsky/feed/getActorFeeds.ts @@ -0,0 +1,45 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyFeedDefs from './defs' + +export interface QueryParams { + actor: string + limit: number + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + feeds: AppBskyFeedDefs.GeneratorView[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/app/bsky/feed/getFeed.ts b/src/lexicon/types/app/bsky/feed/getFeed.ts index 59114f984..850a44a84 100644 --- a/src/lexicon/types/app/bsky/feed/getFeed.ts +++ b/src/lexicon/types/app/bsky/feed/getFeed.ts @@ -33,6 +33,7 @@ export interface HandlerSuccess { export interface HandlerError { status: number message?: string + error?: 'UnknownFeed' } export type HandlerOutput = HandlerError | HandlerSuccess diff --git a/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts b/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts new file mode 100644 index 000000000..0a2005db9 --- /dev/null +++ b/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts @@ -0,0 +1,44 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyFeedDefs from './defs' + +export interface QueryParams { + feed: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + view: AppBskyFeedDefs.GeneratorView + isOnline: boolean + isValid: boolean + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts b/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts index efbb2ea31..d19a27530 100644 --- a/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts +++ b/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts @@ -33,6 +33,7 @@ export interface HandlerSuccess { export interface HandlerError { status: number message?: string + error?: 'UnknownFeed' } export type HandlerOutput = HandlerError | HandlerSuccess diff --git a/src/lexicon/types/app/bsky/feed/getBookmarkedFeeds.ts b/src/lexicon/types/app/bsky/feed/getSavedFeeds.ts similarity index 91% rename from src/lexicon/types/app/bsky/feed/getBookmarkedFeeds.ts rename to src/lexicon/types/app/bsky/feed/getSavedFeeds.ts index 0dad0a97c..176d44c6b 100644 --- a/src/lexicon/types/app/bsky/feed/getBookmarkedFeeds.ts +++ b/src/lexicon/types/app/bsky/feed/getSavedFeeds.ts @@ -7,7 +7,7 @@ import { lexicons } from '../../../../lexicons' import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' import { HandlerAuth } from '@atproto/xrpc-server' -import * as AppBskyActorDefs from '../actor/defs' +import * as AppBskyFeedDefs from './defs' export interface QueryParams { limit: number @@ -18,7 +18,7 @@ export type InputSchema = undefined export interface OutputSchema { cursor?: string - feeds: AppBskyActorDefs.ProfileView[] + feeds: AppBskyFeedDefs.GeneratorView[] [k: string]: unknown } diff --git a/src/lexicon/types/app/bsky/feed/bookmarkFeed.ts b/src/lexicon/types/app/bsky/feed/saveFeed.ts similarity index 100% rename from src/lexicon/types/app/bsky/feed/bookmarkFeed.ts rename to src/lexicon/types/app/bsky/feed/saveFeed.ts diff --git a/src/lexicon/types/app/bsky/feed/unbookmarkFeed.ts b/src/lexicon/types/app/bsky/feed/unsaveFeed.ts similarity index 100% rename from src/lexicon/types/app/bsky/feed/unbookmarkFeed.ts rename to src/lexicon/types/app/bsky/feed/unsaveFeed.ts diff --git a/src/lexicon/types/app/bsky/graph/defs.ts b/src/lexicon/types/app/bsky/graph/defs.ts new file mode 100644 index 000000000..cc2395abc --- /dev/null +++ b/src/lexicon/types/app/bsky/graph/defs.ts @@ -0,0 +1,95 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import * as AppBskyActorDefs from '../actor/defs' +import * as AppBskyRichtextFacet from '../richtext/facet' + +export interface ListViewBasic { + uri: string + name: string + purpose: ListPurpose + avatar?: string + viewer?: ListViewerState + indexedAt?: string + [k: string]: unknown +} + +export function isListViewBasic(v: unknown): v is ListViewBasic { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.graph.defs#listViewBasic' + ) +} + +export function validateListViewBasic(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.graph.defs#listViewBasic', v) +} + +export interface ListView { + uri: string + creator: AppBskyActorDefs.ProfileView + name: string + purpose: ListPurpose + description?: string + descriptionFacets?: AppBskyRichtextFacet.Main[] + avatar?: string + viewer?: ListViewerState + indexedAt: string + [k: string]: unknown +} + +export function isListView(v: unknown): v is ListView { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.graph.defs#listView' + ) +} + +export function validateListView(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.graph.defs#listView', v) +} + +export interface ListItemView { + subject: AppBskyActorDefs.ProfileView + [k: string]: unknown +} + +export function isListItemView(v: unknown): v is ListItemView { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.graph.defs#listItemView' + ) +} + +export function validateListItemView(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.graph.defs#listItemView', v) +} + +export type ListPurpose = 'app.bsky.graph.defs#modlist' | (string & {}) + +/** A list of actors to apply an aggregate moderation action (mute/block) on */ +export const MODLIST = 'app.bsky.graph.defs#modlist' + +export interface ListViewerState { + muted?: boolean + [k: string]: unknown +} + +export function isListViewerState(v: unknown): v is ListViewerState { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.graph.defs#listViewerState' + ) +} + +export function validateListViewerState(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.graph.defs#listViewerState', v) +} diff --git a/src/lexicon/types/app/bsky/graph/getList.ts b/src/lexicon/types/app/bsky/graph/getList.ts new file mode 100644 index 000000000..31bb029f5 --- /dev/null +++ b/src/lexicon/types/app/bsky/graph/getList.ts @@ -0,0 +1,46 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyGraphDefs from './defs' + +export interface QueryParams { + list: string + limit: number + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + list: AppBskyGraphDefs.ListView + items: AppBskyGraphDefs.ListItemView[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/app/bsky/graph/getListMutes.ts b/src/lexicon/types/app/bsky/graph/getListMutes.ts new file mode 100644 index 000000000..981f9cdb3 --- /dev/null +++ b/src/lexicon/types/app/bsky/graph/getListMutes.ts @@ -0,0 +1,44 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyGraphDefs from './defs' + +export interface QueryParams { + limit: number + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + lists: AppBskyGraphDefs.ListView[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/app/bsky/graph/getLists.ts b/src/lexicon/types/app/bsky/graph/getLists.ts new file mode 100644 index 000000000..9b4c06280 --- /dev/null +++ b/src/lexicon/types/app/bsky/graph/getLists.ts @@ -0,0 +1,45 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyGraphDefs from './defs' + +export interface QueryParams { + actor: string + limit: number + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + lists: AppBskyGraphDefs.ListView[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/app/bsky/graph/list.ts b/src/lexicon/types/app/bsky/graph/list.ts new file mode 100644 index 000000000..4304ca98b --- /dev/null +++ b/src/lexicon/types/app/bsky/graph/list.ts @@ -0,0 +1,32 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import * as AppBskyGraphDefs from './defs' +import * as AppBskyRichtextFacet from '../richtext/facet' + +export interface Record { + purpose: AppBskyGraphDefs.ListPurpose + name: string + description?: string + descriptionFacets?: AppBskyRichtextFacet.Main[] + avatar?: BlobRef + createdAt: string + [k: string]: unknown +} + +export function isRecord(v: unknown): v is Record { + return ( + isObj(v) && + hasProp(v, '$type') && + (v.$type === 'app.bsky.graph.list#main' || + v.$type === 'app.bsky.graph.list') + ) +} + +export function validateRecord(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.graph.list#main', v) +} diff --git a/src/lexicon/types/app/bsky/graph/listitem.ts b/src/lexicon/types/app/bsky/graph/listitem.ts new file mode 100644 index 000000000..69eff329e --- /dev/null +++ b/src/lexicon/types/app/bsky/graph/listitem.ts @@ -0,0 +1,27 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' + +export interface Record { + subject: string + list: string + createdAt: string + [k: string]: unknown +} + +export function isRecord(v: unknown): v is Record { + return ( + isObj(v) && + hasProp(v, '$type') && + (v.$type === 'app.bsky.graph.listitem#main' || + v.$type === 'app.bsky.graph.listitem') + ) +} + +export function validateRecord(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.graph.listitem#main', v) +} diff --git a/src/lexicon/types/app/bsky/graph/muteActorList.ts b/src/lexicon/types/app/bsky/graph/muteActorList.ts new file mode 100644 index 000000000..e099011b3 --- /dev/null +++ b/src/lexicon/types/app/bsky/graph/muteActorList.ts @@ -0,0 +1,35 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + list: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/app/bsky/graph/unmuteActorList.ts b/src/lexicon/types/app/bsky/graph/unmuteActorList.ts new file mode 100644 index 000000000..e099011b3 --- /dev/null +++ b/src/lexicon/types/app/bsky/graph/unmuteActorList.ts @@ -0,0 +1,35 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + list: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/com/atproto/admin/defs.ts b/src/lexicon/types/com/atproto/admin/defs.ts index f78afce41..38938d4b2 100644 --- a/src/lexicon/types/com/atproto/admin/defs.ts +++ b/src/lexicon/types/com/atproto/admin/defs.ts @@ -177,6 +177,7 @@ export interface RepoView { indexedAt: string moderation: Moderation invitedBy?: ComAtprotoServerDefs.InviteCode + invitesDisabled?: boolean [k: string]: unknown } @@ -202,6 +203,7 @@ export interface RepoViewDetail { labels?: ComAtprotoLabelDefs.Label[] invitedBy?: ComAtprotoServerDefs.InviteCode invites?: ComAtprotoServerDefs.InviteCode[] + invitesDisabled?: boolean [k: string]: unknown } diff --git a/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts b/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts new file mode 100644 index 000000000..fdba69e2e --- /dev/null +++ b/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts @@ -0,0 +1,35 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + account: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts b/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts new file mode 100644 index 000000000..fdba69e2e --- /dev/null +++ b/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts @@ -0,0 +1,35 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + account: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/com/atproto/admin/getModerationReports.ts b/src/lexicon/types/com/atproto/admin/getModerationReports.ts index f92f20760..8fc5ac887 100644 --- a/src/lexicon/types/com/atproto/admin/getModerationReports.ts +++ b/src/lexicon/types/com/atproto/admin/getModerationReports.ts @@ -12,6 +12,12 @@ import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { subject?: string resolved?: boolean + actionType?: + | 'com.atproto.admin.defs#takedown' + | 'com.atproto.admin.defs#flag' + | 'com.atproto.admin.defs#acknowledge' + | 'com.atproto.admin.defs#escalate' + | (string & {}) limit: number cursor?: string } diff --git a/src/lexicon/types/com/atproto/repo/rebaseRepo.ts b/src/lexicon/types/com/atproto/repo/rebaseRepo.ts new file mode 100644 index 000000000..b3dfe322f --- /dev/null +++ b/src/lexicon/types/com/atproto/repo/rebaseRepo.ts @@ -0,0 +1,39 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + /** The handle or DID of the repo. */ + repo: string + /** Compare and swap with the previous commit by cid. */ + swapCommit?: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string + error?: 'InvalidSwap' +} + +export type HandlerOutput = HandlerError | void +export type Handler = (ctx: { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +}) => Promise | HandlerOutput diff --git a/src/lexicon/types/com/atproto/server/createAccount.ts b/src/lexicon/types/com/atproto/server/createAccount.ts index 7e5ff93ac..4e212bfa0 100644 --- a/src/lexicon/types/com/atproto/server/createAccount.ts +++ b/src/lexicon/types/com/atproto/server/createAccount.ts @@ -13,6 +13,7 @@ export interface QueryParams {} export interface InputSchema { email: string handle: string + did?: string inviteCode?: string password: string recoveryKey?: string @@ -46,6 +47,8 @@ export interface HandlerError { | 'InvalidInviteCode' | 'HandleNotAvailable' | 'UnsupportedDomain' + | 'UnresolvableDid' + | 'IncompatibleDidDoc' } export type HandlerOutput = HandlerError | HandlerSuccess diff --git a/src/methods/describe-generator.ts b/src/methods/describe-generator.ts new file mode 100644 index 000000000..cbd87a848 --- /dev/null +++ b/src/methods/describe-generator.ts @@ -0,0 +1,23 @@ +import { Server } from '../lexicon' +import { AppContext } from '../config' +import algos from '../algos' +import { AtUri } from '@atproto/uri' + +export default function (server: Server, ctx: AppContext) { + server.app.bsky.feed.describeFeedGenerator(async () => { + const feeds = Object.keys(algos).map((shortname) => ({ + uri: AtUri.make( + ctx.cfg.publisherDid, + 'app.bsky.feed.generator', + shortname, + ).toString(), + })) + return { + encoding: 'application/json', + body: { + did: ctx.cfg.serviceDid, + feeds, + }, + } + }) +} diff --git a/src/methods/feed-generation.ts b/src/methods/feed-generation.ts new file mode 100644 index 000000000..0e114ec96 --- /dev/null +++ b/src/methods/feed-generation.ts @@ -0,0 +1,38 @@ +import { InvalidRequestError } from '@atproto/xrpc-server' +import { Server } from '../lexicon' +import { AppContext } from '../config' +import algos from '../algos' +import { validateAuth } from '../auth' +import { AtUri } from '@atproto/uri' + +export default function (server: Server, ctx: AppContext) { + server.app.bsky.feed.getFeedSkeleton(async ({ params, req }) => { + const feedUri = new AtUri(params.feed) + const algo = algos[feedUri.rkey] + if ( + feedUri.hostname !== ctx.cfg.publisherDid || + feedUri.collection !== 'app.bsky.feed.generator' || + !algo + ) { + throw new InvalidRequestError( + 'Unsupported algorithm', + 'UnsupportedAlgorithm', + ) + } + /** + * Example of how to check auth if giving user-specific results: + * + * const requesterDid = await validateAuth( + * req, + * ctx.cfg.serviceDid, + * ctx.didResolver, + * ) + */ + + const body = await algo(ctx, params) + return { + encoding: 'application/json', + body: body, + } + }) +} diff --git a/src/server.ts b/src/server.ts index f86fd5576..ddbd2d2f0 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,16 +1,14 @@ import http from 'http' import events from 'events' import express from 'express' +import { DidResolver, MemoryCache } from '@atproto/did-resolver' import { createServer } from './lexicon' -import feedGeneration from './feed-generation' -import { createDb, Database } from './db' +import feedGeneration from './methods/feed-generation' +import describeGenerator from './methods/describe-generator' +import { createDb, Database, migrateToLatest } from './db' import { FirehoseSubscription } from './subscription' - -export type Config = { - port: number - sqliteLocation: string - subscriptionEndpoint: string -} +import { AppContext, Config } from './config' +import wellKnown from './well-known' export class FeedGenerator { public app: express.Application @@ -31,17 +29,17 @@ export class FeedGenerator { this.cfg = cfg } - static create(config?: Partial) { - const cfg = { - port: config?.port ?? 3000, - sqliteLocation: config?.sqliteLocation ?? 'test.sqlite', - subscriptionEndpoint: - config?.subscriptionEndpoint ?? 'https://bsky.social', - } + static create(cfg: Config) { const app = express() const db = createDb(cfg.sqliteLocation) const firehose = new FirehoseSubscription(db, cfg.subscriptionEndpoint) + const didCache = new MemoryCache() + const didResolver = new DidResolver( + { plcUrl: 'https://plc.directory' }, + didCache, + ) + const server = createServer({ validateResponse: true, payload: { @@ -50,19 +48,25 @@ export class FeedGenerator { blobLimit: 5 * 1024 * 1024, // 5mb }, }) - feedGeneration(server, db) + const ctx: AppContext = { + db, + didResolver, + cfg, + } + feedGeneration(server, ctx) + describeGenerator(server, ctx) app.use(server.xrpc.router) + app.use(wellKnown(ctx)) return new FeedGenerator(app, db, firehose, cfg) } async start(): Promise { - await this.firehose.run() - const server = this.app.listen(this.cfg.port) - server.keepAliveTimeout = 90000 - this.server = server - await events.once(server, 'listening') - return server + await migrateToLatest(this.db) + this.firehose.run(this.cfg.subscriptionReconnectDelay) + this.server = this.app.listen(this.cfg.port, this.cfg.listenhost) + await events.once(this.server, 'listening') + return this.server } } diff --git a/src/subscription.ts b/src/subscription.ts index 943b8d1cd..b3a141e8d 100644 --- a/src/subscription.ts +++ b/src/subscription.ts @@ -1,60 +1,50 @@ -import { ids, lexicons } from './lexicon/lexicons' -import { Record as PostRecord } from './lexicon/types/app/bsky/feed/post' import { OutputSchema as RepoEvent, isCommit, } from './lexicon/types/com/atproto/sync/subscribeRepos' -import { - FirehoseSubscriptionBase, - getPostOperations, -} from './util/subscription' +import { FirehoseSubscriptionBase, getOpsByType } from './util/subscription' export class FirehoseSubscription extends FirehoseSubscriptionBase { async handleEvent(evt: RepoEvent) { if (!isCommit(evt)) return - const postOps = await getPostOperations(evt) - const postsToDelete = postOps.deletes.map((del) => del.uri) - const postsToCreate = postOps.creates + const ops = await getOpsByType(evt) + + // This logs the text of every post off the firehose. + // Just for fun :) + // Delete before actually using + for (const post of ops.posts.creates) { + console.log(post.record.text) + } + + const postsToDelete = ops.posts.deletes.map((del) => del.uri) + const postsToCreate = ops.posts.creates .filter((create) => { // only alf-related posts - return ( - isPost(create.record) && - create.record.text.toLowerCase().includes('alf') - ) + return create.record.text.toLowerCase().includes('alf') }) .map((create) => { // map alf-related posts to a db row - const record = isPost(create.record) ? create.record : null return { uri: create.uri, cid: create.cid, - replyParent: record?.reply?.parent.uri ?? null, - replyRoot: record?.reply?.root.uri ?? null, + replyParent: create.record?.reply?.parent.uri ?? null, + replyRoot: create.record?.reply?.root.uri ?? null, indexedAt: new Date().toISOString(), } }) if (postsToDelete.length > 0) { await this.db - .deleteFrom('posts') + .deleteFrom('post') .where('uri', 'in', postsToDelete) .execute() } if (postsToCreate.length > 0) { await this.db - .insertInto('posts') + .insertInto('post') .values(postsToCreate) .onConflict((oc) => oc.doNothing()) .execute() } } } - -export const isPost = (obj: unknown): obj is PostRecord => { - try { - lexicons.assertValidRecord(ids.AppBskyFeedPost, obj) - return true - } catch (err) { - return false - } -} diff --git a/src/util/subscription.ts b/src/util/subscription.ts index f3a892cb3..87ab11626 100644 --- a/src/util/subscription.ts +++ b/src/util/subscription.ts @@ -1,12 +1,17 @@ import { Subscription } from '@atproto/xrpc-server' +import { cborToLexRecord, readCar } from '@atproto/repo' +import { BlobRef } from '@atproto/lexicon' import { ids, lexicons } from '../lexicon/lexicons' +import { Record as PostRecord } from '../lexicon/types/app/bsky/feed/post' +import { Record as RepostRecord } from '../lexicon/types/app/bsky/feed/repost' +import { Record as LikeRecord } from '../lexicon/types/app/bsky/feed/like' +import { Record as FollowRecord } from '../lexicon/types/app/bsky/graph/follow' import { Commit, OutputSchema as RepoEvent, isCommit, } from '../lexicon/types/com/atproto/sync/subscribeRepos' import { Database } from '../db' -import { cborToLexRecord, readCar } from '@atproto/repo' export abstract class FirehoseSubscriptionBase { public sub: Subscription @@ -31,32 +36,25 @@ export abstract class FirehoseSubscriptionBase { abstract handleEvent(evt: RepoEvent): Promise - async run() { - await this.ensureCursor() - for await (const evt of this.sub) { - try { - await this.handleEvent(evt) - } catch (err) { - console.error('repo subscription could not handle message', err) - } - // update stored cursor every 20 events or so - if (isCommit(evt) && evt.seq % 20 === 0) { - await this.updateCursor(evt.seq) + async run(subscriptionReconnectDelay: number) { + try { + for await (const evt of this.sub) { + try { + await this.handleEvent(evt) + } catch (err) { + console.error('repo subscription could not handle message', err) + } + // update stored cursor every 20 events or so + if (isCommit(evt) && evt.seq % 20 === 0) { + await this.updateCursor(evt.seq) + } } + } catch (err) { + console.error('repo subscription errored', err) + setTimeout(() => this.run(subscriptionReconnectDelay), subscriptionReconnectDelay) } } - async ensureCursor() { - await this.db - .insertInto('sub_state') - .values({ - service: this.service, - cursor: 0, - }) - .onConflict((oc) => oc.doNothing()) - .execute() - } - async updateCursor(cursor: number) { await this.db .updateTable('sub_state') @@ -65,60 +63,128 @@ export abstract class FirehoseSubscriptionBase { .execute() } - async getCursor(): Promise<{ cursor: number }> { + async getCursor(): Promise<{ cursor?: number }> { const res = await this.db .selectFrom('sub_state') .selectAll() .where('service', '=', this.service) .executeTakeFirst() - return res ? { cursor: res.cursor } : { cursor: 0 } + return res ? { cursor: res.cursor } : {} } } -export const getPostOperations = async (evt: Commit): Promise => { - const ops: Operations = { creates: [], deletes: [] } - const postOps = evt.ops.filter( - (op) => op.path.split('/')[1] === ids.AppBskyFeedPost, - ) - - if (postOps.length < 1) return ops - +export const getOpsByType = async (evt: Commit): Promise => { const car = await readCar(evt.blocks) + const opsByType: OperationsByType = { + posts: { creates: [], deletes: [] }, + reposts: { creates: [], deletes: [] }, + likes: { creates: [], deletes: [] }, + follows: { creates: [], deletes: [] }, + } - for (const op of postOps) { - // updates not supported yet - if (op.action === 'update') continue + for (const op of evt.ops) { const uri = `at://${evt.repo}/${op.path}` - if (op.action === 'delete') { - ops.deletes.push({ uri }) - } else if (op.action === 'create') { + const [collection] = op.path.split('/') + + if (op.action === 'update') continue // updates not supported yet + + if (op.action === 'create') { if (!op.cid) continue - const postBytes = await car.blocks.get(op.cid) - if (!postBytes) continue - ops.creates.push({ - uri, - cid: op.cid.toString(), - author: evt.repo, - record: cborToLexRecord(postBytes), - }) + const recordBytes = car.blocks.get(op.cid) + if (!recordBytes) continue + const record = cborToLexRecord(recordBytes) + const create = { uri, cid: op.cid.toString(), author: evt.repo } + if (collection === ids.AppBskyFeedPost && isPost(record)) { + opsByType.posts.creates.push({ record, ...create }) + } else if (collection === ids.AppBskyFeedRepost && isRepost(record)) { + opsByType.reposts.creates.push({ record, ...create }) + } else if (collection === ids.AppBskyFeedLike && isLike(record)) { + opsByType.likes.creates.push({ record, ...create }) + } else if (collection === ids.AppBskyGraphFollow && isFollow(record)) { + opsByType.follows.creates.push({ record, ...create }) + } + } + + if (op.action === 'delete') { + if (collection === ids.AppBskyFeedPost) { + opsByType.posts.deletes.push({ uri }) + } else if (collection === ids.AppBskyFeedRepost) { + opsByType.reposts.deletes.push({ uri }) + } else if (collection === ids.AppBskyFeedLike) { + opsByType.likes.deletes.push({ uri }) + } else if (collection === ids.AppBskyGraphFollow) { + opsByType.follows.deletes.push({ uri }) + } } } - return ops + return opsByType +} + +type OperationsByType = { + posts: Operations + reposts: Operations + likes: Operations + follows: Operations +} + +type Operations> = { + creates: CreateOp[] + deletes: DeleteOp[] } -type CreateOp = { +type CreateOp = { uri: string cid: string author: string - record: Record + record: T } type DeleteOp = { uri: string } -type Operations = { - creates: CreateOp[] - deletes: DeleteOp[] +export const isPost = (obj: unknown): obj is PostRecord => { + return isType(obj, ids.AppBskyFeedPost) +} + +export const isRepost = (obj: unknown): obj is RepostRecord => { + return isType(obj, ids.AppBskyFeedRepost) +} + +export const isLike = (obj: unknown): obj is LikeRecord => { + return isType(obj, ids.AppBskyFeedLike) +} + +export const isFollow = (obj: unknown): obj is FollowRecord => { + return isType(obj, ids.AppBskyGraphFollow) +} + +const isType = (obj: unknown, nsid: string) => { + try { + lexicons.assertValidRecord(nsid, fixBlobRefs(obj)) + return true + } catch (err) { + return false + } +} + +// @TODO right now record validation fails on BlobRefs +// simply because multiple packages have their own copy +// of the BlobRef class, causing instanceof checks to fail. +// This is a temporary solution. +const fixBlobRefs = (obj: unknown): unknown => { + if (Array.isArray(obj)) { + return obj.map(fixBlobRefs) + } + if (obj && typeof obj === 'object') { + if (obj.constructor.name === 'BlobRef') { + const blob = obj as BlobRef + return new BlobRef(blob.ref, blob.mimeType, blob.size, blob.original) + } + return Object.entries(obj).reduce((acc, [key, val]) => { + return Object.assign(acc, { [key]: fixBlobRefs(val) }) + }, {} as Record) + } + return obj } diff --git a/src/well-known.ts b/src/well-known.ts new file mode 100644 index 000000000..11c230464 --- /dev/null +++ b/src/well-known.ts @@ -0,0 +1,26 @@ +import express from 'express' +import { AppContext } from './config' + +const makeRouter = (ctx: AppContext) => { + const router = express.Router() + + router.get('/.well-known/did.json', (_req, res) => { + if (!ctx.cfg.serviceDid.endsWith(ctx.cfg.hostname)) { + return res.sendStatus(404) + } + res.json({ + '@context': ['https://www.w3.org/ns/did/v1'], + id: ctx.cfg.serviceDid, + service: [ + { + id: '#bsky_fg', + type: 'BskyFeedGenerator', + serviceEndpoint: `https://${ctx.cfg.hostname}`, + }, + ], + }) + }) + + return router +} +export default makeRouter diff --git a/test.sqlite b/test.sqlite deleted file mode 100644 index e69de29bb..000000000 diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..0b4f7cc68 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ + +{ + "compilerOptions": { + "lib": [ + "ESNext", + ], + "outDir": "dist", + "module": "CommonJS", + "target": "ES6", + "esModuleInterop": true, + "moduleResolution": "node", + "alwaysStrict": true, + "allowUnreachableCode": false, + "strictNullChecks": true, + "skipLibCheck": true + }, + "include": ["./src/**/*.ts"], + "exclude": [ + "node_modules" + ] +} diff --git a/yarn.lock b/yarn.lock index b2e8e281b..32c0bde72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,9 +2,20 @@ # yarn lockfile v1 +"@atproto/api@^0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.3.7.tgz#5cc4b0ccc5c6690eb0e5a3ae138a84ce20697e2f" + integrity sha512-JHN3rHNGro4AaJWU64hsmpTUzd2+FbfMBiDkqyBmoKtj972ueBJeH8tz6WdnPcsIRfCj1kRthKFj2yJwgt6aSQ== + dependencies: + "@atproto/common-web" "*" + "@atproto/uri" "*" + "@atproto/xrpc" "*" + tlds "^1.234.0" + typed-emitter "^2.1.0" + "@atproto/common-web@*": version "0.1.0" - resolved "https://registry.yarnpkg.com/@atproto/common-web/-/common-web-0.1.0.tgz#5529fa66f9533aa00cfd13f0a25757df7b26bd3d" + resolved "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.1.0.tgz" integrity sha512-qD6xF60hvH+cP++fk/mt+0S9cxs94KsK+rNWypNlgnlp7r9By4ltXwtDSR/DNTA8mwDeularUno4VbTd2IWIzA== dependencies: multiformats "^9.6.4" @@ -13,7 +24,7 @@ "@atproto/common@*": version "0.2.0" - resolved "https://registry.yarnpkg.com/@atproto/common/-/common-0.2.0.tgz#e74502edf636f30e332f516dcb96f7342b71ff1b" + resolved "https://registry.npmjs.org/@atproto/common/-/common-0.2.0.tgz" integrity sha512-PVYSC30pyonz2MOxuBLk27uGdwyZQ42gJfCA/NE9jLeuenVDmZnVrK5WqJ7eGg+F88rZj7NcGfRsZdP0GMykEQ== dependencies: "@atproto/common-web" "*" @@ -24,7 +35,7 @@ "@atproto/crypto@*": version "0.1.1" - resolved "https://registry.yarnpkg.com/@atproto/crypto/-/crypto-0.1.1.tgz#54afad2124c3867091e4d9b271f22d375fcfdf9e" + resolved "https://registry.npmjs.org/@atproto/crypto/-/crypto-0.1.1.tgz" integrity sha512-/7Ntn55dRZPtCnOd6dVo1IvZzpVut6YTAkZ8iFry9JW29l7ZeNkJd+NTnmWRz3aGQody10jngb4SNxQNi/f3+A== dependencies: "@noble/secp256k1" "^1.7.0" @@ -33,26 +44,26 @@ one-webcrypto "^1.0.3" uint8arrays "3.0.0" -"@atproto/did-resolver@*": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@atproto/did-resolver/-/did-resolver-0.0.1.tgz#e54c1b7fddff2cd6adf87c044b4a3b6f00d5eff7" - integrity sha512-sdva3+nydMaWXwHJED558UZdVZuajfC2CHcsIZz0pQybicm3VI+khkf42ClZeOhf4Bwa4V4SOaaAqwyf86bDew== +"@atproto/did-resolver@*", "@atproto/did-resolver@^0.1.0": + version "0.1.0" + resolved "https://registry.npmjs.org/@atproto/did-resolver/-/did-resolver-0.1.0.tgz" + integrity sha512-ztljyMMCqXvJSi/Qqa2zEQFvOm1AUUR7Bybr3cM1BCddbhW46gk6/g8BgdZeDt2sMBdye37qTctR9O/FjhigvQ== dependencies: - "@atproto/common" "*" + "@atproto/common-web" "*" "@atproto/crypto" "*" - axios "^0.24.0" - did-resolver "^4.0.0" + axios "^0.27.2" + zod "^3.14.2" "@atproto/identifier@*": version "0.1.0" - resolved "https://registry.yarnpkg.com/@atproto/identifier/-/identifier-0.1.0.tgz#6b600c8a3da08d9a7d5eab076f8b7064457dde75" + resolved "https://registry.npmjs.org/@atproto/identifier/-/identifier-0.1.0.tgz" integrity sha512-3LV7+4E6S0k8Rru7NBkyDF6Zf6NHVUXVS9d4l9fiXWMC49ghZMjq0vPmz80xjG1rRuFdJFbpRf4ApFciGxLIyQ== dependencies: "@atproto/common-web" "*" -"@atproto/lexicon@*": +"@atproto/lexicon@*", "@atproto/lexicon@^0.1.0": version "0.1.0" - resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.1.0.tgz#e7784cc868c734314d5bf9af83487aba7ccae0b3" + resolved "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.1.0.tgz" integrity sha512-Iy+gV9w42xLhrZrmcbZh7VFoHjXuzWvecGHIfz44owNjjv7aE/d2P5BbOX/XicSkmQ8Qkpg0BqwYDD1XBVS+DQ== dependencies: "@atproto/common-web" "*" @@ -65,12 +76,12 @@ "@atproto/nsid@*": version "0.0.1" - resolved "https://registry.yarnpkg.com/@atproto/nsid/-/nsid-0.0.1.tgz#0cdc00cefe8f0b1385f352b9f57b3ad37fff09a4" + resolved "https://registry.npmjs.org/@atproto/nsid/-/nsid-0.0.1.tgz" integrity sha512-t5M6/CzWBVYoBbIvfKDpqPj/+ZmyoK9ydZSStcTXosJ27XXwOPhz0VDUGKK2SM9G5Y7TPes8S5KTAU0UdVYFCw== "@atproto/repo@^0.1.0": version "0.1.0" - resolved "https://registry.yarnpkg.com/@atproto/repo/-/repo-0.1.0.tgz#8c546af16c30fe5ba4c883ac73b68be9d7eca273" + resolved "https://registry.npmjs.org/@atproto/repo/-/repo-0.1.0.tgz" integrity sha512-O4qs5WfSjEFvUtpOTB4n9cLcK6YP/w/ly6Qxc3S8IFevLGYX58NPPr5zlg3dxs64uLKbWWjzhQM7JAqO44MEKw== dependencies: "@atproto/common" "*" @@ -86,18 +97,19 @@ "@atproto/uri@*", "@atproto/uri@^0.0.2": version "0.0.2" - resolved "https://registry.yarnpkg.com/@atproto/uri/-/uri-0.0.2.tgz#c6d3788e6f12d66ba72690d2d70fe6c291b4acfb" + resolved "https://registry.npmjs.org/@atproto/uri/-/uri-0.0.2.tgz" integrity sha512-/6otLZF7BLpT9suSdHuXLbL12nINcWPsLmcOI+dctqovWUjH+XIRVNXDQgBYSrPVetxMiknuEwWelmnA33AEXg== dependencies: "@atproto/identifier" "*" "@atproto/nsid" "*" -"@atproto/xrpc-server@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@atproto/xrpc-server/-/xrpc-server-0.1.0.tgz#2dd3172bb35fbfefb98c3d727d29be8eca5c3d9b" - integrity sha512-I7EjhnLUrlqQKTe2jDEnyAaOTvj26pg9NRjTXflbIOqCOkh+K9+5ztGSI0djF7TSQ7pegXroj3qRnmpVVCBr7Q== +"@atproto/xrpc-server@^0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@atproto/xrpc-server/-/xrpc-server-0.2.0.tgz" + integrity sha512-sCJuVUIb1tDIlKCFwHPRHbAgEy0HYGlQ7XhpNqMRKXECh8Z+DRICEne3gLDVaXhyNaC/N7OjHcsyuofDDbuGFQ== dependencies: "@atproto/common" "*" + "@atproto/crypto" "*" "@atproto/lexicon" "*" cbor-x "^1.5.1" express "^4.17.2" @@ -107,9 +119,17 @@ ws "^8.12.0" zod "^3.14.2" +"@atproto/xrpc@*": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.1.0.tgz#798569095538ac060475ae51f1b4c071ff8776d6" + integrity sha512-LhBeZkQwPezjEtricGYnG62udFglOqlnmMSS0KyWgEAPi4KMp4H2F4jNoXcf5NPtZ9S4N4hJaErHX4PJYv2lfA== + dependencies: + "@atproto/lexicon" "*" + zod "^3.14.2" + "@cbor-extract/cbor-extract-darwin-arm64@2.1.1": version "2.1.1" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.1.1.tgz#5721f6dd3feae0b96d23122853ce977e0671b7a6" + resolved "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.1.1.tgz" integrity sha512-blVBy5MXz6m36Vx0DfLd7PChOQKEs8lK2bD1WJn/vVgG4FXZiZmZb2GECHFvVPA5T7OnODd9xZiL3nMCv6QUhA== "@cbor-extract/cbor-extract-darwin-x64@2.1.1": @@ -139,14 +159,14 @@ "@cspotcode/source-map-support@^0.8.0": version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: "@jridgewell/trace-mapping" "0.3.9" "@ipld/car@^3.2.3": version "3.2.4" - resolved "https://registry.yarnpkg.com/@ipld/car/-/car-3.2.4.tgz#115951ba2255ec51d865773a074e422c169fb01c" + resolved "https://registry.npmjs.org/@ipld/car/-/car-3.2.4.tgz" integrity sha512-rezKd+jk8AsTGOoJKqzfjLJ3WVft7NZNH95f0pfPbicROvzTyvHCNy567HzSUd6gRXZ9im29z5ZEv9Hw49jSYw== dependencies: "@ipld/dag-cbor" "^7.0.0" @@ -155,7 +175,7 @@ "@ipld/dag-cbor@^7.0.0", "@ipld/dag-cbor@^7.0.3": version "7.0.3" - resolved "https://registry.yarnpkg.com/@ipld/dag-cbor/-/dag-cbor-7.0.3.tgz#aa31b28afb11a807c3d627828a344e5521ac4a1e" + resolved "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-7.0.3.tgz" integrity sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA== dependencies: cborg "^1.6.0" @@ -163,17 +183,17 @@ "@jridgewell/resolve-uri@^3.0.3": version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz" integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" @@ -181,39 +201,39 @@ "@noble/secp256k1@^1.7.0": version "1.7.1" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" + resolved "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz" integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== "@tsconfig/node10@^1.0.7": version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== "@tsconfig/node12@^1.0.7": version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== "@tsconfig/node14@^1.0.0": version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz" integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== "@types/better-sqlite3@^7.6.4": version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/better-sqlite3/-/better-sqlite3-7.6.4.tgz#102462611e67aadf950d3ccca10292de91e6f35b" + resolved "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.4.tgz" integrity sha512-dzrRZCYPXIXfSR1/surNbJ/grU3scTaygS0OMzjlGf71i9sc2fGyHPXXiXmEvNIoE0cGwsanEFMVJxPXmco9Eg== dependencies: "@types/node" "*" "@types/body-parser@*": version "1.19.2" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz" integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== dependencies: "@types/connect" "*" @@ -221,14 +241,14 @@ "@types/connect@*": version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz" integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== dependencies: "@types/node" "*" "@types/express-serve-static-core@^4.17.33": version "4.17.34" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz#c119e85b75215178bc127de588e93100698ab4cc" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz" integrity sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w== dependencies: "@types/node" "*" @@ -238,7 +258,7 @@ "@types/express@^4.17.17": version "4.17.17" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" + resolved "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz" integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== dependencies: "@types/body-parser" "*" @@ -246,34 +266,29 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/mime@*": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" - integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== - -"@types/mime@^1": +"@types/mime@*", "@types/mime@^1": version "1.3.2" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz" integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== -"@types/node@*", "@types/node@^20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.1.1.tgz#afc492e8dbe7f672dd3a13674823522b467a45ad" - integrity sha512-uKBEevTNb+l6/aCQaKVnUModfEMjAl98lw2Si9P5y4hLu9tm6AlX2ZIoXZX6Wh9lJueYPrGPKk5WMCNHg/u6/A== +"@types/node@*", "@types/node@^20.1.2": + version "20.1.2" + resolved "https://registry.npmjs.org/@types/node/-/node-20.1.2.tgz" + integrity sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g== "@types/qs@*": version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz" integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== "@types/range-parser@*": version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== "@types/send@*": version "0.17.1" - resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" + resolved "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz" integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== dependencies: "@types/mime" "^1" @@ -281,7 +296,7 @@ "@types/serve-static@*": version "1.15.1" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.1.tgz#86b1753f0be4f9a1bee68d459fcda5be4ea52b5d" + resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz" integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ== dependencies: "@types/mime" "*" @@ -289,14 +304,14 @@ abort-controller@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== dependencies: event-target-shim "^5.0.0" accepts@~1.3.8: version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: mime-types "~2.1.34" @@ -304,44 +319,50 @@ accepts@~1.3.8: acorn-walk@^8.1.1: version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== acorn@^8.4.1: version "8.8.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== arg@^4.1.0: version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + atomic-sleep@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + resolved "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== -axios@^0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6" - integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== dependencies: - follow-redirects "^1.14.4" + follow-redirects "^1.14.9" + form-data "^4.0.0" base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== better-sqlite3@^8.3.0: version "8.3.0" - resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-8.3.0.tgz#3873ddfd9f2af90b628657e8ff221786c93d1984" + resolved "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-8.3.0.tgz" integrity sha512-JTmvBZL/JLTc+3Msbvq6gK6elbU9/wVMqiudplHrVJpr7sVMR9KJrNhZAbW+RhXKlpMcuEhYkdcHa3TXKNXQ1w== dependencies: bindings "^1.5.0" @@ -349,19 +370,19 @@ better-sqlite3@^8.3.0: big-integer@^1.6.51: version "1.6.51" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz" integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== bindings@^1.5.0: version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== dependencies: file-uri-to-path "1.0.0" bl@^4.0.3: version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== dependencies: buffer "^5.5.0" @@ -370,7 +391,7 @@ bl@^4.0.3: body-parser@1.20.1: version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz" integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== dependencies: bytes "3.1.2" @@ -388,7 +409,7 @@ body-parser@1.20.1: buffer@^5.5.0: version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: base64-js "^1.3.1" @@ -396,7 +417,7 @@ buffer@^5.5.0: buffer@^6.0.3: version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== dependencies: base64-js "^1.3.1" @@ -404,12 +425,12 @@ buffer@^6.0.3: bytes@3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== call-bind@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== dependencies: function-bind "^1.1.1" @@ -417,7 +438,7 @@ call-bind@^1.0.0: cbor-extract@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/cbor-extract/-/cbor-extract-2.1.1.tgz#f154b31529fdb6b7c70fb3ca448f44eda96a1b42" + resolved "https://registry.npmjs.org/cbor-extract/-/cbor-extract-2.1.1.tgz" integrity sha512-1UX977+L+zOJHsp0mWFG13GLwO6ucKgSmSW6JTl8B9GUvACvHeIVpFqhU92299Z6PfD09aTXDell5p+lp1rUFA== dependencies: node-gyp-build-optional-packages "5.0.3" @@ -431,137 +452,149 @@ cbor-extract@^2.1.1: cbor-x@^1.5.1: version "1.5.2" - resolved "https://registry.yarnpkg.com/cbor-x/-/cbor-x-1.5.2.tgz#ceabc48bda06185de1f3a078bb4a793e6e222de5" + resolved "https://registry.npmjs.org/cbor-x/-/cbor-x-1.5.2.tgz" integrity sha512-JArE6xcgj3eo13fpnShO42QFBUuXP2uG12RLeF2Nb+dJcETFYxkUa27gXQrRYp67Ahtaxyfbg+ihc62XTyQqsQ== optionalDependencies: cbor-extract "^2.1.1" cborg@^1.6.0: version "1.10.1" - resolved "https://registry.yarnpkg.com/cborg/-/cborg-1.10.1.tgz#24cfe52c69ec0f66f95e23dc57f2086954c8d718" + resolved "https://registry.npmjs.org/cborg/-/cborg-1.10.1.tgz" integrity sha512-et6Qm8MOUY2kCWa5GKk2MlBVoPjHv0hQBmlzI/Z7+5V3VJCeIkGehIB3vWknNsm2kOkAIs6wEKJFJo8luWQQ/w== chownr@^1.1.1: version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + content-disposition@0.5.4: version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== dependencies: safe-buffer "5.2.1" content-type@~1.0.4: version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== create-require@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== debug@2.6.9: version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" decompress-response@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz" integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== dependencies: mimic-response "^3.1.0" deep-extend@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + depd@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== destroy@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== detect-libc@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz" integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== -did-resolver@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/did-resolver/-/did-resolver-4.1.0.tgz#740852083c4fd5bf9729d528eca5d105aff45eb6" - integrity sha512-S6fWHvCXkZg2IhS4RcVHxwuyVejPR7c+a4Go0xbQ9ps5kILa8viiYQgrM4gfTyeTjJ0ekgJH9gk/BawTpmkbZA== - diff@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +dotenv@^16.0.3: + version "16.0.3" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz" + integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== + ee-first@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== encodeurl@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== etag@~1.8.1: version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== event-target-shim@^5.0.0: version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== events@^3.3.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== expand-template@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== express@^4.17.2, express@^4.18.2: version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz" integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== dependencies: accepts "~1.3.8" @@ -598,17 +631,17 @@ express@^4.17.2, express@^4.18.2: fast-redact@^3.1.1: version "3.1.2" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.2.tgz#d58e69e9084ce9fa4c1a6fa98a3e1ecf5d7839aa" + resolved "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.2.tgz" integrity sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw== file-uri-to-path@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== finalhandler@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== dependencies: debug "2.6.9" @@ -619,34 +652,43 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" -follow-redirects@^1.14.4: +follow-redirects@^1.14.9: version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + forwarded@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fresh@0.5.2: version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== fs-constants@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== function-bind@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== get-intrinsic@^1.0.2: version "1.2.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz" integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== dependencies: function-bind "^1.1.1" @@ -655,24 +697,24 @@ get-intrinsic@^1.0.2: github-from-package@0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== has-symbols@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== has@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" http-errors@2.0.0, http-errors@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: depd "2.0.0" @@ -683,179 +725,179 @@ http-errors@2.0.0, http-errors@^2.0.0: iconv-lite@0.4.24: version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== ini@~1.3.0: version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== ipaddr.js@1.9.1: version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== iso-datestring-validator@^2.2.2: version "2.2.2" - resolved "https://registry.yarnpkg.com/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz#2daa80d2900b7a954f9f731d42f96ee0c19a6895" + resolved "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz" integrity sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA== kysely@^0.22.0: version "0.22.0" - resolved "https://registry.yarnpkg.com/kysely/-/kysely-0.22.0.tgz#8aac53942da3cadc604d7d154a746d983fe8f7b9" + resolved "https://registry.npmjs.org/kysely/-/kysely-0.22.0.tgz" integrity sha512-ZE3qWtnqLOalodzfK5QUEcm7AEulhxsPNuKaGFsC3XiqO92vMLm+mAHk/NnbSIOtC4RmGm0nsv700i8KDp1gfQ== lru-cache@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" make-error@^1.1.1: version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== media-typer@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== merge-descriptors@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== methods@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== mime-db@1.52.0: version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" mime@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mimic-response@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== minimist@^1.2.0, minimist@^1.2.3: version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== ms@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== ms@2.1.3: version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multiformats@^9.4.2, multiformats@^9.5.4, multiformats@^9.6.4: +multiformats@^9.4.2, multiformats@^9.5.4, multiformats@^9.6.4, multiformats@^9.9.0: version "9.9.0" - resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" + resolved "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz" integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg== napi-build-utils@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz" integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== negotiator@0.6.3: version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== node-abi@^3.3.0: version "3.40.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.40.0.tgz#51d8ed44534f70ff1357dfbc3a89717b1ceac1b4" + resolved "https://registry.npmjs.org/node-abi/-/node-abi-3.40.0.tgz" integrity sha512-zNy02qivjjRosswoYmPi8hIKJRr8MpQyeKT6qlcq/OnOgA3Rhoae+IYOqsM9V5+JnHWmxKnWOT2GxvtqdtOCXA== dependencies: semver "^7.3.5" node-gyp-build-optional-packages@5.0.3: version "5.0.3" - resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" + resolved "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz" integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA== object-inspect@^1.9.0: version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== on-exit-leak-free@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz#5c703c968f7e7f851885f6459bf8a8a57edc9cc4" + resolved "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz" integrity sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w== on-finished@2.4.1: version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== dependencies: ee-first "1.1.1" once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" one-webcrypto@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/one-webcrypto/-/one-webcrypto-1.0.3.tgz#f951243cde29b79b6745ad14966fc598a609997c" + resolved "https://registry.npmjs.org/one-webcrypto/-/one-webcrypto-1.0.3.tgz" integrity sha512-fu9ywBVBPx0gS9K0etIROTiCkvI5S1TDjFsYFb3rC1ewFxeOqsbzq7aIMBHsYfrTHBcGXJaONXXjTl8B01cW1Q== parseurl@~1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== path-to-regexp@0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== pino-abstract-transport@v1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz#cc0d6955fffcadb91b7b49ef220a6cc111d48bb3" + resolved "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz" integrity sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA== dependencies: readable-stream "^4.0.0" @@ -863,12 +905,12 @@ pino-abstract-transport@v1.0.0: pino-std-serializers@^6.0.0: version "6.2.1" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-6.2.1.tgz#369f4ae2a19eb6d769ddf2c88a2164b76879a284" + resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.1.tgz" integrity sha512-wHuWB+CvSVb2XqXM0W/WOYUkVSPbiJb9S5fNB7TBhd8s892Xq910bRxwHtC4l71hgztObTjXL6ZheZXFjhDrDQ== pino@^8.6.1: version "8.14.1" - resolved "https://registry.yarnpkg.com/pino/-/pino-8.14.1.tgz#bb38dcda8b500dd90c1193b6c9171eb777a47ac8" + resolved "https://registry.npmjs.org/pino/-/pino-8.14.1.tgz" integrity sha512-8LYNv7BKWXSfS+k6oEc6occy5La+q2sPwU3q2ljTX5AZk7v+5kND2o5W794FyRaqha6DJajmkNRsWtPpFyMUdw== dependencies: atomic-sleep "^1.0.0" @@ -885,7 +927,7 @@ pino@^8.6.1: prebuild-install@^7.1.0: version "7.1.1" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" + resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz" integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw== dependencies: detect-libc "^2.0.0" @@ -903,17 +945,17 @@ prebuild-install@^7.1.0: process-warning@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-2.2.0.tgz#008ec76b579820a8e5c35d81960525ca64feb626" + resolved "https://registry.npmjs.org/process-warning/-/process-warning-2.2.0.tgz" integrity sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg== process@^0.11.10: version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== proxy-addr@~2.0.7: version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: forwarded "0.2.0" @@ -921,7 +963,7 @@ proxy-addr@~2.0.7: pump@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== dependencies: end-of-stream "^1.1.0" @@ -929,24 +971,24 @@ pump@^3.0.0: qs@6.11.0: version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" quick-format-unescaped@^4.0.3: version "4.0.4" - resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" + resolved "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz" integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== range-parser@~1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== raw-body@2.5.1: version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz" integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== dependencies: bytes "3.1.2" @@ -956,7 +998,7 @@ raw-body@2.5.1: rc@^1.2.7: version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" @@ -966,7 +1008,7 @@ rc@^1.2.7: readable-stream@^3.1.1, readable-stream@^3.4.0: version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" @@ -975,7 +1017,7 @@ readable-stream@^3.1.1, readable-stream@^3.4.0: readable-stream@^4.0.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.4.0.tgz#55ce132d60a988c460d75c631e9ccf6a7229b468" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.0.tgz" integrity sha512-kDMOq0qLtxV9f/SQv522h8cxZBqNZXuXNyjyezmfAAuribMyVXziljpQ/uQhfE1XLg2/TLTW2DsnoE4VAi/krg== dependencies: abort-controller "^3.0.0" @@ -985,34 +1027,41 @@ readable-stream@^4.0.0: real-require@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" + resolved "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz" integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== +rxjs@^7.5.2: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== safe-stable-stringify@^2.3.1: version "2.4.3" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" + resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz" integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== "safer-buffer@>= 2.1.2 < 3": version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== semver@^7.3.5: version "7.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" + resolved "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz" integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== dependencies: lru-cache "^6.0.0" send@0.18.0: version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== dependencies: debug "2.6.9" @@ -1031,7 +1080,7 @@ send@0.18.0: serve-static@1.15.0: version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== dependencies: encodeurl "~1.0.2" @@ -1041,12 +1090,12 @@ serve-static@1.15.0: setprototypeof@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== side-channel@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== dependencies: call-bind "^1.0.0" @@ -1055,12 +1104,12 @@ side-channel@^1.0.4: simple-concat@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== simple-get@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + resolved "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz" integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== dependencies: decompress-response "^6.0.0" @@ -1069,36 +1118,36 @@ simple-get@^4.0.0: sonic-boom@^3.1.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-3.3.0.tgz#cffab6dafee3b2bcb88d08d589394198bee1838c" + resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.3.0.tgz" integrity sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g== dependencies: atomic-sleep "^1.0.0" split2@^4.0.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== statuses@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== string_decoder@^1.1.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: safe-buffer "~5.2.0" strip-json-comments@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== tar-fs@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz" integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== dependencies: chownr "^1.1.1" @@ -1108,7 +1157,7 @@ tar-fs@^2.0.0: tar-stream@^2.1.4: version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== dependencies: bl "^4.0.3" @@ -1119,19 +1168,24 @@ tar-stream@^2.1.4: thread-stream@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.3.0.tgz#4fc07fb39eff32ae7bad803cb7dd9598349fed33" + resolved "https://registry.npmjs.org/thread-stream/-/thread-stream-2.3.0.tgz" integrity sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA== dependencies: real-require "^0.2.0" +tlds@^1.234.0: + version "1.238.0" + resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.238.0.tgz#ffe7c19c8940c35b497cda187a6927f9450325a4" + integrity sha512-lFPF9pZFhLrPodaJ0wt9QIN0l8jOxqmUezGZnm7BfkDSVd9q667oVIJukLVzhF+4oW7uDlrLlfJrL5yu9RWwew== + toidentifier@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== ts-node@^10.9.1: version "10.9.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== dependencies: "@cspotcode/source-map-support" "^0.8.0" @@ -1148,84 +1202,96 @@ ts-node@^10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +tslib@^2.1.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.2.tgz#1b6f07185c881557b0ffa84b111a0106989e8338" + integrity sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA== + tunnel-agent@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== dependencies: safe-buffer "^5.0.1" type-is@~1.6.18: version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" mime-types "~2.1.24" +typed-emitter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/typed-emitter/-/typed-emitter-2.1.0.tgz#ca78e3d8ef1476f228f548d62e04e3d4d3fd77fb" + integrity sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA== + optionalDependencies: + rxjs "^7.5.2" + typescript@^5.0.4: version "5.0.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz" integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== uint8arrays@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.0.0.tgz#260869efb8422418b6f04e3fac73a3908175c63b" + resolved "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz" integrity sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA== dependencies: multiformats "^9.4.2" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== util-deprecate@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== utils-merge@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== v8-compile-cache-lib@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== varint@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" + resolved "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz" integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== vary@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@^8.12.0: version "8.13.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + resolved "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz" integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yn@3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== zod@^3.14.2: version "3.21.4" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db" + resolved "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz" integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==