From 21bfda32e452c05b8906bf318df7415d6cd5acd0 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 10:05:51 -0500 Subject: [PATCH 01/58] add connections --- assets/schemas.json | 602 ++++++++++++++++++ src/api/middlewares/Authentication.ts | 2 + .../#connection_id/refresh.ts | 11 + .../connections/#connection_name/authorize.ts | 35 + .../connections/#connection_name/callback.ts | 52 ++ src/api/routes/users/@me/connections.ts | 24 +- .../BattleNet/BattleNetSettings.ts | 5 + src/connections/BattleNet/index.ts | 133 ++++ src/connections/GitHub/GitHubSettings.ts | 5 + src/connections/GitHub/index.ts | 114 ++++ src/gateway/opcodes/Identify.ts | 6 +- src/util/connections/Connection.ts | 72 +++ src/util/connections/ConnectionConfig.ts | 79 +++ src/util/connections/ConnectionLoader.ts | 65 ++ src/util/connections/ConnectionStore.ts | 5 + src/util/connections/index.ts | 4 + src/util/dtos/ConnectedAccountDTO.ts | 41 ++ src/util/dtos/index.ts | 1 + src/util/entities/ConnectedAccount.ts | 23 +- src/util/entities/ConnectionConfigEntity.ts | 11 + src/util/entities/index.ts | 1 + src/util/interfaces/Event.ts | 7 + src/util/schemas/ConnectionCallbackSchema.ts | 7 + src/util/schemas/index.ts | 1 + 24 files changed, 1297 insertions(+), 9 deletions(-) create mode 100644 src/api/routes/connections/#connection_name/#connection_id/refresh.ts create mode 100644 src/api/routes/connections/#connection_name/authorize.ts create mode 100644 src/api/routes/connections/#connection_name/callback.ts create mode 100644 src/connections/BattleNet/BattleNetSettings.ts create mode 100644 src/connections/BattleNet/index.ts create mode 100644 src/connections/GitHub/GitHubSettings.ts create mode 100644 src/connections/GitHub/index.ts create mode 100644 src/util/connections/Connection.ts create mode 100644 src/util/connections/ConnectionConfig.ts create mode 100644 src/util/connections/ConnectionLoader.ts create mode 100644 src/util/connections/ConnectionStore.ts create mode 100644 src/util/connections/index.ts create mode 100644 src/util/dtos/ConnectedAccountDTO.ts create mode 100644 src/util/entities/ConnectionConfigEntity.ts create mode 100644 src/util/schemas/ConnectionCallbackSchema.ts diff --git a/assets/schemas.json b/assets/schemas.json index 1fdfa361..a4215497 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -2790,6 +2790,608 @@ }, "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectionCallbackSchema": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "state": { + "type": "string" + }, + "insecure": { + "type": "boolean" + }, + "friend_sync": { + "type": "boolean" + }, + "openid_params": {} + }, + "additionalProperties": false, + "required": [ + "friend_sync", + "insecure", + "state" + ], + "definitions": { + "ChannelPermissionOverwriteType": { + "enum": [ + 0, + 1, + 2 + ], + "type": "number" + }, + "ChannelModifySchema": { + "type": "object", + "properties": { + "name": { + "maxLength": 100, + "type": "string" + }, + "type": { + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 14, + 15, + 2, + 255, + 3, + 33, + 34, + 35, + 4, + 5, + 6, + 64, + 7, + 8, + 9 + ], + "type": "number" + }, + "topic": { + "type": "string" + }, + "icon": { + "type": [ + "null", + "string" + ] + }, + "bitrate": { + "type": "integer" + }, + "user_limit": { + "type": "integer" + }, + "rate_limit_per_user": { + "type": "integer" + }, + "position": { + "type": "integer" + }, + "permission_overwrites": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ChannelPermissionOverwriteType" + }, + "allow": { + "type": "string" + }, + "deny": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "allow", + "deny", + "id", + "type" + ] + } + }, + "parent_id": { + "type": "string" + }, + "id": { + "type": "string" + }, + "nsfw": { + "type": "boolean" + }, + "rtc_region": { + "type": "string" + }, + "default_auto_archive_duration": { + "type": "integer" + }, + "default_reaction_emoji": { + "type": [ + "null", + "string" + ] + }, + "flags": { + "type": "integer" + }, + "default_thread_rate_limit_per_user": { + "type": "integer" + }, + "video_quality_mode": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "ActivitySchema": { + "type": "object", + "properties": { + "afk": { + "type": "boolean" + }, + "status": { + "$ref": "#/definitions/Status" + }, + "activities": { + "type": "array", + "items": { + "$ref": "#/definitions/Activity" + } + }, + "since": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "status" + ] + }, + "Status": { + "enum": [ + "dnd", + "idle", + "invisible", + "offline", + "online" + ], + "type": "string" + }, + "Activity": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ActivityType" + }, + "url": { + "type": "string" + }, + "created_at": { + "type": "integer" + }, + "timestamps": { + "type": "object", + "properties": { + "start": { + "type": "integer" + }, + "end": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end", + "start" + ] + }, + "application_id": { + "type": "string" + }, + "details": { + "type": "string" + }, + "state": { + "type": "string" + }, + "emoji": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "animated": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "animated", + "name" + ] + }, + "party": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "size": { + "type": "array", + "items": [ + { + "type": "integer" + } + ], + "minItems": 1, + "maxItems": 1 + } + }, + "additionalProperties": false + }, + "assets": { + "type": "object", + "properties": { + "large_image": { + "type": "string" + }, + "large_text": { + "type": "string" + }, + "small_image": { + "type": "string" + }, + "small_text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "secrets": { + "type": "object", + "properties": { + "join": { + "type": "string" + }, + "spectate": { + "type": "string" + }, + "match": { + "type": "string" + } + }, + "additionalProperties": false + }, + "instance": { + "type": "boolean" + }, + "flags": { + "type": "string" + }, + "id": { + "type": "string" + }, + "sync_id": { + "type": "string" + }, + "metadata": { + "type": "object", + "properties": { + "context_uri": { + "type": "string" + }, + "album_id": { + "type": "string" + }, + "artist_ids": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "album_id", + "artist_ids" + ] + }, + "session_id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "flags", + "name", + "session_id", + "type" + ] + }, + "ActivityType": { + "enum": [ + 0, + 1, + 2, + 4, + 5 + ], + "type": "number" + }, + "Record": { + "type": "object", + "additionalProperties": false + }, + "Embed": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "type": { + "enum": [ + "article", + "gifv", + "image", + "link", + "rich", + "video" + ], + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "color": { + "type": "integer" + }, + "footer": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "text" + ] + }, + "image": { + "$ref": "#/definitions/EmbedImage" + }, + "thumbnail": { + "$ref": "#/definitions/EmbedImage" + }, + "video": { + "$ref": "#/definitions/EmbedImage" + }, + "provider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "author": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "inline": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "name", + "value" + ] + } + } + }, + "additionalProperties": false + }, + "EmbedImage": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "proxy_url": { + "type": "string" + }, + "height": { + "type": "integer" + }, + "width": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "Partial": { + "type": "object", + "properties": { + "message_notifications": { + "type": "integer" + }, + "mute_config": { + "$ref": "#/definitions/MuteConfig" + }, + "muted": { + "type": "boolean" + }, + "channel_id": { + "type": [ + "null", + "string" + ] + } + }, + "additionalProperties": false + }, + "MuteConfig": { + "type": "object", + "properties": { + "end_time": { + "type": "integer" + }, + "selected_time_window": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end_time", + "selected_time_window" + ] + }, + "CustomStatus": { + "type": "object", + "properties": { + "emoji_id": { + "type": "string" + }, + "emoji_name": { + "type": "string" + }, + "expires_at": { + "type": "integer" + }, + "text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "FriendSourceFlags": { + "type": "object", + "properties": { + "all": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "all" + ] + }, + "GuildFolder": { + "type": "object", + "properties": { + "color": { + "type": "integer" + }, + "guild_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "color", + "guild_ids", + "id", + "name" + ] + }, + "Partial": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Partial": { + "type": "object", + "properties": { + "credential": { + "type": "string" + }, + "name": { + "type": "string" + }, + "ticket": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" + }, "DmChannelCreateSchema": { "type": "object", "properties": { diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts index 771f0de8..55527984 100644 --- a/src/api/middlewares/Authentication.ts +++ b/src/api/middlewares/Authentication.ts @@ -52,6 +52,8 @@ export const NO_AUTHORIZATION_ROUTES = [ "/oauth2/callback", // Asset delivery /\/guilds\/\d+\/widget\.(json|png)/, + // Connections + /\/connections\/\w+\/callback/ ]; export const API_PREFIX = /^\/api(\/v\d+)?/; diff --git a/src/api/routes/connections/#connection_name/#connection_id/refresh.ts b/src/api/routes/connections/#connection_name/#connection_id/refresh.ts new file mode 100644 index 00000000..cce50436 --- /dev/null +++ b/src/api/routes/connections/#connection_name/#connection_id/refresh.ts @@ -0,0 +1,11 @@ +import { route } from "@fosscord/api"; +import { Request, Response, Router } from "express"; +const router = Router(); + +router.post("/", route({}), async (req: Request, res: Response) => { + // TODO: + const { connection_name, connection_id } = req.params; + res.sendStatus(204); +}); + +export default router; diff --git a/src/api/routes/connections/#connection_name/authorize.ts b/src/api/routes/connections/#connection_name/authorize.ts new file mode 100644 index 00000000..8e640a69 --- /dev/null +++ b/src/api/routes/connections/#connection_name/authorize.ts @@ -0,0 +1,35 @@ +import { Request, Response, Router } from "express"; +import { FieldErrors } from "../../../../util"; +import { ConnectionStore } from "../../../../util/connections"; +import { route } from "../../../util"; + +const router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + const { connection_id: connection_name } = req.params; + const connection = ConnectionStore.connections.get(connection_name); + if (!connection) + throw FieldErrors({ + provider_id: { + code: "BASE_TYPE_CHOICES", + message: req.t("common:field.BASE_TYPE_CHOICES", { + types: Array.from(ConnectionStore.connections.keys()).join( + ", ", + ), + }), + }, + }); + + if (!connection.settings.enabled) + throw FieldErrors({ + provider_id: { + message: "This connection has been disabled server-side.", + }, + }); + + res.json({ + url: await connection.getAuthorizationUrl(req.user_id), + }); +}); + +export default router; diff --git a/src/api/routes/connections/#connection_name/callback.ts b/src/api/routes/connections/#connection_name/callback.ts new file mode 100644 index 00000000..f158a037 --- /dev/null +++ b/src/api/routes/connections/#connection_name/callback.ts @@ -0,0 +1,52 @@ +import { Request, Response, Router } from "express"; +import { + ConnectionCallbackSchema, + emitEvent, + FieldErrors, +} from "../../../../util"; +import { ConnectionStore } from "../../../../util/connections"; +import { route } from "../../../util"; + +const router = Router(); + +router.post( + "/", + route({ body: "ConnectionCallbackSchema" }), + async (req: Request, res: Response) => { + const { connection_id: connection_name } = req.params; + const connection = ConnectionStore.connections.get(connection_name); + if (!connection) + throw FieldErrors({ + provider_id: { + code: "BASE_TYPE_CHOICES", + message: req.t("common:field.BASE_TYPE_CHOICES", { + types: Array.from( + ConnectionStore.connections.keys(), + ).join(", "), + }), + }, + }); + + if (!connection.settings.enabled) + throw FieldErrors({ + provider_id: { + message: "This connection has been disabled server-side.", + }, + }); + + const body = req.body as ConnectionCallbackSchema; + const userId = connection.getUserId(body.state); + const emit = await connection.handleCallback(body); + + // whether we should emit a connections update event, only used when a connection doesnt already exist + if (emit) + emitEvent({ + event: "USER_CONNECTIONS_UPDATE", + data: {}, + user_id: userId, + }); + res.sendStatus(204); + }, +); + +export default router; diff --git a/src/api/routes/users/@me/connections.ts b/src/api/routes/users/@me/connections.ts index 74315bfe..a5041be1 100644 --- a/src/api/routes/users/@me/connections.ts +++ b/src/api/routes/users/@me/connections.ts @@ -16,14 +16,32 @@ along with this program. If not, see . */ -import { Request, Response, Router } from "express"; import { route } from "@fosscord/api"; +import { ConnectedAccount, ConnectedAccountDTO } from "@fosscord/util"; +import { Request, Response, Router } from "express"; const router: Router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - //TODO - res.json([]).status(200); + const connections = await ConnectedAccount.find({ + where: { + user_id: req.user_id, + }, + select: [ + "external_id", + "type", + "name", + "verified", + "visibility", + "show_activity", + "revoked", + "access_token", + "friend_sync", + "integrations", + ], + }); + + res.json(connections.map((x) => new ConnectedAccountDTO(x, true))); }); export default router; diff --git a/src/connections/BattleNet/BattleNetSettings.ts b/src/connections/BattleNet/BattleNetSettings.ts new file mode 100644 index 00000000..75e5c3ae --- /dev/null +++ b/src/connections/BattleNet/BattleNetSettings.ts @@ -0,0 +1,5 @@ +export class BattleNetSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts new file mode 100644 index 00000000..0fd0aa18 --- /dev/null +++ b/src/connections/BattleNet/index.ts @@ -0,0 +1,133 @@ +import fetch from "node-fetch"; +import { Config, ConnectionCallbackSchema, DiscordApiErrors } from "../../util"; +import Connection from "../../util/connections/Connection"; +import { ConnectionLoader } from "../../util/connections/ConnectionLoader"; +import { BattleNetSettings } from "./BattleNetSettings"; + +interface OAuthTokenResponse { + access_token: string; + token_type: string; + scope: string; + refresh_token?: string; + expires_in?: number; +} + +interface BattleNetConnectionUser { + sub: string; + id: number; + battletag: string; +} + +interface BattleNetErrorResponse { + error: string; + error_description: string; +} + +export default class BattleNetConnection extends Connection { + public readonly id = "battlenet"; + public readonly authorizeUrl = "https://oauth.battle.net/authorize"; + public readonly tokenUrl = "https://oauth.battle.net/token"; + public readonly userInfoUrl = "https://us.battle.net/oauth/userinfo"; + public readonly scopes = []; + settings: BattleNetSettings = new BattleNetSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as BattleNetSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + url.searchParams.append("response_type", "code"); + return url.toString(); + } + + getTokenUrl(): string { + return this.tokenUrl; + } + + async exchangeCode(state: string, code: string): Promise { + this.validateState(state); + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + }) + .then((res) => res.json()) + .then((res: OAuthTokenResponse & BattleNetErrorResponse) => { + if (res.error) throw new Error(res.error_description); + return res.access_token; + }) + .catch((e) => { + console.error( + `Error exchanging token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => res.json()) + .then((res: BattleNetConnectionUser & BattleNetErrorResponse) => { + if (res.error) throw new Error(res.error_description); + return res; + }); + } + + async handleCallback(params: ConnectionCallbackSchema): Promise { + const userId = this.getUserId(params.state); + const token = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(token); + + const exists = await this.hasConnection(userId, userInfo.id.toString()); + + if (exists) return false; + await this.createConnection({ + user_id: userId, + external_id: userInfo.id, + friend_sync: params.friend_sync, + name: userInfo.battletag, + revoked: false, + show_activity: false, + type: this.id, + verified: true, + visibility: 0, + integrations: [], + }); + return true; + } +} diff --git a/src/connections/GitHub/GitHubSettings.ts b/src/connections/GitHub/GitHubSettings.ts new file mode 100644 index 00000000..1b4070d2 --- /dev/null +++ b/src/connections/GitHub/GitHubSettings.ts @@ -0,0 +1,5 @@ +export class GitHubSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts new file mode 100644 index 00000000..a96ac68e --- /dev/null +++ b/src/connections/GitHub/index.ts @@ -0,0 +1,114 @@ +import fetch from "node-fetch"; +import { Config, ConnectionCallbackSchema, DiscordApiErrors } from "../../util"; +import Connection from "../../util/connections/Connection"; +import { ConnectionLoader } from "../../util/connections/ConnectionLoader"; +import { GitHubSettings } from "./GitHubSettings"; + +interface OAuthTokenResponse { + access_token: string; + token_type: string; + scope: string; + refresh_token?: string; + expires_in?: number; +} + +interface UserResponse { + login: string; + id: number; + name: string; +} + +export default class GitHubConnection extends Connection { + public readonly id = "github"; + public readonly authorizeUrl = "https://github.com/login/oauth/authorize"; + public readonly tokenUrl = "https://github.com/login/oauth/access_token"; + public readonly userInfoUrl = "https://api.github.com/user"; + public readonly scopes = ["read:user"]; + settings: GitHubSettings = new GitHubSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as GitHubSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + return url.toString(); + } + + getTokenUrl(code: string): string { + const url = new URL(this.tokenUrl); + url.searchParams.append("client_id", this.settings.clientId!); + url.searchParams.append("client_secret", this.settings.clientSecret!); + url.searchParams.append("code", code); + return url.toString(); + } + + async exchangeCode(state: string, code: string): Promise { + this.validateState(state); + + const url = this.getTokenUrl(code); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + }, + }) + .then((res) => res.json()) + .then((res: OAuthTokenResponse) => res.access_token) + .catch((e) => { + console.error( + `Error exchanging token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }).then((res) => res.json()); + } + + async handleCallback(params: ConnectionCallbackSchema): Promise { + const userId = this.getUserId(params.state); + const token = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(token); + + const exists = await this.hasConnection(userId, userInfo.id.toString()); + + if (exists) return false; + await this.createConnection({ + user_id: userId, + external_id: userInfo.id, + friend_sync: params.friend_sync, + name: userInfo.name, + revoked: false, + show_activity: false, + type: this.id, + verified: true, + visibility: 0, + integrations: [], + }); + return true; + } +} diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index 1a632b84..d1d15790 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -43,6 +43,7 @@ import { ReadyGuildDTO, Guild, UserTokenData, + ConnectedAccount, } from "@fosscord/util"; import { Send } from "../util/Send"; import { CLOSECODES, OPCODES } from "../util/Constants"; @@ -78,7 +79,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { this.user_id = decoded.id; const session_id = this.session_id; - const [user, read_states, members, recipients, session, application] = + const [user, read_states, members, recipients, session, application, connected_accounts] = await Promise.all([ User.findOneOrFail({ where: { id: this.user_id }, @@ -123,6 +124,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { activities: [], }).save(), Application.findOne({ where: { id: this.user_id } }), + ConnectedAccount.find({ where: { user_id: this.user_id } }) ]); if (!user) return this.close(CLOSECODES.Authentication_failed); @@ -304,7 +306,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { private_channels: channels, session_id: session_id, analytics_token: "", // TODO - connected_accounts: [], // TODO + connected_accounts, consents: { personalization: { consented: false, // TODO diff --git a/src/util/connections/Connection.ts b/src/util/connections/Connection.ts new file mode 100644 index 00000000..02104d39 --- /dev/null +++ b/src/util/connections/Connection.ts @@ -0,0 +1,72 @@ +import crypto from "crypto"; +import { ConnectedAccount } from "../entities"; +import { OrmUtils } from "../imports"; +import { ConnectionCallbackSchema } from "../schemas"; +import { DiscordApiErrors } from "../util"; + +export default abstract class Connection { + id: string; + settings: { enabled: boolean }; + states: Map = new Map(); + + abstract init(): void; + + /** + * Generates an authorization url for the connection. + * @param args + */ + abstract getAuthorizationUrl(userId: string): string; + + /** + * Processes the callback + * @param args Callback arguments + */ + abstract handleCallback(params: ConnectionCallbackSchema): Promise; + + /** + * Gets a user id from state + * @param state the state to get the user id from + * @returns the user id associated with the state + */ + getUserId(state: string): string { + if (!this.states.has(state)) throw DiscordApiErrors.INVALID_OAUTH_STATE; + return this.states.get(state) as string; + } + + /** + * Generates a state + * @param user_id The user id to generate a state for. + * @returns a new state + */ + createState(userId: string): string { + const state = crypto.randomBytes(16).toString("hex"); + this.states.set(state, userId); + + return state; + } + + /** + * Takes a state and checks if it is valid, and deletes it. + * @param state The state to check. + */ + validateState(state: string): void { + if (!this.states.has(state)) throw DiscordApiErrors.INVALID_OAUTH_STATE; + this.states.delete(state); + } + + async createConnection(data: any): Promise { + const ca = OrmUtils.mergeDeep(new ConnectedAccount(), data); + await ca.save(); + } + + async hasConnection(userId: string, externalId: string): Promise { + const existing = await ConnectedAccount.findOne({ + where: { + user_id: userId, + external_id: externalId, + }, + }); + + return !!existing; + } +} diff --git a/src/util/connections/ConnectionConfig.ts b/src/util/connections/ConnectionConfig.ts new file mode 100644 index 00000000..9b120c93 --- /dev/null +++ b/src/util/connections/ConnectionConfig.ts @@ -0,0 +1,79 @@ +import { ConnectionConfigEntity } from "../entities/ConnectionConfigEntity"; + +let config: any; +let pairs: ConnectionConfigEntity[]; + +export const ConnectionConfig = { + init: async function init() { + if (config) return config; + console.log("[ConnectionConfig] Loading configuration..."); + pairs = await ConnectionConfigEntity.find(); + config = pairsToConfig(pairs); + + return this.set(config); + }, + get: function get() { + if (!config) { + return {}; + } + return config; + }, + set: function set(val: Partial) { + if (!config || !val) return; + config = val.merge(config); + console.debug("config", config); // TODO: if no more issues with sql, remove this or find the reason why it's happening + + return applyConfig(config); + }, +}; + +function applyConfig(val: any) { + async function apply(obj: any, key = ""): Promise { + if (typeof obj === "object" && obj !== null && !(obj instanceof Date)) + return Promise.all( + Object.keys(obj).map((k) => + apply(obj[k], key ? `${key}_${k}` : k), + ), + ); + + let pair = pairs.find((x) => x.key === key); + if (!pair) pair = new ConnectionConfigEntity(); + + pair.key = key; + + if (pair.value !== obj) { + pair.value = obj; + if (!pair.key || pair.key == null) { + console.log(`[ConnectionConfig] WARN: Empty key`); + console.log(pair); + } else return pair.save(); + } + } + + return apply(val); +} + +function pairsToConfig(pairs: ConnectionConfigEntity[]) { + let value: any = {}; + + pairs.forEach((p) => { + const keys = p.key.split("_"); + let obj = value; + let prev = ""; + let prevObj = obj; + let i = 0; + + for (const key of keys) { + if (!isNaN(Number(key)) && !prevObj[prev]?.length) + prevObj[prev] = obj = []; + if (i++ === keys.length - 1) obj[key] = p.value; + else if (!obj[key]) obj[key] = {}; + + prev = key; + prevObj = obj; + obj = obj[key]; + } + }); + + return value; +} diff --git a/src/util/connections/ConnectionLoader.ts b/src/util/connections/ConnectionLoader.ts new file mode 100644 index 00000000..d06a6446 --- /dev/null +++ b/src/util/connections/ConnectionLoader.ts @@ -0,0 +1,65 @@ +import fs from "fs"; +import path from "path"; +import { OrmUtils } from "../imports"; +import Connection from "./Connection"; +import { ConnectionConfig } from "./ConnectionConfig"; +import { ConnectionStore } from "./ConnectionStore"; + +const root = "dist/connections"; +let connectionsLoaded = false; + +export class ConnectionLoader { + public static async loadConnections() { + if (connectionsLoaded) return; + ConnectionConfig.init(); + const dirs = fs.readdirSync(root).filter((x) => { + try { + fs.readdirSync(path.join(root, x)); + return true; + } catch (e) { + return false; + } + }); + + dirs.forEach(async (x) => { + let modPath = path.resolve(path.join(root, x)); + console.log(`Loading connection: ${modPath}`); + const mod = new (require(modPath).default)() as Connection; + ConnectionStore.connections.set(mod.id, mod); + + mod.init(); + console.log(`[Connections] Loaded connection '${mod.id}'`); + }); + } + + public static getConnectionConfig(id: string, defaults?: any): any { + let cfg = ConnectionConfig.get()[id]; + if (defaults) { + if (cfg) cfg = OrmUtils.mergeDeep(defaults, cfg); + else cfg = defaults; + this.setConnectionConfig(id, cfg); + } + + if (!cfg) + console.log( + `[ConnectionConfig/WARN] Getting connection settings for '${id}' returned null! (Did you forget to add settings?)`, + ); + return cfg; + } + + public static async setConnectionConfig( + id: string, + config: Partial, + ): Promise { + if (!config) + console.log( + `[ConnectionConfig/WARN] ${id} tried to set config=null!`, + ); + await ConnectionConfig.set({ + [id]: OrmUtils.mergeDeep( + ConnectionLoader.getConnectionConfig(id) || {}, + config, + ), + }); + } +} diff --git a/src/util/connections/ConnectionStore.ts b/src/util/connections/ConnectionStore.ts new file mode 100644 index 00000000..406e8232 --- /dev/null +++ b/src/util/connections/ConnectionStore.ts @@ -0,0 +1,5 @@ +import Connection from "./Connection"; + +export class ConnectionStore { + public static connections: Map = new Map(); +} diff --git a/src/util/connections/index.ts b/src/util/connections/index.ts new file mode 100644 index 00000000..e15d0c8c --- /dev/null +++ b/src/util/connections/index.ts @@ -0,0 +1,4 @@ +export * from "./Connection"; +export * from "./ConnectionConfig"; +export * from "./ConnectionLoader"; +export * from "./ConnectionStore"; diff --git a/src/util/dtos/ConnectedAccountDTO.ts b/src/util/dtos/ConnectedAccountDTO.ts new file mode 100644 index 00000000..a0287086 --- /dev/null +++ b/src/util/dtos/ConnectedAccountDTO.ts @@ -0,0 +1,41 @@ +import { ConnectedAccount } from "../entities"; + +export class ConnectedAccountDTO { + id: string; + user_id: string; + access_token?: string; + friend_sync: boolean; + name: string; + revoked: boolean; + show_activity: boolean; + type: string; + verified: boolean; + visibility: boolean; + integrations: string[]; + metadata_: any; + metadata_visibility: boolean; + two_way_link: boolean; + + constructor( + connectedAccount: ConnectedAccount, + with_token: boolean = false, + ) { + this.id = connectedAccount.external_id; + this.user_id = connectedAccount.user_id; + this.access_token = + connectedAccount.access_token && with_token + ? connectedAccount.access_token + : undefined; + this.friend_sync = connectedAccount.friend_sync; + this.name = connectedAccount.name; + this.revoked = connectedAccount.revoked; + this.show_activity = connectedAccount.show_activity; + this.type = connectedAccount.type; + this.verified = connectedAccount.verified; + this.visibility = connectedAccount.visibility; + this.integrations = connectedAccount.integrations; + this.metadata_ = connectedAccount.metadata_; + this.metadata_visibility = connectedAccount.metadata_visibility; + this.two_way_link = connectedAccount.two_way_link; + } +} diff --git a/src/util/dtos/index.ts b/src/util/dtos/index.ts index cf3863fa..b91889ff 100644 --- a/src/util/dtos/index.ts +++ b/src/util/dtos/index.ts @@ -16,6 +16,7 @@ along with this program. If not, see . */ +export * from "./ConnectedAccountDTO"; export * from "./DmChannelDTO"; export * from "./ReadyGuildDTO"; export * from "./UserDTO"; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 9f0ce35e..70923d2c 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -27,6 +27,9 @@ export type PublicConnectedAccount = Pick< @Entity("connected_accounts") export class ConnectedAccount extends BaseClass { + @Column() + external_id: string; + @Column({ nullable: true }) @RelationId((account: ConnectedAccount) => account.user) user_id: string; @@ -41,16 +44,16 @@ export class ConnectedAccount extends BaseClass { access_token: string; @Column({ select: false }) - friend_sync: boolean; + friend_sync: boolean = false; @Column() name: string; @Column({ select: false }) - revoked: boolean; + revoked: boolean = false; @Column({ select: false }) - show_activity: boolean; + show_activity: boolean = true; @Column() type: string; @@ -59,5 +62,17 @@ export class ConnectedAccount extends BaseClass { verified: boolean; @Column({ select: false }) - visibility: number; + visibility: boolean = true; + + @Column({ type: "simple-array" }) + integrations: string[]; + + @Column({ type: "simple-json", name: "metadata" }) + metadata_: any; + + @Column() + metadata_visibility: boolean = true; + + @Column() + two_way_link: boolean = false; } diff --git a/src/util/entities/ConnectionConfigEntity.ts b/src/util/entities/ConnectionConfigEntity.ts new file mode 100644 index 00000000..9c212b15 --- /dev/null +++ b/src/util/entities/ConnectionConfigEntity.ts @@ -0,0 +1,11 @@ +import { Column, Entity } from "typeorm"; +import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; + +@Entity("connection_config") +export class ConnectionConfigEntity extends BaseClassWithoutId { + @PrimaryIdColumn() + key: string; + + @Column({ type: "simple-json", nullable: true }) + value: number | boolean | null | string | Date | undefined; +} diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts index 6dfbd822..ad34f67b 100644 --- a/src/util/entities/index.ts +++ b/src/util/entities/index.ts @@ -27,6 +27,7 @@ export * from "./Channel"; export * from "./ClientRelease"; export * from "./Config"; export * from "./ConnectedAccount"; +export * from "./ConnectionConfigEntity"; export * from "./EmbedCache"; export * from "./Emoji"; export * from "./Encryption"; diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts index c3bfbf9b..6609c9ee 100644 --- a/src/util/interfaces/Event.ts +++ b/src/util/interfaces/Event.ts @@ -420,6 +420,10 @@ export interface UserDeleteEvent extends Event { }; } +export interface UserConnectionsUpdateEvent extends Event { + event: "USER_CONNECTIONS_UPDATE"; +} + export interface VoiceStateUpdateEvent extends Event { event: "VOICE_STATE_UPDATE"; data: VoiceState & { @@ -561,6 +565,7 @@ export type EventData = | TypingStartEvent | UserUpdateEvent | UserDeleteEvent + | UserConnectionsUpdateEvent | VoiceStateUpdateEvent | VoiceServerUpdateEvent | WebhooksUpdateEvent @@ -612,6 +617,7 @@ export enum EVENTEnum { TypingStart = "TYPING_START", UserUpdate = "USER_UPDATE", UserDelete = "USER_DELETE", + UserConnectionsUpdate = "USER_CONNECTIONS_UPDATE", WebhooksUpdate = "WEBHOOKS_UPDATE", InteractionCreate = "INTERACTION_CREATE", VoiceStateUpdate = "VOICE_STATE_UPDATE", @@ -663,6 +669,7 @@ export type EVENT = | "TYPING_START" | "USER_UPDATE" | "USER_DELETE" + | "USER_CONNECTIONS_UPDATE" | "USER_NOTE_UPDATE" | "WEBHOOKS_UPDATE" | "INTERACTION_CREATE" diff --git a/src/util/schemas/ConnectionCallbackSchema.ts b/src/util/schemas/ConnectionCallbackSchema.ts new file mode 100644 index 00000000..09ae8a46 --- /dev/null +++ b/src/util/schemas/ConnectionCallbackSchema.ts @@ -0,0 +1,7 @@ +export interface ConnectionCallbackSchema { + code?: string; + state: string; + insecure: boolean; + friend_sync: boolean; + openid_params?: any; // TODO: types +} diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts index 44909a3a..2831d42a 100644 --- a/src/util/schemas/index.ts +++ b/src/util/schemas/index.ts @@ -30,6 +30,7 @@ export * from "./ChannelModifySchema"; export * from "./ChannelPermissionOverwriteSchema"; export * from "./ChannelReorderSchema"; export * from "./CodesVerificationSchema"; +export * from "./ConnectionCallbackSchema"; export * from "./DmChannelCreateSchema"; export * from "./EmojiCreateSchema"; export * from "./EmojiModifySchema"; From 6a52e65e27d514273a4210dadafbee9692f23354 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 10:47:32 -0500 Subject: [PATCH 02/58] adding connection now works --- src/api/Server.ts | 5 ++++ .../connections/#connection_name/authorize.ts | 2 +- .../connections/#connection_name/callback.ts | 2 +- src/connections/BattleNet/index.ts | 7 +----- src/connections/GitHub/index.ts | 7 +----- src/util/connections/Connection.ts | 4 ++-- src/util/connections/ConnectionConfig.ts | 1 - src/util/connections/ConnectionLoader.ts | 7 +++--- src/util/dtos/ConnectedAccountDTO.ts | 18 +++++++------- src/util/entities/ConnectedAccount.ts | 24 +++++++++---------- src/util/index.ts | 1 + src/util/schemas/ConnectedAccountSchema.ts | 16 +++++++++++++ src/util/schemas/index.ts | 1 + 13 files changed, 54 insertions(+), 41 deletions(-) create mode 100644 src/util/schemas/ConnectedAccountSchema.ts diff --git a/src/api/Server.ts b/src/api/Server.ts index 49229494..dc3b66ef 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts @@ -25,6 +25,8 @@ import { registerRoutes, Sentry, WebAuthn, + ConnectionConfig, + ConnectionLoader } from "@fosscord/util"; import { Request, Response, Router } from "express"; import { Server, ServerOptions } from "lambert-server"; @@ -64,6 +66,7 @@ export class FosscordServer extends Server { await Config.init(); await initEvent(); await Email.init(); + await ConnectionConfig.init(); await initInstance(); await Sentry.init(this.app); WebAuthn.init(); @@ -130,6 +133,8 @@ export class FosscordServer extends Server { Sentry.errorHandler(this.app); + ConnectionLoader.loadConnections(); + if (logRequests) console.log( red( diff --git a/src/api/routes/connections/#connection_name/authorize.ts b/src/api/routes/connections/#connection_name/authorize.ts index 8e640a69..5ce420cf 100644 --- a/src/api/routes/connections/#connection_name/authorize.ts +++ b/src/api/routes/connections/#connection_name/authorize.ts @@ -6,7 +6,7 @@ import { route } from "../../../util"; const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - const { connection_id: connection_name } = req.params; + const { connection_name } = req.params; const connection = ConnectionStore.connections.get(connection_name); if (!connection) throw FieldErrors({ diff --git a/src/api/routes/connections/#connection_name/callback.ts b/src/api/routes/connections/#connection_name/callback.ts index f158a037..80a5b784 100644 --- a/src/api/routes/connections/#connection_name/callback.ts +++ b/src/api/routes/connections/#connection_name/callback.ts @@ -13,7 +13,7 @@ router.post( "/", route({ body: "ConnectionCallbackSchema" }), async (req: Request, res: Response) => { - const { connection_id: connection_name } = req.params; + const { connection_name } = req.params; const connection = ConnectionStore.connections.get(connection_name); if (!connection) throw FieldErrors({ diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index 0fd0aa18..1b725afd 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -118,15 +118,10 @@ export default class BattleNetConnection extends Connection { if (exists) return false; await this.createConnection({ user_id: userId, - external_id: userInfo.id, + external_id: userInfo.id.toString(), friend_sync: params.friend_sync, name: userInfo.battletag, - revoked: false, - show_activity: false, type: this.id, - verified: true, - visibility: 0, - integrations: [], }); return true; } diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index a96ac68e..41806a67 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -99,15 +99,10 @@ export default class GitHubConnection extends Connection { if (exists) return false; await this.createConnection({ user_id: userId, - external_id: userInfo.id, + external_id: userInfo.id.toString(), friend_sync: params.friend_sync, name: userInfo.name, - revoked: false, - show_activity: false, type: this.id, - verified: true, - visibility: 0, - integrations: [], }); return true; } diff --git a/src/util/connections/Connection.ts b/src/util/connections/Connection.ts index 02104d39..e8d41c36 100644 --- a/src/util/connections/Connection.ts +++ b/src/util/connections/Connection.ts @@ -1,7 +1,7 @@ import crypto from "crypto"; import { ConnectedAccount } from "../entities"; import { OrmUtils } from "../imports"; -import { ConnectionCallbackSchema } from "../schemas"; +import { ConnectedAccountSchema, ConnectionCallbackSchema } from "../schemas"; import { DiscordApiErrors } from "../util"; export default abstract class Connection { @@ -54,7 +54,7 @@ export default abstract class Connection { this.states.delete(state); } - async createConnection(data: any): Promise { + async createConnection(data: ConnectedAccountSchema): Promise { const ca = OrmUtils.mergeDeep(new ConnectedAccount(), data); await ca.save(); } diff --git a/src/util/connections/ConnectionConfig.ts b/src/util/connections/ConnectionConfig.ts index 9b120c93..dd372ff7 100644 --- a/src/util/connections/ConnectionConfig.ts +++ b/src/util/connections/ConnectionConfig.ts @@ -21,7 +21,6 @@ export const ConnectionConfig = { set: function set(val: Partial) { if (!config || !val) return; config = val.merge(config); - console.debug("config", config); // TODO: if no more issues with sql, remove this or find the reason why it's happening return applyConfig(config); }, diff --git a/src/util/connections/ConnectionLoader.ts b/src/util/connections/ConnectionLoader.ts index d06a6446..7467739c 100644 --- a/src/util/connections/ConnectionLoader.ts +++ b/src/util/connections/ConnectionLoader.ts @@ -23,7 +23,6 @@ export class ConnectionLoader { dirs.forEach(async (x) => { let modPath = path.resolve(path.join(root, x)); - console.log(`Loading connection: ${modPath}`); const mod = new (require(modPath).default)() as Connection; ConnectionStore.connections.set(mod.id, mod); @@ -55,11 +54,13 @@ export class ConnectionLoader { console.log( `[ConnectionConfig/WARN] ${id} tried to set config=null!`, ); - await ConnectionConfig.set({ + + const a = { [id]: OrmUtils.mergeDeep( ConnectionLoader.getConnectionConfig(id) || {}, config, ), - }); + }; + await ConnectionConfig.set(a); } } diff --git a/src/util/dtos/ConnectedAccountDTO.ts b/src/util/dtos/ConnectedAccountDTO.ts index a0287086..36a4e6b3 100644 --- a/src/util/dtos/ConnectedAccountDTO.ts +++ b/src/util/dtos/ConnectedAccountDTO.ts @@ -4,17 +4,17 @@ export class ConnectedAccountDTO { id: string; user_id: string; access_token?: string; - friend_sync: boolean; + friend_sync?: boolean; name: string; - revoked: boolean; - show_activity: boolean; + revoked?: boolean; + show_activity?: boolean; type: string; - verified: boolean; - visibility: boolean; - integrations: string[]; - metadata_: any; - metadata_visibility: boolean; - two_way_link: boolean; + verified?: boolean; + visibility?: number; + integrations?: string[]; + metadata_?: any; + metadata_visibility?: number; + two_way_link?: boolean; constructor( connectedAccount: ConnectedAccount, diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 70923d2c..25d5a0c7 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -40,39 +40,39 @@ export class ConnectedAccount extends BaseClass { }) user: User; - @Column({ select: false }) - access_token: string; + @Column({ select: false, nullable: true }) + access_token?: string; @Column({ select: false }) - friend_sync: boolean = false; + friend_sync?: boolean = false; @Column() name: string; @Column({ select: false }) - revoked: boolean = false; + revoked?: boolean = false; @Column({ select: false }) - show_activity: boolean = true; + show_activity?: boolean = true; @Column() type: string; @Column() - verified: boolean; + verified?: boolean = true; @Column({ select: false }) - visibility: boolean = true; + visibility?: number = 0; @Column({ type: "simple-array" }) - integrations: string[]; + integrations?: string[] = []; - @Column({ type: "simple-json", name: "metadata" }) - metadata_: any; + @Column({ type: "simple-json", name: "metadata", nullable: true }) + metadata_?: any; @Column() - metadata_visibility: boolean = true; + metadata_visibility?: number = 0; @Column() - two_way_link: boolean = false; + two_way_link?: boolean = false; } diff --git a/src/util/index.ts b/src/util/index.ts index a3495a0c..cb180ee8 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -25,3 +25,4 @@ export * from "./dtos/index"; export * from "./schemas"; export * from "./imports"; export * from "./config"; +export * from "./connections" \ No newline at end of file diff --git a/src/util/schemas/ConnectedAccountSchema.ts b/src/util/schemas/ConnectedAccountSchema.ts new file mode 100644 index 00000000..e00e4fa1 --- /dev/null +++ b/src/util/schemas/ConnectedAccountSchema.ts @@ -0,0 +1,16 @@ +export interface ConnectedAccountSchema { + external_id: string; + user_id: string; + access_token?: string; + friend_sync?: boolean; + name: string; + revoked?: boolean; + show_activity?: boolean; + type: string; + verified?: boolean; + visibility?: number; + integrations?: string[]; + metadata_?: any; + metadata_visibility?: number; + two_way_link?: boolean; +} diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts index 2831d42a..71b4c2ce 100644 --- a/src/util/schemas/index.ts +++ b/src/util/schemas/index.ts @@ -30,6 +30,7 @@ export * from "./ChannelModifySchema"; export * from "./ChannelPermissionOverwriteSchema"; export * from "./ChannelReorderSchema"; export * from "./CodesVerificationSchema"; +export * from "./ConnectedAccountSchema"; export * from "./ConnectionCallbackSchema"; export * from "./DmChannelCreateSchema"; export * from "./EmojiCreateSchema"; From 5c682137b2ab6ecef2a52fc3974a2cc01931dbf2 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 11:08:03 -0500 Subject: [PATCH 03/58] implement PATCH connection --- assets/schemas.json | 643 ++++++++++++++++++ .../#connection_name/#connection_id/index.ts | 51 ++ .../{connections.ts => connections/index.ts} | 0 src/util/dtos/ConnectedAccountDTO.ts | 6 +- src/util/entities/ConnectedAccount.ts | 4 +- src/util/entities/ConnectionUpdateSchema.ts | 3 + src/util/entities/index.ts | 1 + src/util/util/Constants.ts | 1 + 8 files changed, 705 insertions(+), 4 deletions(-) create mode 100644 src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts rename src/api/routes/users/@me/{connections.ts => connections/index.ts} (100%) create mode 100644 src/util/entities/ConnectionUpdateSchema.ts diff --git a/assets/schemas.json b/assets/schemas.json index a4215497..881560dd 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -36,6 +36,16 @@ ], "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectionUpdateSchema": { + "type": "object", + "properties": { + "visibility": { + "type": "boolean" + } + }, + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + }, "SMTPConnection.CustomAuthenticationResponse": { "type": "object", "properties": { @@ -2790,6 +2800,639 @@ }, "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectedAccountSchema": { + "type": "object", + "properties": { + "external_id": { + "type": "string" + }, + "user_id": { + "type": "string" + }, + "access_token": { + "type": "string" + }, + "friend_sync": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "revoked": { + "type": "boolean" + }, + "show_activity": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "visibility": { + "type": "integer" + }, + "integrations": { + "type": "array", + "items": { + "type": "string" + } + }, + "metadata_": {}, + "metadata_visibility": { + "type": "integer" + }, + "two_way_link": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "external_id", + "name", + "type", + "user_id" + ], + "definitions": { + "ChannelPermissionOverwriteType": { + "enum": [ + 0, + 1, + 2 + ], + "type": "number" + }, + "ChannelModifySchema": { + "type": "object", + "properties": { + "name": { + "maxLength": 100, + "type": "string" + }, + "type": { + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 14, + 15, + 2, + 255, + 3, + 33, + 34, + 35, + 4, + 5, + 6, + 64, + 7, + 8, + 9 + ], + "type": "number" + }, + "topic": { + "type": "string" + }, + "icon": { + "type": [ + "null", + "string" + ] + }, + "bitrate": { + "type": "integer" + }, + "user_limit": { + "type": "integer" + }, + "rate_limit_per_user": { + "type": "integer" + }, + "position": { + "type": "integer" + }, + "permission_overwrites": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ChannelPermissionOverwriteType" + }, + "allow": { + "type": "string" + }, + "deny": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "allow", + "deny", + "id", + "type" + ] + } + }, + "parent_id": { + "type": "string" + }, + "id": { + "type": "string" + }, + "nsfw": { + "type": "boolean" + }, + "rtc_region": { + "type": "string" + }, + "default_auto_archive_duration": { + "type": "integer" + }, + "default_reaction_emoji": { + "type": [ + "null", + "string" + ] + }, + "flags": { + "type": "integer" + }, + "default_thread_rate_limit_per_user": { + "type": "integer" + }, + "video_quality_mode": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "ActivitySchema": { + "type": "object", + "properties": { + "afk": { + "type": "boolean" + }, + "status": { + "$ref": "#/definitions/Status" + }, + "activities": { + "type": "array", + "items": { + "$ref": "#/definitions/Activity" + } + }, + "since": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "status" + ] + }, + "Status": { + "enum": [ + "dnd", + "idle", + "invisible", + "offline", + "online" + ], + "type": "string" + }, + "Activity": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ActivityType" + }, + "url": { + "type": "string" + }, + "created_at": { + "type": "integer" + }, + "timestamps": { + "type": "object", + "properties": { + "start": { + "type": "integer" + }, + "end": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end", + "start" + ] + }, + "application_id": { + "type": "string" + }, + "details": { + "type": "string" + }, + "state": { + "type": "string" + }, + "emoji": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "animated": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "animated", + "name" + ] + }, + "party": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "size": { + "type": "array", + "items": [ + { + "type": "integer" + } + ], + "minItems": 1, + "maxItems": 1 + } + }, + "additionalProperties": false + }, + "assets": { + "type": "object", + "properties": { + "large_image": { + "type": "string" + }, + "large_text": { + "type": "string" + }, + "small_image": { + "type": "string" + }, + "small_text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "secrets": { + "type": "object", + "properties": { + "join": { + "type": "string" + }, + "spectate": { + "type": "string" + }, + "match": { + "type": "string" + } + }, + "additionalProperties": false + }, + "instance": { + "type": "boolean" + }, + "flags": { + "type": "string" + }, + "id": { + "type": "string" + }, + "sync_id": { + "type": "string" + }, + "metadata": { + "type": "object", + "properties": { + "context_uri": { + "type": "string" + }, + "album_id": { + "type": "string" + }, + "artist_ids": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "album_id", + "artist_ids" + ] + }, + "session_id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "flags", + "name", + "session_id", + "type" + ] + }, + "ActivityType": { + "enum": [ + 0, + 1, + 2, + 4, + 5 + ], + "type": "number" + }, + "Record": { + "type": "object", + "additionalProperties": false + }, + "Embed": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "type": { + "enum": [ + "article", + "gifv", + "image", + "link", + "rich", + "video" + ], + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "color": { + "type": "integer" + }, + "footer": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "text" + ] + }, + "image": { + "$ref": "#/definitions/EmbedImage" + }, + "thumbnail": { + "$ref": "#/definitions/EmbedImage" + }, + "video": { + "$ref": "#/definitions/EmbedImage" + }, + "provider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "author": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "inline": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "name", + "value" + ] + } + } + }, + "additionalProperties": false + }, + "EmbedImage": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "proxy_url": { + "type": "string" + }, + "height": { + "type": "integer" + }, + "width": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "Partial": { + "type": "object", + "properties": { + "message_notifications": { + "type": "integer" + }, + "mute_config": { + "$ref": "#/definitions/MuteConfig" + }, + "muted": { + "type": "boolean" + }, + "channel_id": { + "type": [ + "null", + "string" + ] + } + }, + "additionalProperties": false + }, + "MuteConfig": { + "type": "object", + "properties": { + "end_time": { + "type": "integer" + }, + "selected_time_window": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end_time", + "selected_time_window" + ] + }, + "CustomStatus": { + "type": "object", + "properties": { + "emoji_id": { + "type": "string" + }, + "emoji_name": { + "type": "string" + }, + "expires_at": { + "type": "integer" + }, + "text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "FriendSourceFlags": { + "type": "object", + "properties": { + "all": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "all" + ] + }, + "GuildFolder": { + "type": "object", + "properties": { + "color": { + "type": "integer" + }, + "guild_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "color", + "guild_ids", + "id", + "name" + ] + }, + "Partial": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Partial": { + "type": "object", + "properties": { + "credential": { + "type": "string" + }, + "name": { + "type": "string" + }, + "ticket": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" + }, "ConnectionCallbackSchema": { "type": "object", "properties": { diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts new file mode 100644 index 00000000..76eb9936 --- /dev/null +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts @@ -0,0 +1,51 @@ +import { route } from "@fosscord/api"; +import { Request, Response, Router } from "express"; +import { + ConnectedAccount, + DiscordApiErrors, + OrmUtils, +} from "../../../../../../../util"; +const router = Router(); + +// TODO: connection update schema +router.patch( + "/", + route({ body: "ConnectionUpdateSchema" }), + async (req: Request, res: Response) => { + const { connection_name, connection_id } = req.params; + + const connection = await ConnectedAccount.findOne({ + where: { + user_id: req.user_id, + external_id: connection_id, + type: connection_name, + }, + select: [ + "external_id", + "type", + "name", + "verified", + "visibility", + "show_activity", + "revoked", + "friend_sync", + "integrations", + ], + }); + + if (!connection) return DiscordApiErrors.UNKNOWN_CONNECTION; + // TODO: do we need to do anything if the connection is revoked? + OrmUtils.mergeDeep(connection, req.body); + await ConnectedAccount.update( + { + user_id: req.user_id, + external_id: connection_id, + type: connection_name, + }, + connection, + ); + res.json(connection.toJSON()); + }, +); + +export default router; diff --git a/src/api/routes/users/@me/connections.ts b/src/api/routes/users/@me/connections/index.ts similarity index 100% rename from src/api/routes/users/@me/connections.ts rename to src/api/routes/users/@me/connections/index.ts diff --git a/src/util/dtos/ConnectedAccountDTO.ts b/src/util/dtos/ConnectedAccountDTO.ts index 36a4e6b3..debc5535 100644 --- a/src/util/dtos/ConnectedAccountDTO.ts +++ b/src/util/dtos/ConnectedAccountDTO.ts @@ -32,10 +32,12 @@ export class ConnectedAccountDTO { this.show_activity = connectedAccount.show_activity; this.type = connectedAccount.type; this.verified = connectedAccount.verified; - this.visibility = connectedAccount.visibility; + this.visibility = +(connectedAccount.visibility || false); this.integrations = connectedAccount.integrations; this.metadata_ = connectedAccount.metadata_; - this.metadata_visibility = connectedAccount.metadata_visibility; + this.metadata_visibility = +( + connectedAccount.metadata_visibility || false + ); this.two_way_link = connectedAccount.two_way_link; } } diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 25d5a0c7..714faf0c 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -62,7 +62,7 @@ export class ConnectedAccount extends BaseClass { verified?: boolean = true; @Column({ select: false }) - visibility?: number = 0; + visibility?: boolean = false; @Column({ type: "simple-array" }) integrations?: string[] = []; @@ -71,7 +71,7 @@ export class ConnectedAccount extends BaseClass { metadata_?: any; @Column() - metadata_visibility?: number = 0; + metadata_visibility?: boolean = false; @Column() two_way_link?: boolean = false; diff --git a/src/util/entities/ConnectionUpdateSchema.ts b/src/util/entities/ConnectionUpdateSchema.ts new file mode 100644 index 00000000..ac234e7e --- /dev/null +++ b/src/util/entities/ConnectionUpdateSchema.ts @@ -0,0 +1,3 @@ +export interface ConnectionUpdateSchema { + visibility?: boolean; +} diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts index ad34f67b..b4e3ecd0 100644 --- a/src/util/entities/index.ts +++ b/src/util/entities/index.ts @@ -28,6 +28,7 @@ export * from "./ClientRelease"; export * from "./Config"; export * from "./ConnectedAccount"; export * from "./ConnectionConfigEntity"; +export * from "./ConnectionUpdateSchema"; export * from "./EmbedCache"; export * from "./Emoji"; export * from "./Encryption"; diff --git a/src/util/util/Constants.ts b/src/util/util/Constants.ts index 1afdce49..3bdfcfa9 100644 --- a/src/util/util/Constants.ts +++ b/src/util/util/Constants.ts @@ -578,6 +578,7 @@ export const DiscordApiErrors = { UNKNOWN_EMOJI: new ApiError("Unknown emoji", 10014), UNKNOWN_WEBHOOK: new ApiError("Unknown webhook", 10015), UNKNOWN_WEBHOOK_SERVICE: new ApiError("Unknown webhook service", 10016), + UNKNOWN_CONNECTION: new ApiError("Unknown connection", 10017, 400), UNKNOWN_SESSION: new ApiError("Unknown session", 10020), UNKNOWN_BAN: new ApiError("Unknown ban", 10026), UNKNOWN_SKU: new ApiError("Unknown SKU", 10027), From a4961800d7b6b37864b7b7c44893c734ef1b05ae Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 12:44:04 +1100 Subject: [PATCH 04/58] `handleCallback` returns connection if created for `USER_CONNECTIONS_UPDATE` --- package-lock.json | 1 - .../connections/#connection_name/callback.ts | 15 ++++++++------- src/connections/BattleNet/index.ts | 18 ++++++++---------- src/connections/GitHub/index.ts | 10 +++++----- src/util/connections/Connection.ts | 7 ++++--- 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8927001f..cea4dbb6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,6 @@ "probe-image-size": "^7.2.3", "proxy-agent": "^5.0.0", "reflect-metadata": "^0.1.13", - "sqlite3": "^5.1.5", "ts-node": "^10.9.1", "tslib": "^2.4.1", "typeorm": "^0.3.10", diff --git a/src/api/routes/connections/#connection_name/callback.ts b/src/api/routes/connections/#connection_name/callback.ts index 80a5b784..250d4710 100644 --- a/src/api/routes/connections/#connection_name/callback.ts +++ b/src/api/routes/connections/#connection_name/callback.ts @@ -1,11 +1,11 @@ -import { Request, Response, Router } from "express"; +import { route } from "@fosscord/api"; import { ConnectionCallbackSchema, + ConnectionStore, emitEvent, FieldErrors, -} from "../../../../util"; -import { ConnectionStore } from "../../../../util/connections"; -import { route } from "../../../util"; +} from "@fosscord/util"; +import { Request, Response, Router } from "express"; const router = Router(); @@ -36,15 +36,16 @@ router.post( const body = req.body as ConnectionCallbackSchema; const userId = connection.getUserId(body.state); - const emit = await connection.handleCallback(body); + const connectedAccnt = await connection.handleCallback(body); // whether we should emit a connections update event, only used when a connection doesnt already exist - if (emit) + if (connectedAccnt) emitEvent({ event: "USER_CONNECTIONS_UPDATE", - data: {}, + data: connectedAccnt, user_id: userId, }); + res.sendStatus(204); }, ); diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index 1b725afd..5bbfefe9 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,5 +1,5 @@ import fetch from "node-fetch"; -import { Config, ConnectionCallbackSchema, DiscordApiErrors } from "../../util"; +import { Config, ConnectedAccount, ConnectionCallbackSchema, DiscordApiErrors } from "../../util"; import Connection from "../../util/connections/Connection"; import { ConnectionLoader } from "../../util/connections/ConnectionLoader"; import { BattleNetSettings } from "./BattleNetSettings"; @@ -46,8 +46,7 @@ export default class BattleNetConnection extends Connection { // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. url.searchParams.append( "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" + `${Config.get().cdn.endpointPrivate || "http://localhost:3001" }/connections/${this.id}/callback`, ); url.searchParams.append("scope", this.scopes.join(" ")); @@ -75,9 +74,8 @@ export default class BattleNetConnection extends Connection { code: code, client_id: this.settings.clientId!, client_secret: this.settings.clientSecret!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: `${Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, }), }) .then((res) => res.json()) @@ -108,21 +106,21 @@ export default class BattleNetConnection extends Connection { }); } - async handleCallback(params: ConnectionCallbackSchema): Promise { + async handleCallback(params: ConnectionCallbackSchema): Promise { const userId = this.getUserId(params.state); const token = await this.exchangeCode(params.state, params.code!); const userInfo = await this.getUser(token); const exists = await this.hasConnection(userId, userInfo.id.toString()); - if (exists) return false; - await this.createConnection({ + if (exists) return null; + + return await this.createConnection({ user_id: userId, external_id: userInfo.id.toString(), friend_sync: params.friend_sync, name: userInfo.battletag, type: this.id, }); - return true; } } diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index 41806a67..fc44ff9d 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,5 +1,5 @@ import fetch from "node-fetch"; -import { Config, ConnectionCallbackSchema, DiscordApiErrors } from "../../util"; +import { Config, ConnectedAccount, ConnectionCallbackSchema, DiscordApiErrors } from "../../util"; import Connection from "../../util/connections/Connection"; import { ConnectionLoader } from "../../util/connections/ConnectionLoader"; import { GitHubSettings } from "./GitHubSettings"; @@ -89,21 +89,21 @@ export default class GitHubConnection extends Connection { }).then((res) => res.json()); } - async handleCallback(params: ConnectionCallbackSchema): Promise { + async handleCallback(params: ConnectionCallbackSchema): Promise { const userId = this.getUserId(params.state); const token = await this.exchangeCode(params.state, params.code!); const userInfo = await this.getUser(token); const exists = await this.hasConnection(userId, userInfo.id.toString()); - if (exists) return false; - await this.createConnection({ + if (exists) return null; + + return await this.createConnection({ user_id: userId, external_id: userInfo.id.toString(), friend_sync: params.friend_sync, name: userInfo.name, type: this.id, }); - return true; } } diff --git a/src/util/connections/Connection.ts b/src/util/connections/Connection.ts index e8d41c36..164cfac7 100644 --- a/src/util/connections/Connection.ts +++ b/src/util/connections/Connection.ts @@ -21,7 +21,7 @@ export default abstract class Connection { * Processes the callback * @param args Callback arguments */ - abstract handleCallback(params: ConnectionCallbackSchema): Promise; + abstract handleCallback(params: ConnectionCallbackSchema): Promise; /** * Gets a user id from state @@ -54,9 +54,10 @@ export default abstract class Connection { this.states.delete(state); } - async createConnection(data: ConnectedAccountSchema): Promise { - const ca = OrmUtils.mergeDeep(new ConnectedAccount(), data); + async createConnection(data: ConnectedAccountSchema): Promise { + const ca = OrmUtils.mergeDeep(new ConnectedAccount(), data) as ConnectedAccount; await ca.save(); + return ca; } async hasConnection(userId: string, externalId: string): Promise { From 5491c58ffc83a3172a400eb2764b34cdf7265aa5 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 12:45:03 +1100 Subject: [PATCH 05/58] Don't use mergeDeep --- .../connections/#connection_name/#connection_id/index.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts index 76eb9936..3138d872 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts @@ -1,10 +1,6 @@ import { route } from "@fosscord/api"; +import { ConnectedAccount, DiscordApiErrors } from "@fosscord/util"; import { Request, Response, Router } from "express"; -import { - ConnectedAccount, - DiscordApiErrors, - OrmUtils, -} from "../../../../../../../util"; const router = Router(); // TODO: connection update schema @@ -35,7 +31,7 @@ router.patch( if (!connection) return DiscordApiErrors.UNKNOWN_CONNECTION; // TODO: do we need to do anything if the connection is revoked? - OrmUtils.mergeDeep(connection, req.body); + connection.assign(req.body); await ConnectedAccount.update( { user_id: req.user_id, From 2364096a97ba66949cc3b7fbc5b9fb68977ff3ca Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 12:46:03 +1100 Subject: [PATCH 06/58] entities/ConnectionUpdateSchema -> schemas/ConnectionUpdateSchema --- assets/schemas.json | 597 +++++++++++++++++- .../connections/#connection_name/authorize.ts | 5 +- src/util/entities/index.ts | 1 - .../ConnectionUpdateSchema.ts | 0 src/util/schemas/index.ts | 1 + 5 files changed, 590 insertions(+), 14 deletions(-) rename src/util/{entities => schemas}/ConnectionUpdateSchema.ts (100%) diff --git a/assets/schemas.json b/assets/schemas.json index 881560dd..fe4fcea3 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -36,16 +36,6 @@ ], "$schema": "http://json-schema.org/draft-07/schema#" }, - "ConnectionUpdateSchema": { - "type": "object", - "properties": { - "visibility": { - "type": "boolean" - } - }, - "additionalProperties": false, - "$schema": "http://json-schema.org/draft-07/schema#" - }, "SMTPConnection.CustomAuthenticationResponse": { "type": "object", "properties": { @@ -4035,6 +4025,593 @@ }, "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectionUpdateSchema": { + "type": "object", + "properties": { + "visibility": { + "type": "boolean" + } + }, + "additionalProperties": false, + "definitions": { + "ChannelPermissionOverwriteType": { + "enum": [ + 0, + 1, + 2 + ], + "type": "number" + }, + "ChannelModifySchema": { + "type": "object", + "properties": { + "name": { + "maxLength": 100, + "type": "string" + }, + "type": { + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 14, + 15, + 2, + 255, + 3, + 33, + 34, + 35, + 4, + 5, + 6, + 64, + 7, + 8, + 9 + ], + "type": "number" + }, + "topic": { + "type": "string" + }, + "icon": { + "type": [ + "null", + "string" + ] + }, + "bitrate": { + "type": "integer" + }, + "user_limit": { + "type": "integer" + }, + "rate_limit_per_user": { + "type": "integer" + }, + "position": { + "type": "integer" + }, + "permission_overwrites": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ChannelPermissionOverwriteType" + }, + "allow": { + "type": "string" + }, + "deny": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "allow", + "deny", + "id", + "type" + ] + } + }, + "parent_id": { + "type": "string" + }, + "id": { + "type": "string" + }, + "nsfw": { + "type": "boolean" + }, + "rtc_region": { + "type": "string" + }, + "default_auto_archive_duration": { + "type": "integer" + }, + "default_reaction_emoji": { + "type": [ + "null", + "string" + ] + }, + "flags": { + "type": "integer" + }, + "default_thread_rate_limit_per_user": { + "type": "integer" + }, + "video_quality_mode": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "ActivitySchema": { + "type": "object", + "properties": { + "afk": { + "type": "boolean" + }, + "status": { + "$ref": "#/definitions/Status" + }, + "activities": { + "type": "array", + "items": { + "$ref": "#/definitions/Activity" + } + }, + "since": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "status" + ] + }, + "Status": { + "enum": [ + "dnd", + "idle", + "invisible", + "offline", + "online" + ], + "type": "string" + }, + "Activity": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ActivityType" + }, + "url": { + "type": "string" + }, + "created_at": { + "type": "integer" + }, + "timestamps": { + "type": "object", + "properties": { + "start": { + "type": "integer" + }, + "end": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end", + "start" + ] + }, + "application_id": { + "type": "string" + }, + "details": { + "type": "string" + }, + "state": { + "type": "string" + }, + "emoji": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "animated": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "animated", + "name" + ] + }, + "party": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "size": { + "type": "array", + "items": [ + { + "type": "integer" + } + ], + "minItems": 1, + "maxItems": 1 + } + }, + "additionalProperties": false + }, + "assets": { + "type": "object", + "properties": { + "large_image": { + "type": "string" + }, + "large_text": { + "type": "string" + }, + "small_image": { + "type": "string" + }, + "small_text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "secrets": { + "type": "object", + "properties": { + "join": { + "type": "string" + }, + "spectate": { + "type": "string" + }, + "match": { + "type": "string" + } + }, + "additionalProperties": false + }, + "instance": { + "type": "boolean" + }, + "flags": { + "type": "string" + }, + "id": { + "type": "string" + }, + "sync_id": { + "type": "string" + }, + "metadata": { + "type": "object", + "properties": { + "context_uri": { + "type": "string" + }, + "album_id": { + "type": "string" + }, + "artist_ids": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "album_id", + "artist_ids" + ] + }, + "session_id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "flags", + "name", + "session_id", + "type" + ] + }, + "ActivityType": { + "enum": [ + 0, + 1, + 2, + 4, + 5 + ], + "type": "number" + }, + "Record": { + "type": "object", + "additionalProperties": false + }, + "Embed": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "type": { + "enum": [ + "article", + "gifv", + "image", + "link", + "rich", + "video" + ], + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "color": { + "type": "integer" + }, + "footer": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "text" + ] + }, + "image": { + "$ref": "#/definitions/EmbedImage" + }, + "thumbnail": { + "$ref": "#/definitions/EmbedImage" + }, + "video": { + "$ref": "#/definitions/EmbedImage" + }, + "provider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "author": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "inline": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "name", + "value" + ] + } + } + }, + "additionalProperties": false + }, + "EmbedImage": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "proxy_url": { + "type": "string" + }, + "height": { + "type": "integer" + }, + "width": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "Partial": { + "type": "object", + "properties": { + "message_notifications": { + "type": "integer" + }, + "mute_config": { + "$ref": "#/definitions/MuteConfig" + }, + "muted": { + "type": "boolean" + }, + "channel_id": { + "type": [ + "null", + "string" + ] + } + }, + "additionalProperties": false + }, + "MuteConfig": { + "type": "object", + "properties": { + "end_time": { + "type": "integer" + }, + "selected_time_window": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end_time", + "selected_time_window" + ] + }, + "CustomStatus": { + "type": "object", + "properties": { + "emoji_id": { + "type": "string" + }, + "emoji_name": { + "type": "string" + }, + "expires_at": { + "type": "integer" + }, + "text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "FriendSourceFlags": { + "type": "object", + "properties": { + "all": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "all" + ] + }, + "GuildFolder": { + "type": "object", + "properties": { + "color": { + "type": "integer" + }, + "guild_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "color", + "guild_ids", + "id", + "name" + ] + }, + "Partial": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Partial": { + "type": "object", + "properties": { + "credential": { + "type": "string" + }, + "name": { + "type": "string" + }, + "ticket": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" + }, "DmChannelCreateSchema": { "type": "object", "properties": { diff --git a/src/api/routes/connections/#connection_name/authorize.ts b/src/api/routes/connections/#connection_name/authorize.ts index 5ce420cf..5c24dc7c 100644 --- a/src/api/routes/connections/#connection_name/authorize.ts +++ b/src/api/routes/connections/#connection_name/authorize.ts @@ -1,7 +1,6 @@ +import { route } from "@fosscord/api"; import { Request, Response, Router } from "express"; -import { FieldErrors } from "../../../../util"; -import { ConnectionStore } from "../../../../util/connections"; -import { route } from "../../../util"; +import { ConnectionStore, FieldErrors } from "../../../../util"; const router = Router(); diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts index b4e3ecd0..ad34f67b 100644 --- a/src/util/entities/index.ts +++ b/src/util/entities/index.ts @@ -28,7 +28,6 @@ export * from "./ClientRelease"; export * from "./Config"; export * from "./ConnectedAccount"; export * from "./ConnectionConfigEntity"; -export * from "./ConnectionUpdateSchema"; export * from "./EmbedCache"; export * from "./Emoji"; export * from "./Encryption"; diff --git a/src/util/entities/ConnectionUpdateSchema.ts b/src/util/schemas/ConnectionUpdateSchema.ts similarity index 100% rename from src/util/entities/ConnectionUpdateSchema.ts rename to src/util/schemas/ConnectionUpdateSchema.ts diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts index 71b4c2ce..e9f4268e 100644 --- a/src/util/schemas/index.ts +++ b/src/util/schemas/index.ts @@ -32,6 +32,7 @@ export * from "./ChannelReorderSchema"; export * from "./CodesVerificationSchema"; export * from "./ConnectedAccountSchema"; export * from "./ConnectionCallbackSchema"; +export * from "./ConnectionUpdateSchema"; export * from "./DmChannelCreateSchema"; export * from "./EmojiCreateSchema"; export * from "./EmojiModifySchema"; From a390596e3c47e22563782d3ad20d375d2f0a0bf4 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 12:46:33 +1100 Subject: [PATCH 07/58] Follow Discord docs for `visibility` and `metadata_visibility` fields in ConnectedAccount --- src/util/entities/ConnectedAccount.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 714faf0c..25d5a0c7 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -62,7 +62,7 @@ export class ConnectedAccount extends BaseClass { verified?: boolean = true; @Column({ select: false }) - visibility?: boolean = false; + visibility?: number = 0; @Column({ type: "simple-array" }) integrations?: string[] = []; @@ -71,7 +71,7 @@ export class ConnectedAccount extends BaseClass { metadata_?: any; @Column() - metadata_visibility?: boolean = false; + metadata_visibility?: number = 0; @Column() two_way_link?: boolean = false; From 8ff3767d3232fef9ad3c543af8b16a13a999fac0 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 13:05:37 +1100 Subject: [PATCH 08/58] Fix ConnectionLoader from throwing when uploading default config keys --- src/util/connections/ConnectionLoader.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/util/connections/ConnectionLoader.ts b/src/util/connections/ConnectionLoader.ts index 7467739c..04d7752a 100644 --- a/src/util/connections/ConnectionLoader.ts +++ b/src/util/connections/ConnectionLoader.ts @@ -34,9 +34,11 @@ export class ConnectionLoader { public static getConnectionConfig(id: string, defaults?: any): any { let cfg = ConnectionConfig.get()[id]; if (defaults) { - if (cfg) cfg = OrmUtils.mergeDeep(defaults, cfg); - else cfg = defaults; - this.setConnectionConfig(id, cfg); + if (cfg) cfg = Object.assign({}, defaults, cfg); + else { + cfg = defaults; + this.setConnectionConfig(id, cfg); + } } if (!cfg) @@ -55,12 +57,8 @@ export class ConnectionLoader { `[ConnectionConfig/WARN] ${id} tried to set config=null!`, ); - const a = { - [id]: OrmUtils.mergeDeep( - ConnectionLoader.getConnectionConfig(id) || {}, - config, - ), - }; - await ConnectionConfig.set(a); + await ConnectionConfig.set({ + [id]: Object.assign(config, (ConnectionLoader.getConnectionConfig(id) || {})) + }); } } From d76198d2009f9ddf96aa219d1d0652bc6cb393bb Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 13:56:33 +1100 Subject: [PATCH 09/58] WIP Discord connection --- src/connections/Discord/DiscordSettings.ts | 5 + src/connections/Discord/index.ts | 118 +++++++++++++++++++++ src/util/index.ts | 2 +- 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/connections/Discord/DiscordSettings.ts create mode 100644 src/connections/Discord/index.ts diff --git a/src/connections/Discord/DiscordSettings.ts b/src/connections/Discord/DiscordSettings.ts new file mode 100644 index 00000000..a8976f12 --- /dev/null +++ b/src/connections/Discord/DiscordSettings.ts @@ -0,0 +1,5 @@ +export class DiscordSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} \ No newline at end of file diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts new file mode 100644 index 00000000..5a89860e --- /dev/null +++ b/src/connections/Discord/index.ts @@ -0,0 +1,118 @@ +import fetch from "node-fetch"; +import { + Config, + ConnectedAccount, + ConnectionCallbackSchema, + DiscordApiErrors, + ConnectionLoader, +} from "@fosscord/util"; +import Connection from "../../util/connections/Connection"; +import { DiscordSettings } from "./DiscordSettings"; + +interface OAuthTokenResponse { + access_token: string; + token_type: string; + scope: string; + refresh_token?: string; + expires_in?: number; +} + +interface UserResponse { + id: string; + username: string; + avatar_url: string | null; +} + +export default class DiscordConnection extends Connection { + public readonly id = "discord"; + public readonly authorizeUrl = "https://discord.com/oauth2/authorize"; + public readonly tokenUrl = "https://discord.com/oauth2/token"; + public readonly userInfoUrl = "https://discord.com/api/users/@me"; + public readonly scopes = ["identify"]; + settings: DiscordSettings = new DiscordSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as DiscordSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("state", state); + url.searchParams.append("client_id", this.settings.clientId!); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("response_type", "code"); + // controls whether, on repeated authorizations, the consent screen is shown + url.searchParams.append("consent", "none"); + + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + + return url.toString(); + } + + getTokenUrl(code: string): string { + const url = new URL(this.tokenUrl); + url.searchParams.append("client_id", this.settings.clientId!); + url.searchParams.append("client_secret", this.settings.clientSecret!); + url.searchParams.append("grant_type", "authorization_code"); + url.searchParams.append("code", code); + return url.toString(); + } + + async exchangeCode(state: string, code: string): Promise { + this.validateState(state); + const url = this.getTokenUrl(code); + + return fetch(url, { + method: "POST", + headers: { + Accept: "application/json", + }, + }) + .then((res) => res.json()) + .then((res: OAuthTokenResponse) => res.access_token) + .catch((e) => { + console.error( + `Error exchanging token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }).then((res) => res.json()); + } + + async handleCallback(params: ConnectionCallbackSchema): Promise { + const userId = this.getUserId(params.state); + const token = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(token); + + const exists = await this.hasConnection(userId, userInfo.id); + + if (exists) return null; + + return await this.createConnection({ + user_id: userId, + external_id: userInfo.id, + friend_sync: params.friend_sync, + name: userInfo.username, + type: this.id, + }) + } +} \ No newline at end of file diff --git a/src/util/index.ts b/src/util/index.ts index cb180ee8..9c0f7881 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -25,4 +25,4 @@ export * from "./dtos/index"; export * from "./schemas"; export * from "./imports"; export * from "./config"; -export * from "./connections" \ No newline at end of file +export * from "./connections" From d12751006e98ef11f3bec8f45fd50d91c2cb4a10 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 21:15:38 -0500 Subject: [PATCH 10/58] add epic games connection --- src/connections/BattleNet/index.ts | 23 ++- .../EpicGames/EpicGamesSettings.ts | 5 + src/connections/EpicGames/index.ts | 135 ++++++++++++++++++ src/connections/GitHub/index.ts | 13 +- 4 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 src/connections/EpicGames/EpicGamesSettings.ts create mode 100644 src/connections/EpicGames/index.ts diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index 5bbfefe9..f4b317cc 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,7 +1,12 @@ +import { + Config, + ConnectedAccount, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; import fetch from "node-fetch"; -import { Config, ConnectedAccount, ConnectionCallbackSchema, DiscordApiErrors } from "../../util"; import Connection from "../../util/connections/Connection"; -import { ConnectionLoader } from "../../util/connections/ConnectionLoader"; import { BattleNetSettings } from "./BattleNetSettings"; interface OAuthTokenResponse { @@ -46,7 +51,8 @@ export default class BattleNetConnection extends Connection { // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. url.searchParams.append( "redirect_uri", - `${Config.get().cdn.endpointPrivate || "http://localhost:3001" + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" }/connections/${this.id}/callback`, ); url.searchParams.append("scope", this.scopes.join(" ")); @@ -74,8 +80,9 @@ export default class BattleNetConnection extends Connection { code: code, client_id: this.settings.clientId!, client_secret: this.settings.clientSecret!, - redirect_uri: `${Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, }), }) .then((res) => res.json()) @@ -106,7 +113,9 @@ export default class BattleNetConnection extends Connection { }); } - async handleCallback(params: ConnectionCallbackSchema): Promise { + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { const userId = this.getUserId(params.state); const token = await this.exchangeCode(params.state, params.code!); const userInfo = await this.getUser(token); @@ -114,7 +123,7 @@ export default class BattleNetConnection extends Connection { const exists = await this.hasConnection(userId, userInfo.id.toString()); if (exists) return null; - + return await this.createConnection({ user_id: userId, external_id: userInfo.id.toString(), diff --git a/src/connections/EpicGames/EpicGamesSettings.ts b/src/connections/EpicGames/EpicGamesSettings.ts new file mode 100644 index 00000000..4820a88a --- /dev/null +++ b/src/connections/EpicGames/EpicGamesSettings.ts @@ -0,0 +1,5 @@ +export class EpicGamesSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts new file mode 100644 index 00000000..cffafc60 --- /dev/null +++ b/src/connections/EpicGames/index.ts @@ -0,0 +1,135 @@ +import { + Config, + ConnectedAccount, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; +import fetch from "node-fetch"; +import Connection from "../../util/connections/Connection"; +import { EpicGamesSettings } from "./EpicGamesSettings"; + +interface OAuthTokenResponse { + access_token: string; + token_type: string; + scope: string; + refresh_token?: string; + expires_in?: number; +} + +export interface UserResponse { + accountId: string; + displayName: string; + preferredLanguage: string; +} + +export interface EpicTokenResponse extends OAuthTokenResponse { + expires_at: string; + refresh_expires_in: number; + refresh_expires_at: string; + account_id: string; + client_id: string; + application_id: string; +} + +export default class EpicGamesConnection extends Connection { + public readonly id = "epicgames"; + public readonly authorizeUrl = "https://www.epicgames.com/id/authorize"; + public readonly tokenUrl = "https://api.epicgames.dev/epic/oauth/v1/token"; + public readonly userInfoUrl = + "https://api.epicgames.dev/epic/id/v1/accounts"; + public readonly scopes = ["basic profile"]; + settings: EpicGamesSettings = new EpicGamesSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as EpicGamesSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("response_type", "code"); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + return url.toString(); + } + + getTokenUrl(): string { + return this.tokenUrl; + } + + async exchangeCode(state: string, code: string): Promise { + this.validateState(state); + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + Authorization: `Basic ${Buffer.from( + `${this.settings.clientId}:${this.settings.clientSecret}`, + ).toString("base64")}`, + "Content-Type": "application/x-www-form-urlencoded", + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code, + }), + }) + .then((res) => res.json()) + .then((res: EpicTokenResponse) => res.access_token) + .catch((e) => { + console.error( + `Error exchanging token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + }); + } + + async getUser(token: string): Promise { + const { sub } = JSON.parse( + Buffer.from(token.split(".")[1], "base64").toString("utf8"), + ); + const url = new URL(this.userInfoUrl); + url.searchParams.append("accountId", sub); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }).then((res) => res.json()); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { + const userId = this.getUserId(params.state); + const token = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(token); + + const exists = await this.hasConnection(userId, userInfo[0].accountId); + + if (exists) return null; + + return await this.createConnection({ + user_id: userId, + external_id: userInfo[0].accountId, + friend_sync: params.friend_sync, + name: userInfo[0].displayName, + type: this.id, + }); + } +} diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index fc44ff9d..5f255e66 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,7 +1,12 @@ +import { + Config, + ConnectedAccount, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; import fetch from "node-fetch"; -import { Config, ConnectedAccount, ConnectionCallbackSchema, DiscordApiErrors } from "../../util"; import Connection from "../../util/connections/Connection"; -import { ConnectionLoader } from "../../util/connections/ConnectionLoader"; import { GitHubSettings } from "./GitHubSettings"; interface OAuthTokenResponse { @@ -89,7 +94,9 @@ export default class GitHubConnection extends Connection { }).then((res) => res.json()); } - async handleCallback(params: ConnectionCallbackSchema): Promise { + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { const userId = this.getUserId(params.state); const token = await this.exchangeCode(params.state, params.code!); const userInfo = await this.getUser(token); From 901d126d6b6908c4c7b6fa4a19ec1ae08b866a7f Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 21:23:55 -0500 Subject: [PATCH 11/58] Add facebook connection --- src/connections/Facebook/FacebookSettings.ts | 5 + src/connections/Facebook/index.ts | 142 +++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 src/connections/Facebook/FacebookSettings.ts create mode 100644 src/connections/Facebook/index.ts diff --git a/src/connections/Facebook/FacebookSettings.ts b/src/connections/Facebook/FacebookSettings.ts new file mode 100644 index 00000000..cc3e3402 --- /dev/null +++ b/src/connections/Facebook/FacebookSettings.ts @@ -0,0 +1,5 @@ +export class FacebookSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts new file mode 100644 index 00000000..80950a8e --- /dev/null +++ b/src/connections/Facebook/index.ts @@ -0,0 +1,142 @@ +import { + Config, + ConnectedAccount, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; +import fetch from "node-fetch"; +import Connection from "../../util/connections/Connection"; +import { FacebookSettings } from "./FacebookSettings"; + +interface OAuthTokenResponse { + access_token: string; + token_type: string; + scope: string; + refresh_token?: string; + expires_in?: number; +} + +export interface FacebookErrorResponse { + error: { + message: string; + type: string; + code: number; + fbtrace_id: string; + }; +} + +interface UserResponse { + name: string; + id: string; +} + +export default class FacebookConnection extends Connection { + public readonly id = "facebook"; + public readonly authorizeUrl = + "https://www.facebook.com/v14.0/dialog/oauth"; + public readonly tokenUrl = + "https://graph.facebook.com/v14.0/oauth/access_token"; + public readonly userInfoUrl = "https://graph.facebook.com/v14.0/me"; + public readonly scopes = ["public_profile"]; + settings: FacebookSettings = new FacebookSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as FacebookSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("state", state); + url.searchParams.append("response_type", "code"); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("display", "popup"); + return url.toString(); + } + + getTokenUrl(code: string): string { + const url = new URL(this.tokenUrl); + url.searchParams.append("client_id", this.settings.clientId!); + url.searchParams.append("client_secret", this.settings.clientSecret!); + url.searchParams.append("code", code); + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + return url.toString(); + } + + async exchangeCode(state: string, code: string): Promise { + this.validateState(state); + + const url = this.getTokenUrl(code); + + return fetch(url.toString(), { + method: "GET", + headers: { + Accept: "application/json", + }, + }) + .then((res) => res.json()) + .then((res: OAuthTokenResponse & FacebookErrorResponse) => { + if (res.error) throw new Error(res.error.message); + return res.access_token; + }) + .catch((e) => { + console.error( + `Error exchanging token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => res.json()) + .then((res: UserResponse & FacebookErrorResponse) => { + if (res.error) throw new Error(res.error.message); + return res; + }); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { + const userId = this.getUserId(params.state); + const token = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(token); + + const exists = await this.hasConnection(userId, userInfo.id); + + if (exists) return null; + + return await this.createConnection({ + user_id: userId, + external_id: userInfo.id, + friend_sync: params.friend_sync, + name: userInfo.name, + type: this.id, + }); + } +} From ab4a28ee31ceb3659347be4d7c637514a758d61a Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 21:32:08 -0500 Subject: [PATCH 12/58] Add reddit connection --- src/connections/Reddit/RedditSettings.ts | 5 + src/connections/Reddit/index.ts | 140 +++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 src/connections/Reddit/RedditSettings.ts create mode 100644 src/connections/Reddit/index.ts diff --git a/src/connections/Reddit/RedditSettings.ts b/src/connections/Reddit/RedditSettings.ts new file mode 100644 index 00000000..13208fb5 --- /dev/null +++ b/src/connections/Reddit/RedditSettings.ts @@ -0,0 +1,5 @@ +export class RedditSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts new file mode 100644 index 00000000..c529cfa3 --- /dev/null +++ b/src/connections/Reddit/index.ts @@ -0,0 +1,140 @@ +import { + Config, + ConnectedAccount, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; +import fetch from "node-fetch"; +import Connection from "../../util/connections/Connection"; +import { RedditSettings } from "./RedditSettings"; + +interface OAuthTokenResponse { + access_token: string; + token_type: string; + scope: string; + refresh_token?: string; + expires_in?: number; +} + +export interface UserResponse { + verified: boolean; + coins: number; + id: string; + is_mod: boolean; + has_verified_email: boolean; + total_karma: number; + name: string; + created: number; + gold_creddits: number; + created_utc: number; +} + +export interface ErrorResponse { + message: string; + error: number; +} + +export default class RedditConnection extends Connection { + public readonly id = "reddit"; + public readonly authorizeUrl = "https://www.reddit.com/api/v1/authorize"; + public readonly tokenUrl = "https://www.reddit.com/api/v1/access_token"; + public readonly userInfoUrl = "https://oauth.reddit.com/api/v1/me"; + public readonly scopes = ["identity"]; + settings: RedditSettings = new RedditSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as RedditSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("response_type", "code"); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + return url.toString(); + } + + getTokenUrl(): string { + return this.tokenUrl; + } + + async exchangeCode(state: string, code: string): Promise { + this.validateState(state); + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + Authorization: `Basic ${Buffer.from( + `${this.settings.clientId}:${this.settings.clientSecret}`, + ).toString("base64")}`, + "Content-Type": "application/x-www-form-urlencoded", + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code: code, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + }) + .then((res) => res.json()) + .then((res: OAuthTokenResponse) => res.access_token) + .catch((e) => { + console.error( + `Error exchanging token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }).then((res) => res.json()); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { + const userId = this.getUserId(params.state); + const token = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(token); + + const exists = await this.hasConnection(userId, userInfo.id.toString()); + + if (exists) return null; + + // TODO: connection metadata + + return await this.createConnection({ + access_token: token, + user_id: userId, + external_id: userInfo.id.toString(), + friend_sync: params.friend_sync, + name: userInfo.name, + verified: userInfo.has_verified_email, + type: this.id, + }); + } +} From 3c7cde5985a96d2a841419a7fb439cf73cd68fe1 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 21:55:24 -0500 Subject: [PATCH 13/58] Add spotify connection --- src/connections/Spotify/SpotifySettings.ts | 5 + src/connections/Spotify/index.ts | 148 +++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/connections/Spotify/SpotifySettings.ts create mode 100644 src/connections/Spotify/index.ts diff --git a/src/connections/Spotify/SpotifySettings.ts b/src/connections/Spotify/SpotifySettings.ts new file mode 100644 index 00000000..e73c0304 --- /dev/null +++ b/src/connections/Spotify/SpotifySettings.ts @@ -0,0 +1,5 @@ +export class SpotifySettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts new file mode 100644 index 00000000..eb662141 --- /dev/null +++ b/src/connections/Spotify/index.ts @@ -0,0 +1,148 @@ +import { + Config, + ConnectedAccount, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; +import fetch from "node-fetch"; +import Connection from "../../util/connections/Connection"; +import { SpotifySettings } from "./SpotifySettings"; + +interface OAuthTokenResponse { + access_token: string; + token_type: string; + scope: string; + refresh_token?: string; + expires_in?: number; +} + +export interface UserResponse { + display_name: string; + id: string; +} + +export interface TokenErrorResponse { + error: string; + error_description: string; +} + +export interface ErrorResponse { + error: { + status: number; + message: string; + }; +} + +export default class SpotifyConnection extends Connection { + public readonly id = "spotify"; + public readonly authorizeUrl = "https://accounts.spotify.com/authorize"; + public readonly tokenUrl = "https://accounts.spotify.com/api/token"; + public readonly userInfoUrl = "https://api.spotify.com/v1/me"; + public readonly scopes = [ + "user-read-private", + "user-read-playback-state", + "user-modify-playback-state", + "user-read-currently-playing", + ]; + settings: SpotifySettings = new SpotifySettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as SpotifySettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("response_type", "code"); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + return url.toString(); + } + + getTokenUrl(): string { + return this.tokenUrl; + } + + async exchangeCode(state: string, code: string): Promise { + this.validateState(state); + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `Basic ${Buffer.from( + `${this.settings.clientId!}:${this.settings.clientSecret!}`, + ).toString("base64")}`, + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code: code, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + }) + .then((res) => res.json()) + .then((res: OAuthTokenResponse & TokenErrorResponse) => { + if (res.error) throw new Error(res.error_description); + return res.access_token; + }) + .catch((e) => { + console.error( + `Error exchanging token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => res.json()) + .then((res: UserResponse & ErrorResponse) => { + if (res.error) throw new Error(res.error.message); + return res; + }); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { + const userId = this.getUserId(params.state); + const token = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(token); + + const exists = await this.hasConnection(userId, userInfo.id); + + if (exists) return null; + + return await this.createConnection({ + user_id: userId, + external_id: userInfo.id, + friend_sync: params.friend_sync, + name: userInfo.display_name, + type: this.id, + }); + } +} From 747ff5d3227f87a8c2744e74dc4d8891f748b07d Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 22:46:28 -0500 Subject: [PATCH 14/58] fix discord connection --- src/connections/Discord/index.ts | 40 +++++++++++++++++++------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 5a89860e..11f98750 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -1,11 +1,11 @@ -import fetch from "node-fetch"; import { Config, ConnectedAccount, ConnectionCallbackSchema, - DiscordApiErrors, ConnectionLoader, + DiscordApiErrors, } from "@fosscord/util"; +import fetch from "node-fetch"; import Connection from "../../util/connections/Connection"; import { DiscordSettings } from "./DiscordSettings"; @@ -25,8 +25,8 @@ interface UserResponse { export default class DiscordConnection extends Connection { public readonly id = "discord"; - public readonly authorizeUrl = "https://discord.com/oauth2/authorize"; - public readonly tokenUrl = "https://discord.com/oauth2/token"; + public readonly authorizeUrl = "https://discord.com/api/oauth2/authorize"; + public readonly tokenUrl = "https://discord.com/api/oauth2/token"; public readonly userInfoUrl = "https://discord.com/api/users/@me"; public readonly scopes = ["identify"]; settings: DiscordSettings = new DiscordSettings(); @@ -52,31 +52,37 @@ export default class DiscordConnection extends Connection { // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. url.searchParams.append( "redirect_uri", - `${Config.get().cdn.endpointPrivate || "http://localhost:3001" + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" }/connections/${this.id}/callback`, ); return url.toString(); } - getTokenUrl(code: string): string { - const url = new URL(this.tokenUrl); - url.searchParams.append("client_id", this.settings.clientId!); - url.searchParams.append("client_secret", this.settings.clientSecret!); - url.searchParams.append("grant_type", "authorization_code"); - url.searchParams.append("code", code); - return url.toString(); + getTokenUrl(): string { + return this.tokenUrl; } async exchangeCode(state: string, code: string): Promise { this.validateState(state); - const url = this.getTokenUrl(code); + const url = this.getTokenUrl(); return fetch(url, { method: "POST", headers: { Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", }, + body: new URLSearchParams({ + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + grant_type: "authorization_code", + code: code, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + }), }) .then((res) => res.json()) .then((res: OAuthTokenResponse) => res.access_token) @@ -98,7 +104,9 @@ export default class DiscordConnection extends Connection { }).then((res) => res.json()); } - async handleCallback(params: ConnectionCallbackSchema): Promise { + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { const userId = this.getUserId(params.state); const token = await this.exchangeCode(params.state, params.code!); const userInfo = await this.getUser(token); @@ -113,6 +121,6 @@ export default class DiscordConnection extends Connection { friend_sync: params.friend_sync, name: userInfo.username, type: this.id, - }) + }); } -} \ No newline at end of file +} From 2bae8429269d72bca492cc076e99dfaa7cbd5a62 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 20:02:26 +1100 Subject: [PATCH 15/58] Delete connections --- .../#connection_name/#connection_id/index.ts | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts index 3138d872..84863f6a 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts @@ -1,5 +1,5 @@ import { route } from "@fosscord/api"; -import { ConnectedAccount, DiscordApiErrors } from "@fosscord/util"; +import { ConnectedAccount, DiscordApiErrors, emitEvent } from "@fosscord/util"; import { Request, Response, Router } from "express"; const router = Router(); @@ -44,4 +44,27 @@ router.patch( }, ); +router.delete("/", route({}), async (req: Request, res: Response) => { + const { connection_name, connection_id } = req.params; + + const account = await ConnectedAccount.findOneOrFail({ + where: { + user_id: req.user_id, + external_id: connection_id, + type: connection_name, + } + }); + + await Promise.all([ + ConnectedAccount.remove(account), + emitEvent({ + event: "USER_CONNECTIONS_UPDATE", + data: account, + user_id: req.user_id, + }) + ]); + + return res.sendStatus(200); +}); + export default router; From 3f9887d8559341b476fe11d4488bc818491dd5a0 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 20:06:50 +1100 Subject: [PATCH 16/58] Add discriminator usernames for Discord connection --- src/connections/Discord/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 11f98750..05074c26 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -20,6 +20,7 @@ interface OAuthTokenResponse { interface UserResponse { id: string; username: string; + discriminator: string; avatar_url: string | null; } @@ -119,7 +120,7 @@ export default class DiscordConnection extends Connection { user_id: userId, external_id: userInfo.id, friend_sync: params.friend_sync, - name: userInfo.username, + name: `${userInfo.username}#${userInfo.discriminator}`, type: this.id, }); } From 42b2237d0f11b229340ffd2b7244e0b05515949d Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 20:08:23 +1100 Subject: [PATCH 17/58] Switch from Github real name to username for GH connection --- src/connections/GitHub/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index 5f255e66..d79fd51e 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -109,7 +109,7 @@ export default class GitHubConnection extends Connection { user_id: userId, external_id: userInfo.id.toString(), friend_sync: params.friend_sync, - name: userInfo.name, + name: userInfo.login, type: this.id, }); } From 50f068400d4690930153486de3c03410e877338a Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 20:32:19 +1100 Subject: [PATCH 18/58] Don't try to upload entire config for each connection loaded --- src/util/connections/ConnectionConfig.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/connections/ConnectionConfig.ts b/src/util/connections/ConnectionConfig.ts index dd372ff7..acbca026 100644 --- a/src/util/connections/ConnectionConfig.ts +++ b/src/util/connections/ConnectionConfig.ts @@ -22,7 +22,8 @@ export const ConnectionConfig = { if (!config || !val) return; config = val.merge(config); - return applyConfig(config); + // return applyConfig(config); + return applyConfig(val); }, }; From 0db1fa5f0b2b9b357c1f96178c0e5df7858a99ab Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Fri, 23 Dec 2022 18:34:36 -0500 Subject: [PATCH 19/58] Refreshable connections, refactoring, access-token endpoint - Aded /users/@me/connections/:connection_name/:connection_id/access-token - Replaced `access_token` property on ConnectedAccount with `token_data` object for refreshing tokens - Made a common interface for connection things like ComonOAuthTokenResponse - Added `RefreshableConnection` class - Added token refresh to Spotify connection (disabled) --- .../#connection_id/access-token.ts | 84 +++++++++++++++++++ src/api/routes/users/@me/connections/index.ts | 2 +- src/connections/BattleNet/index.ts | 31 +++---- src/connections/Discord/index.ts | 19 ++--- src/connections/EpicGames/index.ts | 22 ++--- src/connections/Facebook/index.ts | 31 +++---- src/connections/GitHub/index.ts | 19 ++--- src/connections/Reddit/index.ts | 20 ++--- src/connections/Spotify/index.ts | 79 +++++++++++++---- src/util/connections/Connection.ts | 25 +++++- src/util/connections/ConnectionStore.ts | 4 +- src/util/connections/RefreshableConnection.ts | 30 +++++++ src/util/connections/index.ts | 1 + src/util/dtos/ConnectedAccountDTO.ts | 4 +- src/util/entities/ConnectedAccount.ts | 7 +- src/util/interfaces/ConnectedAccount.ts | 16 ++++ src/util/interfaces/index.ts | 5 +- src/util/schemas/ConnectedAccountSchema.ts | 4 +- 18 files changed, 292 insertions(+), 111 deletions(-) create mode 100644 src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts create mode 100644 src/util/connections/RefreshableConnection.ts create mode 100644 src/util/interfaces/ConnectedAccount.ts diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts new file mode 100644 index 00000000..8d51a770 --- /dev/null +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts @@ -0,0 +1,84 @@ +import { route } from "@fosscord/api"; +import { + ApiError, + ConnectedAccount, + ConnectionStore, + DiscordApiErrors, + FieldErrors, +} from "@fosscord/util"; +import { Request, Response, Router } from "express"; +import RefreshableConnection from "../../../../../../../util/connections/RefreshableConnection"; +const router = Router(); + +// TODO: this route is only used for spotify, twitch, and youtube. (battlenet seems to be able to PUT, maybe others also) + +// spotify is disabled here because it cant be used +const ALLOWED_CONNECTIONS = ["twitch", "youtube"]; + +router.get("/", route({}), async (req: Request, res: Response) => { + // TODO: get the current access token or refresh it if it's expired + const { connection_name, connection_id } = req.params; + + const connection = ConnectionStore.connections.get(connection_id); + + if (!ALLOWED_CONNECTIONS.includes(connection_name) || !connection) + throw FieldErrors({ + provider_id: { + code: "BASE_TYPE_CHOICES", + message: req.t("common:field.BASE_TYPE_CHOICES", { + types: ALLOWED_CONNECTIONS.join(", "), + }), + }, + }); + + if (!connection.settings.enabled) + throw FieldErrors({ + provider_id: { + message: "This connection has been disabled server-side.", + }, + }); + + const connectedAccount = await ConnectedAccount.findOne({ + where: { + type: connection_name, + id: connection_id, + user_id: req.user_id, + }, + select: [ + "external_id", + "type", + "name", + "verified", + "visibility", + "show_activity", + "revoked", + "token_data", + "friend_sync", + "integrations", + ], + }); + if (!connectedAccount) throw DiscordApiErrors.UNKNOWN_CONNECTION; + if (connectedAccount.revoked) + throw new ApiError("Connection revoked", 0, 400); + if (!connectedAccount.token_data) + throw new ApiError("No token data", 0, 400); + + let access_token = connectedAccount.token_data.access_token; + const { expires_at, expires_in } = connectedAccount.token_data; + + if (expires_at && expires_at < Date.now()) { + if (!(connection instanceof RefreshableConnection)) + throw new ApiError("Access token expired", 0, 400); + const tokenData = await connection.refresh(connectedAccount); + access_token = tokenData.access_token; + } else if (expires_in && expires_in < Date.now()) { + if (!(connection instanceof RefreshableConnection)) + throw new ApiError("Access token expired", 0, 400); + const tokenData = await connection.refresh(connectedAccount); + access_token = tokenData.access_token; + } + + res.json({ access_token }); +}); + +export default router; diff --git a/src/api/routes/users/@me/connections/index.ts b/src/api/routes/users/@me/connections/index.ts index a5041be1..8e762f19 100644 --- a/src/api/routes/users/@me/connections/index.ts +++ b/src/api/routes/users/@me/connections/index.ts @@ -35,7 +35,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { "visibility", "show_activity", "revoked", - "access_token", + "token_data", "friend_sync", "integrations", ], diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index f4b317cc..ecba0fa9 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,6 +1,7 @@ import { Config, ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, ConnectionLoader, DiscordApiErrors, @@ -9,14 +10,6 @@ import fetch from "node-fetch"; import Connection from "../../util/connections/Connection"; import { BattleNetSettings } from "./BattleNetSettings"; -interface OAuthTokenResponse { - access_token: string; - token_type: string; - scope: string; - refresh_token?: string; - expires_in?: number; -} - interface BattleNetConnectionUser { sub: string; id: number; @@ -65,7 +58,10 @@ export default class BattleNetConnection extends Connection { return this.tokenUrl; } - async exchangeCode(state: string, code: string): Promise { + async exchangeCode( + state: string, + code: string, + ): Promise { this.validateState(state); const url = this.getTokenUrl(); @@ -86,10 +82,15 @@ export default class BattleNetConnection extends Connection { }), }) .then((res) => res.json()) - .then((res: OAuthTokenResponse & BattleNetErrorResponse) => { - if (res.error) throw new Error(res.error_description); - return res.access_token; - }) + .then( + ( + res: ConnectedAccountCommonOAuthTokenResponse & + BattleNetErrorResponse, + ) => { + if (res.error) throw new Error(res.error_description); + return res; + }, + ) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, @@ -117,8 +118,8 @@ export default class BattleNetConnection extends Connection { params: ConnectionCallbackSchema, ): Promise { const userId = this.getUserId(params.state); - const token = await this.exchangeCode(params.state, params.code!); - const userInfo = await this.getUser(token); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); const exists = await this.hasConnection(userId, userInfo.id.toString()); diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 05074c26..61efcfc5 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -1,6 +1,7 @@ import { Config, ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, ConnectionLoader, DiscordApiErrors, @@ -9,14 +10,6 @@ import fetch from "node-fetch"; import Connection from "../../util/connections/Connection"; import { DiscordSettings } from "./DiscordSettings"; -interface OAuthTokenResponse { - access_token: string; - token_type: string; - scope: string; - refresh_token?: string; - expires_in?: number; -} - interface UserResponse { id: string; username: string; @@ -65,7 +58,10 @@ export default class DiscordConnection extends Connection { return this.tokenUrl; } - async exchangeCode(state: string, code: string): Promise { + async exchangeCode( + state: string, + code: string, + ): Promise { this.validateState(state); const url = this.getTokenUrl(); @@ -86,7 +82,6 @@ export default class DiscordConnection extends Connection { }), }) .then((res) => res.json()) - .then((res: OAuthTokenResponse) => res.access_token) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, @@ -109,8 +104,8 @@ export default class DiscordConnection extends Connection { params: ConnectionCallbackSchema, ): Promise { const userId = this.getUserId(params.state); - const token = await this.exchangeCode(params.state, params.code!); - const userInfo = await this.getUser(token); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); const exists = await this.hasConnection(userId, userInfo.id); diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts index cffafc60..f1f3f24c 100644 --- a/src/connections/EpicGames/index.ts +++ b/src/connections/EpicGames/index.ts @@ -1,6 +1,7 @@ import { Config, ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, ConnectionLoader, DiscordApiErrors, @@ -9,21 +10,14 @@ import fetch from "node-fetch"; import Connection from "../../util/connections/Connection"; import { EpicGamesSettings } from "./EpicGamesSettings"; -interface OAuthTokenResponse { - access_token: string; - token_type: string; - scope: string; - refresh_token?: string; - expires_in?: number; -} - export interface UserResponse { accountId: string; displayName: string; preferredLanguage: string; } -export interface EpicTokenResponse extends OAuthTokenResponse { +export interface EpicTokenResponse + extends ConnectedAccountCommonOAuthTokenResponse { expires_at: string; refresh_expires_in: number; refresh_expires_at: string; @@ -70,7 +64,10 @@ export default class EpicGamesConnection extends Connection { return this.tokenUrl; } - async exchangeCode(state: string, code: string): Promise { + async exchangeCode( + state: string, + code: string, + ): Promise { this.validateState(state); const url = this.getTokenUrl(); @@ -90,7 +87,6 @@ export default class EpicGamesConnection extends Connection { }), }) .then((res) => res.json()) - .then((res: EpicTokenResponse) => res.access_token) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, @@ -117,8 +113,8 @@ export default class EpicGamesConnection extends Connection { params: ConnectionCallbackSchema, ): Promise { const userId = this.getUserId(params.state); - const token = await this.exchangeCode(params.state, params.code!); - const userInfo = await this.getUser(token); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); const exists = await this.hasConnection(userId, userInfo[0].accountId); diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts index 80950a8e..2d490c63 100644 --- a/src/connections/Facebook/index.ts +++ b/src/connections/Facebook/index.ts @@ -1,6 +1,7 @@ import { Config, ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, ConnectionLoader, DiscordApiErrors, @@ -9,14 +10,6 @@ import fetch from "node-fetch"; import Connection from "../../util/connections/Connection"; import { FacebookSettings } from "./FacebookSettings"; -interface OAuthTokenResponse { - access_token: string; - token_type: string; - scope: string; - refresh_token?: string; - expires_in?: number; -} - export interface FacebookErrorResponse { error: { message: string; @@ -81,7 +74,10 @@ export default class FacebookConnection extends Connection { return url.toString(); } - async exchangeCode(state: string, code: string): Promise { + async exchangeCode( + state: string, + code: string, + ): Promise { this.validateState(state); const url = this.getTokenUrl(code); @@ -93,10 +89,15 @@ export default class FacebookConnection extends Connection { }, }) .then((res) => res.json()) - .then((res: OAuthTokenResponse & FacebookErrorResponse) => { - if (res.error) throw new Error(res.error.message); - return res.access_token; - }) + .then( + ( + res: ConnectedAccountCommonOAuthTokenResponse & + FacebookErrorResponse, + ) => { + if (res.error) throw new Error(res.error.message); + return res; + }, + ) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, @@ -124,8 +125,8 @@ export default class FacebookConnection extends Connection { params: ConnectionCallbackSchema, ): Promise { const userId = this.getUserId(params.state); - const token = await this.exchangeCode(params.state, params.code!); - const userInfo = await this.getUser(token); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); const exists = await this.hasConnection(userId, userInfo.id); diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index d79fd51e..ab3f8e65 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,6 +1,7 @@ import { Config, ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, ConnectionLoader, DiscordApiErrors, @@ -9,14 +10,6 @@ import fetch from "node-fetch"; import Connection from "../../util/connections/Connection"; import { GitHubSettings } from "./GitHubSettings"; -interface OAuthTokenResponse { - access_token: string; - token_type: string; - scope: string; - refresh_token?: string; - expires_in?: number; -} - interface UserResponse { login: string; id: number; @@ -63,7 +56,10 @@ export default class GitHubConnection extends Connection { return url.toString(); } - async exchangeCode(state: string, code: string): Promise { + async exchangeCode( + state: string, + code: string, + ): Promise { this.validateState(state); const url = this.getTokenUrl(code); @@ -75,7 +71,6 @@ export default class GitHubConnection extends Connection { }, }) .then((res) => res.json()) - .then((res: OAuthTokenResponse) => res.access_token) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, @@ -98,8 +93,8 @@ export default class GitHubConnection extends Connection { params: ConnectionCallbackSchema, ): Promise { const userId = this.getUserId(params.state); - const token = await this.exchangeCode(params.state, params.code!); - const userInfo = await this.getUser(token); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); const exists = await this.hasConnection(userId, userInfo.id.toString()); diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts index c529cfa3..182cd5a5 100644 --- a/src/connections/Reddit/index.ts +++ b/src/connections/Reddit/index.ts @@ -1,6 +1,7 @@ import { Config, ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, ConnectionLoader, DiscordApiErrors, @@ -9,14 +10,6 @@ import fetch from "node-fetch"; import Connection from "../../util/connections/Connection"; import { RedditSettings } from "./RedditSettings"; -interface OAuthTokenResponse { - access_token: string; - token_type: string; - scope: string; - refresh_token?: string; - expires_in?: number; -} - export interface UserResponse { verified: boolean; coins: number; @@ -72,7 +65,10 @@ export default class RedditConnection extends Connection { return this.tokenUrl; } - async exchangeCode(state: string, code: string): Promise { + async exchangeCode( + state: string, + code: string, + ): Promise { this.validateState(state); const url = this.getTokenUrl(); @@ -95,7 +91,6 @@ export default class RedditConnection extends Connection { }), }) .then((res) => res.json()) - .then((res: OAuthTokenResponse) => res.access_token) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, @@ -118,8 +113,8 @@ export default class RedditConnection extends Connection { params: ConnectionCallbackSchema, ): Promise { const userId = this.getUserId(params.state); - const token = await this.exchangeCode(params.state, params.code!); - const userInfo = await this.getUser(token); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); const exists = await this.hasConnection(userId, userInfo.id.toString()); @@ -128,7 +123,6 @@ export default class RedditConnection extends Connection { // TODO: connection metadata return await this.createConnection({ - access_token: token, user_id: userId, external_id: userInfo.id.toString(), friend_sync: params.friend_sync, diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts index eb662141..b40d6189 100644 --- a/src/connections/Spotify/index.ts +++ b/src/connections/Spotify/index.ts @@ -1,22 +1,15 @@ import { Config, ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; import fetch from "node-fetch"; -import Connection from "../../util/connections/Connection"; +import RefreshableConnection from "../../util/connections/RefreshableConnection"; import { SpotifySettings } from "./SpotifySettings"; -interface OAuthTokenResponse { - access_token: string; - token_type: string; - scope: string; - refresh_token?: string; - expires_in?: number; -} - export interface UserResponse { display_name: string; id: string; @@ -34,7 +27,7 @@ export interface ErrorResponse { }; } -export default class SpotifyConnection extends Connection { +export default class SpotifyConnection extends RefreshableConnection { public readonly id = "spotify"; public readonly authorizeUrl = "https://accounts.spotify.com/authorize"; public readonly tokenUrl = "https://accounts.spotify.com/api/token"; @@ -48,6 +41,11 @@ export default class SpotifyConnection extends Connection { settings: SpotifySettings = new SpotifySettings(); init(): void { + /** + * The way Discord shows the currently playing song is by using Spotifys partner API. This is obviously not possible for us. + * So to prevent spamming the spotify api we disable the ability to refresh. + */ + this.refreshEnabled = false; this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, @@ -76,7 +74,10 @@ export default class SpotifyConnection extends Connection { return this.tokenUrl; } - async exchangeCode(state: string, code: string): Promise { + async exchangeCode( + state: string, + code: string, + ): Promise { this.validateState(state); const url = this.getTokenUrl(); @@ -99,10 +100,15 @@ export default class SpotifyConnection extends Connection { }), }) .then((res) => res.json()) - .then((res: OAuthTokenResponse & TokenErrorResponse) => { - if (res.error) throw new Error(res.error_description); - return res.access_token; - }) + .then( + ( + res: ConnectedAccountCommonOAuthTokenResponse & + TokenErrorResponse, + ) => { + if (res.error) throw new Error(res.error_description); + return res; + }, + ) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, @@ -111,6 +117,44 @@ export default class SpotifyConnection extends Connection { }); } + async refreshToken(connectedAccount: ConnectedAccount) { + if (!connectedAccount.token_data?.refresh_token) + throw new Error("No refresh token available."); + const refresh_token = connectedAccount.token_data.refresh_token; + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `Basic ${Buffer.from( + `${this.settings.clientId!}:${this.settings.clientSecret!}`, + ).toString("base64")}`, + }, + body: new URLSearchParams({ + grant_type: "refresh_token", + refresh_token, + }), + }) + .then((res) => res.json()) + .then( + ( + res: ConnectedAccountCommonOAuthTokenResponse & + TokenErrorResponse, + ) => { + if (res.error) throw new Error(res.error_description); + return res; + }, + ) + .catch((e) => { + console.error( + `Error refreshing token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + }); + } + async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); return fetch(url.toString(), { @@ -130,14 +174,15 @@ export default class SpotifyConnection extends Connection { params: ConnectionCallbackSchema, ): Promise { const userId = this.getUserId(params.state); - const token = await this.exchangeCode(params.state, params.code!); - const userInfo = await this.getUser(token); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); const exists = await this.hasConnection(userId, userInfo.id); if (exists) return null; return await this.createConnection({ + token_data: tokenData, user_id: userId, external_id: userInfo.id, friend_sync: params.friend_sync, diff --git a/src/util/connections/Connection.ts b/src/util/connections/Connection.ts index 164cfac7..8b60b0d2 100644 --- a/src/util/connections/Connection.ts +++ b/src/util/connections/Connection.ts @@ -1,9 +1,11 @@ import crypto from "crypto"; import { ConnectedAccount } from "../entities"; -import { OrmUtils } from "../imports"; import { ConnectedAccountSchema, ConnectionCallbackSchema } from "../schemas"; import { DiscordApiErrors } from "../util"; +/** + * A connection that can be used to connect to an external service. + */ export default abstract class Connection { id: string; settings: { enabled: boolean }; @@ -21,7 +23,9 @@ export default abstract class Connection { * Processes the callback * @param args Callback arguments */ - abstract handleCallback(params: ConnectionCallbackSchema): Promise; + abstract handleCallback( + params: ConnectionCallbackSchema, + ): Promise; /** * Gets a user id from state @@ -54,12 +58,25 @@ export default abstract class Connection { this.states.delete(state); } - async createConnection(data: ConnectedAccountSchema): Promise { - const ca = OrmUtils.mergeDeep(new ConnectedAccount(), data) as ConnectedAccount; + /** + * Creates a Connected Account in the database. + * @param data connected account data + * @returns the new connected account + */ + async createConnection( + data: ConnectedAccountSchema, + ): Promise { + const ca = ConnectedAccount.create({ ...data }); await ca.save(); return ca; } + /** + * Checks if a user has an exist connected account for the given extenal id. + * @param userId the user id + * @param externalId the connection id to find + * @returns + */ async hasConnection(userId: string, externalId: string): Promise { const existing = await ConnectedAccount.findOne({ where: { diff --git a/src/util/connections/ConnectionStore.ts b/src/util/connections/ConnectionStore.ts index 406e8232..759b6de7 100644 --- a/src/util/connections/ConnectionStore.ts +++ b/src/util/connections/ConnectionStore.ts @@ -1,5 +1,7 @@ import Connection from "./Connection"; +import RefreshableConnection from "./RefreshableConnection"; export class ConnectionStore { - public static connections: Map = new Map(); + public static connections: Map = + new Map(); } diff --git a/src/util/connections/RefreshableConnection.ts b/src/util/connections/RefreshableConnection.ts new file mode 100644 index 00000000..0008cbc0 --- /dev/null +++ b/src/util/connections/RefreshableConnection.ts @@ -0,0 +1,30 @@ +import { ConnectedAccount } from "../entities"; +import { ConnectedAccountCommonOAuthTokenResponse } from "../interfaces"; +import Connection from "./Connection"; + +/** + * A connection that can refresh its token. + */ +export default abstract class RefreshableConnection extends Connection { + refreshEnabled = true; + /** + * Refreshes the token for a connected account. + * @param connectedAccount The connected account to refresh + */ + abstract refreshToken( + connectedAccount: ConnectedAccount, + ): Promise; + + /** + * Refreshes the token for a connected account and saves it to the database. + * @param connectedAccount The connected account to refresh + */ + async refresh( + connectedAccount: ConnectedAccount, + ): Promise { + const tokenData = await this.refreshToken(connectedAccount); + connectedAccount.token_data = tokenData; + await connectedAccount.save(); + return tokenData; + } +} diff --git a/src/util/connections/index.ts b/src/util/connections/index.ts index e15d0c8c..8d20bf27 100644 --- a/src/util/connections/index.ts +++ b/src/util/connections/index.ts @@ -2,3 +2,4 @@ export * from "./Connection"; export * from "./ConnectionConfig"; export * from "./ConnectionLoader"; export * from "./ConnectionStore"; +export * from "./RefreshableConnection"; diff --git a/src/util/dtos/ConnectedAccountDTO.ts b/src/util/dtos/ConnectedAccountDTO.ts index debc5535..ca15ff41 100644 --- a/src/util/dtos/ConnectedAccountDTO.ts +++ b/src/util/dtos/ConnectedAccountDTO.ts @@ -23,8 +23,8 @@ export class ConnectedAccountDTO { this.id = connectedAccount.external_id; this.user_id = connectedAccount.user_id; this.access_token = - connectedAccount.access_token && with_token - ? connectedAccount.access_token + connectedAccount.token_data && with_token + ? connectedAccount.token_data.access_token : undefined; this.friend_sync = connectedAccount.friend_sync; this.name = connectedAccount.name; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 25d5a0c7..beb53e41 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -17,6 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { ConnectedAccountTokenData } from "../interfaces"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; @@ -40,9 +41,6 @@ export class ConnectedAccount extends BaseClass { }) user: User; - @Column({ select: false, nullable: true }) - access_token?: string; - @Column({ select: false }) friend_sync?: boolean = false; @@ -75,4 +73,7 @@ export class ConnectedAccount extends BaseClass { @Column() two_way_link?: boolean = false; + + @Column({ select: false, nullable: true, type: "simple-json" }) + token_data?: ConnectedAccountTokenData; } diff --git a/src/util/interfaces/ConnectedAccount.ts b/src/util/interfaces/ConnectedAccount.ts new file mode 100644 index 00000000..c96e5f79 --- /dev/null +++ b/src/util/interfaces/ConnectedAccount.ts @@ -0,0 +1,16 @@ +export interface ConnectedAccountCommonOAuthTokenResponse { + access_token: string; + token_type: string; + scope: string; + refresh_token?: string; + expires_in?: number; +} + +export interface ConnectedAccountTokenData { + access_token: string; + token_type?: string; + scope?: string; + refresh_token?: string; + expires_in?: number; + expires_at?: number; +} diff --git a/src/util/interfaces/index.ts b/src/util/interfaces/index.ts index fa259ce1..e194d174 100644 --- a/src/util/interfaces/index.ts +++ b/src/util/interfaces/index.ts @@ -17,7 +17,8 @@ */ export * from "./Activity"; -export * from "./Presence"; -export * from "./Interaction"; +export * from "./ConnectedAccount"; export * from "./Event"; +export * from "./Interaction"; +export * from "./Presence"; export * from "./Status"; diff --git a/src/util/schemas/ConnectedAccountSchema.ts b/src/util/schemas/ConnectedAccountSchema.ts index e00e4fa1..e5f838d0 100644 --- a/src/util/schemas/ConnectedAccountSchema.ts +++ b/src/util/schemas/ConnectedAccountSchema.ts @@ -1,7 +1,9 @@ +import { ConnectedAccountTokenData } from "../interfaces"; + export interface ConnectedAccountSchema { external_id: string; user_id: string; - access_token?: string; + token_data?: ConnectedAccountTokenData; friend_sync?: boolean; name: string; revoked?: boolean; From 02a4a6998d091e76c35fc1d0768c629ba1862c63 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Fri, 23 Dec 2022 18:37:11 -0500 Subject: [PATCH 20/58] Update todo in access-token route --- .../connections/#connection_name/#connection_id/access-token.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts index 8d51a770..760f8135 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts @@ -15,8 +15,8 @@ const router = Router(); // spotify is disabled here because it cant be used const ALLOWED_CONNECTIONS = ["twitch", "youtube"]; +// NOTE: this route has not been extensively tested, as the required connections are not implemented as of writing router.get("/", route({}), async (req: Request, res: Response) => { - // TODO: get the current access token or refresh it if it's expired const { connection_name, connection_id } = req.params; const connection = ConnectionStore.connections.get(connection_id); From a60f147156d688696dbb767c0d681d1c01198be3 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 24 Dec 2022 14:00:54 +1100 Subject: [PATCH 21/58] Fix connection update visibilty dying when given boolean --- .../connections/#connection_name/#connection_id/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts index 84863f6a..9d5f517d 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts @@ -1,5 +1,5 @@ import { route } from "@fosscord/api"; -import { ConnectedAccount, DiscordApiErrors, emitEvent } from "@fosscord/util"; +import { ConnectedAccount, DiscordApiErrors, emitEvent, ConnectionUpdateSchema } from "@fosscord/util"; import { Request, Response, Router } from "express"; const router = Router(); @@ -9,6 +9,7 @@ router.patch( route({ body: "ConnectionUpdateSchema" }), async (req: Request, res: Response) => { const { connection_name, connection_id } = req.params; + const body = req.body as ConnectionUpdateSchema; const connection = await ConnectedAccount.findOne({ where: { @@ -31,7 +32,12 @@ router.patch( if (!connection) return DiscordApiErrors.UNKNOWN_CONNECTION; // TODO: do we need to do anything if the connection is revoked? + + //@ts-ignore For some reason the client sends this as a boolean, even tho docs say its a number? + if (typeof body.visibility === "boolean") body.visibility = body.visibility ? 1 : 0; + connection.assign(req.body); + await ConnectedAccount.update( { user_id: req.user_id, From 6d6944cfee4af656c6386c7a44efc6b99bdfd6ed Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sat, 24 Dec 2022 16:24:58 -0500 Subject: [PATCH 22/58] Add Twitch, error handling, revokation changes, etc --- assets/schemas.json | 1865 ++++++++++++++++- .../#connection_id/access-token.ts | 16 +- .../#connection_name/#connection_id/index.ts | 13 +- src/connections/BattleNet/index.ts | 25 +- src/connections/Discord/index.ts | 26 +- src/connections/EpicGames/index.ts | 26 +- src/connections/Facebook/index.ts | 25 +- src/connections/GitHub/index.ts | 28 +- src/connections/Reddit/index.ts | 28 +- src/connections/Spotify/index.ts | 51 +- src/connections/Twitch/TwitchSettings.ts | 5 + src/connections/Twitch/index.ts | 196 ++ src/util/connections/RefreshableConnection.ts | 2 +- src/util/dtos/ConnectedAccountDTO.ts | 2 +- src/util/entities/ConnectedAccount.ts | 10 +- src/util/interfaces/ConnectedAccount.ts | 1 + src/util/schemas/ConnectedAccountSchema.ts | 2 +- src/util/schemas/ConnectionUpdateSchema.ts | 1 + src/util/util/Constants.ts | 5 + 19 files changed, 2278 insertions(+), 49 deletions(-) create mode 100644 src/connections/Twitch/TwitchSettings.ts create mode 100644 src/connections/Twitch/index.ts diff --git a/assets/schemas.json b/assets/schemas.json index fe4fcea3..5f897c86 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -36,6 +36,33 @@ ], "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectedAccountCommonOAuthTokenResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "scope", + "token_type" + ], + "$schema": "http://json-schema.org/draft-07/schema#" + }, "SMTPConnection.CustomAuthenticationResponse": { "type": "object", "properties": { @@ -419,6 +446,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -1021,6 +1079,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -1623,6 +1712,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -2220,6 +2340,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -2799,8 +2950,8 @@ "user_id": { "type": "string" }, - "access_token": { - "type": "string" + "token_data": { + "$ref": "#/definitions/ConnectedAccountTokenData" }, "friend_sync": { "type": "boolean" @@ -2812,7 +2963,7 @@ "type": "boolean" }, "show_activity": { - "type": "boolean" + "type": "integer" }, "type": { "type": "string" @@ -2853,6 +3004,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -3455,6 +3637,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -4030,6 +4243,9 @@ "properties": { "visibility": { "type": "boolean" + }, + "show_activity": { + "type": "boolean" } }, "additionalProperties": false, @@ -4042,6 +4258,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -4638,6 +4885,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -5243,6 +5521,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -5836,6 +6145,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -6429,6 +6769,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -7041,6 +7412,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -7637,6 +8039,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -8293,6 +8726,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -8908,6 +9372,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -9663,6 +10158,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -10274,6 +10800,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -10889,6 +11446,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -11495,6 +12083,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -12107,6 +12726,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -12709,6 +13359,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -13299,6 +13980,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -14000,6 +14712,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -14698,6 +15441,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -15291,6 +16065,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -15892,6 +16697,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -16486,6 +17322,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -17080,6 +17947,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -17703,6 +18601,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -18297,6 +19226,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -18890,6 +19850,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -19498,6 +20489,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -20095,6 +21117,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -20766,6 +21819,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -21359,6 +22443,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -21952,6 +23067,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -22542,6 +23688,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -23138,6 +24315,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -23744,6 +24952,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -24334,6 +25573,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -24973,6 +26243,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -25598,6 +26899,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -26213,6 +27545,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -26917,6 +28280,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -27506,6 +28900,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -28134,6 +29559,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -28747,6 +30203,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -29415,6 +30902,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -30005,6 +31523,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -30603,6 +32152,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -31191,6 +32771,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -31785,6 +33396,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -32379,6 +34021,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -32973,6 +34646,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -33554,6 +35258,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -34147,6 +35882,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -34737,6 +36503,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -35327,6 +37124,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -35923,6 +37751,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts index 760f8135..1ad1c7a7 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts @@ -19,7 +19,7 @@ const ALLOWED_CONNECTIONS = ["twitch", "youtube"]; router.get("/", route({}), async (req: Request, res: Response) => { const { connection_name, connection_id } = req.params; - const connection = ConnectionStore.connections.get(connection_id); + const connection = ConnectionStore.connections.get(connection_name); if (!ALLOWED_CONNECTIONS.includes(connection_name) || !connection) throw FieldErrors({ @@ -41,7 +41,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { const connectedAccount = await ConnectedAccount.findOne({ where: { type: connection_name, - id: connection_id, + external_id: connection_id, user_id: req.user_id, }, select: [ @@ -64,14 +64,12 @@ router.get("/", route({}), async (req: Request, res: Response) => { throw new ApiError("No token data", 0, 400); let access_token = connectedAccount.token_data.access_token; - const { expires_at, expires_in } = connectedAccount.token_data; + const { expires_at, expires_in, fetched_at } = connectedAccount.token_data; - if (expires_at && expires_at < Date.now()) { - if (!(connection instanceof RefreshableConnection)) - throw new ApiError("Access token expired", 0, 400); - const tokenData = await connection.refresh(connectedAccount); - access_token = tokenData.access_token; - } else if (expires_in && expires_in < Date.now()) { + if ( + (expires_at && expires_at < Date.now()) || + (expires_in && fetched_at + expires_in * 1000 < Date.now()) + ) { if (!(connection instanceof RefreshableConnection)) throw new ApiError("Access token expired", 0, 400); const tokenData = await connection.refresh(connectedAccount); diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts index 9d5f517d..07440eac 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts @@ -1,5 +1,10 @@ import { route } from "@fosscord/api"; -import { ConnectedAccount, DiscordApiErrors, emitEvent, ConnectionUpdateSchema } from "@fosscord/util"; +import { + ConnectedAccount, + ConnectionUpdateSchema, + DiscordApiErrors, + emitEvent +} from "@fosscord/util"; import { Request, Response, Router } from "express"; const router = Router(); @@ -35,6 +40,8 @@ router.patch( //@ts-ignore For some reason the client sends this as a boolean, even tho docs say its a number? if (typeof body.visibility === "boolean") body.visibility = body.visibility ? 1 : 0; + //@ts-ignore For some reason the client sends this as a boolean, even tho docs say its a number? + if (typeof body.show_activity === "boolean") body.show_activity = body.show_activity ? 1 : 0; connection.assign(req.body); @@ -58,7 +65,7 @@ router.delete("/", route({}), async (req: Request, res: Response) => { user_id: req.user_id, external_id: connection_id, type: connection_name, - } + }, }); await Promise.all([ @@ -67,7 +74,7 @@ router.delete("/", route({}), async (req: Request, res: Response) => { event: "USER_CONNECTIONS_UPDATE", data: account, user_id: req.user_id, - }) + }), ]); return res.sendStatus(200); diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index ecba0fa9..8e8eeeed 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -81,7 +82,13 @@ export default class BattleNetConnection extends Connection { }/connections/${this.id}/callback`, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) .then( ( res: ConnectedAccountCommonOAuthTokenResponse & @@ -95,7 +102,7 @@ export default class BattleNetConnection extends Connection { console.error( `Error exchanging token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -107,10 +114,22 @@ export default class BattleNetConnection extends Connection { Authorization: `Bearer ${token}`, }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) .then((res: BattleNetConnectionUser & BattleNetErrorResponse) => { if (res.error) throw new Error(res.error_description); return res; + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 61efcfc5..23f5d978 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -81,12 +82,18 @@ export default class DiscordConnection extends Connection { }/connections/${this.id}/callback`, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange token", 0, 400); + } + + return res.json(); + }) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -97,7 +104,20 @@ export default class DiscordConnection extends Connection { headers: { Authorization: `Bearer ${token}`, }, - }).then((res) => res.json()); + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); } async handleCallback( diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts index f1f3f24c..c720dc5d 100644 --- a/src/connections/EpicGames/index.ts +++ b/src/connections/EpicGames/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -86,12 +87,18 @@ export default class EpicGamesConnection extends Connection { code, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -106,7 +113,20 @@ export default class EpicGamesConnection extends Connection { headers: { Authorization: `Bearer ${token}`, }, - }).then((res) => res.json()); + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); } async handleCallback( diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts index 2d490c63..67f8da79 100644 --- a/src/connections/Facebook/index.ts +++ b/src/connections/Facebook/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -88,7 +89,13 @@ export default class FacebookConnection extends Connection { Accept: "application/json", }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) .then( ( res: ConnectedAccountCommonOAuthTokenResponse & @@ -102,7 +109,7 @@ export default class FacebookConnection extends Connection { console.error( `Error exchanging token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -114,10 +121,22 @@ export default class FacebookConnection extends Connection { Authorization: `Bearer ${token}`, }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) .then((res: UserResponse & FacebookErrorResponse) => { if (res.error) throw new Error(res.error.message); return res; + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index ab3f8e65..aa686b03 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -70,12 +71,18 @@ export default class GitHubConnection extends Connection { Accept: "application/json", }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) .catch((e) => { console.error( - `Error exchanging token for ${this.id} connection: ${e}`, + `Error exchanging code for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -86,7 +93,20 @@ export default class GitHubConnection extends Connection { headers: { Authorization: `Bearer ${token}`, }, - }).then((res) => res.json()); + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); } async handleCallback( diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts index 182cd5a5..06fbcbe5 100644 --- a/src/connections/Reddit/index.ts +++ b/src/connections/Reddit/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -90,12 +91,18 @@ export default class RedditConnection extends Connection { }/connections/${this.id}/callback`, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to code", 0, 400); + } + + return res.json(); + }) .catch((e) => { console.error( - `Error exchanging token for ${this.id} connection: ${e}`, + `Error exchanging code for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -106,7 +113,20 @@ export default class RedditConnection extends Connection { headers: { Authorization: `Bearer ${token}`, }, - }).then((res) => res.json()); + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); } async handleCallback( diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts index b40d6189..44a4bc28 100644 --- a/src/connections/Spotify/index.ts +++ b/src/connections/Spotify/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -99,21 +100,28 @@ export default class SpotifyConnection extends RefreshableConnection { }/connections/${this.id}/callback`, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to refresh token", 0, 400); + } + + return res.json(); + }) .then( ( res: ConnectedAccountCommonOAuthTokenResponse & TokenErrorResponse, ) => { - if (res.error) throw new Error(res.error_description); + if (res.error) + throw new ApiError(res.error_description, 0, 400); return res; }, ) .catch((e) => { console.error( - `Error exchanging token for ${this.id} connection: ${e}`, + `Error exchanging code for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -137,13 +145,26 @@ export default class SpotifyConnection extends RefreshableConnection { refresh_token, }), }) - .then((res) => res.json()) + .then(async (res) => { + if ([400, 401].includes(res.status)) { + // assume the token was revoked + await connectedAccount.revoke(); + return DiscordApiErrors.CONNECTION_REVOKED; + } + // otherwise throw a general error + if (!res.ok) { + throw new ApiError("Failed to refresh token", 0, 400); + } + + return await res.json(); + }) .then( ( res: ConnectedAccountCommonOAuthTokenResponse & TokenErrorResponse, ) => { - if (res.error) throw new Error(res.error_description); + if (res.error) + throw new ApiError(res.error_description, 0, 400); return res; }, ) @@ -151,7 +172,7 @@ export default class SpotifyConnection extends RefreshableConnection { console.error( `Error refreshing token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -163,10 +184,22 @@ export default class SpotifyConnection extends RefreshableConnection { Authorization: `Bearer ${token}`, }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) .then((res: UserResponse & ErrorResponse) => { if (res.error) throw new Error(res.error.message); return res; + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -182,7 +215,7 @@ export default class SpotifyConnection extends RefreshableConnection { if (exists) return null; return await this.createConnection({ - token_data: tokenData, + token_data: { ...tokenData, fetched_at: Date.now() }, user_id: userId, external_id: userInfo.id, friend_sync: params.friend_sync, diff --git a/src/connections/Twitch/TwitchSettings.ts b/src/connections/Twitch/TwitchSettings.ts new file mode 100644 index 00000000..eb732c82 --- /dev/null +++ b/src/connections/Twitch/TwitchSettings.ts @@ -0,0 +1,5 @@ +export class TwitchSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/Twitch/index.ts b/src/connections/Twitch/index.ts new file mode 100644 index 00000000..ce04f098 --- /dev/null +++ b/src/connections/Twitch/index.ts @@ -0,0 +1,196 @@ +import { + ApiError, + Config, + ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; +import fetch from "node-fetch"; +import RefreshableConnection from "../../util/connections/RefreshableConnection"; +import { TwitchSettings } from "./TwitchSettings"; + +interface TwitchConnectionUserResponse { + data: { + id: string; + login: string; + display_name: string; + type: string; + broadcaster_type: string; + description: string; + profile_image_url: string; + offline_image_url: string; + view_count: number; + created_at: string; + }[]; +} + +export default class TwitchConnection extends RefreshableConnection { + public readonly id = "twitch"; + public readonly authorizeUrl = "https://id.twitch.tv/oauth2/authorize"; + public readonly tokenUrl = "https://id.twitch.tv/oauth2/token"; + public readonly userInfoUrl = "https://api.twitch.tv/helix/users"; + public readonly scopes = [ + "channel_subscriptions", + "channel_check_subscription", + "channel:read:subscriptions", + ]; + settings: TwitchSettings = new TwitchSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as TwitchSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("response_type", "code"); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + return url.toString(); + } + + getTokenUrl(): string { + return this.tokenUrl; + } + + async exchangeCode( + state: string, + code: string, + ): Promise { + this.validateState(state); + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error exchanging code for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async refreshToken( + connectedAccount: ConnectedAccount, + ): Promise { + if (!connectedAccount.token_data?.refresh_token) + throw new Error("No refresh token available."); + const refresh_token = connectedAccount.token_data.refresh_token; + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }, + body: new URLSearchParams({ + grant_type: "refresh_token", + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + refresh_token: refresh_token, + }), + }) + .then(async (res) => { + if ([400, 401].includes(res.status)) { + // assume the token was revoked + await connectedAccount.revoke(); + return DiscordApiErrors.CONNECTION_REVOKED; + } + // otherwise throw a general error + if (!res.ok) { + throw new ApiError("Failed to refresh token", 0, 400); + } + + return await res.json(); + }) + .catch((e) => { + console.error( + `Error refreshing token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + "Client-Id": this.settings.clientId!, + }, + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { + const userId = this.getUserId(params.state); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); + + const exists = await this.hasConnection(userId, userInfo.data[0].id); + + if (exists) return null; + + return await this.createConnection({ + token_data: { ...tokenData, fetched_at: Date.now() }, + user_id: userId, + external_id: userInfo.data[0].id, + friend_sync: params.friend_sync, + name: userInfo.data[0].display_name, + type: this.id, + }); + } +} diff --git a/src/util/connections/RefreshableConnection.ts b/src/util/connections/RefreshableConnection.ts index 0008cbc0..87f5f6dd 100644 --- a/src/util/connections/RefreshableConnection.ts +++ b/src/util/connections/RefreshableConnection.ts @@ -23,7 +23,7 @@ export default abstract class RefreshableConnection extends Connection { connectedAccount: ConnectedAccount, ): Promise { const tokenData = await this.refreshToken(connectedAccount); - connectedAccount.token_data = tokenData; + connectedAccount.token_data = { ...tokenData, fetched_at: Date.now() }; await connectedAccount.save(); return tokenData; } diff --git a/src/util/dtos/ConnectedAccountDTO.ts b/src/util/dtos/ConnectedAccountDTO.ts index ca15ff41..a3618fd1 100644 --- a/src/util/dtos/ConnectedAccountDTO.ts +++ b/src/util/dtos/ConnectedAccountDTO.ts @@ -7,7 +7,7 @@ export class ConnectedAccountDTO { friend_sync?: boolean; name: string; revoked?: boolean; - show_activity?: boolean; + show_activity?: number; type: string; verified?: boolean; visibility?: number; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index beb53e41..d8a9de20 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -51,7 +51,7 @@ export class ConnectedAccount extends BaseClass { revoked?: boolean = false; @Column({ select: false }) - show_activity?: boolean = true; + show_activity?: number = 0; @Column() type: string; @@ -75,5 +75,11 @@ export class ConnectedAccount extends BaseClass { two_way_link?: boolean = false; @Column({ select: false, nullable: true, type: "simple-json" }) - token_data?: ConnectedAccountTokenData; + token_data?: ConnectedAccountTokenData | null; + + async revoke() { + this.revoked = true; + this.token_data = null; + await this.save(); + } } diff --git a/src/util/interfaces/ConnectedAccount.ts b/src/util/interfaces/ConnectedAccount.ts index c96e5f79..ede02f6d 100644 --- a/src/util/interfaces/ConnectedAccount.ts +++ b/src/util/interfaces/ConnectedAccount.ts @@ -13,4 +13,5 @@ export interface ConnectedAccountTokenData { refresh_token?: string; expires_in?: number; expires_at?: number; + fetched_at: number; } diff --git a/src/util/schemas/ConnectedAccountSchema.ts b/src/util/schemas/ConnectedAccountSchema.ts index e5f838d0..fa834bd6 100644 --- a/src/util/schemas/ConnectedAccountSchema.ts +++ b/src/util/schemas/ConnectedAccountSchema.ts @@ -7,7 +7,7 @@ export interface ConnectedAccountSchema { friend_sync?: boolean; name: string; revoked?: boolean; - show_activity?: boolean; + show_activity?: number; type: string; verified?: boolean; visibility?: number; diff --git a/src/util/schemas/ConnectionUpdateSchema.ts b/src/util/schemas/ConnectionUpdateSchema.ts index ac234e7e..eb6c0916 100644 --- a/src/util/schemas/ConnectionUpdateSchema.ts +++ b/src/util/schemas/ConnectionUpdateSchema.ts @@ -1,3 +1,4 @@ export interface ConnectionUpdateSchema { visibility?: boolean; + show_activity?: boolean; } diff --git a/src/util/util/Constants.ts b/src/util/util/Constants.ts index 3bdfcfa9..47f650f4 100644 --- a/src/util/util/Constants.ts +++ b/src/util/util/Constants.ts @@ -787,6 +787,11 @@ export const DiscordApiErrors = { 40006, ), USER_BANNED: new ApiError("The user is banned from this guild", 40007), + CONNECTION_REVOKED: new ApiError( + "The connection has been revoked", + 40012, + 400, + ), TARGET_USER_IS_NOT_CONNECTED_TO_VOICE: new ApiError( "Target user is not connected to voice", 40032, From 7e10d73dac766554ea5cb70214887fbce1df4a85 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sat, 24 Dec 2022 16:28:41 -0500 Subject: [PATCH 23/58] use connection revoked error --- .../#connection_name/#connection_id/access-token.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts index 1ad1c7a7..3f4de8b5 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts @@ -58,8 +58,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { ], }); if (!connectedAccount) throw DiscordApiErrors.UNKNOWN_CONNECTION; - if (connectedAccount.revoked) - throw new ApiError("Connection revoked", 0, 400); + if (connectedAccount.revoked) throw DiscordApiErrors.CONNECTION_REVOKED; if (!connectedAccount.token_data) throw new ApiError("No token data", 0, 400); From bdd4ddda522e3a7f0e192e3158148171c0e8f52b Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sat, 24 Dec 2022 16:31:03 -0500 Subject: [PATCH 24/58] don't send token_data on connection update --- src/api/routes/connections/#connection_name/callback.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/routes/connections/#connection_name/callback.ts b/src/api/routes/connections/#connection_name/callback.ts index 250d4710..b3baa060 100644 --- a/src/api/routes/connections/#connection_name/callback.ts +++ b/src/api/routes/connections/#connection_name/callback.ts @@ -42,7 +42,7 @@ router.post( if (connectedAccnt) emitEvent({ event: "USER_CONNECTIONS_UPDATE", - data: connectedAccnt, + data: { ...connectedAccnt, token_data: undefined }, user_id: userId, }); From 0baa37e41f2b9b7d23591569f2b5c38b5404d91a Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 29 Dec 2022 15:41:18 -0500 Subject: [PATCH 25/58] add Twitter connection --- src/connections/Twitter/TwitterSettings.ts | 5 + src/connections/Twitter/index.ts | 222 +++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 src/connections/Twitter/TwitterSettings.ts create mode 100644 src/connections/Twitter/index.ts diff --git a/src/connections/Twitter/TwitterSettings.ts b/src/connections/Twitter/TwitterSettings.ts new file mode 100644 index 00000000..e4aa58eb --- /dev/null +++ b/src/connections/Twitter/TwitterSettings.ts @@ -0,0 +1,5 @@ +export class TwitterSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/Twitter/index.ts b/src/connections/Twitter/index.ts new file mode 100644 index 00000000..d8a765ac --- /dev/null +++ b/src/connections/Twitter/index.ts @@ -0,0 +1,222 @@ +import { + ApiError, + Config, + ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; +import fetch from "node-fetch"; +import RefreshableConnection from "../../util/connections/RefreshableConnection"; +import { TwitterSettings } from "./TwitterSettings"; + +interface TwitterUserResponse { + data: { + id: string; + name: string; + username: string; + created_at: string; + location: string; + url: string; + description: string; + verified: string; + }; +} + +interface TwitterErrorResponse { + error: string; + error_description: string; +} + +export default class TwitterConnection extends RefreshableConnection { + public readonly id = "twitter"; + public readonly authorizeUrl = "https://twitter.com/i/oauth2/authorize"; + public readonly tokenUrl = "https://api.twitter.com/2/oauth2/token"; + public readonly userInfoUrl = + "https://api.twitter.com/2/users/me?user.fields=created_at%2Cdescription%2Cid%2Cname%2Cusername%2Cverified%2Clocation%2Curl"; + public readonly scopes = ["users.read", "tweet.read"]; + settings: TwitterSettings = new TwitterSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as TwitterSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("response_type", "code"); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + url.searchParams.append("code_challenge", "challenge"); // TODO: properly use PKCE challenge + url.searchParams.append("code_challenge_method", "plain"); + return url.toString(); + } + + getTokenUrl(): string { + return this.tokenUrl; + } + + async exchangeCode( + state: string, + code: string, + ): Promise { + this.validateState(state); + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `Basic ${Buffer.from( + `${this.settings.clientId!}:${this.settings.clientSecret!}`, + ).toString("base64")}`, + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + code_verifier: "challenge", // TODO: properly use PKCE challenge + }), + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) + .then( + ( + res: ConnectedAccountCommonOAuthTokenResponse & + TwitterErrorResponse, + ) => { + if (res.error) throw new Error(res.error_description); + return res; + }, + ) + .catch((e) => { + console.error( + `Error exchanging code for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async refreshToken( + connectedAccount: ConnectedAccount, + ): Promise { + if (!connectedAccount.token_data?.refresh_token) + throw new Error("No refresh token available."); + const refresh_token = connectedAccount.token_data.refresh_token; + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `Basic ${Buffer.from( + `${this.settings.clientId!}:${this.settings.clientSecret!}`, + ).toString("base64")}`, + }, + body: new URLSearchParams({ + grant_type: "refresh_token", + refresh_token, + client_id: this.settings.clientId!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + code_verifier: "challenge", // TODO: properly use PKCE challenge + }), + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) + .then( + ( + res: ConnectedAccountCommonOAuthTokenResponse & + TwitterErrorResponse, + ) => { + if (res.error) throw new Error(res.error_description); + return res; + }, + ) + .catch((e) => { + console.error( + `Error exchanging code for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .then((res: TwitterUserResponse & TwitterErrorResponse) => { + if (res.error) throw new Error(res.error_description); + return res; + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { + const userId = this.getUserId(params.state); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); + + const exists = await this.hasConnection(userId, userInfo.data.id); + + if (exists) return null; + + return await this.createConnection({ + token_data: { ...tokenData, fetched_at: Date.now() }, + user_id: userId, + external_id: userInfo.data.id, + friend_sync: params.friend_sync, + name: userInfo.data.name, + type: this.id, + }); + } +} From 06140fc7686a3f8aa2871a3b52a415ac93a4d59c Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Fri, 30 Dec 2022 01:57:08 -0500 Subject: [PATCH 26/58] add Xbox connection --- src/connections/Xbox/XboxSettings.ts | 5 + src/connections/Xbox/index.ts | 224 +++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 src/connections/Xbox/XboxSettings.ts create mode 100644 src/connections/Xbox/index.ts diff --git a/src/connections/Xbox/XboxSettings.ts b/src/connections/Xbox/XboxSettings.ts new file mode 100644 index 00000000..c1a41056 --- /dev/null +++ b/src/connections/Xbox/XboxSettings.ts @@ -0,0 +1,5 @@ +export class XboxSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/Xbox/index.ts b/src/connections/Xbox/index.ts new file mode 100644 index 00000000..eb0e2496 --- /dev/null +++ b/src/connections/Xbox/index.ts @@ -0,0 +1,224 @@ +import { + ApiError, + Config, + ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; +import fetch from "node-fetch"; +import Connection from "../../util/connections/Connection"; +import { XboxSettings } from "./XboxSettings"; + +interface XboxUserResponse { + IssueInstant: string; + NotAfter: string; + Token: string; + DisplayClaims: { + xui: { + gtg: string; + xid: string; + uhs: string; + agg: string; + usr: string; + utr: string; + prv: string; + }[]; + }; +} + +interface XboxErrorResponse { + error: string; + error_description: string; +} + +export default class XboxConnection extends Connection { + public readonly id = "xbox"; + public readonly authorizeUrl = + "https://login.live.com/oauth20_authorize.srf"; + public readonly tokenUrl = "https://login.live.com/oauth20_token.srf"; + public readonly userInfoUrl = + "https://xsts.auth.xboxlive.com/xsts/authorize"; + public readonly userAuthUrl = + "https://user.auth.xboxlive.com/user/authenticate"; + public readonly scopes = ["Xboxlive.signin", "Xboxlive.offline_access"]; + settings: XboxSettings = new XboxSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as XboxSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("response_type", "code"); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + url.searchParams.append("approval_prompt", "auto"); + return url.toString(); + } + + getTokenUrl(): string { + return this.tokenUrl; + } + + async getUserToken(token: string): Promise { + return fetch(this.userAuthUrl, { + method: "POST", + headers: { + "x-xbl-contract-version": "3", + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify({ + RelyingParty: "http://auth.xboxlive.com", + TokenType: "JWT", + Properties: { + AuthMethod: "RPS", + SiteName: "user.auth.xboxlive.com", + RpsTicket: `d=${token}`, + }, + }), + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to get user token", 0, 400); + } + + return res.json(); + }) + .then((res) => res.Token) + .catch((e) => { + console.error( + `Error getting user token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + }); + } + + async exchangeCode( + state: string, + code: string, + ): Promise { + this.validateState(state); + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `Basic ${Buffer.from( + `${this.settings.clientId!}:${this.settings.clientSecret!}`, + ).toString("base64")}`, + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + scope: this.scopes.join(" "), + }), + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) + .then( + ( + res: ConnectedAccountCommonOAuthTokenResponse & + XboxErrorResponse, + ) => { + if (res.error) throw new Error(res.error_description); + return res; + }, + ) + .catch((e) => { + console.error( + `Error exchanging code for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "POST", + headers: { + "x-xbl-contract-version": "3", + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify({ + RelyingParty: "http://xboxlive.com", + TokenType: "JWT", + Properties: { + UserTokens: [token], + SandboxId: "RETAIL", + }, + }), + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .then((res: XboxUserResponse & XboxErrorResponse) => { + if (res.error) throw new Error(res.error_description); + return res; + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { + const userId = this.getUserId(params.state); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userToken = await this.getUserToken(tokenData.access_token); + const userInfo = await this.getUser(userToken); + + const exists = await this.hasConnection( + userId, + userInfo.DisplayClaims.xui[0].xid, + ); + + if (exists) return null; + + return await this.createConnection({ + token_data: { ...tokenData, fetched_at: Date.now() }, + user_id: userId, + external_id: userInfo.DisplayClaims.xui[0].xid, + friend_sync: params.friend_sync, + name: userInfo.DisplayClaims.xui[0].gtg, + type: this.id, + }); + } +} From d8ecc4269f2049f64ee60f518076ccd162857a36 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Fri, 13 Jan 2023 08:52:24 -0500 Subject: [PATCH 27/58] replace node-fetch with wretch --- package-lock.json | 9 + package.json | 1 + pnpm-lock.yaml | 5745 ++++++++++++++++++++++++++++ src/connections/BattleNet/index.ts | 73 +- src/connections/Discord/index.ts | 62 +- src/connections/EpicGames/index.ts | 52 +- src/connections/Facebook/index.ts | 55 +- src/connections/GitHub/index.ts | 42 +- src/connections/Reddit/index.ts | 58 +- src/connections/Spotify/index.ts | 123 +- src/connections/Twitch/index.ts | 107 +- src/connections/Twitter/index.ts | 120 +- src/connections/Xbox/index.ts | 134 +- 13 files changed, 6032 insertions(+), 549 deletions(-) create mode 100644 pnpm-lock.yaml diff --git a/package-lock.json b/package-lock.json index cea4dbb6..8947d9e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,7 @@ "tslib": "^2.4.1", "typeorm": "^0.3.10", "typescript-json-schema": "^0.50.1", + "wretch": "^2.3.2", "ws": "^8.9.0" }, "devDependencies": { @@ -7988,6 +7989,14 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/wretch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/wretch/-/wretch-2.3.2.tgz", + "integrity": "sha512-brN97Z2Mwed+w5z+keYI1u5OwWhPIaW0sJi9CxtKBVxLc3aqP6j1+2FCoIskM7WJq6SUHdxTFx20ox0iDLa0mQ==", + "engines": { + "node": ">=14" + } + }, "node_modules/ws": { "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", diff --git a/package.json b/package.json index 99a0f2d3..4dcd3d26 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,7 @@ "tslib": "^2.4.1", "typeorm": "^0.3.10", "typescript-json-schema": "^0.50.1", + "wretch": "^2.3.2", "ws": "^8.9.0" }, "_moduleAliases": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..f5fbb88d --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,5745 @@ +lockfileVersion: 5.4 + +specifiers: + "@aws-sdk/client-s3": ^3.178.0 + "@sentry/integrations": ^7.17.2 + "@sentry/node": ^7.17.2 + "@sentry/tracing": ^7.17.2 + "@types/amqplib": ^0.8.2 + "@types/bcrypt": ^5.0.0 + "@types/body-parser": ^1.19.2 + "@types/cookie-parser": ^1.4.3 + "@types/express": ^4.17.15 + "@types/i18next-node-fs-backend": ^2.1.1 + "@types/json-bigint": ^1.0.1 + "@types/jsonwebtoken": ^8.5.9 + "@types/morgan": ^1.9.3 + "@types/multer": ^1.4.7 + "@types/node": ^18.7.20 + "@types/node-fetch": ^2.6.2 + "@types/node-os-utils": ^1.3.0 + "@types/probe-image-size": ^7.2.0 + "@types/sharp": ^0.31.0 + "@types/ws": ^8.5.3 + "@yukikaze-bot/erlpack": ^1.0.1 + ajv: 8.6.2 + ajv-formats: 2.1.1 + amqplib: ^0.10.3 + bcrypt: ^5.0.1 + body-parser: 1.20.1 + cheerio: ^1.0.0-rc.12 + cookie-parser: ^1.4.6 + dotenv: ^16.0.2 + exif-be-gone: ^1.3.1 + express: ^4.18.1 + fast-zlib: ^2.0.1 + file-type: "16.5" + form-data: ^4.0.0 + husky: ^8.0.0 + i18next: ^21.9.2 + i18next-http-middleware: ^3.2.1 + i18next-node-fs-backend: ^2.1.3 + image-size: ^1.0.2 + json-bigint: ^1.0.0 + jsonwebtoken: ^8.5.1 + lambert-server: ^1.2.12 + missing-native-js-functions: ^1.2.18 + module-alias: ^2.2.2 + morgan: ^1.10.0 + multer: ^1.4.5-lts.1 + node-2fa: ^2.0.3 + node-fetch: ^2.6.7 + node-os-utils: ^1.3.7 + picocolors: ^1.0.0 + prettier: ^2.7.1 + pretty-quick: ^3.1.3 + probe-image-size: ^7.2.3 + proxy-agent: ^5.0.0 + reflect-metadata: ^0.1.13 + sqlite3: ^5.1.4 + ts-node: ^10.9.1 + tslib: ^2.4.1 + typeorm: ^0.3.10 + typescript: ^4.8.3 + typescript-json-schema: ^0.50.1 + wretch: ^2.3.2 + ws: ^8.9.0 + +dependencies: + "@aws-sdk/client-s3": 3.245.0 + "@sentry/integrations": 7.30.0 + "@sentry/node": 7.30.0 + "@sentry/tracing": 7.30.0 + ajv: 8.6.2 + ajv-formats: 2.1.1_ajv@8.6.2 + amqplib: 0.10.3 + bcrypt: 5.1.0 + body-parser: 1.20.1 + cheerio: 1.0.0-rc.12 + cookie-parser: 1.4.6 + dotenv: 16.0.3 + exif-be-gone: 1.3.2 + fast-zlib: 2.0.1 + file-type: 16.5.4 + form-data: 4.0.0 + i18next: 21.10.0 + i18next-http-middleware: 3.2.1 + i18next-node-fs-backend: 2.1.3 + image-size: 1.0.2 + json-bigint: 1.0.0 + jsonwebtoken: 8.5.1 + lambert-server: 1.2.12 + missing-native-js-functions: 1.3.1 + module-alias: 2.2.2 + morgan: 1.10.0 + multer: 1.4.5-lts.1 + node-2fa: 2.0.3 + node-fetch: 2.6.7 + node-os-utils: 1.3.7 + picocolors: 1.0.0 + probe-image-size: 7.2.3 + proxy-agent: 5.0.0 + reflect-metadata: 0.1.13 + sqlite3: 5.1.4 + ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq + tslib: 2.4.1 + typeorm: 0.3.11_h3l5zcb3i6sggvllyfknv6gs44 + typescript-json-schema: 0.50.1 + wretch: 2.3.2 + ws: 8.12.0 + +optionalDependencies: + "@yukikaze-bot/erlpack": 1.0.1 + +devDependencies: + "@types/amqplib": 0.8.2 + "@types/bcrypt": 5.0.0 + "@types/body-parser": 1.19.2 + "@types/cookie-parser": 1.4.3 + "@types/express": 4.17.15 + "@types/i18next-node-fs-backend": 2.1.1 + "@types/json-bigint": 1.0.1 + "@types/jsonwebtoken": 8.5.9 + "@types/morgan": 1.9.4 + "@types/multer": 1.4.7 + "@types/node": 18.11.18 + "@types/node-fetch": 2.6.2 + "@types/node-os-utils": 1.3.0 + "@types/probe-image-size": 7.2.0 + "@types/sharp": 0.31.1 + "@types/ws": 8.5.4 + express: 4.18.2 + husky: 8.0.3 + prettier: 2.8.2 + pretty-quick: 3.1.3_prettier@2.8.2 + typescript: 4.9.4 + +packages: + /@acuminous/bitsyntax/0.1.2: + resolution: + { + integrity: sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==, + } + engines: { node: ">=0.8" } + dependencies: + buffer-more-ints: 1.0.0 + debug: 4.3.4 + safe-buffer: 5.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@aws-crypto/crc32/2.0.0: + resolution: + { + integrity: sha512-TvE1r2CUueyXOuHdEigYjIZVesInd9KN+K/TFFNfkkxRThiNxO6i4ZqqAVMoEjAamZZ1AA8WXJkjCz7YShHPQA==, + } + dependencies: + "@aws-crypto/util": 2.0.2 + "@aws-sdk/types": 3.226.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/crc32c/2.0.0: + resolution: + { + integrity: sha512-vF0eMdMHx3O3MoOXUfBZry8Y4ZDtcuskjjKgJz8YfIDjLStxTZrYXk+kZqtl6A0uCmmiN/Eb/JbC/CndTV1MHg==, + } + dependencies: + "@aws-crypto/util": 2.0.2 + "@aws-sdk/types": 3.226.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/ie11-detection/2.0.2: + resolution: + { + integrity: sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==, + } + dependencies: + tslib: 1.14.1 + dev: false + + /@aws-crypto/sha1-browser/2.0.0: + resolution: + { + integrity: sha512-3fIVRjPFY8EG5HWXR+ZJZMdWNRpwbxGzJ9IH9q93FpbgCH8u8GHRi46mZXp3cYD7gealmyqpm3ThZwLKJjWJhA==, + } + dependencies: + "@aws-crypto/ie11-detection": 2.0.2 + "@aws-crypto/supports-web-crypto": 2.0.2 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-locate-window": 3.208.0 + "@aws-sdk/util-utf8-browser": 3.188.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/sha256-browser/2.0.0: + resolution: + { + integrity: sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==, + } + dependencies: + "@aws-crypto/ie11-detection": 2.0.2 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-crypto/supports-web-crypto": 2.0.2 + "@aws-crypto/util": 2.0.2 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-locate-window": 3.208.0 + "@aws-sdk/util-utf8-browser": 3.188.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/sha256-js/2.0.0: + resolution: + { + integrity: sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==, + } + dependencies: + "@aws-crypto/util": 2.0.2 + "@aws-sdk/types": 3.226.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/supports-web-crypto/2.0.2: + resolution: + { + integrity: sha512-6mbSsLHwZ99CTOOswvCRP3C+VCWnzBf+1SnbWxzzJ9lR0mA0JnY2JEAhp8rqmTE0GPFy88rrM27ffgp62oErMQ==, + } + dependencies: + tslib: 1.14.1 + dev: false + + /@aws-crypto/util/2.0.2: + resolution: + { + integrity: sha512-Lgu5v/0e/BcrZ5m/IWqzPUf3UYFTy/PpeED+uc9SWUR1iZQL8XXbGQg10UfllwwBryO3hFF5dizK+78aoXC1eA==, + } + dependencies: + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-utf8-browser": 3.188.0 + tslib: 1.14.1 + dev: false + + /@aws-sdk/abort-controller/3.226.0: + resolution: + { + integrity: sha512-cJVzr1xxPBd08voknXvR0RLgtZKGKt6WyDpH/BaPCu3rfSqWCDZKzwqe940eqosjmKrxC6pUZNKASIqHOQ8xxQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/chunked-blob-reader-native/3.208.0: + resolution: + { + integrity: sha512-JeOZ95PW+fJ6bbuqPySYqLqHk1n4+4ueEEraJsiUrPBV0S1ZtyvOGHcnGztKUjr2PYNaiexmpWuvUve9K12HRA==, + } + dependencies: + "@aws-sdk/util-base64": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/chunked-blob-reader/3.188.0: + resolution: + { + integrity: sha512-zkPRFZZPL3eH+kH86LDYYXImiClA1/sW60zYOjse9Pgka+eDJlvBN6hcYxwDEKjcwATYiSRR1aVQHcfCinlGXg==, + } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/client-s3/3.245.0: + resolution: + { + integrity: sha512-wdCrEiqIfwtWebrK7A1giRggwO64S6I2iPXTwRmat4AR6sFlMO02jVFaIDyA8TTiVnBMz7ekT1QFmIjFAKc4uQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-crypto/sha1-browser": 2.0.0 + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/client-sts": 3.245.0 + "@aws-sdk/config-resolver": 3.234.0 + "@aws-sdk/credential-provider-node": 3.245.0 + "@aws-sdk/eventstream-serde-browser": 3.226.0 + "@aws-sdk/eventstream-serde-config-resolver": 3.226.0 + "@aws-sdk/eventstream-serde-node": 3.226.0 + "@aws-sdk/fetch-http-handler": 3.226.0 + "@aws-sdk/hash-blob-browser": 3.226.0 + "@aws-sdk/hash-node": 3.226.0 + "@aws-sdk/hash-stream-node": 3.226.0 + "@aws-sdk/invalid-dependency": 3.226.0 + "@aws-sdk/md5-js": 3.226.0 + "@aws-sdk/middleware-bucket-endpoint": 3.226.0 + "@aws-sdk/middleware-content-length": 3.226.0 + "@aws-sdk/middleware-endpoint": 3.226.0 + "@aws-sdk/middleware-expect-continue": 3.226.0 + "@aws-sdk/middleware-flexible-checksums": 3.226.0 + "@aws-sdk/middleware-host-header": 3.226.0 + "@aws-sdk/middleware-location-constraint": 3.226.0 + "@aws-sdk/middleware-logger": 3.226.0 + "@aws-sdk/middleware-recursion-detection": 3.226.0 + "@aws-sdk/middleware-retry": 3.235.0 + "@aws-sdk/middleware-sdk-s3": 3.231.0 + "@aws-sdk/middleware-serde": 3.226.0 + "@aws-sdk/middleware-signing": 3.226.0 + "@aws-sdk/middleware-ssec": 3.226.0 + "@aws-sdk/middleware-stack": 3.226.0 + "@aws-sdk/middleware-user-agent": 3.226.0 + "@aws-sdk/node-config-provider": 3.226.0 + "@aws-sdk/node-http-handler": 3.226.0 + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/signature-v4-multi-region": 3.226.0 + "@aws-sdk/smithy-client": 3.234.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/url-parser": 3.226.0 + "@aws-sdk/util-base64": 3.208.0 + "@aws-sdk/util-body-length-browser": 3.188.0 + "@aws-sdk/util-body-length-node": 3.208.0 + "@aws-sdk/util-defaults-mode-browser": 3.234.0 + "@aws-sdk/util-defaults-mode-node": 3.234.0 + "@aws-sdk/util-endpoints": 3.245.0 + "@aws-sdk/util-retry": 3.229.0 + "@aws-sdk/util-stream-browser": 3.226.0 + "@aws-sdk/util-stream-node": 3.226.0 + "@aws-sdk/util-user-agent-browser": 3.226.0 + "@aws-sdk/util-user-agent-node": 3.226.0 + "@aws-sdk/util-utf8-browser": 3.188.0 + "@aws-sdk/util-utf8-node": 3.208.0 + "@aws-sdk/util-waiter": 3.226.0 + "@aws-sdk/xml-builder": 3.201.0 + fast-xml-parser: 4.0.11 + tslib: 2.4.1 + transitivePeerDependencies: + - "@aws-sdk/signature-v4-crt" + - aws-crt + dev: false + + /@aws-sdk/client-sso-oidc/3.245.0: + resolution: + { + integrity: sha512-0pGPA00kEsu2Yq1Ul+OwftHxws5YVllm4iZrPtGnqmXr7wmf6B9lOtrMQF44y7Tfw53po6+bKz08OKTEWkkjUA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/config-resolver": 3.234.0 + "@aws-sdk/fetch-http-handler": 3.226.0 + "@aws-sdk/hash-node": 3.226.0 + "@aws-sdk/invalid-dependency": 3.226.0 + "@aws-sdk/middleware-content-length": 3.226.0 + "@aws-sdk/middleware-endpoint": 3.226.0 + "@aws-sdk/middleware-host-header": 3.226.0 + "@aws-sdk/middleware-logger": 3.226.0 + "@aws-sdk/middleware-recursion-detection": 3.226.0 + "@aws-sdk/middleware-retry": 3.235.0 + "@aws-sdk/middleware-serde": 3.226.0 + "@aws-sdk/middleware-stack": 3.226.0 + "@aws-sdk/middleware-user-agent": 3.226.0 + "@aws-sdk/node-config-provider": 3.226.0 + "@aws-sdk/node-http-handler": 3.226.0 + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/smithy-client": 3.234.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/url-parser": 3.226.0 + "@aws-sdk/util-base64": 3.208.0 + "@aws-sdk/util-body-length-browser": 3.188.0 + "@aws-sdk/util-body-length-node": 3.208.0 + "@aws-sdk/util-defaults-mode-browser": 3.234.0 + "@aws-sdk/util-defaults-mode-node": 3.234.0 + "@aws-sdk/util-endpoints": 3.245.0 + "@aws-sdk/util-retry": 3.229.0 + "@aws-sdk/util-user-agent-browser": 3.226.0 + "@aws-sdk/util-user-agent-node": 3.226.0 + "@aws-sdk/util-utf8-browser": 3.188.0 + "@aws-sdk/util-utf8-node": 3.208.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sso/3.245.0: + resolution: + { + integrity: sha512-dxzRwRo55ZNQ4hQigC+cishxLSWlBrbr3iszG0FLviavLDOlnVG5UUxWpOIGvwr8pYiSfM4jnfMxiwYwiCLg1g==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/config-resolver": 3.234.0 + "@aws-sdk/fetch-http-handler": 3.226.0 + "@aws-sdk/hash-node": 3.226.0 + "@aws-sdk/invalid-dependency": 3.226.0 + "@aws-sdk/middleware-content-length": 3.226.0 + "@aws-sdk/middleware-endpoint": 3.226.0 + "@aws-sdk/middleware-host-header": 3.226.0 + "@aws-sdk/middleware-logger": 3.226.0 + "@aws-sdk/middleware-recursion-detection": 3.226.0 + "@aws-sdk/middleware-retry": 3.235.0 + "@aws-sdk/middleware-serde": 3.226.0 + "@aws-sdk/middleware-stack": 3.226.0 + "@aws-sdk/middleware-user-agent": 3.226.0 + "@aws-sdk/node-config-provider": 3.226.0 + "@aws-sdk/node-http-handler": 3.226.0 + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/smithy-client": 3.234.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/url-parser": 3.226.0 + "@aws-sdk/util-base64": 3.208.0 + "@aws-sdk/util-body-length-browser": 3.188.0 + "@aws-sdk/util-body-length-node": 3.208.0 + "@aws-sdk/util-defaults-mode-browser": 3.234.0 + "@aws-sdk/util-defaults-mode-node": 3.234.0 + "@aws-sdk/util-endpoints": 3.245.0 + "@aws-sdk/util-retry": 3.229.0 + "@aws-sdk/util-user-agent-browser": 3.226.0 + "@aws-sdk/util-user-agent-node": 3.226.0 + "@aws-sdk/util-utf8-browser": 3.188.0 + "@aws-sdk/util-utf8-node": 3.208.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sts/3.245.0: + resolution: + { + integrity: sha512-E+7v2sy34TLni/Dmz6bTU20NWvbHYH9sVUHKQ9kHhmFopUWrs4Nt77f85PbuiKJz/irjUh9ppT5q1odJNRKRVQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/config-resolver": 3.234.0 + "@aws-sdk/credential-provider-node": 3.245.0 + "@aws-sdk/fetch-http-handler": 3.226.0 + "@aws-sdk/hash-node": 3.226.0 + "@aws-sdk/invalid-dependency": 3.226.0 + "@aws-sdk/middleware-content-length": 3.226.0 + "@aws-sdk/middleware-endpoint": 3.226.0 + "@aws-sdk/middleware-host-header": 3.226.0 + "@aws-sdk/middleware-logger": 3.226.0 + "@aws-sdk/middleware-recursion-detection": 3.226.0 + "@aws-sdk/middleware-retry": 3.235.0 + "@aws-sdk/middleware-sdk-sts": 3.226.0 + "@aws-sdk/middleware-serde": 3.226.0 + "@aws-sdk/middleware-signing": 3.226.0 + "@aws-sdk/middleware-stack": 3.226.0 + "@aws-sdk/middleware-user-agent": 3.226.0 + "@aws-sdk/node-config-provider": 3.226.0 + "@aws-sdk/node-http-handler": 3.226.0 + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/smithy-client": 3.234.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/url-parser": 3.226.0 + "@aws-sdk/util-base64": 3.208.0 + "@aws-sdk/util-body-length-browser": 3.188.0 + "@aws-sdk/util-body-length-node": 3.208.0 + "@aws-sdk/util-defaults-mode-browser": 3.234.0 + "@aws-sdk/util-defaults-mode-node": 3.234.0 + "@aws-sdk/util-endpoints": 3.245.0 + "@aws-sdk/util-retry": 3.229.0 + "@aws-sdk/util-user-agent-browser": 3.226.0 + "@aws-sdk/util-user-agent-node": 3.226.0 + "@aws-sdk/util-utf8-browser": 3.188.0 + "@aws-sdk/util-utf8-node": 3.208.0 + fast-xml-parser: 4.0.11 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/config-resolver/3.234.0: + resolution: + { + integrity: sha512-uZxy4wzllfvgCQxVc+Iqhde0NGAnfmV2hWR6ejadJaAFTuYNvQiRg9IqJy3pkyDPqXySiJ8Bom5PoJfgn55J/A==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/signature-v4": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-config-provider": 3.208.0 + "@aws-sdk/util-middleware": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/credential-provider-env/3.226.0: + resolution: + { + integrity: sha512-sd8uK1ojbXxaZXlthzw/VXZwCPUtU3PjObOfr3Evj7MPIM2IH8h29foOlggx939MdLQGboJf9gKvLlvKDWtJRA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/credential-provider-imds/3.226.0: + resolution: + { + integrity: sha512-//z/COQm2AjYFI1Lb0wKHTQSrvLFTyuKLFQGPJsKS7DPoxGOCKB7hmYerlbl01IDoCxTdyL//TyyPxbZEOQD5Q==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/node-config-provider": 3.226.0 + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/url-parser": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/credential-provider-ini/3.245.0: + resolution: + { + integrity: sha512-1SjfVc5Wg0lLRUvwMrfjGgFkl+zfxn74gnkPr6by1QyMAoTzmeUkalPLAIqd+uHtFom9e3K633BQtX7zVPZ5XQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/credential-provider-env": 3.226.0 + "@aws-sdk/credential-provider-imds": 3.226.0 + "@aws-sdk/credential-provider-process": 3.226.0 + "@aws-sdk/credential-provider-sso": 3.245.0 + "@aws-sdk/credential-provider-web-identity": 3.226.0 + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/shared-ini-file-loader": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/credential-provider-node/3.245.0: + resolution: + { + integrity: sha512-Dwv8zmRLTDLeEkGrK/sLNFZSC+ahXZxr07CuID054QKACIdUEvkqYlnalRiTeXngiHGQ54u8wU7f0D32R2oL0g==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/credential-provider-env": 3.226.0 + "@aws-sdk/credential-provider-imds": 3.226.0 + "@aws-sdk/credential-provider-ini": 3.245.0 + "@aws-sdk/credential-provider-process": 3.226.0 + "@aws-sdk/credential-provider-sso": 3.245.0 + "@aws-sdk/credential-provider-web-identity": 3.226.0 + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/shared-ini-file-loader": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/credential-provider-process/3.226.0: + resolution: + { + integrity: sha512-iUDMdnrTvbvaCFhWwqyXrhvQ9+ojPqPqXhwZtY1X/Qaz+73S9gXBPJHZaZb2Ke0yKE1Ql3bJbKvmmxC/qLQMng==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/shared-ini-file-loader": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/credential-provider-sso/3.245.0: + resolution: + { + integrity: sha512-txWrJc0WNBhXMi7q+twjx7cs/qzgTfbQ+vbag5idRmdoUeiR8rfLvihCab2NaGg50xhh+TaoUCXrgJp3E/XjYQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/client-sso": 3.245.0 + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/shared-ini-file-loader": 3.226.0 + "@aws-sdk/token-providers": 3.245.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/credential-provider-web-identity/3.226.0: + resolution: + { + integrity: sha512-CCpv847rLB0SFOHz2igvUMFAzeT2fD3YnY4C8jltuJoEkn0ITn1Hlgt13nTJ5BUuvyti2mvyXZHmNzhMIMrIlw==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/eventstream-codec/3.226.0: + resolution: + { + integrity: sha512-6uPtR8vSwz3fqoZk9hrb6qBYdp3PJ22+JxV5Wimdesvow4kJXSgDQXIxEkxbv6SxB9tNRB4uJHD84RetHEi15Q==, + } + dependencies: + "@aws-crypto/crc32": 2.0.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-hex-encoding": 3.201.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/eventstream-serde-browser/3.226.0: + resolution: + { + integrity: sha512-otYC5aZE9eJUqAlKpy8w0rPDQ1eKGvZPtgxWXmFYSO2lDVGfI1nBBNmdZ4MdHqNuQ7ucsKMQYF8BFJ65K2tYPA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/eventstream-serde-universal": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/eventstream-serde-config-resolver/3.226.0: + resolution: + { + integrity: sha512-A56Gypg+lyEfA5cna+EUH9XTrj0SvRG1gwNW7lrUzviN36SeA/LFTUIOEjxVML3Lowy+EPAcrSZ67h6aepoAig==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/eventstream-serde-node/3.226.0: + resolution: + { + integrity: sha512-KWLnKkKDzI9RNkiK6OiSYpG/XjZfue6Bsp/vRG+H5z3fbXdHv4X2+iW+Efu2Kvn7jsUyUv82TCl57DyJ/HKYhQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/eventstream-serde-universal": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/eventstream-serde-universal/3.226.0: + resolution: + { + integrity: sha512-Q8viYM1Sv90/yIUqyWNeG1GEvyVlAI3GIrInQcCMC+xT59jS+IKGy2y7ojCvSWXnhf5/HMXKcmG092QsqeKy0Q==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/eventstream-codec": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/fetch-http-handler/3.226.0: + resolution: + { + integrity: sha512-JewZPMNEBXfi1xVnRa7pVtK/zgZD8/lQ/YnD8pq79WuMa2cwyhDtr8oqCoqsPW+WJT5ScXoMtuHxN78l8eKWgg==, + } + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/querystring-builder": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-base64": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/hash-blob-browser/3.226.0: + resolution: + { + integrity: sha512-5DCvWE6L4xGoViEHyjcPFuUe1G2EtNx8TqswWaoaKgyasP/yuRm4H99Ra7rqIrjCcSTAGD9NVsUQvVVw1bGt9w==, + } + dependencies: + "@aws-sdk/chunked-blob-reader": 3.188.0 + "@aws-sdk/chunked-blob-reader-native": 3.208.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/hash-node/3.226.0: + resolution: + { + integrity: sha512-MdlJhJ9/Espwd0+gUXdZRsHuostB2WxEVAszWxobP0FTT9PnicqnfK7ExmW+DUAc0ywxtEbR3e0UND65rlSTVw==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-buffer-from": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/hash-stream-node/3.226.0: + resolution: + { + integrity: sha512-cgNTGlF8SdHaQXtjEmuLXz2U8SLM2JDKtIVPku/lHTMsUsEn+fuv2C+h1f/hvd4aNw5t1zggym7sO1/h/rv56Q==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/invalid-dependency/3.226.0: + resolution: + { + integrity: sha512-QXOYFmap8g9QzRjumcRCIo2GEZkdCwd7ePQW0OABWPhKHzlJ74vvBxywjU3s39EEBEluWXtZ7Iufg6GxZM4ifw==, + } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/is-array-buffer/3.201.0: + resolution: + { + integrity: sha512-UPez5qLh3dNgt0DYnPD/q0mVJY84rA17QE26hVNOW3fAji8W2wrwrxdacWOxyXvlxWsVRcKmr+lay1MDqpAMfg==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/md5-js/3.226.0: + resolution: + { + integrity: sha512-ENigJRNudqyh6xsch166SZ4gggHd3XzZJ8gkCU4CWPne04HcR3BkWSO774IuWooCHt8zkaEHKecPurRz6qR+Vw==, + } + dependencies: + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-utf8-browser": 3.188.0 + "@aws-sdk/util-utf8-node": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-bucket-endpoint/3.226.0: + resolution: + { + integrity: sha512-A1Vq5W2X7jgTfjqcKPmjoHohF0poP+9fxwL97fQMvzcwmjhtoCV3bLEpo6CGYx0pKPiSlRJXZkRwRPj2hDHDmA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-arn-parser": 3.208.0 + "@aws-sdk/util-config-provider": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-content-length/3.226.0: + resolution: + { + integrity: sha512-ksUzlHJN2JMuyavjA46a4sctvnrnITqt2tbGGWWrAuXY1mel2j+VbgnmJUiwHKUO6bTFBBeft5Vd1TSOb4JmiA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-endpoint/3.226.0: + resolution: + { + integrity: sha512-EvLFafjtUxTT0AC9p3aBQu1/fjhWdIeK58jIXaNFONfZ3F8QbEYUPuF/SqZvJM6cWfOO9qwYKkRDbCSTYhprIg==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/middleware-serde": 3.226.0 + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/signature-v4": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/url-parser": 3.226.0 + "@aws-sdk/util-config-provider": 3.208.0 + "@aws-sdk/util-middleware": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-expect-continue/3.226.0: + resolution: + { + integrity: sha512-YxvQKTV/eA9P8AgW0hXOgj5Qa+TSnNFfyOkfeP089aP3f6p92b1cESf33TEOKsddive2mHT5LRCN6MuPcgWWrA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-flexible-checksums/3.226.0: + resolution: + { + integrity: sha512-8A9Ot9A7794UP5tMGl2MnfTW/UM/jYy1wRWF9YkR/hPIcPb7OmE0hmlwIQGzb/7grxpYw66ETKf0WeH/41YfeQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-crypto/crc32": 2.0.0 + "@aws-crypto/crc32c": 2.0.0 + "@aws-sdk/is-array-buffer": 3.201.0 + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-host-header/3.226.0: + resolution: + { + integrity: sha512-haVkWVh6BUPwKgWwkL6sDvTkcZWvJjv8AgC8jiQuSl8GLZdzHTB8Qhi3IsfFta9HAuoLjxheWBE5Z/L0UrfhLA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-location-constraint/3.226.0: + resolution: + { + integrity: sha512-qHiYaBYPc2R37KxG2uqsUUwh4usrQMHfGkrpTUnx5d4rGzM3mC+muPsTpSHnAL63K2/yJOHQJFjss3GGwV4SSA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-logger/3.226.0: + resolution: + { + integrity: sha512-m9gtLrrYnpN6yckcQ09rV7ExWOLMuq8mMPF/K3DbL/YL0TuILu9i2T1W+JuxSX+K9FMG2HrLAKivE/kMLr55xA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-recursion-detection/3.226.0: + resolution: + { + integrity: sha512-mwRbdKEUeuNH5TEkyZ5FWxp6bL2UC1WbY+LDv6YjHxmSMKpAoOueEdtU34PqDOLrpXXxIGHDFmjeGeMfktyEcA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-retry/3.235.0: + resolution: + { + integrity: sha512-50WHbJGpD3SNp9763MAlHqIhXil++JdQbKejNpHg7HsJne/ao3ub+fDOfx//mMBjpzBV25BGd5UlfL6blrClSg==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/service-error-classification": 3.229.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-middleware": 3.226.0 + "@aws-sdk/util-retry": 3.229.0 + tslib: 2.4.1 + uuid: 8.3.2 + dev: false + + /@aws-sdk/middleware-sdk-s3/3.231.0: + resolution: + { + integrity: sha512-UGaSvevd2TanfKgStF46dDSHkh4bxOr1gdUkyHm9i+1pF5lx4KdbnBZv/5SKnn7XifhHRXrs1M3lTzemXREhTA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-arn-parser": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-sdk-sts/3.226.0: + resolution: + { + integrity: sha512-NN9T/qoSD1kZvAT+VLny3NnlqgylYQcsgV3rvi/8lYzw/G/2s8VS6sm/VTWGGZhx08wZRv20MWzYu3bftcyqUg==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/middleware-signing": 3.226.0 + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/signature-v4": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-serde/3.226.0: + resolution: + { + integrity: sha512-nPuOOAkSfx9TxzdKFx0X2bDlinOxGrqD7iof926K/AEflxGD1DBdcaDdjlYlPDW2CVE8LV/rAgbYuLxh/E/1VA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-signing/3.226.0: + resolution: + { + integrity: sha512-E6HmtPcl+IjYDDzi1xI2HpCbBq2avNWcjvCriMZWuTAtRVpnA6XDDGW5GY85IfS3A8G8vuWqEVPr8JcYUcjfew==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/signature-v4": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-middleware": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-ssec/3.226.0: + resolution: + { + integrity: sha512-DR97oWoLHiMdaUP/wu99HtzG7/ijvCrjZGDH37WBO1rxFtEti6L7T09wgHzwxMN8gtL8FJA7dU8IrffGSC9VmA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-stack/3.226.0: + resolution: + { + integrity: sha512-85wF29LvPvpoed60fZGDYLwv1Zpd/cM0C22WSSFPw1SSJeqO4gtFYyCg2squfT3KI6kF43IIkOCJ+L7GtryPug==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/middleware-user-agent/3.226.0: + resolution: + { + integrity: sha512-N1WnfzCW1Y5yWhVAphf8OPGTe8Df3vmV7/LdsoQfmpkCZgLZeK2o0xITkUQhRj1mbw7yp8tVFLFV3R2lMurdAQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/node-config-provider/3.226.0: + resolution: + { + integrity: sha512-B8lQDqiRk7X5izFEUMXmi8CZLOKCTWQJU9HQf3ako+sF0gexo4nHN3jhoRWyLtcgC5S3on/2jxpAcqtm7kuY3w==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/shared-ini-file-loader": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/node-http-handler/3.226.0: + resolution: + { + integrity: sha512-xQCddnZNMiPmjr3W7HYM+f5ir4VfxgJh37eqZwX6EZmyItFpNNeVzKUgA920ka1VPz/ZUYB+2OFGiX3LCLkkaA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/abort-controller": 3.226.0 + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/querystring-builder": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/property-provider/3.226.0: + resolution: + { + integrity: sha512-TsljjG+Sg0LmdgfiAlWohluWKnxB/k8xenjeozZfzOr5bHmNHtdbWv6BtNvD/R83hw7SFXxbJHlD5H4u9p2NFg==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/protocol-http/3.226.0: + resolution: + { + integrity: sha512-zWkVqiTA9RXL6y0hhfZc9bcU4DX2NI6Hw9IhQmSPeM59mdbPjJlY4bLlMr5YxywqO3yQ/ylNoAfrEzrDjlOSRg==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/querystring-builder/3.226.0: + resolution: + { + integrity: sha512-LVurypuNeotO4lmirKXRC4NYrZRAyMJXuwO0f2a5ZAUJCjauwYrifKue6yCfU7bls7gut7nfcR6B99WBYpHs3g==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-uri-escape": 3.201.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/querystring-parser/3.226.0: + resolution: + { + integrity: sha512-FzB+VrQ47KAFxiPt2YXrKZ8AOLZQqGTLCKHzx4bjxGmwgsjV8yIbtJiJhZLMcUQV4LtGeIY9ixIqQhGvnZHE4A==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/service-error-classification/3.229.0: + resolution: + { + integrity: sha512-dnzWWQ0/NoWMUZ5C0DW3dPm0wC1O76Y/SpKbuJzWPkx1EYy6r8p32Ly4D9vUzrKDbRGf48YHIF2kOkBmu21CLg==, + } + engines: { node: ">=14.0.0" } + dev: false + + /@aws-sdk/shared-ini-file-loader/3.226.0: + resolution: + { + integrity: sha512-661VQefsARxVyyV2FX9V61V+nNgImk7aN2hYlFKla6BCwZfMng+dEtD0xVGyg1PfRw0qvEv5LQyxMVgHcUSevA==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/signature-v4-multi-region/3.226.0: + resolution: + { + integrity: sha512-QHxNuf9ynK208v7Y3imdsa3Cz8ynYV7ZOf3sBJdItuEtHN6uy/KxaOrtvpF8I5Hyn48Hc8z5miTSMujFKT7GEw==, + } + engines: { node: ">=14.0.0" } + peerDependencies: + "@aws-sdk/signature-v4-crt": ^3.118.0 + peerDependenciesMeta: + "@aws-sdk/signature-v4-crt": + optional: true + dependencies: + "@aws-sdk/protocol-http": 3.226.0 + "@aws-sdk/signature-v4": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-arn-parser": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/signature-v4/3.226.0: + resolution: + { + integrity: sha512-/R5q5agdPd7HJB68XMzpxrNPk158EHUvkFkuRu5Qf3kkkHebEzWEBlWoVpUe6ss4rP9Tqcue6xPuaftEmhjpYw==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/is-array-buffer": 3.201.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-hex-encoding": 3.201.0 + "@aws-sdk/util-middleware": 3.226.0 + "@aws-sdk/util-uri-escape": 3.201.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/smithy-client/3.234.0: + resolution: + { + integrity: sha512-8AtR/k4vsFvjXeQbIzq/Wy7Nbk48Ou0wUEeVYPHWHPSU8QamFWORkOwmKtKMfHAyZvmqiAPeQqHFkq+UJhWyyQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/middleware-stack": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/token-providers/3.245.0: + resolution: + { + integrity: sha512-m/spXR/vEXGb+zMqRUMQYVMwFZSTdK5RkddYqamYkNhIoLm60EYeRu57JsMMs5djKi8dBRSKiXwVHx0l2rXMjg==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/client-sso-oidc": 3.245.0 + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/shared-ini-file-loader": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/types/3.226.0: + resolution: + { + integrity: sha512-MmmNHrWeO4man7wpOwrAhXlevqtOV9ZLcH4RhnG5LmRce0RFOApx24HoKENfFCcOyCm5LQBlsXCqi0dZWDWU0A==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/url-parser/3.226.0: + resolution: + { + integrity: sha512-p5RLE0QWyP0OcTOLmFcLdVgUcUEzmEfmdrnOxyNzomcYb0p3vUagA5zfa1HVK2azsQJFBv28GfvMnba9bGhObg==, + } + dependencies: + "@aws-sdk/querystring-parser": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-arn-parser/3.208.0: + resolution: + { + integrity: sha512-QV4af+kscova9dv4VuHOgH8wEr/IIYHDGcnyVtkUEqahCejWr1Kuk+SBK0xMwnZY5LSycOtQ8aeqHOn9qOjZtA==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-base64/3.208.0: + resolution: + { + integrity: sha512-PQniZph5A6N7uuEOQi+1hnMz/FSOK/8kMFyFO+4DgA1dZ5pcKcn5wiFwHkcTb/BsgVqQa3Jx0VHNnvhlS8JyTg==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/util-buffer-from": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-body-length-browser/3.188.0: + resolution: + { + integrity: sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==, + } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-body-length-node/3.208.0: + resolution: + { + integrity: sha512-3zj50e5g7t/MQf53SsuuSf0hEELzMtD8RX8C76f12OSRo2Bca4FLLYHe0TZbxcfQHom8/hOaeZEyTyMogMglqg==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-buffer-from/3.208.0: + resolution: + { + integrity: sha512-7L0XUixNEFcLUGPeBF35enCvB9Xl+K6SQsmbrPk1P3mlV9mguWSDQqbOBwY1Ir0OVbD6H/ZOQU7hI/9RtRI0Zw==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/is-array-buffer": 3.201.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-config-provider/3.208.0: + resolution: + { + integrity: sha512-DSRqwrERUsT34ug+anlMBIFooBEGwM8GejC7q00Y/9IPrQy50KnG5PW2NiTjuLKNi7pdEOlwTSEocJE15eDZIg==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-defaults-mode-browser/3.234.0: + resolution: + { + integrity: sha512-IHMKXjTbOD8XMz5+2oCOsVP94BYb9YyjXdns0aAXr2NAo7k2+RCzXQ2DebJXppGda1F6opFutoKwyVSN0cmbMw==, + } + engines: { node: ">= 10.0.0" } + dependencies: + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/types": 3.226.0 + bowser: 2.11.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-defaults-mode-node/3.234.0: + resolution: + { + integrity: sha512-UGjQ+OjBYYhxFVtUY+jtr0ZZgzZh6OHtYwRhFt8IHewJXFCfZTyfsbX20szBj5y1S4HRIUJ7cwBLIytTqMbI5w==, + } + engines: { node: ">= 10.0.0" } + dependencies: + "@aws-sdk/config-resolver": 3.234.0 + "@aws-sdk/credential-provider-imds": 3.226.0 + "@aws-sdk/node-config-provider": 3.226.0 + "@aws-sdk/property-provider": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-endpoints/3.245.0: + resolution: + { + integrity: sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-hex-encoding/3.201.0: + resolution: + { + integrity: sha512-7t1vR1pVxKx0motd3X9rI3m/xNp78p3sHtP5yo4NP4ARpxyJ0fokBomY8ScaH2D/B+U5o9ARxldJUdMqyBlJcA==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-locate-window/3.208.0: + resolution: + { + integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-middleware/3.226.0: + resolution: + { + integrity: sha512-B96CQnwX4gRvQdaQkdUtqvDPkrptV5+va6FVeJOocU/DbSYMAScLxtR3peMS8cnlOT6nL1Eoa42OI9AfZz1VwQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-retry/3.229.0: + resolution: + { + integrity: sha512-0zKTqi0P1inD0LzIMuXRIYYQ/8c1lWMg/cfiqUcIAF1TpatlpZuN7umU0ierpBFud7S+zDgg0oemh+Nj8xliJw==, + } + engines: { node: ">= 14.0.0" } + dependencies: + "@aws-sdk/service-error-classification": 3.229.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-stream-browser/3.226.0: + resolution: + { + integrity: sha512-ZvjlA1ySaLd0DqUWTKmL7LsxfPhroAONpzsinaHmw9aZVL40s2cADU9eWgBdHTuAOeFklL7NP0cc6UiTFHKe8g==, + } + dependencies: + "@aws-sdk/fetch-http-handler": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-base64": 3.208.0 + "@aws-sdk/util-hex-encoding": 3.201.0 + "@aws-sdk/util-utf8-browser": 3.188.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-stream-node/3.226.0: + resolution: + { + integrity: sha512-HADXiIgDGoXcCLSKuPnjCLENf0iC0lzqqnymZu9H2FoACZhJB7DvJ9LnP51Pvw9lfCu+yvLzbMqSPdbXtMbRWg==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/node-http-handler": 3.226.0 + "@aws-sdk/types": 3.226.0 + "@aws-sdk/util-buffer-from": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-uri-escape/3.201.0: + resolution: + { + integrity: sha512-TeTWbGx4LU2c5rx0obHeDFeO9HvwYwQtMh1yniBz00pQb6Qt6YVOETVQikRZ+XRQwEyCg/dA375UplIpiy54mA==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-user-agent-browser/3.226.0: + resolution: + { + integrity: sha512-PhBIu2h6sPJPcv2I7ELfFizdl5pNiL4LfxrasMCYXQkJvVnoXztHA1x+CQbXIdtZOIlpjC+6BjDcE0uhnpvfcA==, + } + dependencies: + "@aws-sdk/types": 3.226.0 + bowser: 2.11.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-user-agent-node/3.226.0: + resolution: + { + integrity: sha512-othPc5Dz/pkYkxH+nZPhc1Al0HndQT8zHD4e9h+EZ+8lkd8n+IsnLfTS/mSJWrfiC6UlNRVw55cItstmJyMe/A==, + } + engines: { node: ">=14.0.0" } + peerDependencies: + aws-crt: ">=1.0.0" + peerDependenciesMeta: + aws-crt: + optional: true + dependencies: + "@aws-sdk/node-config-provider": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-utf8-browser/3.188.0: + resolution: + { + integrity: sha512-jt627x0+jE+Ydr9NwkFstg3cUvgWh56qdaqAMDsqgRlKD21md/6G226z/Qxl7lb1VEW2LlmCx43ai/37Qwcj2Q==, + } + dependencies: + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-utf8-node/3.208.0: + resolution: + { + integrity: sha512-jKY87Acv0yWBdFxx6bveagy5FYjz+dtV8IPT7ay1E2WPWH1czoIdMAkc8tSInK31T6CRnHWkLZ1qYwCbgRfERQ==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/util-buffer-from": 3.208.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/util-waiter/3.226.0: + resolution: + { + integrity: sha512-qYQMRxnu5k8qQihJXoIWMkBOj0+XkHHj/drLdbRnwL6ni6NcG8++cs9M3DSjIcxmxgF/7SLpDjn1H3sC7cYo4g==, + } + engines: { node: ">=14.0.0" } + dependencies: + "@aws-sdk/abort-controller": 3.226.0 + "@aws-sdk/types": 3.226.0 + tslib: 2.4.1 + dev: false + + /@aws-sdk/xml-builder/3.201.0: + resolution: + { + integrity: sha512-brRdB1wwMgjWEnOQsv7zSUhIQuh7DEicrfslAqHop4S4FtSI3GQAShpQqgOpMTNFYcpaWKmE/Y1MJmNY7xLCnw==, + } + engines: { node: ">=14.0.0" } + dependencies: + tslib: 2.4.1 + dev: false + + /@babel/runtime/7.20.7: + resolution: + { + integrity: sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==, + } + engines: { node: ">=6.9.0" } + dependencies: + regenerator-runtime: 0.13.11 + + /@cspotcode/source-map-support/0.8.1: + resolution: + { + integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, + } + engines: { node: ">=12" } + dependencies: + "@jridgewell/trace-mapping": 0.3.9 + dev: false + + /@gar/promisify/1.1.3: + resolution: + { + integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==, + } + dev: false + optional: true + + /@jridgewell/resolve-uri/3.1.0: + resolution: + { + integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==, + } + engines: { node: ">=6.0.0" } + dev: false + + /@jridgewell/sourcemap-codec/1.4.14: + resolution: + { + integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==, + } + dev: false + + /@jridgewell/trace-mapping/0.3.9: + resolution: + { + integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==, + } + dependencies: + "@jridgewell/resolve-uri": 3.1.0 + "@jridgewell/sourcemap-codec": 1.4.14 + dev: false + + /@mapbox/node-pre-gyp/1.0.10: + resolution: + { + integrity: sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==, + } + hasBin: true + dependencies: + detect-libc: 2.0.1 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.6.7 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.3.8 + tar: 6.1.13 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /@npmcli/fs/1.1.1: + resolution: + { + integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==, + } + dependencies: + "@gar/promisify": 1.1.3 + semver: 7.3.8 + dev: false + optional: true + + /@npmcli/move-file/1.1.2: + resolution: + { + integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==, + } + engines: { node: ">=10" } + deprecated: This functionality has been moved to @npmcli/fs + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + dev: false + optional: true + + /@sentry/core/7.30.0: + resolution: + { + integrity: sha512-NeLigkBlpcK63ymM63GoIHurml6V3BUe1Vi+trwm4/qqOTzT7PQhvdJCX+o3+atzRBH+zdb6kd4VWx44Oye3KA==, + } + engines: { node: ">=8" } + dependencies: + "@sentry/types": 7.30.0 + "@sentry/utils": 7.30.0 + tslib: 1.14.1 + dev: false + + /@sentry/integrations/7.30.0: + resolution: + { + integrity: sha512-KU8TnJm1Yldxnhdu/EZcIGXU9ptGQPk6ot4smcNx/mKsy575VrDdyVDx8uIYURWyfsg7eOayt6VdC7ISSODp8A==, + } + engines: { node: ">=8" } + dependencies: + "@sentry/types": 7.30.0 + "@sentry/utils": 7.30.0 + localforage: 1.10.0 + tslib: 1.14.1 + dev: false + + /@sentry/node/7.30.0: + resolution: + { + integrity: sha512-YYasu6C3I0HBP4N1oc/ed2nunxhGJgtAWaKwq3lo8uk3uF6cB1A8+2e0CpjzU5ejhbaFPUBxHyj4th39Bvku/w==, + } + engines: { node: ">=8" } + dependencies: + "@sentry/core": 7.30.0 + "@sentry/types": 7.30.0 + "@sentry/utils": 7.30.0 + cookie: 0.4.2 + https-proxy-agent: 5.0.1 + lru_map: 0.3.3 + tslib: 1.14.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@sentry/tracing/7.30.0: + resolution: + { + integrity: sha512-bjGeDeKhpGAmLcWcrXFT/xOfHVwp/j0L1aRHzYHnqgTjVzD0NXcooPu/Nz8vF0paxz+hPD5bJwb8kz/ggJzGWQ==, + } + engines: { node: ">=8" } + dependencies: + "@sentry/core": 7.30.0 + "@sentry/types": 7.30.0 + "@sentry/utils": 7.30.0 + tslib: 1.14.1 + dev: false + + /@sentry/types/7.30.0: + resolution: + { + integrity: sha512-l4A86typvt/SfWh5JffpdxNGkg5EEA8m35BzpIcKmCAQZUDmnb4b478r8jdD2uuOjLmPNmZr1tifdRW4NCLuxQ==, + } + engines: { node: ">=8" } + dev: false + + /@sentry/utils/7.30.0: + resolution: + { + integrity: sha512-tSlBhr5u/LdE2emxIDTDmjmyRr99GnZGIAh5GwRxUgeDQ3VEfNUFlyFodBCbZ6yeYTYd6PWNih5xoHn1+Rf3Sw==, + } + engines: { node: ">=8" } + dependencies: + "@sentry/types": 7.30.0 + tslib: 1.14.1 + dev: false + + /@sqltools/formatter/1.2.5: + resolution: + { + integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==, + } + dev: false + + /@tokenizer/token/0.3.0: + resolution: + { + integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==, + } + dev: false + + /@tootallnate/once/1.1.2: + resolution: + { + integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==, + } + engines: { node: ">= 6" } + dev: false + + /@tsconfig/node10/1.0.9: + resolution: + { + integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==, + } + dev: false + + /@tsconfig/node12/1.0.11: + resolution: + { + integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==, + } + dev: false + + /@tsconfig/node14/1.0.3: + resolution: + { + integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==, + } + dev: false + + /@tsconfig/node16/1.0.3: + resolution: + { + integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==, + } + dev: false + + /@types/amqplib/0.8.2: + resolution: + { + integrity: sha512-p+TFLzo52f8UanB+Nq6gyUi65yecAcRY3nYowU6MPGFtaJvEDxcnFWrxssSTkF+ts1W3zyQDvgVICLQem5WxRA==, + } + dependencies: + "@types/bluebird": 3.5.38 + "@types/node": 18.11.18 + dev: true + + /@types/bcrypt/5.0.0: + resolution: + { + integrity: sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==, + } + dependencies: + "@types/node": 18.11.18 + dev: true + + /@types/bluebird/3.5.38: + resolution: + { + integrity: sha512-yR/Kxc0dd4FfwtEoLZMoqJbM/VE/W7hXn/MIjb+axcwag0iFmSPK7OBUZq1YWLynJUoWQkfUrI7T0HDqGApNSg==, + } + dev: true + + /@types/body-parser/1.19.2: + resolution: + { + integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==, + } + dependencies: + "@types/connect": 3.4.35 + "@types/node": 18.11.18 + dev: true + + /@types/connect/3.4.35: + resolution: + { + integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==, + } + dependencies: + "@types/node": 18.11.18 + dev: true + + /@types/cookie-parser/1.4.3: + resolution: + { + integrity: sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==, + } + dependencies: + "@types/express": 4.17.15 + dev: true + + /@types/express-serve-static-core/4.17.32: + resolution: + { + integrity: sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==, + } + dependencies: + "@types/node": 18.11.18 + "@types/qs": 6.9.7 + "@types/range-parser": 1.2.4 + dev: true + + /@types/express/4.17.15: + resolution: + { + integrity: sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==, + } + dependencies: + "@types/body-parser": 1.19.2 + "@types/express-serve-static-core": 4.17.32 + "@types/qs": 6.9.7 + "@types/serve-static": 1.15.0 + dev: true + + /@types/i18next-node-fs-backend/2.1.1: + resolution: + { + integrity: sha512-ESvH90OICQkKU3yuuRzF6YfHt5KACE55FOiUM59mMGnC+h03lHGdEYo3z3THbwS5FdMskLyIs2O7f6Oaz8P9sw==, + } + dependencies: + i18next: 21.10.0 + dev: true + + /@types/json-bigint/1.0.1: + resolution: + { + integrity: sha512-zpchZLNsNuzJHi6v64UBoFWAvQlPhch7XAi36FkH6tL1bbbmimIF+cS7vwkzY4u5RaSWMoflQfu+TshMPPw8uw==, + } + dev: true + + /@types/json-schema/7.0.11: + resolution: + { + integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==, + } + dev: false + + /@types/jsonwebtoken/8.5.9: + resolution: + { + integrity: sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==, + } + dependencies: + "@types/node": 18.11.18 + dev: true + + /@types/mime/3.0.1: + resolution: + { + integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==, + } + dev: true + + /@types/minimatch/3.0.5: + resolution: + { + integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==, + } + dev: true + + /@types/morgan/1.9.4: + resolution: + { + integrity: sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==, + } + dependencies: + "@types/node": 18.11.18 + dev: true + + /@types/multer/1.4.7: + resolution: + { + integrity: sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==, + } + dependencies: + "@types/express": 4.17.15 + dev: true + + /@types/needle/3.2.0: + resolution: + { + integrity: sha512-6XzvzEyJ2ozFNfPajFmqH9JOt0Hp+9TawaYpJT59iIP/zR0U37cfWCRwosyIeEBBZBi021Osq4jGAD3AOju5fg==, + } + dependencies: + "@types/node": 18.11.18 + dev: true + + /@types/node-fetch/2.6.2: + resolution: + { + integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==, + } + dependencies: + "@types/node": 18.11.18 + form-data: 3.0.1 + dev: true + + /@types/node-os-utils/1.3.0: + resolution: + { + integrity: sha512-XwVteWQx/XkfRPyaGkw8dEbrCAkoRZ73pI3XznUYIpzbCfpQB3UnDlR5TnmdhetlT889tUJGF8QWo9xrgTpsiA==, + } + dev: true + + /@types/node/14.18.36: + resolution: + { + integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==, + } + dev: false + + /@types/node/18.11.18: + resolution: + { + integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==, + } + + /@types/notp/2.0.2: + resolution: + { + integrity: sha512-JUcVYN9Tmw0AjoAfvjslS4hbv39fPBbZdftBK3b50g5z/DmhLsu6cd0UOEBiQuMwy2FirshF2Gk9gAvfWjshMw==, + } + dependencies: + "@types/node": 18.11.18 + dev: false + + /@types/probe-image-size/7.2.0: + resolution: + { + integrity: sha512-R5H3vw62gHNHrn+JGZbKejb+Z2D/6E5UNVlhCzIaBBLroMQMOFqy5Pap2gM+ZZHdqBtVU0/cx/M6to+mOJcoew==, + } + dependencies: + "@types/needle": 3.2.0 + "@types/node": 18.11.18 + dev: true + + /@types/qs/6.9.7: + resolution: + { + integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==, + } + dev: true + + /@types/range-parser/1.2.4: + resolution: + { + integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==, + } + dev: true + + /@types/serve-static/1.15.0: + resolution: + { + integrity: sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==, + } + dependencies: + "@types/mime": 3.0.1 + "@types/node": 18.11.18 + dev: true + + /@types/sharp/0.31.1: + resolution: + { + integrity: sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag==, + } + dependencies: + "@types/node": 18.11.18 + dev: true + + /@types/stream-buffers/3.0.4: + resolution: + { + integrity: sha512-qU/K1tb2yUdhXkLIATzsIPwbtX6BpZk0l3dPW6xqWyhfzzM1ECaQ/8faEnu3CNraLiQ9LHyQQPBGp7N9Fbs25w==, + } + dependencies: + "@types/node": 18.11.18 + dev: false + + /@types/ws/8.5.4: + resolution: + { + integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==, + } + dependencies: + "@types/node": 18.11.18 + dev: true + + /@yukikaze-bot/erlpack/1.0.1: + resolution: + { + integrity: sha512-PCJ2lGCf8DsQtrE411PY+NTsolK48l4InNn1kcBo0iUllKZYGLqeqXEWGA/INrmwanKcoYkU4pBySqUFLQDEoA==, + } + requiresBuild: true + dependencies: + "@mapbox/node-pre-gyp": 1.0.10 + node-addon-api: 4.3.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + optional: true + + /abbrev/1.1.1: + resolution: + { + integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==, + } + dev: false + + /accepts/1.3.8: + resolution: + { + integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==, + } + engines: { node: ">= 0.6" } + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + /acorn-walk/8.2.0: + resolution: + { + integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==, + } + engines: { node: ">=0.4.0" } + dev: false + + /acorn/8.8.1: + resolution: + { + integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==, + } + engines: { node: ">=0.4.0" } + hasBin: true + dev: false + + /agent-base/6.0.2: + resolution: + { + integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==, + } + engines: { node: ">= 6.0.0" } + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /agentkeepalive/4.2.1: + resolution: + { + integrity: sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==, + } + engines: { node: ">= 8.0.0" } + dependencies: + debug: 4.3.4 + depd: 1.1.2 + humanize-ms: 1.2.1 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /aggregate-error/3.1.0: + resolution: + { + integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==, + } + engines: { node: ">=8" } + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: false + optional: true + + /ajv-formats/2.1.1_ajv@8.6.2: + resolution: + { + integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==, + } + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.6.2 + dev: false + + /ajv/8.6.2: + resolution: + { + integrity: sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==, + } + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: false + + /amqplib/0.10.3: + resolution: + { + integrity: sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==, + } + engines: { node: ">=10" } + dependencies: + "@acuminous/bitsyntax": 0.1.2 + buffer-more-ints: 1.0.0 + readable-stream: 1.1.14 + url-parse: 1.5.10 + transitivePeerDependencies: + - supports-color + dev: false + + /ansi-regex/5.0.1: + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: ">=8" } + dev: false + + /ansi-styles/4.3.0: + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: ">=8" } + dependencies: + color-convert: 2.0.1 + + /any-promise/1.3.0: + resolution: + { + integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, + } + dev: false + + /app-root-path/3.1.0: + resolution: + { + integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==, + } + engines: { node: ">= 6.0.0" } + dev: false + + /append-field/1.0.0: + resolution: + { + integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==, + } + dev: false + + /aproba/2.0.0: + resolution: + { + integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==, + } + dev: false + + /are-we-there-yet/2.0.0: + resolution: + { + integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==, + } + engines: { node: ">=10" } + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.0 + dev: false + + /are-we-there-yet/3.0.1: + resolution: + { + integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.0 + dev: false + optional: true + + /arg/4.1.3: + resolution: + { + integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==, + } + dev: false + + /argparse/1.0.10: + resolution: + { + integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==, + } + dependencies: + sprintf-js: 1.0.3 + dev: false + + /argparse/2.0.1: + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } + dev: false + + /array-differ/3.0.0: + resolution: + { + integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==, + } + engines: { node: ">=8" } + dev: true + + /array-flatten/1.1.1: + resolution: + { + integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==, + } + + /array-union/2.1.0: + resolution: + { + integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==, + } + engines: { node: ">=8" } + dev: true + + /arrify/2.0.1: + resolution: + { + integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==, + } + engines: { node: ">=8" } + dev: true + + /ast-types/0.13.4: + resolution: + { + integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==, + } + engines: { node: ">=4" } + dependencies: + tslib: 2.4.1 + dev: false + + /asynckit/0.4.0: + resolution: + { + integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, + } + + /balanced-match/1.0.2: + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } + + /base64-js/1.5.1: + resolution: + { + integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, + } + dev: false + + /basic-auth/2.0.1: + resolution: + { + integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==, + } + engines: { node: ">= 0.8" } + dependencies: + safe-buffer: 5.1.2 + dev: false + + /bcrypt/5.1.0: + resolution: + { + integrity: sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==, + } + engines: { node: ">= 10.0.0" } + requiresBuild: true + dependencies: + "@mapbox/node-pre-gyp": 1.0.10 + node-addon-api: 5.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /bignumber.js/9.1.1: + resolution: + { + integrity: sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==, + } + dev: false + + /body-parser/1.20.1: + resolution: + { + integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==, + } + engines: { node: ">= 0.8", npm: 1.2.8000 || >= 1.4.16 } + dependencies: + bytes: 3.1.2 + content-type: 1.0.4 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + /boolbase/1.0.0: + resolution: + { + integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==, + } + dev: false + + /bowser/2.11.0: + resolution: + { + integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==, + } + dev: false + + /brace-expansion/1.1.11: + resolution: + { + integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, + } + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /buffer-equal-constant-time/1.0.1: + resolution: + { + integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==, + } + dev: false + + /buffer-from/1.1.2: + resolution: + { + integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, + } + dev: false + + /buffer-more-ints/1.0.0: + resolution: + { + integrity: sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==, + } + dev: false + + /buffer/6.0.3: + resolution: + { + integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==, + } + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /busboy/1.6.0: + resolution: + { + integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, + } + engines: { node: ">=10.16.0" } + dependencies: + streamsearch: 1.1.0 + dev: false + + /bytes/3.1.2: + resolution: + { + integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==, + } + engines: { node: ">= 0.8" } + + /cacache/15.3.0: + resolution: + { + integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==, + } + engines: { node: ">= 10" } + dependencies: + "@npmcli/fs": 1.1.1 + "@npmcli/move-file": 1.1.2 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 7.2.3 + infer-owner: 1.0.4 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 8.0.1 + tar: 6.1.13 + unique-filename: 1.1.1 + transitivePeerDependencies: + - bluebird + dev: false + optional: true + + /call-bind/1.0.2: + resolution: + { + integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==, + } + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.1.3 + + /chalk/3.0.0: + resolution: + { + integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==, + } + engines: { node: ">=8" } + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chalk/4.1.2: + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: ">=10" } + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: false + + /cheerio-select/2.1.0: + resolution: + { + integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==, + } + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.0.1 + dev: false + + /cheerio/1.0.0-rc.12: + resolution: + { + integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==, + } + engines: { node: ">= 6" } + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.0.1 + htmlparser2: 8.0.1 + parse5: 7.1.2 + parse5-htmlparser2-tree-adapter: 7.0.0 + dev: false + + /chownr/2.0.0: + resolution: + { + integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==, + } + engines: { node: ">=10" } + dev: false + + /clean-stack/2.2.0: + resolution: + { + integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==, + } + engines: { node: ">=6" } + dev: false + optional: true + + /cli-highlight/2.1.11: + resolution: + { + integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==, + } + engines: { node: ">=8.0.0", npm: ">=5.0.0" } + hasBin: true + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + dev: false + + /cliui/7.0.4: + resolution: + { + integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==, + } + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false + + /cliui/8.0.1: + resolution: + { + integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, + } + engines: { node: ">=12" } + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false + + /color-convert/2.0.1: + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: ">=7.0.0" } + dependencies: + color-name: 1.1.4 + + /color-name/1.1.4: + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } + + /color-support/1.1.3: + resolution: + { + integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==, + } + hasBin: true + dev: false + + /combined-stream/1.0.8: + resolution: + { + integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, + } + engines: { node: ">= 0.8" } + dependencies: + delayed-stream: 1.0.0 + + /concat-map/0.0.1: + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } + + /concat-stream/1.6.2: + resolution: + { + integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==, + } + engines: { "0": node >= 0.8 } + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.7 + typedarray: 0.0.6 + dev: false + + /console-control-strings/1.1.0: + resolution: + { + integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==, + } + dev: false + + /content-disposition/0.5.4: + resolution: + { + integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==, + } + engines: { node: ">= 0.6" } + dependencies: + safe-buffer: 5.2.1 + + /content-type/1.0.4: + resolution: + { + integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==, + } + engines: { node: ">= 0.6" } + + /cookie-parser/1.4.6: + resolution: + { + integrity: sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==, + } + engines: { node: ">= 0.8.0" } + dependencies: + cookie: 0.4.1 + cookie-signature: 1.0.6 + dev: false + + /cookie-signature/1.0.6: + resolution: + { + integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==, + } + + /cookie/0.4.1: + resolution: + { + integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==, + } + engines: { node: ">= 0.6" } + dev: false + + /cookie/0.4.2: + resolution: + { + integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==, + } + engines: { node: ">= 0.6" } + dev: false + + /cookie/0.5.0: + resolution: + { + integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==, + } + engines: { node: ">= 0.6" } + + /core-util-is/1.0.3: + resolution: + { + integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, + } + dev: false + + /create-require/1.1.1: + resolution: + { + integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==, + } + dev: false + + /cross-spawn/7.0.3: + resolution: + { + integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==, + } + engines: { node: ">= 8" } + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /css-select/5.1.0: + resolution: + { + integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==, + } + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.0.1 + nth-check: 2.1.1 + dev: false + + /css-what/6.1.0: + resolution: + { + integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==, + } + engines: { node: ">= 6" } + dev: false + + /data-uri-to-buffer/3.0.1: + resolution: + { + integrity: sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==, + } + engines: { node: ">= 6" } + dev: false + + /date-fns/2.29.3: + resolution: + { + integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==, + } + engines: { node: ">=0.11" } + dev: false + + /debug/2.6.9: + resolution: + { + integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==, + } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + + /debug/3.2.7: + resolution: + { + integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, + } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: false + + /debug/4.3.4: + resolution: + { + integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, + } + engines: { node: ">=6.0" } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: false + + /deep-is/0.1.4: + resolution: + { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } + dev: false + + /degenerator/3.0.2: + resolution: + { + integrity: sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==, + } + engines: { node: ">= 6" } + dependencies: + ast-types: 0.13.4 + escodegen: 1.14.3 + esprima: 4.0.1 + vm2: 3.9.13 + dev: false + + /delayed-stream/1.0.0: + resolution: + { + integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, + } + engines: { node: ">=0.4.0" } + + /delegates/1.0.0: + resolution: + { + integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==, + } + dev: false + + /depd/1.1.2: + resolution: + { + integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==, + } + engines: { node: ">= 0.6" } + dev: false + optional: true + + /depd/2.0.0: + resolution: + { + integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==, + } + engines: { node: ">= 0.8" } + + /destroy/1.2.0: + resolution: + { + integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==, + } + engines: { node: ">= 0.8", npm: 1.2.8000 || >= 1.4.16 } + + /detect-libc/2.0.1: + resolution: + { + integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==, + } + engines: { node: ">=8" } + dev: false + + /diff/4.0.2: + resolution: + { + integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==, + } + engines: { node: ">=0.3.1" } + dev: false + + /dom-serializer/2.0.0: + resolution: + { + integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==, + } + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.4.0 + dev: false + + /domelementtype/2.3.0: + resolution: + { + integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, + } + dev: false + + /domhandler/5.0.3: + resolution: + { + integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==, + } + engines: { node: ">= 4" } + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils/3.0.1: + resolution: + { + integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==, + } + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false + + /dotenv/16.0.3: + resolution: + { + integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==, + } + engines: { node: ">=12" } + dev: false + + /ecdsa-sig-formatter/1.0.11: + resolution: + { + integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==, + } + dependencies: + safe-buffer: 5.2.1 + dev: false + + /ee-first/1.1.1: + resolution: + { + integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==, + } + + /emoji-regex/8.0.0: + resolution: + { + integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, + } + dev: false + + /encodeurl/1.0.2: + resolution: + { + integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==, + } + engines: { node: ">= 0.8" } + + /encoding/0.1.13: + resolution: + { + integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==, + } + requiresBuild: true + dependencies: + iconv-lite: 0.6.3 + dev: false + optional: true + + /end-of-stream/1.4.4: + resolution: + { + integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, + } + dependencies: + once: 1.4.0 + dev: true + + /entities/4.4.0: + resolution: + { + integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==, + } + engines: { node: ">=0.12" } + dev: false + + /env-paths/2.2.1: + resolution: + { + integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==, + } + engines: { node: ">=6" } + dev: false + optional: true + + /err-code/2.0.3: + resolution: + { + integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==, + } + dev: false + optional: true + + /escalade/3.1.1: + resolution: + { + integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==, + } + engines: { node: ">=6" } + dev: false + + /escape-html/1.0.3: + resolution: + { + integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, + } + + /escodegen/1.14.3: + resolution: + { + integrity: sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==, + } + engines: { node: ">=4.0" } + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 4.3.0 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.6.1 + dev: false + + /esprima/4.0.1: + resolution: + { + integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==, + } + engines: { node: ">=4" } + hasBin: true + dev: false + + /estraverse/4.3.0: + resolution: + { + integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==, + } + engines: { node: ">=4.0" } + dev: false + + /esutils/2.0.3: + resolution: + { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: ">=0.10.0" } + dev: false + + /etag/1.8.1: + resolution: + { + integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==, + } + engines: { node: ">= 0.6" } + + /execa/4.1.0: + resolution: + { + integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==, + } + engines: { node: ">=10" } + dependencies: + cross-spawn: 7.0.3 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /exif-be-gone/1.3.2: + resolution: + { + integrity: sha512-jVkZWBJNw1SrAzrZ99/ePYx6FqfN6t/+y1xnCAnV5wCcASLBr548OvABfp1WSZGffz31+6DNy0W4ZZSBjs6dJw==, + } + hasBin: true + dependencies: + "@types/stream-buffers": 3.0.4 + dev: false + + /express-async-errors/3.1.1_express@4.18.2: + resolution: + { + integrity: sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==, + } + peerDependencies: + express: ^4.16.2 + dependencies: + express: 4.18.2 + dev: false + + /express/4.18.2: + resolution: + { + integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==, + } + engines: { node: ">= 0.10.0" } + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.1 + content-disposition: 0.5.4 + content-type: 1.0.4 + cookie: 0.5.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: 2.0.7 + qs: 6.11.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + /fast-deep-equal/3.1.3: + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + dev: false + + /fast-levenshtein/2.0.6: + resolution: + { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } + dev: false + + /fast-xml-parser/4.0.11: + resolution: + { + integrity: sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==, + } + hasBin: true + dependencies: + strnum: 1.0.5 + dev: false + + /fast-zlib/2.0.1: + resolution: + { + integrity: sha512-DCoYgNagM2Bt1VIpXpdGnRx4LzqJeYG0oh6Nf/7cWo6elTXkFGMw9CrRCYYUIapYNrozYMoyDRflx9mgT3Awyw==, + } + dev: false + + /file-type/16.5.4: + resolution: + { + integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==, + } + engines: { node: ">=10" } + dependencies: + readable-web-to-node-stream: 3.0.2 + strtok3: 6.3.0 + token-types: 4.2.1 + dev: false + + /file-uri-to-path/2.0.0: + resolution: + { + integrity: sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==, + } + engines: { node: ">= 6" } + dev: false + + /finalhandler/1.2.0: + resolution: + { + integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==, + } + engines: { node: ">= 0.8" } + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + /find-up/4.1.0: + resolution: + { + integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==, + } + engines: { node: ">=8" } + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true + + /form-data/3.0.1: + resolution: + { + integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==, + } + engines: { node: ">= 6" } + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + + /form-data/4.0.0: + resolution: + { + integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==, + } + engines: { node: ">= 6" } + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + + /forwarded/0.2.0: + resolution: + { + integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==, + } + engines: { node: ">= 0.6" } + + /fresh/0.5.2: + resolution: + { + integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==, + } + engines: { node: ">= 0.6" } + + /fs-extra/8.1.0: + resolution: + { + integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==, + } + engines: { node: ">=6 <7 || >=8" } + dependencies: + graceful-fs: 4.2.10 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + + /fs-minipass/2.1.0: + resolution: + { + integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==, + } + engines: { node: ">= 8" } + dependencies: + minipass: 3.3.6 + dev: false + + /fs.realpath/1.0.0: + resolution: + { + integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, + } + dev: false + + /ftp/0.3.10: + resolution: + { + integrity: sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==, + } + engines: { node: ">=0.8.0" } + dependencies: + readable-stream: 1.1.14 + xregexp: 2.0.0 + dev: false + + /function-bind/1.1.1: + resolution: + { + integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==, + } + + /gauge/3.0.2: + resolution: + { + integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==, + } + engines: { node: ">=10" } + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + + /gauge/4.0.4: + resolution: + { + integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + optional: true + + /get-caller-file/2.0.5: + resolution: + { + integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, + } + engines: { node: 6.* || 8.* || >= 10.* } + dev: false + + /get-intrinsic/1.1.3: + resolution: + { + integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==, + } + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 + + /get-stream/5.2.0: + resolution: + { + integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==, + } + engines: { node: ">=8" } + dependencies: + pump: 3.0.0 + dev: true + + /get-uri/3.0.2: + resolution: + { + integrity: sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==, + } + engines: { node: ">= 6" } + dependencies: + "@tootallnate/once": 1.1.2 + data-uri-to-buffer: 3.0.1 + debug: 4.3.4 + file-uri-to-path: 2.0.0 + fs-extra: 8.1.0 + ftp: 0.3.10 + transitivePeerDependencies: + - supports-color + dev: false + + /glob/7.2.3: + resolution: + { + integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, + } + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: false + + /graceful-fs/4.2.10: + resolution: + { + integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==, + } + dev: false + + /has-flag/4.0.0: + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: ">=8" } + + /has-symbols/1.0.3: + resolution: + { + integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==, + } + engines: { node: ">= 0.4" } + + /has-unicode/2.0.1: + resolution: + { + integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==, + } + dev: false + + /has/1.0.3: + resolution: + { + integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==, + } + engines: { node: ">= 0.4.0" } + dependencies: + function-bind: 1.1.1 + + /helmet/4.6.0: + resolution: + { + integrity: sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==, + } + engines: { node: ">=10.0.0" } + dev: false + + /highlight.js/10.7.3: + resolution: + { + integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==, + } + dev: false + + /htmlparser2/8.0.1: + resolution: + { + integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==, + } + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.0.1 + entities: 4.4.0 + dev: false + + /http-cache-semantics/4.1.0: + resolution: + { + integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==, + } + dev: false + optional: true + + /http-errors/2.0.0: + resolution: + { + integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==, + } + engines: { node: ">= 0.8" } + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + /http-proxy-agent/4.0.1: + resolution: + { + integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==, + } + engines: { node: ">= 6" } + dependencies: + "@tootallnate/once": 1.1.2 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /https-proxy-agent/5.0.1: + resolution: + { + integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==, + } + engines: { node: ">= 6" } + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /human-signals/1.1.1: + resolution: + { + integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==, + } + engines: { node: ">=8.12.0" } + dev: true + + /humanize-ms/1.2.1: + resolution: + { + integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==, + } + dependencies: + ms: 2.1.3 + dev: false + optional: true + + /husky/8.0.3: + resolution: + { + integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==, + } + engines: { node: ">=14" } + hasBin: true + dev: true + + /i18next-http-middleware/3.2.1: + resolution: + { + integrity: sha512-zBwXxDChT0YLoTXIR6jRuqnUUhXW0Iw7egoTnNXyaDRtTbfWNXwU0a53ThyuRPQ+k+tXu3ZMNKRzfLuononaRw==, + } + dev: false + + /i18next-node-fs-backend/2.1.3: + resolution: + { + integrity: sha512-CreMFiVl3ChlMc5ys/e0QfuLFOZyFcL40Jj6jaKD6DxZ/GCUMxPI9BpU43QMWUgC7r+PClpxg2cGXAl0CjG04g==, + } + deprecated: replaced by i18next-fs-backend + dependencies: + js-yaml: 3.13.1 + json5: 2.0.0 + dev: false + + /i18next/21.10.0: + resolution: + { + integrity: sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==, + } + dependencies: + "@babel/runtime": 7.20.7 + + /iconv-lite/0.4.24: + resolution: + { + integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==, + } + engines: { node: ">=0.10.0" } + dependencies: + safer-buffer: 2.1.2 + + /iconv-lite/0.6.3: + resolution: + { + integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==, + } + engines: { node: ">=0.10.0" } + dependencies: + safer-buffer: 2.1.2 + dev: false + optional: true + + /ieee754/1.2.1: + resolution: + { + integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, + } + dev: false + + /ignore/5.2.4: + resolution: + { + integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==, + } + engines: { node: ">= 4" } + dev: true + + /image-size/1.0.2: + resolution: + { + integrity: sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==, + } + engines: { node: ">=14.0.0" } + hasBin: true + dependencies: + queue: 6.0.2 + dev: false + + /immediate/3.0.6: + resolution: + { + integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==, + } + dev: false + + /imurmurhash/0.1.4: + resolution: + { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: ">=0.8.19" } + dev: false + optional: true + + /indent-string/4.0.0: + resolution: + { + integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, + } + engines: { node: ">=8" } + dev: false + optional: true + + /infer-owner/1.0.4: + resolution: + { + integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==, + } + dev: false + optional: true + + /inflight/1.0.6: + resolution: + { + integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, + } + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: false + + /inherits/2.0.4: + resolution: + { + integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, + } + + /ip/1.1.8: + resolution: + { + integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==, + } + dev: false + + /ip/2.0.0: + resolution: + { + integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==, + } + dev: false + + /ipaddr.js/1.9.1: + resolution: + { + integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==, + } + engines: { node: ">= 0.10" } + + /is-fullwidth-code-point/3.0.0: + resolution: + { + integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, + } + engines: { node: ">=8" } + dev: false + + /is-lambda/1.0.1: + resolution: + { + integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==, + } + dev: false + optional: true + + /is-stream/2.0.1: + resolution: + { + integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, + } + engines: { node: ">=8" } + dev: true + + /isarray/0.0.1: + resolution: + { + integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==, + } + dev: false + + /isarray/1.0.0: + resolution: + { + integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, + } + dev: false + + /isexe/2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + + /js-yaml/3.13.1: + resolution: + { + integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==, + } + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: false + + /js-yaml/4.1.0: + resolution: + { + integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, + } + hasBin: true + dependencies: + argparse: 2.0.1 + dev: false + + /json-bigint/1.0.0: + resolution: + { + integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==, + } + dependencies: + bignumber.js: 9.1.1 + dev: false + + /json-schema-traverse/1.0.0: + resolution: + { + integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, + } + dev: false + + /json-stable-stringify/1.0.2: + resolution: + { + integrity: sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==, + } + dependencies: + jsonify: 0.0.1 + dev: false + + /json5/2.0.0: + resolution: + { + integrity: sha512-0EdQvHuLm7yJ7lyG5dp7Q3X2ku++BG5ZHaJ5FTnaXpKqDrw4pMxel5Bt3oAYMthnrthFBdnZ1FcsXTPyrQlV0w==, + } + engines: { node: ">=6" } + hasBin: true + dependencies: + minimist: 1.2.7 + dev: false + + /jsonfile/4.0.0: + resolution: + { + integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==, + } + optionalDependencies: + graceful-fs: 4.2.10 + dev: false + + /jsonify/0.0.1: + resolution: + { + integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==, + } + dev: false + + /jsonwebtoken/8.5.1: + resolution: + { + integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==, + } + engines: { node: ">=4", npm: ">=1.4.28" } + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 5.7.1 + dev: false + + /jwa/1.4.1: + resolution: + { + integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==, + } + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + dev: false + + /jws/3.2.2: + resolution: + { + integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==, + } + dependencies: + jwa: 1.4.1 + safe-buffer: 5.2.1 + dev: false + + /lambert-server/1.2.12: + resolution: + { + integrity: sha512-TY6k60KLVfBpPrl9lcrN54RJdTBg9f8JqJPoHg5d/FMLnnwwQtT4budpoQjyLDwBLhS+zpXo0aBCwnnGgTVGaw==, + } + dependencies: + body-parser: 1.20.1 + chalk: 4.1.2 + express: 4.18.2 + express-async-errors: 3.1.1_express@4.18.2 + helmet: 4.6.0 + missing-native-js-functions: 1.3.1 + transitivePeerDependencies: + - supports-color + dev: false + + /levn/0.3.0: + resolution: + { + integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==, + } + engines: { node: ">= 0.8.0" } + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + dev: false + + /lie/3.1.1: + resolution: + { + integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==, + } + dependencies: + immediate: 3.0.6 + dev: false + + /localforage/1.10.0: + resolution: + { + integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==, + } + dependencies: + lie: 3.1.1 + dev: false + + /locate-path/5.0.0: + resolution: + { + integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==, + } + engines: { node: ">=8" } + dependencies: + p-locate: 4.1.0 + dev: true + + /lodash.includes/4.3.0: + resolution: + { + integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==, + } + dev: false + + /lodash.isboolean/3.0.3: + resolution: + { + integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==, + } + dev: false + + /lodash.isinteger/4.0.4: + resolution: + { + integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==, + } + dev: false + + /lodash.isnumber/3.0.3: + resolution: + { + integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==, + } + dev: false + + /lodash.isplainobject/4.0.6: + resolution: + { + integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==, + } + dev: false + + /lodash.isstring/4.0.1: + resolution: + { + integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==, + } + dev: false + + /lodash.merge/4.6.2: + resolution: + { + integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, + } + dev: false + + /lodash.once/4.1.1: + resolution: + { + integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==, + } + dev: false + + /lru-cache/5.1.1: + resolution: + { + integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, + } + dependencies: + yallist: 3.1.1 + dev: false + + /lru-cache/6.0.0: + resolution: + { + integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, + } + engines: { node: ">=10" } + dependencies: + yallist: 4.0.0 + dev: false + + /lru_map/0.3.3: + resolution: + { + integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==, + } + dev: false + + /make-dir/3.1.0: + resolution: + { + integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==, + } + engines: { node: ">=8" } + dependencies: + semver: 6.3.0 + dev: false + + /make-error/1.3.6: + resolution: + { + integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==, + } + dev: false + + /make-fetch-happen/9.1.0: + resolution: + { + integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==, + } + engines: { node: ">= 10" } + dependencies: + agentkeepalive: 4.2.1 + cacache: 15.3.0 + http-cache-semantics: 4.1.0 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 1.4.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.3 + promise-retry: 2.0.1 + socks-proxy-agent: 6.2.1 + ssri: 8.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + optional: true + + /media-typer/0.3.0: + resolution: + { + integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==, + } + engines: { node: ">= 0.6" } + + /merge-descriptors/1.0.1: + resolution: + { + integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==, + } + + /merge-stream/2.0.0: + resolution: + { + integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, + } + dev: true + + /methods/1.1.2: + resolution: + { + integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==, + } + engines: { node: ">= 0.6" } + + /mime-db/1.52.0: + resolution: + { + integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, + } + engines: { node: ">= 0.6" } + + /mime-types/2.1.35: + resolution: + { + integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, + } + engines: { node: ">= 0.6" } + dependencies: + mime-db: 1.52.0 + + /mime/1.6.0: + resolution: + { + integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==, + } + engines: { node: ">=4" } + hasBin: true + + /mimic-fn/2.1.0: + resolution: + { + integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, + } + engines: { node: ">=6" } + dev: true + + /minimatch/3.1.2: + resolution: + { + integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, + } + dependencies: + brace-expansion: 1.1.11 + + /minimist/1.2.7: + resolution: + { + integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==, + } + dev: false + + /minipass-collect/1.0.2: + resolution: + { + integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==, + } + engines: { node: ">= 8" } + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /minipass-fetch/1.4.1: + resolution: + { + integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==, + } + engines: { node: ">=8" } + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + dev: false + optional: true + + /minipass-flush/1.0.5: + resolution: + { + integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==, + } + engines: { node: ">= 8" } + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /minipass-pipeline/1.2.4: + resolution: + { + integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==, + } + engines: { node: ">=8" } + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /minipass-sized/1.0.3: + resolution: + { + integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==, + } + engines: { node: ">=8" } + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /minipass/3.3.6: + resolution: + { + integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==, + } + engines: { node: ">=8" } + dependencies: + yallist: 4.0.0 + dev: false + + /minipass/4.0.0: + resolution: + { + integrity: sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==, + } + engines: { node: ">=8" } + dependencies: + yallist: 4.0.0 + dev: false + + /minizlib/2.1.2: + resolution: + { + integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==, + } + engines: { node: ">= 8" } + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + dev: false + + /missing-native-js-functions/1.3.1: + resolution: + { + integrity: sha512-+27YZhfXCDOwUVZ7qdtJzLWAaA8qYBt6jPrUuF91SpBYUOBLvKr+MgvhlJuNMVhjzNX0245p2zvYYSx9QpuLZQ==, + } + dev: false + + /mkdirp/0.5.6: + resolution: + { + integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==, + } + hasBin: true + dependencies: + minimist: 1.2.7 + dev: false + + /mkdirp/1.0.4: + resolution: + { + integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==, + } + engines: { node: ">=10" } + hasBin: true + dev: false + + /module-alias/2.2.2: + resolution: + { + integrity: sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==, + } + dev: false + + /morgan/1.10.0: + resolution: + { + integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==, + } + engines: { node: ">= 0.8.0" } + dependencies: + basic-auth: 2.0.1 + debug: 2.6.9 + depd: 2.0.0 + on-finished: 2.3.0 + on-headers: 1.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /mri/1.2.0: + resolution: + { + integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==, + } + engines: { node: ">=4" } + dev: true + + /ms/2.0.0: + resolution: + { + integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==, + } + + /ms/2.1.2: + resolution: + { + integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, + } + dev: false + + /ms/2.1.3: + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + + /multer/1.4.5-lts.1: + resolution: + { + integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==, + } + engines: { node: ">= 6.0.0" } + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 1.6.2 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + dev: false + + /multimatch/4.0.0: + resolution: + { + integrity: sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==, + } + engines: { node: ">=8" } + dependencies: + "@types/minimatch": 3.0.5 + array-differ: 3.0.0 + array-union: 2.1.0 + arrify: 2.0.1 + minimatch: 3.1.2 + dev: true + + /mz/2.7.0: + resolution: + { + integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, + } + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: false + + /needle/2.9.1: + resolution: + { + integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==, + } + engines: { node: ">= 4.4.x" } + hasBin: true + dependencies: + debug: 3.2.7 + iconv-lite: 0.4.24 + sax: 1.2.4 + transitivePeerDependencies: + - supports-color + dev: false + + /negotiator/0.6.3: + resolution: + { + integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==, + } + engines: { node: ">= 0.6" } + + /netmask/2.0.2: + resolution: + { + integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==, + } + engines: { node: ">= 0.4.0" } + dev: false + + /node-2fa/2.0.3: + resolution: + { + integrity: sha512-PQldrOhjuoZyoydMvMSctllPN1ZPZ1/NwkEcgYwY9faVqE/OymxR+3awPpbWZxm6acLKqvmNqQmdqTsqYyflFw==, + } + dependencies: + "@types/notp": 2.0.2 + notp: 2.0.3 + thirty-two: 1.0.2 + tslib: 2.4.1 + dev: false + + /node-addon-api/4.3.0: + resolution: + { + integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==, + } + dev: false + + /node-addon-api/5.0.0: + resolution: + { + integrity: sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==, + } + dev: false + + /node-fetch/2.6.7: + resolution: + { + integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==, + } + engines: { node: 4.x || >=6.0.0 } + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false + + /node-gyp/8.4.1: + resolution: + { + integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==, + } + engines: { node: ">= 10.12.0" } + hasBin: true + requiresBuild: true + dependencies: + env-paths: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.10 + make-fetch-happen: 9.1.0 + nopt: 5.0.0 + npmlog: 6.0.2 + rimraf: 3.0.2 + semver: 7.3.8 + tar: 6.1.13 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + optional: true + + /node-os-utils/1.3.7: + resolution: + { + integrity: sha512-fvnX9tZbR7WfCG5BAy3yO/nCLyjVWD6MghEq0z5FDfN+ZXpLWNITBdbifxQkQ25ebr16G0N7eRWJisOcMEHG3Q==, + } + dev: false + + /nopt/5.0.0: + resolution: + { + integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==, + } + engines: { node: ">=6" } + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: false + + /notp/2.0.3: + resolution: + { + integrity: sha512-oBig/2uqkjQ5AkBuw4QJYwkEWa/q+zHxI5/I5z6IeP2NT0alpJFsP/trrfCC+9xOAgQSZXssNi962kp5KBmypQ==, + } + engines: { node: "> v0.6.0" } + dev: false + + /npm-run-path/4.0.1: + resolution: + { + integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==, + } + engines: { node: ">=8" } + dependencies: + path-key: 3.1.1 + dev: true + + /npmlog/5.0.1: + resolution: + { + integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==, + } + dependencies: + are-we-there-yet: 2.0.0 + console-control-strings: 1.1.0 + gauge: 3.0.2 + set-blocking: 2.0.0 + dev: false + + /npmlog/6.0.2: + resolution: + { + integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + dependencies: + are-we-there-yet: 3.0.1 + console-control-strings: 1.1.0 + gauge: 4.0.4 + set-blocking: 2.0.0 + dev: false + optional: true + + /nth-check/2.1.1: + resolution: + { + integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==, + } + dependencies: + boolbase: 1.0.0 + dev: false + + /object-assign/4.1.1: + resolution: + { + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, + } + engines: { node: ">=0.10.0" } + dev: false + + /object-inspect/1.12.2: + resolution: + { + integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==, + } + + /on-finished/2.3.0: + resolution: + { + integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==, + } + engines: { node: ">= 0.8" } + dependencies: + ee-first: 1.1.1 + dev: false + + /on-finished/2.4.1: + resolution: + { + integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==, + } + engines: { node: ">= 0.8" } + dependencies: + ee-first: 1.1.1 + + /on-headers/1.0.2: + resolution: + { + integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==, + } + engines: { node: ">= 0.8" } + dev: false + + /once/1.4.0: + resolution: + { + integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, + } + dependencies: + wrappy: 1.0.2 + + /onetime/5.1.2: + resolution: + { + integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, + } + engines: { node: ">=6" } + dependencies: + mimic-fn: 2.1.0 + dev: true + + /optionator/0.8.3: + resolution: + { + integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==, + } + engines: { node: ">= 0.8.0" } + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + word-wrap: 1.2.3 + dev: false + + /p-limit/2.3.0: + resolution: + { + integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==, + } + engines: { node: ">=6" } + dependencies: + p-try: 2.2.0 + dev: true + + /p-locate/4.1.0: + resolution: + { + integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==, + } + engines: { node: ">=8" } + dependencies: + p-limit: 2.3.0 + dev: true + + /p-map/4.0.0: + resolution: + { + integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==, + } + engines: { node: ">=10" } + dependencies: + aggregate-error: 3.1.0 + dev: false + optional: true + + /p-try/2.2.0: + resolution: + { + integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==, + } + engines: { node: ">=6" } + dev: true + + /pac-proxy-agent/5.0.0: + resolution: + { + integrity: sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==, + } + engines: { node: ">= 8" } + dependencies: + "@tootallnate/once": 1.1.2 + agent-base: 6.0.2 + debug: 4.3.4 + get-uri: 3.0.2 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + pac-resolver: 5.0.1 + raw-body: 2.5.1 + socks-proxy-agent: 5.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /pac-resolver/5.0.1: + resolution: + { + integrity: sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==, + } + engines: { node: ">= 8" } + dependencies: + degenerator: 3.0.2 + ip: 1.1.8 + netmask: 2.0.2 + dev: false + + /parse5-htmlparser2-tree-adapter/6.0.1: + resolution: + { + integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==, + } + dependencies: + parse5: 6.0.1 + dev: false + + /parse5-htmlparser2-tree-adapter/7.0.0: + resolution: + { + integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==, + } + dependencies: + domhandler: 5.0.3 + parse5: 7.1.2 + dev: false + + /parse5/5.1.1: + resolution: + { + integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==, + } + dev: false + + /parse5/6.0.1: + resolution: + { + integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==, + } + dev: false + + /parse5/7.1.2: + resolution: + { + integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==, + } + dependencies: + entities: 4.4.0 + dev: false + + /parseurl/1.3.3: + resolution: + { + integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==, + } + engines: { node: ">= 0.8" } + + /path-exists/4.0.0: + resolution: + { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, + } + engines: { node: ">=8" } + dev: true + + /path-is-absolute/1.0.1: + resolution: + { + integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, + } + engines: { node: ">=0.10.0" } + dev: false + + /path-key/3.1.1: + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: ">=8" } + dev: true + + /path-to-regexp/0.1.7: + resolution: + { + integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==, + } + + /peek-readable/4.1.0: + resolution: + { + integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==, + } + engines: { node: ">=8" } + dev: false + + /picocolors/1.0.0: + resolution: + { + integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, + } + dev: false + + /prelude-ls/1.1.2: + resolution: + { + integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==, + } + engines: { node: ">= 0.8.0" } + dev: false + + /prettier/2.8.2: + resolution: + { + integrity: sha512-BtRV9BcncDyI2tsuS19zzhzoxD8Dh8LiCx7j7tHzrkz8GFXAexeWFdi22mjE1d16dftH2qNaytVxqiRTGlMfpw==, + } + engines: { node: ">=10.13.0" } + hasBin: true + dev: true + + /pretty-quick/3.1.3_prettier@2.8.2: + resolution: + { + integrity: sha512-kOCi2FJabvuh1as9enxYmrnBC6tVMoVOenMaBqRfsvBHB0cbpYHjdQEpSglpASDFEXVwplpcGR4CLEaisYAFcA==, + } + engines: { node: ">=10.13" } + hasBin: true + peerDependencies: + prettier: ">=2.0.0" + dependencies: + chalk: 3.0.0 + execa: 4.1.0 + find-up: 4.1.0 + ignore: 5.2.4 + mri: 1.2.0 + multimatch: 4.0.0 + prettier: 2.8.2 + dev: true + + /probe-image-size/7.2.3: + resolution: + { + integrity: sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==, + } + dependencies: + lodash.merge: 4.6.2 + needle: 2.9.1 + stream-parser: 0.3.1 + transitivePeerDependencies: + - supports-color + dev: false + + /process-nextick-args/2.0.1: + resolution: + { + integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, + } + dev: false + + /promise-inflight/1.0.1: + resolution: + { + integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==, + } + peerDependencies: + bluebird: "*" + peerDependenciesMeta: + bluebird: + optional: true + dev: false + optional: true + + /promise-retry/2.0.1: + resolution: + { + integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==, + } + engines: { node: ">=10" } + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + dev: false + optional: true + + /proxy-addr/2.0.7: + resolution: + { + integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==, + } + engines: { node: ">= 0.10" } + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + /proxy-agent/5.0.0: + resolution: + { + integrity: sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==, + } + engines: { node: ">= 8" } + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + lru-cache: 5.1.1 + pac-proxy-agent: 5.0.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 5.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /proxy-from-env/1.1.0: + resolution: + { + integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, + } + dev: false + + /pump/3.0.0: + resolution: + { + integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==, + } + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: true + + /punycode/2.2.0: + resolution: + { + integrity: sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==, + } + engines: { node: ">=6" } + dev: false + + /qs/6.11.0: + resolution: + { + integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==, + } + engines: { node: ">=0.6" } + dependencies: + side-channel: 1.0.4 + + /querystringify/2.2.0: + resolution: + { + integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==, + } + dev: false + + /queue/6.0.2: + resolution: + { + integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==, + } + dependencies: + inherits: 2.0.4 + dev: false + + /range-parser/1.2.1: + resolution: + { + integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==, + } + engines: { node: ">= 0.6" } + + /raw-body/2.5.1: + resolution: + { + integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==, + } + engines: { node: ">= 0.8" } + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + /readable-stream/1.1.14: + resolution: + { + integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==, + } + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + dev: false + + /readable-stream/2.3.7: + resolution: + { + integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==, + } + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: false + + /readable-stream/3.6.0: + resolution: + { + integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==, + } + engines: { node: ">= 6" } + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readable-web-to-node-stream/3.0.2: + resolution: + { + integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==, + } + engines: { node: ">=8" } + dependencies: + readable-stream: 3.6.0 + dev: false + + /reflect-metadata/0.1.13: + resolution: + { + integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==, + } + dev: false + + /regenerator-runtime/0.13.11: + resolution: + { + integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==, + } + + /require-directory/2.1.1: + resolution: + { + integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, + } + engines: { node: ">=0.10.0" } + dev: false + + /require-from-string/2.0.2: + resolution: + { + integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, + } + engines: { node: ">=0.10.0" } + dev: false + + /requires-port/1.0.0: + resolution: + { + integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==, + } + dev: false + + /retry/0.12.0: + resolution: + { + integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==, + } + engines: { node: ">= 4" } + dev: false + optional: true + + /rimraf/3.0.2: + resolution: + { + integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, + } + hasBin: true + dependencies: + glob: 7.2.3 + dev: false + + /safe-buffer/5.1.2: + resolution: + { + integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, + } + dev: false + + /safe-buffer/5.2.1: + resolution: + { + integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, + } + + /safer-buffer/2.1.2: + resolution: + { + integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, + } + + /sax/1.2.4: + resolution: + { + integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==, + } + dev: false + + /semver/5.7.1: + resolution: + { + integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==, + } + hasBin: true + dev: false + + /semver/6.3.0: + resolution: + { + integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==, + } + hasBin: true + dev: false + + /semver/7.3.8: + resolution: + { + integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==, + } + engines: { node: ">=10" } + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: false + + /send/0.18.0: + resolution: + { + integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==, + } + engines: { node: ">= 0.8.0" } + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + /serve-static/1.15.0: + resolution: + { + integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==, + } + engines: { node: ">= 0.8.0" } + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0 + transitivePeerDependencies: + - supports-color + + /set-blocking/2.0.0: + resolution: + { + integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==, + } + dev: false + + /setprototypeof/1.2.0: + resolution: + { + integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==, + } + + /sha.js/2.4.11: + resolution: + { + integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==, + } + hasBin: true + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + + /shebang-command/2.0.0: + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: ">=8" } + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex/3.0.0: + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: ">=8" } + dev: true + + /side-channel/1.0.4: + resolution: + { + integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==, + } + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + object-inspect: 1.12.2 + + /signal-exit/3.0.7: + resolution: + { + integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, + } + + /smart-buffer/4.2.0: + resolution: + { + integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==, + } + engines: { node: ">= 6.0.0", npm: ">= 3.0.0" } + dev: false + + /socks-proxy-agent/5.0.1: + resolution: + { + integrity: sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==, + } + engines: { node: ">= 6" } + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + socks: 2.7.1 + transitivePeerDependencies: + - supports-color + dev: false + + /socks-proxy-agent/6.2.1: + resolution: + { + integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==, + } + engines: { node: ">= 10" } + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + socks: 2.7.1 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /socks/2.7.1: + resolution: + { + integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==, + } + engines: { node: ">= 10.13.0", npm: ">= 3.0.0" } + dependencies: + ip: 2.0.0 + smart-buffer: 4.2.0 + dev: false + + /source-map-support/0.5.21: + resolution: + { + integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, + } + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: false + + /source-map/0.6.1: + resolution: + { + integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, + } + engines: { node: ">=0.10.0" } + dev: false + + /sprintf-js/1.0.3: + resolution: + { + integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==, + } + dev: false + + /sqlite3/5.1.4: + resolution: + { + integrity: sha512-i0UlWAzPlzX3B5XP2cYuhWQJsTtlMD6obOa1PgeEQ4DHEXUuyJkgv50I3isqZAP5oFc2T8OFvakmDh2W6I+YpA==, + } + requiresBuild: true + peerDependenciesMeta: + node-gyp: + optional: true + dependencies: + "@mapbox/node-pre-gyp": 1.0.10 + node-addon-api: 4.3.0 + tar: 6.1.13 + optionalDependencies: + node-gyp: 8.4.1 + transitivePeerDependencies: + - bluebird + - encoding + - supports-color + dev: false + + /ssri/8.0.1: + resolution: + { + integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==, + } + engines: { node: ">= 8" } + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /statuses/2.0.1: + resolution: + { + integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==, + } + engines: { node: ">= 0.8" } + + /stream-parser/0.3.1: + resolution: + { + integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==, + } + dependencies: + debug: 2.6.9 + transitivePeerDependencies: + - supports-color + dev: false + + /streamsearch/1.1.0: + resolution: + { + integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==, + } + engines: { node: ">=10.0.0" } + dev: false + + /string-width/4.2.3: + resolution: + { + integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, + } + engines: { node: ">=8" } + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: false + + /string_decoder/0.10.31: + resolution: + { + integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==, + } + dev: false + + /string_decoder/1.1.1: + resolution: + { + integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, + } + dependencies: + safe-buffer: 5.1.2 + dev: false + + /string_decoder/1.3.0: + resolution: + { + integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, + } + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi/6.0.1: + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: ">=8" } + dependencies: + ansi-regex: 5.0.1 + dev: false + + /strip-final-newline/2.0.0: + resolution: + { + integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==, + } + engines: { node: ">=6" } + dev: true + + /strnum/1.0.5: + resolution: + { + integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==, + } + dev: false + + /strtok3/6.3.0: + resolution: + { + integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==, + } + engines: { node: ">=10" } + dependencies: + "@tokenizer/token": 0.3.0 + peek-readable: 4.1.0 + dev: false + + /supports-color/7.2.0: + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: ">=8" } + dependencies: + has-flag: 4.0.0 + + /tar/6.1.13: + resolution: + { + integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==, + } + engines: { node: ">=10" } + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 4.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + dev: false + + /thenify-all/1.6.0: + resolution: + { + integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, + } + engines: { node: ">=0.8" } + dependencies: + thenify: 3.3.1 + dev: false + + /thenify/3.3.1: + resolution: + { + integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, + } + dependencies: + any-promise: 1.3.0 + dev: false + + /thirty-two/1.0.2: + resolution: + { + integrity: sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==, + } + engines: { node: ">=0.2.6" } + dev: false + + /toidentifier/1.0.1: + resolution: + { + integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==, + } + engines: { node: ">=0.6" } + + /token-types/4.2.1: + resolution: + { + integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==, + } + engines: { node: ">=10" } + dependencies: + "@tokenizer/token": 0.3.0 + ieee754: 1.2.1 + dev: false + + /tr46/0.0.3: + resolution: + { + integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, + } + dev: false + + /ts-node/10.9.1_awa2wsr5thmg3i7jqycphctjfq: + resolution: + { + integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==, + } + hasBin: true + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + dependencies: + "@cspotcode/source-map-support": 0.8.1 + "@tsconfig/node10": 1.0.9 + "@tsconfig/node12": 1.0.11 + "@tsconfig/node14": 1.0.3 + "@tsconfig/node16": 1.0.3 + "@types/node": 18.11.18 + acorn: 8.8.1 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: false + + /ts-node/9.1.1_typescript@4.2.4: + resolution: + { + integrity: sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==, + } + engines: { node: ">=10.0.0" } + hasBin: true + peerDependencies: + typescript: ">=2.7" + dependencies: + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + source-map-support: 0.5.21 + typescript: 4.2.4 + yn: 3.1.1 + dev: false + + /tslib/1.14.1: + resolution: + { + integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==, + } + dev: false + + /tslib/2.4.1: + resolution: + { + integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==, + } + dev: false + + /type-check/0.3.2: + resolution: + { + integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==, + } + engines: { node: ">= 0.8.0" } + dependencies: + prelude-ls: 1.1.2 + dev: false + + /type-is/1.6.18: + resolution: + { + integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==, + } + engines: { node: ">= 0.6" } + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + /typedarray/0.0.6: + resolution: + { + integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==, + } + dev: false + + /typeorm/0.3.11_h3l5zcb3i6sggvllyfknv6gs44: + resolution: + { + integrity: sha512-pzdOyWbVuz/z8Ww6gqvBW4nylsM0KLdUCDExr2gR20/x1khGSVxQkjNV/3YqliG90jrWzrknYbYscpk8yxFJVg==, + } + engines: { node: ">= 12.9.0" } + hasBin: true + peerDependencies: + "@google-cloud/spanner": ^5.18.0 + "@sap/hana-client": ^2.12.25 + better-sqlite3: ^7.1.2 || ^8.0.0 + hdb-pool: ^0.1.6 + ioredis: ^5.0.4 + mongodb: ^3.6.0 + mssql: ^7.3.0 + mysql2: ^2.2.5 + oracledb: ^5.1.0 + pg: ^8.5.1 + pg-native: ^3.0.0 + pg-query-stream: ^4.0.0 + redis: ^3.1.1 || ^4.0.0 + sql.js: ^1.4.0 + sqlite3: ^5.0.3 + ts-node: ^10.7.0 + typeorm-aurora-data-api-driver: ^2.0.0 + peerDependenciesMeta: + "@google-cloud/spanner": + optional: true + "@sap/hana-client": + optional: true + better-sqlite3: + optional: true + hdb-pool: + optional: true + ioredis: + optional: true + mongodb: + optional: true + mssql: + optional: true + mysql2: + optional: true + oracledb: + optional: true + pg: + optional: true + pg-native: + optional: true + pg-query-stream: + optional: true + redis: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + ts-node: + optional: true + typeorm-aurora-data-api-driver: + optional: true + dependencies: + "@sqltools/formatter": 1.2.5 + app-root-path: 3.1.0 + buffer: 6.0.3 + chalk: 4.1.2 + cli-highlight: 2.1.11 + date-fns: 2.29.3 + debug: 4.3.4 + dotenv: 16.0.3 + glob: 7.2.3 + js-yaml: 4.1.0 + mkdirp: 1.0.4 + reflect-metadata: 0.1.13 + sha.js: 2.4.11 + sqlite3: 5.1.4 + ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq + tslib: 2.4.1 + uuid: 8.3.2 + xml2js: 0.4.23 + yargs: 17.6.2 + transitivePeerDependencies: + - supports-color + dev: false + + /typescript-json-schema/0.50.1: + resolution: + { + integrity: sha512-GCof/SDoiTDl0qzPonNEV4CHyCsZEIIf+mZtlrjoD8vURCcEzEfa2deRuxYid8Znp/e27eDR7Cjg8jgGrimBCA==, + } + hasBin: true + dependencies: + "@types/json-schema": 7.0.11 + "@types/node": 14.18.36 + glob: 7.2.3 + json-stable-stringify: 1.0.2 + ts-node: 9.1.1_typescript@4.2.4 + typescript: 4.2.4 + yargs: 16.2.0 + dev: false + + /typescript/4.2.4: + resolution: + { + integrity: sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==, + } + engines: { node: ">=4.2.0" } + hasBin: true + dev: false + + /typescript/4.9.4: + resolution: + { + integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==, + } + engines: { node: ">=4.2.0" } + hasBin: true + + /unique-filename/1.1.1: + resolution: + { + integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==, + } + dependencies: + unique-slug: 2.0.2 + dev: false + optional: true + + /unique-slug/2.0.2: + resolution: + { + integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==, + } + dependencies: + imurmurhash: 0.1.4 + dev: false + optional: true + + /universalify/0.1.2: + resolution: + { + integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==, + } + engines: { node: ">= 4.0.0" } + dev: false + + /unpipe/1.0.0: + resolution: + { + integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==, + } + engines: { node: ">= 0.8" } + + /uri-js/4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } + dependencies: + punycode: 2.2.0 + dev: false + + /url-parse/1.5.10: + resolution: + { + integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==, + } + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: false + + /util-deprecate/1.0.2: + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, + } + dev: false + + /utils-merge/1.0.1: + resolution: + { + integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==, + } + engines: { node: ">= 0.4.0" } + + /uuid/8.3.2: + resolution: + { + integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==, + } + hasBin: true + dev: false + + /v8-compile-cache-lib/3.0.1: + resolution: + { + integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==, + } + dev: false + + /vary/1.1.2: + resolution: + { + integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==, + } + engines: { node: ">= 0.8" } + + /vm2/3.9.13: + resolution: + { + integrity: sha512-0rvxpB8P8Shm4wX2EKOiMp7H2zq+HUE/UwodY0pCZXs9IffIKZq6vUti5OgkVCTakKo9e/fgO4X1fkwfjWxE3Q==, + } + engines: { node: ">=6.0" } + hasBin: true + dependencies: + acorn: 8.8.1 + acorn-walk: 8.2.0 + dev: false + + /webidl-conversions/3.0.1: + resolution: + { + integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, + } + dev: false + + /whatwg-url/5.0.0: + resolution: + { + integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, + } + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: false + + /which/2.0.2: + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: ">= 8" } + hasBin: true + dependencies: + isexe: 2.0.0 + + /wide-align/1.1.5: + resolution: + { + integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==, + } + dependencies: + string-width: 4.2.3 + dev: false + + /word-wrap/1.2.3: + resolution: + { + integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==, + } + engines: { node: ">=0.10.0" } + dev: false + + /wrap-ansi/7.0.0: + resolution: + { + integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, + } + engines: { node: ">=10" } + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + + /wrappy/1.0.2: + resolution: + { + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + } + + /wretch/2.3.2: + resolution: + { + integrity: sha512-brN97Z2Mwed+w5z+keYI1u5OwWhPIaW0sJi9CxtKBVxLc3aqP6j1+2FCoIskM7WJq6SUHdxTFx20ox0iDLa0mQ==, + } + engines: { node: ">=14" } + dev: false + + /ws/8.12.0: + resolution: + { + integrity: sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==, + } + engines: { node: ">=10.0.0" } + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /xml2js/0.4.23: + resolution: + { + integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==, + } + engines: { node: ">=4.0.0" } + dependencies: + sax: 1.2.4 + xmlbuilder: 11.0.1 + dev: false + + /xmlbuilder/11.0.1: + resolution: + { + integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==, + } + engines: { node: ">=4.0" } + dev: false + + /xregexp/2.0.0: + resolution: + { + integrity: sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==, + } + dev: false + + /xtend/4.0.2: + resolution: + { + integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==, + } + engines: { node: ">=0.4" } + dev: false + + /y18n/5.0.8: + resolution: + { + integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, + } + engines: { node: ">=10" } + dev: false + + /yallist/3.1.1: + resolution: + { + integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, + } + dev: false + + /yallist/4.0.0: + resolution: + { + integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, + } + dev: false + + /yargs-parser/20.2.9: + resolution: + { + integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==, + } + engines: { node: ">=10" } + dev: false + + /yargs-parser/21.1.1: + resolution: + { + integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, + } + engines: { node: ">=12" } + dev: false + + /yargs/16.2.0: + resolution: + { + integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==, + } + engines: { node: ">=10" } + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: false + + /yargs/17.6.2: + resolution: + { + integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==, + } + engines: { node: ">=12" } + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: false + + /yn/3.1.1: + resolution: + { + integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==, + } + engines: { node: ">=6" } + dev: false diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index 8e8eeeed..96c3993c 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { BattleNetSettings } from "./BattleNetSettings"; @@ -67,68 +66,40 @@ export default class BattleNetConnection extends Connection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - client_id: this.settings.clientId!, - client_secret: this.settings.clientSecret!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - BattleNetErrorResponse, - ) => { - if (res.error) throw new Error(res.error_description); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), ) + .post() + .json() .catch((e) => { - console.error( - `Error exchanging token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); - }) - .then((res: BattleNetConnectionUser & BattleNetErrorResponse) => { - if (res.error) throw new Error(res.error_description); - return res; }) + .get() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 23f5d978..52fc9ffd 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { DiscordSettings } from "./DiscordSettings"; @@ -66,56 +65,41 @@ export default class DiscordConnection extends Connection { this.validateState(state); const url = this.getTokenUrl(); - return fetch(url, { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - client_id: this.settings.clientId!, - client_secret: this.settings.clientSecret!, - grant_type: "authorization_code", - code: code, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange token", 0, 400); - } - - return res.json(); }) + .body( + new URLSearchParams({ + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + grant_type: "authorization_code", + code: code, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + ) + .post() + .json() .catch((e) => { - console.error( - `Error exchanging token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); }) + .get() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts index c720dc5d..247d2435 100644 --- a/src/connections/EpicGames/index.ts +++ b/src/connections/EpicGames/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { EpicGamesSettings } from "./EpicGamesSettings"; @@ -73,31 +72,24 @@ export default class EpicGamesConnection extends Connection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", Authorization: `Basic ${Buffer.from( `${this.settings.clientId}:${this.settings.clientSecret}`, ).toString("base64")}`, "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code, + }), + ) + .post() + .json() .catch((e) => { - console.error( - `Error exchanging token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -108,23 +100,15 @@ export default class EpicGamesConnection extends Connection { ); const url = new URL(this.userInfoUrl); url.searchParams.append("accountId", sub); - return fetch(url.toString(), { - method: "GET", - headers: { - Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - return res.json(); + return wretch(url.toString()) + .headers({ + Authorization: `Bearer ${token}`, }) + .get() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts index 67f8da79..5413f867 100644 --- a/src/connections/Facebook/index.ts +++ b/src/connections/Facebook/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { FacebookSettings } from "./FacebookSettings"; @@ -83,59 +82,29 @@ export default class FacebookConnection extends Connection { const url = this.getTokenUrl(code); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - FacebookErrorResponse, - ) => { - if (res.error) throw new Error(res.error.message); - return res; - }, - ) + .get() + .json() .catch((e) => { - console.error( - `Error exchanging token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { - Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - return res.json(); - }) - .then((res: UserResponse & FacebookErrorResponse) => { - if (res.error) throw new Error(res.error.message); - return res; + return wretch(url.toString()) + .headers({ + Authorization: `Bearer ${token}`, }) + .get() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index aa686b03..8380e765 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { GitHubSettings } from "./GitHubSettings"; @@ -65,46 +64,29 @@ export default class GitHubConnection extends Connection { const url = this.getTokenUrl(code); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) + + .post() + .json() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); }) + .get() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts index 06fbcbe5..70b4a8af 100644 --- a/src/connections/Reddit/index.ts +++ b/src/connections/Reddit/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { RedditSettings } from "./RedditSettings"; @@ -74,57 +73,42 @@ export default class RedditConnection extends Connection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", Authorization: `Basic ${Buffer.from( `${this.settings.clientId}:${this.settings.clientSecret}`, ).toString("base64")}`, "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to code", 0, 400); - } - - return res.json(); }) + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + ) + .post() + .json() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); }) + .get() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts index 44a4bc28..54ec2696 100644 --- a/src/connections/Spotify/index.ts +++ b/src/connections/Spotify/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import RefreshableConnection from "../../util/connections/RefreshableConnection"; import { SpotifySettings } from "./SpotifySettings"; @@ -83,122 +82,78 @@ export default class SpotifyConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to refresh token", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - TokenErrorResponse, - ) => { - if (res.error) - throw new ApiError(res.error_description, 0, 400); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), ) + .post() + .json() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } - async refreshToken(connectedAccount: ConnectedAccount) { + async refreshToken( + connectedAccount: ConnectedAccount, + ): Promise { if (!connectedAccount.token_data?.refresh_token) throw new Error("No refresh token available."); const refresh_token = connectedAccount.token_data.refresh_token; const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "refresh_token", - refresh_token, - }), - }) - .then(async (res) => { - if ([400, 401].includes(res.status)) { - // assume the token was revoked - await connectedAccount.revoke(); - return DiscordApiErrors.CONNECTION_REVOKED; - } - // otherwise throw a general error - if (!res.ok) { - throw new ApiError("Failed to refresh token", 0, 400); - } - - return await res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - TokenErrorResponse, - ) => { - if (res.error) - throw new ApiError(res.error_description, 0, 400); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "refresh_token", + refresh_token, + }), ) + .post() + .unauthorized(async () => { + // assume the token was revoked + await connectedAccount.revoke(); + return DiscordApiErrors.CONNECTION_REVOKED; + }) + .json() .catch((e) => { - console.error( - `Error refreshing token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { - Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - return res.json(); - }) - .then((res: UserResponse & ErrorResponse) => { - if (res.error) throw new Error(res.error.message); - return res; + return wretch(url.toString()) + .headers({ + Authorization: `Bearer ${token}`, }) + .get() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Twitch/index.ts b/src/connections/Twitch/index.ts index ce04f098..264db3cc 100644 --- a/src/connections/Twitch/index.ts +++ b/src/connections/Twitch/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import RefreshableConnection from "../../util/connections/RefreshableConnection"; import { TwitchSettings } from "./TwitchSettings"; @@ -75,33 +74,27 @@ export default class TwitchConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - client_id: this.settings.clientId!, - client_secret: this.settings.clientSecret!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + ) + .post() + .json() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -115,60 +108,44 @@ export default class TwitchConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - grant_type: "refresh_token", - client_id: this.settings.clientId!, - client_secret: this.settings.clientSecret!, - refresh_token: refresh_token, - }), - }) - .then(async (res) => { - if ([400, 401].includes(res.status)) { - // assume the token was revoked - await connectedAccount.revoke(); - return DiscordApiErrors.CONNECTION_REVOKED; - } - // otherwise throw a general error - if (!res.ok) { - throw new ApiError("Failed to refresh token", 0, 400); - } - - return await res.json(); }) + .body( + new URLSearchParams({ + grant_type: "refresh_token", + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + refresh_token: refresh_token, + }), + ) + .post() + .unauthorized(async () => { + // assume the token was revoked + await connectedAccount.revoke(); + return DiscordApiErrors.CONNECTION_REVOKED; + }) + .json() .catch((e) => { - console.error( - `Error refreshing token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, "Client-Id": this.settings.clientId!, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); }) + .get() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Twitter/index.ts b/src/connections/Twitter/index.ts index d8a765ac..ad9d55d4 100644 --- a/src/connections/Twitter/index.ts +++ b/src/connections/Twitter/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import RefreshableConnection from "../../util/connections/RefreshableConnection"; import { TwitterSettings } from "./TwitterSettings"; @@ -77,45 +76,30 @@ export default class TwitterConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - client_id: this.settings.clientId!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - code_verifier: "challenge", // TODO: properly use PKCE challenge - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - TwitterErrorResponse, - ) => { - if (res.error) throw new Error(res.error_description); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + code_verifier: "challenge", // TODO: properly use PKCE challenge + }), ) + .post() + .json() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -129,72 +113,44 @@ export default class TwitterConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "refresh_token", - refresh_token, - client_id: this.settings.clientId!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - code_verifier: "challenge", // TODO: properly use PKCE challenge - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - TwitterErrorResponse, - ) => { - if (res.error) throw new Error(res.error_description); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "refresh_token", + refresh_token, + client_id: this.settings.clientId!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + code_verifier: "challenge", // TODO: properly use PKCE challenge + }), ) + .post() + .json() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); - }) - .then((res: TwitterUserResponse & TwitterErrorResponse) => { - if (res.error) throw new Error(res.error_description); - return res; }) + .get() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Xbox/index.ts b/src/connections/Xbox/index.ts index eb0e2496..80a04dea 100644 --- a/src/connections/Xbox/index.ts +++ b/src/connections/Xbox/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { XboxSettings } from "./XboxSettings"; @@ -76,36 +75,28 @@ export default class XboxConnection extends Connection { } async getUserToken(token: string): Promise { - return fetch(this.userAuthUrl, { - method: "POST", - headers: { + return wretch(this.userAuthUrl) + .headers({ "x-xbl-contract-version": "3", "Content-Type": "application/json", Accept: "application/json", - }, - body: JSON.stringify({ - RelyingParty: "http://auth.xboxlive.com", - TokenType: "JWT", - Properties: { - AuthMethod: "RPS", - SiteName: "user.auth.xboxlive.com", - RpsTicket: `d=${token}`, - }, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to get user token", 0, 400); - } - - return res.json(); }) - .then((res) => res.Token) + .body( + JSON.stringify({ + RelyingParty: "http://auth.xboxlive.com", + TokenType: "JWT", + Properties: { + AuthMethod: "RPS", + SiteName: "user.auth.xboxlive.com", + RpsTicket: `d=${token}`, + }, + }), + ) + .post() + .json((res: XboxUserResponse) => res.Token) .catch((e) => { - console.error( - `Error getting user token for ${this.id} connection: ${e}`, - ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + console.error(e); + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -117,82 +108,57 @@ export default class XboxConnection extends Connection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - client_id: this.settings.clientId!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - scope: this.scopes.join(" "), - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - XboxErrorResponse, - ) => { - if (res.error) throw new Error(res.error_description); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + scope: this.scopes.join(" "), + }), ) + .post() + .json() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "POST", - headers: { + + return wretch(url.toString()) + .headers({ "x-xbl-contract-version": "3", "Content-Type": "application/json", Accept: "application/json", - }, - body: JSON.stringify({ - RelyingParty: "http://xboxlive.com", - TokenType: "JWT", - Properties: { - UserTokens: [token], - SandboxId: "RETAIL", - }, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); - }) - .then((res: XboxUserResponse & XboxErrorResponse) => { - if (res.error) throw new Error(res.error_description); - return res; }) + .body( + JSON.stringify({ + RelyingParty: "http://xboxlive.com", + TokenType: "JWT", + Properties: { + UserTokens: [token], + SandboxId: "RETAIL", + }, + }), + ) + .post() + .json() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } From eab530a63dd0de7488028082eddfb6b7277beca7 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Fri, 13 Jan 2023 08:54:09 -0500 Subject: [PATCH 28/58] Add Youtube connection --- src/connections/Youtube/YoutubeSettings.ts | 5 + src/connections/Youtube/index.ts | 143 +++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 src/connections/Youtube/YoutubeSettings.ts create mode 100644 src/connections/Youtube/index.ts diff --git a/src/connections/Youtube/YoutubeSettings.ts b/src/connections/Youtube/YoutubeSettings.ts new file mode 100644 index 00000000..5d11fa40 --- /dev/null +++ b/src/connections/Youtube/YoutubeSettings.ts @@ -0,0 +1,5 @@ +export class YoutubeSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/Youtube/index.ts b/src/connections/Youtube/index.ts new file mode 100644 index 00000000..afc9356b --- /dev/null +++ b/src/connections/Youtube/index.ts @@ -0,0 +1,143 @@ +import { + Config, + ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; +import wretch from "wretch"; +import Connection from "../../util/connections/Connection"; +import { YoutubeSettings } from "./YoutubeSettings"; + +interface YouTubeConnectionChannelListResult { + items: { + snippet: { + // thumbnails: Thumbnails; + title: string; + country: string; + publishedAt: string; + // localized: Localized; + description: string; + }; + kind: string; + etag: string; + id: string; + }[]; + kind: string; + etag: string; + pageInfo: { + resultsPerPage: number; + totalResults: number; + }; +} + +export default class YoutubeConnection extends Connection { + public readonly id = "youtube"; + public readonly authorizeUrl = + "https://accounts.google.com/o/oauth2/v2/auth"; + public readonly tokenUrl = "https://oauth2.googleapis.com/token"; + public readonly userInfoUrl = + "https://www.googleapis.com/youtube/v3/channels?mine=true&part=snippet"; + public readonly scopes = [ + "https://www.googleapis.com/auth/youtube.readonly", + ]; + settings: YoutubeSettings = new YoutubeSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as YoutubeSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("response_type", "code"); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + return url.toString(); + } + + getTokenUrl(): string { + return this.tokenUrl; + } + + async exchangeCode( + state: string, + code: string, + ): Promise { + this.validateState(state); + + const url = this.getTokenUrl(); + + return wretch(url.toString()) + .headers({ + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }) + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + ) + .post() + .json() + .catch((e) => { + console.error(e); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return wretch(url.toString()) + .headers({ + Authorization: `Bearer ${token}`, + }) + .get() + .json() + .catch((e) => { + console.error(e); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { + const userId = this.getUserId(params.state); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); + + const exists = await this.hasConnection(userId, userInfo.items[0].id); + + if (exists) return null; + + return await this.createConnection({ + token_data: { ...tokenData, fetched_at: Date.now() }, + user_id: userId, + external_id: userInfo.items[0].id, + friend_sync: params.friend_sync, + name: userInfo.items[0].snippet.title, + type: this.id, + }); + } +} From 9d5c5a8292a59cc9ed2695f76d0863a553f44224 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 24 Jan 2023 16:23:34 +1100 Subject: [PATCH 29/58] Check visibility for connected accounts in /users/:id/profile --- src/api/routes/users/#id/profile.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/routes/users/#id/profile.ts b/src/api/routes/users/#id/profile.ts index dbf95a52..4efa379e 100644 --- a/src/api/routes/users/#id/profile.ts +++ b/src/api/routes/users/#id/profile.ts @@ -142,7 +142,9 @@ router.get( guild_id, }; res.json({ - connected_accounts: user.connected_accounts, + connected_accounts: user.connected_accounts.filter( + (x) => x.visibility != 0, + ), premium_guild_since: premium_guild_since, // TODO premium_since: user.premium_since, // TODO mutual_guilds: mutual_guilds, // TODO {id: "", nick: null} when ?with_mutual_guilds=true From c7277efbad5d3979222518ae543366ba8a08ca77 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 24 Jan 2023 18:15:26 +1100 Subject: [PATCH 30/58] Move redirect uri generation to getRedirectUri function of Connection class. Use api_endpointPublic instead of cdn_endpointPublic --- package-lock.json | 5 +++++ .../#connection_name/#connection_id/index.ts | 12 +++++++----- src/connections/BattleNet/index.ts | 14 ++------------ src/connections/Discord/index.ts | 15 ++------------- src/connections/EpicGames/index.ts | 9 +-------- src/connections/Facebook/index.ts | 16 ++-------------- src/connections/GitHub/index.ts | 9 +-------- src/connections/Reddit/index.ts | 14 ++------------ src/connections/Spotify/index.ts | 14 ++------------ src/connections/Twitch/index.ts | 14 ++------------ src/connections/Twitter/index.ts | 19 +++---------------- src/connections/Xbox/index.ts | 14 ++------------ src/connections/Youtube/index.ts | 14 ++------------ src/util/config/types/ApiConfiguration.ts | 2 +- src/util/connections/Connection.ts | 12 +++++++++++- 15 files changed, 45 insertions(+), 138 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8947d9e4..db3cbd8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14178,6 +14178,11 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "wretch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/wretch/-/wretch-2.3.2.tgz", + "integrity": "sha512-brN97Z2Mwed+w5z+keYI1u5OwWhPIaW0sJi9CxtKBVxLc3aqP6j1+2FCoIskM7WJq6SUHdxTFx20ox0iDLa0mQ==" + }, "ws": { "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts index 07440eac..5b8936f0 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts @@ -3,7 +3,7 @@ import { ConnectedAccount, ConnectionUpdateSchema, DiscordApiErrors, - emitEvent + emitEvent, } from "@fosscord/util"; import { Request, Response, Router } from "express"; const router = Router(); @@ -38,10 +38,12 @@ router.patch( if (!connection) return DiscordApiErrors.UNKNOWN_CONNECTION; // TODO: do we need to do anything if the connection is revoked? - //@ts-ignore For some reason the client sends this as a boolean, even tho docs say its a number? - if (typeof body.visibility === "boolean") body.visibility = body.visibility ? 1 : 0; - //@ts-ignore For some reason the client sends this as a boolean, even tho docs say its a number? - if (typeof body.show_activity === "boolean") body.show_activity = body.show_activity ? 1 : 0; + if (typeof body.visibility === "boolean") + //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number? + body.visibility = body.visibility ? 1 : 0; + if (typeof body.show_activity === "boolean") + //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number? + body.show_activity = body.show_activity ? 1 : 0; connection.assign(req.body); diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index 96c3993c..a88633ab 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -41,13 +40,7 @@ export default class BattleNetConnection extends Connection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("scope", this.scopes.join(" ")); url.searchParams.append("state", state); url.searchParams.append("response_type", "code"); @@ -76,10 +69,7 @@ export default class BattleNetConnection extends Connection { code: code, client_id: this.settings.clientId!, client_secret: this.settings.clientSecret!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || - "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: this.getRedirectUri(), }), ) .post() diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 52fc9ffd..1f812e4d 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -42,14 +41,7 @@ export default class DiscordConnection extends Connection { url.searchParams.append("response_type", "code"); // controls whether, on repeated authorizations, the consent screen is shown url.searchParams.append("consent", "none"); - - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); return url.toString(); } @@ -76,10 +68,7 @@ export default class DiscordConnection extends Connection { client_secret: this.settings.clientSecret!, grant_type: "authorization_code", code: code, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || - "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: this.getRedirectUri(), }), ) .post() diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts index 247d2435..db09c74f 100644 --- a/src/connections/EpicGames/index.ts +++ b/src/connections/EpicGames/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -47,13 +46,7 @@ export default class EpicGamesConnection extends Connection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("response_type", "code"); url.searchParams.append("scope", this.scopes.join(" ")); url.searchParams.append("state", state); diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts index 5413f867..cc298ed7 100644 --- a/src/connections/Facebook/index.ts +++ b/src/connections/Facebook/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -46,13 +45,7 @@ export default class FacebookConnection extends Connection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("state", state); url.searchParams.append("response_type", "code"); url.searchParams.append("scope", this.scopes.join(" ")); @@ -65,12 +58,7 @@ export default class FacebookConnection extends Connection { url.searchParams.append("client_id", this.settings.clientId!); url.searchParams.append("client_secret", this.settings.clientSecret!); url.searchParams.append("code", code); - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); return url.toString(); } diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index 8380e765..ea5e5493 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -36,13 +35,7 @@ export default class GitHubConnection extends Connection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("scope", this.scopes.join(" ")); url.searchParams.append("state", state); return url.toString(); diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts index 70b4a8af..7e5a1318 100644 --- a/src/connections/Reddit/index.ts +++ b/src/connections/Reddit/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -48,13 +47,7 @@ export default class RedditConnection extends Connection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("response_type", "code"); url.searchParams.append("scope", this.scopes.join(" ")); url.searchParams.append("state", state); @@ -85,10 +78,7 @@ export default class RedditConnection extends Connection { new URLSearchParams({ grant_type: "authorization_code", code: code, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || - "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: this.getRedirectUri(), }), ) .post() diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts index 54ec2696..ff06d341 100644 --- a/src/connections/Spotify/index.ts +++ b/src/connections/Spotify/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -57,13 +56,7 @@ export default class SpotifyConnection extends RefreshableConnection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("response_type", "code"); url.searchParams.append("scope", this.scopes.join(" ")); url.searchParams.append("state", state); @@ -94,10 +87,7 @@ export default class SpotifyConnection extends RefreshableConnection { new URLSearchParams({ grant_type: "authorization_code", code: code, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || - "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: this.getRedirectUri(), }), ) .post() diff --git a/src/connections/Twitch/index.ts b/src/connections/Twitch/index.ts index 264db3cc..7cc88caa 100644 --- a/src/connections/Twitch/index.ts +++ b/src/connections/Twitch/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -49,13 +48,7 @@ export default class TwitchConnection extends RefreshableConnection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("response_type", "code"); url.searchParams.append("scope", this.scopes.join(" ")); url.searchParams.append("state", state); @@ -85,10 +78,7 @@ export default class TwitchConnection extends RefreshableConnection { code: code, client_id: this.settings.clientId!, client_secret: this.settings.clientSecret!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || - "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: this.getRedirectUri(), }), ) .post() diff --git a/src/connections/Twitter/index.ts b/src/connections/Twitter/index.ts index ad9d55d4..8292b2c5 100644 --- a/src/connections/Twitter/index.ts +++ b/src/connections/Twitter/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -49,13 +48,7 @@ export default class TwitterConnection extends RefreshableConnection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("response_type", "code"); url.searchParams.append("scope", this.scopes.join(" ")); url.searchParams.append("state", state); @@ -89,10 +82,7 @@ export default class TwitterConnection extends RefreshableConnection { grant_type: "authorization_code", code: code, client_id: this.settings.clientId!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || - "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: this.getRedirectUri(), code_verifier: "challenge", // TODO: properly use PKCE challenge }), ) @@ -126,10 +116,7 @@ export default class TwitterConnection extends RefreshableConnection { grant_type: "refresh_token", refresh_token, client_id: this.settings.clientId!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || - "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: this.getRedirectUri(), code_verifier: "challenge", // TODO: properly use PKCE challenge }), ) diff --git a/src/connections/Xbox/index.ts b/src/connections/Xbox/index.ts index 80a04dea..1f736373 100644 --- a/src/connections/Xbox/index.ts +++ b/src/connections/Xbox/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -56,13 +55,7 @@ export default class XboxConnection extends Connection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("response_type", "code"); url.searchParams.append("scope", this.scopes.join(" ")); url.searchParams.append("state", state); @@ -121,10 +114,7 @@ export default class XboxConnection extends Connection { grant_type: "authorization_code", code: code, client_id: this.settings.clientId!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || - "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: this.getRedirectUri(), scope: this.scopes.join(" "), }), ) diff --git a/src/connections/Youtube/index.ts b/src/connections/Youtube/index.ts index afc9356b..9fa8eb38 100644 --- a/src/connections/Youtube/index.ts +++ b/src/connections/Youtube/index.ts @@ -1,5 +1,4 @@ import { - Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema, @@ -56,13 +55,7 @@ export default class YoutubeConnection extends Connection { const url = new URL(this.authorizeUrl); url.searchParams.append("client_id", this.settings.clientId!); - // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. - url.searchParams.append( - "redirect_uri", - `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - ); + url.searchParams.append("redirect_uri", this.getRedirectUri()); url.searchParams.append("response_type", "code"); url.searchParams.append("scope", this.scopes.join(" ")); url.searchParams.append("state", state); @@ -92,10 +85,7 @@ export default class YoutubeConnection extends Connection { code: code, client_id: this.settings.clientId!, client_secret: this.settings.clientSecret!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || - "http://localhost:3001" - }/connections/${this.id}/callback`, + redirect_uri: this.getRedirectUri(), }), ) .post() diff --git a/src/util/config/types/ApiConfiguration.ts b/src/util/config/types/ApiConfiguration.ts index 0389ed3e..579b1f2d 100644 --- a/src/util/config/types/ApiConfiguration.ts +++ b/src/util/config/types/ApiConfiguration.ts @@ -20,5 +20,5 @@ export class ApiConfiguration { defaultVersion: string = "9"; activeVersions: string[] = ["6", "7", "8", "9"]; useFosscordEnhancements: boolean = true; - endpointPublic: string = "/api"; + endpointPublic: string | null = null; } diff --git a/src/util/connections/Connection.ts b/src/util/connections/Connection.ts index 8b60b0d2..26279299 100644 --- a/src/util/connections/Connection.ts +++ b/src/util/connections/Connection.ts @@ -1,7 +1,7 @@ import crypto from "crypto"; import { ConnectedAccount } from "../entities"; import { ConnectedAccountSchema, ConnectionCallbackSchema } from "../schemas"; -import { DiscordApiErrors } from "../util"; +import { Config, DiscordApiErrors } from "../util"; /** * A connection that can be used to connect to an external service. @@ -19,6 +19,16 @@ export default abstract class Connection { */ abstract getAuthorizationUrl(userId: string): string; + /** + * Returns the redirect_uri for a connection type + * @returns redirect_uri for this connection + */ + getRedirectUri() { + const endpointPublic = + Config.get().api.endpointPublic ?? "http://localhost:3001"; + return `${endpointPublic}/connections/${this.id}/callback`; + } + /** * Processes the callback * @param args Callback arguments From 7116a9a1b0ee782d10330d5272ed340a36b5ddb6 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sat, 18 Mar 2023 19:48:44 -0400 Subject: [PATCH 31/58] fix a few linting errors --- src/util/connections/ConnectionConfig.ts | 2 +- src/util/connections/ConnectionLoader.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/util/connections/ConnectionConfig.ts b/src/util/connections/ConnectionConfig.ts index acbca026..4950ae90 100644 --- a/src/util/connections/ConnectionConfig.ts +++ b/src/util/connections/ConnectionConfig.ts @@ -54,7 +54,7 @@ function applyConfig(val: any) { } function pairsToConfig(pairs: ConnectionConfigEntity[]) { - let value: any = {}; + const value: any = {}; pairs.forEach((p) => { const keys = p.key.split("_"); diff --git a/src/util/connections/ConnectionLoader.ts b/src/util/connections/ConnectionLoader.ts index 04d7752a..0ca5b9e7 100644 --- a/src/util/connections/ConnectionLoader.ts +++ b/src/util/connections/ConnectionLoader.ts @@ -6,7 +6,7 @@ import { ConnectionConfig } from "./ConnectionConfig"; import { ConnectionStore } from "./ConnectionStore"; const root = "dist/connections"; -let connectionsLoaded = false; +const connectionsLoaded = false; export class ConnectionLoader { public static async loadConnections() { @@ -22,7 +22,7 @@ export class ConnectionLoader { }); dirs.forEach(async (x) => { - let modPath = path.resolve(path.join(root, x)); + const modPath = path.resolve(path.join(root, x)); const mod = new (require(modPath).default)() as Connection; ConnectionStore.connections.set(mod.id, mod); @@ -58,7 +58,10 @@ export class ConnectionLoader { ); await ConnectionConfig.set({ - [id]: Object.assign(config, (ConnectionLoader.getConnectionConfig(id) || {})) + [id]: Object.assign( + config, + ConnectionLoader.getConnectionConfig(id) || {}, + ), }); } } From 5a7765c7dc6e0ee5c873625ef76b0ee9c4e12300 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sat, 18 Mar 2023 19:50:38 -0400 Subject: [PATCH 32/58] prettier --- src/api/Server.ts | 2 +- src/api/middlewares/Authentication.ts | 2 +- src/connections/Discord/DiscordSettings.ts | 2 +- src/gateway/opcodes/Identify.ts | 101 +++++++++++---------- src/util/index.ts | 2 +- 5 files changed, 58 insertions(+), 51 deletions(-) diff --git a/src/api/Server.ts b/src/api/Server.ts index dc3b66ef..30f02e57 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts @@ -26,7 +26,7 @@ import { Sentry, WebAuthn, ConnectionConfig, - ConnectionLoader + ConnectionLoader, } from "@fosscord/util"; import { Request, Response, Router } from "express"; import { Server, ServerOptions } from "lambert-server"; diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts index 55527984..7f008a39 100644 --- a/src/api/middlewares/Authentication.ts +++ b/src/api/middlewares/Authentication.ts @@ -53,7 +53,7 @@ export const NO_AUTHORIZATION_ROUTES = [ // Asset delivery /\/guilds\/\d+\/widget\.(json|png)/, // Connections - /\/connections\/\w+\/callback/ + /\/connections\/\w+\/callback/, ]; export const API_PREFIX = /^\/api(\/v\d+)?/; diff --git a/src/connections/Discord/DiscordSettings.ts b/src/connections/Discord/DiscordSettings.ts index a8976f12..3751b041 100644 --- a/src/connections/Discord/DiscordSettings.ts +++ b/src/connections/Discord/DiscordSettings.ts @@ -2,4 +2,4 @@ export class DiscordSettings { enabled: boolean = false; clientId: string | null = null; clientSecret: string | null = null; -} \ No newline at end of file +} diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index d1d15790..c2a12918 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -79,53 +79,60 @@ export async function onIdentify(this: WebSocket, data: Payload) { this.user_id = decoded.id; const session_id = this.session_id; - const [user, read_states, members, recipients, session, application, connected_accounts] = - await Promise.all([ - User.findOneOrFail({ - where: { id: this.user_id }, - relations: ["relationships", "relationships.to", "settings"], - select: [...PrivateUserProjection, "relationships"], - }), - ReadState.find({ where: { user_id: this.user_id } }), - Member.find({ - where: { id: this.user_id }, - select: MemberPrivateProjection, - relations: [ - "guild", - "guild.channels", - "guild.emojis", - "guild.roles", - "guild.stickers", - "user", - "roles", - ], - }), - Recipient.find({ - where: { user_id: this.user_id, closed: false }, - relations: [ - "channel", - "channel.recipients", - "channel.recipients.user", - ], - // TODO: public user selection - }), - // save the session and delete it when the websocket is closed - Session.create({ - user_id: this.user_id, - session_id: session_id, - // TODO: check if status is only one of: online, dnd, offline, idle - status: identify.presence?.status || "offline", //does the session always start as online? - client_info: { - //TODO read from identity - client: "desktop", - os: identify.properties?.os, - version: 0, - }, - activities: [], - }).save(), - Application.findOne({ where: { id: this.user_id } }), - ConnectedAccount.find({ where: { user_id: this.user_id } }) - ]); + const [ + user, + read_states, + members, + recipients, + session, + application, + connected_accounts, + ] = await Promise.all([ + User.findOneOrFail({ + where: { id: this.user_id }, + relations: ["relationships", "relationships.to", "settings"], + select: [...PrivateUserProjection, "relationships"], + }), + ReadState.find({ where: { user_id: this.user_id } }), + Member.find({ + where: { id: this.user_id }, + select: MemberPrivateProjection, + relations: [ + "guild", + "guild.channels", + "guild.emojis", + "guild.roles", + "guild.stickers", + "user", + "roles", + ], + }), + Recipient.find({ + where: { user_id: this.user_id, closed: false }, + relations: [ + "channel", + "channel.recipients", + "channel.recipients.user", + ], + // TODO: public user selection + }), + // save the session and delete it when the websocket is closed + Session.create({ + user_id: this.user_id, + session_id: session_id, + // TODO: check if status is only one of: online, dnd, offline, idle + status: identify.presence?.status || "offline", //does the session always start as online? + client_info: { + //TODO read from identity + client: "desktop", + os: identify.properties?.os, + version: 0, + }, + activities: [], + }).save(), + Application.findOne({ where: { id: this.user_id } }), + ConnectedAccount.find({ where: { user_id: this.user_id } }), + ]); if (!user) return this.close(CLOSECODES.Authentication_failed); if (!user.settings) { diff --git a/src/util/index.ts b/src/util/index.ts index 9c0f7881..ef2671a5 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -25,4 +25,4 @@ export * from "./dtos/index"; export * from "./schemas"; export * from "./imports"; export * from "./config"; -export * from "./connections" +export * from "./connections"; From d90fd6b4e53eb056c579db736d9874f521319ba9 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sun, 2 Apr 2023 11:15:08 +1000 Subject: [PATCH 33/58] Update connection metadata visibility --- pnpm-lock.yaml | 5745 ----------------- .../#connection_name/#connection_id/index.ts | 5 +- src/util/schemas/ConnectionUpdateSchema.ts | 1 + 3 files changed, 5 insertions(+), 5746 deletions(-) delete mode 100644 pnpm-lock.yaml diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index f5fbb88d..00000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,5745 +0,0 @@ -lockfileVersion: 5.4 - -specifiers: - "@aws-sdk/client-s3": ^3.178.0 - "@sentry/integrations": ^7.17.2 - "@sentry/node": ^7.17.2 - "@sentry/tracing": ^7.17.2 - "@types/amqplib": ^0.8.2 - "@types/bcrypt": ^5.0.0 - "@types/body-parser": ^1.19.2 - "@types/cookie-parser": ^1.4.3 - "@types/express": ^4.17.15 - "@types/i18next-node-fs-backend": ^2.1.1 - "@types/json-bigint": ^1.0.1 - "@types/jsonwebtoken": ^8.5.9 - "@types/morgan": ^1.9.3 - "@types/multer": ^1.4.7 - "@types/node": ^18.7.20 - "@types/node-fetch": ^2.6.2 - "@types/node-os-utils": ^1.3.0 - "@types/probe-image-size": ^7.2.0 - "@types/sharp": ^0.31.0 - "@types/ws": ^8.5.3 - "@yukikaze-bot/erlpack": ^1.0.1 - ajv: 8.6.2 - ajv-formats: 2.1.1 - amqplib: ^0.10.3 - bcrypt: ^5.0.1 - body-parser: 1.20.1 - cheerio: ^1.0.0-rc.12 - cookie-parser: ^1.4.6 - dotenv: ^16.0.2 - exif-be-gone: ^1.3.1 - express: ^4.18.1 - fast-zlib: ^2.0.1 - file-type: "16.5" - form-data: ^4.0.0 - husky: ^8.0.0 - i18next: ^21.9.2 - i18next-http-middleware: ^3.2.1 - i18next-node-fs-backend: ^2.1.3 - image-size: ^1.0.2 - json-bigint: ^1.0.0 - jsonwebtoken: ^8.5.1 - lambert-server: ^1.2.12 - missing-native-js-functions: ^1.2.18 - module-alias: ^2.2.2 - morgan: ^1.10.0 - multer: ^1.4.5-lts.1 - node-2fa: ^2.0.3 - node-fetch: ^2.6.7 - node-os-utils: ^1.3.7 - picocolors: ^1.0.0 - prettier: ^2.7.1 - pretty-quick: ^3.1.3 - probe-image-size: ^7.2.3 - proxy-agent: ^5.0.0 - reflect-metadata: ^0.1.13 - sqlite3: ^5.1.4 - ts-node: ^10.9.1 - tslib: ^2.4.1 - typeorm: ^0.3.10 - typescript: ^4.8.3 - typescript-json-schema: ^0.50.1 - wretch: ^2.3.2 - ws: ^8.9.0 - -dependencies: - "@aws-sdk/client-s3": 3.245.0 - "@sentry/integrations": 7.30.0 - "@sentry/node": 7.30.0 - "@sentry/tracing": 7.30.0 - ajv: 8.6.2 - ajv-formats: 2.1.1_ajv@8.6.2 - amqplib: 0.10.3 - bcrypt: 5.1.0 - body-parser: 1.20.1 - cheerio: 1.0.0-rc.12 - cookie-parser: 1.4.6 - dotenv: 16.0.3 - exif-be-gone: 1.3.2 - fast-zlib: 2.0.1 - file-type: 16.5.4 - form-data: 4.0.0 - i18next: 21.10.0 - i18next-http-middleware: 3.2.1 - i18next-node-fs-backend: 2.1.3 - image-size: 1.0.2 - json-bigint: 1.0.0 - jsonwebtoken: 8.5.1 - lambert-server: 1.2.12 - missing-native-js-functions: 1.3.1 - module-alias: 2.2.2 - morgan: 1.10.0 - multer: 1.4.5-lts.1 - node-2fa: 2.0.3 - node-fetch: 2.6.7 - node-os-utils: 1.3.7 - picocolors: 1.0.0 - probe-image-size: 7.2.3 - proxy-agent: 5.0.0 - reflect-metadata: 0.1.13 - sqlite3: 5.1.4 - ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq - tslib: 2.4.1 - typeorm: 0.3.11_h3l5zcb3i6sggvllyfknv6gs44 - typescript-json-schema: 0.50.1 - wretch: 2.3.2 - ws: 8.12.0 - -optionalDependencies: - "@yukikaze-bot/erlpack": 1.0.1 - -devDependencies: - "@types/amqplib": 0.8.2 - "@types/bcrypt": 5.0.0 - "@types/body-parser": 1.19.2 - "@types/cookie-parser": 1.4.3 - "@types/express": 4.17.15 - "@types/i18next-node-fs-backend": 2.1.1 - "@types/json-bigint": 1.0.1 - "@types/jsonwebtoken": 8.5.9 - "@types/morgan": 1.9.4 - "@types/multer": 1.4.7 - "@types/node": 18.11.18 - "@types/node-fetch": 2.6.2 - "@types/node-os-utils": 1.3.0 - "@types/probe-image-size": 7.2.0 - "@types/sharp": 0.31.1 - "@types/ws": 8.5.4 - express: 4.18.2 - husky: 8.0.3 - prettier: 2.8.2 - pretty-quick: 3.1.3_prettier@2.8.2 - typescript: 4.9.4 - -packages: - /@acuminous/bitsyntax/0.1.2: - resolution: - { - integrity: sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==, - } - engines: { node: ">=0.8" } - dependencies: - buffer-more-ints: 1.0.0 - debug: 4.3.4 - safe-buffer: 5.1.2 - transitivePeerDependencies: - - supports-color - dev: false - - /@aws-crypto/crc32/2.0.0: - resolution: - { - integrity: sha512-TvE1r2CUueyXOuHdEigYjIZVesInd9KN+K/TFFNfkkxRThiNxO6i4ZqqAVMoEjAamZZ1AA8WXJkjCz7YShHPQA==, - } - dependencies: - "@aws-crypto/util": 2.0.2 - "@aws-sdk/types": 3.226.0 - tslib: 1.14.1 - dev: false - - /@aws-crypto/crc32c/2.0.0: - resolution: - { - integrity: sha512-vF0eMdMHx3O3MoOXUfBZry8Y4ZDtcuskjjKgJz8YfIDjLStxTZrYXk+kZqtl6A0uCmmiN/Eb/JbC/CndTV1MHg==, - } - dependencies: - "@aws-crypto/util": 2.0.2 - "@aws-sdk/types": 3.226.0 - tslib: 1.14.1 - dev: false - - /@aws-crypto/ie11-detection/2.0.2: - resolution: - { - integrity: sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==, - } - dependencies: - tslib: 1.14.1 - dev: false - - /@aws-crypto/sha1-browser/2.0.0: - resolution: - { - integrity: sha512-3fIVRjPFY8EG5HWXR+ZJZMdWNRpwbxGzJ9IH9q93FpbgCH8u8GHRi46mZXp3cYD7gealmyqpm3ThZwLKJjWJhA==, - } - dependencies: - "@aws-crypto/ie11-detection": 2.0.2 - "@aws-crypto/supports-web-crypto": 2.0.2 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-locate-window": 3.208.0 - "@aws-sdk/util-utf8-browser": 3.188.0 - tslib: 1.14.1 - dev: false - - /@aws-crypto/sha256-browser/2.0.0: - resolution: - { - integrity: sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==, - } - dependencies: - "@aws-crypto/ie11-detection": 2.0.2 - "@aws-crypto/sha256-js": 2.0.0 - "@aws-crypto/supports-web-crypto": 2.0.2 - "@aws-crypto/util": 2.0.2 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-locate-window": 3.208.0 - "@aws-sdk/util-utf8-browser": 3.188.0 - tslib: 1.14.1 - dev: false - - /@aws-crypto/sha256-js/2.0.0: - resolution: - { - integrity: sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==, - } - dependencies: - "@aws-crypto/util": 2.0.2 - "@aws-sdk/types": 3.226.0 - tslib: 1.14.1 - dev: false - - /@aws-crypto/supports-web-crypto/2.0.2: - resolution: - { - integrity: sha512-6mbSsLHwZ99CTOOswvCRP3C+VCWnzBf+1SnbWxzzJ9lR0mA0JnY2JEAhp8rqmTE0GPFy88rrM27ffgp62oErMQ==, - } - dependencies: - tslib: 1.14.1 - dev: false - - /@aws-crypto/util/2.0.2: - resolution: - { - integrity: sha512-Lgu5v/0e/BcrZ5m/IWqzPUf3UYFTy/PpeED+uc9SWUR1iZQL8XXbGQg10UfllwwBryO3hFF5dizK+78aoXC1eA==, - } - dependencies: - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-utf8-browser": 3.188.0 - tslib: 1.14.1 - dev: false - - /@aws-sdk/abort-controller/3.226.0: - resolution: - { - integrity: sha512-cJVzr1xxPBd08voknXvR0RLgtZKGKt6WyDpH/BaPCu3rfSqWCDZKzwqe940eqosjmKrxC6pUZNKASIqHOQ8xxQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/chunked-blob-reader-native/3.208.0: - resolution: - { - integrity: sha512-JeOZ95PW+fJ6bbuqPySYqLqHk1n4+4ueEEraJsiUrPBV0S1ZtyvOGHcnGztKUjr2PYNaiexmpWuvUve9K12HRA==, - } - dependencies: - "@aws-sdk/util-base64": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/chunked-blob-reader/3.188.0: - resolution: - { - integrity: sha512-zkPRFZZPL3eH+kH86LDYYXImiClA1/sW60zYOjse9Pgka+eDJlvBN6hcYxwDEKjcwATYiSRR1aVQHcfCinlGXg==, - } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/client-s3/3.245.0: - resolution: - { - integrity: sha512-wdCrEiqIfwtWebrK7A1giRggwO64S6I2iPXTwRmat4AR6sFlMO02jVFaIDyA8TTiVnBMz7ekT1QFmIjFAKc4uQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-crypto/sha1-browser": 2.0.0 - "@aws-crypto/sha256-browser": 2.0.0 - "@aws-crypto/sha256-js": 2.0.0 - "@aws-sdk/client-sts": 3.245.0 - "@aws-sdk/config-resolver": 3.234.0 - "@aws-sdk/credential-provider-node": 3.245.0 - "@aws-sdk/eventstream-serde-browser": 3.226.0 - "@aws-sdk/eventstream-serde-config-resolver": 3.226.0 - "@aws-sdk/eventstream-serde-node": 3.226.0 - "@aws-sdk/fetch-http-handler": 3.226.0 - "@aws-sdk/hash-blob-browser": 3.226.0 - "@aws-sdk/hash-node": 3.226.0 - "@aws-sdk/hash-stream-node": 3.226.0 - "@aws-sdk/invalid-dependency": 3.226.0 - "@aws-sdk/md5-js": 3.226.0 - "@aws-sdk/middleware-bucket-endpoint": 3.226.0 - "@aws-sdk/middleware-content-length": 3.226.0 - "@aws-sdk/middleware-endpoint": 3.226.0 - "@aws-sdk/middleware-expect-continue": 3.226.0 - "@aws-sdk/middleware-flexible-checksums": 3.226.0 - "@aws-sdk/middleware-host-header": 3.226.0 - "@aws-sdk/middleware-location-constraint": 3.226.0 - "@aws-sdk/middleware-logger": 3.226.0 - "@aws-sdk/middleware-recursion-detection": 3.226.0 - "@aws-sdk/middleware-retry": 3.235.0 - "@aws-sdk/middleware-sdk-s3": 3.231.0 - "@aws-sdk/middleware-serde": 3.226.0 - "@aws-sdk/middleware-signing": 3.226.0 - "@aws-sdk/middleware-ssec": 3.226.0 - "@aws-sdk/middleware-stack": 3.226.0 - "@aws-sdk/middleware-user-agent": 3.226.0 - "@aws-sdk/node-config-provider": 3.226.0 - "@aws-sdk/node-http-handler": 3.226.0 - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/signature-v4-multi-region": 3.226.0 - "@aws-sdk/smithy-client": 3.234.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/url-parser": 3.226.0 - "@aws-sdk/util-base64": 3.208.0 - "@aws-sdk/util-body-length-browser": 3.188.0 - "@aws-sdk/util-body-length-node": 3.208.0 - "@aws-sdk/util-defaults-mode-browser": 3.234.0 - "@aws-sdk/util-defaults-mode-node": 3.234.0 - "@aws-sdk/util-endpoints": 3.245.0 - "@aws-sdk/util-retry": 3.229.0 - "@aws-sdk/util-stream-browser": 3.226.0 - "@aws-sdk/util-stream-node": 3.226.0 - "@aws-sdk/util-user-agent-browser": 3.226.0 - "@aws-sdk/util-user-agent-node": 3.226.0 - "@aws-sdk/util-utf8-browser": 3.188.0 - "@aws-sdk/util-utf8-node": 3.208.0 - "@aws-sdk/util-waiter": 3.226.0 - "@aws-sdk/xml-builder": 3.201.0 - fast-xml-parser: 4.0.11 - tslib: 2.4.1 - transitivePeerDependencies: - - "@aws-sdk/signature-v4-crt" - - aws-crt - dev: false - - /@aws-sdk/client-sso-oidc/3.245.0: - resolution: - { - integrity: sha512-0pGPA00kEsu2Yq1Ul+OwftHxws5YVllm4iZrPtGnqmXr7wmf6B9lOtrMQF44y7Tfw53po6+bKz08OKTEWkkjUA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-crypto/sha256-browser": 2.0.0 - "@aws-crypto/sha256-js": 2.0.0 - "@aws-sdk/config-resolver": 3.234.0 - "@aws-sdk/fetch-http-handler": 3.226.0 - "@aws-sdk/hash-node": 3.226.0 - "@aws-sdk/invalid-dependency": 3.226.0 - "@aws-sdk/middleware-content-length": 3.226.0 - "@aws-sdk/middleware-endpoint": 3.226.0 - "@aws-sdk/middleware-host-header": 3.226.0 - "@aws-sdk/middleware-logger": 3.226.0 - "@aws-sdk/middleware-recursion-detection": 3.226.0 - "@aws-sdk/middleware-retry": 3.235.0 - "@aws-sdk/middleware-serde": 3.226.0 - "@aws-sdk/middleware-stack": 3.226.0 - "@aws-sdk/middleware-user-agent": 3.226.0 - "@aws-sdk/node-config-provider": 3.226.0 - "@aws-sdk/node-http-handler": 3.226.0 - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/smithy-client": 3.234.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/url-parser": 3.226.0 - "@aws-sdk/util-base64": 3.208.0 - "@aws-sdk/util-body-length-browser": 3.188.0 - "@aws-sdk/util-body-length-node": 3.208.0 - "@aws-sdk/util-defaults-mode-browser": 3.234.0 - "@aws-sdk/util-defaults-mode-node": 3.234.0 - "@aws-sdk/util-endpoints": 3.245.0 - "@aws-sdk/util-retry": 3.229.0 - "@aws-sdk/util-user-agent-browser": 3.226.0 - "@aws-sdk/util-user-agent-node": 3.226.0 - "@aws-sdk/util-utf8-browser": 3.188.0 - "@aws-sdk/util-utf8-node": 3.208.0 - tslib: 2.4.1 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/client-sso/3.245.0: - resolution: - { - integrity: sha512-dxzRwRo55ZNQ4hQigC+cishxLSWlBrbr3iszG0FLviavLDOlnVG5UUxWpOIGvwr8pYiSfM4jnfMxiwYwiCLg1g==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-crypto/sha256-browser": 2.0.0 - "@aws-crypto/sha256-js": 2.0.0 - "@aws-sdk/config-resolver": 3.234.0 - "@aws-sdk/fetch-http-handler": 3.226.0 - "@aws-sdk/hash-node": 3.226.0 - "@aws-sdk/invalid-dependency": 3.226.0 - "@aws-sdk/middleware-content-length": 3.226.0 - "@aws-sdk/middleware-endpoint": 3.226.0 - "@aws-sdk/middleware-host-header": 3.226.0 - "@aws-sdk/middleware-logger": 3.226.0 - "@aws-sdk/middleware-recursion-detection": 3.226.0 - "@aws-sdk/middleware-retry": 3.235.0 - "@aws-sdk/middleware-serde": 3.226.0 - "@aws-sdk/middleware-stack": 3.226.0 - "@aws-sdk/middleware-user-agent": 3.226.0 - "@aws-sdk/node-config-provider": 3.226.0 - "@aws-sdk/node-http-handler": 3.226.0 - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/smithy-client": 3.234.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/url-parser": 3.226.0 - "@aws-sdk/util-base64": 3.208.0 - "@aws-sdk/util-body-length-browser": 3.188.0 - "@aws-sdk/util-body-length-node": 3.208.0 - "@aws-sdk/util-defaults-mode-browser": 3.234.0 - "@aws-sdk/util-defaults-mode-node": 3.234.0 - "@aws-sdk/util-endpoints": 3.245.0 - "@aws-sdk/util-retry": 3.229.0 - "@aws-sdk/util-user-agent-browser": 3.226.0 - "@aws-sdk/util-user-agent-node": 3.226.0 - "@aws-sdk/util-utf8-browser": 3.188.0 - "@aws-sdk/util-utf8-node": 3.208.0 - tslib: 2.4.1 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/client-sts/3.245.0: - resolution: - { - integrity: sha512-E+7v2sy34TLni/Dmz6bTU20NWvbHYH9sVUHKQ9kHhmFopUWrs4Nt77f85PbuiKJz/irjUh9ppT5q1odJNRKRVQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-crypto/sha256-browser": 2.0.0 - "@aws-crypto/sha256-js": 2.0.0 - "@aws-sdk/config-resolver": 3.234.0 - "@aws-sdk/credential-provider-node": 3.245.0 - "@aws-sdk/fetch-http-handler": 3.226.0 - "@aws-sdk/hash-node": 3.226.0 - "@aws-sdk/invalid-dependency": 3.226.0 - "@aws-sdk/middleware-content-length": 3.226.0 - "@aws-sdk/middleware-endpoint": 3.226.0 - "@aws-sdk/middleware-host-header": 3.226.0 - "@aws-sdk/middleware-logger": 3.226.0 - "@aws-sdk/middleware-recursion-detection": 3.226.0 - "@aws-sdk/middleware-retry": 3.235.0 - "@aws-sdk/middleware-sdk-sts": 3.226.0 - "@aws-sdk/middleware-serde": 3.226.0 - "@aws-sdk/middleware-signing": 3.226.0 - "@aws-sdk/middleware-stack": 3.226.0 - "@aws-sdk/middleware-user-agent": 3.226.0 - "@aws-sdk/node-config-provider": 3.226.0 - "@aws-sdk/node-http-handler": 3.226.0 - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/smithy-client": 3.234.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/url-parser": 3.226.0 - "@aws-sdk/util-base64": 3.208.0 - "@aws-sdk/util-body-length-browser": 3.188.0 - "@aws-sdk/util-body-length-node": 3.208.0 - "@aws-sdk/util-defaults-mode-browser": 3.234.0 - "@aws-sdk/util-defaults-mode-node": 3.234.0 - "@aws-sdk/util-endpoints": 3.245.0 - "@aws-sdk/util-retry": 3.229.0 - "@aws-sdk/util-user-agent-browser": 3.226.0 - "@aws-sdk/util-user-agent-node": 3.226.0 - "@aws-sdk/util-utf8-browser": 3.188.0 - "@aws-sdk/util-utf8-node": 3.208.0 - fast-xml-parser: 4.0.11 - tslib: 2.4.1 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/config-resolver/3.234.0: - resolution: - { - integrity: sha512-uZxy4wzllfvgCQxVc+Iqhde0NGAnfmV2hWR6ejadJaAFTuYNvQiRg9IqJy3pkyDPqXySiJ8Bom5PoJfgn55J/A==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/signature-v4": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-config-provider": 3.208.0 - "@aws-sdk/util-middleware": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/credential-provider-env/3.226.0: - resolution: - { - integrity: sha512-sd8uK1ojbXxaZXlthzw/VXZwCPUtU3PjObOfr3Evj7MPIM2IH8h29foOlggx939MdLQGboJf9gKvLlvKDWtJRA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/credential-provider-imds/3.226.0: - resolution: - { - integrity: sha512-//z/COQm2AjYFI1Lb0wKHTQSrvLFTyuKLFQGPJsKS7DPoxGOCKB7hmYerlbl01IDoCxTdyL//TyyPxbZEOQD5Q==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/node-config-provider": 3.226.0 - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/url-parser": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/credential-provider-ini/3.245.0: - resolution: - { - integrity: sha512-1SjfVc5Wg0lLRUvwMrfjGgFkl+zfxn74gnkPr6by1QyMAoTzmeUkalPLAIqd+uHtFom9e3K633BQtX7zVPZ5XQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/credential-provider-env": 3.226.0 - "@aws-sdk/credential-provider-imds": 3.226.0 - "@aws-sdk/credential-provider-process": 3.226.0 - "@aws-sdk/credential-provider-sso": 3.245.0 - "@aws-sdk/credential-provider-web-identity": 3.226.0 - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/shared-ini-file-loader": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/credential-provider-node/3.245.0: - resolution: - { - integrity: sha512-Dwv8zmRLTDLeEkGrK/sLNFZSC+ahXZxr07CuID054QKACIdUEvkqYlnalRiTeXngiHGQ54u8wU7f0D32R2oL0g==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/credential-provider-env": 3.226.0 - "@aws-sdk/credential-provider-imds": 3.226.0 - "@aws-sdk/credential-provider-ini": 3.245.0 - "@aws-sdk/credential-provider-process": 3.226.0 - "@aws-sdk/credential-provider-sso": 3.245.0 - "@aws-sdk/credential-provider-web-identity": 3.226.0 - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/shared-ini-file-loader": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/credential-provider-process/3.226.0: - resolution: - { - integrity: sha512-iUDMdnrTvbvaCFhWwqyXrhvQ9+ojPqPqXhwZtY1X/Qaz+73S9gXBPJHZaZb2Ke0yKE1Ql3bJbKvmmxC/qLQMng==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/shared-ini-file-loader": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/credential-provider-sso/3.245.0: - resolution: - { - integrity: sha512-txWrJc0WNBhXMi7q+twjx7cs/qzgTfbQ+vbag5idRmdoUeiR8rfLvihCab2NaGg50xhh+TaoUCXrgJp3E/XjYQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/client-sso": 3.245.0 - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/shared-ini-file-loader": 3.226.0 - "@aws-sdk/token-providers": 3.245.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/credential-provider-web-identity/3.226.0: - resolution: - { - integrity: sha512-CCpv847rLB0SFOHz2igvUMFAzeT2fD3YnY4C8jltuJoEkn0ITn1Hlgt13nTJ5BUuvyti2mvyXZHmNzhMIMrIlw==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/eventstream-codec/3.226.0: - resolution: - { - integrity: sha512-6uPtR8vSwz3fqoZk9hrb6qBYdp3PJ22+JxV5Wimdesvow4kJXSgDQXIxEkxbv6SxB9tNRB4uJHD84RetHEi15Q==, - } - dependencies: - "@aws-crypto/crc32": 2.0.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-hex-encoding": 3.201.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/eventstream-serde-browser/3.226.0: - resolution: - { - integrity: sha512-otYC5aZE9eJUqAlKpy8w0rPDQ1eKGvZPtgxWXmFYSO2lDVGfI1nBBNmdZ4MdHqNuQ7ucsKMQYF8BFJ65K2tYPA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/eventstream-serde-universal": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/eventstream-serde-config-resolver/3.226.0: - resolution: - { - integrity: sha512-A56Gypg+lyEfA5cna+EUH9XTrj0SvRG1gwNW7lrUzviN36SeA/LFTUIOEjxVML3Lowy+EPAcrSZ67h6aepoAig==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/eventstream-serde-node/3.226.0: - resolution: - { - integrity: sha512-KWLnKkKDzI9RNkiK6OiSYpG/XjZfue6Bsp/vRG+H5z3fbXdHv4X2+iW+Efu2Kvn7jsUyUv82TCl57DyJ/HKYhQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/eventstream-serde-universal": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/eventstream-serde-universal/3.226.0: - resolution: - { - integrity: sha512-Q8viYM1Sv90/yIUqyWNeG1GEvyVlAI3GIrInQcCMC+xT59jS+IKGy2y7ojCvSWXnhf5/HMXKcmG092QsqeKy0Q==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/eventstream-codec": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/fetch-http-handler/3.226.0: - resolution: - { - integrity: sha512-JewZPMNEBXfi1xVnRa7pVtK/zgZD8/lQ/YnD8pq79WuMa2cwyhDtr8oqCoqsPW+WJT5ScXoMtuHxN78l8eKWgg==, - } - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/querystring-builder": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-base64": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/hash-blob-browser/3.226.0: - resolution: - { - integrity: sha512-5DCvWE6L4xGoViEHyjcPFuUe1G2EtNx8TqswWaoaKgyasP/yuRm4H99Ra7rqIrjCcSTAGD9NVsUQvVVw1bGt9w==, - } - dependencies: - "@aws-sdk/chunked-blob-reader": 3.188.0 - "@aws-sdk/chunked-blob-reader-native": 3.208.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/hash-node/3.226.0: - resolution: - { - integrity: sha512-MdlJhJ9/Espwd0+gUXdZRsHuostB2WxEVAszWxobP0FTT9PnicqnfK7ExmW+DUAc0ywxtEbR3e0UND65rlSTVw==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-buffer-from": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/hash-stream-node/3.226.0: - resolution: - { - integrity: sha512-cgNTGlF8SdHaQXtjEmuLXz2U8SLM2JDKtIVPku/lHTMsUsEn+fuv2C+h1f/hvd4aNw5t1zggym7sO1/h/rv56Q==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/invalid-dependency/3.226.0: - resolution: - { - integrity: sha512-QXOYFmap8g9QzRjumcRCIo2GEZkdCwd7ePQW0OABWPhKHzlJ74vvBxywjU3s39EEBEluWXtZ7Iufg6GxZM4ifw==, - } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/is-array-buffer/3.201.0: - resolution: - { - integrity: sha512-UPez5qLh3dNgt0DYnPD/q0mVJY84rA17QE26hVNOW3fAji8W2wrwrxdacWOxyXvlxWsVRcKmr+lay1MDqpAMfg==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/md5-js/3.226.0: - resolution: - { - integrity: sha512-ENigJRNudqyh6xsch166SZ4gggHd3XzZJ8gkCU4CWPne04HcR3BkWSO774IuWooCHt8zkaEHKecPurRz6qR+Vw==, - } - dependencies: - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-utf8-browser": 3.188.0 - "@aws-sdk/util-utf8-node": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-bucket-endpoint/3.226.0: - resolution: - { - integrity: sha512-A1Vq5W2X7jgTfjqcKPmjoHohF0poP+9fxwL97fQMvzcwmjhtoCV3bLEpo6CGYx0pKPiSlRJXZkRwRPj2hDHDmA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-arn-parser": 3.208.0 - "@aws-sdk/util-config-provider": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-content-length/3.226.0: - resolution: - { - integrity: sha512-ksUzlHJN2JMuyavjA46a4sctvnrnITqt2tbGGWWrAuXY1mel2j+VbgnmJUiwHKUO6bTFBBeft5Vd1TSOb4JmiA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-endpoint/3.226.0: - resolution: - { - integrity: sha512-EvLFafjtUxTT0AC9p3aBQu1/fjhWdIeK58jIXaNFONfZ3F8QbEYUPuF/SqZvJM6cWfOO9qwYKkRDbCSTYhprIg==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/middleware-serde": 3.226.0 - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/signature-v4": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/url-parser": 3.226.0 - "@aws-sdk/util-config-provider": 3.208.0 - "@aws-sdk/util-middleware": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-expect-continue/3.226.0: - resolution: - { - integrity: sha512-YxvQKTV/eA9P8AgW0hXOgj5Qa+TSnNFfyOkfeP089aP3f6p92b1cESf33TEOKsddive2mHT5LRCN6MuPcgWWrA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-flexible-checksums/3.226.0: - resolution: - { - integrity: sha512-8A9Ot9A7794UP5tMGl2MnfTW/UM/jYy1wRWF9YkR/hPIcPb7OmE0hmlwIQGzb/7grxpYw66ETKf0WeH/41YfeQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-crypto/crc32": 2.0.0 - "@aws-crypto/crc32c": 2.0.0 - "@aws-sdk/is-array-buffer": 3.201.0 - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-host-header/3.226.0: - resolution: - { - integrity: sha512-haVkWVh6BUPwKgWwkL6sDvTkcZWvJjv8AgC8jiQuSl8GLZdzHTB8Qhi3IsfFta9HAuoLjxheWBE5Z/L0UrfhLA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-location-constraint/3.226.0: - resolution: - { - integrity: sha512-qHiYaBYPc2R37KxG2uqsUUwh4usrQMHfGkrpTUnx5d4rGzM3mC+muPsTpSHnAL63K2/yJOHQJFjss3GGwV4SSA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-logger/3.226.0: - resolution: - { - integrity: sha512-m9gtLrrYnpN6yckcQ09rV7ExWOLMuq8mMPF/K3DbL/YL0TuILu9i2T1W+JuxSX+K9FMG2HrLAKivE/kMLr55xA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-recursion-detection/3.226.0: - resolution: - { - integrity: sha512-mwRbdKEUeuNH5TEkyZ5FWxp6bL2UC1WbY+LDv6YjHxmSMKpAoOueEdtU34PqDOLrpXXxIGHDFmjeGeMfktyEcA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-retry/3.235.0: - resolution: - { - integrity: sha512-50WHbJGpD3SNp9763MAlHqIhXil++JdQbKejNpHg7HsJne/ao3ub+fDOfx//mMBjpzBV25BGd5UlfL6blrClSg==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/service-error-classification": 3.229.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-middleware": 3.226.0 - "@aws-sdk/util-retry": 3.229.0 - tslib: 2.4.1 - uuid: 8.3.2 - dev: false - - /@aws-sdk/middleware-sdk-s3/3.231.0: - resolution: - { - integrity: sha512-UGaSvevd2TanfKgStF46dDSHkh4bxOr1gdUkyHm9i+1pF5lx4KdbnBZv/5SKnn7XifhHRXrs1M3lTzemXREhTA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-arn-parser": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-sdk-sts/3.226.0: - resolution: - { - integrity: sha512-NN9T/qoSD1kZvAT+VLny3NnlqgylYQcsgV3rvi/8lYzw/G/2s8VS6sm/VTWGGZhx08wZRv20MWzYu3bftcyqUg==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/middleware-signing": 3.226.0 - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/signature-v4": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-serde/3.226.0: - resolution: - { - integrity: sha512-nPuOOAkSfx9TxzdKFx0X2bDlinOxGrqD7iof926K/AEflxGD1DBdcaDdjlYlPDW2CVE8LV/rAgbYuLxh/E/1VA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-signing/3.226.0: - resolution: - { - integrity: sha512-E6HmtPcl+IjYDDzi1xI2HpCbBq2avNWcjvCriMZWuTAtRVpnA6XDDGW5GY85IfS3A8G8vuWqEVPr8JcYUcjfew==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/signature-v4": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-middleware": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-ssec/3.226.0: - resolution: - { - integrity: sha512-DR97oWoLHiMdaUP/wu99HtzG7/ijvCrjZGDH37WBO1rxFtEti6L7T09wgHzwxMN8gtL8FJA7dU8IrffGSC9VmA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-stack/3.226.0: - resolution: - { - integrity: sha512-85wF29LvPvpoed60fZGDYLwv1Zpd/cM0C22WSSFPw1SSJeqO4gtFYyCg2squfT3KI6kF43IIkOCJ+L7GtryPug==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/middleware-user-agent/3.226.0: - resolution: - { - integrity: sha512-N1WnfzCW1Y5yWhVAphf8OPGTe8Df3vmV7/LdsoQfmpkCZgLZeK2o0xITkUQhRj1mbw7yp8tVFLFV3R2lMurdAQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/node-config-provider/3.226.0: - resolution: - { - integrity: sha512-B8lQDqiRk7X5izFEUMXmi8CZLOKCTWQJU9HQf3ako+sF0gexo4nHN3jhoRWyLtcgC5S3on/2jxpAcqtm7kuY3w==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/shared-ini-file-loader": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/node-http-handler/3.226.0: - resolution: - { - integrity: sha512-xQCddnZNMiPmjr3W7HYM+f5ir4VfxgJh37eqZwX6EZmyItFpNNeVzKUgA920ka1VPz/ZUYB+2OFGiX3LCLkkaA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/abort-controller": 3.226.0 - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/querystring-builder": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/property-provider/3.226.0: - resolution: - { - integrity: sha512-TsljjG+Sg0LmdgfiAlWohluWKnxB/k8xenjeozZfzOr5bHmNHtdbWv6BtNvD/R83hw7SFXxbJHlD5H4u9p2NFg==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/protocol-http/3.226.0: - resolution: - { - integrity: sha512-zWkVqiTA9RXL6y0hhfZc9bcU4DX2NI6Hw9IhQmSPeM59mdbPjJlY4bLlMr5YxywqO3yQ/ylNoAfrEzrDjlOSRg==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/querystring-builder/3.226.0: - resolution: - { - integrity: sha512-LVurypuNeotO4lmirKXRC4NYrZRAyMJXuwO0f2a5ZAUJCjauwYrifKue6yCfU7bls7gut7nfcR6B99WBYpHs3g==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-uri-escape": 3.201.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/querystring-parser/3.226.0: - resolution: - { - integrity: sha512-FzB+VrQ47KAFxiPt2YXrKZ8AOLZQqGTLCKHzx4bjxGmwgsjV8yIbtJiJhZLMcUQV4LtGeIY9ixIqQhGvnZHE4A==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/service-error-classification/3.229.0: - resolution: - { - integrity: sha512-dnzWWQ0/NoWMUZ5C0DW3dPm0wC1O76Y/SpKbuJzWPkx1EYy6r8p32Ly4D9vUzrKDbRGf48YHIF2kOkBmu21CLg==, - } - engines: { node: ">=14.0.0" } - dev: false - - /@aws-sdk/shared-ini-file-loader/3.226.0: - resolution: - { - integrity: sha512-661VQefsARxVyyV2FX9V61V+nNgImk7aN2hYlFKla6BCwZfMng+dEtD0xVGyg1PfRw0qvEv5LQyxMVgHcUSevA==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/signature-v4-multi-region/3.226.0: - resolution: - { - integrity: sha512-QHxNuf9ynK208v7Y3imdsa3Cz8ynYV7ZOf3sBJdItuEtHN6uy/KxaOrtvpF8I5Hyn48Hc8z5miTSMujFKT7GEw==, - } - engines: { node: ">=14.0.0" } - peerDependencies: - "@aws-sdk/signature-v4-crt": ^3.118.0 - peerDependenciesMeta: - "@aws-sdk/signature-v4-crt": - optional: true - dependencies: - "@aws-sdk/protocol-http": 3.226.0 - "@aws-sdk/signature-v4": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-arn-parser": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/signature-v4/3.226.0: - resolution: - { - integrity: sha512-/R5q5agdPd7HJB68XMzpxrNPk158EHUvkFkuRu5Qf3kkkHebEzWEBlWoVpUe6ss4rP9Tqcue6xPuaftEmhjpYw==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/is-array-buffer": 3.201.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-hex-encoding": 3.201.0 - "@aws-sdk/util-middleware": 3.226.0 - "@aws-sdk/util-uri-escape": 3.201.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/smithy-client/3.234.0: - resolution: - { - integrity: sha512-8AtR/k4vsFvjXeQbIzq/Wy7Nbk48Ou0wUEeVYPHWHPSU8QamFWORkOwmKtKMfHAyZvmqiAPeQqHFkq+UJhWyyQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/middleware-stack": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/token-providers/3.245.0: - resolution: - { - integrity: sha512-m/spXR/vEXGb+zMqRUMQYVMwFZSTdK5RkddYqamYkNhIoLm60EYeRu57JsMMs5djKi8dBRSKiXwVHx0l2rXMjg==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/client-sso-oidc": 3.245.0 - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/shared-ini-file-loader": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/types/3.226.0: - resolution: - { - integrity: sha512-MmmNHrWeO4man7wpOwrAhXlevqtOV9ZLcH4RhnG5LmRce0RFOApx24HoKENfFCcOyCm5LQBlsXCqi0dZWDWU0A==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/url-parser/3.226.0: - resolution: - { - integrity: sha512-p5RLE0QWyP0OcTOLmFcLdVgUcUEzmEfmdrnOxyNzomcYb0p3vUagA5zfa1HVK2azsQJFBv28GfvMnba9bGhObg==, - } - dependencies: - "@aws-sdk/querystring-parser": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-arn-parser/3.208.0: - resolution: - { - integrity: sha512-QV4af+kscova9dv4VuHOgH8wEr/IIYHDGcnyVtkUEqahCejWr1Kuk+SBK0xMwnZY5LSycOtQ8aeqHOn9qOjZtA==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-base64/3.208.0: - resolution: - { - integrity: sha512-PQniZph5A6N7uuEOQi+1hnMz/FSOK/8kMFyFO+4DgA1dZ5pcKcn5wiFwHkcTb/BsgVqQa3Jx0VHNnvhlS8JyTg==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/util-buffer-from": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-body-length-browser/3.188.0: - resolution: - { - integrity: sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==, - } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-body-length-node/3.208.0: - resolution: - { - integrity: sha512-3zj50e5g7t/MQf53SsuuSf0hEELzMtD8RX8C76f12OSRo2Bca4FLLYHe0TZbxcfQHom8/hOaeZEyTyMogMglqg==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-buffer-from/3.208.0: - resolution: - { - integrity: sha512-7L0XUixNEFcLUGPeBF35enCvB9Xl+K6SQsmbrPk1P3mlV9mguWSDQqbOBwY1Ir0OVbD6H/ZOQU7hI/9RtRI0Zw==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/is-array-buffer": 3.201.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-config-provider/3.208.0: - resolution: - { - integrity: sha512-DSRqwrERUsT34ug+anlMBIFooBEGwM8GejC7q00Y/9IPrQy50KnG5PW2NiTjuLKNi7pdEOlwTSEocJE15eDZIg==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-defaults-mode-browser/3.234.0: - resolution: - { - integrity: sha512-IHMKXjTbOD8XMz5+2oCOsVP94BYb9YyjXdns0aAXr2NAo7k2+RCzXQ2DebJXppGda1F6opFutoKwyVSN0cmbMw==, - } - engines: { node: ">= 10.0.0" } - dependencies: - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/types": 3.226.0 - bowser: 2.11.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-defaults-mode-node/3.234.0: - resolution: - { - integrity: sha512-UGjQ+OjBYYhxFVtUY+jtr0ZZgzZh6OHtYwRhFt8IHewJXFCfZTyfsbX20szBj5y1S4HRIUJ7cwBLIytTqMbI5w==, - } - engines: { node: ">= 10.0.0" } - dependencies: - "@aws-sdk/config-resolver": 3.234.0 - "@aws-sdk/credential-provider-imds": 3.226.0 - "@aws-sdk/node-config-provider": 3.226.0 - "@aws-sdk/property-provider": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-endpoints/3.245.0: - resolution: - { - integrity: sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-hex-encoding/3.201.0: - resolution: - { - integrity: sha512-7t1vR1pVxKx0motd3X9rI3m/xNp78p3sHtP5yo4NP4ARpxyJ0fokBomY8ScaH2D/B+U5o9ARxldJUdMqyBlJcA==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-locate-window/3.208.0: - resolution: - { - integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-middleware/3.226.0: - resolution: - { - integrity: sha512-B96CQnwX4gRvQdaQkdUtqvDPkrptV5+va6FVeJOocU/DbSYMAScLxtR3peMS8cnlOT6nL1Eoa42OI9AfZz1VwQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-retry/3.229.0: - resolution: - { - integrity: sha512-0zKTqi0P1inD0LzIMuXRIYYQ/8c1lWMg/cfiqUcIAF1TpatlpZuN7umU0ierpBFud7S+zDgg0oemh+Nj8xliJw==, - } - engines: { node: ">= 14.0.0" } - dependencies: - "@aws-sdk/service-error-classification": 3.229.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-stream-browser/3.226.0: - resolution: - { - integrity: sha512-ZvjlA1ySaLd0DqUWTKmL7LsxfPhroAONpzsinaHmw9aZVL40s2cADU9eWgBdHTuAOeFklL7NP0cc6UiTFHKe8g==, - } - dependencies: - "@aws-sdk/fetch-http-handler": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-base64": 3.208.0 - "@aws-sdk/util-hex-encoding": 3.201.0 - "@aws-sdk/util-utf8-browser": 3.188.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-stream-node/3.226.0: - resolution: - { - integrity: sha512-HADXiIgDGoXcCLSKuPnjCLENf0iC0lzqqnymZu9H2FoACZhJB7DvJ9LnP51Pvw9lfCu+yvLzbMqSPdbXtMbRWg==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/node-http-handler": 3.226.0 - "@aws-sdk/types": 3.226.0 - "@aws-sdk/util-buffer-from": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-uri-escape/3.201.0: - resolution: - { - integrity: sha512-TeTWbGx4LU2c5rx0obHeDFeO9HvwYwQtMh1yniBz00pQb6Qt6YVOETVQikRZ+XRQwEyCg/dA375UplIpiy54mA==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-user-agent-browser/3.226.0: - resolution: - { - integrity: sha512-PhBIu2h6sPJPcv2I7ELfFizdl5pNiL4LfxrasMCYXQkJvVnoXztHA1x+CQbXIdtZOIlpjC+6BjDcE0uhnpvfcA==, - } - dependencies: - "@aws-sdk/types": 3.226.0 - bowser: 2.11.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-user-agent-node/3.226.0: - resolution: - { - integrity: sha512-othPc5Dz/pkYkxH+nZPhc1Al0HndQT8zHD4e9h+EZ+8lkd8n+IsnLfTS/mSJWrfiC6UlNRVw55cItstmJyMe/A==, - } - engines: { node: ">=14.0.0" } - peerDependencies: - aws-crt: ">=1.0.0" - peerDependenciesMeta: - aws-crt: - optional: true - dependencies: - "@aws-sdk/node-config-provider": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-utf8-browser/3.188.0: - resolution: - { - integrity: sha512-jt627x0+jE+Ydr9NwkFstg3cUvgWh56qdaqAMDsqgRlKD21md/6G226z/Qxl7lb1VEW2LlmCx43ai/37Qwcj2Q==, - } - dependencies: - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-utf8-node/3.208.0: - resolution: - { - integrity: sha512-jKY87Acv0yWBdFxx6bveagy5FYjz+dtV8IPT7ay1E2WPWH1czoIdMAkc8tSInK31T6CRnHWkLZ1qYwCbgRfERQ==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/util-buffer-from": 3.208.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/util-waiter/3.226.0: - resolution: - { - integrity: sha512-qYQMRxnu5k8qQihJXoIWMkBOj0+XkHHj/drLdbRnwL6ni6NcG8++cs9M3DSjIcxmxgF/7SLpDjn1H3sC7cYo4g==, - } - engines: { node: ">=14.0.0" } - dependencies: - "@aws-sdk/abort-controller": 3.226.0 - "@aws-sdk/types": 3.226.0 - tslib: 2.4.1 - dev: false - - /@aws-sdk/xml-builder/3.201.0: - resolution: - { - integrity: sha512-brRdB1wwMgjWEnOQsv7zSUhIQuh7DEicrfslAqHop4S4FtSI3GQAShpQqgOpMTNFYcpaWKmE/Y1MJmNY7xLCnw==, - } - engines: { node: ">=14.0.0" } - dependencies: - tslib: 2.4.1 - dev: false - - /@babel/runtime/7.20.7: - resolution: - { - integrity: sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==, - } - engines: { node: ">=6.9.0" } - dependencies: - regenerator-runtime: 0.13.11 - - /@cspotcode/source-map-support/0.8.1: - resolution: - { - integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, - } - engines: { node: ">=12" } - dependencies: - "@jridgewell/trace-mapping": 0.3.9 - dev: false - - /@gar/promisify/1.1.3: - resolution: - { - integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==, - } - dev: false - optional: true - - /@jridgewell/resolve-uri/3.1.0: - resolution: - { - integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==, - } - engines: { node: ">=6.0.0" } - dev: false - - /@jridgewell/sourcemap-codec/1.4.14: - resolution: - { - integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==, - } - dev: false - - /@jridgewell/trace-mapping/0.3.9: - resolution: - { - integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==, - } - dependencies: - "@jridgewell/resolve-uri": 3.1.0 - "@jridgewell/sourcemap-codec": 1.4.14 - dev: false - - /@mapbox/node-pre-gyp/1.0.10: - resolution: - { - integrity: sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==, - } - hasBin: true - dependencies: - detect-libc: 2.0.1 - https-proxy-agent: 5.0.1 - make-dir: 3.1.0 - node-fetch: 2.6.7 - nopt: 5.0.0 - npmlog: 5.0.1 - rimraf: 3.0.2 - semver: 7.3.8 - tar: 6.1.13 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - - /@npmcli/fs/1.1.1: - resolution: - { - integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==, - } - dependencies: - "@gar/promisify": 1.1.3 - semver: 7.3.8 - dev: false - optional: true - - /@npmcli/move-file/1.1.2: - resolution: - { - integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==, - } - engines: { node: ">=10" } - deprecated: This functionality has been moved to @npmcli/fs - dependencies: - mkdirp: 1.0.4 - rimraf: 3.0.2 - dev: false - optional: true - - /@sentry/core/7.30.0: - resolution: - { - integrity: sha512-NeLigkBlpcK63ymM63GoIHurml6V3BUe1Vi+trwm4/qqOTzT7PQhvdJCX+o3+atzRBH+zdb6kd4VWx44Oye3KA==, - } - engines: { node: ">=8" } - dependencies: - "@sentry/types": 7.30.0 - "@sentry/utils": 7.30.0 - tslib: 1.14.1 - dev: false - - /@sentry/integrations/7.30.0: - resolution: - { - integrity: sha512-KU8TnJm1Yldxnhdu/EZcIGXU9ptGQPk6ot4smcNx/mKsy575VrDdyVDx8uIYURWyfsg7eOayt6VdC7ISSODp8A==, - } - engines: { node: ">=8" } - dependencies: - "@sentry/types": 7.30.0 - "@sentry/utils": 7.30.0 - localforage: 1.10.0 - tslib: 1.14.1 - dev: false - - /@sentry/node/7.30.0: - resolution: - { - integrity: sha512-YYasu6C3I0HBP4N1oc/ed2nunxhGJgtAWaKwq3lo8uk3uF6cB1A8+2e0CpjzU5ejhbaFPUBxHyj4th39Bvku/w==, - } - engines: { node: ">=8" } - dependencies: - "@sentry/core": 7.30.0 - "@sentry/types": 7.30.0 - "@sentry/utils": 7.30.0 - cookie: 0.4.2 - https-proxy-agent: 5.0.1 - lru_map: 0.3.3 - tslib: 1.14.1 - transitivePeerDependencies: - - supports-color - dev: false - - /@sentry/tracing/7.30.0: - resolution: - { - integrity: sha512-bjGeDeKhpGAmLcWcrXFT/xOfHVwp/j0L1aRHzYHnqgTjVzD0NXcooPu/Nz8vF0paxz+hPD5bJwb8kz/ggJzGWQ==, - } - engines: { node: ">=8" } - dependencies: - "@sentry/core": 7.30.0 - "@sentry/types": 7.30.0 - "@sentry/utils": 7.30.0 - tslib: 1.14.1 - dev: false - - /@sentry/types/7.30.0: - resolution: - { - integrity: sha512-l4A86typvt/SfWh5JffpdxNGkg5EEA8m35BzpIcKmCAQZUDmnb4b478r8jdD2uuOjLmPNmZr1tifdRW4NCLuxQ==, - } - engines: { node: ">=8" } - dev: false - - /@sentry/utils/7.30.0: - resolution: - { - integrity: sha512-tSlBhr5u/LdE2emxIDTDmjmyRr99GnZGIAh5GwRxUgeDQ3VEfNUFlyFodBCbZ6yeYTYd6PWNih5xoHn1+Rf3Sw==, - } - engines: { node: ">=8" } - dependencies: - "@sentry/types": 7.30.0 - tslib: 1.14.1 - dev: false - - /@sqltools/formatter/1.2.5: - resolution: - { - integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==, - } - dev: false - - /@tokenizer/token/0.3.0: - resolution: - { - integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==, - } - dev: false - - /@tootallnate/once/1.1.2: - resolution: - { - integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==, - } - engines: { node: ">= 6" } - dev: false - - /@tsconfig/node10/1.0.9: - resolution: - { - integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==, - } - dev: false - - /@tsconfig/node12/1.0.11: - resolution: - { - integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==, - } - dev: false - - /@tsconfig/node14/1.0.3: - resolution: - { - integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==, - } - dev: false - - /@tsconfig/node16/1.0.3: - resolution: - { - integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==, - } - dev: false - - /@types/amqplib/0.8.2: - resolution: - { - integrity: sha512-p+TFLzo52f8UanB+Nq6gyUi65yecAcRY3nYowU6MPGFtaJvEDxcnFWrxssSTkF+ts1W3zyQDvgVICLQem5WxRA==, - } - dependencies: - "@types/bluebird": 3.5.38 - "@types/node": 18.11.18 - dev: true - - /@types/bcrypt/5.0.0: - resolution: - { - integrity: sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==, - } - dependencies: - "@types/node": 18.11.18 - dev: true - - /@types/bluebird/3.5.38: - resolution: - { - integrity: sha512-yR/Kxc0dd4FfwtEoLZMoqJbM/VE/W7hXn/MIjb+axcwag0iFmSPK7OBUZq1YWLynJUoWQkfUrI7T0HDqGApNSg==, - } - dev: true - - /@types/body-parser/1.19.2: - resolution: - { - integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==, - } - dependencies: - "@types/connect": 3.4.35 - "@types/node": 18.11.18 - dev: true - - /@types/connect/3.4.35: - resolution: - { - integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==, - } - dependencies: - "@types/node": 18.11.18 - dev: true - - /@types/cookie-parser/1.4.3: - resolution: - { - integrity: sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==, - } - dependencies: - "@types/express": 4.17.15 - dev: true - - /@types/express-serve-static-core/4.17.32: - resolution: - { - integrity: sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==, - } - dependencies: - "@types/node": 18.11.18 - "@types/qs": 6.9.7 - "@types/range-parser": 1.2.4 - dev: true - - /@types/express/4.17.15: - resolution: - { - integrity: sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==, - } - dependencies: - "@types/body-parser": 1.19.2 - "@types/express-serve-static-core": 4.17.32 - "@types/qs": 6.9.7 - "@types/serve-static": 1.15.0 - dev: true - - /@types/i18next-node-fs-backend/2.1.1: - resolution: - { - integrity: sha512-ESvH90OICQkKU3yuuRzF6YfHt5KACE55FOiUM59mMGnC+h03lHGdEYo3z3THbwS5FdMskLyIs2O7f6Oaz8P9sw==, - } - dependencies: - i18next: 21.10.0 - dev: true - - /@types/json-bigint/1.0.1: - resolution: - { - integrity: sha512-zpchZLNsNuzJHi6v64UBoFWAvQlPhch7XAi36FkH6tL1bbbmimIF+cS7vwkzY4u5RaSWMoflQfu+TshMPPw8uw==, - } - dev: true - - /@types/json-schema/7.0.11: - resolution: - { - integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==, - } - dev: false - - /@types/jsonwebtoken/8.5.9: - resolution: - { - integrity: sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==, - } - dependencies: - "@types/node": 18.11.18 - dev: true - - /@types/mime/3.0.1: - resolution: - { - integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==, - } - dev: true - - /@types/minimatch/3.0.5: - resolution: - { - integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==, - } - dev: true - - /@types/morgan/1.9.4: - resolution: - { - integrity: sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==, - } - dependencies: - "@types/node": 18.11.18 - dev: true - - /@types/multer/1.4.7: - resolution: - { - integrity: sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==, - } - dependencies: - "@types/express": 4.17.15 - dev: true - - /@types/needle/3.2.0: - resolution: - { - integrity: sha512-6XzvzEyJ2ozFNfPajFmqH9JOt0Hp+9TawaYpJT59iIP/zR0U37cfWCRwosyIeEBBZBi021Osq4jGAD3AOju5fg==, - } - dependencies: - "@types/node": 18.11.18 - dev: true - - /@types/node-fetch/2.6.2: - resolution: - { - integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==, - } - dependencies: - "@types/node": 18.11.18 - form-data: 3.0.1 - dev: true - - /@types/node-os-utils/1.3.0: - resolution: - { - integrity: sha512-XwVteWQx/XkfRPyaGkw8dEbrCAkoRZ73pI3XznUYIpzbCfpQB3UnDlR5TnmdhetlT889tUJGF8QWo9xrgTpsiA==, - } - dev: true - - /@types/node/14.18.36: - resolution: - { - integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==, - } - dev: false - - /@types/node/18.11.18: - resolution: - { - integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==, - } - - /@types/notp/2.0.2: - resolution: - { - integrity: sha512-JUcVYN9Tmw0AjoAfvjslS4hbv39fPBbZdftBK3b50g5z/DmhLsu6cd0UOEBiQuMwy2FirshF2Gk9gAvfWjshMw==, - } - dependencies: - "@types/node": 18.11.18 - dev: false - - /@types/probe-image-size/7.2.0: - resolution: - { - integrity: sha512-R5H3vw62gHNHrn+JGZbKejb+Z2D/6E5UNVlhCzIaBBLroMQMOFqy5Pap2gM+ZZHdqBtVU0/cx/M6to+mOJcoew==, - } - dependencies: - "@types/needle": 3.2.0 - "@types/node": 18.11.18 - dev: true - - /@types/qs/6.9.7: - resolution: - { - integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==, - } - dev: true - - /@types/range-parser/1.2.4: - resolution: - { - integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==, - } - dev: true - - /@types/serve-static/1.15.0: - resolution: - { - integrity: sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==, - } - dependencies: - "@types/mime": 3.0.1 - "@types/node": 18.11.18 - dev: true - - /@types/sharp/0.31.1: - resolution: - { - integrity: sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag==, - } - dependencies: - "@types/node": 18.11.18 - dev: true - - /@types/stream-buffers/3.0.4: - resolution: - { - integrity: sha512-qU/K1tb2yUdhXkLIATzsIPwbtX6BpZk0l3dPW6xqWyhfzzM1ECaQ/8faEnu3CNraLiQ9LHyQQPBGp7N9Fbs25w==, - } - dependencies: - "@types/node": 18.11.18 - dev: false - - /@types/ws/8.5.4: - resolution: - { - integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==, - } - dependencies: - "@types/node": 18.11.18 - dev: true - - /@yukikaze-bot/erlpack/1.0.1: - resolution: - { - integrity: sha512-PCJ2lGCf8DsQtrE411PY+NTsolK48l4InNn1kcBo0iUllKZYGLqeqXEWGA/INrmwanKcoYkU4pBySqUFLQDEoA==, - } - requiresBuild: true - dependencies: - "@mapbox/node-pre-gyp": 1.0.10 - node-addon-api: 4.3.0 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - optional: true - - /abbrev/1.1.1: - resolution: - { - integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==, - } - dev: false - - /accepts/1.3.8: - resolution: - { - integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==, - } - engines: { node: ">= 0.6" } - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - - /acorn-walk/8.2.0: - resolution: - { - integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==, - } - engines: { node: ">=0.4.0" } - dev: false - - /acorn/8.8.1: - resolution: - { - integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==, - } - engines: { node: ">=0.4.0" } - hasBin: true - dev: false - - /agent-base/6.0.2: - resolution: - { - integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==, - } - engines: { node: ">= 6.0.0" } - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: false - - /agentkeepalive/4.2.1: - resolution: - { - integrity: sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==, - } - engines: { node: ">= 8.0.0" } - dependencies: - debug: 4.3.4 - depd: 1.1.2 - humanize-ms: 1.2.1 - transitivePeerDependencies: - - supports-color - dev: false - optional: true - - /aggregate-error/3.1.0: - resolution: - { - integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==, - } - engines: { node: ">=8" } - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - dev: false - optional: true - - /ajv-formats/2.1.1_ajv@8.6.2: - resolution: - { - integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==, - } - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.6.2 - dev: false - - /ajv/8.6.2: - resolution: - { - integrity: sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==, - } - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: false - - /amqplib/0.10.3: - resolution: - { - integrity: sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==, - } - engines: { node: ">=10" } - dependencies: - "@acuminous/bitsyntax": 0.1.2 - buffer-more-ints: 1.0.0 - readable-stream: 1.1.14 - url-parse: 1.5.10 - transitivePeerDependencies: - - supports-color - dev: false - - /ansi-regex/5.0.1: - resolution: - { - integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, - } - engines: { node: ">=8" } - dev: false - - /ansi-styles/4.3.0: - resolution: - { - integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, - } - engines: { node: ">=8" } - dependencies: - color-convert: 2.0.1 - - /any-promise/1.3.0: - resolution: - { - integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, - } - dev: false - - /app-root-path/3.1.0: - resolution: - { - integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==, - } - engines: { node: ">= 6.0.0" } - dev: false - - /append-field/1.0.0: - resolution: - { - integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==, - } - dev: false - - /aproba/2.0.0: - resolution: - { - integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==, - } - dev: false - - /are-we-there-yet/2.0.0: - resolution: - { - integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==, - } - engines: { node: ">=10" } - dependencies: - delegates: 1.0.0 - readable-stream: 3.6.0 - dev: false - - /are-we-there-yet/3.0.1: - resolution: - { - integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==, - } - engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } - dependencies: - delegates: 1.0.0 - readable-stream: 3.6.0 - dev: false - optional: true - - /arg/4.1.3: - resolution: - { - integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==, - } - dev: false - - /argparse/1.0.10: - resolution: - { - integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==, - } - dependencies: - sprintf-js: 1.0.3 - dev: false - - /argparse/2.0.1: - resolution: - { - integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, - } - dev: false - - /array-differ/3.0.0: - resolution: - { - integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==, - } - engines: { node: ">=8" } - dev: true - - /array-flatten/1.1.1: - resolution: - { - integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==, - } - - /array-union/2.1.0: - resolution: - { - integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==, - } - engines: { node: ">=8" } - dev: true - - /arrify/2.0.1: - resolution: - { - integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==, - } - engines: { node: ">=8" } - dev: true - - /ast-types/0.13.4: - resolution: - { - integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==, - } - engines: { node: ">=4" } - dependencies: - tslib: 2.4.1 - dev: false - - /asynckit/0.4.0: - resolution: - { - integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, - } - - /balanced-match/1.0.2: - resolution: - { - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, - } - - /base64-js/1.5.1: - resolution: - { - integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, - } - dev: false - - /basic-auth/2.0.1: - resolution: - { - integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==, - } - engines: { node: ">= 0.8" } - dependencies: - safe-buffer: 5.1.2 - dev: false - - /bcrypt/5.1.0: - resolution: - { - integrity: sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==, - } - engines: { node: ">= 10.0.0" } - requiresBuild: true - dependencies: - "@mapbox/node-pre-gyp": 1.0.10 - node-addon-api: 5.0.0 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - - /bignumber.js/9.1.1: - resolution: - { - integrity: sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==, - } - dev: false - - /body-parser/1.20.1: - resolution: - { - integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==, - } - engines: { node: ">= 0.8", npm: 1.2.8000 || >= 1.4.16 } - dependencies: - bytes: 3.1.2 - content-type: 1.0.4 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.1 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - /boolbase/1.0.0: - resolution: - { - integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==, - } - dev: false - - /bowser/2.11.0: - resolution: - { - integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==, - } - dev: false - - /brace-expansion/1.1.11: - resolution: - { - integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, - } - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - /buffer-equal-constant-time/1.0.1: - resolution: - { - integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==, - } - dev: false - - /buffer-from/1.1.2: - resolution: - { - integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, - } - dev: false - - /buffer-more-ints/1.0.0: - resolution: - { - integrity: sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==, - } - dev: false - - /buffer/6.0.3: - resolution: - { - integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==, - } - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: false - - /busboy/1.6.0: - resolution: - { - integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, - } - engines: { node: ">=10.16.0" } - dependencies: - streamsearch: 1.1.0 - dev: false - - /bytes/3.1.2: - resolution: - { - integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==, - } - engines: { node: ">= 0.8" } - - /cacache/15.3.0: - resolution: - { - integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==, - } - engines: { node: ">= 10" } - dependencies: - "@npmcli/fs": 1.1.1 - "@npmcli/move-file": 1.1.2 - chownr: 2.0.0 - fs-minipass: 2.1.0 - glob: 7.2.3 - infer-owner: 1.0.4 - lru-cache: 6.0.0 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - mkdirp: 1.0.4 - p-map: 4.0.0 - promise-inflight: 1.0.1 - rimraf: 3.0.2 - ssri: 8.0.1 - tar: 6.1.13 - unique-filename: 1.1.1 - transitivePeerDependencies: - - bluebird - dev: false - optional: true - - /call-bind/1.0.2: - resolution: - { - integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==, - } - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.1.3 - - /chalk/3.0.0: - resolution: - { - integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==, - } - engines: { node: ">=8" } - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /chalk/4.1.2: - resolution: - { - integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, - } - engines: { node: ">=10" } - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: false - - /cheerio-select/2.1.0: - resolution: - { - integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==, - } - dependencies: - boolbase: 1.0.0 - css-select: 5.1.0 - css-what: 6.1.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.0.1 - dev: false - - /cheerio/1.0.0-rc.12: - resolution: - { - integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==, - } - engines: { node: ">= 6" } - dependencies: - cheerio-select: 2.1.0 - dom-serializer: 2.0.0 - domhandler: 5.0.3 - domutils: 3.0.1 - htmlparser2: 8.0.1 - parse5: 7.1.2 - parse5-htmlparser2-tree-adapter: 7.0.0 - dev: false - - /chownr/2.0.0: - resolution: - { - integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==, - } - engines: { node: ">=10" } - dev: false - - /clean-stack/2.2.0: - resolution: - { - integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==, - } - engines: { node: ">=6" } - dev: false - optional: true - - /cli-highlight/2.1.11: - resolution: - { - integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==, - } - engines: { node: ">=8.0.0", npm: ">=5.0.0" } - hasBin: true - dependencies: - chalk: 4.1.2 - highlight.js: 10.7.3 - mz: 2.7.0 - parse5: 5.1.1 - parse5-htmlparser2-tree-adapter: 6.0.1 - yargs: 16.2.0 - dev: false - - /cliui/7.0.4: - resolution: - { - integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==, - } - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: false - - /cliui/8.0.1: - resolution: - { - integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, - } - engines: { node: ">=12" } - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: false - - /color-convert/2.0.1: - resolution: - { - integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, - } - engines: { node: ">=7.0.0" } - dependencies: - color-name: 1.1.4 - - /color-name/1.1.4: - resolution: - { - integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, - } - - /color-support/1.1.3: - resolution: - { - integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==, - } - hasBin: true - dev: false - - /combined-stream/1.0.8: - resolution: - { - integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, - } - engines: { node: ">= 0.8" } - dependencies: - delayed-stream: 1.0.0 - - /concat-map/0.0.1: - resolution: - { - integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, - } - - /concat-stream/1.6.2: - resolution: - { - integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==, - } - engines: { "0": node >= 0.8 } - dependencies: - buffer-from: 1.1.2 - inherits: 2.0.4 - readable-stream: 2.3.7 - typedarray: 0.0.6 - dev: false - - /console-control-strings/1.1.0: - resolution: - { - integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==, - } - dev: false - - /content-disposition/0.5.4: - resolution: - { - integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==, - } - engines: { node: ">= 0.6" } - dependencies: - safe-buffer: 5.2.1 - - /content-type/1.0.4: - resolution: - { - integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==, - } - engines: { node: ">= 0.6" } - - /cookie-parser/1.4.6: - resolution: - { - integrity: sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==, - } - engines: { node: ">= 0.8.0" } - dependencies: - cookie: 0.4.1 - cookie-signature: 1.0.6 - dev: false - - /cookie-signature/1.0.6: - resolution: - { - integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==, - } - - /cookie/0.4.1: - resolution: - { - integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==, - } - engines: { node: ">= 0.6" } - dev: false - - /cookie/0.4.2: - resolution: - { - integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==, - } - engines: { node: ">= 0.6" } - dev: false - - /cookie/0.5.0: - resolution: - { - integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==, - } - engines: { node: ">= 0.6" } - - /core-util-is/1.0.3: - resolution: - { - integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, - } - dev: false - - /create-require/1.1.1: - resolution: - { - integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==, - } - dev: false - - /cross-spawn/7.0.3: - resolution: - { - integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==, - } - engines: { node: ">= 8" } - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /css-select/5.1.0: - resolution: - { - integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==, - } - dependencies: - boolbase: 1.0.0 - css-what: 6.1.0 - domhandler: 5.0.3 - domutils: 3.0.1 - nth-check: 2.1.1 - dev: false - - /css-what/6.1.0: - resolution: - { - integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==, - } - engines: { node: ">= 6" } - dev: false - - /data-uri-to-buffer/3.0.1: - resolution: - { - integrity: sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==, - } - engines: { node: ">= 6" } - dev: false - - /date-fns/2.29.3: - resolution: - { - integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==, - } - engines: { node: ">=0.11" } - dev: false - - /debug/2.6.9: - resolution: - { - integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==, - } - peerDependencies: - supports-color: "*" - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.0.0 - - /debug/3.2.7: - resolution: - { - integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, - } - peerDependencies: - supports-color: "*" - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: false - - /debug/4.3.4: - resolution: - { - integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, - } - engines: { node: ">=6.0" } - peerDependencies: - supports-color: "*" - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: false - - /deep-is/0.1.4: - resolution: - { - integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, - } - dev: false - - /degenerator/3.0.2: - resolution: - { - integrity: sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==, - } - engines: { node: ">= 6" } - dependencies: - ast-types: 0.13.4 - escodegen: 1.14.3 - esprima: 4.0.1 - vm2: 3.9.13 - dev: false - - /delayed-stream/1.0.0: - resolution: - { - integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, - } - engines: { node: ">=0.4.0" } - - /delegates/1.0.0: - resolution: - { - integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==, - } - dev: false - - /depd/1.1.2: - resolution: - { - integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==, - } - engines: { node: ">= 0.6" } - dev: false - optional: true - - /depd/2.0.0: - resolution: - { - integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==, - } - engines: { node: ">= 0.8" } - - /destroy/1.2.0: - resolution: - { - integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==, - } - engines: { node: ">= 0.8", npm: 1.2.8000 || >= 1.4.16 } - - /detect-libc/2.0.1: - resolution: - { - integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==, - } - engines: { node: ">=8" } - dev: false - - /diff/4.0.2: - resolution: - { - integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==, - } - engines: { node: ">=0.3.1" } - dev: false - - /dom-serializer/2.0.0: - resolution: - { - integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==, - } - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.4.0 - dev: false - - /domelementtype/2.3.0: - resolution: - { - integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, - } - dev: false - - /domhandler/5.0.3: - resolution: - { - integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==, - } - engines: { node: ">= 4" } - dependencies: - domelementtype: 2.3.0 - dev: false - - /domutils/3.0.1: - resolution: - { - integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==, - } - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - dev: false - - /dotenv/16.0.3: - resolution: - { - integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==, - } - engines: { node: ">=12" } - dev: false - - /ecdsa-sig-formatter/1.0.11: - resolution: - { - integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==, - } - dependencies: - safe-buffer: 5.2.1 - dev: false - - /ee-first/1.1.1: - resolution: - { - integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==, - } - - /emoji-regex/8.0.0: - resolution: - { - integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, - } - dev: false - - /encodeurl/1.0.2: - resolution: - { - integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==, - } - engines: { node: ">= 0.8" } - - /encoding/0.1.13: - resolution: - { - integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==, - } - requiresBuild: true - dependencies: - iconv-lite: 0.6.3 - dev: false - optional: true - - /end-of-stream/1.4.4: - resolution: - { - integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, - } - dependencies: - once: 1.4.0 - dev: true - - /entities/4.4.0: - resolution: - { - integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==, - } - engines: { node: ">=0.12" } - dev: false - - /env-paths/2.2.1: - resolution: - { - integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==, - } - engines: { node: ">=6" } - dev: false - optional: true - - /err-code/2.0.3: - resolution: - { - integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==, - } - dev: false - optional: true - - /escalade/3.1.1: - resolution: - { - integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==, - } - engines: { node: ">=6" } - dev: false - - /escape-html/1.0.3: - resolution: - { - integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, - } - - /escodegen/1.14.3: - resolution: - { - integrity: sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==, - } - engines: { node: ">=4.0" } - hasBin: true - dependencies: - esprima: 4.0.1 - estraverse: 4.3.0 - esutils: 2.0.3 - optionator: 0.8.3 - optionalDependencies: - source-map: 0.6.1 - dev: false - - /esprima/4.0.1: - resolution: - { - integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==, - } - engines: { node: ">=4" } - hasBin: true - dev: false - - /estraverse/4.3.0: - resolution: - { - integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==, - } - engines: { node: ">=4.0" } - dev: false - - /esutils/2.0.3: - resolution: - { - integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, - } - engines: { node: ">=0.10.0" } - dev: false - - /etag/1.8.1: - resolution: - { - integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==, - } - engines: { node: ">= 0.6" } - - /execa/4.1.0: - resolution: - { - integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==, - } - engines: { node: ">=10" } - dependencies: - cross-spawn: 7.0.3 - get-stream: 5.2.0 - human-signals: 1.1.1 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - dev: true - - /exif-be-gone/1.3.2: - resolution: - { - integrity: sha512-jVkZWBJNw1SrAzrZ99/ePYx6FqfN6t/+y1xnCAnV5wCcASLBr548OvABfp1WSZGffz31+6DNy0W4ZZSBjs6dJw==, - } - hasBin: true - dependencies: - "@types/stream-buffers": 3.0.4 - dev: false - - /express-async-errors/3.1.1_express@4.18.2: - resolution: - { - integrity: sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==, - } - peerDependencies: - express: ^4.16.2 - dependencies: - express: 4.18.2 - dev: false - - /express/4.18.2: - resolution: - { - integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==, - } - engines: { node: ">= 0.10.0" } - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.1 - content-disposition: 0.5.4 - content-type: 1.0.4 - cookie: 0.5.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.2.0 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.7 - qs: 6.11.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - /fast-deep-equal/3.1.3: - resolution: - { - integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, - } - dev: false - - /fast-levenshtein/2.0.6: - resolution: - { - integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, - } - dev: false - - /fast-xml-parser/4.0.11: - resolution: - { - integrity: sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==, - } - hasBin: true - dependencies: - strnum: 1.0.5 - dev: false - - /fast-zlib/2.0.1: - resolution: - { - integrity: sha512-DCoYgNagM2Bt1VIpXpdGnRx4LzqJeYG0oh6Nf/7cWo6elTXkFGMw9CrRCYYUIapYNrozYMoyDRflx9mgT3Awyw==, - } - dev: false - - /file-type/16.5.4: - resolution: - { - integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==, - } - engines: { node: ">=10" } - dependencies: - readable-web-to-node-stream: 3.0.2 - strtok3: 6.3.0 - token-types: 4.2.1 - dev: false - - /file-uri-to-path/2.0.0: - resolution: - { - integrity: sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==, - } - engines: { node: ">= 6" } - dev: false - - /finalhandler/1.2.0: - resolution: - { - integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==, - } - engines: { node: ">= 0.8" } - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - /find-up/4.1.0: - resolution: - { - integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==, - } - engines: { node: ">=8" } - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - dev: true - - /form-data/3.0.1: - resolution: - { - integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==, - } - engines: { node: ">= 6" } - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: true - - /form-data/4.0.0: - resolution: - { - integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==, - } - engines: { node: ">= 6" } - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: false - - /forwarded/0.2.0: - resolution: - { - integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==, - } - engines: { node: ">= 0.6" } - - /fresh/0.5.2: - resolution: - { - integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==, - } - engines: { node: ">= 0.6" } - - /fs-extra/8.1.0: - resolution: - { - integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==, - } - engines: { node: ">=6 <7 || >=8" } - dependencies: - graceful-fs: 4.2.10 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: false - - /fs-minipass/2.1.0: - resolution: - { - integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==, - } - engines: { node: ">= 8" } - dependencies: - minipass: 3.3.6 - dev: false - - /fs.realpath/1.0.0: - resolution: - { - integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, - } - dev: false - - /ftp/0.3.10: - resolution: - { - integrity: sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==, - } - engines: { node: ">=0.8.0" } - dependencies: - readable-stream: 1.1.14 - xregexp: 2.0.0 - dev: false - - /function-bind/1.1.1: - resolution: - { - integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==, - } - - /gauge/3.0.2: - resolution: - { - integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==, - } - engines: { node: ">=10" } - dependencies: - aproba: 2.0.0 - color-support: 1.1.3 - console-control-strings: 1.1.0 - has-unicode: 2.0.1 - object-assign: 4.1.1 - signal-exit: 3.0.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wide-align: 1.1.5 - dev: false - - /gauge/4.0.4: - resolution: - { - integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==, - } - engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } - dependencies: - aproba: 2.0.0 - color-support: 1.1.3 - console-control-strings: 1.1.0 - has-unicode: 2.0.1 - signal-exit: 3.0.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wide-align: 1.1.5 - dev: false - optional: true - - /get-caller-file/2.0.5: - resolution: - { - integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, - } - engines: { node: 6.* || 8.* || >= 10.* } - dev: false - - /get-intrinsic/1.1.3: - resolution: - { - integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==, - } - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-symbols: 1.0.3 - - /get-stream/5.2.0: - resolution: - { - integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==, - } - engines: { node: ">=8" } - dependencies: - pump: 3.0.0 - dev: true - - /get-uri/3.0.2: - resolution: - { - integrity: sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==, - } - engines: { node: ">= 6" } - dependencies: - "@tootallnate/once": 1.1.2 - data-uri-to-buffer: 3.0.1 - debug: 4.3.4 - file-uri-to-path: 2.0.0 - fs-extra: 8.1.0 - ftp: 0.3.10 - transitivePeerDependencies: - - supports-color - dev: false - - /glob/7.2.3: - resolution: - { - integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, - } - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: false - - /graceful-fs/4.2.10: - resolution: - { - integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==, - } - dev: false - - /has-flag/4.0.0: - resolution: - { - integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, - } - engines: { node: ">=8" } - - /has-symbols/1.0.3: - resolution: - { - integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==, - } - engines: { node: ">= 0.4" } - - /has-unicode/2.0.1: - resolution: - { - integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==, - } - dev: false - - /has/1.0.3: - resolution: - { - integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==, - } - engines: { node: ">= 0.4.0" } - dependencies: - function-bind: 1.1.1 - - /helmet/4.6.0: - resolution: - { - integrity: sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==, - } - engines: { node: ">=10.0.0" } - dev: false - - /highlight.js/10.7.3: - resolution: - { - integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==, - } - dev: false - - /htmlparser2/8.0.1: - resolution: - { - integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==, - } - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.0.1 - entities: 4.4.0 - dev: false - - /http-cache-semantics/4.1.0: - resolution: - { - integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==, - } - dev: false - optional: true - - /http-errors/2.0.0: - resolution: - { - integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==, - } - engines: { node: ">= 0.8" } - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - /http-proxy-agent/4.0.1: - resolution: - { - integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==, - } - engines: { node: ">= 6" } - dependencies: - "@tootallnate/once": 1.1.2 - agent-base: 6.0.2 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: false - - /https-proxy-agent/5.0.1: - resolution: - { - integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==, - } - engines: { node: ">= 6" } - dependencies: - agent-base: 6.0.2 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: false - - /human-signals/1.1.1: - resolution: - { - integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==, - } - engines: { node: ">=8.12.0" } - dev: true - - /humanize-ms/1.2.1: - resolution: - { - integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==, - } - dependencies: - ms: 2.1.3 - dev: false - optional: true - - /husky/8.0.3: - resolution: - { - integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==, - } - engines: { node: ">=14" } - hasBin: true - dev: true - - /i18next-http-middleware/3.2.1: - resolution: - { - integrity: sha512-zBwXxDChT0YLoTXIR6jRuqnUUhXW0Iw7egoTnNXyaDRtTbfWNXwU0a53ThyuRPQ+k+tXu3ZMNKRzfLuononaRw==, - } - dev: false - - /i18next-node-fs-backend/2.1.3: - resolution: - { - integrity: sha512-CreMFiVl3ChlMc5ys/e0QfuLFOZyFcL40Jj6jaKD6DxZ/GCUMxPI9BpU43QMWUgC7r+PClpxg2cGXAl0CjG04g==, - } - deprecated: replaced by i18next-fs-backend - dependencies: - js-yaml: 3.13.1 - json5: 2.0.0 - dev: false - - /i18next/21.10.0: - resolution: - { - integrity: sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==, - } - dependencies: - "@babel/runtime": 7.20.7 - - /iconv-lite/0.4.24: - resolution: - { - integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==, - } - engines: { node: ">=0.10.0" } - dependencies: - safer-buffer: 2.1.2 - - /iconv-lite/0.6.3: - resolution: - { - integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==, - } - engines: { node: ">=0.10.0" } - dependencies: - safer-buffer: 2.1.2 - dev: false - optional: true - - /ieee754/1.2.1: - resolution: - { - integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, - } - dev: false - - /ignore/5.2.4: - resolution: - { - integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==, - } - engines: { node: ">= 4" } - dev: true - - /image-size/1.0.2: - resolution: - { - integrity: sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==, - } - engines: { node: ">=14.0.0" } - hasBin: true - dependencies: - queue: 6.0.2 - dev: false - - /immediate/3.0.6: - resolution: - { - integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==, - } - dev: false - - /imurmurhash/0.1.4: - resolution: - { - integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, - } - engines: { node: ">=0.8.19" } - dev: false - optional: true - - /indent-string/4.0.0: - resolution: - { - integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, - } - engines: { node: ">=8" } - dev: false - optional: true - - /infer-owner/1.0.4: - resolution: - { - integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==, - } - dev: false - optional: true - - /inflight/1.0.6: - resolution: - { - integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, - } - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: false - - /inherits/2.0.4: - resolution: - { - integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, - } - - /ip/1.1.8: - resolution: - { - integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==, - } - dev: false - - /ip/2.0.0: - resolution: - { - integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==, - } - dev: false - - /ipaddr.js/1.9.1: - resolution: - { - integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==, - } - engines: { node: ">= 0.10" } - - /is-fullwidth-code-point/3.0.0: - resolution: - { - integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, - } - engines: { node: ">=8" } - dev: false - - /is-lambda/1.0.1: - resolution: - { - integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==, - } - dev: false - optional: true - - /is-stream/2.0.1: - resolution: - { - integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, - } - engines: { node: ">=8" } - dev: true - - /isarray/0.0.1: - resolution: - { - integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==, - } - dev: false - - /isarray/1.0.0: - resolution: - { - integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, - } - dev: false - - /isexe/2.0.0: - resolution: - { - integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, - } - - /js-yaml/3.13.1: - resolution: - { - integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==, - } - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: false - - /js-yaml/4.1.0: - resolution: - { - integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, - } - hasBin: true - dependencies: - argparse: 2.0.1 - dev: false - - /json-bigint/1.0.0: - resolution: - { - integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==, - } - dependencies: - bignumber.js: 9.1.1 - dev: false - - /json-schema-traverse/1.0.0: - resolution: - { - integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, - } - dev: false - - /json-stable-stringify/1.0.2: - resolution: - { - integrity: sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==, - } - dependencies: - jsonify: 0.0.1 - dev: false - - /json5/2.0.0: - resolution: - { - integrity: sha512-0EdQvHuLm7yJ7lyG5dp7Q3X2ku++BG5ZHaJ5FTnaXpKqDrw4pMxel5Bt3oAYMthnrthFBdnZ1FcsXTPyrQlV0w==, - } - engines: { node: ">=6" } - hasBin: true - dependencies: - minimist: 1.2.7 - dev: false - - /jsonfile/4.0.0: - resolution: - { - integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==, - } - optionalDependencies: - graceful-fs: 4.2.10 - dev: false - - /jsonify/0.0.1: - resolution: - { - integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==, - } - dev: false - - /jsonwebtoken/8.5.1: - resolution: - { - integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==, - } - engines: { node: ">=4", npm: ">=1.4.28" } - dependencies: - jws: 3.2.2 - lodash.includes: 4.3.0 - lodash.isboolean: 3.0.3 - lodash.isinteger: 4.0.4 - lodash.isnumber: 3.0.3 - lodash.isplainobject: 4.0.6 - lodash.isstring: 4.0.1 - lodash.once: 4.1.1 - ms: 2.1.3 - semver: 5.7.1 - dev: false - - /jwa/1.4.1: - resolution: - { - integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==, - } - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - dev: false - - /jws/3.2.2: - resolution: - { - integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==, - } - dependencies: - jwa: 1.4.1 - safe-buffer: 5.2.1 - dev: false - - /lambert-server/1.2.12: - resolution: - { - integrity: sha512-TY6k60KLVfBpPrl9lcrN54RJdTBg9f8JqJPoHg5d/FMLnnwwQtT4budpoQjyLDwBLhS+zpXo0aBCwnnGgTVGaw==, - } - dependencies: - body-parser: 1.20.1 - chalk: 4.1.2 - express: 4.18.2 - express-async-errors: 3.1.1_express@4.18.2 - helmet: 4.6.0 - missing-native-js-functions: 1.3.1 - transitivePeerDependencies: - - supports-color - dev: false - - /levn/0.3.0: - resolution: - { - integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==, - } - engines: { node: ">= 0.8.0" } - dependencies: - prelude-ls: 1.1.2 - type-check: 0.3.2 - dev: false - - /lie/3.1.1: - resolution: - { - integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==, - } - dependencies: - immediate: 3.0.6 - dev: false - - /localforage/1.10.0: - resolution: - { - integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==, - } - dependencies: - lie: 3.1.1 - dev: false - - /locate-path/5.0.0: - resolution: - { - integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==, - } - engines: { node: ">=8" } - dependencies: - p-locate: 4.1.0 - dev: true - - /lodash.includes/4.3.0: - resolution: - { - integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==, - } - dev: false - - /lodash.isboolean/3.0.3: - resolution: - { - integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==, - } - dev: false - - /lodash.isinteger/4.0.4: - resolution: - { - integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==, - } - dev: false - - /lodash.isnumber/3.0.3: - resolution: - { - integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==, - } - dev: false - - /lodash.isplainobject/4.0.6: - resolution: - { - integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==, - } - dev: false - - /lodash.isstring/4.0.1: - resolution: - { - integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==, - } - dev: false - - /lodash.merge/4.6.2: - resolution: - { - integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, - } - dev: false - - /lodash.once/4.1.1: - resolution: - { - integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==, - } - dev: false - - /lru-cache/5.1.1: - resolution: - { - integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, - } - dependencies: - yallist: 3.1.1 - dev: false - - /lru-cache/6.0.0: - resolution: - { - integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, - } - engines: { node: ">=10" } - dependencies: - yallist: 4.0.0 - dev: false - - /lru_map/0.3.3: - resolution: - { - integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==, - } - dev: false - - /make-dir/3.1.0: - resolution: - { - integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==, - } - engines: { node: ">=8" } - dependencies: - semver: 6.3.0 - dev: false - - /make-error/1.3.6: - resolution: - { - integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==, - } - dev: false - - /make-fetch-happen/9.1.0: - resolution: - { - integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==, - } - engines: { node: ">= 10" } - dependencies: - agentkeepalive: 4.2.1 - cacache: 15.3.0 - http-cache-semantics: 4.1.0 - http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 - is-lambda: 1.0.1 - lru-cache: 6.0.0 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-fetch: 1.4.1 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - negotiator: 0.6.3 - promise-retry: 2.0.1 - socks-proxy-agent: 6.2.1 - ssri: 8.0.1 - transitivePeerDependencies: - - bluebird - - supports-color - dev: false - optional: true - - /media-typer/0.3.0: - resolution: - { - integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==, - } - engines: { node: ">= 0.6" } - - /merge-descriptors/1.0.1: - resolution: - { - integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==, - } - - /merge-stream/2.0.0: - resolution: - { - integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, - } - dev: true - - /methods/1.1.2: - resolution: - { - integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==, - } - engines: { node: ">= 0.6" } - - /mime-db/1.52.0: - resolution: - { - integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, - } - engines: { node: ">= 0.6" } - - /mime-types/2.1.35: - resolution: - { - integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, - } - engines: { node: ">= 0.6" } - dependencies: - mime-db: 1.52.0 - - /mime/1.6.0: - resolution: - { - integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==, - } - engines: { node: ">=4" } - hasBin: true - - /mimic-fn/2.1.0: - resolution: - { - integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, - } - engines: { node: ">=6" } - dev: true - - /minimatch/3.1.2: - resolution: - { - integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, - } - dependencies: - brace-expansion: 1.1.11 - - /minimist/1.2.7: - resolution: - { - integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==, - } - dev: false - - /minipass-collect/1.0.2: - resolution: - { - integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==, - } - engines: { node: ">= 8" } - dependencies: - minipass: 3.3.6 - dev: false - optional: true - - /minipass-fetch/1.4.1: - resolution: - { - integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==, - } - engines: { node: ">=8" } - dependencies: - minipass: 3.3.6 - minipass-sized: 1.0.3 - minizlib: 2.1.2 - optionalDependencies: - encoding: 0.1.13 - dev: false - optional: true - - /minipass-flush/1.0.5: - resolution: - { - integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==, - } - engines: { node: ">= 8" } - dependencies: - minipass: 3.3.6 - dev: false - optional: true - - /minipass-pipeline/1.2.4: - resolution: - { - integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==, - } - engines: { node: ">=8" } - dependencies: - minipass: 3.3.6 - dev: false - optional: true - - /minipass-sized/1.0.3: - resolution: - { - integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==, - } - engines: { node: ">=8" } - dependencies: - minipass: 3.3.6 - dev: false - optional: true - - /minipass/3.3.6: - resolution: - { - integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==, - } - engines: { node: ">=8" } - dependencies: - yallist: 4.0.0 - dev: false - - /minipass/4.0.0: - resolution: - { - integrity: sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==, - } - engines: { node: ">=8" } - dependencies: - yallist: 4.0.0 - dev: false - - /minizlib/2.1.2: - resolution: - { - integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==, - } - engines: { node: ">= 8" } - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - dev: false - - /missing-native-js-functions/1.3.1: - resolution: - { - integrity: sha512-+27YZhfXCDOwUVZ7qdtJzLWAaA8qYBt6jPrUuF91SpBYUOBLvKr+MgvhlJuNMVhjzNX0245p2zvYYSx9QpuLZQ==, - } - dev: false - - /mkdirp/0.5.6: - resolution: - { - integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==, - } - hasBin: true - dependencies: - minimist: 1.2.7 - dev: false - - /mkdirp/1.0.4: - resolution: - { - integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==, - } - engines: { node: ">=10" } - hasBin: true - dev: false - - /module-alias/2.2.2: - resolution: - { - integrity: sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==, - } - dev: false - - /morgan/1.10.0: - resolution: - { - integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==, - } - engines: { node: ">= 0.8.0" } - dependencies: - basic-auth: 2.0.1 - debug: 2.6.9 - depd: 2.0.0 - on-finished: 2.3.0 - on-headers: 1.0.2 - transitivePeerDependencies: - - supports-color - dev: false - - /mri/1.2.0: - resolution: - { - integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==, - } - engines: { node: ">=4" } - dev: true - - /ms/2.0.0: - resolution: - { - integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==, - } - - /ms/2.1.2: - resolution: - { - integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, - } - dev: false - - /ms/2.1.3: - resolution: - { - integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, - } - - /multer/1.4.5-lts.1: - resolution: - { - integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==, - } - engines: { node: ">= 6.0.0" } - dependencies: - append-field: 1.0.0 - busboy: 1.6.0 - concat-stream: 1.6.2 - mkdirp: 0.5.6 - object-assign: 4.1.1 - type-is: 1.6.18 - xtend: 4.0.2 - dev: false - - /multimatch/4.0.0: - resolution: - { - integrity: sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==, - } - engines: { node: ">=8" } - dependencies: - "@types/minimatch": 3.0.5 - array-differ: 3.0.0 - array-union: 2.1.0 - arrify: 2.0.1 - minimatch: 3.1.2 - dev: true - - /mz/2.7.0: - resolution: - { - integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, - } - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - dev: false - - /needle/2.9.1: - resolution: - { - integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==, - } - engines: { node: ">= 4.4.x" } - hasBin: true - dependencies: - debug: 3.2.7 - iconv-lite: 0.4.24 - sax: 1.2.4 - transitivePeerDependencies: - - supports-color - dev: false - - /negotiator/0.6.3: - resolution: - { - integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==, - } - engines: { node: ">= 0.6" } - - /netmask/2.0.2: - resolution: - { - integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==, - } - engines: { node: ">= 0.4.0" } - dev: false - - /node-2fa/2.0.3: - resolution: - { - integrity: sha512-PQldrOhjuoZyoydMvMSctllPN1ZPZ1/NwkEcgYwY9faVqE/OymxR+3awPpbWZxm6acLKqvmNqQmdqTsqYyflFw==, - } - dependencies: - "@types/notp": 2.0.2 - notp: 2.0.3 - thirty-two: 1.0.2 - tslib: 2.4.1 - dev: false - - /node-addon-api/4.3.0: - resolution: - { - integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==, - } - dev: false - - /node-addon-api/5.0.0: - resolution: - { - integrity: sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==, - } - dev: false - - /node-fetch/2.6.7: - resolution: - { - integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==, - } - engines: { node: 4.x || >=6.0.0 } - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: false - - /node-gyp/8.4.1: - resolution: - { - integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==, - } - engines: { node: ">= 10.12.0" } - hasBin: true - requiresBuild: true - dependencies: - env-paths: 2.2.1 - glob: 7.2.3 - graceful-fs: 4.2.10 - make-fetch-happen: 9.1.0 - nopt: 5.0.0 - npmlog: 6.0.2 - rimraf: 3.0.2 - semver: 7.3.8 - tar: 6.1.13 - which: 2.0.2 - transitivePeerDependencies: - - bluebird - - supports-color - dev: false - optional: true - - /node-os-utils/1.3.7: - resolution: - { - integrity: sha512-fvnX9tZbR7WfCG5BAy3yO/nCLyjVWD6MghEq0z5FDfN+ZXpLWNITBdbifxQkQ25ebr16G0N7eRWJisOcMEHG3Q==, - } - dev: false - - /nopt/5.0.0: - resolution: - { - integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==, - } - engines: { node: ">=6" } - hasBin: true - dependencies: - abbrev: 1.1.1 - dev: false - - /notp/2.0.3: - resolution: - { - integrity: sha512-oBig/2uqkjQ5AkBuw4QJYwkEWa/q+zHxI5/I5z6IeP2NT0alpJFsP/trrfCC+9xOAgQSZXssNi962kp5KBmypQ==, - } - engines: { node: "> v0.6.0" } - dev: false - - /npm-run-path/4.0.1: - resolution: - { - integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==, - } - engines: { node: ">=8" } - dependencies: - path-key: 3.1.1 - dev: true - - /npmlog/5.0.1: - resolution: - { - integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==, - } - dependencies: - are-we-there-yet: 2.0.0 - console-control-strings: 1.1.0 - gauge: 3.0.2 - set-blocking: 2.0.0 - dev: false - - /npmlog/6.0.2: - resolution: - { - integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==, - } - engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } - dependencies: - are-we-there-yet: 3.0.1 - console-control-strings: 1.1.0 - gauge: 4.0.4 - set-blocking: 2.0.0 - dev: false - optional: true - - /nth-check/2.1.1: - resolution: - { - integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==, - } - dependencies: - boolbase: 1.0.0 - dev: false - - /object-assign/4.1.1: - resolution: - { - integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, - } - engines: { node: ">=0.10.0" } - dev: false - - /object-inspect/1.12.2: - resolution: - { - integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==, - } - - /on-finished/2.3.0: - resolution: - { - integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==, - } - engines: { node: ">= 0.8" } - dependencies: - ee-first: 1.1.1 - dev: false - - /on-finished/2.4.1: - resolution: - { - integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==, - } - engines: { node: ">= 0.8" } - dependencies: - ee-first: 1.1.1 - - /on-headers/1.0.2: - resolution: - { - integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==, - } - engines: { node: ">= 0.8" } - dev: false - - /once/1.4.0: - resolution: - { - integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, - } - dependencies: - wrappy: 1.0.2 - - /onetime/5.1.2: - resolution: - { - integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, - } - engines: { node: ">=6" } - dependencies: - mimic-fn: 2.1.0 - dev: true - - /optionator/0.8.3: - resolution: - { - integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==, - } - engines: { node: ">= 0.8.0" } - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.3.0 - prelude-ls: 1.1.2 - type-check: 0.3.2 - word-wrap: 1.2.3 - dev: false - - /p-limit/2.3.0: - resolution: - { - integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==, - } - engines: { node: ">=6" } - dependencies: - p-try: 2.2.0 - dev: true - - /p-locate/4.1.0: - resolution: - { - integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==, - } - engines: { node: ">=8" } - dependencies: - p-limit: 2.3.0 - dev: true - - /p-map/4.0.0: - resolution: - { - integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==, - } - engines: { node: ">=10" } - dependencies: - aggregate-error: 3.1.0 - dev: false - optional: true - - /p-try/2.2.0: - resolution: - { - integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==, - } - engines: { node: ">=6" } - dev: true - - /pac-proxy-agent/5.0.0: - resolution: - { - integrity: sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==, - } - engines: { node: ">= 8" } - dependencies: - "@tootallnate/once": 1.1.2 - agent-base: 6.0.2 - debug: 4.3.4 - get-uri: 3.0.2 - http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 - pac-resolver: 5.0.1 - raw-body: 2.5.1 - socks-proxy-agent: 5.0.1 - transitivePeerDependencies: - - supports-color - dev: false - - /pac-resolver/5.0.1: - resolution: - { - integrity: sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==, - } - engines: { node: ">= 8" } - dependencies: - degenerator: 3.0.2 - ip: 1.1.8 - netmask: 2.0.2 - dev: false - - /parse5-htmlparser2-tree-adapter/6.0.1: - resolution: - { - integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==, - } - dependencies: - parse5: 6.0.1 - dev: false - - /parse5-htmlparser2-tree-adapter/7.0.0: - resolution: - { - integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==, - } - dependencies: - domhandler: 5.0.3 - parse5: 7.1.2 - dev: false - - /parse5/5.1.1: - resolution: - { - integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==, - } - dev: false - - /parse5/6.0.1: - resolution: - { - integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==, - } - dev: false - - /parse5/7.1.2: - resolution: - { - integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==, - } - dependencies: - entities: 4.4.0 - dev: false - - /parseurl/1.3.3: - resolution: - { - integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==, - } - engines: { node: ">= 0.8" } - - /path-exists/4.0.0: - resolution: - { - integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, - } - engines: { node: ">=8" } - dev: true - - /path-is-absolute/1.0.1: - resolution: - { - integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, - } - engines: { node: ">=0.10.0" } - dev: false - - /path-key/3.1.1: - resolution: - { - integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, - } - engines: { node: ">=8" } - dev: true - - /path-to-regexp/0.1.7: - resolution: - { - integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==, - } - - /peek-readable/4.1.0: - resolution: - { - integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==, - } - engines: { node: ">=8" } - dev: false - - /picocolors/1.0.0: - resolution: - { - integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, - } - dev: false - - /prelude-ls/1.1.2: - resolution: - { - integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==, - } - engines: { node: ">= 0.8.0" } - dev: false - - /prettier/2.8.2: - resolution: - { - integrity: sha512-BtRV9BcncDyI2tsuS19zzhzoxD8Dh8LiCx7j7tHzrkz8GFXAexeWFdi22mjE1d16dftH2qNaytVxqiRTGlMfpw==, - } - engines: { node: ">=10.13.0" } - hasBin: true - dev: true - - /pretty-quick/3.1.3_prettier@2.8.2: - resolution: - { - integrity: sha512-kOCi2FJabvuh1as9enxYmrnBC6tVMoVOenMaBqRfsvBHB0cbpYHjdQEpSglpASDFEXVwplpcGR4CLEaisYAFcA==, - } - engines: { node: ">=10.13" } - hasBin: true - peerDependencies: - prettier: ">=2.0.0" - dependencies: - chalk: 3.0.0 - execa: 4.1.0 - find-up: 4.1.0 - ignore: 5.2.4 - mri: 1.2.0 - multimatch: 4.0.0 - prettier: 2.8.2 - dev: true - - /probe-image-size/7.2.3: - resolution: - { - integrity: sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==, - } - dependencies: - lodash.merge: 4.6.2 - needle: 2.9.1 - stream-parser: 0.3.1 - transitivePeerDependencies: - - supports-color - dev: false - - /process-nextick-args/2.0.1: - resolution: - { - integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, - } - dev: false - - /promise-inflight/1.0.1: - resolution: - { - integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==, - } - peerDependencies: - bluebird: "*" - peerDependenciesMeta: - bluebird: - optional: true - dev: false - optional: true - - /promise-retry/2.0.1: - resolution: - { - integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==, - } - engines: { node: ">=10" } - dependencies: - err-code: 2.0.3 - retry: 0.12.0 - dev: false - optional: true - - /proxy-addr/2.0.7: - resolution: - { - integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==, - } - engines: { node: ">= 0.10" } - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - /proxy-agent/5.0.0: - resolution: - { - integrity: sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==, - } - engines: { node: ">= 8" } - dependencies: - agent-base: 6.0.2 - debug: 4.3.4 - http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 - lru-cache: 5.1.1 - pac-proxy-agent: 5.0.0 - proxy-from-env: 1.1.0 - socks-proxy-agent: 5.0.1 - transitivePeerDependencies: - - supports-color - dev: false - - /proxy-from-env/1.1.0: - resolution: - { - integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, - } - dev: false - - /pump/3.0.0: - resolution: - { - integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==, - } - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - dev: true - - /punycode/2.2.0: - resolution: - { - integrity: sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==, - } - engines: { node: ">=6" } - dev: false - - /qs/6.11.0: - resolution: - { - integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==, - } - engines: { node: ">=0.6" } - dependencies: - side-channel: 1.0.4 - - /querystringify/2.2.0: - resolution: - { - integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==, - } - dev: false - - /queue/6.0.2: - resolution: - { - integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==, - } - dependencies: - inherits: 2.0.4 - dev: false - - /range-parser/1.2.1: - resolution: - { - integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==, - } - engines: { node: ">= 0.6" } - - /raw-body/2.5.1: - resolution: - { - integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==, - } - engines: { node: ">= 0.8" } - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - - /readable-stream/1.1.14: - resolution: - { - integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==, - } - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 0.0.1 - string_decoder: 0.10.31 - dev: false - - /readable-stream/2.3.7: - resolution: - { - integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==, - } - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - dev: false - - /readable-stream/3.6.0: - resolution: - { - integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==, - } - engines: { node: ">= 6" } - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - dev: false - - /readable-web-to-node-stream/3.0.2: - resolution: - { - integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==, - } - engines: { node: ">=8" } - dependencies: - readable-stream: 3.6.0 - dev: false - - /reflect-metadata/0.1.13: - resolution: - { - integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==, - } - dev: false - - /regenerator-runtime/0.13.11: - resolution: - { - integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==, - } - - /require-directory/2.1.1: - resolution: - { - integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, - } - engines: { node: ">=0.10.0" } - dev: false - - /require-from-string/2.0.2: - resolution: - { - integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, - } - engines: { node: ">=0.10.0" } - dev: false - - /requires-port/1.0.0: - resolution: - { - integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==, - } - dev: false - - /retry/0.12.0: - resolution: - { - integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==, - } - engines: { node: ">= 4" } - dev: false - optional: true - - /rimraf/3.0.2: - resolution: - { - integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, - } - hasBin: true - dependencies: - glob: 7.2.3 - dev: false - - /safe-buffer/5.1.2: - resolution: - { - integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, - } - dev: false - - /safe-buffer/5.2.1: - resolution: - { - integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, - } - - /safer-buffer/2.1.2: - resolution: - { - integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, - } - - /sax/1.2.4: - resolution: - { - integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==, - } - dev: false - - /semver/5.7.1: - resolution: - { - integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==, - } - hasBin: true - dev: false - - /semver/6.3.0: - resolution: - { - integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==, - } - hasBin: true - dev: false - - /semver/7.3.8: - resolution: - { - integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==, - } - engines: { node: ">=10" } - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: false - - /send/0.18.0: - resolution: - { - integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==, - } - engines: { node: ">= 0.8.0" } - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - - /serve-static/1.15.0: - resolution: - { - integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==, - } - engines: { node: ">= 0.8.0" } - dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.18.0 - transitivePeerDependencies: - - supports-color - - /set-blocking/2.0.0: - resolution: - { - integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==, - } - dev: false - - /setprototypeof/1.2.0: - resolution: - { - integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==, - } - - /sha.js/2.4.11: - resolution: - { - integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==, - } - hasBin: true - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: false - - /shebang-command/2.0.0: - resolution: - { - integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, - } - engines: { node: ">=8" } - dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex/3.0.0: - resolution: - { - integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, - } - engines: { node: ">=8" } - dev: true - - /side-channel/1.0.4: - resolution: - { - integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==, - } - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 - object-inspect: 1.12.2 - - /signal-exit/3.0.7: - resolution: - { - integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, - } - - /smart-buffer/4.2.0: - resolution: - { - integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==, - } - engines: { node: ">= 6.0.0", npm: ">= 3.0.0" } - dev: false - - /socks-proxy-agent/5.0.1: - resolution: - { - integrity: sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==, - } - engines: { node: ">= 6" } - dependencies: - agent-base: 6.0.2 - debug: 4.3.4 - socks: 2.7.1 - transitivePeerDependencies: - - supports-color - dev: false - - /socks-proxy-agent/6.2.1: - resolution: - { - integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==, - } - engines: { node: ">= 10" } - dependencies: - agent-base: 6.0.2 - debug: 4.3.4 - socks: 2.7.1 - transitivePeerDependencies: - - supports-color - dev: false - optional: true - - /socks/2.7.1: - resolution: - { - integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==, - } - engines: { node: ">= 10.13.0", npm: ">= 3.0.0" } - dependencies: - ip: 2.0.0 - smart-buffer: 4.2.0 - dev: false - - /source-map-support/0.5.21: - resolution: - { - integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, - } - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: false - - /source-map/0.6.1: - resolution: - { - integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, - } - engines: { node: ">=0.10.0" } - dev: false - - /sprintf-js/1.0.3: - resolution: - { - integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==, - } - dev: false - - /sqlite3/5.1.4: - resolution: - { - integrity: sha512-i0UlWAzPlzX3B5XP2cYuhWQJsTtlMD6obOa1PgeEQ4DHEXUuyJkgv50I3isqZAP5oFc2T8OFvakmDh2W6I+YpA==, - } - requiresBuild: true - peerDependenciesMeta: - node-gyp: - optional: true - dependencies: - "@mapbox/node-pre-gyp": 1.0.10 - node-addon-api: 4.3.0 - tar: 6.1.13 - optionalDependencies: - node-gyp: 8.4.1 - transitivePeerDependencies: - - bluebird - - encoding - - supports-color - dev: false - - /ssri/8.0.1: - resolution: - { - integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==, - } - engines: { node: ">= 8" } - dependencies: - minipass: 3.3.6 - dev: false - optional: true - - /statuses/2.0.1: - resolution: - { - integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==, - } - engines: { node: ">= 0.8" } - - /stream-parser/0.3.1: - resolution: - { - integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==, - } - dependencies: - debug: 2.6.9 - transitivePeerDependencies: - - supports-color - dev: false - - /streamsearch/1.1.0: - resolution: - { - integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==, - } - engines: { node: ">=10.0.0" } - dev: false - - /string-width/4.2.3: - resolution: - { - integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, - } - engines: { node: ">=8" } - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: false - - /string_decoder/0.10.31: - resolution: - { - integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==, - } - dev: false - - /string_decoder/1.1.1: - resolution: - { - integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, - } - dependencies: - safe-buffer: 5.1.2 - dev: false - - /string_decoder/1.3.0: - resolution: - { - integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, - } - dependencies: - safe-buffer: 5.2.1 - dev: false - - /strip-ansi/6.0.1: - resolution: - { - integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, - } - engines: { node: ">=8" } - dependencies: - ansi-regex: 5.0.1 - dev: false - - /strip-final-newline/2.0.0: - resolution: - { - integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==, - } - engines: { node: ">=6" } - dev: true - - /strnum/1.0.5: - resolution: - { - integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==, - } - dev: false - - /strtok3/6.3.0: - resolution: - { - integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==, - } - engines: { node: ">=10" } - dependencies: - "@tokenizer/token": 0.3.0 - peek-readable: 4.1.0 - dev: false - - /supports-color/7.2.0: - resolution: - { - integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, - } - engines: { node: ">=8" } - dependencies: - has-flag: 4.0.0 - - /tar/6.1.13: - resolution: - { - integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==, - } - engines: { node: ">=10" } - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 4.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - dev: false - - /thenify-all/1.6.0: - resolution: - { - integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, - } - engines: { node: ">=0.8" } - dependencies: - thenify: 3.3.1 - dev: false - - /thenify/3.3.1: - resolution: - { - integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, - } - dependencies: - any-promise: 1.3.0 - dev: false - - /thirty-two/1.0.2: - resolution: - { - integrity: sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==, - } - engines: { node: ">=0.2.6" } - dev: false - - /toidentifier/1.0.1: - resolution: - { - integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==, - } - engines: { node: ">=0.6" } - - /token-types/4.2.1: - resolution: - { - integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==, - } - engines: { node: ">=10" } - dependencies: - "@tokenizer/token": 0.3.0 - ieee754: 1.2.1 - dev: false - - /tr46/0.0.3: - resolution: - { - integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, - } - dev: false - - /ts-node/10.9.1_awa2wsr5thmg3i7jqycphctjfq: - resolution: - { - integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==, - } - hasBin: true - peerDependencies: - "@swc/core": ">=1.2.50" - "@swc/wasm": ">=1.2.50" - "@types/node": "*" - typescript: ">=2.7" - peerDependenciesMeta: - "@swc/core": - optional: true - "@swc/wasm": - optional: true - dependencies: - "@cspotcode/source-map-support": 0.8.1 - "@tsconfig/node10": 1.0.9 - "@tsconfig/node12": 1.0.11 - "@tsconfig/node14": 1.0.3 - "@tsconfig/node16": 1.0.3 - "@types/node": 18.11.18 - acorn: 8.8.1 - acorn-walk: 8.2.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 4.9.4 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: false - - /ts-node/9.1.1_typescript@4.2.4: - resolution: - { - integrity: sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==, - } - engines: { node: ">=10.0.0" } - hasBin: true - peerDependencies: - typescript: ">=2.7" - dependencies: - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - source-map-support: 0.5.21 - typescript: 4.2.4 - yn: 3.1.1 - dev: false - - /tslib/1.14.1: - resolution: - { - integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==, - } - dev: false - - /tslib/2.4.1: - resolution: - { - integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==, - } - dev: false - - /type-check/0.3.2: - resolution: - { - integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==, - } - engines: { node: ">= 0.8.0" } - dependencies: - prelude-ls: 1.1.2 - dev: false - - /type-is/1.6.18: - resolution: - { - integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==, - } - engines: { node: ">= 0.6" } - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - - /typedarray/0.0.6: - resolution: - { - integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==, - } - dev: false - - /typeorm/0.3.11_h3l5zcb3i6sggvllyfknv6gs44: - resolution: - { - integrity: sha512-pzdOyWbVuz/z8Ww6gqvBW4nylsM0KLdUCDExr2gR20/x1khGSVxQkjNV/3YqliG90jrWzrknYbYscpk8yxFJVg==, - } - engines: { node: ">= 12.9.0" } - hasBin: true - peerDependencies: - "@google-cloud/spanner": ^5.18.0 - "@sap/hana-client": ^2.12.25 - better-sqlite3: ^7.1.2 || ^8.0.0 - hdb-pool: ^0.1.6 - ioredis: ^5.0.4 - mongodb: ^3.6.0 - mssql: ^7.3.0 - mysql2: ^2.2.5 - oracledb: ^5.1.0 - pg: ^8.5.1 - pg-native: ^3.0.0 - pg-query-stream: ^4.0.0 - redis: ^3.1.1 || ^4.0.0 - sql.js: ^1.4.0 - sqlite3: ^5.0.3 - ts-node: ^10.7.0 - typeorm-aurora-data-api-driver: ^2.0.0 - peerDependenciesMeta: - "@google-cloud/spanner": - optional: true - "@sap/hana-client": - optional: true - better-sqlite3: - optional: true - hdb-pool: - optional: true - ioredis: - optional: true - mongodb: - optional: true - mssql: - optional: true - mysql2: - optional: true - oracledb: - optional: true - pg: - optional: true - pg-native: - optional: true - pg-query-stream: - optional: true - redis: - optional: true - sql.js: - optional: true - sqlite3: - optional: true - ts-node: - optional: true - typeorm-aurora-data-api-driver: - optional: true - dependencies: - "@sqltools/formatter": 1.2.5 - app-root-path: 3.1.0 - buffer: 6.0.3 - chalk: 4.1.2 - cli-highlight: 2.1.11 - date-fns: 2.29.3 - debug: 4.3.4 - dotenv: 16.0.3 - glob: 7.2.3 - js-yaml: 4.1.0 - mkdirp: 1.0.4 - reflect-metadata: 0.1.13 - sha.js: 2.4.11 - sqlite3: 5.1.4 - ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq - tslib: 2.4.1 - uuid: 8.3.2 - xml2js: 0.4.23 - yargs: 17.6.2 - transitivePeerDependencies: - - supports-color - dev: false - - /typescript-json-schema/0.50.1: - resolution: - { - integrity: sha512-GCof/SDoiTDl0qzPonNEV4CHyCsZEIIf+mZtlrjoD8vURCcEzEfa2deRuxYid8Znp/e27eDR7Cjg8jgGrimBCA==, - } - hasBin: true - dependencies: - "@types/json-schema": 7.0.11 - "@types/node": 14.18.36 - glob: 7.2.3 - json-stable-stringify: 1.0.2 - ts-node: 9.1.1_typescript@4.2.4 - typescript: 4.2.4 - yargs: 16.2.0 - dev: false - - /typescript/4.2.4: - resolution: - { - integrity: sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==, - } - engines: { node: ">=4.2.0" } - hasBin: true - dev: false - - /typescript/4.9.4: - resolution: - { - integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==, - } - engines: { node: ">=4.2.0" } - hasBin: true - - /unique-filename/1.1.1: - resolution: - { - integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==, - } - dependencies: - unique-slug: 2.0.2 - dev: false - optional: true - - /unique-slug/2.0.2: - resolution: - { - integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==, - } - dependencies: - imurmurhash: 0.1.4 - dev: false - optional: true - - /universalify/0.1.2: - resolution: - { - integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==, - } - engines: { node: ">= 4.0.0" } - dev: false - - /unpipe/1.0.0: - resolution: - { - integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==, - } - engines: { node: ">= 0.8" } - - /uri-js/4.4.1: - resolution: - { - integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, - } - dependencies: - punycode: 2.2.0 - dev: false - - /url-parse/1.5.10: - resolution: - { - integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==, - } - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - dev: false - - /util-deprecate/1.0.2: - resolution: - { - integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, - } - dev: false - - /utils-merge/1.0.1: - resolution: - { - integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==, - } - engines: { node: ">= 0.4.0" } - - /uuid/8.3.2: - resolution: - { - integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==, - } - hasBin: true - dev: false - - /v8-compile-cache-lib/3.0.1: - resolution: - { - integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==, - } - dev: false - - /vary/1.1.2: - resolution: - { - integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==, - } - engines: { node: ">= 0.8" } - - /vm2/3.9.13: - resolution: - { - integrity: sha512-0rvxpB8P8Shm4wX2EKOiMp7H2zq+HUE/UwodY0pCZXs9IffIKZq6vUti5OgkVCTakKo9e/fgO4X1fkwfjWxE3Q==, - } - engines: { node: ">=6.0" } - hasBin: true - dependencies: - acorn: 8.8.1 - acorn-walk: 8.2.0 - dev: false - - /webidl-conversions/3.0.1: - resolution: - { - integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, - } - dev: false - - /whatwg-url/5.0.0: - resolution: - { - integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, - } - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - dev: false - - /which/2.0.2: - resolution: - { - integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, - } - engines: { node: ">= 8" } - hasBin: true - dependencies: - isexe: 2.0.0 - - /wide-align/1.1.5: - resolution: - { - integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==, - } - dependencies: - string-width: 4.2.3 - dev: false - - /word-wrap/1.2.3: - resolution: - { - integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==, - } - engines: { node: ">=0.10.0" } - dev: false - - /wrap-ansi/7.0.0: - resolution: - { - integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, - } - engines: { node: ">=10" } - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: false - - /wrappy/1.0.2: - resolution: - { - integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, - } - - /wretch/2.3.2: - resolution: - { - integrity: sha512-brN97Z2Mwed+w5z+keYI1u5OwWhPIaW0sJi9CxtKBVxLc3aqP6j1+2FCoIskM7WJq6SUHdxTFx20ox0iDLa0mQ==, - } - engines: { node: ">=14" } - dev: false - - /ws/8.12.0: - resolution: - { - integrity: sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==, - } - engines: { node: ">=10.0.0" } - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false - - /xml2js/0.4.23: - resolution: - { - integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==, - } - engines: { node: ">=4.0.0" } - dependencies: - sax: 1.2.4 - xmlbuilder: 11.0.1 - dev: false - - /xmlbuilder/11.0.1: - resolution: - { - integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==, - } - engines: { node: ">=4.0" } - dev: false - - /xregexp/2.0.0: - resolution: - { - integrity: sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==, - } - dev: false - - /xtend/4.0.2: - resolution: - { - integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==, - } - engines: { node: ">=0.4" } - dev: false - - /y18n/5.0.8: - resolution: - { - integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, - } - engines: { node: ">=10" } - dev: false - - /yallist/3.1.1: - resolution: - { - integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, - } - dev: false - - /yallist/4.0.0: - resolution: - { - integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, - } - dev: false - - /yargs-parser/20.2.9: - resolution: - { - integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==, - } - engines: { node: ">=10" } - dev: false - - /yargs-parser/21.1.1: - resolution: - { - integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, - } - engines: { node: ">=12" } - dev: false - - /yargs/16.2.0: - resolution: - { - integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==, - } - engines: { node: ">=10" } - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - dev: false - - /yargs/17.6.2: - resolution: - { - integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==, - } - engines: { node: ">=12" } - dependencies: - cliui: 8.0.1 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - dev: false - - /yn/3.1.1: - resolution: - { - integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==, - } - engines: { node: ">=6" } - dev: false diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts index 6a8d31ca..afb0df06 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts @@ -4,7 +4,7 @@ import { ConnectionUpdateSchema, DiscordApiErrors, emitEvent, -} from "@spacevar/util"; +} from "@spacebar/util"; import { Request, Response, Router } from "express"; const router = Router(); @@ -44,6 +44,9 @@ router.patch( if (typeof body.show_activity === "boolean") //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number? body.show_activity = body.show_activity ? 1 : 0; + if (typeof body.metadata_visibility === "boolean") + //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number? + body.metadata_visibility = body.metadata_visibility ? 1 : 0; connection.assign(req.body); diff --git a/src/util/schemas/ConnectionUpdateSchema.ts b/src/util/schemas/ConnectionUpdateSchema.ts index eb6c0916..e1e6523a 100644 --- a/src/util/schemas/ConnectionUpdateSchema.ts +++ b/src/util/schemas/ConnectionUpdateSchema.ts @@ -1,4 +1,5 @@ export interface ConnectionUpdateSchema { visibility?: boolean; show_activity?: boolean; + metadata_visibility?: boolean; } From 2e27281e2319c6a4240972bdfead6eaac43935e0 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sun, 2 Apr 2023 11:26:24 +1000 Subject: [PATCH 34/58] Less spammy user connection logs --- src/util/connections/ConnectionConfig.ts | 5 +++-- src/util/connections/ConnectionLoader.ts | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/util/connections/ConnectionConfig.ts b/src/util/connections/ConnectionConfig.ts index 4950ae90..7d1f9857 100644 --- a/src/util/connections/ConnectionConfig.ts +++ b/src/util/connections/ConnectionConfig.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { ConnectionConfigEntity } from "../entities/ConnectionConfigEntity"; let config: any; @@ -6,7 +7,7 @@ let pairs: ConnectionConfigEntity[]; export const ConnectionConfig = { init: async function init() { if (config) return config; - console.log("[ConnectionConfig] Loading configuration..."); + console.log("[Connections] Loading configuration..."); pairs = await ConnectionConfigEntity.find(); config = pairsToConfig(pairs); @@ -44,7 +45,7 @@ function applyConfig(val: any) { if (pair.value !== obj) { pair.value = obj; if (!pair.key || pair.key == null) { - console.log(`[ConnectionConfig] WARN: Empty key`); + console.log(`[Connections] WARN: Empty config key`); console.log(pair); } else return pair.save(); } diff --git a/src/util/connections/ConnectionLoader.ts b/src/util/connections/ConnectionLoader.ts index 0ca5b9e7..b32f77cd 100644 --- a/src/util/connections/ConnectionLoader.ts +++ b/src/util/connections/ConnectionLoader.ts @@ -1,6 +1,5 @@ import fs from "fs"; import path from "path"; -import { OrmUtils } from "../imports"; import Connection from "./Connection"; import { ConnectionConfig } from "./ConnectionConfig"; import { ConnectionStore } from "./ConnectionStore"; @@ -27,10 +26,11 @@ export class ConnectionLoader { ConnectionStore.connections.set(mod.id, mod); mod.init(); - console.log(`[Connections] Loaded connection '${mod.id}'`); + // console.log(`[Connections] Loaded connection '${mod.id}'`); }); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any public static getConnectionConfig(id: string, defaults?: any): any { let cfg = ConnectionConfig.get()[id]; if (defaults) { @@ -41,21 +41,22 @@ export class ConnectionLoader { } } - if (!cfg) - console.log( - `[ConnectionConfig/WARN] Getting connection settings for '${id}' returned null! (Did you forget to add settings?)`, - ); + if (cfg?.enabled) console.log(`[Connections] ${id} enabled`); + + // if (!cfg) + // console.log( + // `[ConnectionConfig/WARN] Getting connection settings for '${id}' returned null! (Did you forget to add settings?)`, + // ); return cfg; } public static async setConnectionConfig( id: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any config: Partial, ): Promise { if (!config) - console.log( - `[ConnectionConfig/WARN] ${id} tried to set config=null!`, - ); + console.warn(`[Connections/WARN] ${id} tried to set config=null!`); await ConnectionConfig.set({ [id]: Object.assign( From 844f1de6aa67cfa9bcb0fdf3a5f8b45026d96e5d Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sun, 2 Apr 2023 11:32:40 +1000 Subject: [PATCH 35/58] License information --- .../#connection_name/#connection_id/refresh.ts | 18 ++++++++++++++++++ .../connections/#connection_name/authorize.ts | 18 ++++++++++++++++++ .../connections/#connection_name/callback.ts | 18 ++++++++++++++++++ .../#connection_id/access-token.ts | 18 ++++++++++++++++++ .../#connection_name/#connection_id/index.ts | 18 ++++++++++++++++++ src/connections/BattleNet/BattleNetSettings.ts | 18 ++++++++++++++++++ src/connections/BattleNet/index.ts | 18 ++++++++++++++++++ src/connections/Discord/DiscordSettings.ts | 18 ++++++++++++++++++ src/connections/Discord/index.ts | 18 ++++++++++++++++++ src/connections/EpicGames/EpicGamesSettings.ts | 18 ++++++++++++++++++ src/connections/EpicGames/index.ts | 18 ++++++++++++++++++ src/connections/Facebook/FacebookSettings.ts | 18 ++++++++++++++++++ src/connections/Facebook/index.ts | 18 ++++++++++++++++++ src/connections/GitHub/GitHubSettings.ts | 18 ++++++++++++++++++ src/connections/GitHub/index.ts | 18 ++++++++++++++++++ src/connections/Reddit/RedditSettings.ts | 18 ++++++++++++++++++ src/connections/Reddit/index.ts | 18 ++++++++++++++++++ src/connections/Spotify/SpotifySettings.ts | 18 ++++++++++++++++++ src/connections/Spotify/index.ts | 18 ++++++++++++++++++ src/connections/Twitch/TwitchSettings.ts | 18 ++++++++++++++++++ src/connections/Twitch/index.ts | 18 ++++++++++++++++++ src/connections/Twitter/TwitterSettings.ts | 18 ++++++++++++++++++ src/connections/Twitter/index.ts | 18 ++++++++++++++++++ src/connections/Xbox/XboxSettings.ts | 18 ++++++++++++++++++ src/connections/Xbox/index.ts | 18 ++++++++++++++++++ src/connections/Youtube/YoutubeSettings.ts | 18 ++++++++++++++++++ src/connections/Youtube/index.ts | 18 ++++++++++++++++++ src/util/connections/Connection.ts | 18 ++++++++++++++++++ src/util/connections/ConnectionConfig.ts | 18 ++++++++++++++++++ src/util/connections/ConnectionLoader.ts | 18 ++++++++++++++++++ src/util/connections/ConnectionStore.ts | 18 ++++++++++++++++++ src/util/connections/RefreshableConnection.ts | 18 ++++++++++++++++++ src/util/connections/index.ts | 18 ++++++++++++++++++ src/util/dtos/ConnectedAccountDTO.ts | 18 ++++++++++++++++++ src/util/entities/ConnectionConfigEntity.ts | 18 ++++++++++++++++++ src/util/interfaces/ConnectedAccount.ts | 18 ++++++++++++++++++ src/util/schemas/ConnectedAccountSchema.ts | 18 ++++++++++++++++++ src/util/schemas/ConnectionCallbackSchema.ts | 18 ++++++++++++++++++ src/util/schemas/ConnectionUpdateSchema.ts | 18 ++++++++++++++++++ 39 files changed, 702 insertions(+) diff --git a/src/api/routes/connections/#connection_name/#connection_id/refresh.ts b/src/api/routes/connections/#connection_name/#connection_id/refresh.ts index 4fa64978..0d432c2b 100644 --- a/src/api/routes/connections/#connection_name/#connection_id/refresh.ts +++ b/src/api/routes/connections/#connection_name/#connection_id/refresh.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { route } from "@spacebar/api"; import { Request, Response, Router } from "express"; const router = Router(); diff --git a/src/api/routes/connections/#connection_name/authorize.ts b/src/api/routes/connections/#connection_name/authorize.ts index 63738e7c..b43f46d7 100644 --- a/src/api/routes/connections/#connection_name/authorize.ts +++ b/src/api/routes/connections/#connection_name/authorize.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { route } from "@spacebar/api"; import { Request, Response, Router } from "express"; import { ConnectionStore, FieldErrors } from "../../../../util"; diff --git a/src/api/routes/connections/#connection_name/callback.ts b/src/api/routes/connections/#connection_name/callback.ts index 74021170..bc9ba455 100644 --- a/src/api/routes/connections/#connection_name/callback.ts +++ b/src/api/routes/connections/#connection_name/callback.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { route } from "@spacebar/api"; import { ConnectionCallbackSchema, diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts index a290d88a..9031f3c8 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { route } from "@spacebar/api"; import { ApiError, diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts index afb0df06..3a4e5e0a 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { route } from "@spacebar/api"; import { ConnectedAccount, diff --git a/src/connections/BattleNet/BattleNetSettings.ts b/src/connections/BattleNet/BattleNetSettings.ts index 75e5c3ae..8fa0748b 100644 --- a/src/connections/BattleNet/BattleNetSettings.ts +++ b/src/connections/BattleNet/BattleNetSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class BattleNetSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index 7ea919f1..7edc2e92 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/Discord/DiscordSettings.ts b/src/connections/Discord/DiscordSettings.ts index 3751b041..12633076 100644 --- a/src/connections/Discord/DiscordSettings.ts +++ b/src/connections/Discord/DiscordSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class DiscordSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 24e90860..76de33be 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/EpicGames/EpicGamesSettings.ts b/src/connections/EpicGames/EpicGamesSettings.ts index 4820a88a..a66b6f4f 100644 --- a/src/connections/EpicGames/EpicGamesSettings.ts +++ b/src/connections/EpicGames/EpicGamesSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class EpicGamesSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts index 5e758540..bd7c7eef 100644 --- a/src/connections/EpicGames/index.ts +++ b/src/connections/EpicGames/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/Facebook/FacebookSettings.ts b/src/connections/Facebook/FacebookSettings.ts index cc3e3402..17811a12 100644 --- a/src/connections/Facebook/FacebookSettings.ts +++ b/src/connections/Facebook/FacebookSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class FacebookSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts index 8e0f8d27..6ce722dd 100644 --- a/src/connections/Facebook/index.ts +++ b/src/connections/Facebook/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/GitHub/GitHubSettings.ts b/src/connections/GitHub/GitHubSettings.ts index 1b4070d2..ef5fe405 100644 --- a/src/connections/GitHub/GitHubSettings.ts +++ b/src/connections/GitHub/GitHubSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class GitHubSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index 638a34af..a675873f 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/Reddit/RedditSettings.ts b/src/connections/Reddit/RedditSettings.ts index 13208fb5..3d1bf8bc 100644 --- a/src/connections/Reddit/RedditSettings.ts +++ b/src/connections/Reddit/RedditSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class RedditSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts index 2f3418c0..191c6452 100644 --- a/src/connections/Reddit/index.ts +++ b/src/connections/Reddit/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/Spotify/SpotifySettings.ts b/src/connections/Spotify/SpotifySettings.ts index e73c0304..0f5ae95e 100644 --- a/src/connections/Spotify/SpotifySettings.ts +++ b/src/connections/Spotify/SpotifySettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class SpotifySettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts index c9517b1a..61b17366 100644 --- a/src/connections/Spotify/index.ts +++ b/src/connections/Spotify/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/Twitch/TwitchSettings.ts b/src/connections/Twitch/TwitchSettings.ts index eb732c82..31927e3e 100644 --- a/src/connections/Twitch/TwitchSettings.ts +++ b/src/connections/Twitch/TwitchSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class TwitchSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/Twitch/index.ts b/src/connections/Twitch/index.ts index d53215f1..6d679aa4 100644 --- a/src/connections/Twitch/index.ts +++ b/src/connections/Twitch/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/Twitter/TwitterSettings.ts b/src/connections/Twitter/TwitterSettings.ts index e4aa58eb..df979d5f 100644 --- a/src/connections/Twitter/TwitterSettings.ts +++ b/src/connections/Twitter/TwitterSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class TwitterSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/Twitter/index.ts b/src/connections/Twitter/index.ts index f8eac894..aa48ca12 100644 --- a/src/connections/Twitter/index.ts +++ b/src/connections/Twitter/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/Xbox/XboxSettings.ts b/src/connections/Xbox/XboxSettings.ts index c1a41056..5dc764d3 100644 --- a/src/connections/Xbox/XboxSettings.ts +++ b/src/connections/Xbox/XboxSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class XboxSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/Xbox/index.ts b/src/connections/Xbox/index.ts index 011f87a8..c592fd0b 100644 --- a/src/connections/Xbox/index.ts +++ b/src/connections/Xbox/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/connections/Youtube/YoutubeSettings.ts b/src/connections/Youtube/YoutubeSettings.ts index 5d11fa40..f2daaada 100644 --- a/src/connections/Youtube/YoutubeSettings.ts +++ b/src/connections/Youtube/YoutubeSettings.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export class YoutubeSettings { enabled: boolean = false; clientId: string | null = null; diff --git a/src/connections/Youtube/index.ts b/src/connections/Youtube/index.ts index 4d90e452..f3a43fcc 100644 --- a/src/connections/Youtube/index.ts +++ b/src/connections/Youtube/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, diff --git a/src/util/connections/Connection.ts b/src/util/connections/Connection.ts index 26279299..becee589 100644 --- a/src/util/connections/Connection.ts +++ b/src/util/connections/Connection.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import crypto from "crypto"; import { ConnectedAccount } from "../entities"; import { ConnectedAccountSchema, ConnectionCallbackSchema } from "../schemas"; diff --git a/src/util/connections/ConnectionConfig.ts b/src/util/connections/ConnectionConfig.ts index 7d1f9857..5a2239a0 100644 --- a/src/util/connections/ConnectionConfig.ts +++ b/src/util/connections/ConnectionConfig.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + /* eslint-disable @typescript-eslint/no-explicit-any */ import { ConnectionConfigEntity } from "../entities/ConnectionConfigEntity"; diff --git a/src/util/connections/ConnectionLoader.ts b/src/util/connections/ConnectionLoader.ts index b32f77cd..28f1a202 100644 --- a/src/util/connections/ConnectionLoader.ts +++ b/src/util/connections/ConnectionLoader.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import fs from "fs"; import path from "path"; import Connection from "./Connection"; diff --git a/src/util/connections/ConnectionStore.ts b/src/util/connections/ConnectionStore.ts index 759b6de7..39abfea6 100644 --- a/src/util/connections/ConnectionStore.ts +++ b/src/util/connections/ConnectionStore.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import Connection from "./Connection"; import RefreshableConnection from "./RefreshableConnection"; diff --git a/src/util/connections/RefreshableConnection.ts b/src/util/connections/RefreshableConnection.ts index 87f5f6dd..fd93adfa 100644 --- a/src/util/connections/RefreshableConnection.ts +++ b/src/util/connections/RefreshableConnection.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount } from "../entities"; import { ConnectedAccountCommonOAuthTokenResponse } from "../interfaces"; import Connection from "./Connection"; diff --git a/src/util/connections/index.ts b/src/util/connections/index.ts index 8d20bf27..8ad267b1 100644 --- a/src/util/connections/index.ts +++ b/src/util/connections/index.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export * from "./Connection"; export * from "./ConnectionConfig"; export * from "./ConnectionLoader"; diff --git a/src/util/dtos/ConnectedAccountDTO.ts b/src/util/dtos/ConnectedAccountDTO.ts index a3618fd1..0a3604d5 100644 --- a/src/util/dtos/ConnectedAccountDTO.ts +++ b/src/util/dtos/ConnectedAccountDTO.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccount } from "../entities"; export class ConnectedAccountDTO { diff --git a/src/util/entities/ConnectionConfigEntity.ts b/src/util/entities/ConnectionConfigEntity.ts index 9c212b15..e4b7cea8 100644 --- a/src/util/entities/ConnectionConfigEntity.ts +++ b/src/util/entities/ConnectionConfigEntity.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { Column, Entity } from "typeorm"; import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; diff --git a/src/util/interfaces/ConnectedAccount.ts b/src/util/interfaces/ConnectedAccount.ts index ede02f6d..7278c0cb 100644 --- a/src/util/interfaces/ConnectedAccount.ts +++ b/src/util/interfaces/ConnectedAccount.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export interface ConnectedAccountCommonOAuthTokenResponse { access_token: string; token_type: string; diff --git a/src/util/schemas/ConnectedAccountSchema.ts b/src/util/schemas/ConnectedAccountSchema.ts index fa834bd6..fe808a35 100644 --- a/src/util/schemas/ConnectedAccountSchema.ts +++ b/src/util/schemas/ConnectedAccountSchema.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + import { ConnectedAccountTokenData } from "../interfaces"; export interface ConnectedAccountSchema { diff --git a/src/util/schemas/ConnectionCallbackSchema.ts b/src/util/schemas/ConnectionCallbackSchema.ts index 09ae8a46..eb86c087 100644 --- a/src/util/schemas/ConnectionCallbackSchema.ts +++ b/src/util/schemas/ConnectionCallbackSchema.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export interface ConnectionCallbackSchema { code?: string; state: string; diff --git a/src/util/schemas/ConnectionUpdateSchema.ts b/src/util/schemas/ConnectionUpdateSchema.ts index e1e6523a..f9f17b0d 100644 --- a/src/util/schemas/ConnectionUpdateSchema.ts +++ b/src/util/schemas/ConnectionUpdateSchema.ts @@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + export interface ConnectionUpdateSchema { visibility?: boolean; show_activity?: boolean; From 2c067969a0699c359b3642791999407c2289cdaa Mon Sep 17 00:00:00 2001 From: "Rainb0w :3" <81040339+Rainb0wCodes@users.noreply.github.com> Date: Sat, 8 Apr 2023 22:07:23 -0600 Subject: [PATCH 36/58] properly track reactions --- .../channels/#channel_id/messages/#message_id/reactions.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts index eafa70c8..fa1c996d 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts @@ -180,6 +180,7 @@ router.put( if (already_added.user_ids.includes(req.user_id)) return res.sendStatus(204); // Do not throw an error ¯\_(ツ)_/¯ as discord also doesn't throw any error already_added.count++; + already_added.user_ids.push(req.user_id); } else message.reactions.push({ count: 1, @@ -247,6 +248,7 @@ router.delete( already_added.count--; if (already_added.count <= 0) message.reactions.remove(already_added); + else already_added.user_ids.splice(already_added.user_ids.indexOf(user_id), 1); await message.save(); From 73276696728fd61705fc6242a459dec8411a8972 Mon Sep 17 00:00:00 2001 From: ochen1 Date: Sun, 9 Apr 2023 11:13:28 -0600 Subject: [PATCH 37/58] Send guild name and icon of guild through Identify gateway opcode These properties are mandatory as per the documentation: https://discord.com/developers/docs/resources/guild#guild-object --- src/gateway/opcodes/Identify.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index de3b3cfe..98fae3ed 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -295,6 +295,8 @@ export async function onIdentify(this: WebSocket, data: Payload) { ...new ReadyGuildDTO(x).toJSON(), guild_hashes: {}, joined_at: x.joined_at, + name: x.name, + icon: x.icon, }; }), guild_experiments: [], // TODO From 3c2d07d0b1a611f27188746e3d6d347fd5fb0145 Mon Sep 17 00:00:00 2001 From: ochen1 Date: Sun, 9 Apr 2023 12:34:45 -0600 Subject: [PATCH 38/58] Add PATCH /guilds/#guild_id/roles/#role_id/members API Discord uses this in the Edit Role menu, Manage members tab to update the list of members with the role. --- .../#guild_id/roles/#role_id/members.ts | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/api/routes/guilds/#guild_id/roles/#role_id/members.ts diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts new file mode 100644 index 00000000..25ca7557 --- /dev/null +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts @@ -0,0 +1,53 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { Router, Request, Response } from "express"; +import { Member } from "@spacebar/util"; +import { route } from "@spacebar/api"; + +const router = Router(); + +router.patch( + "/", + route({ permission: "MANAGE_ROLES" }), + async (req: Request, res: Response) => { + // Payload is JSON containing a list of member_ids, the new list of members to have the role + const { guild_id, role_id } = req.params; + const { member_ids } = req.body; + await Member.IsInGuildOrFail(req.user_id, guild_id); + const members = await Member.find({ + where: { guild_id }, + relations: ["roles"], + }); + const members_to_add = members.filter((member) => { + return member_ids.includes(member.id) && !member.roles.map((role) => role.id).includes(role_id); + }); + const members_to_remove = members.filter((member) => { + return !member_ids.includes(member.id) && member.roles.map((role) => role.id).includes(role_id); + }); + for (const member of members_to_add) { + Member.addRole(member.id, guild_id, role_id); + } + for (const member of members_to_remove) { + Member.removeRole(member.id, guild_id, role_id); + } + res.sendStatus(204); + } +); + +export default router; From 4a7eb89a721254e30464b4865801de3d0b3ff7c7 Mon Sep 17 00:00:00 2001 From: ochen1 Date: Sun, 9 Apr 2023 12:36:31 -0600 Subject: [PATCH 39/58] Fix indentation --- src/api/routes/guilds/#guild_id/roles/#role_id/members.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts index 25ca7557..26359a69 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts @@ -46,7 +46,7 @@ router.patch( for (const member of members_to_remove) { Member.removeRole(member.id, guild_id, role_id); } - res.sendStatus(204); + res.sendStatus(204); } ); From f4e172eec26de624b6736b68679b63574c39fc7e Mon Sep 17 00:00:00 2001 From: ochen1 Date: Sun, 9 Apr 2023 12:38:13 -0600 Subject: [PATCH 40/58] Add PATCH /guilds/#guild_id/roles/#role_id/member-ids API --- .../#guild_id/roles/#role_id/member-ids.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts new file mode 100644 index 00000000..6353e1f6 --- /dev/null +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts @@ -0,0 +1,38 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { Router, Request, Response } from "express"; +import { Member } from "@spacebar/util"; +import { route } from "@spacebar/api"; + +const router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + const { guild_id, role_id } = req.params; + await Member.IsInGuildOrFail(req.user_id, guild_id); + const members = await Member.find({ + select: ["id"], + relations: ["roles"], + }); + const member_ids = members.filter((member) => { + return member.roles.map((role) => role.id).includes(role_id); + }).map((member) => member.id); + return res.json(member_ids); +}); + +export default router; From 36ac484a9d6391831954729f499db89ec46a35e0 Mon Sep 17 00:00:00 2001 From: ochen1 Date: Sun, 9 Apr 2023 14:22:24 -0600 Subject: [PATCH 41/58] Fix obvious bugs in Member removeRole function --- src/util/entities/Member.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index 13e74dcd..dc56bc47 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -260,9 +260,9 @@ export class Member extends BaseClassWithoutId { }, }, }), - await Role.findOneOrFail({ where: { id: role_id, guild_id } }), + Role.findOneOrFail({ where: { id: role_id, guild_id } }), ]); - member.roles = member.roles.filter((x) => x.id == role_id); + member.roles = member.roles.filter((x) => x.id !== role_id); await Promise.all([ member.save(), From 88031fd0b7fa6c8e8d104340874944fe53efc19a Mon Sep 17 00:00:00 2001 From: "Rainb0w :3" <81040339+Rainb0wCodes@users.noreply.github.com> Date: Mon, 10 Apr 2023 20:26:00 -0600 Subject: [PATCH 42/58] Update reactions.ts --- .../channels/#channel_id/messages/#message_id/reactions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts index fa1c996d..e0a51668 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts @@ -248,7 +248,8 @@ router.delete( already_added.count--; if (already_added.count <= 0) message.reactions.remove(already_added); - else already_added.user_ids.splice(already_added.user_ids.indexOf(user_id), 1); + else + already_added.user_ids.splice(already_added.user_ids.indexOf(user_id), 1); await message.save(); From b91fca6d745edbc438a468bcb1826372029869f5 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 11 Apr 2023 12:28:16 +1000 Subject: [PATCH 43/58] prettier --- .../#guild_id/roles/#role_id/member-ids.ts | 22 ++++---- .../#guild_id/roles/#role_id/members.ts | 56 ++++++++++--------- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts index 6353e1f6..e0e7bd20 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts @@ -23,16 +23,18 @@ import { route } from "@spacebar/api"; const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - const { guild_id, role_id } = req.params; - await Member.IsInGuildOrFail(req.user_id, guild_id); - const members = await Member.find({ - select: ["id"], - relations: ["roles"], - }); - const member_ids = members.filter((member) => { - return member.roles.map((role) => role.id).includes(role_id); - }).map((member) => member.id); - return res.json(member_ids); + const { guild_id, role_id } = req.params; + await Member.IsInGuildOrFail(req.user_id, guild_id); + const members = await Member.find({ + select: ["id"], + relations: ["roles"], + }); + const member_ids = members + .filter((member) => { + return member.roles.map((role) => role.id).includes(role_id); + }) + .map((member) => member.id); + return res.json(member_ids); }); export default router; diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts index 26359a69..a1238382 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts @@ -23,31 +23,37 @@ import { route } from "@spacebar/api"; const router = Router(); router.patch( - "/", - route({ permission: "MANAGE_ROLES" }), - async (req: Request, res: Response) => { - // Payload is JSON containing a list of member_ids, the new list of members to have the role - const { guild_id, role_id } = req.params; - const { member_ids } = req.body; - await Member.IsInGuildOrFail(req.user_id, guild_id); - const members = await Member.find({ - where: { guild_id }, - relations: ["roles"], - }); - const members_to_add = members.filter((member) => { - return member_ids.includes(member.id) && !member.roles.map((role) => role.id).includes(role_id); - }); - const members_to_remove = members.filter((member) => { - return !member_ids.includes(member.id) && member.roles.map((role) => role.id).includes(role_id); - }); - for (const member of members_to_add) { - Member.addRole(member.id, guild_id, role_id); - } - for (const member of members_to_remove) { - Member.removeRole(member.id, guild_id, role_id); - } - res.sendStatus(204); - } + "/", + route({ permission: "MANAGE_ROLES" }), + async (req: Request, res: Response) => { + // Payload is JSON containing a list of member_ids, the new list of members to have the role + const { guild_id, role_id } = req.params; + const { member_ids } = req.body; + await Member.IsInGuildOrFail(req.user_id, guild_id); + const members = await Member.find({ + where: { guild_id }, + relations: ["roles"], + }); + const members_to_add = members.filter((member) => { + return ( + member_ids.includes(member.id) && + !member.roles.map((role) => role.id).includes(role_id) + ); + }); + const members_to_remove = members.filter((member) => { + return ( + !member_ids.includes(member.id) && + member.roles.map((role) => role.id).includes(role_id) + ); + }); + for (const member of members_to_add) { + Member.addRole(member.id, guild_id, role_id); + } + for (const member of members_to_remove) { + Member.removeRole(member.id, guild_id, role_id); + } + res.sendStatus(204); + }, ); export default router; From 6a148898a511da630ccafd0d47a1854aab9f79a3 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 11 Apr 2023 12:33:59 +1000 Subject: [PATCH 44/58] Remove Member.isInGuildOrFail, as it will always pass ( route permission check ) --- .../routes/guilds/#guild_id/roles/#role_id/members.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts index a1238382..886b0d1a 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts @@ -29,11 +29,12 @@ router.patch( // Payload is JSON containing a list of member_ids, the new list of members to have the role const { guild_id, role_id } = req.params; const { member_ids } = req.body; - await Member.IsInGuildOrFail(req.user_id, guild_id); + const members = await Member.find({ where: { guild_id }, relations: ["roles"], }); + const members_to_add = members.filter((member) => { return ( member_ids.includes(member.id) && @@ -46,12 +47,15 @@ router.patch( member.roles.map((role) => role.id).includes(role_id) ); }); + for (const member of members_to_add) { - Member.addRole(member.id, guild_id, role_id); + await Member.addRole(member.id, guild_id, role_id); } + for (const member of members_to_remove) { - Member.removeRole(member.id, guild_id, role_id); + await Member.removeRole(member.id, guild_id, role_id); } + res.sendStatus(204); }, ); From debfaea8667257b6179f83f460b4b76d9dec1b01 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 11 Apr 2023 12:56:32 +1000 Subject: [PATCH 45/58] Use partition func instead + use Promise.all --- .../#guild_id/roles/#role_id/members.ts | 33 ++++++++----------- src/gateway/opcodes/LazyRequest.ts | 9 +---- src/util/util/Array.ts | 8 +++++ 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts index 886b0d1a..6b9fad9c 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts @@ -17,7 +17,7 @@ */ import { Router, Request, Response } from "express"; -import { Member } from "@spacebar/util"; +import { Member, partition } from "@spacebar/util"; import { route } from "@spacebar/api"; const router = Router(); @@ -35,26 +35,21 @@ router.patch( relations: ["roles"], }); - const members_to_add = members.filter((member) => { - return ( + const [add, remove] = partition( + members, + (member) => member_ids.includes(member.id) && - !member.roles.map((role) => role.id).includes(role_id) - ); - }); - const members_to_remove = members.filter((member) => { - return ( - !member_ids.includes(member.id) && - member.roles.map((role) => role.id).includes(role_id) - ); - }); + !member.roles.map((role) => role.id).includes(role_id), + ); - for (const member of members_to_add) { - await Member.addRole(member.id, guild_id, role_id); - } - - for (const member of members_to_remove) { - await Member.removeRole(member.id, guild_id, role_id); - } + await Promise.all([ + ...add.map((member) => + Member.addRole(member.id, guild_id, role_id), + ), + ...remove.map((member) => + Member.removeRole(member.id, guild_id, role_id), + ), + ]); res.sendStatus(204); }, diff --git a/src/gateway/opcodes/LazyRequest.ts b/src/gateway/opcodes/LazyRequest.ts index 3cc2b655..64e50d92 100644 --- a/src/gateway/opcodes/LazyRequest.ts +++ b/src/gateway/opcodes/LazyRequest.ts @@ -26,6 +26,7 @@ import { LazyRequestSchema, User, Presence, + partition, } from "@spacebar/util"; import { WebSocket, @@ -302,11 +303,3 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) { }, }); } - -/* https://stackoverflow.com/a/50636286 */ -function partition(array: T[], filter: (elem: T) => boolean) { - const pass: T[] = [], - fail: T[] = []; - array.forEach((e) => (filter(e) ? pass : fail).push(e)); - return [pass, fail]; -} diff --git a/src/util/util/Array.ts b/src/util/util/Array.ts index 8a141340..082ac307 100644 --- a/src/util/util/Array.ts +++ b/src/util/util/Array.ts @@ -21,3 +21,11 @@ export function containsAll(arr: unknown[], target: unknown[]) { return target.every((v) => arr.includes(v)); } + +/* https://stackoverflow.com/a/50636286 */ +export function partition(array: T[], filter: (elem: T) => boolean) { + const pass: T[] = [], + fail: T[] = []; + array.forEach((e) => (filter(e) ? pass : fail).push(e)); + return [pass, fail]; +} From e9ce4ca51b740122b2150727196ac20d3e01a5bc Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 11 Apr 2023 13:11:19 +1000 Subject: [PATCH 46/58] member-counts route --- .../guilds/#guild_id/roles/member-counts.ts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/api/routes/guilds/#guild_id/roles/member-counts.ts diff --git a/src/api/routes/guilds/#guild_id/roles/member-counts.ts b/src/api/routes/guilds/#guild_id/roles/member-counts.ts new file mode 100644 index 00000000..88243b42 --- /dev/null +++ b/src/api/routes/guilds/#guild_id/roles/member-counts.ts @@ -0,0 +1,39 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { Request, Response, Router } from "express"; +import { Role, Member } from "@spacebar/util"; +import { route } from "@spacebar/api"; +import {} from "typeorm"; + +const router: Router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + const { guild_id } = req.params; + await Member.IsInGuildOrFail(req.user_id, guild_id); + + const role_ids = await Role.find({ where: { guild_id }, select: ["id"] }); + const counts: { [id: string]: number } = {}; + for (const { id } of role_ids) { + counts[id] = await Member.count({ where: { roles: { id }, guild_id } }); + } + + return res.json(counts); +}); + +export default router; From 7a2a41be3ec8af8b155a241cbbc2507082f40eae Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 11 Apr 2023 13:17:51 +1000 Subject: [PATCH 47/58] Don't fetch the entire role relation when counting member ids --- .../#guild_id/roles/#role_id/member-ids.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts index e0e7bd20..b086193e 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/member-ids.ts @@ -24,17 +24,19 @@ const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { const { guild_id, role_id } = req.params; - await Member.IsInGuildOrFail(req.user_id, guild_id); + + // TODO: Is this route really not paginated? const members = await Member.find({ select: ["id"], - relations: ["roles"], + where: { + roles: { + id: role_id, + }, + guild_id, + }, }); - const member_ids = members - .filter((member) => { - return member.roles.map((role) => role.id).includes(role_id); - }) - .map((member) => member.id); - return res.json(member_ids); + + return res.json(members.map((x) => x.id)); }); export default router; From d865528442769b3d5683b75d0872b01da2b5374f Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 11 Apr 2023 13:19:26 +1000 Subject: [PATCH 48/58] Add erkins note --- src/api/routes/guilds/#guild_id/roles/#role_id/members.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts index 6b9fad9c..705848aa 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts @@ -42,6 +42,7 @@ router.patch( !member.roles.map((role) => role.id).includes(role_id), ); + // TODO (erkin): have a bulk add/remove function that adds the roles in a single txn await Promise.all([ ...add.map((member) => Member.addRole(member.id, guild_id, role_id), From ab07ad692c837e5abe016cfb4a973d35d50c8d44 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 11 Apr 2023 13:47:26 +1000 Subject: [PATCH 49/58] send public member in message_reaction_add eventt --- .../#channel_id/messages/#message_id/reactions.ts | 13 +++++++++++-- src/util/entities/Member.ts | 9 +++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts index e0a51668..cb66cd64 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts @@ -28,6 +28,7 @@ import { MessageReactionRemoveEmojiEvent, MessageReactionRemoveEvent, PartialEmoji, + PublicMemberProjection, PublicUserProjection, User, } from "@spacebar/util"; @@ -192,7 +193,12 @@ router.put( const member = channel.guild_id && - (await Member.findOneOrFail({ where: { id: req.user_id } })); + ( + await Member.findOneOrFail({ + where: { id: req.user_id }, + select: PublicMemberProjection, + }) + ).toPublicMember(); await emitEvent({ event: "MESSAGE_REACTION_ADD", @@ -249,7 +255,10 @@ router.delete( if (already_added.count <= 0) message.reactions.remove(already_added); else - already_added.user_ids.splice(already_added.user_ids.indexOf(user_id), 1); + already_added.user_ids.splice( + already_added.user_ids.indexOf(user_id), + 1, + ); await message.save(); diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index 13e74dcd..cd885c13 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -440,6 +440,15 @@ export class Member extends BaseClassWithoutId { ]); } } + + toPublicMember() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const member: any = {}; + PublicMemberProjection.forEach((x) => { + member[x] = this[x]; + }); + return member as PublicMember; + } } export interface ChannelOverride { From 3c981b496b23b49885452ac6ea41dd51d3d20e04 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 11 Apr 2023 13:51:55 +1000 Subject: [PATCH 50/58] don't allow editing @everyone role --- src/api/routes/guilds/#guild_id/roles/#role_id/members.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts index 705848aa..539cd5d8 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts @@ -17,7 +17,7 @@ */ import { Router, Request, Response } from "express"; -import { Member, partition } from "@spacebar/util"; +import { DiscordApiErrors, Member, partition } from "@spacebar/util"; import { route } from "@spacebar/api"; const router = Router(); @@ -30,6 +30,9 @@ router.patch( const { guild_id, role_id } = req.params; const { member_ids } = req.body; + // don't mess with @everyone + if (role_id == guild_id) throw DiscordApiErrors.INVALID_ROLE; + const members = await Member.find({ where: { guild_id }, relations: ["roles"], From 2d50adf151acaadbe1965924469113a6caf50e06 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:45:51 +1000 Subject: [PATCH 51/58] Add missing route middleware to messages route --- src/api/routes/channels/#channel_id/messages/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts index c871087a..7f0c9fb5 100644 --- a/src/api/routes/channels/#channel_id/messages/index.ts +++ b/src/api/routes/channels/#channel_id/messages/index.ts @@ -73,9 +73,11 @@ export function isTextChannel(type: ChannelType): boolean { // https://discord.com/developers/docs/resources/channel#create-message // get messages -router.get("/", async (req: Request, res: Response) => { +router.get("/", route({}), async (req: Request, res: Response) => { const channel_id = req.params.channel_id; - const channel = await Channel.findOneOrFail({ where: { id: channel_id } }); + const channel = await Channel.findOneOrFail({ + where: { id: channel_id }, + }); if (!channel) throw new HTTPError("Channel not found", 404); isTextChannel(channel.type); From 195ea514807d568dfdeb037b411931b365b52479 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:48:00 +1000 Subject: [PATCH 52/58] generate:openapi --- assets/openapi.json | 426 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 426 insertions(+) diff --git a/assets/openapi.json b/assets/openapi.json index e0b2e564..4e4d50a8 100644 --- a/assets/openapi.json +++ b/assets/openapi.json @@ -2838,6 +2838,149 @@ "connected_accounts", "user" ] + }, + "ConnectedAccountCommonOAuthTokenResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + } + }, + "required": [ + "access_token", + "scope", + "token_type" + ] + }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "required": [ + "access_token", + "fetched_at" + ] + }, + "ConnectedAccountSchema": { + "type": "object", + "properties": { + "external_id": { + "type": "string" + }, + "user_id": { + "type": "string" + }, + "token_data": { + "$ref": "#/components/schemas/ConnectedAccountTokenData" + }, + "friend_sync": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "revoked": { + "type": "boolean" + }, + "show_activity": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "visibility": { + "type": "integer" + }, + "integrations": { + "type": "array", + "items": { + "type": "string" + } + }, + "metadata_": {}, + "metadata_visibility": { + "type": "integer" + }, + "two_way_link": { + "type": "boolean" + } + }, + "required": [ + "external_id", + "name", + "type", + "user_id" + ] + }, + "ConnectionCallbackSchema": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "state": { + "type": "string" + }, + "insecure": { + "type": "boolean" + }, + "friend_sync": { + "type": "boolean" + }, + "openid_params": {} + }, + "required": [ + "friend_sync", + "insecure", + "state" + ] + }, + "ConnectionUpdateSchema": { + "type": "object", + "properties": { + "visibility": { + "type": "boolean" + }, + "show_activity": { + "type": "boolean" + } + } } } }, @@ -2934,6 +3077,9 @@ }, { "name": "read-states" + }, + { + "name": "connections" } ], "paths": { @@ -7561,6 +7707,286 @@ "auth" ] } + }, + "/users/@me/connections/{connection_name}/{connection_id}/": { + "patch": { + "security": [ + { + "bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionUpdateSchema" + } + } + } + }, + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + }, + { + "name": "connection_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_id" + } + ], + "tags": [ + "users" + ] + }, + "delete": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + }, + { + "name": "connection_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_id" + } + ], + "tags": [ + "users" + ] + } + }, + "/users/@me/connections/{connection_name}/{connection_id}/access-token/": { + "get": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + }, + { + "name": "connection_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_id" + } + ], + "tags": [ + "users" + ] + } + }, + "/guilds/{guild_id}/roles/member-counts/": { + "get": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "guild_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "guild_id" + } + ], + "tags": [ + "guilds" + ] + } + }, + "/guilds/{guild_id}/roles/{role_id}/members/": { + "patch": { + "x-permission-required": "MANAGE_ROLES", + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "guild_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "guild_id" + }, + { + "name": "role_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "role_id" + } + ], + "tags": [ + "guilds" + ] + } + }, + "/guilds/{guild_id}/roles/{role_id}/member-ids/": { + "get": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "guild_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "guild_id" + }, + { + "name": "role_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "role_id" + } + ], + "tags": [ + "guilds" + ] + } + }, + "/connections/{connection_name}/callback/": { + "post": { + "security": [ + { + "bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionCallbackSchema" + } + } + } + }, + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + } + ], + "tags": [ + "connections" + ] + } + }, + "/connections/{connection_name}/authorize/": { + "get": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + } + ], + "tags": [ + "connections" + ] + } + }, + "/connections/{connection_name}/{connection_id}/refresh/": { + "post": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + }, + { + "name": "connection_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_id" + } + ], + "tags": [ + "connections" + ] + } } } } \ No newline at end of file From 3b62aff769be5d7e29fefebfb37f7a1ee6ae33d7 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:58:44 +1000 Subject: [PATCH 53/58] fix crowdin badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 589cac47..c990c1d1 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ - + From f81e92a159705c868c59ed823352ff6e15087580 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 12 Apr 2023 20:36:55 +1000 Subject: [PATCH 54/58] Move prettier and eslint into separate workflow --- .github/workflows/build.yml | 2 -- .github/workflows/style.yml | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/style.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5b27fddf..e3bcc81f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,5 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'npm' - run: npm ci - - run: npx eslint . - - run: npx prettier --check . - run: npm run build --if-present - run: npm run test --if-present \ No newline at end of file diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml new file mode 100644 index 00000000..931449b7 --- /dev/null +++ b/.github/workflows/style.yml @@ -0,0 +1,27 @@ +name: Style + +on: + push: + branches: [ "**" ] + pull_request: + branches: [ "**" ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npx eslint . + - run: npx prettier --check . \ No newline at end of file From 3f4344a6105f8f3cf93d3b9996f1a7d450423329 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 12 Apr 2023 20:41:52 +1000 Subject: [PATCH 55/58] Remove unnecessary stresstest folder --- scripts/benchmark/index.js | 22 - scripts/stresstest/.gitignore | 3 - scripts/stresstest/accounts.json.example | 1 - scripts/stresstest/config.json.example | 5 - scripts/stresstest/index.js | 58 -- scripts/stresstest/package-lock.json | 856 ----------------------- scripts/stresstest/package.json | 17 - scripts/stresstest/src/login/index.js | 38 - scripts/stresstest/src/message/send.js | 44 -- scripts/stresstest/src/register/index.js | 58 -- 10 files changed, 1102 deletions(-) delete mode 100644 scripts/benchmark/index.js delete mode 100644 scripts/stresstest/.gitignore delete mode 100644 scripts/stresstest/accounts.json.example delete mode 100644 scripts/stresstest/config.json.example delete mode 100644 scripts/stresstest/index.js delete mode 100644 scripts/stresstest/package-lock.json delete mode 100644 scripts/stresstest/package.json delete mode 100644 scripts/stresstest/src/login/index.js delete mode 100644 scripts/stresstest/src/message/send.js delete mode 100644 scripts/stresstest/src/register/index.js diff --git a/scripts/benchmark/index.js b/scripts/benchmark/index.js deleted file mode 100644 index ca799a85..00000000 --- a/scripts/benchmark/index.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -require("dotenv").config(); - -require("./connections"); -require("./messages"); diff --git a/scripts/stresstest/.gitignore b/scripts/stresstest/.gitignore deleted file mode 100644 index bde26fd4..00000000 --- a/scripts/stresstest/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/node_modules -config.json -accounts.json diff --git a/scripts/stresstest/accounts.json.example b/scripts/stresstest/accounts.json.example deleted file mode 100644 index ec1b2a0d..00000000 --- a/scripts/stresstest/accounts.json.example +++ /dev/null @@ -1 +0,0 @@ -[{"email":"org11ncxa8.wi732t9b4o@spacebar.chat","password":"x.ibahfyqwle.ne4hajbzp11.gpc4lcup4"},{"email":"rek6kyprik.i5hldol255@spacebar.chat","password":"1.o3w16haor2y.0e1ey2yk1x.1r0gn5o5h"},{"email":"07o37povsi.uk5q9dtxbp@spacebar.chat","password":"8.6z64gcjavp1n.uar3qqymwfi.g0sfmmbd9m"},{"email":"94di5zaie4.n1vhzdfsj@spacebar.chat","password":"1e.k3ijylxme1u.e9xr9yqbrk.3tir7qnvh"},{"email":"zbrqft4chj.yl73e5puq3@spacebar.chat","password":"5.nkc3g8cvwl15.dmp8ywmkka.m79e9t4wij"},{"email":"br1wknv7k.6hw6yl69e@spacebar.chat","password":"3.gimzx06u7mh.6rjrdflo9j1t.h3d8k2f5t"},{"email":"cdehs12h6h.iexxvg16xf@spacebar.chat","password":"1i.5ab7e9rtwl1n.31qtfv7cz9.e1k313py9"},{"email":"pazx37jpra.mgsb8k50ip@spacebar.chat","password":"d.eg5dwqvd981e.5qobehiyffe.6k5pb4fqm"},{"email":"vs6k62ak2o.xo1v4w0rj@spacebar.chat","password":"c.hrkcrnlxlg1d.w18ztd39d1p.eycgehb49"},{"email":"u5d27rbewm.3p0wa7s899@spacebar.chat","password":"s.1r7o1ur8o9k.puzbm1uuta9.an5m8bhh0a"},{"email":"vyp6x66fr.yv74eftomo@spacebar.chat","password":"m.w0c7h21asf.pq2lj3uot6a.xnhv9ftqii"},{"email":"da0k6sra2n.qts4gs9ufg@spacebar.chat","password":"h.8e42ud5f6r5.896sp1t8y6e.shwe0d8no9"},{"email":"l093koc05n.81vt1v8tsx@spacebar.chat","password":"11.zhkv1jbhdf.0ub2po3mnu.no4lq8l4"},{"email":"115tfo7ct.muvy04u0tf@spacebar.chat","password":"1c.4bpk2a17z1p.gw2h6qmvhez.57drs0quz"},{"email":"dq6bk1hjch.huw092gkhr@spacebar.chat","password":"1l.kp28mclrtee.5i4dmacbpc1j.hcqgemsni"},{"email":"8g8q9v3wmk.l2frwpuds8@spacebar.chat","password":"1n.i0wwg0njmv.teaiqjqalt1g.ib6551nh4"},{"email":"5b3y3neqxa.mmi0ex2hxd@spacebar.chat","password":"8.tvz7q9uw0hm.6ufz6fu65c1a.88vp9di6e"},{"email":"mg28g3krsp.35h1akxrqj@spacebar.chat","password":"s.y8j2n19iffr.qyecyrgo6ig.6hgrc5vy9"},{"email":"ehtumcok2j.2oozlhiq97@spacebar.chat","password":"11.uq0up8g8h1q.ofvjsx29yd.pfwen3kr38"},{"email":"le98rah1uc.au4ug9tpnt@spacebar.chat","password":"t.q15zsc0q2mt.2nj3jsdxhfc.leb9ba1xku"},{"email":"hrroex9f5n.6cl98h3jsi@spacebar.chat","password":"17.qnqqhg2us4.kh92v74atg19.49ufgil7g"},{"email":"w95wrrn48.6gfnue7dcq@spacebar.chat","password":"b.jnqgbi89oj1k.8rn0llovbll.kcblui80th"},{"email":"rqo4n0il5w.4gl1u8hlyc@spacebar.chat","password":"17.41d1lpjmi0.d8ijhslby11w.sjn7sqhi9"},{"email":"6dv3yp4kon.pk7ye6q1r6@spacebar.chat","password":"0.j70py6yysjz.sf56ebpp2gp.z68yo9hiim"},{"email":"knmi9qkige.5v1bg6h09w@spacebar.chat","password":"1d.7n58xntwg1s.umnglex7h13.c5xrsfkosm"},{"email":"cefymgc7te.dd81jabws4@spacebar.chat","password":"1u.73ea7dde1o.0i1fhyaird.sjk30nky1e"},{"email":"33xcwiqf73.r6khs46a7j@spacebar.chat","password":"b.5p5gdmh1891f.11g4590n5a.vfoek6qjb9"},{"email":"9zcgmr84s6.utnlygoubi@spacebar.chat","password":"8.g4v53t7kcl16.wgaiufzgg1u.pusdfdneb"},{"email":"26vpzekrdw.3bwq27wla@spacebar.chat","password":"11.yxey8293lj1d.nxhkju2eke.hl86mcvswd"},{"email":"vvq6w36r84.lr1auhpfc@spacebar.chat","password":"y.7vlqbpftom.6xfrtozd11k.ycf9ifi7o"},{"email":"6ejeiq64yo.zorve5saw4@spacebar.chat","password":"o.eue50qp1frq.qi0rwphg3dv.psph7va2fb"},{"email":"6s0hu88ro8.hsckrmud1i@spacebar.chat","password":"16.fc836nhb91a.ul37503ppg.l62wgser4i"},{"email":"h8qwchz2x9.5br1kcw1iv@spacebar.chat","password":"l.iw1041wgy.6azyc9h6vb.br9cr0dmn8"},{"email":"yx13rst2hu.ybisfdwgv@spacebar.chat","password":"8.5yasf5ba619.ir0toxu251p.tbgwjd18f"},{"email":"1j7vrr1trh.wqj0ozl357@spacebar.chat","password":"1m.iucscoe7b0.6ca1jfaag361.c2trc36mnvk"},{"email":"9w2w572pzr.fv1rk360pp@spacebar.chat","password":"t.labzw6qw8t3.33k42uvhgd1s.e1gj71h14"},{"email":"yf5e43ol4.6509owbcxa@spacebar.chat","password":"12.jewy0uvx1m1m.ce28kht6dk.v2p0bzlvz"},{"email":"gzny2o1re.1xrl0ua7yd@spacebar.chat","password":"h.3valf7r8jh.6bzfr4ions.r4b2mt0l0g"},{"email":"bc77a5kw9v.hu5barps6q@spacebar.chat","password":"1a.jt11azsa81j.4v70jvm9d1o.hflrb1tigk"},{"email":"ltoezpefev.hrvnxmq9ee@spacebar.chat","password":"b.v4f5lqrlc912.dx4dd4xq91v.zj345to03"},{"email":"svcpsuoenk.b8mfqxpbzg@spacebar.chat","password":"1a.7aobev8b4r.xqqfybkcs1t.cjuswku0a"},{"email":"n0mroewqq.svq5iq57pe@spacebar.chat","password":"1l.zxm1xhlavp.65rp7bz57x.01vjajdsc"},{"email":"trly6yupd.dt37kh07dn@spacebar.chat","password":"1i.o2ieg72fz1j.er031tzerx.2ngg4dcvlh"},{"email":"ickkf14cqv.9pu2pnmx7n@spacebar.chat","password":"18.pyhd9ruatl1k.erfchcjc95.wfd67r5e8x"},{"email":"5o4ornfwy9.yabymb8e2k@spacebar.chat","password":"1g.117kmei8df10.cedozr4vee.08te5d44nb"},{"email":"p0ulegfi3.dgmar6qc2v@spacebar.chat","password":"1h.tle7s3ed82.un20o5nv3dk.wnz4w802h8"},{"email":"58gejpvr6v.jolxrsl83p@spacebar.chat","password":"e.ksw14117hbo.f0pgufr3na.ssrjys23al"},{"email":"vf349zeoja.r8bjel59kd@spacebar.chat","password":"1o.79kh6e6glm9.d76d86g1jp16.u37p4jhf7"},{"email":"uc786nn0go.n9ygun6owj@spacebar.chat","password":"m.xo4bwhct5be.lpokbj59w8p.z4l52dzv1r"},{"email":"5jgx24s87u.odlx0bfo0r@spacebar.chat","password":"1k.ni9jyfol7h1g.vczzsa8dbg.r4bhoh5op"},{"email":"2v44408x8l.unfspunnnm@spacebar.chat","password":"16.63njhji5b4.r4xkcf672f1a.x389dr603g"},{"email":"ityj8kcvrm.9djzannsll@spacebar.chat","password":"1p.6jdbhaxiqc.nfnpw7e09g8.967dtt2dy3"},{"email":"8csbvl9qot.28etdf4pf@spacebar.chat","password":"1b.52rdo5qmj3.ta9jw1wm3k9.m96fe27tp"},{"email":"dqndi38hsq.yv77wk3mov@spacebar.chat","password":"k.zpjwpwxmlr1f.tbj03rxayn17.9x451qclu"},{"email":"ohwmvag9j.w6t8ngs4t@spacebar.chat","password":"b.h1ta0mly991q.wzu1ssffyk1h.kc10wt8i2"},{"email":"2mmors2h0w.jwukibc7oi@spacebar.chat","password":"y.xo4kgepqa1t.b77zwt1in5.3um79fx22r"},{"email":"ux0q6gvwnr.gnywxxrsn@spacebar.chat","password":"g.52userbsonu.ny8omqaduf.rvhtwq4jer"},{"email":"0q12b4zet.y87zc04r8r@spacebar.chat","password":"1t.79mg1a9q85.k66wagu67j14.ad0gw3caw"},{"email":"gatbconrvq.dsopxa8fkk@spacebar.chat","password":"1n.fycl7y9roh1p.4yg37pst4k16.votnvabrf"},{"email":"mmp9g1b1v.xz1w4qzxee@spacebar.chat","password":"1k.cjmz3huosl.jh502yz5jf1e.hyce7qc67"},{"email":"5s90s1hbns.b027pfiv3s@spacebar.chat","password":"1l.86ipkmi6fg.scabtvproj4.yw4nb9qui9"},{"email":"l4zrvtrbpb.1r627sllk@spacebar.chat","password":"1l.zzm1dunzzek.10sr7mp01ly.yyrjj1hsli"},{"email":"xih9rwk90i.rmdifv40g@spacebar.chat","password":"15.db9k0pxci1v.hs6l033urm.5a1zv42fhl"},{"email":"55mq93jdq.2dhr1ps4f5@spacebar.chat","password":"i.v5hpg2qez1u.xhs32cwes1h.n10pexmfff"},{"email":"5c0vb38rul.5su27w4pn8@spacebar.chat","password":"12.y87q6jxq41m.qgiji2j0hm.gmy2wuavc"},{"email":"qjk2eoqeqq.ljq4dig10o@spacebar.chat","password":"0.lpu8eio3hra12.mq8qcehpe1e.77p7zilh4"},{"email":"b45ltbf5d.o4oouuik1e@spacebar.chat","password":"1u.wb7hn2b1x1k.jys5p3ri4j.9ew9jab3ll"},{"email":"1mw205tjri.gpi2h76eps@spacebar.chat","password":"1g.kyh53pnamd13.5yufexmyv1h.r56pmhm7i"},{"email":"8y0psdjq2s.ifqyimhnkj@spacebar.chat","password":"1d.fi03hlwk41u.b89w0vrd712.ljudzvdo6"},{"email":"ls73glp0q9.3rtqyb262@spacebar.chat","password":"1.z70c4ef5hfi.fes9zmue2it.5cobkz3ah"},{"email":"ipe2um46bi.in93oau1l@spacebar.chat","password":"5.a5he7keuru1n.l05ivx4n24.piohqdy51w"},{"email":"mt16ta8diq.krypy2t9cv@spacebar.chat","password":"n.zk4goctn5p3.r1fhllqy1m1p.ni2q3y68w"},{"email":"qehwflm0ja.x5uvmxgfle@spacebar.chat","password":"1e.r2sj0uimq1f.nmtozr8qd1s.xgvz4d62b"},{"email":"0ppn1iwd6.ivrqbvn17i@spacebar.chat","password":"1n.fr6x1pbzjl.c8xwipgo6c.m1me2h2g58"},{"email":"xiiq47ofev.u9z0gndxs6@spacebar.chat","password":"1t.7tfe0181ij.jbznx5eebs.ytm50kp5qf"},{"email":"kqhk3lt2mo.o4y7u23zbu@spacebar.chat","password":"1b.bkoqmxjcf1l.c5q9oneuz1u.00x93z7l4"},{"email":"ri64c5o5zn.o429slph64@spacebar.chat","password":"1r.mre2hu1gpu.401xyxa6eu.j98cetaplg"},{"email":"j5jpukoktw.q5bseyjfu@spacebar.chat","password":"h.k1ar11fpx1m.n50t8tz4k4.9oj17rtdjw"},{"email":"cg8gyuhu16.jezv2bo8n@spacebar.chat","password":"1c.vyfo117pd1b.hxlc7e9zve.j6ej7ho2rk"},{"email":"7ngysyss7w.yjy0whd5fh@spacebar.chat","password":"12.pl4jjp66wi1r.xx7s13gsgy.v2slv2vyx"},{"email":"7uhylwdaiq.w557htx0x@spacebar.chat","password":"1j.icm6w8m4mh.4qyoql77m8.ar8kliax0s"},{"email":"y6yn1ckm1e.7xxizerecm@spacebar.chat","password":"1e.om7n18zisn1w.usblhxf4p1m.r9ke41xox"},{"email":"uwdsktqhuw.4vmh5gmg7d@spacebar.chat","password":"6.cdte4bk24b16.cf1sbtxlx1o.n62w4weh9"},{"email":"8v1nt755y.w0y1jgfcgm@spacebar.chat","password":"f.ozxpvznxj41o.bs5s5dhua1l.ffayy0gsy"},{"email":"rmy9b61cij.qir0bjorcm@spacebar.chat","password":"1h.bxjxpx0u6f13.e97yh8g761c.j8zog74iql"},{"email":"93ir0yiyi9.1f7bfzt3fb@spacebar.chat","password":"18.vky28kwlw14.w1wsoyu6c15.yhxbr725xe"},{"email":"g0kqw9plr.v2zcovhyg6@spacebar.chat","password":"1r.3txq1jt4zl1d.ha0ejtekjh.xhjl9e6vqg"},{"email":"xmk2q5zxa.v1ka9gm3a8@spacebar.chat","password":"1l.ryvykh3ihm16.rxea04ifq0.h14sz83yisv"},{"email":"mqt2bmltj9.53o16bc6xn@spacebar.chat","password":"i.vt66ajtme1f.lllyzaprk16.yb0yh0o1z"},{"email":"4kvjyddsv.7u7lmex2df@spacebar.chat","password":"1i.axaegtd0qz.2yvfr5n261g.8s8fprsd8"},{"email":"yigntcopcc.8bchnlmclm@spacebar.chat","password":"n.b5yn5xried1d.siep9e4fb1t.h6s6erw5t"},{"email":"meubr1b03t.t97015wih6@spacebar.chat","password":"5.wu3izi2gyqi.iurx5qpp7l.znq1htzuel"},{"email":"xz3gta0hi.1x5o83xyee@spacebar.chat","password":"14.uafjiryde3.oin9k24w3510.vkjmjleb4i"},{"email":"9jkrkk9r6o.6ossrgj919@spacebar.chat","password":"v.u9531wtw2o11.151eg145bf.bk57nd0s6u"},{"email":"kf9fdmnacv.67shfcubvn@spacebar.chat","password":"1i.7f1olv2hkt.v2cso7zxlfw.8ylhl33g1"},{"email":"k8zuiett0r.0w299k0t9j@spacebar.chat","password":"t.1mrpwsil15.999lbrfvz1h.7od0kjlxo"},{"email":"8m9rt3vgg.vkpf6apx9@spacebar.chat","password":"1n.2ohz11tk412.5ezp8ujcwn8.rvqqrozh9s"},{"email":"rfavhpnhc.6xwy7o3ulm@spacebar.chat","password":"11.ikd54271zj.vq3brjark7.h1ryvz7ap8"},{"email":"6zmju5azrd.4bes4a3cq@spacebar.chat","password":"5.litb6taajto.ownyp3uhjkh.f543o47uc9"},{"email":"ml5pst7t3g.kbvn8b1vg@spacebar.chat","password":"1q.co2aumj6fw.fa18frro5e.vnpotfg209"},{"email":"kaa1r6srjs.wjriguic5e@spacebar.chat","password":"y.y635jqxai9.s4hcd1weni5.51i7z3c26r"},{"email":"n09uhfkuc5.9aqau9qyk@spacebar.chat","password":"1f.wtjqoqzdwg6.mfvvtcwtx91t.8ujt3pwx4"},{"email":"6y5y3px9oa.4183pg5aq6@spacebar.chat","password":"11.8a00uh75g1i.d462wzpqv1t.dnd8sdvr"},{"email":"aqdzadem03.f8uv1m4zv4@spacebar.chat","password":"4.4ndx89thn53.afcjfzjqe51o.ivaemdp5hf"},{"email":"oqv3944yav.31ccatif3r@spacebar.chat","password":"1w.9cstqu9o21f.p40uqca3vl19.iqnn79lqde"},{"email":"akzyzmigv.9c6w5aj4o@spacebar.chat","password":"m.m382wa8nznr.szvso4c03ke.ttw2jhnwh8"},{"email":"13dqfm57jo.e05e711ggt@spacebar.chat","password":"1b.t1b51jt7lf.rhi4j32rw91u.0foqthilf"},{"email":"3derfs5v66.s2kbedbm3o@spacebar.chat","password":"t.e153si8xso1m.9rv9il857fd.e3i0di3ope"},{"email":"92k9vmws7.dt9mvv6ijh@spacebar.chat","password":"1r.r8oy0su9c1e.irtwz9gdna.3fddwt8k4n"},{"email":"w1huzvblr.q9qp44japt@spacebar.chat","password":"1v.dfdr92srfs.3x2wd25frh15.z73xb3vol"},{"email":"vne3an2fif.32eq9woyl@spacebar.chat","password":"7.lurd6n689ek.sf3gedrf711.5xclyfsn3"},{"email":"298zj4dvxf.5sfh7f2e2m@spacebar.chat","password":"n.1rbv0z54wr1n.nt2041ujks.0gwbe80zyl"},{"email":"ywp1ssr2zh.gl97epixxu@spacebar.chat","password":"1w.gfpvze8vq1p.is7b2795819.4hilzah3"},{"email":"kqzujy4m5j.ocydwl4yyh@spacebar.chat","password":"1c.sqxzxuareez.fgczf2qh3en.yi5vo23phn"},{"email":"ck8n5p7d6d.2vu4cdm6iw@spacebar.chat","password":"1o.g3lq6grnm1t.otf44zgiw1c.jfdgqubfjl"},{"email":"s3vqe9bzj.muec34461t@spacebar.chat","password":"1u.i4u3eidof19.tl8hf5fpdv.mvbij0fdgc"},{"email":"7hedrsktw.oqe4hym4us@spacebar.chat","password":"1j.orlptqc2h.hs6661zehh1r.ngepsoldvf"},{"email":"44tm2rsu6j.oxrw5ib1np@spacebar.chat","password":"1o.n71dxtllrf9.htwjv6fsi81l.5w9pyr8eee"},{"email":"o28saa2e4t.m49530ir45@spacebar.chat","password":"16.z31xrcp6li12.uaklzxvskl.nqyq23zqb"},{"email":"aaz3kkwx2q.u42rdyacy6@spacebar.chat","password":"1k.aohk44bxqkq.6lec7k6yfa14.geiq4ok3b"},{"email":"ntw1oc87mh.js3q1iqxrh@spacebar.chat","password":"15.li45vduoy15.h90fv4ytl1t.3v78qdvcq"},{"email":"cpkgoh313.lkdhhl039a@spacebar.chat","password":"3.fdw00uv0dn1v.qz6frlgeh0.3g0c7xnn9le"},{"email":"wznnajnyww.3f5s5cf0lt@spacebar.chat","password":"4.3d2ro1uvag2.9yum8m4gd5t.yd1zriwovn"},{"email":"odwdxlk49g.m113aywba@spacebar.chat","password":"y.24hnap1ckh.n0q1dtobf717.0tzaopasse"},{"email":"0xt66uuwbs.24qfa4w82q@spacebar.chat","password":"e.3cfcd0usw57.oydvjpl5wm1b.sxnf38ihh"},{"email":"4pxgasro0t.xifcrlp26f@spacebar.chat","password":"1d.oxpqgh8jbgb.6epjawtwga1u.o5d33jm"},{"email":"l202g9q8xo.t4ck4xu44v@spacebar.chat","password":"d.gyul2yhu7h1g.163rzn4kqik.e5qlstdwp"},{"email":"8mwzma33ko.b9on13ypjl@spacebar.chat","password":"b.0sdy90whqr1o.rruwt57r8l14.hjejwclmr"},{"email":"h8dm19fu77.hzpnw8famh@spacebar.chat","password":"s.q49kg1uq8gc.046rudurb1o.2lqegjfds"},{"email":"exkp3ve6z7.mdydbk9jy@spacebar.chat","password":"16.bq8o0d13sd8.tri7wtdjpro.2ebtbyqgtt"},{"email":"n8fe02yphv.huwi91ywha@spacebar.chat","password":"1d.8qp5wkq541k.ulwk4bzjsm19.q3qbxorto"},{"email":"lsslgvrdyb.u86qng3p7o@spacebar.chat","password":"11.9q1m8gwavd.9z3kflcg5k1e.lrux8aqm8"},{"email":"0jur86ya2p.gb26btuz7@spacebar.chat","password":"n.fflp1f1yksg.10rh6etc61.yld8y7u9hi"},{"email":"raseda2c45.vl9resp89r@spacebar.chat","password":"b.6gd8az3ljg.es1yjenqskk.i4i8m466p"},{"email":"jmam7ha069.b96jzg1bkl@spacebar.chat","password":"1f.2z41vc92bo.84f3d3j3gra.5yev9enzv"},{"email":"pp2rki7hjd.a037bg6u6@spacebar.chat","password":"3.nktq53a97c19.khsapwl0wd.ej16kksime"},{"email":"c35l8m3ikr.e7vx8nmbil@spacebar.chat","password":"2.oryjofui8mu.7jes36sirs1u.oclq1geaf"},{"email":"ufhsl7tn5u.j4ey0abswv@spacebar.chat","password":"14.uctn73o6h1n.t75arwloxgf.nvgdr4l41o"},{"email":"8ru4fr2ed.kf8ffg9ko8@spacebar.chat","password":"n.hqxwr2ypwd1l.vu23byfp3c.nzgszptoqk"},{"email":"6gmjeij67o.ep5256bmf@spacebar.chat","password":"1i.237gs5pk5j1w.yvuhvp9ho15.l4qibsw5i"},{"email":"4wrhgqel0w.e0sz7l0zki@spacebar.chat","password":"w.g09qtor0p1g.a5uzjl6u3g17.v3z6rhb9h"},{"email":"3860ixs8g.6pha1slnur@spacebar.chat","password":"m.o7o62cqw3g.wkkaak7zz8.h82m4nenbf"},{"email":"wnnpg8stto.zwsxqfp38i@spacebar.chat","password":"c.k2b6jn1b3r14.ojpvlbxil1r.rpkncuyqp"},{"email":"t04ss33dlw.98dpq7j8rg@spacebar.chat","password":"5.7zgfmumai7.iphztcsjfw1h.sq2kp3j9j"},{"email":"hy53et7kw6.vsku4tebj9@spacebar.chat","password":"3.ayjddj0roe1m.ngz1qajzlgu.xue35w1d1d"},{"email":"252ueajele.j4euv8la1d@spacebar.chat","password":"h.tw1utyw7mh9.ydii1rkvp4.8xafwfxrqd"},{"email":"ye2mi1d86.uqa7ig7qxb@spacebar.chat","password":"j.pn3eoar1ft1e.k8febwch91o.fzau5lnbx"},{"email":"4cq5y22mm8.q33hk612wu@spacebar.chat","password":"1l.7tx03ihc9e1a.3i2l76ur5.28yffumat8"},{"email":"d9op87vvj7.vbu23p4mnq@spacebar.chat","password":"10.z7pgyokesip.0i0axexmwpa.0p5xrlag9k"},{"email":"tnhgsqizxh.14ulf4jinl@spacebar.chat","password":"j.8p0jucy5xk10.creosnkf2o.vzznt05x"},{"email":"8h2h3w3ex5.8ogl7f027n@spacebar.chat","password":"1b.08wkhdm03g3.8hdklh1zj41t.fq57w9raf"},{"email":"ommn4ocwtn.1fkdjbz2v8@spacebar.chat","password":"1e.i8k15b9uk1p.70n34lxbzf.4inv63cwt8"},{"email":"fnxg92zeqn.ljg5uumt3e@spacebar.chat","password":"w.ltho2dsgveu.d1ome2w0x8j.7wr2hq1wk8"},{"email":"lzi8aurosp.mck9i974of@spacebar.chat","password":"u.zezf4qdz2p0.l2g634tak98.ql0n1tg6sq"},{"email":"fdhv4fccm5.o9x209i94g@spacebar.chat","password":"5.2o84u6v43619.4c0c71a9gk7.n9cmjegefv"},{"email":"tuedrm1ajt.bxjgzsyj4s@spacebar.chat","password":"1m.ng2h807gvu.rhd056e6bbb.lkvewwp2tg"},{"email":"488bryb32a.x928qzsf8g@spacebar.chat","password":"y.n2c3x3irffa.fz9xwiimno8.nnpvm280oc"},{"email":"n928oorjaa.kj35rf9p35@spacebar.chat","password":"1l.flvmvopcj16.pmx6n9hi7hi.v9odjzq3at"},{"email":"emzd8qz0f8.b972dvhf0m@spacebar.chat","password":"3.7umgbd5apm18.0n6yi8ol9g.m4607npuc"},{"email":"g7jzdulwv5.0a2wzws2ua@spacebar.chat","password":"10.1u1sac19wkf.lvi2qwfhtq16.8wbdddpms"},{"email":"giuivahumo.7iqapfnbfr@spacebar.chat","password":"q.pzck5qtbype.llhl9ypv6b1e.3dz8gsv0pg"},{"email":"0t84mm2pj9.kycgvqkuag@spacebar.chat","password":"1t.kpvjmvipo14.kwv0np3ordv.ustw31ifu"},{"email":"vx5t6yurg7.pocn2c069m@spacebar.chat","password":"f.gdwgrk0wia1u.7m1ozam0b0.d5y62kwyih5"},{"email":"p7arvq1hha.7wryrvhvl@spacebar.chat","password":"1v.eb62r3rx71h.d3fhbfdxa1l.4gzcu184s"},{"email":"adp64dkhdd.q2nc2qvy3@spacebar.chat","password":"q.96rt5rc517h.3f0foodom4.h1wee4z428"},{"email":"pfhrq2kv8.92dq9bxy8a@spacebar.chat","password":"1g.nfaha2xx7hi.vtng22emxs1l.fpbra2wo6h"},{"email":"jjnysdssoc.eqr6v2pqeo@spacebar.chat","password":"1.112arb9m3cb.w3yfq6ekz1d.keb15ptd5"},{"email":"m5rab6dhrc.p1tnxv9feg@spacebar.chat","password":"1.3guc8m7j0uj4.xphgg3121714.7ii7ah6g7f"},{"email":"zgq1iount.blsiqtyvc6@spacebar.chat","password":"16.dzt6188au1w.ilwc3p3ds17.7j7lcsqur"},{"email":"ix7nx1ce4a.3wj4gs8b7p@spacebar.chat","password":"13.p2v1p2nwa1t.2yarcqsmzk.ay7w9u0p1r"},{"email":"5jh7wm63ug.feyytgy11g@spacebar.chat","password":"10.otpp2mz0smb.uv94hcp26c8.a3nlz16n14"},{"email":"9cd7yy1ps4.jet2fn1fdb@spacebar.chat","password":"9.bjtfocm7zk12.sushyeb1yg.lhtmj6a70t"},{"email":"20u20f6dlk.l8n5tvh2re@spacebar.chat","password":"19.qfrr25rarj.4tzf063a9n4.3i5s3vm30b"},{"email":"b1hnmmwcb.q21mrflg1h@spacebar.chat","password":"3.ysh10ultyjz.nz8azt84216.lxn1kgvly"},{"email":"j7nhj8s2d.aqaeidbi8m@spacebar.chat","password":"g.nlnw7ejuqbz.41exhwj2wiv.1yr0njmd"}] \ No newline at end of file diff --git a/scripts/stresstest/config.json.example b/scripts/stresstest/config.json.example deleted file mode 100644 index 73f52f05..00000000 --- a/scripts/stresstest/config.json.example +++ /dev/null @@ -1,5 +0,0 @@ -{ - "url": "", - "text-channel": "", - "invite": "" -} diff --git a/scripts/stresstest/index.js b/scripts/stresstest/index.js deleted file mode 100644 index d3f2d2ba..00000000 --- a/scripts/stresstest/index.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/* eslint-env node */ - -const register = require("./src/register"); -const login = require("./src/login/index"); -const config = require("./config.json"); -const figlet = require("figlet"); -const sendMessage = require("./src/message/send"); -const fs = require("fs"); -figlet("Spacebar Stress Test :)", function (err, data) { - if (err) { - console.log("Something went wrong..."); - console.dir(err); - return; - } - console.log("\x1b[32m", data); -}); -setInterval(() => { - generate(); -}, 1000 * 5); -setInterval(() => { - getUsers(); -}, 60 * 1000); -async function generate() { - var accounts = await JSON.parse(fs.readFileSync("accounts.json")); - console.log(accounts); - var account = await register(); - accounts.push(account); - fs.writeFileSync("accounts.json", JSON.stringify(accounts)); - console.log(accounts.length); - var y = await login(account); - sendMessage(y); -} -async function getUsers() { - var accounts = await JSON.parse(fs.readFileSync("accounts.json")); - accounts.forEach(async (x) => { - var y = await login(x); - console.log(y); - sendMessage(y); - }); -} diff --git a/scripts/stresstest/package-lock.json b/scripts/stresstest/package-lock.json deleted file mode 100644 index 81c9b817..00000000 --- a/scripts/stresstest/package-lock.json +++ /dev/null @@ -1,856 +0,0 @@ -{ - "name": "stresstest", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "stresstest", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "figlet": "^1.5.2", - "node-fetch": "^2.6.6", - "request": "^2.88.2" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "node_modules/combined-stream": { - "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" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/figlet": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz", - "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dependencies": { - "mime-db": "1.51.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "engines": { - "node": "*" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "figlet": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz", - "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "requires": { - "mime-db": "1.51.0" - } - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } -} diff --git a/scripts/stresstest/package.json b/scripts/stresstest/package.json deleted file mode 100644 index 8d94d05b..00000000 --- a/scripts/stresstest/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "stresstest", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "node ." - }, - "author": "", - "license": "ISC", - "dependencies": { - "figlet": "^1.5.2", - "node-fetch": "^2.6.6", - "request": "^2.88.2" - } -} diff --git a/scripts/stresstest/src/login/index.js b/scripts/stresstest/src/login/index.js deleted file mode 100644 index 128a477b..00000000 --- a/scripts/stresstest/src/login/index.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -const fetch = require("node-fetch"); -const fs = require("fs"); -var config = require("../../config.json"); -module.exports = login; -async function login(account) { - var body = { - fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw", - login: account.email, - password: account.password, - }; - var x = await fetch(config.url + "/auth/login", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(body), - }); - console.log(x); - x = await x.json(); - console.log(x); - return x; -} diff --git a/scripts/stresstest/src/message/send.js b/scripts/stresstest/src/message/send.js deleted file mode 100644 index ca6af62c..00000000 --- a/scripts/stresstest/src/message/send.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -const fetch = require("node-fetch"); -const fs = require("fs"); -var config = require("../../config.json"); -module.exports = sendMessage; -async function sendMessage(account) { - var body = { - fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw", - content: "Test", - tts: false, - }; - var x = await fetch( - config.url + "/channels/" + config["text-channel"] + "/messages", - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: account.token, - }, - body: JSON.stringify(body), - }, - ); - console.log(x); - x = await x.json(); - console.log(x); - return x; -} diff --git a/scripts/stresstest/src/register/index.js b/scripts/stresstest/src/register/index.js deleted file mode 100644 index f085386f..00000000 --- a/scripts/stresstest/src/register/index.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/* eslint-env node */ - -const fetch = require("node-fetch"); -const fs = require("fs"); -var config = require("../../config.json"); -module.exports = generate; -async function generate() { - var mail = (Math.random() + 10).toString(36).substring(2); - mail = - mail + - "." + - (Math.random() + 10).toString(36).substring(2) + - "@stresstest.com"; - var password = - (Math.random() * 69).toString(36).substring(-7) + - (Math.random() * 69).toString(36).substring(-7) + - (Math.random() * 69).toString(36).substring(-8); - console.log(mail); - console.log(password); - var body = { - fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw", - email: mail, - username: "Spacebar Stress Test", - password: password, - invite: config.invite, - consent: true, - date_of_birth: "2000-04-04", - gift_code_sku_id: null, - captcha_key: null, - }; - var x = await fetch(config.url + "/auth/register", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(body), - }); - console.log(x); - x = await x.json(); - console.log(x); - return { email: mail, password: password }; -} From 5771552408898a3c33a7432a207fcfa51ad5f5df Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 12 Apr 2023 20:43:49 +1000 Subject: [PATCH 56/58] Set eslint env properly --- .eslintrc | 3 +++ scripts/changelog.js | 2 -- scripts/license.js | 2 -- scripts/openapi.js | 2 -- scripts/rights.js | 2 -- scripts/schema.js | 2 -- scripts/syncronise.js | 2 -- 7 files changed, 3 insertions(+), 12 deletions(-) diff --git a/.eslintrc b/.eslintrc index 00ce9892..40eac134 100644 --- a/.eslintrc +++ b/.eslintrc @@ -7,5 +7,8 @@ "no-mixed-spaces-and-tabs": "off", "@typescript-eslint/no-inferrable-types": "off", // Required by typeorm "@typescript-eslint/no-var-requires": "off" // Sometimes requred by typeorm to resolve circular deps + }, + "env": { + "node": true } } diff --git a/scripts/changelog.js b/scripts/changelog.js index f6329a46..658193ba 100644 --- a/scripts/changelog.js +++ b/scripts/changelog.js @@ -26,8 +26,6 @@ This grabs the new changelog from `spacebarchat/server/assets/changelog.txt` */ -/* eslint-env node */ - const fetch = require("node-fetch"); const fs = require("fs/promises"); const path = require("path"); diff --git a/scripts/license.js b/scripts/license.js index d36165bb..b12080dd 100644 --- a/scripts/license.js +++ b/scripts/license.js @@ -5,8 +5,6 @@ Does not prepend is file contains @fc-license-skip */ -/* eslint-env node */ - const Path = require("path"); const fs = require("fs"); const walk = require("./util/walk"); diff --git a/scripts/openapi.js b/scripts/openapi.js index b5001829..49d5dfde 100644 --- a/scripts/openapi.js +++ b/scripts/openapi.js @@ -16,8 +16,6 @@ along with this program. If not, see . */ -/* eslint-env node */ - require("module-alias/register"); const getRouteDescriptions = require("./util/getRouteDescriptions"); const path = require("path"); diff --git a/scripts/rights.js b/scripts/rights.js index 148570eb..bf79ef79 100644 --- a/scripts/rights.js +++ b/scripts/rights.js @@ -20,8 +20,6 @@ Calculates a discord.com-like rights value. */ -/* eslint-env node */ - require("module-alias/register"); const { Rights } = require(".."); diff --git a/scripts/schema.js b/scripts/schema.js index 2a19ea26..c29d5bab 100644 --- a/scripts/schema.js +++ b/scripts/schema.js @@ -20,8 +20,6 @@ Regenerates the `spacebarchat/server/assets/schemas.json` file, used for API/Gateway input validation. */ -/* eslint-env node */ - const path = require("path"); const fs = require("fs"); const TJS = require("typescript-json-schema"); diff --git a/scripts/syncronise.js b/scripts/syncronise.js index 5f6987c3..34cd0ddd 100644 --- a/scripts/syncronise.js +++ b/scripts/syncronise.js @@ -25,8 +25,6 @@ it doesn't break the below, thus we're left with this :sob: */ -/* eslint-env node */ - require("module-alias/register"); require("dotenv").config(); const { initDatabase } = require(".."); From 9a6390b9bdbb6eb7e3ea6360619a2879ce42cbe1 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 12 Apr 2023 21:03:49 +1000 Subject: [PATCH 57/58] Fix DC client throwing on GUILD_CREATE --- src/util/dtos/ReadyGuildDTO.ts | 15 +++++++++++---- src/util/entities/Member.ts | 26 +++++++++++++++++--------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/util/dtos/ReadyGuildDTO.ts b/src/util/dtos/ReadyGuildDTO.ts index 2a99ea46..b21afe74 100644 --- a/src/util/dtos/ReadyGuildDTO.ts +++ b/src/util/dtos/ReadyGuildDTO.ts @@ -16,7 +16,14 @@ along with this program. If not, see . */ -import { Channel, Emoji, Guild, Member, Role, Sticker } from "../entities"; +import { + Channel, + Emoji, + Guild, + PublicMember, + Role, + Sticker, +} from "../entities"; export interface IReadyGuildDTO { application_command_counts?: { 1: number; 2: number; 3: number }; // ???????????? @@ -28,7 +35,7 @@ export interface IReadyGuildDTO { large: boolean | undefined; lazy: boolean; member_count: number | undefined; - members: Member[]; + members: PublicMember[]; premium_subscription_count: number | undefined; properties: { name: string; @@ -76,7 +83,7 @@ export class ReadyGuildDTO implements IReadyGuildDTO { large: boolean | undefined; lazy: boolean; member_count: number | undefined; - members: Member[]; + members: PublicMember[]; premium_subscription_count: number | undefined; properties: { name: string; @@ -127,7 +134,7 @@ export class ReadyGuildDTO implements IReadyGuildDTO { this.large = guild.large; this.lazy = true; // ?????????? this.member_count = guild.member_count; - this.members = guild.members; + this.members = guild.members?.map((x) => x.toPublicMember()); this.premium_subscription_count = guild.premium_subscription_count; this.properties = { name: guild.name, diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index cc2bf2a1..8c208202 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -330,17 +330,25 @@ export class Member extends BaseClassWithoutId { }); const memberCount = await Member.count({ where: { guild_id } }); - const memberPreview = await Member.find({ - where: { - guild_id, - user: { - sessions: { - status: Not("invisible" as const), // lol typescript? + + const memberPreview = ( + await Member.find({ + where: { + guild_id, + user: { + sessions: { + status: Not("invisible" as const), // lol typescript? + }, }, }, - }, - take: 10, - }); + relations: ["user", "roles"], + take: 10, + }) + ).map((member) => ({ + ...member.toPublicMember(), + user: member.user.toPublicUser(), + roles: member.roles.map((x) => x.id), + })); if ( await Member.count({ From 174d34c376a6a94c88b163cf46f76f2b6e52e633 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 12 Apr 2023 21:22:09 +1000 Subject: [PATCH 58/58] fix style action --- .github/workflows/style.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 931449b7..4fd62bae 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -23,5 +23,6 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: 'npm' + - run: npm i --only=dev - run: npx eslint . - run: npx prettier --check . \ No newline at end of file