diff --git a/.eslintrc.json b/.eslintrc.json index f2d9db8eb..294bd2f04 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,5 +1,5 @@ { - "parser": "@babel/eslint-parser", + "parser": "@typescript-eslint/parser", "env": { "node": true, "browser": true, @@ -9,13 +9,23 @@ }, "extends": [ "eslint:recommended", + "plugin:@typescript-eslint/recommended", "plugin:react/recommended", "google", "prettier", "plugin:json/recommended" ], - "overrides": [], + "overrides": [ + { + "files": ["test/**/*.js", "**/*.json"], + "parser": "espree", + "rules": { + "@typescript-eslint/no-unused-expressions": "off" + } + } + ], "parserOptions": { + "project": "./tsconfig.json", "requireConfigFile": false, "ecmaVersion": 12, "sourceType": "module", @@ -27,11 +37,13 @@ "presets": ["@babel/preset-react"] } }, - "plugins": ["react", "prettier"], + "plugins": ["@typescript-eslint", "react", "prettier"], "rules": { "react/prop-types": "off", "require-jsdoc": "off", - "no-async-promise-executor": "off" + "no-async-promise-executor": "off", + "@typescript-eslint/no-require-imports": "off", + "@typescript-eslint/no-explicit-any": "off" }, "settings": { "react": { diff --git a/.github/workflows/unused-dependencies.yml b/.github/workflows/unused-dependencies.yml index 3aa9dda66..39071e270 100644 --- a/.github/workflows/unused-dependencies.yml +++ b/.github/workflows/unused-dependencies.yml @@ -1,8 +1,8 @@ name: 'Unused Dependencies' on: [pull_request] -permissions: - contents: read +permissions: + contents: read jobs: unused-dependecies: @@ -20,11 +20,10 @@ jobs: with: node-version: '18.x' - name: 'Run depcheck' - run: | - npx depcheck --skip-missing --ignores="@babel/*,@commitlint/*,eslint,eslint-*,husky,mocha,concurrently,nyc,prettier" + run: | + npx depcheck --skip-missing --ignores="tsx,@babel/*,@commitlint/*,eslint,eslint-*,husky,mocha,ts-mocha,ts-node,concurrently,nyc,prettier,typescript,tsconfig-paths,vite-tsconfig-paths" echo $? if [[ $? == 1 ]]; then echo "Unused dependencies or devDependencies found" exit 1 fi - diff --git a/index.js b/index.ts similarity index 65% rename from index.js rename to index.ts index c86c0425e..f5d1c4b5e 100755 --- a/index.js +++ b/index.ts @@ -1,6 +1,13 @@ -#!/usr/bin/env node +#!/usr/bin/env tsx /* eslint-disable max-len */ -const argv = require('yargs/yargs')(process.argv.slice(2)) +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; +import * as fs from 'fs'; +import config from './src/config/file'; +import proxy from './src/proxy'; +import service from './src/service'; + +const argv = yargs(hideBin(process.argv)) .usage('Usage: $0 [options]') .options({ validate: { @@ -8,23 +15,23 @@ const argv = require('yargs/yargs')(process.argv.slice(2)) 'Check the proxy.config.json file in the current working directory for validation errors.', required: false, alias: 'v', + type: 'boolean', }, config: { description: 'Path to custom git-proxy configuration file.', default: 'proxy.config.json', required: false, alias: 'c', + type: 'string', }, }) - .strict().argv; + .strict() + .parseSync(); -const config = require('./src/config/file'); config.configFile = argv.c ? argv.c : undefined; if (argv.v) { - const fs = require('fs'); - - if (!fs.existsSync(config.configFile)) { + if (!fs.existsSync(config.configFile as string)) { console.error( `Config file ${config.configFile} doesn't exist, nothing to validate! Did you forget -c/--config?`, ); @@ -38,11 +45,7 @@ if (argv.v) { config.validate(); -const proxy = require('./src/proxy'); -const service = require('./src/service'); - proxy.start(); service.start(); -module.exports.proxy = proxy; -module.exports.service = service; +export { proxy, service }; diff --git a/package-lock.json b/package-lock.json index b356d0bc6..d0a0979fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,6 +63,12 @@ "@babel/preset-react": "^7.22.5", "@commitlint/cli": "^19.0.0", "@commitlint/config-conventional": "^19.0.0", + "@types/lodash": "^4.17.15", + "@types/mocha": "^10.0.10", + "@types/node": "^22.13.5", + "@types/yargs": "^17.0.33", + "@typescript-eslint/eslint-plugin": "^8.26.1", + "@typescript-eslint/parser": "^8.26.1", "@vitejs/plugin-react": "^4.0.2", "chai": "^4.2.0", "chai-http": "^4.3.0", @@ -75,11 +81,16 @@ "eslint-plugin-react": "^7.21.5", "eslint-plugin-standard": "^5.0.0", "husky": "^9.0.0", - "mocha": "^10.2.0", + "mocha": "^10.8.2", "nyc": "^17.0.0", "prettier": "^3.0.0", "sinon": "^19.0.2", - "vite": "^4.4.2" + "ts-mocha": "^11.1.0", + "ts-node": "^10.9.2", + "tsx": "^4.19.3", + "typescript": "^5.7.3", + "vite": "4.5.5", + "vite-tsconfig-paths": "^5.1.4" }, "optionalDependencies": { "@esbuild/darwin-arm64": "^0.18.20", @@ -1652,6 +1663,30 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@cypress/request": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.6.tgz", @@ -1715,6 +1750,22 @@ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", @@ -1984,6 +2035,22 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", @@ -2001,6 +2068,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/openbsd-x64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", @@ -3492,6 +3575,34 @@ "node": ">=14.0.0" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3555,12 +3666,25 @@ "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", + "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true + }, "node_modules/@types/node": { - "version": "20.10.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.7.tgz", - "integrity": "sha512-fRbIKb8C/Y2lXxB5eVMj4IU7xpdox0Lh8bUPEdtLysaylsml1hOOx1+STloRs/B9nf7C6kPRmmg/V7aQW7usNg==", + "version": "22.13.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", + "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.20.0" } }, "node_modules/@types/prop-types": { @@ -3632,6 +3756,23 @@ "@types/webidl-conversions": "*" } }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -3642,6 +3783,238 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.1.tgz", + "integrity": "sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/type-utils": "8.26.1", + "@typescript-eslint/utils": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.1.tgz", + "integrity": "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.1.tgz", + "integrity": "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.1.tgz", + "integrity": "sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.26.1", + "@typescript-eslint/utils": "8.26.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.1.tgz", + "integrity": "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.1.tgz", + "integrity": "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.1.tgz", + "integrity": "sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.1.tgz", + "integrity": "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.26.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -3711,6 +4084,19 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/activedirectory2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/activedirectory2/-/activedirectory2-2.2.0.tgz", @@ -3866,6 +4252,13 @@ "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -5112,6 +5505,13 @@ "node": ">=0.8" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -6610,6 +7010,36 @@ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -7113,6 +7543,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/getos": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", @@ -7271,6 +7713,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -7579,9 +8028,10 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", "engines": { "node": ">= 4" } @@ -9229,6 +9679,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -9297,6 +9754,16 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -9305,6 +9772,20 @@ "node": ">= 0.6" } }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -9649,6 +10130,25 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/nanoid": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz", + "integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -10595,24 +11095,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/precond": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", @@ -11086,6 +11568,15 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -12268,6 +12759,117 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-mocha": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-11.1.0.tgz", + "integrity": "sha512-yT7FfzNRCu8ZKkYvAOiH01xNma/vLq6Vit7yINKYFNVP8e5UyrYXSOMIipERTpzVKJQ4Qcos5bQo1tNERNZevQ==", + "dev": true, + "license": "MIT", + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", + "ts-node": "^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", + "tsconfig-paths": "^4.X.X" + }, + "peerDependenciesMeta": { + "tsconfig-paths": { + "optional": true + } + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfck": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.5.tgz", + "integrity": "sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -12281,6 +12883,417 @@ "node": ">=0.6.x" } }, + "node_modules/tsx": { + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", + "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", + "dev": true, + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -12434,12 +13447,11 @@ } }, "node_modules/typescript": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12479,9 +13491,10 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "license": "MIT" }, "node_modules/unicorn-magic": { "version": "0.1.0", @@ -12600,6 +13613,13 @@ "uuid": "dist/esm/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -12701,6 +13721,26 @@ } } }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, "node_modules/vscode-json-languageservice": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz", @@ -13107,6 +14147,16 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index d6f214f72..f191d35cc 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,11 @@ "cli": "node ./packages/git-proxy-cli/index.js", "client": "vite --config vite.config.js", "clientinstall": "npm install --prefix client", - "server": "node index.js", + "server": "tsx index.ts", "start": "concurrently \"npm run server\" \"npm run client\"", "build": "vite build", - "test": "NODE_ENV=test mocha './test/**/*.js' --exit", + "build-ts": "tsc", + "test": "NODE_ENV=test ts-mocha './test/*.js' --exit; mocha './test/plugin/*.js' --exit", "test-coverage": "nyc npm run test", "test-coverage-ci": "nyc --reporter=lcovonly --reporter=text npm run test", "prepare": "node ./scripts/prepare.js", @@ -80,6 +81,12 @@ "@babel/preset-react": "^7.22.5", "@commitlint/cli": "^19.0.0", "@commitlint/config-conventional": "^19.0.0", + "@types/lodash": "^4.17.15", + "@types/mocha": "^10.0.10", + "@types/node": "^22.13.5", + "@types/yargs": "^17.0.33", + "@typescript-eslint/eslint-plugin": "^8.26.1", + "@typescript-eslint/parser": "^8.26.1", "@vitejs/plugin-react": "^4.0.2", "chai": "^4.2.0", "chai-http": "^4.3.0", @@ -92,11 +99,16 @@ "eslint-plugin-react": "^7.21.5", "eslint-plugin-standard": "^5.0.0", "husky": "^9.0.0", - "mocha": "^10.2.0", + "mocha": "^10.8.2", "nyc": "^17.0.0", "prettier": "^3.0.0", "sinon": "^19.0.2", - "vite": "^4.4.2" + "ts-mocha": "^11.1.0", + "ts-node": "^10.9.2", + "tsx": "^4.19.3", + "typescript": "^5.7.3", + "vite": "4.5.5", + "vite-tsconfig-paths": "^5.1.4" }, "optionalDependencies": { "@esbuild/darwin-arm64": "^0.18.20", diff --git a/packages/git-proxy-cli/index.js b/packages/git-proxy-cli/index.js index e3c69ce8d..b4bb24e8e 100755 --- a/packages/git-proxy-cli/index.js +++ b/packages/git-proxy-cli/index.js @@ -307,7 +307,7 @@ async function logout() { } // Parsing command line arguments -yargs(hideBin(process.argv)) +yargs(hideBin(process.argv)) // eslint-disable-line @typescript-eslint/no-unused-expressions .command({ command: 'authorise', describe: 'Authorise git push by ID', @@ -339,7 +339,7 @@ yargs(hideBin(process.argv)) .command({ command: 'config', describe: 'Print configuration', - handler(argv) { + handler() { console.log(`GitProxy URL: ${baseUrl}`); }, }) @@ -365,7 +365,7 @@ yargs(hideBin(process.argv)) .command({ command: 'logout', describe: 'Log out', - handler(argv) { + handler() { logout(); }, }) diff --git a/packages/git-proxy-cli/package.json b/packages/git-proxy-cli/package.json index c2bcf6ef4..baade725c 100644 --- a/packages/git-proxy-cli/package.json +++ b/packages/git-proxy-cli/package.json @@ -13,7 +13,7 @@ }, "scripts": { "lint": "eslint --fix . --ext .js,.jsx", - "test": "NODE_ENV=test mocha --exit --timeout 10000", + "test": "NODE_ENV=test ts-mocha --exit --timeout 10000", "test-coverage": "nyc npm run test", "test-coverage-ci": "nyc --reporter=lcovonly --reporter=text --reporter=html npm run test" }, diff --git a/packages/git-proxy-cli/tsconfig.json b/packages/git-proxy-cli/tsconfig.json new file mode 100644 index 000000000..236bfabc5 --- /dev/null +++ b/packages/git-proxy-cli/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES6", + "lib": ["DOM", "ESNext"], + "allowJs": true, + "checkJs": false, + "jsx": "react-jsx", + "moduleResolution": "Node", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "isolatedModules": true, + "module": "CommonJS", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "include": ["index.js", "test", "coverage"] +} diff --git a/src/db/file/index.js b/src/db/file/index.js deleted file mode 100644 index 03dd8ecf0..000000000 --- a/src/db/file/index.js +++ /dev/null @@ -1,30 +0,0 @@ -const pushes = require('./pushes'); -const users = require('./users'); -const repo = require('./repo'); - -module.exports.getPushes = pushes.getPushes; -module.exports.writeAudit = pushes.writeAudit; -module.exports.getPush = pushes.getPush; -module.exports.authorise = pushes.authorise; -module.exports.cancel = pushes.cancel; -module.exports.reject = pushes.reject; -module.exports.canUserCancelPush = pushes.canUserCancelPush; -module.exports.canUserApproveRejectPush = pushes.canUserApproveRejectPush; - -module.exports.findUser = users.findUser; -module.exports.findUserByOIDC = users.findUserByOIDC; -module.exports.getUsers = users.getUsers; -module.exports.createUser = users.createUser; -module.exports.deleteUser = users.deleteUser; -module.exports.updateUser = users.updateUser; - -module.exports.getRepos = repo.getRepos; -module.exports.getRepo = repo.getRepo; -module.exports.createRepo = repo.createRepo; -module.exports.addUserCanPush = repo.addUserCanPush; -module.exports.addUserCanAuthorise = repo.addUserCanAuthorise; -module.exports.removeUserCanPush = repo.removeUserCanPush; -module.exports.removeUserCanAuthorise = repo.removeUserCanAuthorise; -module.exports.deleteRepo = repo.deleteRepo; -module.exports.isUserPushAllowed = repo.isUserPushAllowed; -module.exports.canUserApproveRejectPushRepo = repo.canUserApproveRejectPushRepo; diff --git a/src/db/file/index.ts b/src/db/file/index.ts new file mode 100644 index 000000000..a31610173 --- /dev/null +++ b/src/db/file/index.ts @@ -0,0 +1,36 @@ +import * as users from './users'; +import * as repo from './repo'; +import * as pushes from './pushes'; + +export const { + getPushes, + writeAudit, + getPush, + authorise, + cancel, + reject, + canUserCancelPush, + canUserApproveRejectPush, +} = pushes; + +export const { + getRepos, + getRepo, + createRepo, + addUserCanPush, + addUserCanAuthorise, + removeUserCanPush, + removeUserCanAuthorise, + deleteRepo, + isUserPushAllowed, + canUserApproveRejectPushRepo, +} = repo; + +export const { + findUser, + findUserByOIDC, + getUsers, + createUser, + deleteUser, + updateUser, +} = users; diff --git a/src/db/file/pushes.js b/src/db/file/pushes.ts similarity index 57% rename from src/db/file/pushes.js rename to src/db/file/pushes.ts index cbc79244a..6a0866910 100644 --- a/src/db/file/pushes.js +++ b/src/db/file/pushes.ts @@ -1,26 +1,27 @@ -const fs = require('fs'); -const _ = require('lodash'); -const Datastore = require('@seald-io/nedb'); -const Action = require('../../proxy/actions/Action').Action; -const toClass = require('../helper').toClass; -const repo = require('./repo'); +import fs from 'fs'; +import _ from 'lodash'; +import Datastore from '@seald-io/nedb'; +import { Action } from '../../proxy/actions/Action'; +import { toClass } from '../helper'; +import * as repo from './repo'; +import { PushQuery } from '../types' if (!fs.existsSync('./.data')) fs.mkdirSync('./.data'); if (!fs.existsSync('./.data/db')) fs.mkdirSync('./.data/db'); const db = new Datastore({ filename: './.data/db/pushes.db', autoload: true }); -const defaultPushQuery = { +const defaultPushQuery: PushQuery = { error: false, blocked: true, allowPush: false, authorised: false, }; -const getPushes = (query, logger) => { +export const getPushes = (query: PushQuery) => { if (!query) query = defaultPushQuery; return new Promise((resolve, reject) => { - db.find(query, (err, docs) => { + db.find(query, (err: Error, docs: Action[]) => { if (err) { reject(err); } else { @@ -34,8 +35,8 @@ const getPushes = (query, logger) => { }); }; -const getPush = async (id, logger) => { - return new Promise((resolve, reject) => { +export const getPush = async (id: string) => { + return new Promise((resolve, reject) => { db.findOne({ id: id }, (err, doc) => { if (err) { reject(err); @@ -50,7 +51,7 @@ const getPush = async (id, logger) => { }); }; -const writeAudit = async (action, logger) => { +export const writeAudit = async (action: Action) => { return new Promise((resolve, reject) => { const options = { multi: false, upsert: true }; db.update({ id: action.id }, action, options, (err) => { @@ -63,8 +64,12 @@ const writeAudit = async (action, logger) => { }); }; -const authorise = async (id, attestation) => { +export const authorise = async (id: string, attestation: any) => { const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + action.authorised = true; action.canceled = false; action.rejected = false; @@ -73,8 +78,12 @@ const authorise = async (id, attestation) => { return { message: `authorised ${id}` }; }; -const reject = async (id, logger) => { - const action = await getPush(id, logger); +export const reject = async (id: string) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + action.authorised = false; action.canceled = false; action.rejected = true; @@ -82,8 +91,11 @@ const reject = async (id, logger) => { return { message: `reject ${id}` }; }; -const cancel = async (id, logger) => { - const action = await getPush(id, logger); +export const cancel = async (id: string) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } action.authorised = false; action.canceled = true; action.rejected = false; @@ -91,10 +103,14 @@ const cancel = async (id, logger) => { return { message: `cancel ${id}` }; }; -const canUserCancelPush = async (id, user) => { - return new Promise(async (resolve) => { +export const canUserCancelPush = async (id: string, user: any) => { + return new Promise(async (resolve) => { const pushDetail = await getPush(id); - const repoName = pushDetail.repoName.replace('.git', ''); + if (!pushDetail) { + resolve(false); + } + + const repoName = pushDetail?.repoName.replace('.git', ''); const isAllowed = await repo.isUserPushAllowed(repoName, user); if (isAllowed) { @@ -105,21 +121,15 @@ const canUserCancelPush = async (id, user) => { }); }; -const canUserApproveRejectPush = async (id, user) => { - return new Promise(async (resolve) => { +export const canUserApproveRejectPush = async (id: string, user: any) => { + return new Promise(async (resolve) => { const action = await getPush(id); - const repoName = action.repoName.replace('.git', ''); + if (!action) { + resolve(false); + } + const repoName = action?.repoName.replace('.git', ''); const isAllowed = await repo.canUserApproveRejectPushRepo(repoName, user); resolve(isAllowed); }); }; - -module.exports.getPushes = getPushes; -module.exports.writeAudit = writeAudit; -module.exports.getPush = getPush; -module.exports.authorise = authorise; -module.exports.reject = reject; -module.exports.cancel = cancel; -module.exports.canUserCancelPush = canUserCancelPush; -module.exports.canUserApproveRejectPush = canUserApproveRejectPush; diff --git a/src/db/file/repo.js b/src/db/file/repo.ts similarity index 61% rename from src/db/file/repo.js rename to src/db/file/repo.ts index e6f7dd894..06f97de40 100644 --- a/src/db/file/repo.js +++ b/src/db/file/repo.ts @@ -1,14 +1,15 @@ -const fs = require('fs'); -const Datastore = require('@seald-io/nedb'); +import fs from 'fs'; +import Datastore from '@seald-io/nedb' +import { Repo } from '../types'; if (!fs.existsSync('./.data')) fs.mkdirSync('./.data'); if (!fs.existsSync('./.data/db')) fs.mkdirSync('./.data/db'); const db = new Datastore({ filename: './.data/db/repos.db', autoload: true }); -exports.getRepos = async (query = {}) => { - return new Promise((resolve, reject) => { - db.find({}, (err, docs) => { +export const getRepos = async () => { + return new Promise((resolve, reject) => { + db.find({}, (err: Error, docs: Repo[]) => { if (err) { reject(err); } else { @@ -18,29 +19,26 @@ exports.getRepos = async (query = {}) => { }); }; -exports.getRepo = async (name) => { - return new Promise((resolve, reject) => { - db.findOne({ name: name }, (err, doc) => { +export const getRepo = async (name: string) => { + return new Promise((resolve, reject) => { + db.findOne({ name }, (err: Error | null, doc: Repo) => { if (err) { reject(err); } else { - if (!doc) { - resolve(null); - } else { - resolve(doc); - } + resolve(doc); } }); }); }; -exports.createRepo = async (repo) => { + +export const createRepo = async (repo: Repo) => { repo.users = { canPush: [], canAuthorise: [], }; - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { db.insert(repo, (err, doc) => { if (err) { reject(err); @@ -51,9 +49,13 @@ exports.createRepo = async (repo) => { }); }; -exports.addUserCanPush = async (name, user) => { +export const addUserCanPush = async (name: string, user: string) => { return new Promise(async (resolve, reject) => { - const repo = await exports.getRepo(name); + const repo = await getRepo(name); + if (!repo) { + reject(new Error('Repo not found')); + return; + } if (repo.users.canPush.includes(user)) { resolve(null); @@ -72,9 +74,13 @@ exports.addUserCanPush = async (name, user) => { }); }; -exports.addUserCanAuthorise = async (name, user) => { +export const addUserCanAuthorise = async (name: string, user: string) => { return new Promise(async (resolve, reject) => { - const repo = await exports.getRepo(name); + const repo = await getRepo(name); + if (!repo) { + reject(new Error('Repo not found')); + return; + } if (repo.users.canAuthorise.includes(user)) { resolve(null); @@ -94,11 +100,15 @@ exports.addUserCanAuthorise = async (name, user) => { }); }; -exports.removeUserCanAuthorise = async (name, user) => { +export const removeUserCanAuthorise = async (name: string, user: string) => { return new Promise(async (resolve, reject) => { - const repo = await exports.getRepo(name); + const repo = await getRepo(name); + if (!repo) { + reject(new Error('Repo not found')); + return; + } - repo.users.canAuthorise = repo.users.canAuthorise.filter((x) => x != user); + repo.users.canAuthorise = repo.users.canAuthorise.filter((x: string) => x != user); const options = { multi: false, upsert: false }; db.update({ name: name }, repo, options, (err) => { @@ -111,9 +121,13 @@ exports.removeUserCanAuthorise = async (name, user) => { }); }; -exports.removeUserCanPush = async (name, user) => { +export const removeUserCanPush = async (name: string, user: string) => { return new Promise(async (resolve, reject) => { - const repo = await exports.getRepo(name); + const repo = await getRepo(name); + if (!repo) { + reject(new Error('Repo not found')); + return; + } repo.users.canPush = repo.users.canPush.filter((x) => x != user); @@ -128,8 +142,8 @@ exports.removeUserCanPush = async (name, user) => { }); }; -exports.deleteRepo = async (name) => { - return new Promise((resolve, reject) => { +export const deleteRepo = async (name: string) => { + return new Promise((resolve, reject) => { db.remove({ name: name }, (err) => { if (err) { reject(err); @@ -140,9 +154,9 @@ exports.deleteRepo = async (name) => { }); }; -exports.isUserPushAllowed = async (name, user) => { +export const isUserPushAllowed = async (name: string, user: string) => { name = name.toLowerCase(); - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve) => { const repo = await exports.getRepo(name); console.log(repo.users.canPush); console.log(repo.users.canAuthorise); @@ -155,10 +169,10 @@ exports.isUserPushAllowed = async (name, user) => { }); }; -exports.canUserApproveRejectPushRepo = async (name, user) => { +export const canUserApproveRejectPushRepo = async (name: string, user: string) => { name = name.toLowerCase(); console.log(`checking if user ${user} can approve/reject for ${name}`); - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve) => { const repo = await exports.getRepo(name); if (repo.users.canAuthorise.includes(user)) { console.log(`user ${user} can approve/reject to repo ${name}`); diff --git a/src/db/file/users.js b/src/db/file/users.ts similarity index 66% rename from src/db/file/users.js rename to src/db/file/users.ts index 2661006af..c702c9bd6 100644 --- a/src/db/file/users.js +++ b/src/db/file/users.ts @@ -1,14 +1,15 @@ -const fs = require('fs'); -const Datastore = require('@seald-io/nedb'); +import fs from 'fs'; +import Datastore from '@seald-io/nedb'; +import { User } from '../types'; if (!fs.existsSync('./.data')) fs.mkdirSync('./.data'); if (!fs.existsSync('./.data/db')) fs.mkdirSync('./.data/db'); const db = new Datastore({ filename: './.data/db/users.db', autoload: true }); -exports.findUser = function (username) { - return new Promise((resolve, reject) => { - db.findOne({ username: username }, (err, doc) => { +export const findUser = (username: string) => { + return new Promise((resolve, reject) => { + db.findOne({ username: username }, (err: Error | null, doc: User) => { if (err) { reject(err); } else { @@ -22,7 +23,7 @@ exports.findUser = function (username) { }); }; -exports.findUserByOIDC = function (oidcId) { +export const findUserByOIDC = function (oidcId: string) { return new Promise((resolve, reject) => { db.findOne({ oidcId: oidcId }, (err, doc) => { if (err) { @@ -38,20 +39,20 @@ exports.findUserByOIDC = function (oidcId) { }); }; -exports.createUser = function (data) { +export const createUser = function (user: User) { return new Promise((resolve, reject) => { - db.insert(data, (err) => { + db.insert(user, (err) => { if (err) { reject(err); } else { - resolve(data); + resolve(user); } }); }); }; -exports.deleteUser = function (username) { - return new Promise((resolve, reject) => { +export const deleteUser = (username: string) => { + return new Promise((resolve, reject) => { db.remove({ username: username }, (err) => { if (err) { reject(err); @@ -62,7 +63,7 @@ exports.deleteUser = function (username) { }); }; -exports.updateUser = function (user) { +export const updateUser = (user: User) => { return new Promise((resolve, reject) => { const options = { multi: false, upsert: false }; db.update({ username: user.username }, user, options, (err) => { @@ -75,10 +76,10 @@ exports.updateUser = function (user) { }); }; -exports.getUsers = function (query) { +export const getUsers = (query: any) => { if (!query) query = {}; return new Promise((resolve, reject) => { - db.find(query, (err, docs) => { + db.find(query, (err: Error, docs: User[]) => { if (err) { reject(err); } else { diff --git a/src/db/helper.js b/src/db/helper.ts similarity index 52% rename from src/db/helper.js rename to src/db/helper.ts index 8faa636e7..55c5aca0b 100644 --- a/src/db/helper.js +++ b/src/db/helper.ts @@ -1,7 +1,5 @@ -const toClass = function (obj, proto) { +export const toClass = function (obj: any, proto: any) { obj = JSON.parse(JSON.stringify(obj)); obj.__proto__ = proto; return obj; }; - -module.exports.toClass = toClass; diff --git a/src/db/index.js b/src/db/index.js deleted file mode 100644 index ed2c13524..000000000 --- a/src/db/index.js +++ /dev/null @@ -1,85 +0,0 @@ -const bcrypt = require('bcryptjs'); -const config = require('../config'); -let sink; -if (config.getDatabase().type === 'mongo') { - sink = require('../db/mongo'); -} else if (config.getDatabase().type === 'fs') { - sink = require('../db/file'); -} - -module.exports.createUser = async ( - username, - password, - email, - gitAccount, - admin = false, - oidcId = null, -) => { - console.log( - `creating user - user=${username}, - gitAccount=${gitAccount} - email=${email}, - admin=${admin} - oidcId=${oidcId}`, - ); - - const data = { - username: username, - password: oidcId ? null : await bcrypt.hash(password, 10), - gitAccount: gitAccount, - email: email, - admin: admin, - oidcId: oidcId, - }; - - if (username === undefined || username === null || username === '') { - const errorMessage = `username ${username} cannot be empty`; - throw new Error(errorMessage); - } - - if (gitAccount === undefined || gitAccount === null || gitAccount === '') { - const errorMessage = `GitAccount ${gitAccount} cannot be empty`; - throw new Error(errorMessage); - } - - if (email === undefined || email === null || email === '') { - const errorMessage = `Email ${email} cannot be empty`; - throw new Error(errorMessage); - } - const existingUser = await sink.findUser(username); - - if (existingUser) { - const errorMessage = `user ${username} already exists`; - throw new Error(errorMessage); - } - - await sink.createUser(data); -}; - -// The module exports -module.exports.authorise = sink.authorise; -module.exports.reject = sink.reject; -module.exports.cancel = sink.cancel; -module.exports.getPushes = sink.getPushes; -module.exports.writeAudit = sink.writeAudit; -module.exports.getPush = sink.getPush; -module.exports.findUser = sink.findUser; -module.exports.findUserByOIDC = sink.findUserByOIDC; -module.exports.getUsers = sink.getUsers; -module.exports.deleteUser = sink.deleteUser; -module.exports.updateUser = sink.updateUser; -module.exports.getRepos = sink.getRepos; -module.exports.getRepo = sink.getRepo; -module.exports.createRepo = sink.createRepo; -module.exports.addUserCanPush = sink.addUserCanPush; -module.exports.addUserCanAuthorise = sink.addUserCanAuthorise; -module.exports.removeUserCanAuthorise = sink.removeUserCanAuthorise; -module.exports.removeUserCanPush = sink.removeUserCanPush; - -module.exports.deleteRepo = sink.deleteRepo; -module.exports.isUserPushAllowed = sink.isUserPushAllowed; -module.exports.canUserApproveRejectPushRepo = sink.canUserApproveRejectPushRepo; -module.exports.canUserApproveRejectPush = sink.canUserApproveRejectPush; -module.exports.canUserCancelPush = sink.canUserCancelPush; -module.exports.getSessionStore = sink.getSessionStore; diff --git a/src/db/index.ts b/src/db/index.ts new file mode 100644 index 000000000..0fc681058 --- /dev/null +++ b/src/db/index.ts @@ -0,0 +1,84 @@ +const bcrypt = require('bcryptjs'); +const config = require('../config'); +let sink: any; +if (config.getDatabase().type === 'mongo') { + sink = require('./mongo'); +} else if (config.getDatabase().type === 'fs') { + sink = require('./file'); +} + +export const createUser = async ( + username: string, + password: string, + email: string, + gitAccount: string, + admin: boolean = false, + oidcId: string = '', +) => { + console.log( + `creating user + user=${username}, + gitAccount=${gitAccount} + email=${email}, + admin=${admin} + oidcId=${oidcId}`, + ); + + const data = { + username: username, + password: oidcId ? null : await bcrypt.hash(password, 10), + gitAccount: gitAccount, + email: email, + admin: admin, + }; + + if (username === undefined || username === null || username === '') { + const errorMessage = `username ${username} cannot be empty`; + throw new Error(errorMessage); + } + + if (gitAccount === undefined || gitAccount === null || gitAccount === '') { + const errorMessage = `GitAccount ${gitAccount} cannot be empty`; + throw new Error(errorMessage); + } + + if (email === undefined || email === null || email === '') { + const errorMessage = `Email ${email} cannot be empty`; + throw new Error(errorMessage); + } + const existingUser = await sink.findUser(username); + + if (existingUser) { + const errorMessage = `user ${username} already exists`; + throw new Error(errorMessage); + } + + await sink.createUser(data); +}; + +export const { + authorise, + reject, + cancel, + getPushes, + writeAudit, + getPush, + findUser, + findUserByOIDC, + getUsers, + deleteUser, + updateUser, + getRepos, + getRepo, + createRepo, + addUserCanPush, + addUserCanAuthorise, + removeUserCanAuthorise, + removeUserCanPush, + deleteRepo, + isUserPushAllowed, + canUserApproveRejectPushRepo, + canUserApproveRejectPush, + canUserCancelPush, + getSessionStore, +} = sink; diff --git a/src/db/mongo/helper.js b/src/db/mongo/helper.js deleted file mode 100644 index 116b35c08..000000000 --- a/src/db/mongo/helper.js +++ /dev/null @@ -1,26 +0,0 @@ -const mongo = require('mongodb'); -const config = require('../../config'); -const dbConfig = config.getDatabase(); -const options = dbConfig.options; -const connectionString = dbConfig.connectionString; -const MongoDBStore = require('connect-mongo'); - -let _db; - -exports.connect = async (collectionName) => { - if (!_db) { - const client = new mongo.MongoClient(connectionString, options); - await client.connect(); - _db = await client.db(); - } - - return _db.collection(collectionName); -}; - -exports.getSessionStore = (session) => { - return new MongoDBStore({ - mongoUrl: connectionString, - collectionName: 'user_session', - mongoOptions: options, - }); -}; diff --git a/src/db/mongo/helper.ts b/src/db/mongo/helper.ts new file mode 100644 index 000000000..ca5130925 --- /dev/null +++ b/src/db/mongo/helper.ts @@ -0,0 +1,45 @@ +import { MongoClient, Db, Collection, Filter, Document, FindOptions } from 'mongodb'; +import config from '../../config'; +import MongoDBStore from 'connect-mongo'; + +const dbConfig = config.getDatabase(); +const connectionString = dbConfig.connectionString; +const options = dbConfig.options; + +let _db: Db | null = null; + +export const connect = async (collectionName: string): Promise => { + if (!_db) { + const client = new MongoClient(connectionString, options); + await client.connect(); + _db = client.db(); + } + + return _db.collection(collectionName); +}; + +export const findDocuments = async ( + collectionName: string, + filter: Filter = {}, + options: FindOptions = {} +): Promise => { + const collection = await connect(collectionName); + return collection.find(filter, options).toArray() as Promise; +}; + +export const findOneDocument = async ( + collectionName: string, + filter: Filter = {}, + options: FindOptions = {} +): Promise => { + const collection = await connect(collectionName); + return (await collection.findOne(filter, options)) as T | null; +}; + +export const getSessionStore = () => { + return new MongoDBStore({ + mongoUrl: connectionString, + collectionName: 'user_session', + mongoOptions: options, + }); +}; diff --git a/src/db/mongo/index.js b/src/db/mongo/index.js deleted file mode 100644 index d8687f30c..000000000 --- a/src/db/mongo/index.js +++ /dev/null @@ -1,32 +0,0 @@ -const pushes = require('./pushes'); -const users = require('./users'); -const repo = require('./repo'); -const helper = require('./helper'); - -module.exports.getPushes = pushes.getPushes; -module.exports.writeAudit = pushes.writeAudit; -module.exports.getPush = pushes.getPush; -module.exports.authorise = pushes.authorise; -module.exports.cancel = pushes.cancel; -module.exports.reject = pushes.reject; -module.exports.canUserApproveRejectPush = pushes.canUserApproveRejectPush; -module.exports.canUserCancelPush = pushes.canUserCancelPush; - -module.exports.findUser = users.findUser; -module.exports.getUsers = users.getUsers; -module.exports.createUser = users.createUser; -module.exports.deleteUser = users.deleteUser; -module.exports.updateUser = users.updateUser; - -module.exports.getRepos = repo.getRepos; -module.exports.getRepo = repo.getRepo; -module.exports.createRepo = repo.createRepo; -module.exports.addUserCanPush = repo.addUserCanPush; -module.exports.addUserCanAuthorise = repo.addUserCanAuthorise; -module.exports.removeUserCanPush = repo.removeUserCanPush; -module.exports.removeUserCanAuthorise = repo.removeUserCanAuthorise; -module.exports.deleteRepo = repo.deleteRepo; -module.exports.isUserPushAllowed = repo.isUserPushAllowed; -module.exports.canUserApproveRejectPushRepo = repo.canUserApproveRejectPushRepo; - -module.exports.getSessionStore = helper.getSessionStore; diff --git a/src/db/mongo/index.ts b/src/db/mongo/index.ts new file mode 100644 index 000000000..11f526c2a --- /dev/null +++ b/src/db/mongo/index.ts @@ -0,0 +1,40 @@ +import * as helper from './helper'; +import * as pushes from './pushes'; +import * as repo from './repo'; +import * as users from './users'; + +export const { + getSessionStore, +} = helper; + +export const { + getPushes, + writeAudit, + getPush, + authorise, + cancel, + reject, + canUserCancelPush, + canUserApproveRejectPush, +} = pushes; + +export const { + getRepos, + getRepo, + createRepo, + addUserCanPush, + addUserCanAuthorise, + removeUserCanPush, + removeUserCanAuthorise, + deleteRepo, + isUserPushAllowed, + canUserApproveRejectPushRepo, +} = repo; + +export const { + findUser, + getUsers, + createUser, + deleteUser, + updateUser, +} = users; diff --git a/src/db/mongo/pushes.js b/src/db/mongo/pushes.js deleted file mode 100644 index f92d7ba52..000000000 --- a/src/db/mongo/pushes.js +++ /dev/null @@ -1,126 +0,0 @@ -const connect = require('./helper').connect; -const Action = require('../../proxy/actions').Action; -const toClass = require('../helper').toClass; -const repo = require('./repo'); -const cnName = 'pushes'; - -const defaultPushQuery = { - error: false, - blocked: true, - allowPush: false, - authorised: false, -}; - -const getPushes = async (query = defaultPushQuery) => { - const collection = await connect(cnName); - return collection - .find(query, { - projection: { - _id: 0, - id: 1, - allowPush: 1, - authorised: 1, - blocked: 1, - blockedMessage: 1, - branch: 1, - canceled: 1, - commitData: 1, - commitFrom: 1, - commitTo: 1, - error: 1, - method: 1, - project: 1, - rejected: 1, - repo: 1, - repoName: 1, - timepstamp: 1, - type: 1, - url: 1, - }, - }) - .toArray(); -}; - -const getPush = async (id) => { - const collection = await connect(cnName); - const doc = await collection.findOne({ id: id }); - - if (doc) { - return toClass(doc, Action.prototype); - } - - return null; -}; - -const writeAudit = async (action) => { - const data = JSON.parse(JSON.stringify(action)); - const options = { upsert: true }; - const collection = await connect(cnName); - delete data._id; - if (typeof data.id !== 'string') { - throw new Error('Invalid id'); - } - await collection.updateOne({ id: { $eq: data.id } }, { $set: data }, options); - return action; -}; - -const authorise = async (id, attestation) => { - const action = await getPush(id); - action.authorised = true; - action.canceled = false; - action.rejected = false; - action.attestation = attestation; - await writeAudit(action); - return { message: `authorised ${id}` }; -}; - -const reject = async (id) => { - const action = await getPush(id); - action.authorised = false; - action.canceled = false; - action.rejected = true; - await writeAudit(action); - return { message: `reject ${id}` }; -}; - -const cancel = async (id) => { - const action = await getPush(id); - action.authorised = false; - action.canceled = true; - action.rejected = false; - await writeAudit(action); - return { message: `canceled ${id}` }; -}; - -const canUserApproveRejectPush = async (id, user) => { - return new Promise(async (resolve) => { - const action = await getPush(id); - const repoName = action.repoName.replace('.git', ''); - const isAllowed = await repo.canUserApproveRejectPushRepo(repoName, user); - - resolve(isAllowed); - }); -}; - -const canUserCancelPush = async (id, user) => { - return new Promise(async (resolve) => { - const pushDetail = await getPush(id); - const repoName = pushDetail.repoName.replace('.git', ''); - const isAllowed = await repo.isUserPushAllowed(repoName, user); - - if (isAllowed) { - resolve(true); - } else { - resolve(false); - } - }); -}; - -module.exports.getPushes = getPushes; -module.exports.writeAudit = writeAudit; -module.exports.getPush = getPush; -module.exports.authorise = authorise; -module.exports.reject = reject; -module.exports.cancel = cancel; -module.exports.canUserApproveRejectPush = canUserApproveRejectPush; -module.exports.canUserCancelPush = canUserCancelPush; diff --git a/src/db/mongo/pushes.ts b/src/db/mongo/pushes.ts new file mode 100644 index 000000000..609db1252 --- /dev/null +++ b/src/db/mongo/pushes.ts @@ -0,0 +1,132 @@ +import { connect, findDocuments, findOneDocument } from './helper'; +import { Action } from '../../proxy/actions'; +import { toClass } from '../helper'; +import * as repo from './repo'; +import { Push, PushQuery } from '../types'; + +const collectionName = 'pushes'; + +const defaultPushQuery: PushQuery = { + error: false, + blocked: true, + allowPush: false, + authorised: false, +}; + +export const getPushes = async ( + query: PushQuery = defaultPushQuery +): Promise => { + return findDocuments(collectionName, query, { + projection: { + _id: 0, + id: 1, + allowPush: 1, + authorised: 1, + blocked: 1, + blockedMessage: 1, + branch: 1, + canceled: 1, + commitData: 1, + commitFrom: 1, + commitTo: 1, + error: 1, + method: 1, + project: 1, + rejected: 1, + repo: 1, + repoName: 1, + timepstamp: 1, + type: 1, + url: 1, + }, + }); +}; + +export const getPush = async (id: string): Promise => { + const doc = await findOneDocument(collectionName, { id }); + return doc ? toClass(doc, Action.prototype) as Action : null; +}; + +export const writeAudit = async (action: Action): Promise => { + const data = JSON.parse(JSON.stringify(action)); + const options = { upsert: true }; + const collection = await connect(collectionName); + delete data._id; + if (typeof data.id !== 'string') { + throw new Error('Invalid id'); + } + await collection.updateOne({ id: data.id }, { $set: data }, options); + return action; +}; + +export const authorise = async (id: string, attestation: any) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + + action.authorised = true; + action.canceled = false; + action.rejected = false; + action.attestation = attestation; + await writeAudit(action); + return { message: `authorised ${id}` }; +}; + +export const reject = async (id: string) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + action.authorised = false; + action.canceled = false; + action.rejected = true; + await writeAudit(action); + return { message: `reject ${id}` }; +}; + +export const cancel = async (id: string) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + action.authorised = false; + action.canceled = true; + action.rejected = false; + await writeAudit(action); + return { message: `canceled ${id}` }; +}; + +export const canUserApproveRejectPush = async (id: string, user: string) => { + return new Promise(async (resolve) => { + const action = await getPush(id); + if (!action) { + resolve(false); + return; + } + + const repoName = action.repoName.replace('.git', ''); + const isAllowed = await repo.canUserApproveRejectPushRepo(repoName, user); + + resolve(isAllowed); + }); +}; + +export const canUserCancelPush = async (id: string, user: string) => { + return new Promise(async (resolve) => { + const pushDetail = await getPush(id); + if (!pushDetail) { + resolve(false); + return; + } + + const repoName = pushDetail.repoName.replace('.git', ''); + const isAllowed = await repo.isUserPushAllowed(repoName, user); + + if (isAllowed) { + resolve(true); + } else { + resolve(false); + } + }); +}; diff --git a/src/db/mongo/repo.js b/src/db/mongo/repo.ts similarity index 60% rename from src/db/mongo/repo.js rename to src/db/mongo/repo.ts index 1c604069e..edfecea57 100644 --- a/src/db/mongo/repo.js +++ b/src/db/mongo/repo.ts @@ -1,21 +1,23 @@ +import { Repo } from "../types"; + const connect = require('./helper').connect; -const cnName = 'repos'; +const collectionName = 'repos'; -const isBlank = (str) => { +const isBlank = (str: string) => { return !str || /^\s*$/.test(str); }; -exports.getRepos = async (query = {}) => { - const collection = await connect(cnName); +export const getRepos = async () => { + const collection = await connect(collectionName); return collection.find().toArray(); }; -exports.getRepo = async (name) => { - const collection = await connect(cnName); +export const getRepo = async (name: string) => { + const collection = await connect(collectionName); return collection.findOne({ name: { $eq: name } }); }; -exports.createRepo = async (repo) => { +export const createRepo = async (repo: Repo) => { console.log(`creating new repo ${JSON.stringify(repo)}`); if (isBlank(repo.project)) { @@ -33,43 +35,43 @@ exports.createRepo = async (repo) => { canAuthorise: [], }; - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.insertOne(repo); console.log(`created new repo ${JSON.stringify(repo)}`); }; -exports.addUserCanPush = async (name, user) => { +export const addUserCanPush = async (name: string, user: string) => { name = name.toLowerCase(); - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.updateOne({ name: name }, { $push: { 'users.canPush': user } }); }; -exports.addUserCanAuthorise = async (name, user) => { +export const addUserCanAuthorise = async (name: string, user: string) => { name = name.toLowerCase(); - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.updateOne({ name: name }, { $push: { 'users.canAuthorise': user } }); }; -exports.removeUserCanPush = async (name, user) => { +export const removeUserCanPush = async (name: string, user: string) => { name = name.toLowerCase(); - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.updateOne({ name: name }, { $pull: { 'users.canPush': user } }); }; -exports.removeUserCanAuthorise = async (name, user) => { +export const removeUserCanAuthorise = async (name: string, user: string) => { name = name.toLowerCase(); - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.updateOne({ name: name }, { $pull: { 'users.canAuthorise': user } }); }; -exports.deleteRepo = async (name) => { - const collection = await connect(cnName); +export const deleteRepo = async (name: string) => { + const collection = await connect(collectionName); await collection.deleteMany({ name: name }); }; -exports.isUserPushAllowed = async (name, user) => { +export const isUserPushAllowed = async (name: string, user: string) => { name = name.toLowerCase(); - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve) => { const repo = await exports.getRepo(name); console.log(repo.users.canPush); console.log(repo.users.canAuthorise); @@ -82,10 +84,10 @@ exports.isUserPushAllowed = async (name, user) => { }); }; -exports.canUserApproveRejectPushRepo = async (name, user) => { +export const canUserApproveRejectPushRepo = async (name: string, user: string) => { name = name.toLowerCase(); console.log(`checking if user ${user} can approve/reject for ${name}`); - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve) => { const repo = await exports.getRepo(name); if (repo.users.canAuthorise.includes(user)) { console.log(`user ${user} can approve/reject to repo ${name}`); diff --git a/src/db/mongo/users.js b/src/db/mongo/users.js deleted file mode 100644 index c93977694..000000000 --- a/src/db/mongo/users.js +++ /dev/null @@ -1,31 +0,0 @@ -const connect = require('./helper').connect; -const usersCollection = 'users'; - -exports.findUser = async function (username) { - const collection = await connect(usersCollection); - return collection.findOne({ username: { $eq: username } }); -}; - -exports.getUsers = async function (query) { - console.log(`Getting users for query= ${JSON.stringify(query)}`); - const collection = await connect(usersCollection); - return collection.find(query, { password: 0 }).toArray(); -}; - -exports.deleteUser = async function (username) { - const collection = await connect(usersCollection); - return collection.deleteOne({ username: username }); -}; - -exports.createUser = async function (data) { - data.username = data.username.toLowerCase(); - const collection = await connect(usersCollection); - return collection.insertOne(data); -}; - -exports.updateUser = async (user) => { - user.username = user.username.toLowerCase(); - const options = { upsert: true }; - const collection = await connect(usersCollection); - await collection.updateOne({ username: user.username }, { $set: user }, options); -}; diff --git a/src/db/mongo/users.ts b/src/db/mongo/users.ts new file mode 100644 index 000000000..388527777 --- /dev/null +++ b/src/db/mongo/users.ts @@ -0,0 +1,33 @@ +import { User } from "../types"; + +const connect = require('./helper').connect; +const collectionName = 'users'; + +export const findUser = async function (username: string) { + const collection = await connect(collectionName); + return collection.findOne({ username: { $eq: username } }); +}; + +export const getUsers = async function (query: string) { + console.log(`Getting users for query= ${JSON.stringify(query)}`); + const collection = await connect(collectionName); + return collection.find(query, { password: 0 }).toArray(); +}; + +export const deleteUser = async function (username: string) { + const collection = await connect(collectionName); + return collection.deleteOne({ username: username }); +}; + +export const createUser = async function (user: User) { + user.username = user.username.toLowerCase(); + const collection = await connect(collectionName); + return collection.insertOne(user); +}; + +export const updateUser = async (user: User) => { + user.username = user.username.toLowerCase(); + const options = { upsert: true }; + const collection = await connect(collectionName); + await collection.updateOne({ username: user.username }, { $set: user }, options); +}; diff --git a/src/db/types.ts b/src/db/types.ts new file mode 100644 index 000000000..dba9bdf3a --- /dev/null +++ b/src/db/types.ts @@ -0,0 +1,48 @@ +export type PushQuery = { + error: boolean; + blocked: boolean, + allowPush: boolean, + authorised: boolean +}; + +export type UserRole = 'canPush' | 'canAuthorise'; + +export type Repo = { + project: string; + name: string; + url: string; + users: Record; + _id: string; +}; + +export type User = { + _id: string; + username: string; + password: string | null; // null if oidcId is set + gitAccount: string; + email: string; + admin: boolean; + oidcId: string | null; +}; + +export type Push = { + id: string; + allowPush: boolean; + authorised: boolean; + blocked: boolean; + blockedMessage: string; + branch: string; + canceled: boolean; + commitData: object; + commitFrom: string; + commitTo: string; + error: boolean; + method: string; + project: string; + rejected: boolean; + repo: string; + repoName: string; + timepstamp: string; + type: string; + url: string; +}; diff --git a/src/plugin.js b/src/plugin.js index b02e3bb8e..2f78e5f05 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -1,4 +1,5 @@ const lpModule = import('load-plugin'); +/* eslint-disable @typescript-eslint/no-unused-expressions */ ('use strict'); /** diff --git a/src/proxy/actions/Action.js b/src/proxy/actions/Action.js index 50b0e8fa8..ca8096351 100644 --- a/src/proxy/actions/Action.js +++ b/src/proxy/actions/Action.js @@ -62,10 +62,9 @@ class Action { /** * - * @param {*} step * @return {Step} */ - getLastStep(step) { + getLastStep() { return this.lastStep; } diff --git a/src/proxy/routes/index.js b/src/proxy/routes/index.js index 1ef84bcb5..4c329f9f7 100644 --- a/src/proxy/routes/index.js +++ b/src/proxy/routes/index.js @@ -106,7 +106,7 @@ router.use( console.log('Sending request to ' + url); return url; }, - proxyReqOptDecorator: function (proxyReqOpts, srcReq) { + proxyReqOptDecorator: function (proxyReqOpts) { return proxyReqOpts; }, diff --git a/src/service/routes/auth.js b/src/service/routes/auth.js index e433d7ad8..92cd82e39 100644 --- a/src/service/routes/auth.js +++ b/src/service/routes/auth.js @@ -122,7 +122,7 @@ router.post('/gitAccount', async (req, res) => { user.gitAccount = req.body.gitAccount; db.updateUser(user); res.status(200).end(); - } catch (e) { + } catch { res .status(500) .send({ diff --git a/src/ui/components/Footer/Footer.jsx b/src/ui/components/Footer/Footer.jsx index 951abde8c..7cd9933f0 100644 --- a/src/ui/components/Footer/Footer.jsx +++ b/src/ui/components/Footer/Footer.jsx @@ -7,7 +7,7 @@ import { MarkGithubIcon } from '@primer/octicons-react'; const useStyles = makeStyles(styles); -export default function Footer(props) { +export default function Footer() { const classes = useStyles(); return (