From 1de0dbe50942803c00eff92dd695694db4a771f3 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:36:25 +0100 Subject: build: update dependencies --- src/api/middlewares/Translation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/api/middlewares/Translation.ts b/src/api/middlewares/Translation.ts index 928d29ff..999d42a3 100644 --- a/src/api/middlewares/Translation.ts +++ b/src/api/middlewares/Translation.ts @@ -20,7 +20,7 @@ import fs from "fs"; import path from "path"; import i18next from "i18next"; import i18nextMiddleware from "i18next-http-middleware"; -import i18nextBackend from "i18next-node-fs-backend"; +import i18nextBackend from "i18next-fs-backend"; import { Router } from "express"; const ASSET_FOLDER_PATH = path.join(__dirname, "..", "..", "..", "assets"); -- cgit 1.4.1 From 5b6b97e86c77b7ce0df1da7eb1c75b7989b028a1 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:36:44 +0100 Subject: fix: types when using yarn --- .gitignore | 4 ++++ src/util/schemas/Validator.ts | 2 +- src/util/util/index.ts | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/.gitignore b/.gitignore index bc780d64..9ac5d944 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,10 @@ assets/cache .env config.json assets/cacheMisses +assets/client_test +scripts/client.js +src/api/middlewares/TestClient.ts +yarn.lock .vscode/settings.json diff --git a/src/util/schemas/Validator.ts b/src/util/schemas/Validator.ts index 3190dd05..7ddd9b72 100644 --- a/src/util/schemas/Validator.ts +++ b/src/util/schemas/Validator.ts @@ -43,7 +43,7 @@ export const ajv = new Ajv({ allowUnionTypes: true, }); -addFormats(ajv); +addFormats(ajv as never); export function validateSchema(schema: string, data: G): G { const valid = ajv.validate(schema, normalizeBody(data)); diff --git a/src/util/util/index.ts b/src/util/util/index.ts index 93656ecb..fa9dd326 100644 --- a/src/util/util/index.ts +++ b/src/util/util/index.ts @@ -24,7 +24,7 @@ export * from "./cdn"; export * from "./Config"; export * from "./Constants"; export * from "./Database"; -export * from "./email"; +export * from "./email/index"; export * from "./Event"; export * from "./FieldError"; export * from "./Intents"; -- cgit 1.4.1 From 810f5dd84cab8249f90276ce3acde5ffe6938c8d Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:47:43 +0100 Subject: perf: cache jwt secret as key --- src/api/Server.ts | 8 ++++++-- src/api/middlewares/Authentication.ts | 17 +++++++++++++---- src/util/util/Token.ts | 3 ++- 3 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/api/Server.ts b/src/api/Server.ts index 49229494..ced82dce 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts @@ -32,7 +32,7 @@ import "missing-native-js-functions"; import morgan from "morgan"; import path from "path"; import { red } from "picocolors"; -import { Authentication, CORS } from "./middlewares/"; +import { CORS, initAuthentication } from "./middlewares/"; import { BodyParser } from "./middlewares/BodyParser"; import { ErrorHandler } from "./middlewares/ErrorHandler"; import { initRateLimits } from "./middlewares/RateLimit"; @@ -97,7 +97,7 @@ export class FosscordServer extends Server { // @ts-ignore this.app = api; - api.use(Authentication); + initAuthentication(api); await initRateLimits(api); await initTranslation(api); @@ -126,6 +126,10 @@ export class FosscordServer extends Server { app.use("/api/v9", api); app.use("/api", api); // allow unversioned requests + try { + require("./middlewares/TestClient").default(this.app); + // eslint-disable-next-line no-empty + } catch (error) {} this.app.use(ErrorHandler); Sentry.errorHandler(this.app); diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts index 771f0de8..e6e2f59a 100644 --- a/src/api/middlewares/Authentication.ts +++ b/src/api/middlewares/Authentication.ts @@ -18,8 +18,9 @@ import { checkToken, Config, Rights } from "@fosscord/util"; import * as Sentry from "@sentry/node"; -import { NextFunction, Request, Response } from "express"; +import { NextFunction, Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; +import { createSecretKey, KeyObject } from "crypto"; export const NO_AUTHORIZATION_ROUTES = [ // Authentication routes @@ -69,6 +70,16 @@ declare global { } } +let jwtPublicKey: KeyObject; + +// Initialize the jwt secret as a key object so it does not need to be regenerated for each request. +export function initAuthentication(api: Router) { + jwtPublicKey = createSecretKey( + Buffer.from(Config.get().security.jwtSecret), + ); + api.use(Authentication); +} + export async function Authentication( req: Request, res: Response, @@ -90,11 +101,9 @@ export async function Authentication( Sentry.setUser({ id: req.user_id }); try { - const { jwtSecret } = Config.get().security; - const { decoded, user } = await checkToken( req.headers.authorization, - jwtSecret, + jwtPublicKey, ); req.token = decoded; diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts index ffc442aa..67e4b879 100644 --- a/src/util/util/Token.ts +++ b/src/util/util/Token.ts @@ -19,6 +19,7 @@ import jwt, { VerifyOptions } from "jsonwebtoken"; import { Config } from "./Config"; import { User } from "../entities"; +import { KeyObject } from "crypto"; export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] }; @@ -62,7 +63,7 @@ async function checkEmailToken( export function checkToken( token: string, - jwtSecret: string, + jwtSecret: string | KeyObject, isEmailVerification = false, ): Promise { return new Promise((res, rej) => { -- cgit 1.4.1 From d086c053bbfb50a24403a270ce8d45f04ef000b7 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:49:12 +0100 Subject: perf: custom i18next middleware that only initializes when needed --- package.json | 1 - src/api/middlewares/Translation.ts | 56 ++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/package.json b/package.json index 5578849a..03cc7981 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,6 @@ "form-data": "^4.0.0", "i18next": "^22.4.12", "i18next-fs-backend": "^2.1.1", - "i18next-http-middleware": "^3.2.1", "image-size": "^1.0.2", "json-bigint": "^1.0.0", "jsonwebtoken": "^9.0.0", diff --git a/src/api/middlewares/Translation.ts b/src/api/middlewares/Translation.ts index 999d42a3..bf6ea034 100644 --- a/src/api/middlewares/Translation.ts +++ b/src/api/middlewares/Translation.ts @@ -18,11 +18,20 @@ import fs from "fs"; import path from "path"; -import i18next from "i18next"; -import i18nextMiddleware from "i18next-http-middleware"; +import i18next, { TFunction } from "i18next"; import i18nextBackend from "i18next-fs-backend"; import { Router } from "express"; +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Express { + interface Request { + t: TFunction; + language?: string; + } + } +} + const ASSET_FOLDER_PATH = path.join(__dirname, "..", "..", "..", "assets"); export async function initTranslation(router: Router) { @@ -34,21 +43,32 @@ export async function initTranslation(router: Router) { .filter((x) => x.endsWith(".json")) .map((x) => x.slice(0, x.length - 5)); - await i18next - .use(i18nextBackend) - .use(i18nextMiddleware.LanguageDetector) - .init({ - preload: languages, - // debug: true, - fallbackLng: "en", - ns, - backend: { - loadPath: - path.join(ASSET_FOLDER_PATH, "locales") + - "/{{lng}}/{{ns}}.json", - }, - load: "all", - }); + await i18next.use(i18nextBackend).init({ + preload: languages, + // debug: true, + fallbackLng: "en", + ns, + backend: { + loadPath: + path.join(ASSET_FOLDER_PATH, "locales") + + "/{{lng}}/{{ns}}.json", + }, + load: "all", + }); - router.use(i18nextMiddleware.handle(i18next, {})); + router.use((req, res, next) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + req.t = (key: string | string[], options?: any) => { + let lng = "en"; + if (req.headers["accept-language"]) { + lng = req.headers["accept-language"].split(",")[0]; + } + req.language = lng; + return i18next.t(key, { + ...options, + lng, + }); + }; + next(); + }); } -- cgit 1.4.1 From 197f1aacd2dad264cf0cb415efeb57d1ea08c849 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:18:31 +0100 Subject: feat: better-sqlite3 support --- package.json | 1 + src/util/util/Database.ts | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/package.json b/package.json index 03cc7981..101a5f53 100644 --- a/package.json +++ b/package.json @@ -112,6 +112,7 @@ "@fosscord/util": "dist/util" }, "optionalDependencies": { + "better-sqlite3": "^8.2.0", "erlpack": "^0.1.4", "nodemailer-mailgun-transport": "^2.1.5", "nodemailer-mailjet-transport": "github:n0script22/nodemailer-mailjet-transport", diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts index 64d7ca14..e625ea9b 100644 --- a/src/util/util/Database.ts +++ b/src/util/util/Database.ts @@ -36,9 +36,17 @@ if (!process.env) { const dbConnectionString = process.env.DATABASE || path.join(process.cwd(), "database.db"); -const DatabaseType = dbConnectionString.includes("://") +let DatabaseType = dbConnectionString.includes("://") ? dbConnectionString.split(":")[0]?.replace("+srv", "") : "sqlite"; + +if (DatabaseType === "sqlite") { + try { + require("better-sqlite3"); + DatabaseType = "better-sqlite3"; + // eslint-disable-next-line no-empty + } catch (error) {} +} const isSqlite = DatabaseType.includes("sqlite"); const DataSourceOptions = new DataSource({ @@ -55,6 +63,7 @@ const DataSourceOptions = new DataSource({ supportBigNumbers: true, name: "default", migrations: [path.join(__dirname, "..", "migration", DatabaseType, "*.js")], + cache: true, }); // Gets the existing database connection @@ -77,7 +86,13 @@ export async function initDatabase(): Promise { } if (!process.env.DB_SYNC) { - const supported = ["mysql", "mariadb", "postgres", "sqlite"]; + const supported = [ + "mysql", + "mariadb", + "postgres", + "sqlite", + "better-sqlite3", + ]; if (!supported.includes(DatabaseType)) { console.log( "[Database]" + -- cgit 1.4.1 From 5ba7c6b5bc87d5874de881f675ad92811837aaac Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:18:57 +0100 Subject: perf: optimize getPermission() --- src/util/util/Permissions.ts | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/util/util/Permissions.ts b/src/util/util/Permissions.ts index 996c72ea..4aeb9268 100644 --- a/src/util/util/Permissions.ts +++ b/src/util/util/Permissions.ts @@ -257,23 +257,26 @@ export async function getPermission( } if (guild_id) { - guild = await Guild.findOneOrFail({ - where: { id: guild_id }, - select: ["id", "owner_id", ...(opts.guild_select || [])], - relations: opts.guild_relations, - }); + const result = await Promise.all([ + Guild.findOneOrFail({ + where: { id: guild_id }, + select: ["id", "owner_id", ...(opts.guild_select || [])], + relations: opts.guild_relations, + }), + Member.findOneOrFail({ + where: { guild_id, id: user_id }, + relations: ["roles", ...(opts.member_relations || [])], + // select: [ + // "id", // TODO: Bug in typeorm? adding these selects breaks the query. + // "roles", + // ...(opts.member_select || []), + // ], + }), + ]); + guild = result[0]; + member = result[1]; if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR); - - member = await Member.findOneOrFail({ - where: { guild_id, id: user_id }, - relations: ["roles", ...(opts.member_relations || [])], - // select: [ - // "id", // TODO: Bug in typeorm? adding these selects breaks the query. - // "roles", - // ...(opts.member_select || []), - // ], - }); } let recipient_ids = channel?.recipients?.map((x) => x.user_id); -- cgit 1.4.1 From cae6fcc72a61608d594b3a7c3077c8e01a0b5045 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:30:54 +0100 Subject: fix: request language property --- src/api/middlewares/Translation.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/api/middlewares/Translation.ts b/src/api/middlewares/Translation.ts index bf6ea034..0e292962 100644 --- a/src/api/middlewares/Translation.ts +++ b/src/api/middlewares/Translation.ts @@ -57,13 +57,14 @@ export async function initTranslation(router: Router) { }); router.use((req, res, next) => { + let lng = "en"; + if (req.headers["accept-language"]) { + lng = req.headers["accept-language"].split(",")[0]; + } + req.language = lng; + // eslint-disable-next-line @typescript-eslint/no-explicit-any req.t = (key: string | string[], options?: any) => { - let lng = "en"; - if (req.headers["accept-language"]) { - lng = req.headers["accept-language"].split(",")[0]; - } - req.language = lng; return i18next.t(key, { ...options, lng, -- cgit 1.4.1 From 2e473576cf765f5c5e83888056c889d0da43e7fc Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:47:23 +0100 Subject: wip: cache --- src/util/util/Cache.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ src/util/util/Database.ts | 1 - 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/util/util/Cache.ts (limited to 'src') diff --git a/src/util/util/Cache.ts b/src/util/util/Cache.ts new file mode 100644 index 00000000..44839a65 --- /dev/null +++ b/src/util/util/Cache.ts @@ -0,0 +1,42 @@ +/* eslint-disable */ +import { DataSource, QueryRunner } from "typeorm"; +import { QueryResultCache } from "typeorm/cache/QueryResultCache"; +import { QueryResultCacheOptions } from "typeorm/cache/QueryResultCacheOptions"; + +export class CustomQueryResultCache implements QueryResultCache { + constructor(private dataSource: DataSource) {} + connect(): Promise { + throw new Error("Method not implemented."); + } + disconnect(): Promise { + throw new Error("Method not implemented."); + } + synchronize(queryRunner?: QueryRunner | undefined): Promise { + throw new Error("Method not implemented."); + } + getFromCache( + options: QueryResultCacheOptions, + queryRunner?: QueryRunner | undefined, + ): Promise { + throw new Error("Method not implemented."); + } + storeInCache( + options: QueryResultCacheOptions, + savedCache: QueryResultCacheOptions | undefined, + queryRunner?: QueryRunner | undefined, + ): Promise { + throw new Error("Method not implemented."); + } + isExpired(savedCache: QueryResultCacheOptions): boolean { + throw new Error("Method not implemented."); + } + clear(queryRunner?: QueryRunner | undefined): Promise { + throw new Error("Method not implemented."); + } + remove( + identifiers: string[], + queryRunner?: QueryRunner | undefined, + ): Promise { + throw new Error("Method not implemented."); + } +} diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts index e625ea9b..5c5c8b4c 100644 --- a/src/util/util/Database.ts +++ b/src/util/util/Database.ts @@ -63,7 +63,6 @@ const DataSourceOptions = new DataSource({ supportBigNumbers: true, name: "default", migrations: [path.join(__dirname, "..", "migration", DatabaseType, "*.js")], - cache: true, }); // Gets the existing database connection -- cgit 1.4.1 From 366c4935a42d5056c51cdbd7c82c2674f1b8b128 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Sat, 18 Mar 2023 04:11:48 +0100 Subject: feat: Database Query Cache --- src/util/cache/Cache.ts | 85 +++++++++++++++ src/util/cache/EntityCache.ts | 160 ++++++++++++++++++++++++++++ src/util/cache/LocalCache.ts | 91 ++++++++++++++++ src/util/cache/index.ts | 3 + src/util/config/Config.ts | 2 + src/util/config/types/CacheConfiguration.ts | 22 ++++ src/util/config/types/index.ts | 1 + src/util/entities/Application.ts | 4 +- src/util/entities/Attachment.ts | 4 +- src/util/entities/AuditLog.ts | 4 +- src/util/entities/BackupCodes.ts | 4 +- src/util/entities/Ban.ts | 4 +- src/util/entities/BaseClass.ts | 44 ++++---- src/util/entities/Channel.ts | 4 +- src/util/entities/ClientRelease.ts | 4 +- src/util/entities/ConnectedAccount.ts | 4 +- src/util/entities/EmbedCache.ts | 4 +- src/util/entities/Emoji.ts | 4 +- src/util/entities/Encryption.ts | 4 +- src/util/entities/Guild.ts | 4 +- src/util/entities/Message.ts | 4 +- src/util/entities/Note.ts | 4 +- src/util/entities/RateLimit.ts | 4 +- src/util/entities/ReadState.ts | 4 +- src/util/entities/Recipient.ts | 4 +- src/util/entities/Relationship.ts | 4 +- src/util/entities/Role.ts | 4 +- src/util/entities/SecurityKey.ts | 4 +- src/util/entities/Session.ts | 4 +- src/util/entities/Sticker.ts | 4 +- src/util/entities/StickerPack.ts | 4 +- src/util/entities/Team.ts | 4 +- src/util/entities/TeamMember.ts | 4 +- src/util/entities/Template.ts | 4 +- src/util/entities/User.ts | 4 +- src/util/entities/VoiceState.ts | 4 +- src/util/entities/Webhook.ts | 4 +- src/util/util/Cache.ts | 42 -------- 38 files changed, 442 insertions(+), 124 deletions(-) create mode 100644 src/util/cache/Cache.ts create mode 100644 src/util/cache/EntityCache.ts create mode 100644 src/util/cache/LocalCache.ts create mode 100644 src/util/cache/index.ts create mode 100644 src/util/config/types/CacheConfiguration.ts delete mode 100644 src/util/util/Cache.ts (limited to 'src') diff --git a/src/util/cache/Cache.ts b/src/util/cache/Cache.ts new file mode 100644 index 00000000..fb66c2e3 --- /dev/null +++ b/src/util/cache/Cache.ts @@ -0,0 +1,85 @@ +/* + Fosscord: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Fosscord and Fosscord 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/ban-ts-comment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { EntityMetadata, FindOptionsWhere } from "typeorm"; +import { LocalCache } from "./LocalCache"; + +declare module "typeorm" { + interface BaseEntity { + metadata?: EntityMetadata; + cache: CacheManager; + } +} + +export type BaseEntityWithId = { id: string; [name: string]: any }; +export type Criteria = + | string + | string[] + | number + | number[] + | FindOptionsWhere; + +export interface Cache { + get(id: string): BaseEntityWithId | undefined; + set(id: string, entity: BaseEntityWithId): this; + find(options: Record): BaseEntityWithId | undefined; + filter(options: Record): BaseEntityWithId[]; + delete(id: string): boolean; +} + +export class CacheManager { + // last access time to automatically remove old entities from cache after 5 minutes of inactivity (to prevent memory leaks) + cache: Cache; + + constructor() { + this.cache = new LocalCache(); + // TODO: Config.get().cache.redis; + } + + delete(id: string) { + return this.cache.delete(id); + } + + insert(entity: BaseEntityWithId) { + if (!entity.id) return; + + return this.cache.set(entity.id, entity); + } + + find(options?: Record, select?: string[] | undefined) { + if (!options) return null; + const entity = this.cache.find(options); + if (!entity) return null; + if (!select) return entity; + + const result = {}; + for (const prop of select) { + // @ts-ignore + result[prop] = entity[prop]; + } + + // @ts-ignore + return entity.constructor.create(result); + } + + filter(options: Record) { + return this.cache.filter(options); + } +} diff --git a/src/util/cache/EntityCache.ts b/src/util/cache/EntityCache.ts new file mode 100644 index 00000000..9135fef3 --- /dev/null +++ b/src/util/cache/EntityCache.ts @@ -0,0 +1,160 @@ +/* + Fosscord: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Fosscord and Fosscord 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 */ +import { + DataSource, + FindOneOptions, + EntityNotFoundError, + FindOptionsWhere, +} from "typeorm"; +import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity"; +import { BaseClassWithId } from "../entities/BaseClass"; +import { Config, getDatabase } from "../util"; +import { CacheManager } from "./Cache"; + +function getObjectKeysAsArray(obj?: Record) { + if (!obj) return []; + if (Array.isArray(obj)) return obj; + return Object.keys(obj); +} + +export type ThisType = { + new (): T; +} & typeof BaseEntityCache; + +interface BaseEntityCache { + constructor: typeof BaseEntityCache; +} + +// @ts-ignore +class BaseEntityCache extends BaseClassWithId { + static cache: CacheManager; + static cacheEnabled: boolean; + + public get metadata() { + return getDatabase()?.getMetadata(this.constructor)!; + } + + static useDataSource(dataSource: DataSource | null) { + super.useDataSource(dataSource); + this.cacheEnabled = Config.get().cache.enabled ?? true; + if (Config.get().cache.redis) return; // TODO: Redis cache + if (!this.cacheEnabled) return; + this.cache = new CacheManager(); + } + + static async findOne( + this: ThisType, + options: FindOneOptions, + ) { + // @ts-ignore + if (!this.cacheEnabled) return super.findOne(options); + let select = getObjectKeysAsArray(options.select); + + if (!select.length) { + // get all columns that are marked as select + getDatabase() + ?.getMetadata(this) + .columns.forEach((x) => { + if (!x.isSelect) return; + select.push(x.propertyName); + }); + } + if (options.relations) { + select.push(...getObjectKeysAsArray(options.relations)); + } + + const cacheResult = this.cache.find(options.where as never, select); + if (cacheResult) { + const hasAllProps = select.every((key) => { + if (key.includes(".")) return true; // @ts-ignore + return cacheResult[key] !== undefined; + }); + // console.log(`[Cache] get ${cacheResult.id} from ${cacheResult.constructor.name}`,); + if (hasAllProps) return cacheResult; + } + + // @ts-ignore + const result = await super.findOne(options); + if (!result) return null; + + this.cache.insert(result as any); + + return result; + } + + static async findOneOrFail( + this: ThisType, + options: FindOneOptions, + ) { + const result = await this.findOne(options); + if (!result) throw new EntityNotFoundError(this, options); + return result; + } + + save() { + if (this.constructor.cacheEnabled) this.constructor.cache.insert(this); + return super.save(); + } + + remove() { + if (this.constructor.cacheEnabled) + this.constructor.cache.delete(this.id); + return super.remove(); + } + + static async update( + this: ThisType, + criteria: FindOptionsWhere, + partialEntity: QueryDeepPartialEntity, + ) { + // @ts-ignore + const result = super.update(criteria, partialEntity); + if (!this.cacheEnabled) return result; + + const entities = this.cache.filter(criteria as never); + for (const entity of entities) { + // @ts-ignore + partialEntity.id = entity.id; + this.cache.insert(partialEntity as never); + } + + return result; + } + + static async delete( + this: ThisType, + criteria: FindOptionsWhere, + ) { + // @ts-ignore + const result = super.delete(criteria); + if (!this.cacheEnabled) return result; + + const entities = this.cache.filter(criteria as never); + for (const entity of entities) { + this.cache.delete(entity.id); + } + + return result; + } +} + +// needed, because typescript can't infer the type of the static methods with generics +const EntityCache = BaseEntityCache as unknown as typeof BaseClassWithId; + +export { EntityCache }; diff --git a/src/util/cache/LocalCache.ts b/src/util/cache/LocalCache.ts new file mode 100644 index 00000000..547899ac --- /dev/null +++ b/src/util/cache/LocalCache.ts @@ -0,0 +1,91 @@ +/* + Fosscord: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Fosscord and Fosscord 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/ban-ts-comment */ +import { BaseEntityWithId, Cache } from "./Cache"; + +export const cacheTimeout = 1000 * 60 * 5; + +export class LocalCache extends Map implements Cache { + last_access = new Map(); + + constructor() { + super(); + + setInterval(() => { + const now = Date.now(); + for (const [key, value] of this.last_access) { + if (now - value > cacheTimeout) { + this.delete(key); + this.last_access.delete(key); + } + } + }, cacheTimeout); + } + + set(key: string, value: BaseEntityWithId): this { + this.last_access.set(key, Date.now()); + if (this.has(key)) this.update(key, value); + return super.set(key, value as never); + } + + get(key: string) { + const value = super.get(key); + if (value) this.last_access.set(key, Date.now()); + return value; + } + + update(id: string, entity: BaseEntityWithId) { + const oldEntity = this.get(id); + if (!oldEntity) return; + for (const key in entity) { + // @ts-ignore + if (entity[key] === undefined) continue; // @ts-ignore + oldEntity[key] = entity[key]; + } + } + + find(options: Record): BaseEntityWithId | undefined { + if (options.id && Object.keys(options).length === 1) { + return this.get(options.id); + } + for (const entity of this.values()) { + if (objectFulfillsQuery(entity, options)) return entity; + } + } + + filter(options: Record): BaseEntityWithId[] { + const result = []; + for (const entity of this.values()) { + if (objectFulfillsQuery(entity, options)) { + result.push(entity); + } + } + return result; + } +} + +function objectFulfillsQuery( + entity: BaseEntityWithId, + options: Record, +) { + for (const key in options) { + // @ts-ignore + if (entity[key] !== options[key]) return false; + } + return true; +} diff --git a/src/util/cache/index.ts b/src/util/cache/index.ts new file mode 100644 index 00000000..43f0aa96 --- /dev/null +++ b/src/util/cache/index.ts @@ -0,0 +1,3 @@ +export * from "./EntityCache"; +export * from "./Cache"; +export * from "./LocalCache"; diff --git a/src/util/config/Config.ts b/src/util/config/Config.ts index f130e760..3cd18d3d 100644 --- a/src/util/config/Config.ts +++ b/src/util/config/Config.ts @@ -37,6 +37,7 @@ import { SecurityConfiguration, SentryConfiguration, TemplateConfiguration, + CacheConfiguration, } from "../config"; export class ConfigValue { @@ -61,4 +62,5 @@ export class ConfigValue { email: EmailConfiguration = new EmailConfiguration(); passwordReset: PasswordResetConfiguration = new PasswordResetConfiguration(); + cache: CacheConfiguration = new CacheConfiguration(); } diff --git a/src/util/config/types/CacheConfiguration.ts b/src/util/config/types/CacheConfiguration.ts new file mode 100644 index 00000000..4178090e --- /dev/null +++ b/src/util/config/types/CacheConfiguration.ts @@ -0,0 +1,22 @@ +/* + Fosscord: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Fosscord and Fosscord 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 CacheConfiguration { + enabled: boolean | null = true; + redis: string | null = null; +} diff --git a/src/util/config/types/index.ts b/src/util/config/types/index.ts index cd3335e0..03cc2e8b 100644 --- a/src/util/config/types/index.ts +++ b/src/util/config/types/index.ts @@ -17,6 +17,7 @@ */ export * from "./ApiConfiguration"; +export * from "./CacheConfiguration"; export * from "./CdnConfiguration"; export * from "./DefaultsConfiguration"; export * from "./EmailConfiguration"; diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts index 94709320..5613109e 100644 --- a/src/util/entities/Application.ts +++ b/src/util/entities/Application.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Team } from "./Team"; import { User } from "./User"; @Entity("applications") -export class Application extends BaseClass { +export class Application extends EntityCache { @Column() name: string; diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts index fdc1b3f1..da879fad 100644 --- a/src/util/entities/Attachment.ts +++ b/src/util/entities/Attachment.ts @@ -25,11 +25,11 @@ import { RelationId, } from "typeorm"; import { URL } from "url"; +import { EntityCache } from "../cache"; import { deleteFile } from "../util/cdn"; -import { BaseClass } from "./BaseClass"; @Entity("attachments") -export class Attachment extends BaseClass { +export class Attachment extends EntityCache { @Column() filename: string; // name of file attached diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts index 0cc2fc04..0c10c6f0 100644 --- a/src/util/entities/AuditLog.ts +++ b/src/util/entities/AuditLog.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { ChannelPermissionOverwrite } from "./Channel"; import { User } from "./User"; @@ -112,7 +112,7 @@ export enum AuditLogEvents { } @Entity("audit_logs") -export class AuditLog extends BaseClass { +export class AuditLog extends EntityCache { @JoinColumn({ name: "target_id" }) @ManyToOne(() => User) target?: User; diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts index 467e1fe3..d6a38a63 100644 --- a/src/util/entities/BackupCodes.ts +++ b/src/util/entities/BackupCodes.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; import crypto from "crypto"; @Entity("backup_codes") -export class BackupCode extends BaseClass { +export class BackupCode extends EntityCache { @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, { onDelete: "CASCADE" }) user: User; diff --git a/src/util/entities/Ban.ts b/src/util/entities/Ban.ts index 4ed6e201..7accc153 100644 --- a/src/util/entities/Ban.ts +++ b/src/util/entities/Ban.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; import { User } from "./User"; @Entity("bans") -export class Ban extends BaseClass { +export class Ban extends EntityCache { @Column({ nullable: true }) @RelationId((ban: Ban) => ban.user) user_id: string; diff --git a/src/util/entities/BaseClass.ts b/src/util/entities/BaseClass.ts index 445b3fc9..87b394c5 100644 --- a/src/util/entities/BaseClass.ts +++ b/src/util/entities/BaseClass.ts @@ -25,16 +25,12 @@ import { PrimaryColumn, } from "typeorm"; import { Snowflake } from "../util/Snowflake"; -import { getDatabase } from "../util/Database"; import { OrmUtils } from "../imports/OrmUtils"; +import { getDatabase } from "../util"; export class BaseClassWithoutId extends BaseEntity { - private get construct() { - return this.constructor; - } - - private get metadata() { - return getDatabase()?.getMetadata(this.construct); + public get metadata() { + return getDatabase()?.getMetadata(this.constructor); } assign(props: object) { @@ -61,8 +57,23 @@ export class BaseClassWithoutId extends BaseEntity { ), ); } +} + +export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") + ? ObjectIdColumn + : PrimaryColumn; + +export class BaseClassWithId extends BaseClassWithoutId { + @PrimaryIdColumn() + id: string = Snowflake.generate(); + + @BeforeUpdate() + @BeforeInsert() + _do_validate() { + if (!this.id) this.id = Snowflake.generate(); + } - static increment( + static increment( conditions: FindOptionsWhere, propertyPath: string, value: number | string, @@ -71,7 +82,7 @@ export class BaseClassWithoutId extends BaseEntity { return repository.increment(conditions, propertyPath, value); } - static decrement( + static decrement( conditions: FindOptionsWhere, propertyPath: string, value: number | string, @@ -80,18 +91,3 @@ export class BaseClassWithoutId extends BaseEntity { return repository.decrement(conditions, propertyPath, value); } } - -export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") - ? ObjectIdColumn - : PrimaryColumn; - -export class BaseClass extends BaseClassWithoutId { - @PrimaryIdColumn() - id: string = Snowflake.generate(); - - @BeforeUpdate() - @BeforeInsert() - _do_validate() { - if (!this.id) this.id = Snowflake.generate(); - } -} diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 1f128713..1cad928b 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -24,7 +24,7 @@ import { OneToMany, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; import { PublicUserProjection, User } from "./User"; import { HTTPError } from "lambert-server"; @@ -70,7 +70,7 @@ export enum ChannelType { } @Entity("channels") -export class Channel extends BaseClass { +export class Channel extends EntityCache { @Column() created_at: Date; diff --git a/src/util/entities/ClientRelease.ts b/src/util/entities/ClientRelease.ts index 4b8150fd..57710194 100644 --- a/src/util/entities/ClientRelease.ts +++ b/src/util/entities/ClientRelease.ts @@ -17,10 +17,10 @@ */ import { Column, Entity } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("client_release") -export class Release extends BaseClass { +export class Release extends EntityCache { @Column() name: string; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 9f0ce35e..dabdb944 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; export type PublicConnectedAccount = Pick< @@ -26,7 +26,7 @@ export type PublicConnectedAccount = Pick< >; @Entity("connected_accounts") -export class ConnectedAccount extends BaseClass { +export class ConnectedAccount extends EntityCache { @Column({ nullable: true }) @RelationId((account: ConnectedAccount) => account.user) user_id: string; diff --git a/src/util/entities/EmbedCache.ts b/src/util/entities/EmbedCache.ts index 800ee4e7..fd6db90e 100644 --- a/src/util/entities/EmbedCache.ts +++ b/src/util/entities/EmbedCache.ts @@ -16,12 +16,12 @@ along with this program. If not, see . */ -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Entity, Column } from "typeorm"; import { Embed } from "./Message"; @Entity("embed_cache") -export class EmbedCache extends BaseClass { +export class EmbedCache extends EntityCache { @Column() url: string; diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts index 94ce3d54..c7678361 100644 --- a/src/util/entities/Emoji.ts +++ b/src/util/entities/Emoji.ts @@ -18,11 +18,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { User } from "."; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; @Entity("emojis") -export class Emoji extends BaseClass { +export class Emoji extends EntityCache { @Column() animated: boolean; diff --git a/src/util/entities/Encryption.ts b/src/util/entities/Encryption.ts index 016b4331..19cb3987 100644 --- a/src/util/entities/Encryption.ts +++ b/src/util/entities/Encryption.ts @@ -17,10 +17,10 @@ */ import { Column, Entity } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("security_settings") -export class SecuritySettings extends BaseClass { +export class SecuritySettings extends EntityCache { @Column({ nullable: true }) guild_id: string; diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts index c835f5fc..b08e37d1 100644 --- a/src/util/entities/Guild.ts +++ b/src/util/entities/Guild.ts @@ -26,7 +26,7 @@ import { } from "typeorm"; import { Config, handleFile, Snowflake } from ".."; import { Ban } from "./Ban"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Channel } from "./Channel"; import { Emoji } from "./Emoji"; import { Invite } from "./Invite"; @@ -67,7 +67,7 @@ export const PublicGuildRelations = [ ]; @Entity("guilds") -export class Guild extends BaseClass { +export class Guild extends EntityCache { @Column({ nullable: true }) @RelationId((guild: Guild) => guild.afk_channel) afk_channel_id?: string; diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts index fc8c011c..feee84a7 100644 --- a/src/util/entities/Message.ts +++ b/src/util/entities/Message.ts @@ -34,7 +34,7 @@ import { OneToMany, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; import { Webhook } from "./Webhook"; import { Sticker } from "./Sticker"; @@ -70,7 +70,7 @@ export enum MessageType { @Entity("messages") @Index(["channel_id", "id"], { unique: true }) -export class Message extends BaseClass { +export class Message extends EntityCache { @Column({ nullable: true }) @RelationId((message: Message) => message.channel) @Index() diff --git a/src/util/entities/Note.ts b/src/util/entities/Note.ts index 0f2a5ce3..9f13b257 100644 --- a/src/util/entities/Note.ts +++ b/src/util/entities/Note.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, Unique } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; @Entity("notes") @Unique(["owner", "target"]) -export class Note extends BaseClass { +export class Note extends EntityCache { @JoinColumn({ name: "owner_id" }) @ManyToOne(() => User, { onDelete: "CASCADE" }) owner: User; diff --git a/src/util/entities/RateLimit.ts b/src/util/entities/RateLimit.ts index 79ebbb01..23f0952c 100644 --- a/src/util/entities/RateLimit.ts +++ b/src/util/entities/RateLimit.ts @@ -17,10 +17,10 @@ */ import { Column, Entity } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("rate_limits") -export class RateLimit extends BaseClass { +export class RateLimit extends EntityCache { @Column() // no relation as it also executor_id: string; diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts index 825beb03..d39bfb4b 100644 --- a/src/util/entities/ReadState.ts +++ b/src/util/entities/ReadState.ts @@ -24,7 +24,7 @@ import { ManyToOne, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Channel } from "./Channel"; import { User } from "./User"; @@ -34,7 +34,7 @@ import { User } from "./User"; @Entity("read_states") @Index(["channel_id", "user_id"], { unique: true }) -export class ReadState extends BaseClass { +export class ReadState extends EntityCache { @Column() @RelationId((read_state: ReadState) => read_state.channel) channel_id: string; diff --git a/src/util/entities/Recipient.ts b/src/util/entities/Recipient.ts index 1cf028dd..4c301827 100644 --- a/src/util/entities/Recipient.ts +++ b/src/util/entities/Recipient.ts @@ -17,10 +17,10 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("recipients") -export class Recipient extends BaseClass { +export class Recipient extends EntityCache { @Column() @RelationId((recipient: Recipient) => recipient.channel) channel_id: string; diff --git a/src/util/entities/Relationship.ts b/src/util/entities/Relationship.ts index 1bf04c2c..48fbc81d 100644 --- a/src/util/entities/Relationship.ts +++ b/src/util/entities/Relationship.ts @@ -24,7 +24,7 @@ import { ManyToOne, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; export enum RelationshipType { @@ -36,7 +36,7 @@ export enum RelationshipType { @Entity("relationships") @Index(["from_id", "to_id"], { unique: true }) -export class Relationship extends BaseClass { +export class Relationship extends EntityCache { @Column({}) @RelationId((relationship: Relationship) => relationship.from) from_id: string; diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts index d3275ede..c44fa2b1 100644 --- a/src/util/entities/Role.ts +++ b/src/util/entities/Role.ts @@ -18,11 +18,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; @Entity("roles") -export class Role extends BaseClass { +export class Role extends EntityCache { @Column({ nullable: true }) @RelationId((role: Role) => role.guild) guild_id: string; diff --git a/src/util/entities/SecurityKey.ts b/src/util/entities/SecurityKey.ts index 8f377d9d..86e5531e 100644 --- a/src/util/entities/SecurityKey.ts +++ b/src/util/entities/SecurityKey.ts @@ -17,11 +17,11 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; @Entity("security_keys") -export class SecurityKey extends BaseClass { +export class SecurityKey extends EntityCache { @Column({ nullable: true }) @RelationId((key: SecurityKey) => key.user) user_id: string; diff --git a/src/util/entities/Session.ts b/src/util/entities/Session.ts index f416b9f5..f6e16916 100644 --- a/src/util/entities/Session.ts +++ b/src/util/entities/Session.ts @@ -17,7 +17,7 @@ */ import { User } from "./User"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { Status } from "../interfaces/Status"; import { Activity } from "../interfaces/Activity"; @@ -25,7 +25,7 @@ import { Activity } from "../interfaces/Activity"; //TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them @Entity("sessions") -export class Session extends BaseClass { +export class Session extends EntityCache { @Column({ nullable: true }) @RelationId((session: Session) => session.user) user_id: string; diff --git a/src/util/entities/Sticker.ts b/src/util/entities/Sticker.ts index 513a4c9f..dd3d39dd 100644 --- a/src/util/entities/Sticker.ts +++ b/src/util/entities/Sticker.ts @@ -18,7 +18,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { User } from "./User"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; export enum StickerType { @@ -34,7 +34,7 @@ export enum StickerFormatType { } @Entity("stickers") -export class Sticker extends BaseClass { +export class Sticker extends EntityCache { @Column() name: string; diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts index ce8d5e87..ad1a9c0f 100644 --- a/src/util/entities/StickerPack.ts +++ b/src/util/entities/StickerPack.ts @@ -25,10 +25,10 @@ import { RelationId, } from "typeorm"; import { Sticker } from "."; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("sticker_packs") -export class StickerPack extends BaseClass { +export class StickerPack extends EntityCache { @Column() name: string; diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts index 82859409..5b86bfa6 100644 --- a/src/util/entities/Team.ts +++ b/src/util/entities/Team.ts @@ -24,12 +24,12 @@ import { OneToMany, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { TeamMember } from "./TeamMember"; import { User } from "./User"; @Entity("teams") -export class Team extends BaseClass { +export class Team extends EntityCache { @Column({ nullable: true }) icon?: string; diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts index df70050c..c8c07ea9 100644 --- a/src/util/entities/TeamMember.ts +++ b/src/util/entities/TeamMember.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; export enum TeamMemberState { @@ -26,7 +26,7 @@ export enum TeamMemberState { } @Entity("team_members") -export class TeamMember extends BaseClass { +export class TeamMember extends EntityCache { @Column({ type: "int" }) membership_state: TeamMemberState; diff --git a/src/util/entities/Template.ts b/src/util/entities/Template.ts index 17f26e1c..7349367c 100644 --- a/src/util/entities/Template.ts +++ b/src/util/entities/Template.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; import { User } from "./User"; @Entity("templates") -export class Template extends BaseClass { +export class Template extends EntityCache { @Column({ unique: true }) code: string; diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index f99a85e7..2b182c16 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -34,7 +34,7 @@ import { trimSpecial, } from ".."; import { BitField } from "../util/BitField"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { ConnectedAccount } from "./ConnectedAccount"; import { Member } from "./Member"; import { Relationship } from "./Relationship"; @@ -94,7 +94,7 @@ export interface UserPrivate extends Pick { } @Entity("users") -export class User extends BaseClass { +export class User extends EntityCache { @Column() username: string; // username max length 32, min 2 (should be configurable) diff --git a/src/util/entities/VoiceState.ts b/src/util/entities/VoiceState.ts index f790945f..32d94ed1 100644 --- a/src/util/entities/VoiceState.ts +++ b/src/util/entities/VoiceState.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { User } from "./User"; @@ -25,7 +25,7 @@ import { Member } from "./Member"; //https://gist.github.com/vassjozsef/e482c65df6ee1facaace8b3c9ff66145#file-voice_state-ex @Entity("voice_states") -export class VoiceState extends BaseClass { +export class VoiceState extends EntityCache { @Column({ nullable: true }) @RelationId((voice_state: VoiceState) => voice_state.guild) guild_id: string; diff --git a/src/util/entities/Webhook.ts b/src/util/entities/Webhook.ts index 9be86c6d..3e845ddc 100644 --- a/src/util/entities/Webhook.ts +++ b/src/util/entities/Webhook.ts @@ -18,7 +18,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { Application } from "./Application"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { User } from "./User"; @@ -30,7 +30,7 @@ export enum WebhookType { } @Entity("webhooks") -export class Webhook extends BaseClass { +export class Webhook extends EntityCache { @Column({ type: "int" }) type: WebhookType; diff --git a/src/util/util/Cache.ts b/src/util/util/Cache.ts deleted file mode 100644 index 44839a65..00000000 --- a/src/util/util/Cache.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable */ -import { DataSource, QueryRunner } from "typeorm"; -import { QueryResultCache } from "typeorm/cache/QueryResultCache"; -import { QueryResultCacheOptions } from "typeorm/cache/QueryResultCacheOptions"; - -export class CustomQueryResultCache implements QueryResultCache { - constructor(private dataSource: DataSource) {} - connect(): Promise { - throw new Error("Method not implemented."); - } - disconnect(): Promise { - throw new Error("Method not implemented."); - } - synchronize(queryRunner?: QueryRunner | undefined): Promise { - throw new Error("Method not implemented."); - } - getFromCache( - options: QueryResultCacheOptions, - queryRunner?: QueryRunner | undefined, - ): Promise { - throw new Error("Method not implemented."); - } - storeInCache( - options: QueryResultCacheOptions, - savedCache: QueryResultCacheOptions | undefined, - queryRunner?: QueryRunner | undefined, - ): Promise { - throw new Error("Method not implemented."); - } - isExpired(savedCache: QueryResultCacheOptions): boolean { - throw new Error("Method not implemented."); - } - clear(queryRunner?: QueryRunner | undefined): Promise { - throw new Error("Method not implemented."); - } - remove( - identifiers: string[], - queryRunner?: QueryRunner | undefined, - ): Promise { - throw new Error("Method not implemented."); - } -} -- cgit 1.4.1 From 52f8508b38aa0a0aed67c3ac1fab72b35bbfe3bb Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Sat, 18 Mar 2023 04:12:16 +0100 Subject: fix: missing id in select query --- src/api/routes/guilds/#guild_id/templates.ts | 1 + src/util/util/Token.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/api/routes/guilds/#guild_id/templates.ts b/src/api/routes/guilds/#guild_id/templates.ts index 284bbccf..7c4a6961 100644 --- a/src/api/routes/guilds/#guild_id/templates.ts +++ b/src/api/routes/guilds/#guild_id/templates.ts @@ -39,6 +39,7 @@ const TemplateGuildProjection: (keyof Guild)[] = [ "system_channel_id", "system_channel_flags", "icon", + "id", ]; router.get("/", route({}), async (req: Request, res: Response) => { diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts index 67e4b879..0a8e7378 100644 --- a/src/util/util/Token.ts +++ b/src/util/util/Token.ts @@ -87,7 +87,7 @@ export function checkToken( const user = await User.findOne({ where: { id: decoded.id }, - select: ["data", "bot", "disabled", "deleted", "rights"], + select: ["id", "data", "bot", "disabled", "deleted", "rights"], }); if (!user) return rej("Invalid Token"); -- cgit 1.4.1 From 7b00e9905327c826b82fc47cfa22e37b9c5161a9 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Sat, 18 Mar 2023 04:13:04 +0100 Subject: fix: use entity.save() instead of insert (needed for caching) --- src/api/routes/users/@me/notes.ts | 6 +++--- src/api/util/handlers/Message.ts | 2 +- src/util/util/Database.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/api/routes/users/@me/notes.ts b/src/api/routes/users/@me/notes.ts index 64730c1a..f82c3ca1 100644 --- a/src/api/routes/users/@me/notes.ts +++ b/src/api/routes/users/@me/notes.ts @@ -52,17 +52,17 @@ router.put("/:id", route({}), async (req: Request, res: Response) => { where: { owner: { id: owner.id }, target: { id: target.id } }, }) ) { - Note.update( + await Note.update( { owner: { id: owner.id }, target: { id: target.id } }, { owner, target, content: note }, ); } else { - Note.insert({ + await Note.create({ id: Snowflake.generate(), owner, target, content: note, - }); + }).save(); } } else { await Note.delete({ diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts index e514d400..8fbbf4bf 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts @@ -274,7 +274,7 @@ export async function sendMessage(opts: MessageOptions) { const message = await handleMessage({ ...opts, timestamp: new Date() }); await Promise.all([ - Message.insert(message), + message.save(), emitEvent({ event: "MESSAGE_CREATE", channel_id: opts.channel_id, diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts index 5c5c8b4c..5d48ac03 100644 --- a/src/util/util/Database.ts +++ b/src/util/util/Database.ts @@ -127,10 +127,10 @@ export async function initDatabase(): Promise { // Manually insert every current migration to prevent this: await Promise.all( dbConnection.migrations.map((migration) => - Migration.insert({ + Migration.create({ name: migration.name, timestamp: Date.now(), - }), + }).save(), ), ); } else { -- cgit 1.4.1 From d97dbdf73cb4a5b21492575fce9b24cdcc337402 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Sat, 18 Mar 2023 04:18:18 +0100 Subject: fix: remove proxy --- src/api/Server.ts | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/api/Server.ts b/src/api/Server.ts index ced82dce..fb32e511 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts @@ -126,10 +126,6 @@ export class FosscordServer extends Server { app.use("/api/v9", api); app.use("/api", api); // allow unversioned requests - try { - require("./middlewares/TestClient").default(this.app); - // eslint-disable-next-line no-empty - } catch (error) {} this.app.use(ErrorHandler); Sentry.errorHandler(this.app); -- cgit 1.4.1 From fd1c99db2d0004cbdfa6e5a1e00f691614c249fd Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Sat, 18 Mar 2023 04:20:03 +0100 Subject: build: remove sqlite3 in favor of better-sqlite3 --- package-lock.json | 145 +++++++++++++++++++++++++++++++++++++--------- package.json | 3 +- src/util/util/Database.ts | 13 +---- 3 files changed, 121 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 43a1114e..3713fc53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,8 +82,7 @@ "erlpack": "^0.1.4", "nodemailer-mailgun-transport": "^2.1.5", "nodemailer-mailjet-transport": "github:n0script22/nodemailer-mailjet-transport", - "nodemailer-sendgrid-transport": "github:Maria-Golomb/nodemailer-sendgrid-transport", - "sqlite3": "^5.1.6" + "nodemailer-sendgrid-transport": "github:Maria-Golomb/nodemailer-sendgrid-transport" } }, "node_modules/@acuminous/bitsyntax": { @@ -1580,7 +1579,8 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@hexagon/base64": { "version": "1.1.26", @@ -1701,6 +1701,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", "optional": true, + "peer": true, "dependencies": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" @@ -1712,6 +1713,7 @@ "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", "deprecated": "This functionality has been moved to @npmcli/fs", "optional": true, + "peer": true, "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -1725,6 +1727,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "optional": true, + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -2455,6 +2458,7 @@ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", "optional": true, + "peer": true, "dependencies": { "debug": "^4.1.0", "depd": "^2.0.0", @@ -2469,6 +2473,7 @@ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "optional": true, + "peer": true, "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -3016,6 +3021,7 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", "optional": true, + "peer": true, "dependencies": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", @@ -3045,6 +3051,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -3057,6 +3064,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "optional": true, + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -3068,7 +3076,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true + "optional": true, + "peer": true }, "node_modules/call-bind": { "version": "1.0.2", @@ -3184,6 +3193,7 @@ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -3763,6 +3773,7 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "optional": true, + "peer": true, "dependencies": { "iconv-lite": "^0.6.2" } @@ -3781,6 +3792,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -3813,6 +3825,7 @@ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -3832,7 +3845,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "optional": true + "optional": true, + "peer": true }, "node_modules/escalade": { "version": "3.1.1", @@ -4848,7 +4862,8 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "optional": true + "optional": true, + "peer": true }, "node_modules/http-errors": { "version": "2.0.0", @@ -4904,6 +4919,7 @@ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "optional": true, + "peer": true, "dependencies": { "ms": "^2.0.0" } @@ -5038,6 +5054,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -5046,7 +5063,8 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "optional": true + "optional": true, + "peer": true }, "node_modules/inflight": { "version": "1.0.6", @@ -5114,7 +5132,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "optional": true + "optional": true, + "peer": true }, "node_modules/is-number": { "version": "7.0.0", @@ -5425,6 +5444,7 @@ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", "optional": true, + "peer": true, "dependencies": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", @@ -5452,6 +5472,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -5464,6 +5485,7 @@ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", "optional": true, + "peer": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -5477,7 +5499,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true + "optional": true, + "peer": true }, "node_modules/media-typer": { "version": "0.3.0", @@ -5614,6 +5637,7 @@ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -5626,6 +5650,7 @@ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.1.0", "minipass-sized": "^1.0.3", @@ -5643,6 +5668,7 @@ "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -5655,6 +5681,7 @@ "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -5667,6 +5694,7 @@ "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -5935,6 +5963,7 @@ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", "optional": true, + "peer": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -5970,6 +5999,7 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", "optional": true, + "peer": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -5983,6 +6013,7 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "optional": true, + "peer": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -6002,6 +6033,7 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", "optional": true, + "peer": true, "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -6017,6 +6049,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "optional": true, + "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -6044,13 +6077,15 @@ "url": "https://feross.org/support" } ], - "optional": true + "optional": true, + "peer": true }, "node_modules/node-gyp/node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "optional": true, + "peer": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -6312,6 +6347,7 @@ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "optional": true, + "peer": true, "dependencies": { "aggregate-error": "^3.0.0" }, @@ -6647,13 +6683,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "optional": true + "optional": true, + "peer": true }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "optional": true, + "peer": true, "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -6935,6 +6973,7 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "optional": true, + "peer": true, "engines": { "node": ">= 4" } @@ -7264,6 +7303,7 @@ "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", "hasInstallScript": true, "optional": true, + "peer": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", "node-addon-api": "^4.2.0", @@ -7285,13 +7325,15 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "optional": true + "optional": true, + "peer": true }, "node_modules/ssri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.1.1" }, @@ -8116,6 +8158,7 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "optional": true, + "peer": true, "dependencies": { "unique-slug": "^2.0.0" } @@ -8125,6 +8168,7 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "optional": true, + "peer": true, "dependencies": { "imurmurhash": "^0.1.4" } @@ -9636,7 +9680,8 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "optional": true + "optional": true, + "peer": true }, "@hexagon/base64": { "version": "1.1.26", @@ -9732,6 +9777,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", "optional": true, + "peer": true, "requires": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" @@ -9742,6 +9788,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", "optional": true, + "peer": true, "requires": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -9751,7 +9798,8 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true + "optional": true, + "peer": true } } }, @@ -10347,6 +10395,7 @@ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", "optional": true, + "peer": true, "requires": { "debug": "^4.1.0", "depd": "^2.0.0", @@ -10358,6 +10407,7 @@ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "optional": true, + "peer": true, "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -10760,6 +10810,7 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", "optional": true, + "peer": true, "requires": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", @@ -10786,6 +10837,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "optional": true, + "peer": true, "requires": { "yallist": "^4.0.0" } @@ -10794,13 +10846,15 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true + "optional": true, + "peer": true }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true + "optional": true, + "peer": true } } }, @@ -10887,7 +10941,8 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "optional": true + "optional": true, + "peer": true }, "cli-highlight": { "version": "2.1.11", @@ -11323,6 +11378,7 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "optional": true, + "peer": true, "requires": { "iconv-lite": "^0.6.2" }, @@ -11332,6 +11388,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "optional": true, + "peer": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -11362,7 +11419,8 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "optional": true + "optional": true, + "peer": true }, "erlpack": { "version": "0.1.4", @@ -11378,7 +11436,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "optional": true + "optional": true, + "peer": true }, "escalade": { "version": "3.1.1", @@ -12138,7 +12197,8 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "optional": true + "optional": true, + "peer": true }, "http-errors": { "version": "2.0.0", @@ -12182,6 +12242,7 @@ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "optional": true, + "peer": true, "requires": { "ms": "^2.0.0" } @@ -12257,13 +12318,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "optional": true + "optional": true, + "peer": true }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "optional": true + "optional": true, + "peer": true }, "inflight": { "version": "1.0.6", @@ -12319,7 +12382,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "optional": true + "optional": true, + "peer": true }, "is-number": { "version": "7.0.0", @@ -12581,6 +12645,7 @@ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", "optional": true, + "peer": true, "requires": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", @@ -12605,6 +12670,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "optional": true, + "peer": true, "requires": { "yallist": "^4.0.0" } @@ -12614,6 +12680,7 @@ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", "optional": true, + "peer": true, "requires": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -12624,7 +12691,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true + "optional": true, + "peer": true } } }, @@ -12728,6 +12796,7 @@ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", "optional": true, + "peer": true, "requires": { "minipass": "^3.0.0" } @@ -12737,6 +12806,7 @@ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", "optional": true, + "peer": true, "requires": { "encoding": "^0.1.12", "minipass": "^3.1.0", @@ -12749,6 +12819,7 @@ "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "optional": true, + "peer": true, "requires": { "minipass": "^3.0.0" } @@ -12758,6 +12829,7 @@ "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "optional": true, + "peer": true, "requires": { "minipass": "^3.0.0" } @@ -12767,6 +12839,7 @@ "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "optional": true, + "peer": true, "requires": { "minipass": "^3.0.0" } @@ -12986,6 +13059,7 @@ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", "optional": true, + "peer": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -13004,6 +13078,7 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", "optional": true, + "peer": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -13014,6 +13089,7 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "optional": true, + "peer": true, "requires": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -13030,6 +13106,7 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", "optional": true, + "peer": true, "requires": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -13042,6 +13119,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "optional": true, + "peer": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -13052,13 +13130,15 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "optional": true + "optional": true, + "peer": true }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "optional": true, + "peer": true, "requires": { "safe-buffer": "~5.2.0" } @@ -13268,6 +13348,7 @@ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "optional": true, + "peer": true, "requires": { "aggregate-error": "^3.0.0" } @@ -13505,13 +13586,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "optional": true + "optional": true, + "peer": true }, "promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "optional": true, + "peer": true, "requires": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -13716,7 +13799,8 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "optional": true + "optional": true, + "peer": true }, "reusify": { "version": "1.0.4", @@ -13954,6 +14038,7 @@ "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz", "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", "optional": true, + "peer": true, "requires": { "@mapbox/node-pre-gyp": "^1.0.0", "node-addon-api": "^4.2.0", @@ -13965,7 +14050,8 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "optional": true + "optional": true, + "peer": true } } }, @@ -13974,6 +14060,7 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", "optional": true, + "peer": true, "requires": { "minipass": "^3.1.1" } @@ -14512,6 +14599,7 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "optional": true, + "peer": true, "requires": { "unique-slug": "^2.0.0" } @@ -14521,6 +14609,7 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "optional": true, + "peer": true, "requires": { "imurmurhash": "^0.1.4" } diff --git a/package.json b/package.json index 101a5f53..85edb0e5 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,6 @@ "erlpack": "^0.1.4", "nodemailer-mailgun-transport": "^2.1.5", "nodemailer-mailjet-transport": "github:n0script22/nodemailer-mailjet-transport", - "nodemailer-sendgrid-transport": "github:Maria-Golomb/nodemailer-sendgrid-transport", - "sqlite3": "^5.1.6" + "nodemailer-sendgrid-transport": "github:Maria-Golomb/nodemailer-sendgrid-transport" } } diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts index 5d48ac03..1cf7adfd 100644 --- a/src/util/util/Database.ts +++ b/src/util/util/Database.ts @@ -36,17 +36,10 @@ if (!process.env) { const dbConnectionString = process.env.DATABASE || path.join(process.cwd(), "database.db"); -let DatabaseType = dbConnectionString.includes("://") +const DatabaseType = dbConnectionString.includes("://") ? dbConnectionString.split(":")[0]?.replace("+srv", "") - : "sqlite"; - -if (DatabaseType === "sqlite") { - try { - require("better-sqlite3"); - DatabaseType = "better-sqlite3"; - // eslint-disable-next-line no-empty - } catch (error) {} -} + : "better-sqlite"; + const isSqlite = DatabaseType.includes("sqlite"); const DataSourceOptions = new DataSource({ -- cgit 1.4.1 From c6708f744369ce6967abe074b637201fe203986b Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Sat, 18 Mar 2023 04:20:03 +0100 Subject: build: remove sqlite3 in favor of better-sqlite3 --- src/util/util/Database.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts index 1cf7adfd..5a5a4b75 100644 --- a/src/util/util/Database.ts +++ b/src/util/util/Database.ts @@ -38,7 +38,7 @@ const dbConnectionString = const DatabaseType = dbConnectionString.includes("://") ? dbConnectionString.split(":")[0]?.replace("+srv", "") - : "better-sqlite"; + : "better-sqlite3"; const isSqlite = DatabaseType.includes("sqlite"); -- cgit 1.4.1 From f1f7e5ad7d7f197cd741f248011cc45636a0f434 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Sat, 18 Mar 2023 05:11:14 +0100 Subject: fix: local cache --- src/util/cache/LocalCache.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/util/cache/LocalCache.ts b/src/util/cache/LocalCache.ts index 547899ac..9c4f23b3 100644 --- a/src/util/cache/LocalCache.ts +++ b/src/util/cache/LocalCache.ts @@ -38,8 +38,11 @@ export class LocalCache extends Map implements Cache { } set(key: string, value: BaseEntityWithId): this { + if (this.has(key)) { + this.update(key, value); + return this; + } this.last_access.set(key, Date.now()); - if (this.has(key)) this.update(key, value); return super.set(key, value as never); } -- cgit 1.4.1 From 3dc0e68534f9c30f29f5b7e039f439706edf0a16 Mon Sep 17 00:00:00 2001 From: Samuel <34555296+Flam3rboy@users.noreply.github.com> Date: Sat, 18 Mar 2023 05:11:33 +0100 Subject: feat: add DB_LOGGING env --- src/util/util/Database.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts index 5a5a4b75..122a8793 100644 --- a/src/util/util/Database.ts +++ b/src/util/util/Database.ts @@ -51,7 +51,7 @@ const DataSourceOptions = new DataSource({ database: isSqlite ? dbConnectionString : undefined, entities: [path.join(__dirname, "..", "entities", "*.js")], synchronize: !!process.env.DB_SYNC, - logging: false, + logging: process.env["DB_LOGGING"] === "true", bigNumberStrings: false, supportBigNumbers: true, name: "default", -- cgit 1.4.1