Initial commit

This commit is contained in:
TopchetoEU 2023-06-26 16:46:12 +03:00
commit bfeb01484c
No known key found for this signature in database
GPG Key ID: 24E57B2E9C61AD19
15 changed files with 894 additions and 0 deletions

5
.eslintrc.json Normal file
View File

@ -0,0 +1,5 @@
{
"rules": {
"@typescript-eslint/no-explicit-any": "off"
}
}

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.idea/
.vscode/
node_modules/
build/
tmp/
temp/
keys/

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# Awesome Project Build with TypeORM
Steps to run this project:
1. Run `npm i` command
2. Setup database settings inside `data-source.ts` file
3. Run `npm start` command

21
package.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "clonegur",
"version": "1.0.0",
"main": "index.ts",
"license": "MIT",
"type": "commonjs",
"dependencies": {
"mongodb": "^5.2.0",
"reflect-metadata": "^0.1.13"
},
"devDependencies": {
"@types/express": "^4.17.14",
"@types/node": "^16.11.10",
"ts-node": "^10.9.1",
"typescript": "^5.1.3"
},
"scripts": {
"start": "ts-node src/index.ts",
"typeorm": "typeorm-ts-node-commonjs"
}
}

30
src/index.ts Normal file
View File

@ -0,0 +1,30 @@
import { Collection, MongoClient } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
import UserRouter from "./routers/UserRouter.ts";
import { Router, rest, route } from "./server/Server.ts";
import User from "./models/User.ts";
import Response from "./server/Response.ts";
class RootRouter extends Router {
@route('users/*') users: UserRouter;
@rest('*', '*')
default() {
return new Response().body(new Blob(['Page not found :/'])).status(404);
}
constructor(salt: string, users: Collection<User>) {
super();
this.users = new UserRouter(salt, users);
}
}
export default async function clonegur() {
const salt = new TextDecoder().decode(await Deno.readFile('keys/salt.txt'));
const db = await new MongoClient().connect({
db: 'clonegur',
servers: [ { host: '127.0.0.1', port: 27017 } ]
});
await new RootRouter(salt, db.collection('users')).attach(Deno.listen({ port: 4000, hostname: 'localhost' }));
}
clonegur();

2
src/models/User.js Normal file
View File

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

5
src/models/User.ts Normal file
View File

@ -0,0 +1,5 @@
export default interface User {
_id: string;
username: string;
password: string;
}

8
src/routers/AppRouter.ts Normal file
View File

@ -0,0 +1,8 @@
import { HttpError, RestRequest, RestResponse, Router } from "../server/Server.ts";
export default class AppRouter extends Router {
public onError(_req: RestRequest, error: unknown): RestResponse | HttpError | Promise<RestResponse | HttpError> {
if (error instanceof HttpError) return new HttpError({ error: error.body }, error.status);
return super.onError(_req, error);
}
}

46
src/routers/UserRouter.ts Normal file
View File

@ -0,0 +1,46 @@
import { Collection } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
import { HttpError, rest } from "../server/Server.ts";
import User from "../models/User.ts";
import { body, schema } from "../server/Router.ts";
import AppRouter from "./AppRouter.ts";
import * as bcrypt from "https://deno.land/x/bcrypt@v0.4.1/mod.ts";
interface SignupRequest {
username: string;
password: string;
}
export default class UserRouter extends AppRouter {
@rest('GET', '/')
async get(@schema('string') username: string) {
const res = await this.users.findOne({ username });
if (res === undefined) throw new HttpError('User not found.');
return { username: res.username };
}
@rest('POST', '/signup')
async signup(
@schema({
username: 'string', password: 'string',
}) @body() body: SignupRequest
) {
if (await this.users.countDocuments({ username: body.username }) > 0) {
throw new HttpError('User with the same username already exists.');
}
const password = await bcrypt.hash(body.password, this.salt);
await this.users.insertOne({
username: body.username,
password: password,
});
return {};
}
public constructor(private salt: string, private users: Collection<User>) {
super();
users.createIndexes({ indexes: [ { key: { username: 1 }, name: 'Username Index' } ] });
}
}

122
src/server/Request.ts Normal file
View File

@ -0,0 +1,122 @@
export type ParamDict = Record<string, string>;
export type Headers = Record<string, string | string[] | undefined>;
function splitUrl(url: string) {
return url.split('/').map(v => v.trim()).filter(v => v !== '');
}
function sanitizeUrl(url: string, forceAbsolute = true) {
url = url.trim();
if (forceAbsolute || url.startsWith('/')) {
return '/' + splitUrl(url).join('/');
}
else {
return '/' + splitUrl(url).join('/');
}
}
export const FetchRequest = Request;
export default class RestRequest {
public readonly body: unknown;
public readonly method: string;
public readonly url: string;
public readonly pathParams: ParamDict;
public readonly queryParams: ParamDict;
public readonly headers: Headers;
public get params() {
return { ...this.queryParams, ...this.pathParams };
}
public constructor(
body: unknown,
headers: Headers,
method: string,
url: string,
pathParams: ParamDict = {},
queryParams: ParamDict = {}
) {
this.body = body;
this.headers = headers;
this.pathParams = { ...pathParams };
this.queryParams = { ...queryParams };
this.method = method.toLowerCase();
this.url = sanitizeUrl(url);
if (this.url.includes('?')) {
const questionIndex = this.url.indexOf('?');
this.url = this.url.substring(0, questionIndex);
const params = this.url
.substring(questionIndex + 1)
.split('&')
.map(v => v.trim())
.filter(v => v !== '');
for (const rawParam of params) {
const i = rawParam.indexOf('=');
if (i < 0) continue;
const name = rawParam.substring(0, i);
const val = rawParam.substring(i + 1);
if (name === '') continue;
this.queryParams[name] = val;
}
}
}
public match(predicate: string) {
const urlSegments = splitUrl(this.url);
const predSegments = splitUrl(predicate);
const wildcardIndex = predSegments.indexOf('*');
const hasWildcard = wildcardIndex >= 0;
const pathParams: ParamDict = { ...this.pathParams };
if (wildcardIndex >= 0) {
if (predSegments.includes('*', wildcardIndex + 1)) throw new Error("A path predicate may not have more than one wildcard.");
if (predSegments.splice(wildcardIndex).length > 1) throw new Error("A path predicate must be the last segment.");
}
for (const predSeg of predSegments) {
const urlSeg = urlSegments.shift();
if (urlSeg === undefined) return undefined;
else if (predSeg.startsWith(':')) {
const name = predSeg.substring(1);
if (name.length === 0) throw new Error('Invalid path predicate - a segment may not be ":".');
pathParams[name] = decodeURI(urlSeg);
}
else if (predSeg === urlSeg) continue;
else return undefined;
}
if (!hasWildcard && urlSegments.length > 0) return undefined;
return new RestRequest(
this.body, this.headers, this.method, '/' + urlSegments.join('/'),
{ ...this.pathParams, ...pathParams }, this.queryParams
);
}
public static async fromMessage(msg: Deno.RequestEvent) {
const raw = msg.request.body;
const headers = {} as Headers;
for (const entry of msg.request.headers.entries()) {
headers[entry[0]] = entry[1];
}
const parts: Uint8Array[] = [];
if (raw !== null) {
for await (const part of raw) {
parts.push(part);
}
}
const url = new URL(msg.request.url);
const params = {} as ParamDict;
for (const entry of url.searchParams.entries()) params[entry[0]] = entry[1];
return new RestRequest(new Blob(parts), headers, msg.request.method, url.pathname, {}, params);
}
}

51
src/server/Response.ts Normal file
View File

@ -0,0 +1,51 @@
import { Headers } from "./Request.ts";
export const FetchResponse = Response;
export default class RestResponse {
#status = 200;
#statusMsg = '';
#body?: Blob;
headers: Headers = {};
public constructor() { }
public get statusCode() { return this.#status; }
public get statusMessage() { return this.#statusMsg; }
public get content() { return this.#body; }
public header(name: string, val: string | string[]) {
this.headers[name] = val;
return this;
}
public status(val: number, message = '') {
this.#status = val;
this.#statusMsg = message;
return this;
}
public body(val: string | Blob) {
if (typeof val === 'string') val = new Blob([val]);
this.#body = val;
return this;
}
public toFetchResponse(): Response {
const headers: string[][] = [];
for (const key in this.headers) {
const val = this.headers[key];
if (typeof val === 'string') {
headers.push([key, val]);
}
else if (val instanceof Array) {
headers.push([key, ...val]);
}
else headers.push([key]);
}
return new Response(this.#body, {
headers: headers,
status: this.#status,
statusText: this.#statusMsg,
});
}
}

249
src/server/Router.ts Normal file
View File

@ -0,0 +1,249 @@
// deno-lint-ignore-file no-explicit-any ban-types
import { Reflect } from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts";
import { HttpError, RestRequest, RestResponse, serialize } from "./Server.ts";
export type HandlerRes = Promise<RestResponse | undefined> | RestResponse | undefined;
export type HttpMethod = '*' | 'GET' | 'POST' | 'CHANGE' | 'DELETE' | 'PUT' | 'UPDATE';
export type BodyType = 'raw' | 'json';
export type AuthType = 'raw' | 'jwt';
export type PrimitiveSchema = 'string' | 'number' | 'boolean' | 'object';
export type OptionalSchema = `${PrimitiveSchema}?`;
export type Schema = 'any' | PrimitiveSchema | OptionalSchema | Schema[] | ({ $optional?: boolean; } & { [key: string]: Schema });
export interface Handler {
handle(req: RestRequest): HandlerRes;
}
export interface RestOptions {
route?: string;
}
type ProcessFunc = (req: RestRequest, arg: unknown, name: string) => Promise<unknown> | unknown;
type Base<KeyT extends string> = Router & { [X in KeyT]: Function; };
interface RouterHandler {
path: string;
handler: Handler;
}
export function makeParameterModifier(func: ProcessFunc) {
return (target: Router, key: string, index: number) => {
let res = Reflect.getOwnMetadata('router:params', target, key);
if (res === undefined) Reflect.defineMetadata('router:params', res = [], target, key);
(res[index] ??= []).push(func);
return res;
}
}
export function schema(desc: Schema) {
function stringify(desc: Schema): string {
if (typeof desc === 'string') return desc;
if (desc instanceof Array) return desc.map(stringify).join(' | ');
let res = '{ ';
for (const key in desc) {
if (key === '$optional') continue;
if (res != '{ ') res += ', ';
res += key + ': ';
res += stringify(desc[key]);
}
res += '}';
if (desc.$optional) res += '?';
return res;
}
function test(path: string[], val: unknown, desc: Schema) {
if (desc === 'any') return;
if (typeof desc === 'string') {
let type: string = desc;
const opt = desc.endsWith('?');
if (opt) type = type.substring(0, desc.length - 1);
if (opt && val === undefined) return;
if (typeof val as any !== type) throw new HttpError(`${path.join('.')}: Expected a ${type}, got ${typeof val} instead.`);
}
else if (desc instanceof Array) {
for (const type of desc) {
try {
test(path, val, type);
return;
}
catch { /**/ }
}
throw new HttpError(`${path.join('.')}: Expected a ${stringify(desc)}, got ${typeof val} instead.`);
}
else {
if (desc.$optional && val === undefined) return;
if (typeof val !== 'object' || val === null) throw new HttpError(`${path.join('.')}: Expected an object, got ${typeof val} instead.`);
for (const key in desc) {
if (key === '$optional') continue;
test([ ...path, key ], (val as any)[key], desc[key]);
}
}
}
return makeParameterModifier((_req, val, name) => (test([name], val, desc), val));
}
export function body(type: BodyType = 'json') {
return makeParameterModifier(async req => {
let body = req.body;
if (type === 'json') {
try {
if (body instanceof Blob) body = await body.text();
if (typeof body === 'string') body = JSON.parse(body.toString());
}
catch (e) {
if (e instanceof SyntaxError) throw new HttpError('Body syntax error: ' + e.message);
}
}
return body;
});
}
export function auth(type: AuthType = 'jwt') {
return makeParameterModifier(req => {
let res = req.headers.authorization;
if (typeof res !== 'string') return undefined;
if (res.startsWith('Bearer')) res = res.substring(6).trimStart();
if (type === 'jwt') throw new Error('JWT is not supported.');
return res;
});
}
function addMetaQuery(target: any, ...handlers: ((r: Router) => RouterHandler)[]) {
let props = Reflect.getOwnMetadata('router:queries', target);
if (props === undefined) Reflect.defineMetadata('router:queries', props = [], target);
props.push(...handlers);
}
export function rest<KeyT extends keyof T & string, T extends Base<KeyT>>(method: HttpMethod, route?: string) {
return (target: T, key: KeyT) => {
const path = route ?? key;
addMetaQuery(target, (r: any) => ({
path, handler: {
async handle(req) {
if (method !== '*' && req.method.toUpperCase() !== method) return undefined;
const params: string[] = [];
const func = (r as T)[key];
const args: any[] = [];
const allMods: ([ProcessFunc, ...ProcessFunc[]] | undefined)[] = [];
let signature = (target[key] as Function).toString();
signature = signature.substring(signature.indexOf('(') + 1, signature.indexOf(')'));
params.push(...signature.split(',').map(v => v.trim()).filter(v => v !== ''));
for (let proto = target; proto instanceof Router; proto = Object.getPrototypeOf(proto)) {
const data = Reflect.getOwnMetadata('router:params', proto, key);
if (!data) continue;
for (let i = 0; i < data.length; i++) {
allMods[i] ??= [] as any;
if (data[i]) allMods[i]!.push(...data[i]);
}
}
for (let i = 0; i < params.length; i++) {
const param = params[i];
let arg: any = req.params[param];
for (const mod of allMods[i] ?? []) {
arg = await mod(req, arg, params[i]);
}
args.push(arg);
}
const res = func.apply(r, args);
if (res instanceof RestResponse) return res;
return new RestResponse().body(await serialize(res));
}
},
}));
};
}
export function route<KeyT extends keyof T & string, T extends Router & { [x in KeyT]: Handler }>(path?: string) {
return (target: T, key: KeyT) => {
addMetaQuery(target, (r: any) => ({
handler: r[key],
path: path ?? key,
}));
};
}
export default class Router {
private _handlers?: RouterHandler[];
public defaultHandler?: Handler;
private _init() {
if (this._handlers === undefined) {
this._handlers = [];
// why the actual fuck not
// deno-lint-ignore no-this-alias
for (let proto = this; proto instanceof Router; proto = Object.getPrototypeOf(proto)) {
const props = Reflect.getOwnMetadata('router:queries', proto);
for (const handler of props ?? []) {
this._handlers.push(handler(this));
}
}
}
return this._handlers;
}
public async handle(req: RestRequest) {
for (const hnd of this._init()) {
const _req = req.match(hnd.path);
if (_req) {
try {
const res = await hnd.handler.handle(_req);
if (res) return res;
}
catch (e) {
const res = await this.onError(_req, e);
if (res instanceof HttpError) return new RestResponse()
.body(await serialize(res.body))
.status(res.status);
else return res;
}
}
}
return this.defaultHandler?.handle(req);
}
public addHandler(path: string, handler: Handler) {
this._init().push({ path, handler });
return this;
}
public onError(_req: RestRequest, error: unknown): Promise<RestResponse | HttpError> | RestResponse | HttpError {
if (error instanceof HttpError) return error;
else {
console.error(error);
try {
return new HttpError(`Internal error: ${error}\nSee logs for details`, 500);
}
catch {
return new HttpError('Internal error.\nSee logs for details', 500);
}
}
}
public async attach(server: Deno.Listener) {
for await (const conn of server) {
for await (const req of Deno.serveHttp(conn)) {
const r = await this.handle(await RestRequest.fromMessage(req));
if (r) req.respondWith(r.toFetchResponse());
}
}
}
}

38
src/server/Server.ts Normal file
View File

@ -0,0 +1,38 @@
import Router, { rest, route } from "./Router.ts";
import RestRequest from "./Request.ts";
import RestResponse from "./Response.ts";
export { RestRequest, RestResponse, Router, rest, route };
export class HttpError extends Error {
constructor(public readonly body: unknown, public readonly status = 400) {
super();
serialize(body).then(v => this.message = v.toString());
}
}
const undefinedBuff = new Blob([new TextEncoder().encode('undefined')]);
const nullBuff = new Blob([new TextEncoder().encode('null')]);
export async function serialize(val: unknown, depth = 16): Promise<Blob> {
while (true) {
if (depth <= 0) throw new Error("Call depth exceeded limit.");
if (val instanceof Promise) val = await val;
else if (val instanceof Function) {
if (val.length !== 0) throw new Error('Can\'t serialize an argument-accepting function');
val = val();
}
else break;
depth--;
}
if (val === undefined) return undefinedBuff;
if (val === null) return nullBuff;
if (val instanceof Blob) return val;
while (typeof val !== 'string' && val && val.toString !== Object.prototype.toString && val.toString instanceof Function) {
val = val.toString();
}
return new Blob([new TextEncoder().encode(JSON.stringify(val))]);
}

11
tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"moduleResolution": "node",
"outDir": "./dst",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": false
// "module": "ESNext"
}
}

292
yarn.lock Normal file
View File

@ -0,0 +1,292 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@jridgewell/resolve-uri@^3.0.3":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.15"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@0.3.9":
version "0.3.9"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@tsconfig/node10@^1.0.7":
version "1.0.9"
resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz"
integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
"@tsconfig/node12@^1.0.7":
version "1.0.11"
resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz"
integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
"@tsconfig/node14@^1.0.0":
version "1.0.3"
resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz"
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
"@tsconfig/node16@^1.0.2":
version "1.0.4"
resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz"
integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==
"@types/body-parser@*":
version "1.19.2"
resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz"
integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==
dependencies:
"@types/connect" "*"
"@types/node" "*"
"@types/connect@*":
version "3.4.35"
resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz"
integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==
dependencies:
"@types/node" "*"
"@types/express-serve-static-core@^4.17.33":
version "4.17.35"
resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz"
integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==
dependencies:
"@types/node" "*"
"@types/qs" "*"
"@types/range-parser" "*"
"@types/send" "*"
"@types/express@^4.17.14":
version "4.17.17"
resolved "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz"
integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==
dependencies:
"@types/body-parser" "*"
"@types/express-serve-static-core" "^4.17.33"
"@types/qs" "*"
"@types/serve-static" "*"
"@types/mime@*":
version "3.0.1"
resolved "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz"
integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==
"@types/mime@^1":
version "1.3.2"
resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz"
integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
"@types/node@*", "@types/node@^16.11.10":
version "16.18.36"
resolved "https://registry.npmjs.org/@types/node/-/node-16.18.36.tgz"
integrity sha512-8egDX8dE50XyXWH6C6PRCNkTP106DuUrvdrednFouDSmCi7IOvrqr0frznfZaHifHH/3aq/7a7v9N4wdXMqhBQ==
"@types/qs@*":
version "6.9.7"
resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz"
integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==
"@types/range-parser@*":
version "1.2.4"
resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz"
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
"@types/send@*":
version "0.17.1"
resolved "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz"
integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==
dependencies:
"@types/mime" "^1"
"@types/node" "*"
"@types/serve-static@*":
version "1.15.1"
resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz"
integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==
dependencies:
"@types/mime" "*"
"@types/node" "*"
"@types/webidl-conversions@*":
version "7.0.0"
resolved "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz"
integrity sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==
"@types/whatwg-url@^8.2.1":
version "8.2.2"
resolved "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz"
integrity sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==
dependencies:
"@types/node" "*"
"@types/webidl-conversions" "*"
acorn-walk@^8.1.1:
version "8.2.0"
resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@^8.4.1:
version "8.9.0"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz"
integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
bson@^5.3.0:
version "5.3.0"
resolved "https://registry.npmjs.org/bson/-/bson-5.3.0.tgz"
integrity sha512-ukmCZMneMlaC5ebPHXIkP8YJzNl5DC41N5MAIvKDqLggdao342t4McltoJBQfQya/nHBWAcSsYRqlXPoQkTJag==
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
memory-pager@^1.0.2:
version "1.5.0"
resolved "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz"
integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==
mongodb-connection-string-url@^2.6.0:
version "2.6.0"
resolved "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz"
integrity sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==
dependencies:
"@types/whatwg-url" "^8.2.1"
whatwg-url "^11.0.0"
mongodb@^5.2.0:
version "5.6.0"
resolved "https://registry.npmjs.org/mongodb/-/mongodb-5.6.0.tgz"
integrity sha512-z8qVs9NfobHJm6uzK56XBZF8XwM9H294iRnB7wNjF0SnY93si5HPziIJn+qqvUR5QOff/4L0gCD6SShdR/GtVQ==
dependencies:
bson "^5.3.0"
mongodb-connection-string-url "^2.6.0"
socks "^2.7.1"
optionalDependencies:
saslprep "^1.0.3"
punycode@^2.1.1:
version "2.3.0"
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz"
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
reflect-metadata@^0.1.13:
version "0.1.13"
resolved "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz"
integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
saslprep@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz"
integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==
dependencies:
sparse-bitfield "^3.0.3"
smart-buffer@^4.2.0:
version "4.2.0"
resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
socks@^2.7.1:
version "2.7.1"
resolved "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz"
integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==
dependencies:
ip "^2.0.0"
smart-buffer "^4.2.0"
sparse-bitfield@^3.0.3:
version "3.0.3"
resolved "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz"
integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==
dependencies:
memory-pager "^1.0.2"
tr46@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz"
integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==
dependencies:
punycode "^2.1.1"
ts-node@^10.9.1:
version "10.9.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
dependencies:
"@cspotcode/source-map-support" "^0.8.0"
"@tsconfig/node10" "^1.0.7"
"@tsconfig/node12" "^1.0.7"
"@tsconfig/node14" "^1.0.0"
"@tsconfig/node16" "^1.0.2"
acorn "^8.4.1"
acorn-walk "^8.1.1"
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
typescript@^5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826"
integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
webidl-conversions@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz"
integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==
whatwg-url@^11.0.0:
version "11.0.0"
resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz"
integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==
dependencies:
tr46 "^3.0.0"
webidl-conversions "^7.0.0"
yn@3.1.1:
version "3.1.1"
resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==