diff --git a/.gitignore b/.gitignore index 1c45eedf3..6c1a3bef1 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ coverage # api api/oracle-cloud/build api/fetch_cache +api/sqlite_db api/nodemon.json # web diff --git a/api/db/migrations/0000_sudden_doctor_doom.sql b/api/db/migrations/0000_sudden_doctor_doom.sql new file mode 100644 index 000000000..9bc405bec --- /dev/null +++ b/api/db/migrations/0000_sudden_doctor_doom.sql @@ -0,0 +1,48 @@ +CREATE TABLE `contributions` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `record_imported_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL, + `title` text NOT NULL, + `updated_at` text NOT NULL, + `url` text NOT NULL, + `type` text NOT NULL, + `run_id` text NOT NULL, + `activity_count` integer NOT NULL, + `repository_id` integer NOT NULL, + `contributor_id` integer NOT NULL, + FOREIGN KEY (`repository_id`) REFERENCES `repositories`(`id`) ON UPDATE no action ON DELETE no action, + FOREIGN KEY (`contributor_id`) REFERENCES `contributors`(`id`) ON UPDATE no action ON DELETE no action +); +--> statement-breakpoint +CREATE TABLE `contributors` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `record_imported_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL, + `run_id` text DEFAULT 'initial-run-id' NOT NULL, + `name` text NOT NULL, + `username` text NOT NULL, + `url` text NOT NULL, + `avatar_url` text NOT NULL +); +--> statement-breakpoint +CREATE TABLE `projects` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `record_imported_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL, + `name` text NOT NULL, + `slug` text NOT NULL, + `run_id` text DEFAULT 'initial-run-id' NOT NULL +); +--> statement-breakpoint +CREATE TABLE `repositories` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `record_imported_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL, + `provider` text NOT NULL, + `owner` text NOT NULL, + `name` text NOT NULL, + `run_id` text DEFAULT 'initial-run-id' NOT NULL, + `project_id` integer NOT NULL, + FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE no action +); +--> statement-breakpoint +CREATE UNIQUE INDEX `contributions_url_unique` ON `contributions` (`url`);--> statement-breakpoint +CREATE UNIQUE INDEX `contributors_url_unique` ON `contributors` (`url`);--> statement-breakpoint +CREATE UNIQUE INDEX `projects_slug_unique` ON `projects` (`slug`);--> statement-breakpoint +CREATE UNIQUE INDEX `repositories_provider_owner_name_unique` ON `repositories` (`provider`,`owner`,`name`); \ No newline at end of file diff --git a/api/db/migrations/0001_black_eternals.sql b/api/db/migrations/0001_black_eternals.sql new file mode 100644 index 000000000..c3109ac28 --- /dev/null +++ b/api/db/migrations/0001_black_eternals.sql @@ -0,0 +1,10 @@ +CREATE TABLE `contributor_repository_relation` ( + `contributor_id` integer NOT NULL, + `repository_id` integer NOT NULL, + `record_imported_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL, + `run_id` text DEFAULT 'initial-run-id' NOT NULL, + `score` integer NOT NULL, + PRIMARY KEY(`contributor_id`, `repository_id`), + FOREIGN KEY (`contributor_id`) REFERENCES `contributors`(`id`) ON UPDATE no action ON DELETE no action, + FOREIGN KEY (`repository_id`) REFERENCES `repositories`(`id`) ON UPDATE no action ON DELETE no action +); diff --git a/api/db/migrations/meta/0000_snapshot.json b/api/db/migrations/meta/0000_snapshot.json new file mode 100644 index 000000000..04bb43a03 --- /dev/null +++ b/api/db/migrations/meta/0000_snapshot.json @@ -0,0 +1,316 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "ba41012f-4495-42ff-ace1-61bd7eaef476", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "contributions": { + "name": "contributions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "record_imported_at": { + "name": "record_imported_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "activity_count": { + "name": "activity_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "repository_id": { + "name": "repository_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "contributor_id": { + "name": "contributor_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "contributions_url_unique": { + "name": "contributions_url_unique", + "columns": ["url"], + "isUnique": true + } + }, + "foreignKeys": { + "contributions_repository_id_repositories_id_fk": { + "name": "contributions_repository_id_repositories_id_fk", + "tableFrom": "contributions", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "contributions_contributor_id_contributors_id_fk": { + "name": "contributions_contributor_id_contributors_id_fk", + "tableFrom": "contributions", + "tableTo": "contributors", + "columnsFrom": ["contributor_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "contributors": { + "name": "contributors", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "record_imported_at": { + "name": "record_imported_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'initial-run-id'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "contributors_url_unique": { + "name": "contributors_url_unique", + "columns": ["url"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "projects": { + "name": "projects", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "record_imported_at": { + "name": "record_imported_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'initial-run-id'" + } + }, + "indexes": { + "projects_slug_unique": { + "name": "projects_slug_unique", + "columns": ["slug"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "repositories": { + "name": "repositories", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "record_imported_at": { + "name": "record_imported_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'initial-run-id'" + }, + "project_id": { + "name": "project_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "repositories_provider_owner_name_unique": { + "name": "repositories_provider_owner_name_unique", + "columns": ["provider", "owner", "name"], + "isUnique": true + } + }, + "foreignKeys": { + "repositories_project_id_projects_id_fk": { + "name": "repositories_project_id_projects_id_fk", + "tableFrom": "repositories", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/api/db/migrations/meta/0001_snapshot.json b/api/db/migrations/meta/0001_snapshot.json new file mode 100644 index 000000000..67f027972 --- /dev/null +++ b/api/db/migrations/meta/0001_snapshot.json @@ -0,0 +1,386 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "d99b3c61-9212-4dde-814c-d4cbac5ea54d", + "prevId": "ba41012f-4495-42ff-ace1-61bd7eaef476", + "tables": { + "contributions": { + "name": "contributions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "record_imported_at": { + "name": "record_imported_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "activity_count": { + "name": "activity_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "repository_id": { + "name": "repository_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "contributor_id": { + "name": "contributor_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "contributions_url_unique": { + "name": "contributions_url_unique", + "columns": ["url"], + "isUnique": true + } + }, + "foreignKeys": { + "contributions_repository_id_repositories_id_fk": { + "name": "contributions_repository_id_repositories_id_fk", + "tableFrom": "contributions", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "contributions_contributor_id_contributors_id_fk": { + "name": "contributions_contributor_id_contributors_id_fk", + "tableFrom": "contributions", + "tableTo": "contributors", + "columnsFrom": ["contributor_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "contributor_repository_relation": { + "name": "contributor_repository_relation", + "columns": { + "contributor_id": { + "name": "contributor_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "repository_id": { + "name": "repository_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "record_imported_at": { + "name": "record_imported_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'initial-run-id'" + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "contributor_repository_relation_contributor_id_contributors_id_fk": { + "name": "contributor_repository_relation_contributor_id_contributors_id_fk", + "tableFrom": "contributor_repository_relation", + "tableTo": "contributors", + "columnsFrom": ["contributor_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "contributor_repository_relation_repository_id_repositories_id_fk": { + "name": "contributor_repository_relation_repository_id_repositories_id_fk", + "tableFrom": "contributor_repository_relation", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "contributor_repository_relation_pk": { + "columns": ["contributor_id", "repository_id"], + "name": "contributor_repository_relation_pk" + } + }, + "uniqueConstraints": {} + }, + "contributors": { + "name": "contributors", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "record_imported_at": { + "name": "record_imported_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'initial-run-id'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "contributors_url_unique": { + "name": "contributors_url_unique", + "columns": ["url"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "projects": { + "name": "projects", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "record_imported_at": { + "name": "record_imported_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'initial-run-id'" + } + }, + "indexes": { + "projects_slug_unique": { + "name": "projects_slug_unique", + "columns": ["slug"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "repositories": { + "name": "repositories", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "record_imported_at": { + "name": "record_imported_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'initial-run-id'" + }, + "project_id": { + "name": "project_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "repositories_provider_owner_name_unique": { + "name": "repositories_provider_owner_name_unique", + "columns": ["provider", "owner", "name"], + "isUnique": true + } + }, + "foreignKeys": { + "repositories_project_id_projects_id_fk": { + "name": "repositories_project_id_projects_id_fk", + "tableFrom": "repositories", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/api/db/migrations/meta/_journal.json b/api/db/migrations/meta/_journal.json new file mode 100644 index 000000000..7da2d65ac --- /dev/null +++ b/api/db/migrations/meta/_journal.json @@ -0,0 +1,20 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1725654548149, + "tag": "0000_sudden_doctor_doom", + "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1725790243766, + "tag": "0001_black_eternals", + "breakpoints": true + } + ] +} diff --git a/api/drizzle.config.ts b/api/drizzle.config.ts new file mode 100644 index 000000000..e4f7ef132 --- /dev/null +++ b/api/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + schema: "src/**/*table.ts", + out: "./db/migrations", + dialect: "sqlite", +}); diff --git a/api/oracle-cloud/deploy.ts b/api/oracle-cloud/deploy.ts index 271c8f602..cf1353a12 100644 --- a/api/oracle-cloud/deploy.ts +++ b/api/oracle-cloud/deploy.ts @@ -10,7 +10,7 @@ const stdout = execSync( "lerna list --include-dependencies --json --all --loglevel silent --scope @dzcode.io/api", ); const dependencies = JSON.parse(stdout.toString()) as Array<{ name: string; location: string }>; -const subPaths = ["dist", "package.json", "models"]; +const subPaths = ["dist", "package.json", "models", "db"]; const workspaceRoot = join(__dirname, "../.."); const fromToRecords = dependencies .map<{ from: string; to: string }>(({ location }) => ({ diff --git a/api/oracle-cloud/docker-compose.yml b/api/oracle-cloud/docker-compose.yml index c66ec79cb..d3e522570 100644 --- a/api/oracle-cloud/docker-compose.yml +++ b/api/oracle-cloud/docker-compose.yml @@ -9,3 +9,4 @@ services: - /home/ubuntu/app-env/api.env volumes: - /home/ubuntu/app-data/api/fetch_cache:/usr/src/repo/api/fetch_cache + - /home/ubuntu/app-data/api/sqlite_db:/usr/src/repo/api/sqlite_db diff --git a/api/package.json b/api/package.json index dd9f9c57a..c978f7c83 100644 --- a/api/package.json +++ b/api/package.json @@ -10,29 +10,31 @@ "@dzcode.io/data": "*", "@dzcode.io/models": "*", "@dzcode.io/utils": "*", - "@sentry/node": "^7.46.0", - "@sentry/tracing": "^7.46.0", + "@sentry/node": "^8.28.0", + "@sentry/profiling-node": "^8.28.0", + "better-sqlite3": "^11.2.1", "class-transformer": "^0.5.1", - "class-validator": "^0.13.2", - "class-validator-jsonschema": "^3.1.0", + "class-validator": "^0.14.1", "cors": "^2.8.5", + "cron": "^3.1.7", "dotenv": "^8.2.0", + "drizzle-orm": "^0.33.0", "express": "^4.17.1", "express-rate-limit": "^5.2.6", "express-robots-txt": "^1.0.0", "fs-extra": "^10.0.0", "helmet": "^4.4.1", + "lodash": "^4.17.21", "make-fetch-happen": "^9.0.2", "morgan": "^1.10.0", - "reflect-metadata": "^0.1.13", + "reflect-metadata": "^0.2.2", "routing-controllers": "^0.9.0", - "routing-controllers-openapi": "^3.1.0", - "swagger-ui-express": "^4.1.6", "typedi": "^0.10.0", "winston": "^3.3.3" }, "devDependencies": { "@dzcode.io/tooling": "*", + "@types/better-sqlite3": "^7.6.11", "@types/body-parser": "^1.19.0", "@types/cors": "^2.8.9", "@types/express": "^4.17.9", @@ -40,14 +42,15 @@ "@types/faker": "^5.5.6", "@types/fs-extra": "^9.0.13", "@types/glob": "^7.1.4", + "@types/lodash": "^4.17.7", "@types/make-fetch-happen": "^9.0.1", "@types/morgan": "^1.9.2", - "@types/swagger-ui-express": "^4.1.2", + "drizzle-kit": "^0.24.2", "faker": "^5.5.3", "glob": "^7.1.7" }, "engines": { - "node": ">=16", + "node": ">=20", "yarn": ">=1.4.2" }, "license": "MIT", @@ -69,6 +72,7 @@ "build:watch": "lerna run build:alone:watch --scope=@dzcode.io/api --include-dependencies --parallel", "clean": "lerna run clean:alone --scope=@dzcode.io/api --include-dependencies --stream", "clean:alone": "rimraf dist coverage fetch_cache oracle-cloud/build", + "db:generate-migration": "drizzle-kit generate", "deploy": "rimraf ./oracle-cloud/build && ts-node oracle-cloud/deploy.ts production", "deploy:stg": "rimraf ./oracle-cloud/build && ts-node oracle-cloud/deploy.ts staging", "generate:bundle-info": "ts-node ../packages/tooling/bundle-info.ts", @@ -78,7 +82,7 @@ "lint:eslint": "eslint --config ../packages/tooling/.eslintrc.json --ignore-path ../packages/tooling/.eslintignore --report-unused-disable-directives", "lint:fix": "yarn build && yarn lint:fix:alone", "lint:fix:alone": "yarn lint:eslint --fix . && yarn lint:prettier --write .", - "lint:prettier": "prettier --config ../packages/tooling/.prettierrc --ignore-path ../packages/tooling/.prettierignore --loglevel warn", + "lint:prettier": "prettier --config ../packages/tooling/.prettierrc --ignore-path ../packages/tooling/.prettierignore --log-level warn", "lint:ts-prune": "ts-node ../packages/tooling/setup-ts-prune.ts && ts-prune --error", "lint:tsc": "tspc --noEmit", "start": "node dist/app/index.js", diff --git a/api/src/_test/mocks.ts b/api/src/_test/mocks.ts deleted file mode 100644 index 34c50b2a5..000000000 --- a/api/src/_test/mocks.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-disable camelcase */ -import { GithubUser } from "src/github/types"; - -export const githubUserMock: GithubUser = { - login: "ZibanPirate", - id: 20110076, - node_id: "MDQ6VXNlcjIwMTEwMDc2", - avatar_url: "https://avatars.githubusercontent.com/u/20110076?v=4", - gravatar_id: "", - url: "https://api.github.com/users/ZibanPirate", - html_url: "https://github.com/ZibanPirate", - followers_url: "https://api.github.com/users/ZibanPirate/followers", - following_url: "https://api.github.com/users/ZibanPirate/following{/other_user}", - gists_url: "https://api.github.com/users/ZibanPirate/gists{/gist_id}", - starred_url: "https://api.github.com/users/ZibanPirate/starred{/owner}{/repo}", - subscriptions_url: "https://api.github.com/users/ZibanPirate/subscriptions", - organizations_url: "https://api.github.com/users/ZibanPirate/orgs", - repos_url: "https://api.github.com/users/ZibanPirate/repos", - events_url: "https://api.github.com/users/ZibanPirate/events{/privacy}", - received_events_url: "https://api.github.com/users/ZibanPirate/received_events", - type: "User", - site_admin: false, - name: "Zakaria Mansouri", - company: "@dzcode-io @avimedical", - blog: "zak.dzcode.io", - location: "Algeria", - email: "", - hireable: true, - bio: "One-man-army lone programmer", - twitter_username: "ZibanPirate", - public_repos: 18, - public_gists: 2, - followers: 130, - following: 92, - created_at: "2016-06-23T12:41:14Z", - updated_at: "2023-04-10T21:31:26Z", -}; diff --git a/api/src/_utils/case.ts b/api/src/_utils/case.ts new file mode 100644 index 000000000..212f42055 --- /dev/null +++ b/api/src/_utils/case.ts @@ -0,0 +1,22 @@ +import camelCase from "lodash/camelCase"; +import mapKeys from "lodash/mapKeys"; + +export function camelCaseObject(obj: T): T { + if (typeof obj !== "object") { + return obj; + } + + if (Array.isArray(obj)) { + return obj.map((item) => camelCaseObject(item)) as unknown as T; + } + + const mappedRootKeys = mapKeys(obj, (value, key) => camelCase(key)) as T; + + for (const key in mappedRootKeys) { + if (typeof mappedRootKeys[key] === "object") { + (mappedRootKeys[key] as unknown) = camelCaseObject(mappedRootKeys[key] as any); // eslint-disable-line @typescript-eslint/no-explicit-any + } + } + + return mappedRootKeys; +} diff --git a/api/src/_utils/reverse-hierarchy.ts b/api/src/_utils/reverse-hierarchy.ts new file mode 100644 index 000000000..eb9673e7d --- /dev/null +++ b/api/src/_utils/reverse-hierarchy.ts @@ -0,0 +1,47 @@ +type ForeignKeyParentKeyRecord = { from: string; setParentAs: string }; + +export function reverseHierarchy( + _obj: unknown, + foreignKeyParentKeyRecord: ForeignKeyParentKeyRecord[], + parentWithItsKey: Record = {}, + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): any { + if (Array.isArray(_obj)) { + return _obj + .map((item) => reverseHierarchy(item, foreignKeyParentKeyRecord, parentWithItsKey)) + .reduce((pV, cV) => [...pV, ...cV], []); + } + + if (typeof _obj !== "object") { + return _obj; + } + + const obj = { ..._obj, ...parentWithItsKey }; + + const objWithRecognizedKeys: Record = {}; + const objWithoutRecognizedKeys: Record = {}; + for (const [key, value] of Object.entries(obj)) { + const mappedKey = foreignKeyParentKeyRecord.find(({ from: mk }) => mk === key)?.from; + if (mappedKey) objWithRecognizedKeys[mappedKey] = value; + else objWithoutRecognizedKeys[key] = value; + } + + if (Object.keys(objWithRecognizedKeys).length > 0) { + let res: unknown[] = []; + for (const recognizedKey in objWithRecognizedKeys) { + if (Object.prototype.hasOwnProperty.call(objWithRecognizedKeys, recognizedKey)) { + const recognizedObj = objWithRecognizedKeys[recognizedKey]; + const { setParentAs } = foreignKeyParentKeyRecord.find( + ({ from }) => from === recognizedKey, + ) as ForeignKeyParentKeyRecord; + const reversedPredecessor = reverseHierarchy(recognizedObj, foreignKeyParentKeyRecord, { + [setParentAs]: objWithoutRecognizedKeys, + }); + res = res.concat(reversedPredecessor); + } + } + return res; + } + + return [objWithoutRecognizedKeys]; +} diff --git a/api/src/_utils/setup-sentry.ts b/api/src/_utils/setup-sentry.ts new file mode 100644 index 000000000..0ea1bb005 --- /dev/null +++ b/api/src/_utils/setup-sentry.ts @@ -0,0 +1,17 @@ +import * as Sentry from "@sentry/node"; +import { nodeProfilingIntegration } from "@sentry/profiling-node"; +import { generateConfig } from "src/config/generate-config"; + +const { NODE_ENV, BUNDLE_INFO } = generateConfig(); + +if (NODE_ENV !== "development") { + Sentry.init({ + dsn: "https://5f9d7ae6e98944e1815f8d1944fc3c12@o953637.ingest.sentry.io/5904452", + integrations: [nodeProfilingIntegration()], + tracesSampleRate: NODE_ENV === "production" ? 0.1 : 1.0, + profilesSampleRate: 1.0, // relative to tracesSampleRate + environment: NODE_ENV, + debug: NODE_ENV !== "production", + release: `api@${BUNDLE_INFO.version}`, + }); +} diff --git a/api/src/_utils/unstringify-deep.ts b/api/src/_utils/unstringify-deep.ts new file mode 100644 index 000000000..8ac0490b0 --- /dev/null +++ b/api/src/_utils/unstringify-deep.ts @@ -0,0 +1,34 @@ +/** + * Recursively look for any string field that starts with `[{"` or `{"` and parse it + unStringify + * its children. + */ + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function unStringifyDeep(obj: any): any { + if (Array.isArray(obj)) { + return obj.map((item) => unStringifyDeep(item)) as unknown as typeof obj; + } + + if (typeof obj !== "object" || obj === null) { + return obj; + } + + const result = { ...obj }; + + for (const key in result) { + if (typeof result[key] === "string") { + try { + const value = JSON.parse(result[key]); + if (typeof value === "object") { + result[key] = unStringifyDeep(value); + } else { + result[key] = value; + } + } catch (error) { + // ignore + } + } + } + + return result as typeof obj; +} diff --git a/api/src/app/endpoints.ts b/api/src/app/endpoints.ts index 0cf5e8fa6..bfccfc8b8 100644 --- a/api/src/app/endpoints.ts +++ b/api/src/app/endpoints.ts @@ -1,37 +1,20 @@ -import { GetArticleResponseDto, GetArticlesResponseDto } from "src/article/types"; -import { GetContributionsResponseDto } from "src/contribution/types"; -import { GetADocumentationResponseDto, GetDocumentationResponseDto } from "src/documentation/types"; -import { GetMilestonesResponseDto } from "src/milestone/types"; -import { GetProjectsResponseDto } from "src/project/types"; -import { GetTeamResponseDto } from "src/team/types"; +import { GetContributionsResponse } from "src/contribution/types"; +import { GetContributorsResponse } from "src/contributor/types"; +import { GetMilestonesResponse } from "src/milestone/types"; +import { GetProjectsResponse } from "src/project/types"; // ts-prune-ignore-next export interface Endpoints { - "api:Articles": { - response: GetArticlesResponseDto; - }; - "api:Articles/:slug": { - response: GetArticleResponseDto; - params: { slug: string }; - }; - "api:Documentation": { - response: GetDocumentationResponseDto; - }; - "api:Documentation/:slug": { - response: GetADocumentationResponseDto; - params: { slug: string }; - }; "api:Projects": { - response: GetProjectsResponseDto; + response: GetProjectsResponse; }; "api:Contributions": { - response: GetContributionsResponseDto; - query: [string, string][]; + response: GetContributionsResponse; }; - "api:Team": { - response: GetTeamResponseDto; + "api:Contributors": { + response: GetContributorsResponse; }; "api:MileStones/dzcode": { - response: GetMilestonesResponseDto; + response: GetMilestonesResponse; }; } diff --git a/api/src/app/index.ts b/api/src/app/index.ts index b4e95e402..0bd628eba 100644 --- a/api/src/app/index.ts +++ b/api/src/app/index.ts @@ -1,63 +1,50 @@ +// @TODO-ZM: remove the need for reflect-metadata +// Import these two first! in this order import "reflect-metadata"; +import "src/_utils/setup-sentry"; import { fsConfig } from "@dzcode.io/utils/dist/config"; import * as Sentry from "@sentry/node"; import { Application } from "express"; import { createExpressServer, RoutingControllersOptions, useContainer } from "routing-controllers"; -import { ArticleController } from "src/article/controller"; import { ConfigService } from "src/config/service"; import { ContributionController } from "src/contribution/controller"; -import { DocumentationController } from "src/documentation/controller"; +import { ContributorController } from "src/contributor/controller"; +import { DigestCron } from "src/digest/cron"; import { GithubController } from "src/github/controller"; import { LoggerService } from "src/logger/service"; import { MilestoneController } from "src/milestone/controller"; import { ProjectController } from "src/project/controller"; -import { TeamController } from "src/team/controller"; +import { SQLiteService } from "src/sqlite/service"; import Container from "typedi"; -import { DocsMiddleware } from "./middlewares/docs"; import { ErrorMiddleware } from "./middlewares/error"; import { LoggerMiddleware } from "./middlewares/logger"; import { RobotsMiddleware } from "./middlewares/robots"; import { SecurityMiddleware } from "./middlewares/security"; -import { SentryErrorHandlerMiddleware } from "./middlewares/sentry-error-handler"; -import { SentryRequestHandlerMiddleware } from "./middlewares/sentry-request-handler"; // Use typedi container useContainer(Container); -const { NODE_ENV, PORT, BUNDLE_INFO } = Container.get(ConfigService).env(); +// Initialize Database +Container.get(SQLiteService); -if (NODE_ENV !== "development") { - Sentry.init({ - dsn: "https://5f9d7ae6e98944e1815f8d1944fc3c12@o953637.ingest.sentry.io/5904452", - tracesSampleRate: 1.0, - environment: NODE_ENV, - debug: NODE_ENV !== "production", - release: `api@${BUNDLE_INFO.version}`, - }); -} +const { NODE_ENV, PORT } = Container.get(ConfigService).env(); + +// Add crons to DI container +const CronServices = [DigestCron]; +CronServices.forEach((service) => Container.get(service)); // Create the app: -export const routingControllersOptions: RoutingControllersOptions = { +const routingControllersOptions: RoutingControllersOptions = { controllers: [ ContributionController, - TeamController, GithubController, MilestoneController, ProjectController, - ArticleController, - DocumentationController, - ], - middlewares: [ - SentryRequestHandlerMiddleware, - SecurityMiddleware, - SentryErrorHandlerMiddleware, - ErrorMiddleware, - LoggerMiddleware, - DocsMiddleware, - RobotsMiddleware, + ContributorController, ], + middlewares: [SecurityMiddleware, ErrorMiddleware, LoggerMiddleware, RobotsMiddleware], defaultErrorHandler: false, cors: Container.get(SecurityMiddleware).cors(), }; @@ -65,8 +52,10 @@ const app: Application = createExpressServer(routingControllersOptions); const logger = Container.get(LoggerService); +Sentry.setupExpressErrorHandler(app); + // Start it app.listen(PORT, () => { const commonConfig = fsConfig(NODE_ENV); - logger.info({ message: `API Server up on: ${commonConfig.api.url}/docs` }); + logger.info({ message: `API Server up on: ${commonConfig.api.url}/` }); }); diff --git a/api/src/app/middlewares/docs.ts b/api/src/app/middlewares/docs.ts deleted file mode 100644 index f2d5b91ea..000000000 --- a/api/src/app/middlewares/docs.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { RequestHandler, Router } from "express"; -import { ExpressMiddlewareInterface, Middleware } from "routing-controllers"; -import { ConfigService } from "src/config/service"; -import { serve, setup } from "swagger-ui-express"; -import { Service } from "typedi"; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { defaultMetadataStorage } = require("class-transformer/cjs/storage"); -import { validationMetadatasToSchemas } from "class-validator-jsonschema"; -import { getMetadataArgsStorage } from "routing-controllers"; -import { routingControllersToSpec } from "routing-controllers-openapi"; - -import { routingControllersOptions } from ".."; - -@Service() -@Middleware({ type: "after" }) -export class DocsMiddleware implements ExpressMiddlewareInterface { - constructor(private configService: ConfigService) { - // Parse class-validator classes into JSON Schema: - const schemas = validationMetadatasToSchemas({ - refPointerPrefix: "#/components/schemas/", - classTransformerMetadataStorage: defaultMetadataStorage, - }); - // Parse routing-controllers classes into OpenAPI spec: - const storage = getMetadataArgsStorage(); - const spec = routingControllersToSpec(storage, routingControllersOptions, { - components: { schemas }, - info: { - description: "Swagger documentation for dzcode.io API", - title: "dzcode.io API", - version: configService.env().BUNDLE_INFO.version, - }, - }); - - this.router.use("/docs", serve, setup(spec)); - } - - private router = Router(); - - use: RequestHandler = this.router; -} diff --git a/api/src/app/middlewares/error.ts b/api/src/app/middlewares/error.ts index ba8d25cca..f951d978f 100644 --- a/api/src/app/middlewares/error.ts +++ b/api/src/app/middlewares/error.ts @@ -1,6 +1,6 @@ import { ErrorRequestHandler } from "express"; import { ExpressErrorMiddlewareInterface, Middleware } from "routing-controllers"; -import { GeneralResponseDto } from "src/app/types"; +import { GeneralResponse } from "src/app/types"; import { LoggerService } from "src/logger/service"; import { Service } from "typedi"; @@ -9,7 +9,7 @@ import { Service } from "typedi"; export class ErrorMiddleware implements ExpressErrorMiddlewareInterface { constructor(private loggerService: LoggerService) {} - error: ErrorRequestHandler = (err, req, res, next) => { + error: ErrorRequestHandler = (err, req, res, next) => { // Logs error this.loggerService.error({ message: "Internal Server Error", diff --git a/api/src/app/middlewares/security.ts b/api/src/app/middlewares/security.ts index dc47787d5..f62bddd62 100644 --- a/api/src/app/middlewares/security.ts +++ b/api/src/app/middlewares/security.ts @@ -3,8 +3,8 @@ import { RequestHandler, Router } from "express"; import rateLimit from "express-rate-limit"; import helmet from "helmet"; import { ExpressMiddlewareInterface, Middleware } from "routing-controllers"; -import { ENVDto } from "src/config/dto"; import { ConfigService } from "src/config/service"; +import { EnvRecord } from "src/config/types"; import { Service } from "typedi"; @Service() @@ -16,8 +16,8 @@ export class SecurityMiddleware implements ExpressMiddlewareInterface { this.env === "staging" ? ["https://stage.dzcode.io"] : this.env === "production" - ? ["https://www.dzcode.io"] - : []; + ? ["https://www.dzcode.io"] + : []; this.router.use(helmet()); @@ -30,7 +30,7 @@ export class SecurityMiddleware implements ExpressMiddlewareInterface { } private router = Router(); - private env: ENVDto["NODE_ENV"]; + private env: EnvRecord["NODE_ENV"]; private whitelist: string[]; use: RequestHandler = this.router; diff --git a/api/src/app/middlewares/sentry-error-handler.ts b/api/src/app/middlewares/sentry-error-handler.ts deleted file mode 100644 index e34f181fc..000000000 --- a/api/src/app/middlewares/sentry-error-handler.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as Sentry from "@sentry/node"; -import { RequestHandler } from "express"; -import { ExpressErrorMiddlewareInterface, Middleware } from "routing-controllers"; -import { Service } from "typedi"; - -@Service() -@Middleware({ type: "after" }) -export class SentryErrorHandlerMiddleware implements ExpressErrorMiddlewareInterface { - error: RequestHandler = - Sentry.Handlers.errorHandler() as unknown as SentryErrorHandlerMiddleware["error"]; -} diff --git a/api/src/app/middlewares/sentry-request-handler.ts b/api/src/app/middlewares/sentry-request-handler.ts deleted file mode 100644 index 12dc39c50..000000000 --- a/api/src/app/middlewares/sentry-request-handler.ts +++ /dev/null @@ -1,10 +0,0 @@ -import * as Sentry from "@sentry/node"; -import { RequestHandler } from "express"; -import { ExpressMiddlewareInterface, Middleware } from "routing-controllers"; -import { Service } from "typedi"; - -@Service() -@Middleware({ type: "before", priority: 0 }) -export class SentryRequestHandlerMiddleware implements ExpressMiddlewareInterface { - use: RequestHandler = Sentry.Handlers.requestHandler(); -} diff --git a/api/src/app/types/index.ts b/api/src/app/types/index.ts index 868ed103e..6aefa8215 100644 --- a/api/src/app/types/index.ts +++ b/api/src/app/types/index.ts @@ -1,17 +1,5 @@ -import "reflect-metadata"; - -import { IsNumber, IsObject, IsOptional, IsString } from "class-validator"; - -export class GeneralResponseDto { - @IsNumber() - @IsOptional() +export interface GeneralResponse { code?: number; - - @IsString() - @IsOptional() msg?: string; - - @IsObject() - @IsOptional() debug?: Record; } diff --git a/api/src/article/controller.ts b/api/src/article/controller.ts deleted file mode 100644 index 295f269fe..000000000 --- a/api/src/article/controller.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Controller, Get, Param } from "routing-controllers"; -import { OpenAPI, ResponseSchema } from "routing-controllers-openapi"; -import { DataService } from "src/data/service"; -import { GithubService } from "src/github/service"; -import { GithubUser } from "src/github/types"; -import { Service } from "typedi"; - -import { GetArticleResponseDto, GetArticlesResponseDto } from "./types"; - -@Service() -@Controller("/Articles") -export class ArticleController { - constructor( - private readonly githubService: GithubService, - private readonly dataService: DataService, - ) {} - - @Get("/") - @OpenAPI({ - summary: "Return list of all articles", - }) - @ResponseSchema(GetArticlesResponseDto) - public async getArticles(): Promise { - // get articles from /data folder: - const articles = await this.dataService.listArticles(); - - return { - articles, - }; - } - - @Get("/:slug(*)") - @OpenAPI({ - summary: "Return info about a single article", - }) - @ResponseSchema(GetArticleResponseDto) - public async getArticle(@Param("slug") slug: string): Promise { - // get articles from /data folder: - const { ...article } = await this.dataService.getArticle(slug); - - // get authors and contributors info from github: - const authors = await Promise.all( - article.authors.map(async (author) => { - const githubUser = await this.githubService.getUser({ username: author }); - return this.githubService.githubUserToAccountEntity(githubUser); - }), - ); - - const committersBatches = await Promise.all([ - // current place for data: - this.githubService.listPathCommitters({ - owner: "dzcode-io", - repository: "dzcode.io", - path: `data/models/articles/${slug}`, - }), - // also check old place for data, to not lose contribution effort: - this.githubService.listPathCommitters({ - owner: "dzcode-io", - repository: "dzcode.io", - path: `data/articles/${slug}`, - }), - ]); - - // filter and sort contributors: - const uniqUsernames: Record = {}; - const contributors: GetArticleResponseDto["article"]["contributors"] = [ - ...committersBatches[0], - ...committersBatches[1], - ] - .reduce((pV, cV) => { - if (uniqUsernames[cV.login]) { - uniqUsernames[cV.login]++; - return pV; - } else { - uniqUsernames[cV.login] = 1; - return [...pV, cV]; - } - }, []) - .sort((a, b) => uniqUsernames[b.login] - uniqUsernames[a.login]) - .map((committer) => this.githubService.githubUserToAccountEntity(committer)) - .filter(({ id }) => !authors.find((author) => author.id === id)); - - return { - article: { - ...article, - authors, - contributors, - }, - }; - } -} diff --git a/api/src/article/types.ts b/api/src/article/types.ts deleted file mode 100644 index 753535c20..000000000 --- a/api/src/article/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Model } from "@dzcode.io/models/dist/_base"; -import { ArticleEntity, ArticleInfoEntity } from "@dzcode.io/models/dist/article"; -import { Type } from "class-transformer"; -import { ValidateNested } from "class-validator"; -import { GeneralResponseDto } from "src/app/types"; - -export class GetArticlesResponseDto extends GeneralResponseDto { - @ValidateNested({ each: true }) - @Type(() => ArticleInfoEntity) - articles!: Model[]; -} - -export class GetArticleResponseDto extends GeneralResponseDto { - @ValidateNested() - article!: Model; -} diff --git a/api/src/config/generate-config.ts b/api/src/config/generate-config.ts new file mode 100644 index 000000000..34cd90edc --- /dev/null +++ b/api/src/config/generate-config.ts @@ -0,0 +1,31 @@ +import { plainToClass } from "class-transformer"; +import { validateSync } from "class-validator"; +import { config } from "dotenv"; + +import { EnvRecord } from "./types"; + +let cachedEnv: EnvRecord | undefined = undefined; + +export function generateConfig(): EnvRecord { + if (cachedEnv) return cachedEnv; + + const _config = config(); + const output = plainToClass(EnvRecord, { + ...process.env, + ...(_config.parsed || {}), + }); + + const errors = validateSync(output); + + if (errors.length > 0) + throw new Error( + `⚠️ Errors in .env file in the following keys:${errors.reduce( + (pV, cV) => (pV += "\n" + cV.property + " : " + JSON.stringify(cV.constraints)), + "", + )}`, + ); + + cachedEnv = output; + + return output; +} diff --git a/api/src/config/service.ts b/api/src/config/service.ts index 26590d5b6..37162dc5b 100644 --- a/api/src/config/service.ts +++ b/api/src/config/service.ts @@ -1,37 +1,15 @@ -import { plainToClass } from "class-transformer"; -import { validateSync } from "class-validator"; -import { config } from "dotenv"; import { Service } from "typedi"; -import { ENVDto } from "./dto"; +import { generateConfig } from "./generate-config"; +import { EnvRecord } from "./types"; -let _env: ENVDto; +let _env: EnvRecord; @Service() export class ConfigService { constructor() { - this.generateConfig(); + _env = generateConfig(); } public env = () => _env; - - private generateConfig = () => { - const _config = config(); - const output = plainToClass(ENVDto, { - ...process.env, - ...(_config.parsed || {}), - }); - - const errors = validateSync(output); - - if (errors.length > 0) - throw new Error( - `⚠️ Errors in .env file in the following keys:${errors.reduce( - (pV, cV) => (pV += "\n" + cV.property + " : " + JSON.stringify(cV.constraints)), - "", - )}`, - ); - - _env = output; - }; } diff --git a/api/src/config/dto.ts b/api/src/config/types.ts similarity index 87% rename from api/src/config/dto.ts rename to api/src/config/types.ts index d9461218c..4bd23cf43 100644 --- a/api/src/config/dto.ts +++ b/api/src/config/types.ts @@ -10,15 +10,18 @@ try { /**/ } -export class ENVDto { +export class EnvRecord { PORT = 7070; @Matches("(" + environments.join(")|(") + ")") - NODE_ENV: Environment = "development"; + NODE_ENV!: Environment; @IsString() FETCH_CACHE_PATH = "./fetch_cache"; + @IsString() + SQLITE_DB_PATH = "./sqlite_db"; + @IsString() @IsOptional() GITHUB_TOKEN?: string; diff --git a/api/src/contribution/controller.ts b/api/src/contribution/controller.ts index 7bfbea048..22f65106e 100644 --- a/api/src/contribution/controller.ts +++ b/api/src/contribution/controller.ts @@ -1,9 +1,8 @@ -import { Controller, Get, QueryParams } from "routing-controllers"; -import { OpenAPI, ResponseSchema } from "routing-controllers-openapi"; +import { Controller, Get } from "routing-controllers"; import { Service } from "typedi"; import { ContributionRepository } from "./repository"; -import { GetContributionsQueryDto, GetContributionsResponseDto } from "./types"; +import { GetContributionsResponse } from "./types"; @Service() @Controller("/Contributions") @@ -11,28 +10,11 @@ export class ContributionController { constructor(private readonly contributionRepository: ContributionRepository) {} @Get("/") - @OpenAPI({ - summary: "Return a list of contributions for all projects listed in dzcode.io", - }) - @ResponseSchema(GetContributionsResponseDto) - public async getContributions( - @QueryParams() { labels, languages, projects }: GetContributionsQueryDto, - ): Promise { - const { contributions, filters } = await this.contributionRepository.find( - (contribution) => - !contribution.createdBy.username.includes("[bot]") && - (labels.length === 0 || labels.some((label) => contribution.labels.includes(label))) && - (languages.length === 0 || - languages.some((language) => contribution.languages.includes(language))) && - (projects.length === 0 || - projects.some((project) => { - return contribution.project.slug === project; - })), - ); + public async getContributions(): Promise { + const contributions = await this.contributionRepository.findForList(); return { contributions, - filters, }; } } diff --git a/api/src/contribution/repository.ts b/api/src/contribution/repository.ts index 2eda63401..c0d7891c4 100644 --- a/api/src/contribution/repository.ts +++ b/api/src/contribution/repository.ts @@ -1,124 +1,106 @@ -import { Model } from "@dzcode.io/models/dist/_base"; -import { ContributionEntity } from "@dzcode.io/models/dist/contribution"; -import { DataService } from "src/data/service"; -import { GithubService } from "src/github/service"; -import { LoggerService } from "src/logger/service"; +import { ne, sql } from "drizzle-orm"; +import { camelCaseObject } from "src/_utils/case"; +import { reverseHierarchy } from "src/_utils/reverse-hierarchy"; +import { unStringifyDeep } from "src/_utils/unstringify-deep"; +import { contributorsTable } from "src/contributor/table"; +import { projectsTable } from "src/project/table"; +import { repositoriesTable } from "src/repository/table"; +import { SQLiteService } from "src/sqlite/service"; import { Service } from "typedi"; -import { allFilterNames, FilterDto, GetContributionsResponseDto, OptionDto } from "./types"; +import { ContributionRow, contributionsTable } from "./table"; @Service() export class ContributionRepository { - constructor( - private readonly githubService: GithubService, - private readonly dataService: DataService, - private readonly loggerService: LoggerService, - ) {} + constructor(private readonly sqliteService: SQLiteService) {} - public async find( - filterFn?: (value: ContributionEntity, index: number, array: ContributionEntity[]) => boolean, - ): Promise> { - const projects = await this.dataService.listProjects(); + public async upsert(contribution: ContributionRow) { + return await this.sqliteService.db + .insert(contributionsTable) + .values(contribution) + .onConflictDoUpdate({ + target: [contributionsTable.url], + set: contribution, + }) + .returning({ id: contributionsTable.id }); + } - let contributions = ( - await Promise.all( - projects.reduce[]>[]>( - (pV, { repositories, name, slug }) => [ - ...pV, - ...repositories - .filter(({ provider }) => provider === "github") - .map(async ({ owner, repository }) => { - try { - const issuesIncludingPRs = await this.githubService.listRepositoryIssues({ - owner, - repository, - }); + public async deleteAllButWithRunId(runId: string) { + return await this.sqliteService.db + .delete(contributionsTable) + .where(ne(contributionsTable.runId, runId)); + } - const languages = await this.githubService.listRepositoryLanguages({ - owner, - repository, - }); - return issuesIncludingPRs.map>( - ({ - number, - labels: gLabels, - title, - html_url, // eslint-disable-line camelcase - pull_request, // eslint-disable-line camelcase - created_at, // eslint-disable-line camelcase - updated_at, // eslint-disable-line camelcase - comments, - user, - }) => ({ - id: `${number}`, - labels: gLabels.map(({ name }) => name), - languages, - project: { - slug, - name, - }, - title, - type: pull_request ? "pullRequest" : "issue", // eslint-disable-line camelcase - url: html_url, // eslint-disable-line camelcase - createdAt: created_at, // eslint-disable-line camelcase - updatedAt: updated_at, // eslint-disable-line camelcase - commentsCount: comments, - /* eslint-enable camelcase */ - createdBy: this.githubService.githubUserToAccountEntity(user), - }), - ); - } catch (error) { - this.loggerService.warn({ - message: `Failed to fetch contributions for ${owner}/${repository}: ${error}`, - meta: { owner, repository }, - }); - return []; - } - }), - ], - [], - ), - ) - ).reduce((pV, cV) => [...pV, ...cV], []); - if (filterFn) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - contributions = contributions.filter(filterFn); - } - contributions = contributions.sort( - (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(), - ); + public async findForList() { + const statement = sql` + SELECT + p.id as id, + p.name as name, + json_group_array( + json_object('id', r.id, 'name', r.name, 'owner', r.owner, 'contributions', r.contributions) + ) AS repositories + FROM + (SELECT + r.id as id, + r.owner as owner, + r.name as name, + r.project_id as project_id, + json_group_array( + json_object( + 'id', + c.id, + 'title', + c.title, + 'type', + c.type, + 'url', + c.url, + 'updated_at', + c.updated_at, + 'activity_count', + c.activity_count, + 'contributor', + json_object( + 'id', + cr.id, + 'name', + cr.name, + 'username', + cr.username, + 'avatar_url', + cr.avatar_url + ) + ) + ) AS contributions + FROM + ${contributionsTable} c + INNER JOIN + ${repositoriesTable} r ON c.repository_id = r.id + INNER JOIN + ${contributorsTable} cr ON c.contributor_id = cr.id + GROUP BY + c.id) AS r + INNER JOIN + ${projectsTable} p ON r.project_id = p.id + GROUP BY + p.id + `; - const filters: FilterDto[] = allFilterNames.map((name) => ({ name, options: [] })); + const raw = this.sqliteService.db.all(statement); + const unStringifiedRaw = unStringifyDeep(raw); - contributions.forEach(({ project, languages, labels }) => { - this.pushUniqueOption([{ name: project.slug, label: project.name }], filters[0].options); + const reversed = reverseHierarchy(unStringifiedRaw, [ + { from: "repositories", setParentAs: "project" }, + { from: "contributions", setParentAs: "repository" }, + ]); - this.pushUniqueOption( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - languages.map((language) => ({ name: language })), - filters[1].options, - ); + const camelCased = camelCaseObject(reversed); - this.pushUniqueOption( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - labels.map((label) => ({ name: label })), - filters[2].options, - ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const sortedUpdatedAt = camelCased.sort((a: any, b: any) => { + return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(); }); - return { - contributions, - filters, - }; + return sortedUpdatedAt; } - - private pushUniqueOption = (options: OptionDto[], filterOptions: OptionDto[]) => { - const uniqueOptions = options.filter( - (_option) => !filterOptions.some(({ name }) => _option.name === name), - ); - filterOptions.push(...uniqueOptions); - }; } diff --git a/api/src/contribution/table.ts b/api/src/contribution/table.ts new file mode 100644 index 000000000..e8501a1a4 --- /dev/null +++ b/api/src/contribution/table.ts @@ -0,0 +1,28 @@ +import { ContributionEntity } from "@dzcode.io/models/dist/contribution"; +import { sql } from "drizzle-orm"; +import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; +import { contributorsTable } from "src/contributor/table"; +import { repositoriesTable } from "src/repository/table"; + +export const contributionsTable = sqliteTable("contributions", { + id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }), + recordImportedAt: text("record_imported_at") + .notNull() + .default(sql`CURRENT_TIMESTAMP`), + title: text("title").notNull(), + updatedAt: text("updated_at").notNull(), + url: text("url").notNull().unique(), + type: text("type").notNull().$type(), + runId: text("run_id").notNull(), + activityCount: integer("activity_count").notNull(), + repositoryId: integer("repository_id") + .notNull() + .references(() => repositoriesTable.id), + contributorId: integer("contributor_id") + .notNull() + .references(() => contributorsTable.id), +}); + +contributionsTable.$inferSelect satisfies ContributionEntity; + +export type ContributionRow = typeof contributionsTable.$inferInsert; diff --git a/api/src/contribution/types.ts b/api/src/contribution/types.ts index a80c985c4..8c9f54c2e 100644 --- a/api/src/contribution/types.ts +++ b/api/src/contribution/types.ts @@ -1,64 +1,16 @@ -import { Model } from "@dzcode.io/models/dist/_base"; import { ContributionEntity } from "@dzcode.io/models/dist/contribution"; -import { Transform, TransformFnParams, Type } from "class-transformer"; -import { IsBoolean, IsIn, IsOptional, IsString, ValidateNested } from "class-validator"; -import { GeneralResponseDto } from "src/app/types"; - -export class OptionDto { - @IsString() - @IsOptional() - label?: string; - - @IsString() - name!: string; - - @IsBoolean() - @IsOptional() - checked?: boolean; -} - -export const allFilterNames = ["projects", "languages", "labels"] as const; - -export class FilterDto { - @IsIn(allFilterNames) - name!: typeof allFilterNames[number]; - - @ValidateNested({ each: true }) - @Type(() => OptionDto) - options!: OptionDto[]; -} - -export class GetContributionsResponseDto extends GeneralResponseDto { - @ValidateNested({ each: true }) - @Type(() => ContributionEntity) - contributions!: Model[]; - - @ValidateNested({ each: true }) - @Type(() => FilterDto) - filters!: FilterDto[]; -} - -const transformFilterOptions = ({ value }: TransformFnParams) => { - let filterOptions: string[] = []; - if (typeof value === "string" && value.length > 0) { - filterOptions = value.split(","); - } - if (Array.isArray(value)) { - filterOptions = value; - } - return filterOptions; -}; - -export class GetContributionsQueryDto { - @Transform(transformFilterOptions) - @Reflect.metadata("design:type", { name: "string" }) - projects: string[] = []; - - @Transform(transformFilterOptions) - @Reflect.metadata("design:type", { name: "string" }) - languages: string[] = []; - - @Transform(transformFilterOptions) - @Reflect.metadata("design:type", { name: "string" }) - labels: string[] = []; +import { ContributorEntity } from "@dzcode.io/models/dist/contributor"; +import { ProjectEntity } from "@dzcode.io/models/dist/project"; +import { RepositoryEntity } from "@dzcode.io/models/dist/repository"; +import { GeneralResponse } from "src/app/types"; + +export interface GetContributionsResponse extends GeneralResponse { + contributions: Array< + Pick & { + repository: Pick & { + project: Pick; + }; + contributor: Pick; + } + >; } diff --git a/api/src/contributor/controller.ts b/api/src/contributor/controller.ts new file mode 100644 index 000000000..645853295 --- /dev/null +++ b/api/src/contributor/controller.ts @@ -0,0 +1,20 @@ +import { Controller, Get } from "routing-controllers"; +import { Service } from "typedi"; + +import { ContributorRepository } from "./repository"; +import { GetContributorsResponse } from "./types"; + +@Service() +@Controller("/Contributors") +export class ContributorController { + constructor(private readonly contributorRepository: ContributorRepository) {} + + @Get("/") + public async getContributors(): Promise { + const contributors = await this.contributorRepository.findForList(); + + return { + contributors, + }; + } +} diff --git a/api/src/contributor/repository.ts b/api/src/contributor/repository.ts new file mode 100644 index 000000000..2c010633f --- /dev/null +++ b/api/src/contributor/repository.ts @@ -0,0 +1,137 @@ +import { ne, sql } from "drizzle-orm"; +import { camelCaseObject } from "src/_utils/case"; +import { unStringifyDeep } from "src/_utils/unstringify-deep"; +import { projectsTable } from "src/project/table"; +import { repositoriesTable } from "src/repository/table"; +import { SQLiteService } from "src/sqlite/service"; +import { Service } from "typedi"; + +import { + ContributorRepositoryRelationRow, + contributorRepositoryRelationTable, + ContributorRow, + contributorsTable, +} from "./table"; + +@Service() +export class ContributorRepository { + constructor(private readonly sqliteService: SQLiteService) {} + + public async findForList() { + const statement = sql` + SELECT + sum(c.score) as score, + cr.id as id, + cr.name as name, + cr.username as username, + cr.url as url, + cr.avatar_url as avatar_url, + json_group_array( + json_object( + 'id', + p.id, + 'name', + p.name, + 'score', + c.score, + 'repositories', + c.repositories + ) + ) AS projects + FROM + (SELECT + sum(crr.score) as score, + crr.contributor_id as contributor_id, + crr.project_id as project_id, + json_group_array( + json_object( + 'id', + r.id, + 'owner', + r.owner, + 'name', + r.name, + 'score', + crr.score + ) + ) AS repositories + FROM + (SELECT + contributor_id, + repository_id, + score, + r.project_id as project_id + FROM + ${contributorRepositoryRelationTable} crr + INNER JOIN + ${repositoriesTable} r ON crr.repository_id = r.id + ORDER BY + crr.score DESC + ) as crr + INNER JOIN + ${repositoriesTable} r ON crr.repository_id = r.id + GROUP BY + crr.contributor_id, crr.project_id + ORDER BY + crr.score DESC + ) as c + INNER JOIN + ${contributorsTable} cr ON c.contributor_id = cr.id + INNER JOIN + ${projectsTable} p ON c.project_id = p.id + GROUP BY + c.contributor_id + ORDER BY + score DESC + `; + + const raw = this.sqliteService.db.all(statement); + const unStringifiedRaw = unStringifyDeep(raw); + + const camelCased = camelCaseObject(unStringifiedRaw); + + return camelCased; + } + + public async upsert(contributor: ContributorRow) { + return await this.sqliteService.db + .insert(contributorsTable) + .values(contributor) + .onConflictDoUpdate({ + target: contributorsTable.url, + set: contributor, + }) + .returning({ id: contributorsTable.id }); + } + + public async upsertRelationWithRepository( + contributorRelationWithRepository: ContributorRepositoryRelationRow, + ) { + return await this.sqliteService.db + .insert(contributorRepositoryRelationTable) + .values(contributorRelationWithRepository) + .onConflictDoUpdate({ + target: [ + contributorRepositoryRelationTable.contributorId, + contributorRepositoryRelationTable.repositoryId, + ], + set: contributorRelationWithRepository, + }) + .returning({ + contributorId: contributorRepositoryRelationTable.contributorId, + repositoryId: contributorRepositoryRelationTable.repositoryId, + }); + } + + public async deleteAllRelationWithRepositoryButWithRunId(runId: string) { + return await this.sqliteService.db + .delete(contributorRepositoryRelationTable) + .where(ne(contributorRepositoryRelationTable.runId, runId)); + } + + public async deleteAllButWithRunId(runId: string) { + return await this.sqliteService.db + .delete(contributorsTable) + .where(ne(contributorsTable.runId, runId)); + } +} diff --git a/api/src/contributor/table.ts b/api/src/contributor/table.ts new file mode 100644 index 000000000..4a6cd366d --- /dev/null +++ b/api/src/contributor/table.ts @@ -0,0 +1,46 @@ +import { ContributorEntity } from "@dzcode.io/models/dist/contributor"; +import { sql } from "drizzle-orm"; +import { integer, primaryKey, sqliteTable, text } from "drizzle-orm/sqlite-core"; +import { repositoriesTable } from "src/repository/table"; + +export const contributorsTable = sqliteTable("contributors", { + id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }), + recordImportedAt: text("record_imported_at") + .notNull() + .default(sql`CURRENT_TIMESTAMP`), + runId: text("run_id").notNull().default("initial-run-id"), + name: text("name").notNull(), + username: text("username").notNull(), + url: text("url").notNull().unique(), + avatarUrl: text("avatar_url").notNull(), +}); + +contributorsTable.$inferSelect satisfies ContributorEntity; + +export type ContributorRow = typeof contributorsTable.$inferInsert; + +export const contributorRepositoryRelationTable = sqliteTable( + "contributor_repository_relation", + { + contributorId: integer("contributor_id") + .notNull() + .references(() => contributorsTable.id), + repositoryId: integer("repository_id") + .notNull() + .references(() => repositoriesTable.id), + recordImportedAt: text("record_imported_at") + .notNull() + .default(sql`CURRENT_TIMESTAMP`), + runId: text("run_id").notNull().default("initial-run-id"), + score: integer("score").notNull(), + }, + (table) => ({ + pk: primaryKey({ + name: "contributor_repository_relation_pk", + columns: [table.contributorId, table.repositoryId], + }), + }), +); + +export type ContributorRepositoryRelationRow = + typeof contributorRepositoryRelationTable.$inferInsert; diff --git a/api/src/contributor/types.ts b/api/src/contributor/types.ts new file mode 100644 index 000000000..f0aede29f --- /dev/null +++ b/api/src/contributor/types.ts @@ -0,0 +1,17 @@ +import { ContributorEntity } from "@dzcode.io/models/dist/contributor"; +import { ProjectEntity } from "@dzcode.io/models/dist/project"; +import { RepositoryEntity } from "@dzcode.io/models/dist/repository"; +import { GeneralResponse } from "src/app/types"; + +export interface GetContributorsResponse extends GeneralResponse { + contributors: Array< + Pick & { + projects: Array< + Pick & { + repositories: Array>; + } + >; + score: number; + } + >; +} diff --git a/api/src/data/service.ts b/api/src/data/service.ts index 7b58806d5..c346edb6c 100644 --- a/api/src/data/service.ts +++ b/api/src/data/service.ts @@ -1,9 +1,8 @@ import { getCollection } from "@dzcode.io/data/dist/collection"; -import { getEntry } from "@dzcode.io/data/dist/entry"; import { join } from "path"; import { Service } from "typedi"; -import { DataArticleEntity, DataDocumentationEntity, DataProjectEntity } from "./types"; +import { DataProjectEntity } from "./types"; @Service() export class DataService { @@ -15,50 +14,5 @@ export class DataService { return projects; }; - public listArticles = async (): Promise[]> => { - const articles = getCollection(this.dataModelsPath, "articles", "list.json"); - - if (articles === 404) throw new Error("Articles list not found"); - - const mappedArticles = articles.map(({ slug, title }) => ({ slug, title })); - - return mappedArticles; - }; - - public getArticle = async (slug: string): Promise => { - const article = getEntry(this.dataModelsPath, `articles/${slug}`); - - if (article === 404) throw new Error("Article not found"); - - return article; - }; - - public listDocumentation = async (): Promise< - Pick[] - > => { - const documentation = getCollection( - this.dataModelsPath, - "documentation", - "list.json", - ); - - if (documentation === 404) throw new Error("Documentation list not found"); - - const mappedDocumentation = documentation.map(({ slug, title }) => ({ slug, title })); - - return mappedDocumentation; - }; - - public getDocumentation = async (slug: string): Promise => { - const documentation = getEntry( - this.dataModelsPath, - `documentation/${slug}`, - ); - - if (documentation === 404) throw new Error("Documentation not found"); - - return documentation; - }; - private dataModelsPath = join(__dirname, "../../../data"); } diff --git a/api/src/data/types.ts b/api/src/data/types.ts index c47b3b993..af426196c 100644 --- a/api/src/data/types.ts +++ b/api/src/data/types.ts @@ -1,20 +1,11 @@ -import { Model } from "@dzcode.io/models/dist/_base"; -import { ArticleInfoEntity } from "@dzcode.io/models/dist/article"; -import { DocumentationInfoEntity } from "@dzcode.io/models/dist/documentation"; -import { ProjectEntity } from "@dzcode.io/models/dist/project"; +import { RepositoryEntity } from "@dzcode.io/models/dist/repository"; -export type DataProjectEntity = Model; - -export type DataArticleEntity = Model & { - authors: string[]; - description: string; - content: string; - image: string; -}; - -export type DataDocumentationEntity = Model & { - authors: string[]; - description: string; - content: string; - image: string; +export type DataProjectEntity = { + name: string; + slug: string; + repositories: Array<{ + provider: RepositoryEntity["provider"]; + owner: string; + name: string; + }>; }; diff --git a/api/src/digest/cron.ts b/api/src/digest/cron.ts new file mode 100644 index 000000000..df1702066 --- /dev/null +++ b/api/src/digest/cron.ts @@ -0,0 +1,180 @@ +import { captureException, cron } from "@sentry/node"; +import { CronJob } from "cron"; +import { ContributionRepository } from "src/contribution/repository"; +import { ContributorRepository } from "src/contributor/repository"; +import { DataService } from "src/data/service"; +import { GithubService } from "src/github/service"; +import { LoggerService } from "src/logger/service"; +import { ProjectRepository } from "src/project/repository"; +import { RepositoryRepository } from "src/repository/repository"; +import { Service } from "typedi"; + +@Service() +export class DigestCron { + private readonly schedule = "15 * * * *"; + private isRunning = false; + + constructor( + private readonly logger: LoggerService, + private readonly dataService: DataService, + private readonly githubService: GithubService, + private readonly projectsRepository: ProjectRepository, + private readonly repositoriesRepository: RepositoryRepository, + private readonly contributionsRepository: ContributionRepository, + private readonly contributorsRepository: ContributorRepository, + ) { + const SentryCronJob = cron.instrumentCron(CronJob, "DigestCron"); + new SentryCronJob( + this.schedule, + async () => { + if (this.isRunning) { + logger.warn({ message: "Digest cron already running" }); + return; + } + + this.isRunning = true; + try { + await this.run(); + } catch (error) { + this.isRunning = false; + console.error(error); + captureException(error, { tags: { type: "CRON" } }); + logger.error({ + message: `Digest cron failed: ${error}`, + meta: { error }, + }); + } + this.isRunning = false; + }, + () => { + this.isRunning = false; + }, + true, + undefined, + undefined, + true, + ); + logger.info({ message: "Digest cron initialized" }); + } + + /** + * Generate a random runId, use it to tag all newly fetched data, persist it to the database, then delete all data that doesn't have that runId. + */ + private async run() { + const runId = Math.random().toString(36).slice(2); + this.logger.info({ message: `Digest cron started, runId: ${runId}` }); + + const projectsFromDataFolder = await this.dataService.listProjects(); + + for (const project of projectsFromDataFolder) { + const [{ id: projectId }] = await this.projectsRepository.upsert({ ...project, runId }); + + let addedRepositoryCount = 0; + try { + const repositoriesFromDataFolder = project.repositories; + for (const repository of repositoriesFromDataFolder) { + try { + const repoInfo = await this.githubService.getRepository({ + owner: repository.owner, + repo: repository.name, + }); + + const [{ id: repositoryId }] = await this.repositoriesRepository.upsert({ + provider: "github", + name: repoInfo.name, + owner: repoInfo.owner.login, + runId, + projectId, + }); + addedRepositoryCount++; + + const issues = await this.githubService.listRepositoryIssues({ + owner: repository.owner, + repo: repository.name, + }); + + for (const issue of issues) { + const githubUser = await this.githubService.getUser({ username: issue.user.login }); + + if (githubUser.type !== "User") continue; + + const [{ id: contributorId }] = await this.contributorsRepository.upsert({ + name: githubUser.name || githubUser.login, + username: githubUser.login, + url: githubUser.html_url, + avatarUrl: githubUser.avatar_url, + runId, + }); + + await this.contributorsRepository.upsertRelationWithRepository({ + contributorId, + repositoryId, + runId, + score: 1, + }); + + const type = issue.pull_request ? "PULL_REQUEST" : "ISSUE"; + await this.contributionsRepository.upsert({ + title: issue.title, + type, + updatedAt: issue.updated_at, + activityCount: issue.comments, + runId, + url: type === "PULL_REQUEST" ? issue.pull_request.html_url : issue.html_url, + repositoryId, + contributorId, + }); + } + + const repoContributors = await this.githubService.listRepositoryContributors({ + owner: repository.owner, + repository: repository.name, + }); + + const repoContributorsFiltered = repoContributors.filter( + (contributor) => contributor.type === "User", + ); + + for (const repoContributor of repoContributorsFiltered) { + const [{ id: contributorId }] = await this.contributorsRepository.upsert({ + name: repoContributor.name || repoContributor.login, + username: repoContributor.login, + url: repoContributor.html_url, + avatarUrl: repoContributor.avatar_url, + runId, + }); + + await this.contributorsRepository.upsertRelationWithRepository({ + contributorId, + repositoryId, + runId, + score: repoContributor.contributions, + }); + } + } catch (error) { + captureException(error, { tags: { type: "CRON" } }); + } + } + } catch (error) { + captureException(error, { tags: { type: "CRON" } }); + } + + if (addedRepositoryCount === 0) { + captureException(new Error("Empty project"), { extra: { project } }); + await this.projectsRepository.deleteById(projectId); + } + } + + try { + await this.contributorsRepository.deleteAllRelationWithRepositoryButWithRunId(runId); + await this.contributionsRepository.deleteAllButWithRunId(runId); + await this.contributorsRepository.deleteAllButWithRunId(runId); + await this.repositoriesRepository.deleteAllButWithRunId(runId); + await this.projectsRepository.deleteAllButWithRunId(runId); + } catch (error) { + captureException(error, { tags: { type: "CRON" } }); + } + + this.logger.info({ message: `Digest cron finished, runId: ${runId}` }); + } +} diff --git a/api/src/documentation/controller.ts b/api/src/documentation/controller.ts deleted file mode 100644 index 06fcf3708..000000000 --- a/api/src/documentation/controller.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { Controller, Get, Param } from "routing-controllers"; -import { OpenAPI, ResponseSchema } from "routing-controllers-openapi"; -import { DataService } from "src/data/service"; -import { GithubService } from "src/github/service"; -import { GithubUser } from "src/github/types"; -import { Service } from "typedi"; - -import { GetADocumentationResponseDto, GetDocumentationResponseDto } from "./types"; - -@Service() -@Controller("/Documentation") -export class DocumentationController { - constructor( - private readonly githubService: GithubService, - private readonly dataService: DataService, - ) {} - - @Get("/") - @OpenAPI({ - summary: "Return list of all documentation", - }) - @ResponseSchema(GetDocumentationResponseDto) - public async getDocumentation(): Promise { - // get documentation from /data folder: - const documentation = await this.dataService.listDocumentation(); - - return { - documentation, - }; - } - - @Get("/:slug(*)") - @OpenAPI({ - summary: "Return info about a single documentation", - }) - @ResponseSchema(GetADocumentationResponseDto) - public async getADocumentation( - @Param("slug") slug: string, - ): Promise { - // get documentation from /data folder: - const { ...documentation } = await this.dataService.getDocumentation(slug); - - // get authors and contributors info from github: - const authors = await Promise.all( - documentation.authors.map(async (author) => { - const githubUser = await this.githubService.getUser({ username: author }); - return this.githubService.githubUserToAccountEntity(githubUser); - }), - ); - - const committersBatches = await Promise.all([ - // current place for data: - this.githubService.listPathCommitters({ - owner: "dzcode-io", - repository: "dzcode.io", - path: `data/models/documentation/${slug}`, - }), - // also check old place for data, to not lose contribution effort: - this.githubService.listPathCommitters({ - owner: "dzcode-io", - repository: "dzcode.io", - path: `data/documentation/${slug}`, - }), - ]); - - // filter and sort contributors: - const uniqUsernames: Record = {}; - const contributors: GetADocumentationResponseDto["documentation"]["contributors"] = [ - ...committersBatches[0], - ...committersBatches[1], - ] - .reduce((pV, cV) => { - if (uniqUsernames[cV.login]) { - uniqUsernames[cV.login]++; - return pV; - } else { - uniqUsernames[cV.login] = 1; - return [...pV, cV]; - } - }, []) - .sort((a, b) => uniqUsernames[b.login] - uniqUsernames[a.login]) - .map((contributor) => this.githubService.githubUserToAccountEntity(contributor)) - .filter(({ id }) => !authors.find((author) => author.id === id)); - - return { - documentation: { - ...documentation, - authors, - contributors, - }, - }; - } -} diff --git a/api/src/documentation/types.ts b/api/src/documentation/types.ts deleted file mode 100644 index 951f323c6..000000000 --- a/api/src/documentation/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Model } from "@dzcode.io/models/dist/_base"; -import { DocumentationEntity, DocumentationInfoEntity } from "@dzcode.io/models/dist/documentation"; -import { Type } from "class-transformer"; -import { ValidateNested } from "class-validator"; -import { GeneralResponseDto } from "src/app/types"; - -export class GetDocumentationResponseDto extends GeneralResponseDto { - @ValidateNested({ each: true }) - @Type(() => DocumentationInfoEntity) - documentation!: Model[]; -} - -export class GetADocumentationResponseDto extends GeneralResponseDto { - @ValidateNested() - documentation!: Model; -} diff --git a/api/src/fetch/service.ts b/api/src/fetch/service.ts index 6d1a2fc7b..1e8ebdaf2 100644 --- a/api/src/fetch/service.ts +++ b/api/src/fetch/service.ts @@ -1,13 +1,17 @@ import { lockFactory } from "@dzcode.io/utils/dist/concurrency"; import { defaults } from "make-fetch-happen"; import { ConfigService } from "src/config/service"; +import { LoggerService } from "src/logger/service"; import { Service } from "typedi"; import { FetchConfig } from "./types"; @Service() export class FetchService { - constructor(private readonly configService: ConfigService) { + constructor( + private readonly configService: ConfigService, + private readonly logger: LoggerService, + ) { const { FETCH_CACHE_PATH } = this.configService.env(); this.makeFetchHappenInstance = defaults({ @@ -15,11 +19,10 @@ export class FetchService { }); } - // @TODO-ZM: using DTO, validate response and DRY the types - public get = async ( + public get = async ( url: string, { params = {}, headers = {} }: FetchConfig = {}, - ) => { + ): Promise> => { const _url = new URL(url); Object.keys(params).forEach((key) => _url.searchParams.append(key, String(params[key]))); @@ -28,8 +31,10 @@ export class FetchService { }; private makeFetchHappenInstance; + // @TODO-ZM: make sure lockFactory works as expected private fetch = lockFactory( async (url: string, { headers }: Omit = {}) => { + this.logger.info({ message: `Fetching ${url}` }); const response = await this.makeFetchHappenInstance(url, { headers }); const jsonResponse = (await response.json()) as T; return jsonResponse; diff --git a/api/src/github/controller.ts b/api/src/github/controller.ts index f0cd095f4..add90ae0f 100644 --- a/api/src/github/controller.ts +++ b/api/src/github/controller.ts @@ -1,9 +1,8 @@ import { Controller, Get } from "routing-controllers"; -import { OpenAPI, ResponseSchema } from "routing-controllers-openapi"; import { GithubService } from "src/github/service"; import { Service } from "typedi"; -import { GetRateLimitResponseDto } from "./types"; +import { GetRateLimitResponse } from "./types"; @Service() @Controller("/Github") @@ -11,11 +10,7 @@ export class GithubController { constructor(private readonly githubService: GithubService) {} @Get("/RateLimit") - @OpenAPI({ - summary: "Return Info about Github Rate limit", - }) - @ResponseSchema(GetRateLimitResponseDto) - public async getRateLimitInfo(): Promise { + public async getRateLimitInfo(): Promise { const { limit, used, ratio } = await this.githubService.getRateLimit(); return { diff --git a/api/src/github/service.spec.ts b/api/src/github/service.spec.ts deleted file mode 100644 index ddc826306..000000000 --- a/api/src/github/service.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { mock } from "jest-mock-extended"; -import { githubUserMock } from "src/_test/mocks"; -import { ConfigService } from "src/config/service"; -import { FetchService } from "src/fetch/service"; - -import { GithubService } from "./service"; -import { GeneralGithubQuery, ListPathCommittersResponse } from "./types"; - -describe("GithubService", () => { - const githubQuery: GeneralGithubQuery = { - owner: "test-owner", - repository: "test-repo", - path: "test/path", - }; - const contributorsMock: ListPathCommittersResponse = [ - { - author: githubUserMock, - committer: githubUserMock, - }, - ]; - - const configService = mock({ - env: () => ({ - FETCH_CACHE_PATH: "", - NODE_ENV: "development", - PORT: 0, - BUNDLE_INFO: { version: "test" }, - }), - }); - const fetchService = mock(); - - it("should throw error when api call fails", async () => { - fetchService.get.mockRejectedValue({ meg: "service down" }); - const githubService = new GithubService(configService, fetchService); - let errorThrown: unknown; - try { - await githubService.listPathCommitters(githubQuery); - } catch (error) { - errorThrown = error; - } - expect(errorThrown).toMatchObject({ meg: "service down" }); - }); - - it("should return list of contributors when api call succeed", async () => { - fetchService.get.mockResolvedValue(contributorsMock); - const githubService = new GithubService(configService, fetchService); - const contributors = await githubService.listPathCommitters(githubQuery); - - expect(contributors).toMatchObject([githubUserMock]); - }); -}); diff --git a/api/src/github/service.ts b/api/src/github/service.ts index 4982c424f..16067c2c9 100644 --- a/api/src/github/service.ts +++ b/api/src/github/service.ts @@ -1,21 +1,17 @@ -import { Model } from "@dzcode.io/models/dist/_base"; -import { AccountEntity } from "@dzcode.io/models/dist/account"; import { ConfigService } from "src/config/service"; import { FetchService } from "src/fetch/service"; import { Service } from "typedi"; import { GeneralGithubQuery, + GetRepositoryInput, + GetRepositoryIssuesResponse, + GetRepositoryResponse, GetUserInput, - GithubIssue, - GitHubListRepositoryIssuesInput, - GitHubListRepositoryLanguagesInput, GitHubListRepositoryMilestonesInput, GithubMilestone, GitHubRateLimitApiResponse, - GithubUser, GitHubUserApiResponse, - ListPathCommittersResponse, ListRepositoryContributorsResponse, } from "./types"; @@ -26,26 +22,6 @@ export class GithubService { private readonly fetchService: FetchService, ) {} - public listPathCommitters = async ({ - owner, - repository, - path, - }: GeneralGithubQuery): Promise => { - const commits = await this.fetchService.get( - `${this.apiURL}/repos/${owner}/${repository}/commits`, - { - headers: this.githubToken ? { Authorization: `Token ${this.githubToken}` } : {}, - params: { path, state: "all", per_page: 100 }, // eslint-disable-line camelcase - }, - ); - const contributors = commits - // @TODO-ZM: dry to a user block-list - // excluding github.com/web-flow user - .filter((item) => item.committer && item.committer.id !== 19864447) - .map(({ committer }) => committer); - return contributors; - }; - public getUser = async ({ username }: GetUserInput): Promise => { const user = await this.fetchService.get( `${this.apiURL}/users/${username}`, @@ -56,28 +32,29 @@ export class GithubService { public listRepositoryIssues = async ({ owner, - repository, - }: GitHubListRepositoryIssuesInput): Promise => { - const issues = await this.fetchService.get( - `${this.apiURL}/repos/${owner}/${repository}/issues`, + repo, + }: GetRepositoryInput): Promise => { + const repoIssues = await this.fetchService.get( + `${this.apiURL}/repos/${owner}/${repo}/issues`, { headers: this.githubToken ? { Authorization: `Token ${this.githubToken}` } : {}, + // @TODO-ZM: add pagination params: { sort: "updated", per_page: 100 }, // eslint-disable-line camelcase }, ); - return issues; + return repoIssues; }; - public listRepositoryLanguages = async ({ + public getRepository = async ({ owner, - repository, - }: GitHubListRepositoryLanguagesInput): Promise => { - const languages = await this.fetchService.get>( - `${this.apiURL}/repos/${owner}/${repository}/languages`, + repo, + }: GetRepositoryInput): Promise => { + const repoInfo = await this.fetchService.get( + `${this.apiURL}/repos/${owner}/${repo}`, { headers: this.githubToken ? { Authorization: `Token ${this.githubToken}` } : {} }, ); - return Object.keys(languages); + return repoInfo; }; public listRepositoryContributors = async ({ @@ -95,12 +72,7 @@ export class GithubService { // @TODO-ZM: validate responses using DTOs, for all fetchService methods if (!Array.isArray(contributors)) return []; - return ( - contributors - // @TODO-ZM: filter out bots - .filter(({ type }) => type === "User") - .sort((a, b) => b.contributions - a.contributions) - ); + return contributors; }; public getRateLimit = async (): Promise<{ limit: number; used: number; ratio: number }> => { @@ -130,17 +102,6 @@ export class GithubService { return milestones; }; - public githubUserToAccountEntity = ( - user: Pick, - ): Model => ({ - id: `github/${user.id}`, - username: user.login, - name: user.name || user.login, - // @TODO-ZM: change this to `/Account/github/${user.id}` once we have a /Accounts page - profileUrl: user.html_url, - avatarUrl: user.avatar_url, - }); - private githubToken = this.configService.env().GITHUB_TOKEN; private apiURL = "https://api.github.com"; } diff --git a/api/src/github/types.ts b/api/src/github/types.ts index 3c9578890..f5404b5fb 100644 --- a/api/src/github/types.ts +++ b/api/src/github/types.ts @@ -1,70 +1,17 @@ -import { IsNumber } from "class-validator"; +import { GeneralResponse } from "src/app/types"; -export interface GithubUser { +interface GithubUser { login: string; - id: number; - node_id: string; - avatar_url: string; - gravatar_id: string; - url: string; - html_url: string; - followers_url: string; - following_url: string; - gists_url: string; - starred_url: string; - subscriptions_url: string; - organizations_url: string; - repos_url: string; - events_url: string; - received_events_url: string; - type: string; - site_admin: boolean; name: string; - company: string; - blog: string; - location: string; - email: string; - hireable: boolean; - bio: string; - twitter_username: string; - public_repos: number; - public_gists: number; - followers: number; - following: number; - created_at: string; - updated_at: string; + html_url: string; + avatar_url: string; + type: "User" | "_other"; } -export interface GithubRepositoryContributor - extends Pick< - GithubUser, - | "login" - | "id" - | "node_id" - | "avatar_url" - | "gravatar_id" - | "url" - | "html_url" - | "followers_url" - | "following_url" - | "gists_url" - | "starred_url" - | "subscriptions_url" - | "organizations_url" - | "repos_url" - | "events_url" - | "received_events_url" - | "type" - | "site_admin" - > { +interface GithubRepositoryContributor extends GithubUser { contributions: number; } -export type ListPathCommittersResponse = Array<{ - author: GithubUser; - committer: GithubUser; -}>; - export type ListRepositoryContributorsResponse = GithubRepositoryContributor[]; export interface GeneralGithubQuery { @@ -79,33 +26,16 @@ export interface GetUserInput { export type GitHubUserApiResponse = GithubUser; -export interface GitHubListRepositoryIssuesInput { +export interface GetRepositoryInput { owner: string; - repository: string; + repo: string; } -export interface GithubIssue { - html_url: string; - number: number; - title: string; - user: GithubUser; - body: string; - labels: Array<{ - name: string; - }>; - state: "closed" | "open"; - assignees: GithubUser[]; - comments: number; - created_at: string; - updated_at: string; - closed_at: string | null; - pull_request?: { - html_url: string; - }; +interface GitHubListRepositoryIssuesInput { + owner: string; + repository: string; } -export type GitHubListRepositoryLanguagesInput = GitHubListRepositoryIssuesInput; - export type GitHubListRepositoryMilestonesInput = GitHubListRepositoryIssuesInput; export interface GithubMilestone { @@ -163,13 +93,26 @@ export interface GitHubRateLimitApiResponse { }; } -export class GetRateLimitResponseDto { - @IsNumber() - limit!: number; +export interface GetRateLimitResponse extends GeneralResponse { + limit: number; + used: number; + ratio: number; +} - @IsNumber() - used!: number; +export interface GetRepositoryResponse { + name: string; + owner: GithubUser; +} - @IsNumber() - ratio!: number; +interface GithubIssue { + title: string; + user: GithubUser; + labels: string[]; + state: "closed" | "open"; + assignees: GithubUser[]; + updated_at: string; + html_url: string; + pull_request: { html_url: string }; + comments: number; } +export type GetRepositoryIssuesResponse = GithubIssue[]; diff --git a/api/src/milestone/controller.ts b/api/src/milestone/controller.ts index 38e710571..c475642c7 100644 --- a/api/src/milestone/controller.ts +++ b/api/src/milestone/controller.ts @@ -1,9 +1,8 @@ import { Controller, Get } from "routing-controllers"; -import { OpenAPI, ResponseSchema } from "routing-controllers-openapi"; import { GithubService } from "src/github/service"; import { Service } from "typedi"; -import { GetMilestonesResponseDto } from "./types"; +import { GetMilestonesResponse } from "./types"; @Service() @Controller("/Milestones") @@ -11,11 +10,7 @@ export class MilestoneController { constructor(private readonly githubService: GithubService) {} @Get("/dzcode") - @OpenAPI({ - summary: "Return a list of milestones for dzcode.io repository", - }) - @ResponseSchema(GetMilestonesResponseDto) - public async getMilestones(): Promise { + public async getMilestones(): Promise { const githubMilestones = await this.githubService.listRepositoryMilestones({ owner: "dzcode-io", repository: "dzcode.io", diff --git a/api/src/milestone/types.ts b/api/src/milestone/types.ts index 5e7103c0c..919ba7699 100644 --- a/api/src/milestone/types.ts +++ b/api/src/milestone/types.ts @@ -1,11 +1,6 @@ -import { Model } from "@dzcode.io/models/dist/_base"; import { MilestoneEntity } from "@dzcode.io/models/dist/milestone"; -import { Type } from "class-transformer"; -import { ValidateNested } from "class-validator"; -import { GeneralResponseDto } from "src/app/types"; +import { GeneralResponse } from "src/app/types"; -export class GetMilestonesResponseDto extends GeneralResponseDto { - @ValidateNested({ each: true }) - @Type(() => MilestoneEntity) - milestones!: Model[]; +export interface GetMilestonesResponse extends GeneralResponse { + milestones: MilestoneEntity[]; } diff --git a/api/src/project/controller.ts b/api/src/project/controller.ts index c5f3715ac..9838d9f10 100644 --- a/api/src/project/controller.ts +++ b/api/src/project/controller.ts @@ -1,29 +1,17 @@ import { Controller, Get } from "routing-controllers"; -import { OpenAPI, ResponseSchema } from "routing-controllers-openapi"; -import { DataService } from "src/data/service"; -import { GithubService } from "src/github/service"; -import { LoggerService } from "src/logger/service"; import { Service } from "typedi"; -import { GetProjectsResponseDto } from "./types"; +import { ProjectRepository } from "./repository"; +import { GetProjectsResponse } from "./types"; @Service() @Controller("/Projects") export class ProjectController { - constructor( - private readonly githubService: GithubService, - private readonly dataService: DataService, - private readonly loggerService: LoggerService, - ) {} + constructor(private readonly projectRepository: ProjectRepository) {} @Get("/") - @OpenAPI({ - summary: "Return all projects listed in dzcode.io website", - }) - @ResponseSchema(GetProjectsResponseDto) - public async getProjects(): Promise { - // get projects from /data folder: - const projects = await this.dataService.listProjects(); + public async getProjects(): Promise { + const projects = await this.projectRepository.findForList(); return { projects, diff --git a/api/src/project/repository.ts b/api/src/project/repository.ts new file mode 100644 index 000000000..f5bc511b6 --- /dev/null +++ b/api/src/project/repository.ts @@ -0,0 +1,66 @@ +import { eq, ne, sql } from "drizzle-orm"; +import { camelCaseObject } from "src/_utils/case"; +import { unStringifyDeep } from "src/_utils/unstringify-deep"; +import { contributorRepositoryRelationTable } from "src/contributor/table"; +import { repositoriesTable } from "src/repository/table"; +import { SQLiteService } from "src/sqlite/service"; +import { Service } from "typedi"; + +import { ProjectRow, projectsTable } from "./table"; + +@Service() +export class ProjectRepository { + constructor(private readonly sqliteService: SQLiteService) {} + + public async findForList() { + const statement = sql` + SELECT + p.id as id, + p.name as name, + sum(rs.repo_contributor_count) as contributor_count, + sum(rs.repo_score) as activity_count, + 100 * sum(rs.repo_contributor_count) + max(rs.repo_score) - sum(rs.repo_score) / sum(rs.repo_contributor_count) as score, + json_group_array(json_object('id', rs.id, 'owner', rs.owner, 'name', rs.name)) as repositories + FROM + (SELECT + *, + sum(crr.score) as repo_score, + count(*) as repo_contributor_count + FROM + ${contributorRepositoryRelationTable} crr + JOIN + ${repositoriesTable} r ON crr.repository_id = r.id + GROUP BY + r.id) as rs + JOIN + ${projectsTable} p ON rs.project_id = p.id + GROUP BY + p.id + ORDER BY + score DESC + `; + const raw = this.sqliteService.db.all(statement); + const unStringifiedRaw = unStringifyDeep(raw); + const camelCased = camelCaseObject(unStringifiedRaw); + return camelCased; + } + + public async upsert(project: ProjectRow) { + return await this.sqliteService.db + .insert(projectsTable) + .values(project) + .onConflictDoUpdate({ + target: projectsTable.slug, + set: project, + }) + .returning({ id: projectsTable.id }); + } + + public async deleteById(id: number) { + return await this.sqliteService.db.delete(projectsTable).where(eq(projectsTable.id, id)); + } + + public async deleteAllButWithRunId(runId: string) { + return await this.sqliteService.db.delete(projectsTable).where(ne(projectsTable.runId, runId)); + } +} diff --git a/api/src/project/table.ts b/api/src/project/table.ts new file mode 100644 index 000000000..6301943a3 --- /dev/null +++ b/api/src/project/table.ts @@ -0,0 +1,17 @@ +import { ProjectEntity } from "@dzcode.io/models/dist/project"; +import { sql } from "drizzle-orm"; +import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; + +export const projectsTable = sqliteTable("projects", { + id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }), + recordImportedAt: text("record_imported_at") + .notNull() + .default(sql`CURRENT_TIMESTAMP`), + name: text("name").notNull(), + slug: text("slug").notNull().unique(), + runId: text("run_id").notNull().default("initial-run-id"), +}); + +projectsTable.$inferSelect satisfies ProjectEntity; + +export type ProjectRow = typeof projectsTable.$inferInsert; diff --git a/api/src/project/types.ts b/api/src/project/types.ts index 35f66202b..c099115c3 100644 --- a/api/src/project/types.ts +++ b/api/src/project/types.ts @@ -1,12 +1,14 @@ -import { Model } from "@dzcode.io/models/dist/_base"; import { ProjectEntity } from "@dzcode.io/models/dist/project"; import { RepositoryEntity } from "@dzcode.io/models/dist/repository"; -import { Type } from "class-transformer"; -import { ValidateNested } from "class-validator"; -import { GeneralResponseDto } from "src/app/types"; +import { GeneralResponse } from "src/app/types"; -export class GetProjectsResponseDto extends GeneralResponseDto { - @ValidateNested({ each: true }) - @Type(() => ProjectEntity) - projects!: Array & { repositories: Model[] }>; +export interface GetProjectsResponse extends GeneralResponse { + projects: Array< + Pick & { + repositories: Array>; + contributor_count: number; + activity_count: number; + score: number; + } + >; } diff --git a/api/src/repository/repository.ts b/api/src/repository/repository.ts new file mode 100644 index 000000000..b98625859 --- /dev/null +++ b/api/src/repository/repository.ts @@ -0,0 +1,27 @@ +import { ne } from "drizzle-orm"; +import { SQLiteService } from "src/sqlite/service"; +import { Service } from "typedi"; + +import { repositoriesTable, RepositoryRow } from "./table"; + +@Service() +export class RepositoryRepository { + constructor(private readonly sqliteService: SQLiteService) {} + + public async upsert(repository: RepositoryRow) { + return await this.sqliteService.db + .insert(repositoriesTable) + .values(repository) + .onConflictDoUpdate({ + target: [repositoriesTable.provider, repositoriesTable.owner, repositoriesTable.name], + set: repository, + }) + .returning({ id: repositoriesTable.id }); + } + + public async deleteAllButWithRunId(runId: string) { + return await this.sqliteService.db + .delete(repositoriesTable) + .where(ne(repositoriesTable.runId, runId)); + } +} diff --git a/api/src/repository/table.ts b/api/src/repository/table.ts new file mode 100644 index 000000000..c2a3d620c --- /dev/null +++ b/api/src/repository/table.ts @@ -0,0 +1,30 @@ +import { RepositoryEntity } from "@dzcode.io/models/dist/repository"; +import { sql } from "drizzle-orm"; +import { integer, sqliteTable, text, unique } from "drizzle-orm/sqlite-core"; +import { projectsTable } from "src/project/table"; + +export const repositoriesTable = sqliteTable( + "repositories", + { + id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }), + recordImportedAt: text("record_imported_at") + .notNull() + .default(sql`CURRENT_TIMESTAMP`), + provider: text("provider").notNull().$type(), + owner: text("owner").notNull(), + name: text("name").notNull(), + runId: text("run_id").notNull().default("initial-run-id"), + projectId: integer("project_id") + .notNull() + .references(() => projectsTable.id), + }, + (table) => { + return { + uniquePath: unique().on(table.provider, table.owner, table.name), + }; + }, +); + +repositoriesTable.$inferSelect satisfies RepositoryEntity; + +export type RepositoryRow = typeof repositoriesTable.$inferInsert; diff --git a/api/src/sqlite/service.ts b/api/src/sqlite/service.ts new file mode 100644 index 000000000..c1865d03f --- /dev/null +++ b/api/src/sqlite/service.ts @@ -0,0 +1,26 @@ +import Database from "better-sqlite3"; +import { drizzle } from "drizzle-orm/better-sqlite3"; +import { migrate } from "drizzle-orm/better-sqlite3/migrator"; +import { mkdirSync } from "fs"; +import { join } from "path"; +import { ConfigService } from "src/config/service"; +import { LoggerService } from "src/logger/service"; +import { Service } from "typedi"; + +@Service() +export class SQLiteService { + public db; + + constructor( + private readonly configService: ConfigService, + private readonly loggerService: LoggerService, + ) { + this.loggerService.info({ message: "Initializing SQLite database" }); + const { SQLITE_DB_PATH } = this.configService.env(); + mkdirSync(SQLITE_DB_PATH, { recursive: true }); + const sqlite = new Database(join(SQLITE_DB_PATH, "main.sqlite")); + this.db = drizzle(sqlite); + migrate(this.db, { migrationsFolder: join(__dirname, "../../db/migrations") }); + this.loggerService.info({ message: "Database migration complete" }); + } +} diff --git a/api/src/team/controller.ts b/api/src/team/controller.ts deleted file mode 100644 index ae75d171d..000000000 --- a/api/src/team/controller.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Controller, Get } from "routing-controllers"; -import { OpenAPI, ResponseSchema } from "routing-controllers-openapi"; -import { Service } from "typedi"; - -import { TeamRepository } from "./repository"; -import { GetTeamResponseDto } from "./types"; - -@Service() -@Controller("/Team") -export class TeamController { - constructor(private readonly teamRepository: TeamRepository) {} - - @Get("/") - @OpenAPI({ summary: "Return a list of contributors for all listed projects in dzcode.io" }) - @ResponseSchema(GetTeamResponseDto) - public async getContributions(): Promise { - const contributors = await this.teamRepository.find(); - - return { - contributors, - }; - } -} diff --git a/api/src/team/repository.ts b/api/src/team/repository.ts deleted file mode 100644 index 0a78f5531..000000000 --- a/api/src/team/repository.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Model } from "@dzcode.io/models/dist/_base"; -import { AccountEntity } from "@dzcode.io/models/dist/account"; -import { RepositoryEntity } from "@dzcode.io/models/dist/repository"; -import { DataService } from "src/data/service"; -import { GithubService } from "src/github/service"; -import { GithubRepositoryContributor } from "src/github/types"; -import { LoggerService } from "src/logger/service"; -import { Service } from "typedi"; - -@Service() -export class TeamRepository { - constructor( - private readonly githubService: GithubService, - private readonly dataService: DataService, - private readonly loggerService: LoggerService, - ) {} - - public async find(): Promise[]> { - const projects = await this.dataService.listProjects(); - - // flatten repositories into one array - const repositories = projects.reduce( - (repositories, project) => [...repositories, ...project.repositories], - [], - ); - - // we first store them in a Record (object with id as keys) so we can uniquify and rank them - const contributorsUsernameRankedRecord: Record< - string, - Pick< - GithubRepositoryContributor & Model, - "login" | "contributions" | "repositories" - > - > = {}; - - // get contributors from all the repos we have - await Promise.all( - repositories.map(async ({ provider, owner, repository }) => { - if (provider === "github") { - try { - const contributors = await this.githubService.listRepositoryContributors({ - owner, - repository, - }); - contributors.forEach((contributor) => { - const uuid = this.githubService.githubUserToAccountEntity({ - ...contributor, - name: "", - }).id; - const { login, contributions } = contributor; - // contributor first time appearing in the list - if (!contributorsUsernameRankedRecord[uuid]) { - contributorsUsernameRankedRecord[uuid] = { - login, - contributions, - repositories: [{ provider, owner, repository }], - }; - } else { - // contributor already exists in the list, and is a contributor to another repository - // - so we count additional contributions: - contributorsUsernameRankedRecord[uuid].contributions += contributor.contributions; - // - and add the other repository to the list of repositories he contributed to - contributorsUsernameRankedRecord[uuid].repositories.push({ - provider, - owner, - repository, - }); - } - }); - } catch (error) { - this.loggerService.warn({ - message: `Failed to fetch contributors for ${owner}/${repository}: ${error}`, - meta: { owner, repository }, - }); - } - } else throw new Error(`Provider ${provider} is not supported yet`); - }), - ); - - const contributors: Model[] = await Promise.all( - Object.keys(contributorsUsernameRankedRecord) - // sort contributors by their commits count - .sort( - (a, b) => - contributorsUsernameRankedRecord[b].contributions - - contributorsUsernameRankedRecord[a].contributions, - ) - // get the github user data for each contributor - .map(async (uuid) => { - const { repositories, login } = contributorsUsernameRankedRecord[uuid]; - const githubUser = await this.githubService.getUser({ username: login }); - const account = this.githubService.githubUserToAccountEntity(githubUser); - - return { ...account, repositories }; - }), - ); - - return contributors; - } -} diff --git a/api/src/team/types.ts b/api/src/team/types.ts deleted file mode 100644 index 96cf59212..000000000 --- a/api/src/team/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Model } from "@dzcode.io/models/dist/_base"; -import { AccountEntity } from "@dzcode.io/models/dist/account"; -import { Type } from "class-transformer"; -import { ValidateNested } from "class-validator"; -import { GeneralResponseDto } from "src/app/types"; - -export class GetTeamResponseDto extends GeneralResponseDto { - @ValidateNested({ each: true }) - @Type(() => AccountEntity) - contributors!: Model[]; -} diff --git a/data/models/articles/A_Python_Website_No_Framework_Needed_PART_2/content.md b/data/models/articles/A_Python_Website_No_Framework_Needed_PART_2/content.md index ebe305765..053c99710 100644 --- a/data/models/articles/A_Python_Website_No_Framework_Needed_PART_2/content.md +++ b/data/models/articles/A_Python_Website_No_Framework_Needed_PART_2/content.md @@ -43,7 +43,7 @@ now let's move to the HTML template add this code to it ```html - + diff --git a/data/models/projects/AiPalettes/info.json b/data/models/projects/AiPalettes/info.json index fe6968344..c9fec86d6 100644 --- a/data/models/projects/AiPalettes/info.json +++ b/data/models/projects/AiPalettes/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "bondbenz", - "repository": "aipalettes" + "name": "aipalettes" } ] } diff --git a/data/models/projects/Algeria_Covid19_Tracker/info.json b/data/models/projects/Algeria_Covid19_Tracker/info.json index c3c2a0d81..751d926ec 100644 --- a/data/models/projects/Algeria_Covid19_Tracker/info.json +++ b/data/models/projects/Algeria_Covid19_Tracker/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "DGLcsGaming", - "repository": "dz-covid19.com" + "name": "dz-covid19.com" } ] } diff --git a/data/models/projects/Algeria_Logos/info.json b/data/models/projects/Algeria_Logos/info.json index e7086a577..754f75be6 100644 --- a/data/models/projects/Algeria_Logos/info.json +++ b/data/models/projects/Algeria_Logos/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "aimen08", - "repository": "algerialogos" + "name": "algerialogos" } ] } diff --git a/data/models/projects/Algeria_Startup_Jobs/info.json b/data/models/projects/Algeria_Startup_Jobs/info.json index 61fe3020c..ceaf14751 100644 --- a/data/models/projects/Algeria_Startup_Jobs/info.json +++ b/data/models/projects/Algeria_Startup_Jobs/info.json @@ -4,12 +4,12 @@ { "provider": "github", "owner": "algeriastartupjobs", - "repository": "algeriastartupjobs.com" + "name": "algeriastartupjobs.com" }, { "provider": "github", "owner": "algeriastartupjobs", - "repository": "diagrams" + "name": "diagrams" } ] } diff --git a/data/models/projects/Algeria_boukal/info.json b/data/models/projects/Algeria_boukal/info.json index a74f7b677..79b9d4bfa 100644 --- a/data/models/projects/Algeria_boukal/info.json +++ b/data/models/projects/Algeria_boukal/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "jusinamine", - "repository": "algeria-boukal" + "name": "algeria-boukal" } ] } diff --git a/data/models/projects/Algerian_Administrative_Division/info.json b/data/models/projects/Algerian_Administrative_Division/info.json index 515c72a99..bd2926018 100644 --- a/data/models/projects/Algerian_Administrative_Division/info.json +++ b/data/models/projects/Algerian_Administrative_Division/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "mohsenuss91", - "repository": "AlgerianAdministrativeDivision" + "name": "AlgerianAdministrativeDivision" } ] } diff --git a/data/models/projects/AlgeriansCoinsObjectDetection/info.json b/data/models/projects/AlgeriansCoinsObjectDetection/info.json index 91149b53a..47581aace 100644 --- a/data/models/projects/AlgeriansCoinsObjectDetection/info.json +++ b/data/models/projects/AlgeriansCoinsObjectDetection/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "lablack576", - "repository": "algerians_coins_object_detection" + "name": "algerians_coins_object_detection" } ] } diff --git a/data/models/projects/Archiy_Package/info.json b/data/models/projects/Archiy_Package/info.json index 8ce0e7cfe..9e28dabdb 100644 --- a/data/models/projects/Archiy_Package/info.json +++ b/data/models/projects/Archiy_Package/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "yassine-youcefi", - "repository": "Archy" + "name": "Archy" } ] } diff --git a/data/models/projects/Check_Hadith/info.json b/data/models/projects/Check_Hadith/info.json index b8bbf8921..d57bae68a 100644 --- a/data/models/projects/Check_Hadith/info.json +++ b/data/models/projects/Check_Hadith/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "adelpro", - "repository": "check-hadith" + "name": "check-hadith" } ] } diff --git a/data/models/projects/Dzair_Data_Usage/info.json b/data/models/projects/Dzair_Data_Usage/info.json index d7fea036a..1a7ed9dc2 100644 --- a/data/models/projects/Dzair_Data_Usage/info.json +++ b/data/models/projects/Dzair_Data_Usage/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "dfourcfive", - "repository": "dzair_data_usage" + "name": "dzair_data_usage" } ] } diff --git a/data/models/projects/Face_Mask_Detect/info.json b/data/models/projects/Face_Mask_Detect/info.json index 83908c753..0da4cb6a4 100644 --- a/data/models/projects/Face_Mask_Detect/info.json +++ b/data/models/projects/Face_Mask_Detect/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "Ghali-Benbernou", - "repository": "mask-detect" + "name": "mask-detect" } ] } diff --git a/data/models/projects/Flutter_Reaction_Button/info.json b/data/models/projects/Flutter_Reaction_Button/info.json index 7aa8adb8b..ce6fdbbab 100644 --- a/data/models/projects/Flutter_Reaction_Button/info.json +++ b/data/models/projects/Flutter_Reaction_Button/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "geekabdelouahed", - "repository": "flutter-reaction-button" + "name": "flutter-reaction-button" } ] } diff --git a/data/models/projects/Godaddy_Reseller/info.json b/data/models/projects/Godaddy_Reseller/info.json index cc4cb0e5f..ad67d6d88 100644 --- a/data/models/projects/Godaddy_Reseller/info.json +++ b/data/models/projects/Godaddy_Reseller/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "bychis", - "repository": "godaddy-reseller" + "name": "godaddy-reseller" } ] } diff --git a/data/models/projects/Godaddy_Reseller_Api_Client/info.json b/data/models/projects/Godaddy_Reseller_Api_Client/info.json index 9fdffe165..d8fc69432 100644 --- a/data/models/projects/Godaddy_Reseller_Api_Client/info.json +++ b/data/models/projects/Godaddy_Reseller_Api_Client/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "Omar-Belghaouti", - "repository": "godaddy-reseller-api-client" + "name": "godaddy-reseller-api-client" } ] } diff --git a/data/models/projects/Gold_Prices_Web/info.json b/data/models/projects/Gold_Prices_Web/info.json index 142aafb55..77f168971 100644 --- a/data/models/projects/Gold_Prices_Web/info.json +++ b/data/models/projects/Gold_Prices_Web/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "jusinamine", - "repository": "gold-prices-web" + "name": "gold-prices-web" } ] } diff --git a/data/models/projects/Kuliya/info.json b/data/models/projects/Kuliya/info.json index 917cc0c9b..ea7b3ff2f 100644 --- a/data/models/projects/Kuliya/info.json +++ b/data/models/projects/Kuliya/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "dzcode-io", - "repository": "kuliya" + "name": "kuliya" } ] } diff --git a/data/models/projects/Laravel_Algerian_Education_System/info.json b/data/models/projects/Laravel_Algerian_Education_System/info.json index 3847758e7..d2f972f04 100644 --- a/data/models/projects/Laravel_Algerian_Education_System/info.json +++ b/data/models/projects/Laravel_Algerian_Education_System/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "elaborate-code", - "repository": "laravel-algerian-education-system" + "name": "laravel-algerian-education-system" } ] } diff --git a/data/models/projects/Laravel_Algerian_Provinces/info.json b/data/models/projects/Laravel_Algerian_Provinces/info.json index aa6fb2a83..69a6e45d0 100644 --- a/data/models/projects/Laravel_Algerian_Provinces/info.json +++ b/data/models/projects/Laravel_Algerian_Provinces/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "elaborate-code", - "repository": "laravel-algerian-provinces" + "name": "laravel-algerian-provinces" } ] } diff --git a/data/models/projects/Leblad/info.json b/data/models/projects/Leblad/info.json index b50654c0e..144f20026 100644 --- a/data/models/projects/Leblad/info.json +++ b/data/models/projects/Leblad/info.json @@ -4,22 +4,22 @@ { "provider": "github", "owner": "dzcode-io", - "repository": "leblad" + "name": "leblad" }, { "provider": "github", "owner": "abderrahmaneMustapha", - "repository": "leblad-py" + "name": "leblad-py" }, { "provider": "github", "owner": "omdxp", - "repository": "leblad" + "name": "leblad" }, { "provider": "github", "owner": "omdxp", - "repository": "leblad-rs" + "name": "leblad-rs" } ] } diff --git a/data/models/projects/List_to_Tree_aka_l2t/info.json b/data/models/projects/List_to_Tree_aka_l2t/info.json index 02d7b88a4..dc1148a69 100644 --- a/data/models/projects/List_to_Tree_aka_l2t/info.json +++ b/data/models/projects/List_to_Tree_aka_l2t/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "ZibanPirate", - "repository": "l2t" + "name": "l2t" } ] } diff --git a/data/models/projects/MERN_Auth_Roles_Boilerplate/info.json b/data/models/projects/MERN_Auth_Roles_Boilerplate/info.json index 10a0e3c5f..e134b6986 100644 --- a/data/models/projects/MERN_Auth_Roles_Boilerplate/info.json +++ b/data/models/projects/MERN_Auth_Roles_Boilerplate/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "adelpro", - "repository": "MERN-auth-roles-boilerplate" + "name": "MERN-auth-roles-boilerplate" } ] } diff --git a/data/models/projects/Madinati_Meteo/info.json b/data/models/projects/Madinati_Meteo/info.json index c67d4d910..2ad669e1a 100644 --- a/data/models/projects/Madinati_Meteo/info.json +++ b/data/models/projects/Madinati_Meteo/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "khalilpreview", - "repository": "madinateo" + "name": "madinateo" } ] } diff --git a/data/models/projects/Melyon_Theme/info.json b/data/models/projects/Melyon_Theme/info.json index 00362d52f..477537edd 100644 --- a/data/models/projects/Melyon_Theme/info.json +++ b/data/models/projects/Melyon_Theme/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "CA1R7", - "repository": "melyon" + "name": "melyon" } ] } diff --git a/data/models/projects/Mishkal/info.json b/data/models/projects/Mishkal/info.json index f0f1fcbaf..9bfa2b7a8 100644 --- a/data/models/projects/Mishkal/info.json +++ b/data/models/projects/Mishkal/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "linuxscout", - "repository": "mishkal" + "name": "mishkal" } ] } diff --git a/data/models/projects/Moadaly/info.json b/data/models/projects/Moadaly/info.json index 6ea846d36..17e07ac00 100644 --- a/data/models/projects/Moadaly/info.json +++ b/data/models/projects/Moadaly/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "madjsmail", - "repository": "moadaly" + "name": "moadaly" } ] } diff --git a/data/models/projects/Mylinks_Space/info.json b/data/models/projects/Mylinks_Space/info.json index 8570d1bbe..37214857d 100644 --- a/data/models/projects/Mylinks_Space/info.json +++ b/data/models/projects/Mylinks_Space/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "bacloud23", - "repository": "mylinks" + "name": "mylinks" } ] } diff --git a/data/models/projects/Open-listings/info.json b/data/models/projects/Open-listings/info.json index 553e7ca05..e2837dfb8 100644 --- a/data/models/projects/Open-listings/info.json +++ b/data/models/projects/Open-listings/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "bacloud23", - "repository": "open-listings" + "name": "open-listings" } ] } diff --git a/data/models/projects/Openadhan/info.json b/data/models/projects/Openadhan/info.json index 85ae272f0..20eeea55f 100644 --- a/data/models/projects/Openadhan/info.json +++ b/data/models/projects/Openadhan/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "adelpro", - "repository": "Openadhan" + "name": "Openadhan" } ] } diff --git a/data/models/projects/PHP_JSON_Tongue/info.json b/data/models/projects/PHP_JSON_Tongue/info.json index 44165625b..02cfdde22 100644 --- a/data/models/projects/PHP_JSON_Tongue/info.json +++ b/data/models/projects/PHP_JSON_Tongue/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "elaborate-code", - "repository": "php-json-tongue" + "name": "php-json-tongue" } ] } diff --git a/data/models/projects/Python_Complex/info.json b/data/models/projects/Python_Complex/info.json index e4eefda9b..0dc742fe4 100644 --- a/data/models/projects/Python_Complex/info.json +++ b/data/models/projects/Python_Complex/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "Omar-Belghaouti", - "repository": "PythonComplex" + "name": "PythonComplex" } ] } diff --git a/data/models/projects/QuranIPFS/info.json b/data/models/projects/QuranIPFS/info.json index ebb5b14ca..5337dc30d 100644 --- a/data/models/projects/QuranIPFS/info.json +++ b/data/models/projects/QuranIPFS/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "adelpro", - "repository": "Quranipfs" + "name": "Quranipfs" } ] } diff --git a/data/models/projects/React_Glassmorphism_Components/info.json b/data/models/projects/React_Glassmorphism_Components/info.json index 91e9699f9..fb2414981 100644 --- a/data/models/projects/React_Glassmorphism_Components/info.json +++ b/data/models/projects/React_Glassmorphism_Components/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "jusinamine", - "repository": "react-glassmorphism-components" + "name": "react-glassmorphism-components" } ] } diff --git a/data/models/projects/React_Help_Create/info.json b/data/models/projects/React_Help_Create/info.json index d53cb41ca..c5495bd94 100644 --- a/data/models/projects/React_Help_Create/info.json +++ b/data/models/projects/React_Help_Create/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "Omar-Belghaouti", - "repository": "react-help-create" + "name": "react-help-create" } ] } diff --git a/data/models/projects/React_Native_Currency_Converter/info.json b/data/models/projects/React_Native_Currency_Converter/info.json index e1c913cbf..01575027a 100644 --- a/data/models/projects/React_Native_Currency_Converter/info.json +++ b/data/models/projects/React_Native_Currency_Converter/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "ilies-space", - "repository": "currency_converter_rn" + "name": "currency_converter_rn" } ] } diff --git a/data/models/projects/React_Native_Help_Create/info.json b/data/models/projects/React_Native_Help_Create/info.json index 11ff0a899..22a1bfc10 100644 --- a/data/models/projects/React_Native_Help_Create/info.json +++ b/data/models/projects/React_Native_Help_Create/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "Omar-Belghaouti", - "repository": "react-native-help-create" + "name": "react-native-help-create" } ] } diff --git a/data/models/projects/React_Project_Builder/info.json b/data/models/projects/React_Project_Builder/info.json index 48a97ee61..6c5556059 100644 --- a/data/models/projects/React_Project_Builder/info.json +++ b/data/models/projects/React_Project_Builder/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "AmineVolk", - "repository": "react-project-builder" + "name": "react-project-builder" } ] } diff --git a/data/models/projects/STRM_Test/info.json b/data/models/projects/STRM_Test/info.json index 4eeac6853..f97a6002d 100644 --- a/data/models/projects/STRM_Test/info.json +++ b/data/models/projects/STRM_Test/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "linuxscout", - "repository": "strm-tests" + "name": "strm-tests" } ] } diff --git a/data/models/projects/System_Monitor/info.json b/data/models/projects/System_Monitor/info.json index d56bcb93f..69a0df761 100644 --- a/data/models/projects/System_Monitor/info.json +++ b/data/models/projects/System_Monitor/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "ZibanPirate", - "repository": "sysmon" + "name": "sysmon" } ] } diff --git a/data/models/projects/Violence_Detection/info.json b/data/models/projects/Violence_Detection/info.json index 245c52be0..366227088 100644 --- a/data/models/projects/Violence_Detection/info.json +++ b/data/models/projects/Violence_Detection/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "jusinamine", - "repository": "violence_detection" + "name": "violence_detection" } ] } diff --git a/data/models/projects/Voice_Translator_React_Native/info.json b/data/models/projects/Voice_Translator_React_Native/info.json index 27ed7aea2..2a0e63499 100644 --- a/data/models/projects/Voice_Translator_React_Native/info.json +++ b/data/models/projects/Voice_Translator_React_Native/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "ilies-space", - "repository": "voiceTranslator-reactNative" + "name": "voiceTranslator-reactNative" } ] } diff --git a/data/models/projects/Weather_Forecast/info.json b/data/models/projects/Weather_Forecast/info.json index 143397d4e..92b670bda 100644 --- a/data/models/projects/Weather_Forecast/info.json +++ b/data/models/projects/Weather_Forecast/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "jidmaa", - "repository": "weather-forecast" + "name": "weather-forecast" } ] } diff --git a/data/models/projects/dzcode.io_website/info.json b/data/models/projects/dzcode.io_website/info.json index 6b8bcfe23..d2b9bf8cf 100644 --- a/data/models/projects/dzcode.io_website/info.json +++ b/data/models/projects/dzcode.io_website/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "dzcode-io", - "repository": "dzcode.io" + "name": "dzcode.io" } ] } diff --git a/data/models/projects/who_want_to_millionaire/info.json b/data/models/projects/who_want_to_millionaire/info.json index da8f90a5f..7ef5ca13d 100644 --- a/data/models/projects/who_want_to_millionaire/info.json +++ b/data/models/projects/who_want_to_millionaire/info.json @@ -4,7 +4,7 @@ { "provider": "github", "owner": "brahaim360", - "repository": "who-want-to-be-millionere" + "name": "who-want-to-be-millionere" } ] } diff --git a/data/package.json b/data/package.json index 261661e2d..628ce361a 100644 --- a/data/package.json +++ b/data/package.json @@ -49,7 +49,7 @@ "lint:eslint": "eslint --config ../packages/tooling/.eslintrc.json --ignore-path ../packages/tooling/.eslintignore --report-unused-disable-directives", "lint:fix": "yarn build && yarn lint:fix:alone", "lint:fix:alone": "yarn lint:eslint --fix . && yarn lint:prettier --write .", - "lint:prettier": "prettier --config ../packages/tooling/.prettierrc --ignore-path ../packages/tooling/.prettierignore --loglevel warn", + "lint:prettier": "prettier --config ../packages/tooling/.prettierrc --ignore-path ../packages/tooling/.prettierignore --log-level warn", "lint:ts-prune": "ts-node ../packages/tooling/setup-ts-prune.ts && ts-prune --error", "lint:tsc": "tsc --noEmit", "test": "jest src", diff --git a/mobile/package.json b/mobile/package.json index 40368db0a..a2ca443b1 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -89,7 +89,7 @@ "lint:eslint": "eslint --config ../packages/tooling/.eslintrc.json --ignore-path ../packages/tooling/.eslintignore --report-unused-disable-directives", "lint:fix": "yarn build && yarn lint:fix:alone", "lint:fix:alone": "yarn lint:eslint --fix . && yarn lint:prettier --write .", - "lint:prettier": "prettier --config ../packages/tooling/.prettierrc --ignore-path ../packages/tooling/.prettierignore --loglevel warn", + "lint:prettier": "prettier --config ../packages/tooling/.prettierrc --ignore-path ../packages/tooling/.prettierignore --log-level warn", "lint:tsc": "tsc --noEmit", "start:dev": "echo \" \n\\033[0;32mPlease run in a separate terminal session the following command:\n \n\\033[0;32myarn --cwd=mobile start:expo\n \n \"", "start:expo": "rimraf .bundle-info.json && expo start --port 1010", diff --git a/package.json b/package.json index 981b45689..00b159b01 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "@dzcode.io/root", + "dependencies": {}, "devDependencies": { "@prettier/plugin-pug": "^1.17.3", "@sentry/cli": "^1.71.0", @@ -23,7 +24,7 @@ "npm-run-all": "^4.1.5", "patch-package": "^6.5.1", "postinstall-postinstall": "^2.1.0", - "prettier": "^2.4.1", + "prettier": "^3.3.3", "rimraf": "^3.0.2", "semver": "^7.3.5", "syncpack": "^5.8.15", @@ -39,7 +40,7 @@ "syncpack format" ], "./*.*": [ - "prettier --config ./packages/tooling/.prettierrc --ignore-path ./packages/tooling/.prettierignore --loglevel warn --write" + "prettier --config ./packages/tooling/.prettierrc --ignore-path ./packages/tooling/.prettierignore --log-level warn --write" ] }, "private": true, diff --git a/packages/models/package.json b/packages/models/package.json index 45f34b3c9..4cc8a384e 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -8,10 +8,7 @@ "url": "https://zakiii.com/" }, "dependencies": { - "@dzcode.io/utils": "*", - "class-transformer": "^0.5.1", - "class-validator": "^0.13.2", - "reflect-metadata": "^0.1.13" + "@dzcode.io/utils": "*" }, "devDependencies": { "@dzcode.io/tooling": "*" @@ -37,9 +34,9 @@ "lint:eslint": "eslint --config ../tooling/.eslintrc.json --ignore-path ../tooling/.eslintignore --report-unused-disable-directives", "lint:fix": "yarn build && yarn lint:fix:alone", "lint:fix:alone": "yarn lint:eslint --fix . && yarn lint:prettier --write .", - "lint:prettier": "prettier --config ../tooling/.prettierrc --ignore-path ../tooling/.prettierignore --loglevel warn", + "lint:prettier": "prettier --config ../tooling/.prettierrc --ignore-path ../tooling/.prettierignore --log-level warn", "test": "yarn build && yarn test:alone", - "test:alone": "jest --config ../tooling/jest.config.ts --rootDir .", + "test:alone": "jest --passWithNoTests --config ../tooling/jest.config.ts --rootDir .", "test:watch": "npm-run-all build --parallel build:watch \"test:alone --watch {@}\" --" } } diff --git a/packages/models/src/_base/index.ts b/packages/models/src/_base/index.ts index d1c6f4492..e3c851e25 100644 --- a/packages/models/src/_base/index.ts +++ b/packages/models/src/_base/index.ts @@ -1,14 +1,4 @@ -import "reflect-metadata"; - -import { KeysMatching } from "@dzcode.io/utils/dist/ts"; - -export class BaseEntity { - private _entity?: undefined; +export interface BaseEntity { + id: number; + runId: string; } - -export type Model = never> = Pick< - ENTITY, - Exclude> -> & - Pick, RELATIONS> & - BaseEntity; diff --git a/packages/models/src/_test/index.ts b/packages/models/src/_test/index.ts deleted file mode 100644 index 2bcfac264..000000000 --- a/packages/models/src/_test/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { OptionalPropertiesOf, RequiredPropertiesOf } from "@dzcode.io/utils/dist/ts"; -import { ClassConstructor, plainToClass } from "class-transformer"; -import { validateSync } from "class-validator"; -import { BaseEntity } from "src/_base"; - -export type Cases = [ - [string, RequiredPropertiesOf, false], - [string, Required, false], - [string, Record, boolean], -]; - -export const runDTOTestCases = ( - entity: ClassConstructor, - requiredFields: RequiredPropertiesOf, - optionalFields: OptionalPropertiesOf, -): void => { - const hasNoRequiredFields = Object.keys(requiredFields).length === 0; - const cases: Cases = [ - ["should match snapshot when providing required fields only", requiredFields, false], - [ - "should match snapshot when providing all fields", - { ...requiredFields, ...optionalFields } as Required, - false, - ], - [ - hasNoRequiredFields - ? "should match snapshot when providing an empty object" - : "should show an error that matches snapshot when passing empty object", - {}, - !hasNoRequiredFields, - ], - ]; - - it.each(cases)("%s", (name, input, expectErrors) => { - const output = plainToClass(entity, input); - const errors = validateSync(output); - - expect(output).toMatchSnapshot("output"); - expect(errors).toMatchSnapshot("errors"); - if (expectErrors) { - expect(errors.length).not.toBeLessThanOrEqual(0); - } else { - expect(errors.length).toBe(0); - } - }); -}; diff --git a/packages/models/src/account/__snapshots__/index.spec.ts.snap b/packages/models/src/account/__snapshots__/index.spec.ts.snap deleted file mode 100644 index 9fe2b605a..000000000 --- a/packages/models/src/account/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,78 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -AccountEntity { - "avatarUrl": "https://avatars.githubusercontent.com/u/20110076?v=4", - "id": "github/20110076", - "name": "Zakaria Mansouri", - "profileUrl": "/Account/github/20110076", - "repositories": [], - "username": "ZibanPirate", -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -AccountEntity { - "avatarUrl": "https://avatars.githubusercontent.com/u/20110076?v=4", - "id": "github/20110076", - "name": "Zakaria Mansouri", - "profileUrl": "/Account/github/20110076", - "username": "ZibanPirate", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isString": "id must be a string", - }, - "property": "id", - "target": AccountEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "username must be a string", - }, - "property": "username", - "target": AccountEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "name must be a string", - }, - "property": "name", - "target": AccountEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isUrl": "profileUrl must be an URL address", - }, - "property": "profileUrl", - "target": AccountEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isUrl": "avatarUrl must be an URL address", - }, - "property": "avatarUrl", - "target": AccountEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `AccountEntity {}`; diff --git a/packages/models/src/account/index.spec.ts b/packages/models/src/account/index.spec.ts deleted file mode 100644 index fd54565c0..000000000 --- a/packages/models/src/account/index.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { AccountEntity } from "."; - -runDTOTestCases( - AccountEntity, - { - id: "github/20110076", - username: "ZibanPirate", - name: "Zakaria Mansouri", - profileUrl: "/Account/github/20110076", - avatarUrl: "https://avatars.githubusercontent.com/u/20110076?v=4", - }, - { - repositories: [], - }, -); diff --git a/packages/models/src/account/index.ts b/packages/models/src/account/index.ts deleted file mode 100644 index 7f63f0980..000000000 --- a/packages/models/src/account/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Type } from "class-transformer"; -import { IsString, IsUrl, ValidateNested } from "class-validator"; -import { BaseEntity, Model } from "src/_base"; -import { RepositoryReferenceEntity } from "src/repository-reference"; - -export class AccountEntity extends BaseEntity { - @IsString() - id!: string; - - @IsString() - username!: string; - - @IsString() - name!: string; - - // eslint-disable-next-line camelcase - @IsUrl({ require_protocol: false, require_host: false }) - profileUrl!: string; - - @IsUrl() - avatarUrl!: string; - - @ValidateNested({ each: true }) - @Type(() => RepositoryReferenceEntity) - repositories?: Model[]; -} diff --git a/packages/models/src/article/__snapshots__/index.spec.ts.snap b/packages/models/src/article/__snapshots__/index.spec.ts.snap deleted file mode 100644 index 6f7270641..000000000 --- a/packages/models/src/article/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,81 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -ArticleEntity { - "authors": [], - "content": "test-content", - "contributors": [], - "description": "test-description", - "image": "https://images.unsplash.com/photo-1520338661084-680395057c93?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=formatfit=crop&w=800&q=100", - "slug": "learn/Getting_Started", - "title": "Getting Started", -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -ArticleEntity { - "authors": [], - "content": "test-content", - "contributors": [], - "description": "test-description", - "image": "https://images.unsplash.com/photo-1520338661084-680395057c93?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=formatfit=crop&w=800&q=100", - "slug": "learn/Getting_Started", - "title": "Getting Started", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isString": "image must be a string", - }, - "property": "image", - "target": ArticleEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "description must be a string", - }, - "property": "description", - "target": ArticleEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "content must be a string", - }, - "property": "content", - "target": ArticleEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "slug must be a string", - }, - "property": "slug", - "target": ArticleEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "title must be a string", - }, - "property": "title", - "target": ArticleEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `ArticleEntity {}`; diff --git a/packages/models/src/article/index.spec.ts b/packages/models/src/article/index.spec.ts deleted file mode 100644 index baf5b259f..000000000 --- a/packages/models/src/article/index.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { ArticleEntity } from "."; - -runDTOTestCases( - ArticleEntity, - { - image: - "https://images.unsplash.com/photo-1520338661084-680395057c93?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=formatfit=crop&w=800&q=100", - slug: "learn/Getting_Started", - title: "Getting Started", - description: "test-description", - content: "test-content", - authors: [], - contributors: [], - }, - {}, -); diff --git a/packages/models/src/article/index.ts b/packages/models/src/article/index.ts deleted file mode 100644 index 16f77445d..000000000 --- a/packages/models/src/article/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Type } from "class-transformer"; -import { IsString, ValidateNested } from "class-validator"; -import { BaseEntity, Model } from "src/_base"; -import { AccountEntity } from "src/account"; - -export class ArticleInfoEntity extends BaseEntity { - @IsString() - slug!: string; - - @IsString() - title!: string; -} - -export class ArticleEntity extends ArticleInfoEntity { - @IsString() - image!: string; - - @IsString() - description!: string; - - @IsString() - content!: string; - - @ValidateNested({ each: true }) - @Type(() => AccountEntity) - authors!: Model[]; - - @ValidateNested({ each: true }) - @Type(() => AccountEntity) - contributors!: Model[]; -} diff --git a/packages/models/src/contribution/__snapshots__/index.spec.ts.snap b/packages/models/src/contribution/__snapshots__/index.spec.ts.snap deleted file mode 100644 index 750d74aed..000000000 --- a/packages/models/src/contribution/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,155 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -ContributionEntity { - "commentsCount": 0, - "createdAt": "2020-02-02T20:22:02.000Z", - "createdBy": AccountEntity { - "avatarUrl": "https://avatars.githubusercontent.com/u/20110076?v=4", - "id": "github/20110076", - "name": "Zakaria Mansouri", - "profileUrl": "/Account/github/20110076", - "username": "ZibanPirate", - }, - "id": "71", - "labels": [ - "discussion", - "good first issue", - ], - "languages": [ - "JavaScript", - "Shell", - ], - "project": ProjectReferenceEntity { - "name": "Leblad", - "slug": "Leblad", - }, - "title": "Update the data set", - "type": "issue", - "updatedAt": "2020-02-02T20:22:02.000Z", - "url": "https://github.com/dzcode-io/leblad/issues/71", -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -ContributionEntity { - "commentsCount": 0, - "createdAt": "2020-02-02T20:22:02.000Z", - "createdBy": AccountEntity { - "avatarUrl": "https://avatars.githubusercontent.com/u/20110076?v=4", - "id": "github/20110076", - "name": "Zakaria Mansouri", - "profileUrl": "/Account/github/20110076", - "username": "ZibanPirate", - }, - "id": "71", - "labels": [ - "discussion", - "good first issue", - ], - "languages": [ - "JavaScript", - "Shell", - ], - "project": ProjectReferenceEntity { - "name": "Leblad", - "slug": "Leblad", - }, - "title": "Update the data set", - "type": "issue", - "updatedAt": "2020-02-02T20:22:02.000Z", - "url": "https://github.com/dzcode-io/leblad/issues/71", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isString": "id must be a string", - }, - "property": "id", - "target": ContributionEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "title must be a string", - }, - "property": "title", - "target": ContributionEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "type must be a string", - }, - "property": "type", - "target": ContributionEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isUrl": "url must be an URL address", - }, - "property": "url", - "target": ContributionEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "each value in languages must be a string", - }, - "property": "languages", - "target": ContributionEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "each value in labels must be a string", - }, - "property": "labels", - "target": ContributionEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isDateString": "createdAt must be a valid ISO 8601 date string", - }, - "property": "createdAt", - "target": ContributionEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isDateString": "updatedAt must be a valid ISO 8601 date string", - }, - "property": "updatedAt", - "target": ContributionEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isNumber": "commentsCount must be a number conforming to the specified constraints", - }, - "property": "commentsCount", - "target": ContributionEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `ContributionEntity {}`; diff --git a/packages/models/src/contribution/index.spec.ts b/packages/models/src/contribution/index.spec.ts deleted file mode 100644 index 1a25692fb..000000000 --- a/packages/models/src/contribution/index.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { ContributionEntity } from "."; - -runDTOTestCases( - ContributionEntity, - { - commentsCount: 0, - id: "71", - labels: ["discussion", "good first issue"], - languages: ["JavaScript", "Shell"], - project: { - name: "Leblad", - slug: "Leblad", - }, - title: "Update the data set", - type: "issue", - createdAt: "2020-02-02T20:22:02.000Z", - updatedAt: "2020-02-02T20:22:02.000Z", - url: "https://github.com/dzcode-io/leblad/issues/71", - createdBy: { - id: "github/20110076", - username: "ZibanPirate", - name: "Zakaria Mansouri", - profileUrl: "/Account/github/20110076", - avatarUrl: "https://avatars.githubusercontent.com/u/20110076?v=4", - }, - }, - {}, -); diff --git a/packages/models/src/contribution/index.ts b/packages/models/src/contribution/index.ts index da22a1118..046e82c6c 100644 --- a/packages/models/src/contribution/index.ts +++ b/packages/models/src/contribution/index.ts @@ -1,42 +1,9 @@ -import { Type } from "class-transformer"; -import { IsDateString, IsNumber, IsString, IsUrl, ValidateNested } from "class-validator"; -import { BaseEntity, Model } from "src/_base"; -import { AccountEntity } from "src/account"; -import { ProjectReferenceEntity } from "src/project-reference"; - -export class ContributionEntity extends BaseEntity { - @IsString() - id!: string; - - @IsString() - title!: string; - - @ValidateNested() - @Type(() => ProjectReferenceEntity) - project!: Model; - - @ValidateNested() - @Type(() => AccountEntity) - createdBy!: Model; - - @IsString() - type!: "issue" | "pullRequest"; - - @IsUrl() - url!: string; - - @IsString({ each: true }) - languages!: string[]; - - @IsString({ each: true }) - labels!: string[]; - - @IsDateString() - createdAt!: string; - - @IsDateString() - updatedAt!: string; - - @IsNumber() - commentsCount!: number; +import { BaseEntity } from "src/_base"; + +export interface ContributionEntity extends BaseEntity { + title: string; + type: "ISSUE" | "PULL_REQUEST"; + url: string; + updatedAt: string; + activityCount: number; } diff --git a/packages/models/src/contributor/index.ts b/packages/models/src/contributor/index.ts new file mode 100644 index 000000000..5c63a438d --- /dev/null +++ b/packages/models/src/contributor/index.ts @@ -0,0 +1,8 @@ +import { BaseEntity } from "src/_base"; + +export interface ContributorEntity extends BaseEntity { + name: string; + username: string; + url: string; + avatarUrl: string; +} diff --git a/packages/models/src/documentation/__snapshots__/index.spec.ts.snap b/packages/models/src/documentation/__snapshots__/index.spec.ts.snap deleted file mode 100644 index d899429e9..000000000 --- a/packages/models/src/documentation/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,81 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -DocumentationEntity { - "authors": [], - "content": "test-content", - "contributors": [], - "description": "test-description", - "image": "https://images.unsplash.com/photo-1520338661084-680395057c93?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=formatfit=crop&w=800&q=100", - "slug": "learn/Getting_Started", - "title": "Getting Started", -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -DocumentationEntity { - "authors": [], - "content": "test-content", - "contributors": [], - "description": "test-description", - "image": "https://images.unsplash.com/photo-1520338661084-680395057c93?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=formatfit=crop&w=800&q=100", - "slug": "learn/Getting_Started", - "title": "Getting Started", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isString": "image must be a string", - }, - "property": "image", - "target": DocumentationEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "description must be a string", - }, - "property": "description", - "target": DocumentationEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "content must be a string", - }, - "property": "content", - "target": DocumentationEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "slug must be a string", - }, - "property": "slug", - "target": DocumentationEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "title must be a string", - }, - "property": "title", - "target": DocumentationEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `DocumentationEntity {}`; diff --git a/packages/models/src/documentation/index.spec.ts b/packages/models/src/documentation/index.spec.ts deleted file mode 100644 index 8ed27367e..000000000 --- a/packages/models/src/documentation/index.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { DocumentationEntity } from "."; - -runDTOTestCases( - DocumentationEntity, - { - image: - "https://images.unsplash.com/photo-1520338661084-680395057c93?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=formatfit=crop&w=800&q=100", - slug: "learn/Getting_Started", - title: "Getting Started", - description: "test-description", - content: "test-content", - authors: [], - contributors: [], - }, - {}, -); diff --git a/packages/models/src/documentation/index.ts b/packages/models/src/documentation/index.ts deleted file mode 100644 index a2a74bccf..000000000 --- a/packages/models/src/documentation/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Type } from "class-transformer"; -import { IsString, ValidateNested } from "class-validator"; -import { BaseEntity, Model } from "src/_base"; -import { AccountEntity } from "src/account"; - -export class DocumentationInfoEntity extends BaseEntity { - @IsString() - slug!: string; - - @IsString() - title!: string; -} - -export class DocumentationEntity extends DocumentationInfoEntity { - @IsString() - image!: string; - - @IsString() - description!: string; - - @IsString() - content!: string; - - @ValidateNested({ each: true }) - @Type(() => AccountEntity) - authors!: Model[]; - - @ValidateNested({ each: true }) - @Type(() => AccountEntity) - contributors!: Model[]; -} diff --git a/packages/models/src/language/__snapshots__/index.spec.ts.snap b/packages/models/src/language/__snapshots__/index.spec.ts.snap deleted file mode 100644 index a9b1c2a83..000000000 --- a/packages/models/src/language/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,83 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot of allLanguages: allLanguages 1`] = ` -[ - { - "code": "en", - "direction": "ltr", - "label": "English", - "shortLabel": "EN", - }, - { - "code": "ar", - "direction": "rtl", - "label": "العربية", - "shortLabel": "ع", - }, -] -`; - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -LanguageEntity { - "code": "en", - "direction": "ltr", - "label": "English", - "shortLabel": "EN", -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -LanguageEntity { - "code": "en", - "direction": "ltr", - "label": "English", - "shortLabel": "EN", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isIn": "code must be one of the following values: en, ar", - }, - "property": "code", - "target": LanguageEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isIn": "shortLabel must be one of the following values: EN, ع", - }, - "property": "shortLabel", - "target": LanguageEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isIn": "label must be one of the following values: English, العربية", - }, - "property": "label", - "target": LanguageEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isIn": "direction must be one of the following values: ltr, rtl", - }, - "property": "direction", - "target": LanguageEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `LanguageEntity {}`; diff --git a/packages/models/src/language/index.spec.ts b/packages/models/src/language/index.spec.ts deleted file mode 100644 index 533a00e3b..000000000 --- a/packages/models/src/language/index.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { allLanguages, LanguageEntity } from "."; - -runDTOTestCases( - LanguageEntity, - { - code: "en", - label: "English", - shortLabel: "EN", - direction: "ltr", - }, - {}, -); - -it("should match snapshot of allLanguages", () => { - expect(allLanguages).toMatchSnapshot("allLanguages"); -}); diff --git a/packages/models/src/language/index.ts b/packages/models/src/language/index.ts index 1c62dc4c5..e56b4c4ea 100644 --- a/packages/models/src/language/index.ts +++ b/packages/models/src/language/index.ts @@ -1,21 +1,11 @@ -import { IsIn } from "class-validator"; -import { BaseEntity } from "src/_base"; - export const allLanguages = [ { code: "en", shortLabel: "EN", label: "English", direction: "ltr" }, { code: "ar", shortLabel: "ع", label: "العربية", direction: "rtl" }, ] as const; -export class LanguageEntity extends BaseEntity { - @IsIn(allLanguages.map(({ code }) => code)) - code!: typeof allLanguages[number]["code"]; - - @IsIn(allLanguages.map(({ shortLabel }) => shortLabel)) - shortLabel!: typeof allLanguages[number]["shortLabel"]; - - @IsIn(allLanguages.map(({ label }) => label)) - label!: typeof allLanguages[number]["label"]; - - @IsIn(allLanguages.map(({ direction }) => direction)) - direction!: typeof allLanguages[number]["direction"]; +export interface LanguageEntity { + code: (typeof allLanguages)[number]["code"]; + shortLabel: (typeof allLanguages)[number]["shortLabel"]; + label: (typeof allLanguages)[number]["label"]; + direction: (typeof allLanguages)[number]["direction"]; } diff --git a/packages/models/src/milestone/__snapshots__/index.spec.ts.snap b/packages/models/src/milestone/__snapshots__/index.spec.ts.snap deleted file mode 100644 index 73f1b4b3d..000000000 --- a/packages/models/src/milestone/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,112 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -MilestoneEntity { - "closedAt": "2022-08-30T09:55:46Z", - "closedIssuesCount": 2, - "createdAt": "2022-08-18T09:55:46Z", - "description": "Adding an Arabic version of dzcode.io", - "dueAt": "2022-08-30T09:55:46Z", - "id": "8320713", - "openIssuesCount": 4, - "status": "open", - "title": "Localization (web)", - "url": "https://github.com/dzcode-io/dzcode.io/milestone/9", -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -MilestoneEntity { - "closedIssuesCount": 2, - "createdAt": "2022-08-18T09:55:46Z", - "description": "Adding an Arabic version of dzcode.io", - "id": "8320713", - "openIssuesCount": 4, - "status": "open", - "title": "Localization (web)", - "url": "https://github.com/dzcode-io/dzcode.io/milestone/9", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isString": "id must be a string", - }, - "property": "id", - "target": MilestoneEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "title must be a string", - }, - "property": "title", - "target": MilestoneEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "description must be a string", - }, - "property": "description", - "target": MilestoneEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isUrl": "url must be an URL address", - }, - "property": "url", - "target": MilestoneEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isNumber": "openIssuesCount must be a number conforming to the specified constraints", - }, - "property": "openIssuesCount", - "target": MilestoneEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isNumber": "closedIssuesCount must be a number conforming to the specified constraints", - }, - "property": "closedIssuesCount", - "target": MilestoneEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "status must be a string", - }, - "property": "status", - "target": MilestoneEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isDateString": "createdAt must be a valid ISO 8601 date string", - }, - "property": "createdAt", - "target": MilestoneEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `MilestoneEntity {}`; diff --git a/packages/models/src/milestone/index.spec.ts b/packages/models/src/milestone/index.spec.ts deleted file mode 100644 index eea290f35..000000000 --- a/packages/models/src/milestone/index.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { MilestoneEntity } from "."; - -runDTOTestCases( - MilestoneEntity, - { - id: "8320713", - title: "Localization (web)", - description: "Adding an Arabic version of dzcode.io", - url: "https://github.com/dzcode-io/dzcode.io/milestone/9", - status: "open", - closedIssuesCount: 2, - openIssuesCount: 4, - createdAt: "2022-08-18T09:55:46Z", - }, - { - closedAt: "2022-08-30T09:55:46Z", - dueAt: "2022-08-30T09:55:46Z", - }, -); diff --git a/packages/models/src/milestone/index.ts b/packages/models/src/milestone/index.ts index bf9892f2d..8878a3b72 100644 --- a/packages/models/src/milestone/index.ts +++ b/packages/models/src/milestone/index.ts @@ -1,36 +1,13 @@ -import { IsDateString, IsNumber, IsOptional, IsString, IsUrl } from "class-validator"; -import { BaseEntity } from "src/_base"; - -export class MilestoneEntity extends BaseEntity { - @IsString() - id!: string; - - @IsString() - title!: string; - - @IsString() - description!: string; - - @IsUrl() - url!: string; - - @IsNumber() - openIssuesCount!: number; - - @IsNumber() - closedIssuesCount!: number; - - @IsString() - status!: "open" | "closed" | "in-progress"; - - @IsDateString() - createdAt!: string; - - @IsDateString() - @IsOptional() +// TODO-ZM: digest this to database later (then extends BaseEntity) +export interface MilestoneEntity { + id: string; + title: string; + description: string; + url: string; + openIssuesCount: number; + closedIssuesCount: number; + status: "open" | "closed" | "in-progress"; + createdAt: string; dueAt?: string; - - @IsDateString() - @IsOptional() closedAt?: string; } diff --git a/packages/models/src/project-reference/__snapshots__/index.spec.ts.snap b/packages/models/src/project-reference/__snapshots__/index.spec.ts.snap deleted file mode 100644 index 42c998511..000000000 --- a/packages/models/src/project-reference/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,68 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -ProjectReferenceEntity { - "name": "Leblad", - "repositories": [ - RepositoryReferenceEntity { - "owner": "dzcode-io", - "provider": "github", - "repository": "leblad", - }, - RepositoryReferenceEntity { - "owner": "abderrahmaneMustapha", - "provider": "github", - "repository": "leblad-py", - }, - ], - "slug": "Leblad", -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -ProjectReferenceEntity { - "name": "Leblad", - "repositories": [ - RepositoryReferenceEntity { - "owner": "dzcode-io", - "provider": "github", - "repository": "leblad", - }, - RepositoryReferenceEntity { - "owner": "abderrahmaneMustapha", - "provider": "github", - "repository": "leblad-py", - }, - ], - "slug": "Leblad", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isString": "slug must be a string", - }, - "property": "slug", - "target": ProjectReferenceEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "name must be a string", - }, - "property": "name", - "target": ProjectReferenceEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `ProjectReferenceEntity {}`; diff --git a/packages/models/src/project-reference/index.spec.ts b/packages/models/src/project-reference/index.spec.ts deleted file mode 100644 index d22d5e496..000000000 --- a/packages/models/src/project-reference/index.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { ProjectReferenceEntity } from "."; - -runDTOTestCases( - ProjectReferenceEntity, - { - name: "Leblad", - repositories: [ - { - provider: "github", - owner: "dzcode-io", - repository: "leblad", - }, - { - provider: "github", - owner: "abderrahmaneMustapha", - repository: "leblad-py", - }, - ], - slug: "Leblad", - }, - {}, -); diff --git a/packages/models/src/project-reference/index.ts b/packages/models/src/project-reference/index.ts deleted file mode 100644 index 827cc1714..000000000 --- a/packages/models/src/project-reference/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Type } from "class-transformer"; -import { IsString } from "class-validator"; -import { ValidateNested } from "class-validator"; -import { BaseEntity, Model } from "src/_base"; -import { RepositoryReferenceEntity } from "src/repository-reference"; - -// @TODO-ZM: remove this -export class ProjectReferenceEntity extends BaseEntity { - @IsString() - slug!: string; - @IsString() - name!: string; - - @ValidateNested({ each: true }) - @Type(() => RepositoryReferenceEntity) - repositories!: Model[]; -} diff --git a/packages/models/src/project/__snapshots__/index.spec.ts.snap b/packages/models/src/project/__snapshots__/index.spec.ts.snap deleted file mode 100644 index 4cbb6de2b..000000000 --- a/packages/models/src/project/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,68 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -ProjectEntity { - "name": "Leblad", - "repositories": [ - RepositoryEntity { - "owner": "dzcode-io", - "provider": "github", - "repository": "leblad", - }, - RepositoryEntity { - "owner": "abderrahmaneMustapha", - "provider": "github", - "repository": "leblad-py", - }, - ], - "slug": "Leblad", -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -ProjectEntity { - "name": "Leblad", - "repositories": [ - RepositoryEntity { - "owner": "dzcode-io", - "provider": "github", - "repository": "leblad", - }, - RepositoryEntity { - "owner": "abderrahmaneMustapha", - "provider": "github", - "repository": "leblad-py", - }, - ], - "slug": "Leblad", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isString": "slug must be a string", - }, - "property": "slug", - "target": ProjectEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "name must be a string", - }, - "property": "name", - "target": ProjectEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `ProjectEntity {}`; diff --git a/packages/models/src/project/index.spec.ts b/packages/models/src/project/index.spec.ts deleted file mode 100644 index 2edf4c72f..000000000 --- a/packages/models/src/project/index.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { ProjectEntity } from "."; - -runDTOTestCases( - ProjectEntity, - { - name: "Leblad", - repositories: [ - { - provider: "github", - owner: "dzcode-io", - repository: "leblad", - }, - { - provider: "github", - owner: "abderrahmaneMustapha", - repository: "leblad-py", - }, - ], - slug: "Leblad", - }, - {}, -); diff --git a/packages/models/src/project/index.ts b/packages/models/src/project/index.ts index c060e8279..64955e455 100644 --- a/packages/models/src/project/index.ts +++ b/packages/models/src/project/index.ts @@ -1,16 +1,6 @@ -import { Type } from "class-transformer"; -import { IsString, ValidateNested } from "class-validator"; -import { BaseEntity, Model } from "src/_base"; -import { RepositoryEntity } from "src/repository"; +import { BaseEntity } from "src/_base"; -export class ProjectEntity extends BaseEntity { - @IsString() - slug!: string; - - @IsString() - name!: string; - - @ValidateNested({ each: true }) - @Type(() => RepositoryEntity) - declare repositories: Model[]; +export interface ProjectEntity extends BaseEntity { + slug: string; + name: string; } diff --git a/packages/models/src/repository-reference/__snapshots__/index.spec.ts.snap b/packages/models/src/repository-reference/__snapshots__/index.spec.ts.snap deleted file mode 100644 index c9192cf93..000000000 --- a/packages/models/src/repository-reference/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,57 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -RepositoryReferenceEntity { - "contributions": [], - "contributors": [], - "owner": "dzcode-io", - "provider": "github", - "repository": "leblad", -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -RepositoryReferenceEntity { - "owner": "dzcode-io", - "provider": "github", - "repository": "leblad", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isString": "provider must be a string", - }, - "property": "provider", - "target": RepositoryReferenceEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "owner must be a string", - }, - "property": "owner", - "target": RepositoryReferenceEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "repository must be a string", - }, - "property": "repository", - "target": RepositoryReferenceEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `RepositoryReferenceEntity {}`; diff --git a/packages/models/src/repository-reference/index.spec.ts b/packages/models/src/repository-reference/index.spec.ts deleted file mode 100644 index 3b690189c..000000000 --- a/packages/models/src/repository-reference/index.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { RepositoryReferenceEntity } from "."; - -runDTOTestCases( - RepositoryReferenceEntity, - { - provider: "github", - owner: "dzcode-io", - repository: "leblad", - }, - { - contributions: [], - contributors: [], - }, -); diff --git a/packages/models/src/repository-reference/index.ts b/packages/models/src/repository-reference/index.ts deleted file mode 100644 index bc614e4d8..000000000 --- a/packages/models/src/repository-reference/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IsString } from "class-validator"; -import { BaseEntity } from "src/_base"; - -// @TODO-ZM: to remove this -export class RepositoryReferenceEntity extends BaseEntity { - @IsString() - provider!: "github" | "gitlab"; - - @IsString() - owner!: string; - - @IsString() - repository!: string; -} diff --git a/packages/models/src/repository-reference/utils.ts b/packages/models/src/repository-reference/utils.ts deleted file mode 100644 index c3c2f7a8e..000000000 --- a/packages/models/src/repository-reference/utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Model } from "src/_base"; - -import { RepositoryReferenceEntity } from "."; - -export const getRepositoryURL = (repository: Model): string => { - switch (repository.provider) { - case "github": - return `https://www.github.com/${repository.owner}/${repository.repository}`; - case "gitlab": - return `https://www.gitlab.com/${repository.owner}/${repository.repository}`; - } -}; diff --git a/packages/models/src/repository/__snapshots__/index.spec.ts.snap b/packages/models/src/repository/__snapshots__/index.spec.ts.snap deleted file mode 100644 index 72edf3836..000000000 --- a/packages/models/src/repository/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,64 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot when providing all fields: errors 1`] = `[]`; - -exports[`should match snapshot when providing all fields: output 1`] = ` -RepositoryEntity { - "contributions": [], - "contributors": [], - "owner": "dzcode-io", - "provider": "github", - "repository": "leblad", - "stats": RepositoryStatsEntity { - "contributionCount": 10, - "languages": [ - "TypeScript", - "Rust", - ], - }, -} -`; - -exports[`should match snapshot when providing required fields only: errors 1`] = `[]`; - -exports[`should match snapshot when providing required fields only: output 1`] = ` -RepositoryEntity { - "owner": "dzcode-io", - "provider": "github", - "repository": "leblad", -} -`; - -exports[`should show an error that matches snapshot when passing empty object: errors 1`] = ` -[ - ValidationError { - "children": [], - "constraints": { - "isIn": "provider must be one of the following values: github, gitlab", - }, - "property": "provider", - "target": RepositoryEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "owner must be a string", - }, - "property": "owner", - "target": RepositoryEntity {}, - "value": undefined, - }, - ValidationError { - "children": [], - "constraints": { - "isString": "repository must be a string", - }, - "property": "repository", - "target": RepositoryEntity {}, - "value": undefined, - }, -] -`; - -exports[`should show an error that matches snapshot when passing empty object: output 1`] = `RepositoryEntity {}`; diff --git a/packages/models/src/repository/index.spec.ts b/packages/models/src/repository/index.spec.ts deleted file mode 100644 index 2d14be94d..000000000 --- a/packages/models/src/repository/index.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { runDTOTestCases } from "src/_test"; - -import { RepositoryEntity } from "."; - -runDTOTestCases( - RepositoryEntity, - { - provider: "github", - owner: "dzcode-io", - repository: "leblad", - }, - { - contributions: [], - contributors: [], - stats: { contributionCount: 10, languages: ["TypeScript", "Rust"] }, - }, -); diff --git a/packages/models/src/repository/index.ts b/packages/models/src/repository/index.ts index eddf07d57..16283051f 100644 --- a/packages/models/src/repository/index.ts +++ b/packages/models/src/repository/index.ts @@ -1,38 +1,7 @@ -import { Type } from "class-transformer"; -import { IsIn, IsNumber, IsString, ValidateNested } from "class-validator"; -import { BaseEntity, Model } from "src/_base"; -import { AccountEntity } from "src/account"; -import { ContributionEntity } from "src/contribution"; +import { BaseEntity } from "src/_base"; -export class RepositoryStatsEntity extends BaseEntity { - @IsNumber() - contributionCount!: number; - - @IsString({ each: true }) - languages!: string[]; -} - -const RepositoryProviders = ["github", "gitlab"] as const; -type RepositoryProvider = typeof RepositoryProviders[number]; - -export class RepositoryEntity extends BaseEntity { - @IsIn(RepositoryProviders) - provider!: RepositoryProvider; - - @IsString() - owner!: string; - - @IsString() - repository!: string; - - @Type(() => RepositoryStatsEntity) - stats?: Model; - - @ValidateNested({ each: true }) - @Type(() => AccountEntity) - contributors?: Model[]; - - @ValidateNested({ each: true }) - @Type(() => ContributionEntity) - contributions?: Model[]; +export interface RepositoryEntity extends BaseEntity { + owner: string; + name: string; + provider: "github" | "gitlab"; } diff --git a/packages/tooling/.prettierignore b/packages/tooling/.prettierignore index 8fcc4f0bc..1e8c7d40b 100644 --- a/packages/tooling/.prettierignore +++ b/packages/tooling/.prettierignore @@ -34,3 +34,4 @@ nodemon.json *.ttf *.ts-prunerc *.patch +*.sql diff --git a/packages/tooling/package.json b/packages/tooling/package.json index 439879183..95ba99600 100644 --- a/packages/tooling/package.json +++ b/packages/tooling/package.json @@ -21,6 +21,6 @@ "lint:eslint": "eslint --config .eslintrc.json --ignore-path .eslintignore --report-unused-disable-directives", "lint:fix": "yarn lint:fix:alone", "lint:fix:alone": "yarn lint:eslint --fix . && yarn lint:prettier --write .", - "lint:prettier": "prettier --config .prettierrc --ignore-path .prettierignore --loglevel warn" + "lint:prettier": "prettier --config .prettierrc --ignore-path .prettierignore --log-level warn" } } diff --git a/packages/tooling/sentry-release.ts b/packages/tooling/sentry-release.ts index 993543472..26acfc352 100644 --- a/packages/tooling/sentry-release.ts +++ b/packages/tooling/sentry-release.ts @@ -6,8 +6,9 @@ if (!scope) throw new Error("Please provide a scope"); const uploadPath = process.argv[3]; if (!uploadPath) throw new Error("Please provide a uploadPath"); -const version = process.argv[4]; +let version = process.argv[4]; if (!version) throw new Error("Please provide a version"); +version = version.replace(/\//g, "-"); const environment = process.argv[5]; if (!environment) throw new Error("Please provide a environment"); diff --git a/packages/ui-mobile/package.jsonc b/packages/ui-mobile/package.jsonc index e86072b5a..329778682 100644 --- a/packages/ui-mobile/package.jsonc +++ b/packages/ui-mobile/package.jsonc @@ -49,7 +49,7 @@ "lint:eslint": "eslint --config ../tooling/.eslintrc.json --ignore-path ../tooling/.eslintignore --report-unused-disable-directives", "lint:fix": "yarn build && yarn lint:fix:alone", "lint:fix:alone": "yarn lint:eslint --fix . && yarn lint:prettier --write .", - "lint:prettier": "prettier --config ../tooling/.prettierrc --ignore-path ../tooling/.prettierignore --loglevel warn", + "lint:prettier": "prettier --config ../tooling/.prettierrc --ignore-path ../tooling/.prettierignore --log-level warn", "test": "yarn build && yarn test:alone", "test:alone": "echo \"skipped for now\"", "test:watch": "npm-run-all build --parallel build:watch \"test:alone --watch {@}\" --" diff --git a/packages/utils/package.json b/packages/utils/package.json index b6938f23a..9aca034e3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -31,7 +31,7 @@ "lint:eslint": "eslint --config ../tooling/.eslintrc.json --ignore-path ../tooling/.eslintignore --report-unused-disable-directives", "lint:fix": "yarn build && yarn lint:fix:alone", "lint:fix:alone": "yarn lint:eslint --fix . && yarn lint:prettier --write .", - "lint:prettier": "prettier --config ../tooling/.prettierrc --ignore-path ../tooling/.prettierignore --loglevel warn", + "lint:prettier": "prettier --config ../tooling/.prettierrc --ignore-path ../tooling/.prettierignore --log-level warn", "test": "yarn build && yarn test:alone", "test:alone": "jest --config ../tooling/jest.config.ts --rootDir .", "test:watch": "npm-run-all build --parallel build:watch \"test:alone --watch {@}\" --" diff --git a/packages/utils/src/config/environment.ts b/packages/utils/src/config/environment.ts index f4bd3fcd1..33d3e7e44 100644 --- a/packages/utils/src/config/environment.ts +++ b/packages/utils/src/config/environment.ts @@ -1,3 +1,3 @@ export const environments = ["development", "staging", "production"] as const; -export type Environment = typeof environments[number]; +export type Environment = (typeof environments)[number]; diff --git a/packages/utils/src/ts/index.ts b/packages/utils/src/ts/index.ts index a5913d73b..2d971000b 100644 --- a/packages/utils/src/ts/index.ts +++ b/packages/utils/src/ts/index.ts @@ -1,9 +1,5 @@ export type Flatten = T extends any[] ? T[number] : T; // eslint-disable-line @typescript-eslint/no-explicit-any -export type KeysMatching = { - [K in keyof Required]: Flatten[K]> extends V ? K : never; -}[keyof Required]; - export type OptionalPropertiesOf = Required< Pick< T, @@ -26,18 +22,18 @@ export type TreeItem> = { export type SplitString = string extends S ? string[] : S extends "" - ? [] - : S extends `${infer T}${D}${infer U}` - ? [T, ...SplitString] - : [S]; + ? [] + : S extends `${infer T}${D}${infer U}` + ? [T, ...SplitString] + : [S]; export type PopSubString = string extends S ? string : S extends "" - ? [] - : S extends `${string}${D}${infer U}` - ? PopSubString - : S; + ? [] + : S extends `${string}${D}${infer U}` + ? PopSubString + : S; export type PyramidSplitString< S extends string, diff --git a/web/package.json b/web/package.json index 423204ce1..34235334d 100644 --- a/web/package.json +++ b/web/package.json @@ -73,7 +73,7 @@ "lint:eslint": "eslint --config ../packages/tooling/.eslintrc.json --ignore-path ../packages/tooling/.eslintignore --report-unused-disable-directives", "lint:fix": "yarn build && yarn lint:fix:alone", "lint:fix:alone": "yarn lint:eslint --fix . && yarn lint:prettier --write .", - "lint:prettier": "prettier --config ../packages/tooling/.prettierrc --ignore-path ../packages/tooling/.prettierignore --loglevel warn", + "lint:prettier": "prettier --config ../packages/tooling/.prettierrc --ignore-path ../packages/tooling/.prettierignore --log-level warn", "lint:ts-prune": "ts-node ../packages/tooling/setup-ts-prune.ts && ts-prune --error", "lint:tsc": "tsc --noEmit", "start:dev": "rsbuild dev --open", diff --git a/web/rsbuild.config.ts b/web/rsbuild.config.ts index 4976fe954..af7b49719 100644 --- a/web/rsbuild.config.ts +++ b/web/rsbuild.config.ts @@ -1,4 +1,4 @@ -import { Environment, environments } from "@dzcode.io/utils/dist/config/environment"; +import { environments } from "@dzcode.io/utils/dist/config/environment"; import { defineConfig } from "@rsbuild/core"; import { pluginReact } from "@rsbuild/plugin-react"; import { readFileSync } from "fs"; diff --git a/web/src/_entry/index.html b/web/src/_entry/index.html index d681155db..d0b66c75c 100644 --- a/web/src/_entry/index.html +++ b/web/src/_entry/index.html @@ -1,4 +1,4 @@ - + <% if (stage !== "development") { %> {{googleAnalytics}} <% } %> diff --git a/web/src/components/locale/languages.ts b/web/src/components/locale/languages.ts index 97dbf757c..a1764fe1a 100644 --- a/web/src/components/locale/languages.ts +++ b/web/src/components/locale/languages.ts @@ -3,4 +3,4 @@ export const Languages = [ { code: "ar", label: "العربية" }, ] as const; -export type Language = typeof Languages[number]; +export type Language = (typeof Languages)[number]; diff --git a/web/src/pages/contribute/index.tsx b/web/src/pages/contribute/index.tsx index fa7aa6a95..ad91cd40e 100644 --- a/web/src/pages/contribute/index.tsx +++ b/web/src/pages/contribute/index.tsx @@ -54,29 +54,18 @@ export default function Page(): JSX.Element {

- {contribution.project.name} -
- {contribution.labels.map((label, labelIndex) => ( - - {label} - - ))} - {contribution.languages.map((language, languageIndex) => ( - - {language} - - ))} -
+ + {contribution.repository.project.name} + + {contribution.repository.owner}/{contribution.repository.name} +
-
- {getElapsedTime(contribution.updatedAt, localize("elapsed-time-suffixes"))} -
- {contribution.commentsCount > 0 && ( + {contribution.activityCount > 0 && (
- {contribution.commentsCount} + {contribution.activityCount}
)} +
+ {getElapsedTime(contribution.updatedAt, localize("elapsed-time-suffixes"))} +
- {contribution.type === "issue" + {contribution.type === "ISSUE" ? localize("contribute-read-issue") : localize("contribute-review-changes")} diff --git a/web/src/pages/not-found/index.tsx b/web/src/pages/not-found/index.tsx index b5dc16a96..4b64c9104 100644 --- a/web/src/pages/not-found/index.tsx +++ b/web/src/pages/not-found/index.tsx @@ -2,7 +2,6 @@ import { Helmet } from "react-helmet-async"; import svg from "src/assets/svg/404.svg"; import { Link } from "src/components/link"; import { Locale, useLocale } from "src/components/locale"; -import { Markdown } from "src/components/markdown"; // ts-prune-ignore-next export default function Page(): JSX.Element { diff --git a/web/src/pages/projects/index.tsx b/web/src/pages/projects/index.tsx index c39afeeb9..2ceb198bd 100644 --- a/web/src/pages/projects/index.tsx +++ b/web/src/pages/projects/index.tsx @@ -1,12 +1,11 @@ import { useEffect } from "react"; import { Helmet } from "react-helmet-async"; -import { Link } from "src/components/link"; import { Loading } from "src/components/loading"; import { Locale, useLocale } from "src/components/locale"; import { TryAgain } from "src/components/try-again"; import { fetchProjectsListAction } from "src/redux/actions/projects"; import { useAppDispatch, useAppSelector } from "src/redux/store"; -import { getRepositoryName, getRepositoryURL } from "src/utils/repository"; +import { getRepositoryName } from "src/utils/repository"; // ts-prune-ignore-next export default function Page(): JSX.Element { @@ -45,15 +44,9 @@ export default function Page(): JSX.Element {

{project.name}

-
    - {project.repositories.map((repository, repositoryIndex) => ( -
  • - - {getRepositoryName(repository)} - -
  • - ))} -
+ {project.repositories.map((repository, repositoryIndex) => ( + {getRepositoryName(repository)} + ))}
))} diff --git a/web/src/pages/team/index.tsx b/web/src/pages/team/index.tsx index 134a69bcf..641e2a014 100644 --- a/web/src/pages/team/index.tsx +++ b/web/src/pages/team/index.tsx @@ -1,12 +1,11 @@ import { useEffect } from "react"; import { Helmet } from "react-helmet-async"; -import { Link } from "src/components/link"; import { Loading } from "src/components/loading"; import { Locale, useLocale } from "src/components/locale"; import { TryAgain } from "src/components/try-again"; import { fetchContributorsListAction } from "src/redux/actions/contributors"; import { useAppDispatch, useAppSelector } from "src/redux/store"; -import { getRepositoryName, getRepositoryURL } from "src/utils/repository"; +import { getRepositoryName } from "src/utils/repository"; // ts-prune-ignore-next export default function Page(): JSX.Element { @@ -51,15 +50,18 @@ export default function Page(): JSX.Element { className="rounded-full w-20 h-20" />

{contributor.name}

-
    - {contributor.repositories.map((repository, repositoryIndex) => ( -
  • - - {getRepositoryName(repository)} - -
  • +
    + {contributor.projects.map((project, projectIndex) => ( +
    + {project.name} + {project.repositories.map((repository, repositoryIndex) => ( + + {getRepositoryName(repository)} + + ))} +
    ))} -
+
))} diff --git a/web/src/redux/actions/contributions.ts b/web/src/redux/actions/contributions.ts index 642530343..cf9ae31f3 100644 --- a/web/src/redux/actions/contributions.ts +++ b/web/src/redux/actions/contributions.ts @@ -8,7 +8,7 @@ export const fetchContributionsListAction = (): ThunkAction => async (dispatch) => { try { dispatch(contributionsPageSlice.actions.set({ contributionsList: null })); - const { contributions } = await fetchV2("api:Contributions", { query: [] }); + const { contributions } = await fetchV2("api:Contributions", {}); dispatch(contributionsPageSlice.actions.set({ contributionsList: contributions })); } catch (error) { diff --git a/web/src/redux/actions/contributors.ts b/web/src/redux/actions/contributors.ts index 9224adac2..f3e050c53 100644 --- a/web/src/redux/actions/contributors.ts +++ b/web/src/redux/actions/contributors.ts @@ -8,7 +8,7 @@ export const fetchContributorsListAction = (): ThunkAction => async (dispatch) => { try { dispatch(contributorsPageSlice.actions.set({ contributorsList: null })); - const { contributors } = await fetchV2("api:Team", {}); + const { contributors } = await fetchV2("api:Contributors", {}); dispatch(contributorsPageSlice.actions.set({ contributorsList: contributors })); } catch (error) { dispatch(contributorsPageSlice.actions.set({ contributorsList: "ERROR" })); diff --git a/web/src/redux/slices/contributions-page.ts b/web/src/redux/slices/contributions-page.ts index f945061d3..4cbeaa9e7 100644 --- a/web/src/redux/slices/contributions-page.ts +++ b/web/src/redux/slices/contributions-page.ts @@ -1,11 +1,11 @@ -import { GetContributionsResponseDto } from "@dzcode.io/api/dist/contribution/types"; +import { GetContributionsResponse } from "@dzcode.io/api/dist/contribution/types"; import { createSlice } from "@reduxjs/toolkit"; import { setReducerFactory } from "src/redux/utils"; import { Loadable } from "src/utils/loadable"; // ts-prune-ignore-next export interface ContributionsPageState { - contributionsList: Loadable; + contributionsList: Loadable; } const initialState: ContributionsPageState = { diff --git a/web/src/redux/slices/contributors-page.ts b/web/src/redux/slices/contributors-page.ts index 47150399a..d132936a5 100644 --- a/web/src/redux/slices/contributors-page.ts +++ b/web/src/redux/slices/contributors-page.ts @@ -1,11 +1,11 @@ -import { GetTeamResponseDto } from "@dzcode.io/api/dist/team/types"; +import { GetContributorsResponse } from "@dzcode.io/api/dist/contributor/types"; import { createSlice } from "@reduxjs/toolkit"; import { setReducerFactory } from "src/redux/utils"; import { Loadable } from "src/utils/loadable"; // ts-prune-ignore-next export interface ContributorsPageState { - contributorsList: Loadable; + contributorsList: Loadable; } const initialState: ContributorsPageState = { diff --git a/web/src/redux/slices/landing-page.ts b/web/src/redux/slices/landing-page.ts index 4c198d344..066c7e340 100644 --- a/web/src/redux/slices/landing-page.ts +++ b/web/src/redux/slices/landing-page.ts @@ -1,11 +1,11 @@ -import { GetMilestonesResponseDto } from "@dzcode.io/api/dist/milestone/types"; +import { GetMilestonesResponse } from "@dzcode.io/api/dist/milestone/types"; import { createSlice } from "@reduxjs/toolkit"; import { setReducerFactory } from "src/redux/utils"; import { Loadable } from "src/utils/loadable"; // ts-prune-ignore-next export interface LandingPageState { - milestones: Loadable; + milestones: Loadable; } const initialState: LandingPageState = { diff --git a/web/src/redux/slices/projects-page.ts b/web/src/redux/slices/projects-page.ts index 70c157e4f..19250703b 100644 --- a/web/src/redux/slices/projects-page.ts +++ b/web/src/redux/slices/projects-page.ts @@ -1,11 +1,11 @@ -import { GetProjectsResponseDto } from "@dzcode.io/api/dist/project/types"; +import { GetProjectsResponse } from "@dzcode.io/api/dist/project/types"; import { createSlice } from "@reduxjs/toolkit"; import { setReducerFactory } from "src/redux/utils"; import { Loadable } from "src/utils/loadable"; // ts-prune-ignore-next export interface ProjectsPageState { - projectsList: Loadable; + projectsList: Loadable; } const initialState: ProjectsPageState = { diff --git a/web/src/redux/slices/settings.ts b/web/src/redux/slices/settings.ts index c55ac3382..43dda2a4d 100644 --- a/web/src/redux/slices/settings.ts +++ b/web/src/redux/slices/settings.ts @@ -1,5 +1,5 @@ import { createSlice } from "@reduxjs/toolkit"; -import { Language, Languages } from "src/components/locale/languages"; +import { Language } from "src/components/locale/languages"; import { getInitialLanguageCode } from "src/utils/website-language"; // ts-prune-ignore-next diff --git a/web/src/utils/repository.test.ts b/web/src/utils/repository.test.ts index da85f33d9..cf61d31e2 100644 --- a/web/src/utils/repository.test.ts +++ b/web/src/utils/repository.test.ts @@ -4,7 +4,7 @@ describe("getRepositoryName", () => { it("should return the repository name", () => { const repository = { owner: "dzcode.io", - repository: "dzcode.io", + name: "dzcode.io", } as const; expect(getRepositoryName(repository)).toBe("dzcode.io/dzcode.io"); }); @@ -14,7 +14,7 @@ describe("getRepositoryURL", () => { it("should return the repository URL", () => { const repository = { owner: "dzcode.io", - repository: "dzcode.io", + name: "dzcode.io", provider: "github", } as const; expect(getRepositoryURL(repository)).toBe("https://www.github.com/dzcode.io/dzcode.io"); diff --git a/web/src/utils/repository.ts b/web/src/utils/repository.ts index 6a2a986df..264e4c247 100644 --- a/web/src/utils/repository.ts +++ b/web/src/utils/repository.ts @@ -1,18 +1,19 @@ -import { Model } from "@dzcode.io/models/dist/_base"; import { RepositoryEntity } from "@dzcode.io/models/dist/repository"; -export function getRepositoryName( - repository: Pick, "owner" | "repository">, -): string { - return `${repository.owner}/${repository.repository}`; +export function getRepositoryName(repository: Pick): string { + return `${repository.owner}/${repository.name}`; } -export const getRepositoryURL = (repository: Model): string => { - switch (repository.provider) { +export const getRepositoryURL = ({ + provider, + owner, + name, +}: Pick): string => { + switch (provider) { case "github": - return `https://www.github.com/${repository.owner}/${repository.repository}`; + return `https://www.github.com/${owner}/${name}`; case "gitlab": - return `https://www.gitlab.com/${repository.owner}/${repository.repository}`; + return `https://www.gitlab.com/${owner}/${name}`; default: return ""; } diff --git a/yarn.lock b/yarn.lock index b47515f6f..f6166e4ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -613,6 +613,252 @@ enabled "2.0.x" kuler "^2.0.0" +"@drizzle-team/brocli@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@drizzle-team/brocli/-/brocli-0.10.1.tgz#8b73d65eaf2f6d04f45718ea6f4d789d69526cd3" + integrity sha512-AHy0vjc+n/4w/8Mif+w86qpppHuF3AyXbcWW+R/W7GNA3F5/p2nuhlkCJaTXSLZheB4l1rtHzOfr9A7NwoR/Zg== + +"@esbuild-kit/core-utils@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz#186b6598a5066f0413471d7c4d45828e399ba96c" + integrity sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ== + dependencies: + esbuild "~0.18.20" + source-map-support "^0.5.21" + +"@esbuild-kit/esm-loader@^2.5.5": + version "2.6.5" + resolved "https://registry.yarnpkg.com/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz#6eedee46095d7d13b1efc381e2211ed1c60e64ea" + integrity sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA== + dependencies: + "@esbuild-kit/core-utils" "^3.3.2" + get-tsconfig "^4.7.0" + +"@esbuild/aix-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" + integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== + +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" + integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" + integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/android-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" + integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" + integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/darwin-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" + integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" + integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/freebsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" + integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" + integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" + integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" + integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-loong64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" + integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-mips64el@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" + integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" + integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-riscv64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" + integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-s390x@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" + integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/linux-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" + integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/netbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" + integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/openbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" + integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/sunos-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" + integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" + integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" + integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + +"@esbuild/win32-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" + integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== + "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -1958,16 +2204,251 @@ dependencies: "@octokit/openapi-types" "^11.2.0" -"@opentelemetry/api@~1.9.0": +"@opentelemetry/api-logs@0.52.1": + version "0.52.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.52.1.tgz#52906375da4d64c206b0c4cb8ffa209214654ecc" + integrity sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A== + dependencies: + "@opentelemetry/api" "^1.0.0" + +"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.8", "@opentelemetry/api@^1.9.0", "@opentelemetry/api@~1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== -"@opentelemetry/semantic-conventions@~1.25.1": +"@opentelemetry/context-async-hooks@^1.25.1": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-1.26.0.tgz#fa92f722cf685685334bba95f258d3ef9fce60f6" + integrity sha512-HedpXXYzzbaoutw6DFLWLDket2FwLkLpil4hGCZ1xYEIMTcivdfwEOISgdbLEWyG3HW52gTq2V9mOVJrONgiwg== + +"@opentelemetry/core@1.25.1": + version "1.25.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.25.1.tgz#ff667d939d128adfc7c793edae2f6bca177f829d" + integrity sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ== + dependencies: + "@opentelemetry/semantic-conventions" "1.25.1" + +"@opentelemetry/core@1.26.0", "@opentelemetry/core@^1.1.0", "@opentelemetry/core@^1.25.1", "@opentelemetry/core@^1.8.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.26.0.tgz#7d84265aaa850ed0ca5813f97d831155be42b328" + integrity sha512-1iKxXXE8415Cdv0yjG3G6hQnB5eVEsJce3QaawX8SjDn0mAS0ZM8fAbZZJD4ajvhC15cePvosSCut404KrIIvQ== + dependencies: + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/instrumentation-connect@0.38.0": + version "0.38.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.38.0.tgz#1f4aa27894eac2538fb3c8fce7b1be92cae0217e" + integrity sha512-2/nRnx3pjYEmdPIaBwtgtSviTKHWnDZN3R+TkRUnhIVrvBKVcq+I5B2rtd6mr6Fe9cHlZ9Ojcuh7pkNh/xdWWg== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + "@types/connect" "3.4.36" + +"@opentelemetry/instrumentation-express@0.41.1": + version "0.41.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-express/-/instrumentation-express-0.41.1.tgz#658561df6ffbae86f5ad33e8d7ef2abb7b4967fc" + integrity sha512-uRx0V3LPGzjn2bxAnV8eUsDT82vT7NTwI0ezEuPMBOTOsnPpGhWdhcdNdhH80sM4TrWrOfXm9HGEdfWE3TRIww== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + +"@opentelemetry/instrumentation-fastify@0.38.0": + version "0.38.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.38.0.tgz#0cb02ee1156197075e8a90e4fd18a6b6c94221ba" + integrity sha512-HBVLpTSYpkQZ87/Df3N0gAw7VzYZV3n28THIBrJWfuqw3Or7UqdhnjeuMIPQ04BKk3aZc0cWn2naSQObbh5vXw== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + +"@opentelemetry/instrumentation-fs@0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.14.0.tgz#19f1cb38a8c2d05f3b96af67f1c8d43f0af2829b" + integrity sha512-pVc8P5AgliC1DphyyBUgsxXlm2XaPH4BpYvt7rAZDMIqUpRk8gs19SioABtKqqxvFzg5jPtgJfJsdxq0Y+maLw== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.52.0" + +"@opentelemetry/instrumentation-graphql@0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.42.0.tgz#588a18c39e3b3f655bc09243566172ab0b638d35" + integrity sha512-N8SOwoKL9KQSX7z3gOaw5UaTeVQcfDO1c21csVHnmnmGUoqsXbArK2B8VuwPWcv6/BC/i3io+xTo7QGRZ/z28Q== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + +"@opentelemetry/instrumentation-hapi@0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.40.0.tgz#ae11190f0f57cdb4dc8d792cb8bca61e5343684c" + integrity sha512-8U/w7Ifumtd2bSN1OLaSwAAFhb9FyqWUki3lMMB0ds+1+HdSxYBe9aspEJEgvxAqOkrQnVniAPTEGf1pGM7SOw== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + +"@opentelemetry/instrumentation-http@0.52.1": + version "0.52.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-http/-/instrumentation-http-0.52.1.tgz#12061501601838d1c912f9c29bdd40a13a7e44cf" + integrity sha512-dG/aevWhaP+7OLv4BQQSEKMJv8GyeOp3Wxl31NHqE8xo9/fYMfEljiZphUHIfyg4gnZ9swMyWjfOQs5GUQe54Q== + dependencies: + "@opentelemetry/core" "1.25.1" + "@opentelemetry/instrumentation" "0.52.1" + "@opentelemetry/semantic-conventions" "1.25.1" + semver "^7.5.2" + +"@opentelemetry/instrumentation-ioredis@0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.42.0.tgz#0f488ffc68af3caa474e2f67861759075170729c" + integrity sha512-P11H168EKvBB9TUSasNDOGJCSkpT44XgoM6d3gRIWAa9ghLpYhl0uRkS8//MqPzcJVHr3h3RmfXIpiYLjyIZTw== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/redis-common" "^0.36.2" + "@opentelemetry/semantic-conventions" "^1.23.0" + +"@opentelemetry/instrumentation-koa@0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.42.0.tgz#1c180f3605448c2e57a4ba073b69ffba7b2970b3" + integrity sha512-H1BEmnMhho8o8HuNRq5zEI4+SIHDIglNB7BPKohZyWG4fWNuR7yM4GTlR01Syq21vODAS7z5omblScJD/eZdKw== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + +"@opentelemetry/instrumentation-mongodb@0.46.0": + version "0.46.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.46.0.tgz#e3720e8ca3ca9f228fbf02f0812f7518c030b05e" + integrity sha512-VF/MicZ5UOBiXrqBslzwxhN7TVqzu1/LN/QDpkskqM0Zm0aZ4CVRbUygL8d7lrjLn15x5kGIe8VsSphMfPJzlA== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/sdk-metrics" "^1.9.1" + "@opentelemetry/semantic-conventions" "^1.22.0" + +"@opentelemetry/instrumentation-mongoose@0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.40.0.tgz#9c888312e524c381bfdf56a094c799150332dd51" + integrity sha512-niRi5ZUnkgzRhIGMOozTyoZIvJKNJyhijQI4nF4iFSb+FUx2v5fngfR+8XLmdQAO7xmsD8E5vEGdDVYVtKbZew== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + +"@opentelemetry/instrumentation-mysql2@0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.40.0.tgz#fa2992c36d54427dccea68e5c69fff01103dabe6" + integrity sha512-0xfS1xcqUmY7WE1uWjlmI67Xg3QsSUlNT+AcXHeA4BDUPwZtWqF4ezIwLgpVZfHOnkAEheqGfNSWd1PIu3Wnfg== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/sql-common" "^0.40.1" + +"@opentelemetry/instrumentation-mysql@0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.40.0.tgz#bde5894c8eb447a4b8e940b030b2b73898da03fa" + integrity sha512-d7ja8yizsOCNMYIJt5PH/fKZXjb/mS48zLROO4BzZTtDfhNCl2UM/9VIomP2qkGIFVouSJrGr/T00EzY7bPtKA== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + "@types/mysql" "2.15.22" + +"@opentelemetry/instrumentation-nestjs-core@0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.39.0.tgz#733fef4306c796951d7ea1951b45f9df0aed234d" + integrity sha512-mewVhEXdikyvIZoMIUry8eb8l3HUjuQjSjVbmLVTt4NQi35tkpnHQrG9bTRBrl3403LoWZ2njMPJyg4l6HfKvA== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.23.0" + +"@opentelemetry/instrumentation-pg@0.43.0": + version "0.43.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.43.0.tgz#3cd94ad5144e1fd326a921280fa8bb7b49005eb5" + integrity sha512-og23KLyoxdnAeFs1UWqzSonuCkePUzCX30keSYigIzJe/6WSYA8rnEI5lobcxPEzg+GcU06J7jzokuEHbjVJNw== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/sql-common" "^0.40.1" + "@types/pg" "8.6.1" + "@types/pg-pool" "2.0.4" + +"@opentelemetry/instrumentation-redis-4@0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.41.0.tgz#6c1b1a37c18478887f346a3bc7ef309ee9f726c0" + integrity sha512-H7IfGTqW2reLXqput4yzAe8YpDC0fmVNal95GHMLOrS89W+qWUKIqxolSh63hJyfmwPSFwXASzj7wpSk8Az+Dg== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/redis-common" "^0.36.2" + "@opentelemetry/semantic-conventions" "^1.22.0" + +"@opentelemetry/instrumentation@0.52.1", "@opentelemetry/instrumentation@^0.49 || ^0.50 || ^0.51 || ^0.52.0", "@opentelemetry/instrumentation@^0.52.0", "@opentelemetry/instrumentation@^0.52.1": + version "0.52.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.52.1.tgz#2e7e46a38bd7afbf03cf688c862b0b43418b7f48" + integrity sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw== + dependencies: + "@opentelemetry/api-logs" "0.52.1" + "@types/shimmer" "^1.0.2" + import-in-the-middle "^1.8.1" + require-in-the-middle "^7.1.1" + semver "^7.5.2" + shimmer "^1.2.1" + +"@opentelemetry/instrumentation@^0.46.0": + version "0.46.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.46.0.tgz#a8a252306f82e2eace489312798592a14eb9830e" + integrity sha512-a9TijXZZbk0vI5TGLZl+0kxyFfrXHhX6Svtz7Pp2/VBlCSKrazuULEyoJQrOknJyFWNMEmbbJgOciHCCpQcisw== + dependencies: + "@types/shimmer" "^1.0.2" + import-in-the-middle "1.7.1" + require-in-the-middle "^7.1.1" + semver "^7.5.2" + shimmer "^1.2.1" + +"@opentelemetry/redis-common@^0.36.2": + version "0.36.2" + resolved "https://registry.yarnpkg.com/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz#906ac8e4d804d4109f3ebd5c224ac988276fdc47" + integrity sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g== + +"@opentelemetry/resources@1.26.0", "@opentelemetry/resources@^1.25.1": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.26.0.tgz#da4c7366018bd8add1f3aa9c91c6ac59fd503cef" + integrity sha512-CPNYchBE7MBecCSVy0HKpUISEeJOniWqcHaAHpmasZ3j9o6V3AyBzhRc90jdmemq0HOxDr6ylhUbDhBqqPpeNw== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/sdk-metrics@^1.9.1": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.26.0.tgz#37bb0afb1d4447f50aab9cdd05db6f2d8b86103e" + integrity sha512-0SvDXmou/JjzSDOjUmetAAvcKQW6ZrvosU0rkbDGpXvvZN+pQF6JbK/Kd4hNdK4q/22yeruqvukXEJyySTzyTQ== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/resources" "1.26.0" + +"@opentelemetry/sdk-trace-base@^1.22", "@opentelemetry/sdk-trace-base@^1.25.1": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.26.0.tgz#0c913bc6d2cfafd901de330e4540952269ae579c" + integrity sha512-olWQldtvbK4v22ymrKLbIcBi9L2SpMO84sCPY54IVsJhP9fRsxJT194C/AVaAuJzLE30EdhhM1VmvVYR7az+cw== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/semantic-conventions@1.25.1", "@opentelemetry/semantic-conventions@~1.25.1": version "1.25.1" resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz#0deecb386197c5e9c2c28f2f89f51fb8ae9f145e" integrity sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ== +"@opentelemetry/semantic-conventions@1.27.0", "@opentelemetry/semantic-conventions@^1.17.0", "@opentelemetry/semantic-conventions@^1.22.0", "@opentelemetry/semantic-conventions@^1.23.0", "@opentelemetry/semantic-conventions@^1.25.1": + version "1.27.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz#1a857dcc95a5ab30122e04417148211e6f945e6c" + integrity sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg== + +"@opentelemetry/sql-common@^0.40.1": + version "0.40.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz#93fbc48d8017449f5b3c3274f2268a08af2b83b6" + integrity sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg== + dependencies: + "@opentelemetry/core" "^1.1.0" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -2001,6 +2482,15 @@ dependencies: pug-lexer "^5.0.0" +"@prisma/instrumentation@5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-5.18.0.tgz#8b49e25bf3f8f756eb0c4c199b4cf8b6631db891" + integrity sha512-r074avGkpPXItk+josQPhufZEmGhUCb16PQx4ITPS40vWTpTPET4VsgCBZB2alIN6SS7pRFod2vz2M2HHEEylQ== + dependencies: + "@opentelemetry/api" "^1.8" + "@opentelemetry/instrumentation" "^0.49 || ^0.50 || ^0.51 || ^0.52.0" + "@opentelemetry/sdk-trace-base" "^1.22" + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -2212,16 +2702,6 @@ "@sentry/types" "8.27.0" "@sentry/utils" "8.27.0" -"@sentry-internal/tracing@7.46.0": - version "7.46.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.46.0.tgz#26febabe21a2c2cab45a3de75809d88753ec07eb" - integrity sha512-KYoppa7PPL8Er7bdPoxTNUfIY804JL7hhOEomQHYD22rLynwQ4AaLm3YEY75QWwcGb0B7ZDMV+tSumW7Rxuwuw== - dependencies: - "@sentry/core" "7.46.0" - "@sentry/types" "7.46.0" - "@sentry/utils" "7.46.0" - tslib "^1.9.3" - "@sentry/browser@8.27.0": version "8.27.0" resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.27.0.tgz#997eb6b3c298a659a109704a0fb660eae365cd3a" @@ -2247,15 +2727,6 @@ progress "^2.0.3" proxy-from-env "^1.1.0" -"@sentry/core@7.46.0": - version "7.46.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.46.0.tgz#f377e556d8679f29bde1cce15b1682b6c689d6b7" - integrity sha512-BnNHGh/ZTztqQedFko7vb2u6yLs/kWesOQNivav32ZbsEpVCjcmG1gOJXh2YmGIvj3jXOC9a4xfIuh+lYFcA6A== - dependencies: - "@sentry/types" "7.46.0" - "@sentry/utils" "7.46.0" - tslib "^1.9.3" - "@sentry/core@8.27.0": version "8.27.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.27.0.tgz#a0ebe31cdd9313186a14d9738238ed9cf7a59c01" @@ -2264,19 +2735,71 @@ "@sentry/types" "8.27.0" "@sentry/utils" "8.27.0" -"@sentry/node@^7.46.0": - version "7.46.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.46.0.tgz#f85ee74926372d19d6b6a23f68f19023d7a528a7" - integrity sha512-+GrgJMCye2WXGarRiU5IJHCK27xg7xbPc2XjGojBKbBoZfqxVAWbXEK4bnBQgRGP1pCmrU/M6ZhVgR3dP580xA== +"@sentry/core@8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.28.0.tgz#dd28fa913c296b443d4070f147c63e81edf429c8" + integrity sha512-+If9uubvpZpvaQQw4HLiKPhrSS9/KcoA/AcdQkNm+5CVwAoOmDPtyYfkPBgfo2hLZnZQqR1bwkz/PrNoOm+gqA== + dependencies: + "@sentry/types" "8.28.0" + "@sentry/utils" "8.28.0" + +"@sentry/node@8.28.0", "@sentry/node@^8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-8.28.0.tgz#fef8cccd2c75345cb3e8840dba8b748a07376060" + integrity sha512-444hx0S7EAYDdq3g2U37qHFC/WFErgf8ZvXqhWfoCI4RweHHntdFbz3azexYnO61iUsmSAnFAX6htJtAG2zNdA== + dependencies: + "@opentelemetry/api" "^1.9.0" + "@opentelemetry/context-async-hooks" "^1.25.1" + "@opentelemetry/core" "^1.25.1" + "@opentelemetry/instrumentation" "^0.52.1" + "@opentelemetry/instrumentation-connect" "0.38.0" + "@opentelemetry/instrumentation-express" "0.41.1" + "@opentelemetry/instrumentation-fastify" "0.38.0" + "@opentelemetry/instrumentation-fs" "0.14.0" + "@opentelemetry/instrumentation-graphql" "0.42.0" + "@opentelemetry/instrumentation-hapi" "0.40.0" + "@opentelemetry/instrumentation-http" "0.52.1" + "@opentelemetry/instrumentation-ioredis" "0.42.0" + "@opentelemetry/instrumentation-koa" "0.42.0" + "@opentelemetry/instrumentation-mongodb" "0.46.0" + "@opentelemetry/instrumentation-mongoose" "0.40.0" + "@opentelemetry/instrumentation-mysql" "0.40.0" + "@opentelemetry/instrumentation-mysql2" "0.40.0" + "@opentelemetry/instrumentation-nestjs-core" "0.39.0" + "@opentelemetry/instrumentation-pg" "0.43.0" + "@opentelemetry/instrumentation-redis-4" "0.41.0" + "@opentelemetry/resources" "^1.25.1" + "@opentelemetry/sdk-trace-base" "^1.25.1" + "@opentelemetry/semantic-conventions" "^1.25.1" + "@prisma/instrumentation" "5.18.0" + "@sentry/core" "8.28.0" + "@sentry/opentelemetry" "8.28.0" + "@sentry/types" "8.28.0" + "@sentry/utils" "8.28.0" + import-in-the-middle "^1.11.0" + optionalDependencies: + opentelemetry-instrumentation-fetch-node "1.2.3" + +"@sentry/opentelemetry@8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@sentry/opentelemetry/-/opentelemetry-8.28.0.tgz#402465eb5f2cf015f389321361953b9637e24e5e" + integrity sha512-xClK/fa2Y9AMoaV6f7sWfoHAz56actn2RN3UuYAfxlgmNEfZEa0tc78x4XygCT+2b83QbUb+qf1q4+1ft+HEsQ== dependencies: - "@sentry-internal/tracing" "7.46.0" - "@sentry/core" "7.46.0" - "@sentry/types" "7.46.0" - "@sentry/utils" "7.46.0" - cookie "^0.4.1" - https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^1.9.3" + "@sentry/core" "8.28.0" + "@sentry/types" "8.28.0" + "@sentry/utils" "8.28.0" + +"@sentry/profiling-node@^8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@sentry/profiling-node/-/profiling-node-8.28.0.tgz#d6796e0b1f376b9c273b1c2bb5fa73473dd9e450" + integrity sha512-VJFj0XxodeRm+mRJlLYMEmn6HKnYkEm07Zb2mdhG979bQwt2VRoPd+Cv4M6irEfmFoRD1OAR9HX0/p9ClcWzXg== + dependencies: + "@sentry/core" "8.28.0" + "@sentry/node" "8.28.0" + "@sentry/types" "8.28.0" + "@sentry/utils" "8.28.0" + detect-libc "^2.0.2" + node-abi "^3.61.0" "@sentry/react@^8.27.0": version "8.27.0" @@ -2289,30 +2812,15 @@ "@sentry/utils" "8.27.0" hoist-non-react-statics "^3.3.2" -"@sentry/tracing@^7.46.0": - version "7.46.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.46.0.tgz#cdda3a20edbb35789e4e8623492e9f0ca5f9af48" - integrity sha512-7qBtzmu7CDHclSKp+ZRrxoDcMyrev6/rxD2rSVJgB3o8gd2XGcO5vx9vuUOoYF0xTfOMXscR6Ft6JXE49xovYg== - dependencies: - "@sentry-internal/tracing" "7.46.0" - -"@sentry/types@7.46.0": - version "7.46.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.46.0.tgz#8573ba8676342c594fcfefff4552123278cfec51" - integrity sha512-2FMEMgt2h6u7AoELhNhu9L54GAh67KKfK2pJ1kEXJHmWxM9FSCkizjLs/t+49xtY7jEXr8qYq8bV967VfDPQ9g== - "@sentry/types@8.27.0": version "8.27.0" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.27.0.tgz#a5c7d2877c6c3620f812b2b31377b58d390b89d4" integrity sha512-B6lrP46+m2x0lfqWc9F4VcUbN893mVGnPEd7KIMRk95mPzkFJ3sNxggTQF5/ZfNO7lDQYQb22uysB5sj/BqFiw== -"@sentry/utils@7.46.0": - version "7.46.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.46.0.tgz#7a713724db3d1c8bc0aef6d19a7fe2c76db0bdf2" - integrity sha512-elRezDAF84guMG0OVIIZEWm6wUpgbda4HGks98CFnPsrnMm3N1bdBI9XdlxYLtf+ir5KsGR5YlEIf/a0kRUwAQ== - dependencies: - "@sentry/types" "7.46.0" - tslib "^1.9.3" +"@sentry/types@8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.28.0.tgz#a1cfc004d5714679cb3fed06c27298b0275d13b5" + integrity sha512-hOfqfd92/AzBrEdMgmmV1VfOXJbIfleFTnerRl0mg/+CcNgP/6+Fdonp354TD56ouWNF2WkOM6sEKSXMWp6SEQ== "@sentry/utils@8.27.0": version "8.27.0" @@ -2321,6 +2829,13 @@ dependencies: "@sentry/types" "8.27.0" +"@sentry/utils@8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.28.0.tgz#0feb46015033879b2a3cee4c0661386610025f47" + integrity sha512-smhk7PJpvDMQ2DB5p2qn9UeoUHdU41IgjMmS2xklZpa8tjzBTxDeWpGvrX2fuH67D9bAJuLC/XyZjJCHLoEW5g== + dependencies: + "@sentry/types" "8.28.0" + "@sideway/address@^4.1.5": version "4.1.5" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" @@ -2459,6 +2974,13 @@ dependencies: "@babel/types" "^7.3.0" +"@types/better-sqlite3@^7.6.11": + version "7.6.11" + resolved "https://registry.yarnpkg.com/@types/better-sqlite3/-/better-sqlite3-7.6.11.tgz#95acf22fcf5577624eea202058e26ba239760b9f" + integrity sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg== + dependencies: + "@types/node" "*" + "@types/body-parser@*", "@types/body-parser@^1.19.0": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -2479,6 +3001,13 @@ dependencies: "@types/node" "*" +"@types/connect@3.4.36": + version "3.4.36" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.36.tgz#e511558c15a39cb29bd5357eebb57bd1459cd1ab" + integrity sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w== + dependencies: + "@types/node" "*" + "@types/cors@^2.8.9": version "2.8.12" resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" @@ -2602,11 +3131,21 @@ dependencies: "@types/react" "*" +"@types/lodash@^4.17.7": + version "4.17.7" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.7.tgz#2f776bcb53adc9e13b2c0dfd493dfcbd7de43612" + integrity sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA== + "@types/long@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== +"@types/luxon@~3.4.0": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.4.2.tgz#e4fc7214a420173cea47739c33cdf10874694db7" + integrity sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA== + "@types/make-fetch-happen@^9.0.1": version "9.0.1" resolved "https://registry.yarnpkg.com/@types/make-fetch-happen/-/make-fetch-happen-9.0.1.tgz#90d391c9b8f6ba1470302e9f44d6c83f77bf7835" @@ -2650,6 +3189,13 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== +"@types/mysql@2.15.22": + version "2.15.22" + resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.22.tgz#8705edb9872bf4aa9dbc004cd494e00334e5cdb4" + integrity sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ== + dependencies: + "@types/node" "*" + "@types/node-fetch@^2.5.12": version "2.5.12" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" @@ -2678,6 +3224,31 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/pg-pool@2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/pg-pool/-/pg-pool-2.0.4.tgz#b5c60f678094ff3acf3442628a7f708928fcf263" + integrity sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ== + dependencies: + "@types/pg" "*" + +"@types/pg@*": + version "8.11.8" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.11.8.tgz#bc712f1ad8ca664acb1d321b42691d1a166a88d6" + integrity sha512-IqpCf8/569txXN/HoP5i1LjXfKZWL76Yr2R77xgeIICUbAYHeoaEZFhYHo2uDftecLWrTJUq63JvQu8q3lnDyA== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^4.0.1" + +"@types/pg@8.6.1": + version "8.6.1" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.6.1.tgz#099450b8dc977e8197a44f5229cedef95c8747f9" + integrity sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^2.2.0" + "@types/prettier@^2.1.5": version "2.7.2" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" @@ -2767,6 +3338,11 @@ "@types/mime" "^1" "@types/node" "*" +"@types/shimmer@^1.0.2": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/shimmer/-/shimmer-1.2.0.tgz#9b706af96fa06416828842397a70dfbbf1c14ded" + integrity sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg== + "@types/sinonjs__fake-timers@8.1.1": version "8.1.1" resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" @@ -2789,14 +3365,6 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== -"@types/swagger-ui-express@^4.1.2": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@types/swagger-ui-express/-/swagger-ui-express-4.1.3.tgz#7adbbbf5343b45869debef1e9ff39c9ba73e380f" - integrity sha512-jqCjGU/tGEaqIplPy3WyQg+Nrp6y80DCFnDEAvVKWkJyv0VivSSDCChkppHRHAablvInZe6pijDFMnavtN0vqA== - dependencies: - "@types/express" "*" - "@types/serve-static" "*" - "@types/tough-cookie@*": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" @@ -2822,6 +3390,11 @@ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== +"@types/validator@^13.11.8": + version "13.12.1" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.12.1.tgz#8835d22f7e25b261e624d02a42fe4ade2c689a3c" + integrity sha512-w0URwf7BQb0rD/EuiG12KP0bailHKHP5YVviJG9zw3ykAokL0TuxU2TUqMB7EwZ59bDHYdeTIvjI5m0S7qHfOA== + "@types/yargs-parser@*": version "20.2.1" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" @@ -3048,6 +3621,16 @@ accepts@^1.3.5, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -3068,6 +3651,11 @@ acorn@^8.4.1, acorn@^8.6.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== +acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" @@ -3637,6 +4225,14 @@ before-after-hook@^2.2.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== +better-sqlite3@^11.2.1: + version "11.2.1" + resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.2.1.tgz#3c6b8a8e2e12444d380e811796b59c8aba012e03" + integrity sha512-Xbt1d68wQnUuFIEVsbt6V+RG30zwgbtCGQ4QOcXVrOH0FE4eHk64FWZ9NUfRHS4/x1PXqwz/+KOrnXD7f0WieA== + dependencies: + bindings "^1.5.0" + prebuild-install "^7.1.1" + bignumber.js@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" @@ -3659,7 +4255,7 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^4.1.0: +bl@^4.0.3, bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== @@ -4022,15 +4618,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.1.tgz#250fd350cfd555d0d2160b1d51510eaf8326e86e" integrity sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA== -caniuse-lite@^1.0.30001280, caniuse-lite@^1.0.30001370: - version "1.0.30001473" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz#3859898b3cab65fc8905bb923df36ad35058153c" - integrity sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg== - -caniuse-lite@^1.0.30001599, caniuse-lite@^1.0.30001616, caniuse-lite@^1.0.30001640: - version "1.0.30001643" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz#9c004caef315de9452ab970c3da71085f8241dbd" - integrity sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg== +caniuse-lite@^1.0.30001280, caniuse-lite@^1.0.30001370, caniuse-lite@^1.0.30001599, caniuse-lite@^1.0.30001616, caniuse-lite@^1.0.30001640: + version "1.0.30001655" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz" + integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg== caseless@~0.12.0: version "0.12.0" @@ -4152,7 +4743,7 @@ chokidar@^3.5.3, chokidar@^3.6.0: optionalDependencies: fsevents "~2.3.2" -chownr@^1.1.4: +chownr@^1.1.1, chownr@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -4177,6 +4768,11 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== +cjs-module-lexer@^1.2.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.0.tgz#677de7ed7efff67cc40c9bf1897fea79d41b5215" + integrity sha512-N1NGmowPlGBLsOZLPvm48StN04V4YvQRL0i6b7ctrVY3epjP/ct7hFLOItz6pDIvRjwpfPxi52a2UWV2ziir8g== + cjson@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/cjson/-/cjson-0.3.3.tgz#a92d9c786e5bf9b930806329ee05d5d3261b4afa" @@ -4199,24 +4795,14 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -class-validator-jsonschema@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/class-validator-jsonschema/-/class-validator-jsonschema-3.1.0.tgz#95cafa347ddc9da49343639d3261f85d23b06d39" - integrity sha512-1If+ZK3ZKhJfA7QWi064RJ2oTadBqmBtVPRb4DyxIlWS2m2hc9kWHwoEfycOroVfTuANMZ4XOtp3JD27U5V95w== - dependencies: - lodash.groupby "^4.6.0" - lodash.merge "^4.6.2" - openapi3-ts "^2.0.0" - reflect-metadata "^0.1.13" - tslib "^2.0.3" - -class-validator@^0.13.2: - version "0.13.2" - resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.13.2.tgz#64b031e9f3f81a1e1dcd04a5d604734608b24143" - integrity sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw== +class-validator@^0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.1.tgz#ff2411ed8134e9d76acfeb14872884448be98110" + integrity sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ== dependencies: - libphonenumber-js "^1.9.43" - validator "^13.7.0" + "@types/validator" "^13.11.8" + libphonenumber-js "^1.10.53" + validator "^13.9.0" clean-regexp@^1.0.0: version "1.0.0" @@ -4723,7 +5309,7 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== -cookie@0.4.1, cookie@^0.4.0, cookie@^0.4.1: +cookie@0.4.1, cookie@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== @@ -4844,6 +5430,14 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cron@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/cron/-/cron-3.1.7.tgz#3423d618ba625e78458fff8cb67001672d49ba0d" + integrity sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw== + dependencies: + "@types/luxon" "~3.4.0" + luxon "~3.4.0" + cross-env@^5.1.3: version "5.2.1" resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.2.1.tgz#b2c76c1ca7add66dc874d11798466094f551b34d" @@ -5038,6 +5632,13 @@ debug@^4.3.4: dependencies: ms "2.1.2" +debug@^4.3.5: + version "4.3.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== + dependencies: + ms "2.1.2" + debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -5075,6 +5676,13 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -5217,6 +5825,11 @@ detect-indent@^6.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== +detect-libc@^2.0.0, detect-libc@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -5310,6 +5923,21 @@ dotenv@^8.2.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== +drizzle-kit@^0.24.2: + version "0.24.2" + resolved "https://registry.yarnpkg.com/drizzle-kit/-/drizzle-kit-0.24.2.tgz#928a56a6a2bec1c5725321f559ec51dc5a943412" + integrity sha512-nXOaTSFiuIaTMhS8WJC2d4EBeIcN9OSt2A2cyFbQYBAZbi7lRsVGJNqDpEwPqYfJz38yxbY/UtbvBBahBfnExQ== + dependencies: + "@drizzle-team/brocli" "^0.10.1" + "@esbuild-kit/esm-loader" "^2.5.5" + esbuild "^0.19.7" + esbuild-register "^3.5.0" + +drizzle-orm@^0.33.0: + version "0.33.0" + resolved "https://registry.yarnpkg.com/drizzle-orm/-/drizzle-orm-0.33.0.tgz#ece81e3e85f7559b5f7c01fc09e654e9a2f087fe" + integrity sha512-SHy72R2Rdkz0LEq0PSG/IdvnT3nGiWuRk+2tXZQ90GVq/XQhpCzu/EFT3V2rox+w8MlkBQxifF8pCStNYnERfA== + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -5502,6 +6130,70 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +esbuild-register@^3.5.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/esbuild-register/-/esbuild-register-3.6.0.tgz#cf270cfa677baebbc0010ac024b823cbf723a36d" + integrity sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg== + dependencies: + debug "^4.3.4" + +esbuild@^0.19.7: + version "0.19.12" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" + integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.19.12" + "@esbuild/android-arm" "0.19.12" + "@esbuild/android-arm64" "0.19.12" + "@esbuild/android-x64" "0.19.12" + "@esbuild/darwin-arm64" "0.19.12" + "@esbuild/darwin-x64" "0.19.12" + "@esbuild/freebsd-arm64" "0.19.12" + "@esbuild/freebsd-x64" "0.19.12" + "@esbuild/linux-arm" "0.19.12" + "@esbuild/linux-arm64" "0.19.12" + "@esbuild/linux-ia32" "0.19.12" + "@esbuild/linux-loong64" "0.19.12" + "@esbuild/linux-mips64el" "0.19.12" + "@esbuild/linux-ppc64" "0.19.12" + "@esbuild/linux-riscv64" "0.19.12" + "@esbuild/linux-s390x" "0.19.12" + "@esbuild/linux-x64" "0.19.12" + "@esbuild/netbsd-x64" "0.19.12" + "@esbuild/openbsd-x64" "0.19.12" + "@esbuild/sunos-x64" "0.19.12" + "@esbuild/win32-arm64" "0.19.12" + "@esbuild/win32-ia32" "0.19.12" + "@esbuild/win32-x64" "0.19.12" + +esbuild@~0.18.20: + version "0.18.20" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -5879,6 +6571,11 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + expect-more@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/expect-more/-/expect-more-1.1.0.tgz#f484ac5bc3f504d34a872d41092e3912778eade9" @@ -6430,6 +7127,11 @@ fresh@0.5.2, fresh@~0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-extra@10.0.0, fs-extra@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" @@ -6646,6 +7348,13 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" +get-tsconfig@^4.7.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.0.tgz#125dc13a316f61650a12b20c97c11b8fd996fedd" + integrity sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw== + dependencies: + resolve-pkg-maps "^1.0.0" + get-uri@^6.0.1: version "6.0.3" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.3.tgz#0d26697bc13cf91092e519aa63aa60ee5b6f385a" @@ -6724,6 +7433,11 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== + glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -7364,6 +8078,26 @@ import-fresh@^3.0.0, import-fresh@^3.2.1, import-fresh@^3.3.0: parent-module "^1.0.0" resolve-from "^4.0.0" +import-in-the-middle@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.7.1.tgz#3e111ff79c639d0bde459bd7ba29dd9fdf357364" + integrity sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg== + dependencies: + acorn "^8.8.2" + acorn-import-assertions "^1.9.0" + cjs-module-lexer "^1.2.2" + module-details-from-path "^1.0.3" + +import-in-the-middle@^1.11.0, import-in-the-middle@^1.8.1: + version "1.11.0" + resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.11.0.tgz#a94c4925b8da18256cde3b3b7b38253e6ca5e708" + integrity sha512-5DimNQGoe0pLUHbR9qK84iWaWjjbsxiqXnw6Qz64+azRgleqv9k2kTt5fw7QsOpmaGYtuxxursnPPsnTKEx10Q== + dependencies: + acorn "^8.8.2" + acorn-import-attributes "^1.9.5" + cjs-module-lexer "^1.2.2" + module-details-from-path "^1.0.3" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -8926,10 +9660,10 @@ libnpmpublish@^4.0.0: semver "^7.1.3" ssri "^8.0.1" -libphonenumber-js@^1.9.43: - version "1.9.43" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.43.tgz#2371e4383e6780990381d5b900b8c22666221cbb" - integrity sha512-tNB87ZutAiAkl3DE/Bo0Mxqn/XZbNxhPg4v9bYBwQQW4dlhBGqXl1vtmPxeDWbrijzwOA9vRjOOFm5V9SK/W3w== +libphonenumber-js@^1.10.53: + version "1.11.7" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.7.tgz#efe4fcf816e1982925e9c800d0013b0ee99b8283" + integrity sha512-x2xON4/Qg2bRIS11KIN9yCNYUjhtiEjNyptjX0mX+pyKHecxuJVLIpfX1lq9ZD6CrC/rB+y4GBi18c6CEcUR+A== libsodium-wrappers@^0.7.10: version "0.7.15" @@ -9061,16 +9795,6 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= -lodash.capitalize@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" - integrity sha1-+CbJtOKoUR2E46yinbBeGk87cqk= - -lodash.groupby@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" - integrity sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E= - lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -9138,11 +9862,6 @@ lodash.snakecase@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40= -lodash.startcase@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8" - integrity sha1-lDbjTtJgk+1/+uGTYUQ1CRXZrdg= - lodash.template@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" @@ -9243,10 +9962,10 @@ lru-cache@^7.14.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" - integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= +luxon@~3.4.0: + version "3.4.4" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.4.tgz#cf20dc27dc532ba41a169c43fdcc0063601577af" + integrity sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA== make-dir@^2.1.0: version "2.1.0" @@ -9824,6 +10543,11 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -9878,16 +10602,16 @@ minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.2.3, minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + minimist@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -minimist@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - minipass-collect@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" @@ -10001,6 +10725,11 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp-infer-owner@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" @@ -10034,6 +10763,11 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== +module-details-from-path@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" + integrity sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A== + moo@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c" @@ -10160,6 +10894,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -10205,6 +10944,13 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-abi@^3.3.0, node-abi@^3.61.0: + version "3.67.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.67.0.tgz#1d159907f18d18e18809dbbb5df47ed2426a08df" + integrity sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw== + dependencies: + semver "^7.3.5" + node-emoji@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-2.1.3.tgz#93cfabb5cc7c3653aa52f29d6ffb7927d8047c06" @@ -10640,6 +11386,11 @@ object.values@^1.1.5: define-properties "^1.1.3" es-abstract "^1.19.1" +obuf@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + on-finished@^2.2.0, on-finished@^2.3.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -10693,13 +11444,6 @@ open@^7.4.2: is-docker "^2.0.0" is-wsl "^2.1.1" -openapi3-ts@^2.0.0, openapi3-ts@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/openapi3-ts/-/openapi3-ts-2.0.1.tgz#b270aecea09e924f1886bc02a72608fca5a98d85" - integrity sha512-v6X3iwddhi276siej96jHGIqTx3wzVfMTmpGJEQDt7GPI7pI6sywItURLzpEci21SBRpPN/aOWSF5mVfFVNmcg== - dependencies: - yaml "^1.10.0" - openapi3-ts@^3.1.1: version "3.2.0" resolved "https://registry.yarnpkg.com/openapi3-ts/-/openapi3-ts-3.2.0.tgz#7e30d33c480e938e67e809ab16f419bc9beae3f8" @@ -10707,6 +11451,14 @@ openapi3-ts@^3.1.1: dependencies: yaml "^2.2.1" +opentelemetry-instrumentation-fetch-node@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/opentelemetry-instrumentation-fetch-node/-/opentelemetry-instrumentation-fetch-node-1.2.3.tgz#beb24048bdccb1943ba2a5bbadca68020e448ea7" + integrity sha512-Qb11T7KvoCevMaSeuamcLsAD+pZnavkhDnlVL0kRozfhl42dKG5Q3anUklAFKJZjY3twLR+BnRa6DlwwkIE/+A== + dependencies: + "@opentelemetry/instrumentation" "^0.46.0" + "@opentelemetry/semantic-conventions" "^1.17.0" + optionator@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" @@ -11099,11 +11851,6 @@ path-to-regexp@^1.1.1, path-to-regexp@^1.8.0: dependencies: isarray "0.0.1" -path-to-regexp@^2.2.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.4.0.tgz#35ce7f333d5616f1c1e1bfe266c3aba2e5b2e704" - integrity sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w== - path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -11141,17 +11888,22 @@ pg-int8@1.0.1: resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== +pg-numeric@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a" + integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== + pg-pool@^3.6.2: version "3.6.2" resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.2.tgz#3a592370b8ae3f02a7c8130d245bc02fa2c5f3f2" integrity sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg== -pg-protocol@^1.6.1: +pg-protocol@*, pg-protocol@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.1.tgz#21333e6d83b01faaebfe7a33a7ad6bfd9ed38cb3" integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg== -pg-types@^2.1.0: +pg-types@^2.1.0, pg-types@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== @@ -11162,6 +11914,19 @@ pg-types@^2.1.0: postgres-date "~1.0.4" postgres-interval "^1.1.0" +pg-types@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-4.0.2.tgz#399209a57c326f162461faa870145bb0f918b76d" + integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng== + dependencies: + pg-int8 "1.0.1" + pg-numeric "1.0.2" + postgres-array "~3.0.1" + postgres-bytea "~3.0.0" + postgres-date "~2.1.0" + postgres-interval "^3.0.0" + postgres-range "^1.1.1" + pg@^8.11.3: version "8.12.0" resolved "https://registry.yarnpkg.com/pg/-/pg-8.12.0.tgz#9341724db571022490b657908f65aee8db91df79" @@ -11332,16 +12097,33 @@ postgres-array@~2.0.0: resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== +postgres-array@~3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-3.0.2.tgz#68d6182cb0f7f152a7e60dc6a6889ed74b0a5f98" + integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog== + postgres-bytea@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== +postgres-bytea@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-3.0.0.tgz#9048dc461ac7ba70a6a42d109221619ecd1cb089" + integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw== + dependencies: + obuf "~1.1.2" + postgres-date@~1.0.4: version "1.0.7" resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== +postgres-date@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-2.1.0.tgz#b85d3c1fb6fb3c6c8db1e9942a13a3bf625189d0" + integrity sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA== + postgres-interval@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" @@ -11349,11 +12131,39 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" +postgres-interval@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-3.0.0.tgz#baf7a8b3ebab19b7f38f07566c7aab0962f0c86a" + integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw== + +postgres-range@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" + integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== + postinstall-postinstall@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== +prebuild-install@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.2.tgz#a5fd9986f5a6251fbc47e1e5c65de71e68c0a056" + integrity sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ== + dependencies: + detect-libc "^2.0.0" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^1.0.1" + node-abi "^3.3.0" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^4.0.0" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -11369,10 +12179,10 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= -prettier@^2.4.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.0.tgz#a6370e2d4594e093270419d9cc47f7670488f893" - integrity sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg== +prettier@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== pretty-bytes@^5.6.0: version "5.6.0" @@ -11704,7 +12514,7 @@ raw-body@^2.3.3: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.2.8: +rc@^1.2.7, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -12015,6 +12825,11 @@ reflect-metadata@^0.1.13: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== +reflect-metadata@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== + regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" @@ -12158,6 +12973,15 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +require-in-the-middle@^7.1.1: + version "7.4.0" + resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-7.4.0.tgz#606977820d4b5f9be75e5a108ce34cfed25b3bb4" + integrity sha512-X34iHADNbNDfr6OTStIAHWSAvvKQRYgLO6duASaVf7J2VA3lvmNYboAHOuLC2huav1IwgZJtyEcJCKVzFxOSMQ== + dependencies: + debug "^4.3.5" + module-details-from-path "^1.0.3" + resolve "^1.22.8" + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -12185,6 +13009,11 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -12212,7 +13041,7 @@ resolve@^1.20.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.22.2: +resolve@^1.22.2, resolve@^1.22.8: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -12312,19 +13141,6 @@ router@^1.3.1: setprototypeof "1.2.0" utils-merge "1.0.1" -routing-controllers-openapi@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/routing-controllers-openapi/-/routing-controllers-openapi-3.1.0.tgz#90898a46c2490b203242e64bc08b536ba1228118" - integrity sha512-FnTYnbNfsCN+vTDAc7rhCm5u0nLAH+p+UpbJXZT10cgo2t7xiZ23BrrzsR5nnqMGwe/iwsDUEEr8lxs6KarscQ== - dependencies: - lodash.capitalize "^4.2.1" - lodash.merge "^4.6.2" - lodash.startcase "^4.4.0" - openapi3-ts "^2.0.1" - path-to-regexp "^2.2.1" - reflect-metadata "^0.1.13" - tslib "^2.1.0" - routing-controllers@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/routing-controllers/-/routing-controllers-0.9.0.tgz#979016523db37832d4c9a23c33b2654a89a563de" @@ -12566,6 +13382,11 @@ shell-quote@^1.6.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== +shimmer@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" + integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -12600,6 +13421,20 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== + dependencies: + decompress-response "^6.0.0" + once "^1.3.1" + simple-concat "^1.0.0" + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" @@ -12793,6 +13628,14 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@^0.5.21: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" @@ -13282,18 +14125,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -swagger-ui-dist@^3.18.1: - version "3.52.5" - resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.52.5.tgz#9aa8101a2be751f5145195b9e048bc21b12fac60" - integrity sha512-8z18eX8G/jbTXYzyNIaobrnD7PSN7yU/YkSasMmajrXtw0FGS64XjrKn5v37d36qmU3o1xLeuYnktshRr7uIFw== - -swagger-ui-express@^4.1.6: - version "4.1.6" - resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-4.1.6.tgz#682294af3d5c70f74a1fa4d6a9b503a9ee55ea82" - integrity sha512-Xs2BGGudvDBtL7RXcYtNvHsFtP1DBFPMJFRxHe5ez/VG/rzVOEjazJOOSc/kSCyxreCTKfJrII6MJlL9a6t8vw== - dependencies: - swagger-ui-dist "^3.18.1" - syncpack@^5.8.15: version "5.8.15" resolved "https://registry.yarnpkg.com/syncpack/-/syncpack-5.8.15.tgz#4b9e7837fa738d7ddd80c49ac14a9cba152951b3" @@ -13336,6 +14167,27 @@ tailwindcss@^3.4.4: resolve "^1.22.2" sucrase "^3.32.0" +tar-fs@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + tar-stream@^3.0.0: version "3.1.7" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b" @@ -13710,12 +14562,12 @@ ts-prune@^0.10.3: "true-myth" "^4.1.0" ts-morph "^13.0.1" -tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0: +tslib@^2.0.1, tslib@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -14215,10 +15067,10 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -validator@^13.7.0: - version "13.7.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857" - integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== +validator@^13.9.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f" + integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg== vary@^1, vary@^1.1.2, vary@~1.1.2: version "1.1.2"