diff --git a/.gitignore b/.gitignore index 104d867..0f9772e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ pnpm-debug.log* # Dependencies node_modules +**/__pycache__/ .pnp .pnp.js @@ -38,3 +39,4 @@ coverage .env.* /src/generated/prisma +.npmrc \ No newline at end of file diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 9e09b04..0000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -@coveritlabs:registry=https://npm.pkg.github.com diff --git a/Dockerfile b/Dockerfile index 8cc148a..1551319 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,7 @@ FROM node:22-alpine AS build WORKDIR /app COPY package.json package-lock.json ./ +COPY vendor ./vendor RUN --mount=type=secret,id=npm_token \ printf "@coveritlabs:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=$(cat /run/secrets/npm_token)\n" > .npmrc \ && npm ci --ignore-scripts \ @@ -25,6 +26,7 @@ WORKDIR /app ENV NODE_ENV=production COPY package.json package-lock.json ./ +COPY vendor ./vendor RUN --mount=type=secret,id=npm_token \ printf "@coveritlabs:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=$(cat /run/secrets/npm_token)\n" > .npmrc \ && npm ci --ignore-scripts --omit=dev \ diff --git a/Dockerfile.dev b/Dockerfile.dev index 81aa40e..d7c3f3f 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -5,6 +5,7 @@ WORKDIR /app # Install dependencies (including devDependencies) COPY package.json package-lock.json ./ +COPY vendor ./vendor RUN --mount=type=secret,id=npm_token \ printf "@coveritlabs:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=$(cat /run/secrets/npm_token)\n" > .npmrc \ && npm ci --ignore-scripts \ diff --git a/docker-compose.yml b/docker-compose.yml index 168caac..29d371a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -43,10 +43,11 @@ services: condition: service_healthy redis: condition: service_healthy - db: image: postgres:18 container_name: coverit-postgres + ports: + - "5432:5432" environment: - POSTGRES_USER=${DB_USER:-postgres} - POSTGRES_PASSWORD=${DB_PASSWORD:-postgres} diff --git a/jest.config.js b/jest.config.js index edb0be9..dfea438 100644 --- a/jest.config.js +++ b/jest.config.js @@ -16,6 +16,7 @@ module.exports = { '^@lib/(.*)$': '/src/lib/$1', '^@services/(.*)$': '/src/services/$1', '^@utils/(.*)$': '/src/utils/$1', + '^@mappers/(.*)$': '/src/mappers/$1', '^@models/(.*)$': '/src/models/$1', '^@constants/(.*)$': '/src/constants/$1', '^@generated/(.*)$': '/src/generated/$1', diff --git a/package-lock.json b/package-lock.json index 64b154f..32e2578 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@asteasolutions/zod-to-openapi": "^8.4.3", "@bufbuild/protobuf": "^2.11.0", - "@coveritlabs/contracts": "^1.3.1", + "@coveritlabs/contracts": "file:vendor/coveritlabs-contracts-1.6.1.tgz", "@prisma/adapter-pg": "^7.4.2", "@prisma/client": "^7.4.2", "argon2": "^0.44.0", @@ -108,9 +108,9 @@ } }, "node_modules/@asteasolutions/zod-to-openapi": { - "version": "8.4.3", - "resolved": "https://registry.npmjs.org/@asteasolutions/zod-to-openapi/-/zod-to-openapi-8.4.3.tgz", - "integrity": "sha512-lwfMTN7kDbFDwMniYZUebiGGHxVGBw9ZSI4IBYjm6Ey22Kd5z/fsQb2k+Okr8WMbCCC553vi/ZM9utl5/XcvuQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@asteasolutions/zod-to-openapi/-/zod-to-openapi-8.5.0.tgz", + "integrity": "sha512-SABbKiObg5dLRiTFnqiW1WWwGcg1BJfmHtT2asIBnBHg6Smy/Ms2KHc650+JI4Hw7lSkdiNebEGXpwoxfben8Q==", "license": "MIT", "dependencies": { "openapi3-ts": "^4.1.2" @@ -150,7 +150,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -313,23 +312,23 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "license": "MIT", "dependencies": { @@ -642,51 +641,18 @@ "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==", "license": "(Apache-2.0 AND BSD-3-Clause)" }, - "node_modules/@chevrotain/cst-dts-gen": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.5.0.tgz", - "integrity": "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/gast": "10.5.0", - "@chevrotain/types": "10.5.0", - "lodash": "4.17.21" - } - }, - "node_modules/@chevrotain/gast": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.5.0.tgz", - "integrity": "sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/types": "10.5.0", - "lodash": "4.17.21" - } - }, - "node_modules/@chevrotain/types": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.5.0.tgz", - "integrity": "sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==", - "license": "Apache-2.0" - }, - "node_modules/@chevrotain/utils": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.5.0.tgz", - "integrity": "sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==", - "license": "Apache-2.0" - }, "node_modules/@commitlint/cli": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.4.4.tgz", - "integrity": "sha512-GLMNQHYGcn0ohL2HMlAnXcD1PS2vqBBGbYKlhrRPOYsWiRoLWtrewsR3uKRb9v/IdS+qOS0vqJQ64n1g8VPKFw==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.0.tgz", + "integrity": "sha512-yNkyN/tuKTJS3wdVfsZ2tXDM4G4Gi7z+jW54Cki8N8tZqwKBltbIvUUrSbT4hz1bhW/h0CdR+5sCSpXD+wMKaQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/format": "^20.4.4", - "@commitlint/lint": "^20.4.4", - "@commitlint/load": "^20.4.4", - "@commitlint/read": "^20.4.4", - "@commitlint/types": "^20.4.4", + "@commitlint/format": "^20.5.0", + "@commitlint/lint": "^20.5.0", + "@commitlint/load": "^20.5.0", + "@commitlint/read": "^20.5.0", + "@commitlint/types": "^20.5.0", "tinyexec": "^1.0.0", "yargs": "^17.0.0" }, @@ -698,13 +664,13 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.4.4.tgz", - "integrity": "sha512-Usg+XXbPNG2GtFWTgRURNWCge1iH1y6jQIvvklOdAbyn2t8ajfVwZCnf5t5X4gUsy17BOiY+myszGsSMIvhOVA==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.5.0.tgz", + "integrity": "sha512-t3Ni88rFw1XMa4nZHgOKJ8fIAT9M2j5TnKyTqJzsxea7FUetlNdYFus9dz+MhIRZmc16P0PPyEfh6X2d/qw8SA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.4", + "@commitlint/types": "^20.5.0", "conventional-changelog-conventionalcommits": "^9.2.0" }, "engines": { @@ -712,13 +678,13 @@ } }, "node_modules/@commitlint/config-validator": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.4.4.tgz", - "integrity": "sha512-K8hMS9PTLl7EYe5vWtSFQ/sgsV2PHUOtEnosg8k3ZQxCyfKD34I4C7FxWEfRTR54rFKeUYmM3pmRQqBNQeLdlw==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.5.0.tgz", + "integrity": "sha512-T/Uh6iJUzyx7j35GmHWdIiGRQB+ouZDk0pwAaYq4SXgB54KZhFdJ0vYmxiW6AMYICTIWuyMxDBl1jK74oFp/Gw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.4", + "@commitlint/types": "^20.5.0", "ajv": "^8.11.0" }, "engines": { @@ -726,15 +692,15 @@ } }, "node_modules/@commitlint/cz-commitlint": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/cz-commitlint/-/cz-commitlint-20.4.4.tgz", - "integrity": "sha512-dQuLSHrLbeLx/7JI0bCeYI2sWmmEs8rCUwIZu0d6p9C4OjnjPcLxQOBRaFwiqXGrjr1Dctb2dIzNtymt06vTQA==", + "version": "20.5.1", + "resolved": "https://registry.npmjs.org/@commitlint/cz-commitlint/-/cz-commitlint-20.5.1.tgz", + "integrity": "sha512-tvcHpk/DQRF749PuaYKPeLhml4grD4h8qEIW5uoboKy0tfnJxmAy99xOo2U1xpQj5uo3LH7pjnVv1xvuhzLWRw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/ensure": "^20.4.4", - "@commitlint/load": "^20.4.4", - "@commitlint/types": "^20.4.4", + "@commitlint/ensure": "^20.5.0", + "@commitlint/load": "^20.5.0", + "@commitlint/types": "^20.5.0", "is-plain-obj": "^4.1.0", "picocolors": "^1.1.1", "word-wrap": "^1.2.5" @@ -748,13 +714,13 @@ } }, "node_modules/@commitlint/ensure": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.4.4.tgz", - "integrity": "sha512-QivV0M1MGL867XCaF+jJkbVXEPKBALhUUXdjae66hes95aY1p3vBJdrcl3x8jDv2pdKWvIYIz+7DFRV/v0dRkA==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.5.0.tgz", + "integrity": "sha512-IpHqAUesBeW1EDDdjzJeaOxU9tnogLAyXLRBn03SHlj1SGENn2JGZqSWGkFvBJkJzfXAuCNtsoYzax+ZPS+puw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.4", + "@commitlint/types": "^20.5.0", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", @@ -776,13 +742,13 @@ } }, "node_modules/@commitlint/format": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.4.4.tgz", - "integrity": "sha512-jLi/JBA4GEQxc5135VYCnkShcm1/rarbXMn2Tlt3Si7DHiiNKHm4TaiJCLnGbZ1r8UfwDRk+qrzZ80kwh08Aow==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.5.0.tgz", + "integrity": "sha512-TI9EwFU/qZWSK7a5qyXMpKPPv3qta7FO4tKW+Wt2al7sgMbLWTsAcDpX1cU8k16TRdsiiet9aOw0zpvRXNJu7Q==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.4", + "@commitlint/types": "^20.5.0", "picocolors": "^1.1.1" }, "engines": { @@ -790,13 +756,13 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.4.4.tgz", - "integrity": "sha512-y76rT8yq02x+pMDBI2vY4y/ByAwmJTkta/pASbgo8tldBiKLduX8/2NCRTSCjb3SumE5FBeopERKx3oMIm8RTQ==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.5.0.tgz", + "integrity": "sha512-JWLarAsurHJhPozbuAH6GbP4p/hdOCoqS9zJMfqwswne+/GPs5V0+rrsfOkP68Y8PSLphwtFXV0EzJ+GTXTTGg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.4", + "@commitlint/types": "^20.5.0", "semver": "^7.6.0" }, "engines": { @@ -804,32 +770,32 @@ } }, "node_modules/@commitlint/lint": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.4.4.tgz", - "integrity": "sha512-svOEW+RptcNpXKE7UllcAsV0HDIdOck9reC2TP1QA6K5Fo0xxQV+QPjV8Zqx9g6X/hQBkF2S9ZQZ78Xrv1Eiog==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.5.0.tgz", + "integrity": "sha512-jiM3hNUdu04jFBf1VgPdjtIPvbuVfDTBAc6L98AWcoLjF5sYqkulBHBzlVWll4rMF1T5zeQFB6r//a+s+BBKlA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/is-ignored": "^20.4.4", - "@commitlint/parse": "^20.4.4", - "@commitlint/rules": "^20.4.4", - "@commitlint/types": "^20.4.4" + "@commitlint/is-ignored": "^20.5.0", + "@commitlint/parse": "^20.5.0", + "@commitlint/rules": "^20.5.0", + "@commitlint/types": "^20.5.0" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/load": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.4.4.tgz", - "integrity": "sha512-kvFrzvoIACa/fMjXEP0LNEJB1joaH3q3oeMJsLajXE5IXjYrNGVcW1ZFojXUruVJ7odTZbC3LdE/6+ONW4f2Dg==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.5.0.tgz", + "integrity": "sha512-sLhhYTL/KxeOTZjjabKDhwidGZan84XKK1+XFkwDYL/4883kIajcz/dZFAhBJmZPtL8+nBx6bnkzA95YxPeDPw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^20.4.4", + "@commitlint/config-validator": "^20.5.0", "@commitlint/execute-rule": "^20.0.0", - "@commitlint/resolve-extends": "^20.4.4", - "@commitlint/types": "^20.4.4", + "@commitlint/resolve-extends": "^20.5.0", + "@commitlint/types": "^20.5.0", "cosmiconfig": "^9.0.1", "cosmiconfig-typescript-loader": "^6.1.0", "is-plain-obj": "^4.1.0", @@ -851,13 +817,13 @@ } }, "node_modules/@commitlint/parse": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.4.4.tgz", - "integrity": "sha512-AjfgOgrjEozeQNzhFu1KL5N0nDx4JZmswVJKNfOTLTUGp6xODhZHCHqb//QUHKOzx36If5DQ7tci2o7szYxu1A==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.5.0.tgz", + "integrity": "sha512-SeKWHBMk7YOTnnEWUhx+d1a9vHsjjuo6Uo1xRfPNfeY4bdYFasCH1dDpAv13Lyn+dDPOels+jP6D2GRZqzc5fA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.4", + "@commitlint/types": "^20.5.0", "conventional-changelog-angular": "^8.2.0", "conventional-commits-parser": "^6.3.0" }, @@ -866,14 +832,14 @@ } }, "node_modules/@commitlint/read": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.4.4.tgz", - "integrity": "sha512-jvgdAQDdEY6L8kCxOo21IWoiAyNFzvrZb121wU2eBxI1DzWAUZgAq+a8LlJRbT0Qsj9INhIPVWgdaBbEzlF0dQ==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.5.0.tgz", + "integrity": "sha512-JDEIJ2+GnWpK8QqwfmW7O42h0aycJEWNqcdkJnyzLD11nf9dW2dWLTVEa8Wtlo4IZFGLPATjR5neA5QlOvIH1w==", "dev": true, "license": "MIT", "dependencies": { "@commitlint/top-level": "^20.4.3", - "@commitlint/types": "^20.4.4", + "@commitlint/types": "^20.5.0", "git-raw-commits": "^5.0.0", "minimist": "^1.2.8", "tinyexec": "^1.0.0" @@ -883,14 +849,14 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.4.4.tgz", - "integrity": "sha512-pyOf+yX3c3m/IWAn2Jop+7s0YGKPQ8YvQaxt9IQxnLIM3yZAlBdkKiQCT14TnrmZTkVGTXiLtckcnFTXYwlY0A==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.5.0.tgz", + "integrity": "sha512-3SHPWUW2v0tyspCTcfSsYml0gses92l6TlogwzvM2cbxDgmhSRc+fldDjvGkCXJrjSM87BBaWYTPWwwyASZRrg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^20.4.4", - "@commitlint/types": "^20.4.4", + "@commitlint/config-validator": "^20.5.0", + "@commitlint/types": "^20.5.0", "global-directory": "^4.0.1", "import-meta-resolve": "^4.0.0", "lodash.mergewith": "^4.6.2", @@ -901,16 +867,16 @@ } }, "node_modules/@commitlint/rules": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.4.4.tgz", - "integrity": "sha512-PmUp8QPLICn9w05dAx5r1rdOYoTk7SkfusJJh5tP3TqHwo2mlQ9jsOm8F0HSXU9kuLfgTEGNrunAx/dlK/RyPQ==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.5.0.tgz", + "integrity": "sha512-5NdQXQEdnDPT5pK8O39ZA7HohzPRHEsDGU23cyVCNPQy4WegAbAwrQk3nIu7p2sl3dutPk8RZd91yKTrMTnRkQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/ensure": "^20.4.4", + "@commitlint/ensure": "^20.5.0", "@commitlint/message": "^20.4.3", "@commitlint/to-lines": "^20.0.0", - "@commitlint/types": "^20.4.4" + "@commitlint/types": "^20.5.0" }, "engines": { "node": ">=v18" @@ -940,9 +906,9 @@ } }, "node_modules/@commitlint/types": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.4.4.tgz", - "integrity": "sha512-dwTGzyAblFXHJNBOgrTuO5Ee48ioXpS5XPRLLatxhQu149DFAHUcB3f0Q5eea3RM4USSsP1+WVT2dBtLVod4fg==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.5.0.tgz", + "integrity": "sha512-ZJoS8oSq2CAZEpc/YI9SulLrdiIyXeHb/OGqGrkUP6Q7YV+0ouNAa7GjqRdXeQPncHQIDz/jbCTlHScvYvO/gA==", "dev": true, "license": "MIT", "dependencies": { @@ -954,9 +920,9 @@ } }, "node_modules/@conventional-changelog/git-client": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.6.0.tgz", - "integrity": "sha512-T+uPDciKf0/ioNNDpMGc8FDsehJClZP0yR3Q5MN6wE/Y/1QZ7F+80OgznnTCOlMEG4AV0LvH2UJi3C/nBnaBUg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.7.0.tgz", + "integrity": "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==", "dev": true, "license": "MIT", "dependencies": { @@ -969,7 +935,7 @@ }, "peerDependencies": { "conventional-commits-filter": "^5.0.0", - "conventional-commits-parser": "^6.3.0" + "conventional-commits-parser": "^6.4.0" }, "peerDependenciesMeta": { "conventional-commits-filter": { @@ -981,16 +947,16 @@ } }, "node_modules/@coveritlabs/contracts": { - "version": "1.3.1", - "resolved": "https://npm.pkg.github.com/download/@coveritlabs/contracts/1.3.1/0f70431fbaa063e1f253869e4cdfe5416fa0910a", - "integrity": "sha512-0bq7xGkR5Rsfsz7eXPibNY6hjlhfiqejPi3WTSnl/4/pUsLgNtQ1aoEfzqNYXzcKjAsyzspsOtzlwdw/DXxiRg==", + "version": "1.6.1", + "resolved": "file:vendor/coveritlabs-contracts-1.6.1.tgz", + "integrity": "sha512-eSTN3c+rHiKoMWXJFm00RUtouILK0YIUcyXNDoX2YjzOvJluwdKL4aJ5X0o1WBySP0IcNglH3WmCMXwakSR4zQ==", "dependencies": { "@bufbuild/protobuf": "^2.5.0" } }, "node_modules/@coveritlabs/git-hooks": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/CoveritLabs/.github.git#8b96a0dc12c3084dfa9db3085840ff633965a167", + "resolved": "git+ssh://git@github.com/CoveritLabs/.github.git#a48c212fecda8290a0715c4a4c4632fb9b8a692f", "dev": true, "license": "UNLICENSED", "dependencies": { @@ -1030,49 +996,48 @@ } }, "node_modules/@electric-sql/pglite": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.3.15.tgz", - "integrity": "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==", - "license": "Apache-2.0", - "peer": true + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.1.tgz", + "integrity": "sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==", + "license": "Apache-2.0" }, "node_modules/@electric-sql/pglite-socket": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.0.20.tgz", - "integrity": "sha512-J5nLGsicnD9wJHnno9r+DGxfcZWh+YJMCe0q/aCgtG6XOm9Z7fKeite8IZSNXgZeGltSigM9U/vAWZQWdgcSFg==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.1.1.tgz", + "integrity": "sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==", "license": "Apache-2.0", "bin": { "pglite-server": "dist/scripts/server.js" }, "peerDependencies": { - "@electric-sql/pglite": "0.3.15" + "@electric-sql/pglite": "0.4.1" } }, "node_modules/@electric-sql/pglite-tools": { - "version": "0.2.20", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.2.20.tgz", - "integrity": "sha512-BK50ZnYa3IG7ztXhtgYf0Q7zijV32Iw1cYS8C+ThdQlwx12V5VZ9KRJ42y82Hyb4PkTxZQklVQA9JHyUlex33A==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.3.1.tgz", + "integrity": "sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==", "license": "Apache-2.0", "peerDependencies": { - "@electric-sql/pglite": "0.3.15" + "@electric-sql/pglite": "0.4.1" } }, "node_modules/@emnapi/core": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", - "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", - "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", "dev": true, "license": "MIT", "optional": true, @@ -1081,9 +1046,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, @@ -1279,9 +1244,9 @@ } }, "node_modules/@hono/node-server": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", + "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", "license": "MIT", "engines": { "node": ">=18.14.1" @@ -1348,6 +1313,7 @@ "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chardet": "^2.1.1", "iconv-lite": "^0.7.0" @@ -1370,6 +1336,7 @@ "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -1387,6 +1354,7 @@ "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -1995,9 +1963,9 @@ } }, "node_modules/@jest/reporters/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -2507,18 +2475,11 @@ "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", "license": "MIT" }, - "node_modules/@mrleebo/prisma-ast": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@mrleebo/prisma-ast/-/prisma-ast-0.13.1.tgz", - "integrity": "sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==", - "license": "MIT", - "dependencies": { - "chevrotain": "^10.5.0", - "lilconfig": "^2.1.0" - }, - "engines": { - "node": ">=16" - } + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { "version": "3.0.3", @@ -2712,83 +2673,24 @@ } }, "node_modules/@prisma/adapter-pg": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.5.0.tgz", - "integrity": "sha512-EJx7OLULahcC3IjJgdx2qRDNCT+ToY2v66UkeETMCLhNOTgqVzRzYvOEphY7Zp0eHyzfkC33Edd/qqeadf9R4A==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.7.0.tgz", + "integrity": "sha512-q33Ta8sKbgzEpAy0lx45tAq//yMv0qcb+8nj+TCA3P4wiAY+OBFEFk/NDkZncAfHaNJeGo5WJpJdpbL+ijYx8g==", "license": "Apache-2.0", "dependencies": { - "@prisma/driver-adapter-utils": "7.5.0", - "@types/pg": "8.11.11", + "@prisma/driver-adapter-utils": "7.7.0", + "@types/pg": "^8.16.0", "pg": "^8.16.3", "postgres-array": "3.0.4" } }, - "node_modules/@prisma/adapter-pg/node_modules/@types/pg": { - "version": "8.11.11", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.11.tgz", - "integrity": "sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^4.0.1" - } - }, - "node_modules/@prisma/adapter-pg/node_modules/pg-types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.1.0.tgz", - "integrity": "sha512-o2XFanIMy/3+mThw69O8d4n1E5zsLhdO+OPqswezu7Z5ekP4hYDqlDjlmOpYMbzY2Br0ufCwJLdDIXeNVwcWFg==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@prisma/adapter-pg/node_modules/postgres-bytea": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", - "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", - "license": "MIT", - "dependencies": { - "obuf": "~1.1.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@prisma/adapter-pg/node_modules/postgres-date": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", - "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/@prisma/adapter-pg/node_modules/postgres-interval": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", - "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, "node_modules/@prisma/client": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.5.0.tgz", - "integrity": "sha512-h4hF9ctp+kSRs7ENHGsFQmHAgHcfkOCxbYt6Ti9Xi8x7D+kP4tTi9x51UKmiTH/OqdyJAO+8V+r+JA5AWdav7w==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.7.0.tgz", + "integrity": "sha512-5Ar4OsZpJ54s21sy5oDNNW9gQtd4NuxCaiM7+JDTOU07D6VvlpLjYzAVCMB1+JzokN+08dAVomlx+b7bhJd3ww==", "license": "Apache-2.0", "dependencies": { - "@prisma/client-runtime-utils": "7.5.0" + "@prisma/client-runtime-utils": "7.7.0" }, "engines": { "node": "^20.19 || ^22.12 || >=24.0" @@ -2807,45 +2709,45 @@ } }, "node_modules/@prisma/client-runtime-utils": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.5.0.tgz", - "integrity": "sha512-KnJ2b4Si/pcWEtK68uM+h0h1oh80CZt2suhLTVuLaSKg4n58Q9jBF/A42Kw6Ma+aThy1yAhfDeTC0JvEmeZnFQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.7.0.tgz", + "integrity": "sha512-BLyd0UpFYOtyJFTHm7jS9vesHW7P83abibodQMiIofqjBKzDHQ1VAsQkdfvXyYDkPlONPfOTz7/rv3x/+CQqvQ==", "license": "Apache-2.0" }, "node_modules/@prisma/config": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.5.0.tgz", - "integrity": "sha512-1J/9YEX7A889xM46PYg9e8VAuSL1IUmXJW3tEhMv7XQHDWlfC9YSkIw9sTYRaq5GswGlxZ+GnnyiNsUZ9JJhSQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.7.0.tgz", + "integrity": "sha512-hmPI3tKLO2aP0Y5vugbjcnA9qqlfJndiT6ds4tw28U5hNHLWg+mHJEWAhjsSPgxjtmxhJ/EDIeIlyh+3Us0OPg==", "license": "Apache-2.0", "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", - "effect": "3.18.4", + "effect": "3.20.0", "empathic": "2.0.0" } }, "node_modules/@prisma/debug": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.5.0.tgz", - "integrity": "sha512-163+nffny0JoPEkDhfNco0vcuT3ymIJc9+WX7MHSQhfkeKUmKe9/wqvGk5SjppT93DtBjVwr5HPJYlXbzm6qtg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.7.0.tgz", + "integrity": "sha512-12J62XdqCmpiwJHhHdQxZeY3ckVCWIFmcJP8hg5dPTceeiQ0wiojXGFYTluKqFQfu46fRLgb/rLALZMAx3+dTA==", "license": "Apache-2.0" }, "node_modules/@prisma/dev": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.20.0.tgz", - "integrity": "sha512-ovlBYwWor0OzG+yH4J3Ot+AneD818BttLA+Ii7wjbcLHUrnC4tbUPVGyNd3c/+71KETPKZfjhkTSpdS15dmXNQ==", + "version": "0.24.3", + "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.24.3.tgz", + "integrity": "sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==", "license": "ISC", "dependencies": { - "@electric-sql/pglite": "0.3.15", - "@electric-sql/pglite-socket": "0.0.20", - "@electric-sql/pglite-tools": "0.2.20", - "@hono/node-server": "1.19.9", - "@mrleebo/prisma-ast": "0.13.1", + "@electric-sql/pglite": "0.4.1", + "@electric-sql/pglite-socket": "0.1.1", + "@electric-sql/pglite-tools": "0.3.1", + "@hono/node-server": "1.19.11", "@prisma/get-platform": "7.2.0", "@prisma/query-plan-executor": "7.2.0", + "@prisma/streams-local": "0.1.2", "foreground-child": "3.3.1", "get-port-please": "3.2.0", - "hono": "4.11.4", + "hono": "^4.12.8", "http-status-codes": "2.3.0", "pathe": "2.0.3", "proper-lockfile": "4.1.2", @@ -2856,60 +2758,60 @@ } }, "node_modules/@prisma/driver-adapter-utils": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.5.0.tgz", - "integrity": "sha512-B79N/amgV677mFesFDBAdrW0OIaqawap9E0sjgLBtzIz2R3hIMS1QB8mLZuUEiS4q5Y8Oh3I25Kw4SLxMypk9Q==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.7.0.tgz", + "integrity": "sha512-gZXREeu6mOk7zXfGFJgh86p7Vhj0sXNKp+4Cg1tWYo7V2dfncP2qxS2BiTmbIIha8xPqItkl0WSw38RuSq1HoQ==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.5.0" + "@prisma/debug": "7.7.0" } }, "node_modules/@prisma/engines": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.5.0.tgz", - "integrity": "sha512-ondGRhzoaVpRWvFaQ5wH5zS1BIbhzbKqczKjCn6j3L0Zfe/LInjcEg8+xtB49AuZBX30qyx1ZtGoootUohz2pw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.7.0.tgz", + "integrity": "sha512-7fmcbT7HHXBq/b+3h/dO1JI3fd8l8q7erf7xP7pRprh58hmSSnG8mg9K3yjW3h9WaHWUwngVFpSxxxivaitQ2w==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.5.0", - "@prisma/engines-version": "7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e", - "@prisma/fetch-engine": "7.5.0", - "@prisma/get-platform": "7.5.0" + "@prisma/debug": "7.7.0", + "@prisma/engines-version": "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711", + "@prisma/fetch-engine": "7.7.0", + "@prisma/get-platform": "7.7.0" } }, "node_modules/@prisma/engines-version": { - "version": "7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e.tgz", - "integrity": "sha512-E+iRV/vbJLl8iGjVr6g/TEWokA+gjkV/doZkaQN1i/ULVdDwGnPJDfLUIFGS3BVwlG/m6L8T4x1x5isl8hGMxA==", + "version": "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711.tgz", + "integrity": "sha512-r51DLcJ8bDRSrBEJF3J4cinoWyGA7rfP2mG6lD90VqIbGNOkbfcLcXalSVjq5Y6brQS3vcjrq4GbyUb1Cb7vkw==", "license": "Apache-2.0" }, "node_modules/@prisma/engines/node_modules/@prisma/get-platform": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.5.0.tgz", - "integrity": "sha512-7I+2y1nu/gkEKSiHHbcZ1HPe/euGdEqJZxEEMT0246q4De1+hla0ZzlTgvaT9dHcVCgLSuCG8v39db5qUUWNgw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.7.0.tgz", + "integrity": "sha512-MEUNzvKxvYnJ7kgvd6oNRnMmmiGNS9TYLB2weMeIXplnHdL/UWEGnvavYGnN7KLJ2n0iI4dDAyzSkHI3c7AscQ==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.5.0" + "@prisma/debug": "7.7.0" } }, "node_modules/@prisma/fetch-engine": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.5.0.tgz", - "integrity": "sha512-kZCl2FV54qnyrVdnII8MI6qvt7HfU6Cbiz8dZ8PXz4f4lbSw45jEB9/gEMK2SGdiNhBKyk/Wv95uthoLhGMLYA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.7.0.tgz", + "integrity": "sha512-TfyzveBQoK4xALzsTpVhB/0KG1N8zOK0ap+RnBMkzGUu3f98fnQ4QtXa2wlKPhsO2X8a3N5ugFQgcKNoHGmDfw==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.5.0", - "@prisma/engines-version": "7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e", - "@prisma/get-platform": "7.5.0" + "@prisma/debug": "7.7.0", + "@prisma/engines-version": "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711", + "@prisma/get-platform": "7.7.0" } }, "node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.5.0.tgz", - "integrity": "sha512-7I+2y1nu/gkEKSiHHbcZ1HPe/euGdEqJZxEEMT0246q4De1+hla0ZzlTgvaT9dHcVCgLSuCG8v39db5qUUWNgw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.7.0.tgz", + "integrity": "sha512-MEUNzvKxvYnJ7kgvd6oNRnMmmiGNS9TYLB2weMeIXplnHdL/UWEGnvavYGnN7KLJ2n0iI4dDAyzSkHI3c7AscQ==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.5.0" + "@prisma/debug": "7.7.0" } }, "node_modules/@prisma/get-platform": { @@ -2933,13 +2835,45 @@ "integrity": "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==", "license": "Apache-2.0" }, + "node_modules/@prisma/streams-local": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@prisma/streams-local/-/streams-local-0.1.2.tgz", + "integrity": "sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==", + "license": "Apache-2.0", + "dependencies": { + "ajv": "^8.12.0", + "better-result": "^2.7.0", + "env-paths": "^3.0.0", + "proper-lockfile": "^4.1.2" + }, + "engines": { + "bun": ">=1.3.6", + "node": ">=22.0.0" + } + }, + "node_modules/@prisma/streams-local/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@prisma/studio-core": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.21.1.tgz", - "integrity": "sha512-bOGqG/eMQtKC0XVvcVLRmhWWzm/I+0QUWqAEhEBtetpuS3k3V4IWqKGUONkAIT223DNXJMxMtZp36b1FmcdPeg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.27.3.tgz", + "integrity": "sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==", "license": "Apache-2.0", + "dependencies": { + "@radix-ui/react-toggle": "1.1.10", + "chart.js": "4.5.1" + }, "engines": { - "node": "^20.19 || ^22.12 || ^24.0", + "node": "^20.19 || ^22.12 || >=24.0", "pnpm": "8" }, "peerDependencies": { @@ -2948,6 +2882,145 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@scarf/scarf": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", @@ -2985,9 +3058,9 @@ } }, "node_modules/@sinclair/typebox": { - "version": "0.34.48", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", - "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", "dev": true, "license": "MIT" }, @@ -3002,9 +3075,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz", - "integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==", + "version": "15.3.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.3.2.tgz", + "integrity": "sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -3262,20 +3335,18 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.19.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz", - "integrity": "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==", + "version": "22.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", + "integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } }, "node_modules/@types/pg": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.18.0.tgz", - "integrity": "sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==", - "dev": true, + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==", "license": "MIT", "dependencies": { "@types/node": "*", @@ -3407,20 +3478,20 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz", - "integrity": "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.1.tgz", + "integrity": "sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/type-utils": "8.57.0", - "@typescript-eslint/utils": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", + "@typescript-eslint/scope-manager": "8.58.1", + "@typescript-eslint/type-utils": "8.58.1", + "@typescript-eslint/utils": "8.58.1", + "@typescript-eslint/visitor-keys": "8.58.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3430,9 +3501,9 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.57.0", + "@typescript-eslint/parser": "^8.58.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { @@ -3446,17 +3517,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.0.tgz", - "integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.1.tgz", + "integrity": "sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", + "@typescript-eslint/scope-manager": "8.58.1", + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/typescript-estree": "8.58.1", + "@typescript-eslint/visitor-keys": "8.58.1", "debug": "^4.4.3" }, "engines": { @@ -3468,18 +3538,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", - "integrity": "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.1.tgz", + "integrity": "sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.0", - "@typescript-eslint/types": "^8.57.0", + "@typescript-eslint/tsconfig-utils": "^8.58.1", + "@typescript-eslint/types": "^8.58.1", "debug": "^4.4.3" }, "engines": { @@ -3490,18 +3560,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz", - "integrity": "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.1.tgz", + "integrity": "sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0" + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/visitor-keys": "8.58.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3512,9 +3582,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz", - "integrity": "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.1.tgz", + "integrity": "sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==", "dev": true, "license": "MIT", "engines": { @@ -3525,21 +3595,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz", - "integrity": "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.1.tgz", + "integrity": "sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/utils": "8.57.0", + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/typescript-estree": "8.58.1", + "@typescript-eslint/utils": "8.58.1", "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3550,13 +3620,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", - "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.1.tgz", + "integrity": "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==", "dev": true, "license": "MIT", "engines": { @@ -3568,21 +3638,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz", - "integrity": "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.1.tgz", + "integrity": "sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.57.0", - "@typescript-eslint/tsconfig-utils": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", + "@typescript-eslint/project-service": "8.58.1", + "@typescript-eslint/tsconfig-utils": "8.58.1", + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/visitor-keys": "8.58.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3592,7 +3662,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { @@ -3606,9 +3676,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3619,13 +3689,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -3635,16 +3705,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.0.tgz", - "integrity": "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.1.tgz", + "integrity": "sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0" + "@typescript-eslint/scope-manager": "8.58.1", + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/typescript-estree": "8.58.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3655,17 +3725,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz", - "integrity": "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.1.tgz", + "integrity": "sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/types": "8.58.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -3802,6 +3872,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3816,6 +3889,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3830,6 +3906,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3844,6 +3923,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3858,6 +3940,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3872,6 +3957,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3886,6 +3974,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3900,6 +3991,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3984,7 +4078,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4019,7 +4112,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -4086,9 +4178,9 @@ } }, "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -4395,9 +4487,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.7", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.7.tgz", - "integrity": "sha512-1ghYO3HnxGec0TCGBXiDLVns4eCSx4zJpxnHrlqFQajmhfKMQBzUGDdkMK7fUW7PTHTeLf+j87aTuKuuwWzMGw==", + "version": "2.10.18", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.18.tgz", + "integrity": "sha512-VSnGQAOLtP5mib/DPyg2/t+Tlv65NTBz83BJBJvmLVHHuKJVaDOBvJJykiT5TR++em5nfAySPccDZDa4oSrn8A==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4407,6 +4499,12 @@ "node": ">=6.0.0" } }, + "node_modules/better-result": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/better-result/-/better-result-2.8.2.tgz", + "integrity": "sha512-YOf0VSj5nUPI27doTtXF+BBnsiRq3qY7avHqfIWnppxTLGyvkLq1QV2RTxkwoZwJ60ywLfZ0raFF4J/G886i7A==", + "license": "MIT" + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -4472,9 +4570,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -4495,9 +4593,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -4514,13 +4612,12 @@ } ], "license": "MIT", - "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -4591,13 +4688,13 @@ "license": "MIT" }, "node_modules/bullmq": { - "version": "5.71.0", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.71.0.tgz", - "integrity": "sha512-aeNWh4drsafSKnAJeiNH/nZP/5O8ZdtdMbnOPZmpjXj7NZUP5YC901U3bIH41iZValm7d1i3c34ojv7q31m30w==", + "version": "5.73.4", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.73.4.tgz", + "integrity": "sha512-Q+NeFLtdKSD3GDPYSX4pH+Mc9E4OZVKimXwrnZ5WmndNy31COMy4vQV9zfhgfHGSUFrlpsBicfKYbSjx9FbO+A==", "license": "MIT", "dependencies": { "cron-parser": "4.9.0", - "ioredis": "5.9.3", + "ioredis": "5.10.1", "msgpackr": "1.11.5", "node-abort-controller": "3.1.1", "semver": "7.7.4", @@ -4736,9 +4833,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001778", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001778.tgz", - "integrity": "sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==", + "version": "1.0.30001787", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001787.tgz", + "integrity": "sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==", "dev": true, "funding": [ { @@ -4786,20 +4883,19 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, - "node_modules/chevrotain": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.5.0.tgz", - "integrity": "sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==", - "license": "Apache-2.0", + "node_modules/chart.js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", + "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", + "license": "MIT", "dependencies": { - "@chevrotain/cst-dts-gen": "10.5.0", - "@chevrotain/gast": "10.5.0", - "@chevrotain/types": "10.5.0", - "@chevrotain/utils": "10.5.0", - "lodash": "4.17.21", - "regexp-to-ast": "0.5.0" + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" } }, "node_modules/chokidar": { @@ -4904,6 +5000,7 @@ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": ">= 12" } @@ -5065,7 +5162,6 @@ "integrity": "sha512-gwAPAVTy/j5YcOOebcCRIijn+mSjWJC+IYKivTu6aG8Ei/scoXgfsMRnuAk6b0GRste2J4NGxVdMN3ZpfNaVaw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cachedir": "2.3.0", "cz-conventional-changelog": "3.3.0", @@ -5313,9 +5409,9 @@ } }, "node_modules/conventional-changelog-angular": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.0.tgz", - "integrity": "sha512-DOuBwYSqWzfwuRByY9O4oOIvDlkUCTDzfbOgcSbkY+imXXj+4tmrEFao3K+FxemClYfYnZzsvudbwrhje9VHDA==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.1.tgz", + "integrity": "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==", "dev": true, "license": "ISC", "dependencies": { @@ -5326,9 +5422,9 @@ } }, "node_modules/conventional-changelog-conventionalcommits": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.0.tgz", - "integrity": "sha512-kYFx6gAyjSIMwNtASkI3ZE99U1fuVDJr0yTYgVy+I2QG46zNZfl2her+0+eoviG82c5WQvW1jMt1eOQTeJLodA==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.1.tgz", + "integrity": "sha512-dTYtpIacRpcZgrvBYvBfArMmK2xvIpv2TaxM0/ZI5CBtNUzvF2x0t15HsbRABWprS6UPmvj+PzHVjSx4qAVKyw==", "dev": true, "license": "ISC", "dependencies": { @@ -5346,9 +5442,9 @@ "license": "ISC" }, "node_modules/conventional-commits-parser": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.3.0.tgz", - "integrity": "sha512-RfOq/Cqy9xV9bOA8N+ZH6DlrDR+5S3Mi0B5kACEjESpE+AviIpAptx9a9cFpWCCvgRtWT+0BbUw+e1BZfts9jg==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.4.0.tgz", + "integrity": "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==", "dev": true, "license": "MIT", "dependencies": { @@ -5414,7 +5510,6 @@ "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -5437,13 +5532,13 @@ } }, "node_modules/cosmiconfig-typescript-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", - "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz", + "integrity": "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==", "dev": true, "license": "MIT", "dependencies": { - "jiti": "^2.6.1" + "jiti": "2.6.1" }, "engines": { "node": ">=v18" @@ -5508,7 +5603,8 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cz-conventional-changelog": { "version": "3.3.0", @@ -5604,9 +5700,9 @@ } }, "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", "license": "MIT" }, "node_modules/delayed-stream": { @@ -5801,9 +5897,9 @@ "license": "MIT" }, "node_modules/effect": { - "version": "3.18.4", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", - "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.20.0.tgz", + "integrity": "sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -5811,9 +5907,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.313", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.313.tgz", - "integrity": "sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==", + "version": "1.5.335", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.335.tgz", + "integrity": "sha512-q9n5T4BR4Xwa2cwbrwcsDJtHD/enpQ5S1xF1IAtdqf5AAgqDFmR/aakqH3ChFdqd/QXJhS3rnnXFtexU7rax6Q==", "dev": true, "license": "ISC" }, @@ -5962,7 +6058,6 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6439,16 +6534,15 @@ "license": "MIT" }, "node_modules/fast-copy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.2.tgz", - "integrity": "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.3.tgz", + "integrity": "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==", "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -6511,7 +6605,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true, "funding": [ { "type": "github", @@ -6703,9 +6796,9 @@ } }, "node_modules/flatted": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz", - "integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -6931,9 +7024,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", - "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", + "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -7145,9 +7238,9 @@ "license": "MIT" }, "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7245,11 +7338,10 @@ } }, "node_modules/hono": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.4.tgz", - "integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==", + "version": "4.12.12", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.12.tgz", + "integrity": "sha512-p1JfQMKaceuCbpJKAPKVqyqviZdS0eUxH9v82oWo1kb9xjQ5wA6iP3FNVAPDFlz5/p7d45lO+BpSk1tuSZMF4Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=16.9.0" } @@ -7484,9 +7576,9 @@ } }, "node_modules/ioredis": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.0.tgz", - "integrity": "sha512-HVBe9OFuqs+Z6n64q09PQvP1/R4Bm+30PAyyD4wIEqssh3v9L21QjCVk4kRLucMBcDokJTcLjsGeVRlq/nH6DA==", + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.1.tgz", + "integrity": "sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==", "license": "MIT", "dependencies": { "@ioredis/commands": "1.5.1", @@ -7793,7 +7885,6 @@ "integrity": "sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "30.3.0", "@jest/types": "30.3.0", @@ -8130,9 +8221,9 @@ } }, "node_modules/jest-config/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -8996,9 +9087,9 @@ } }, "node_modules/jest-runtime/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -9620,7 +9711,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { @@ -9733,15 +9823,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -9769,6 +9850,7 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, "license": "MIT" }, "node_modules/lodash.camelcase": { @@ -10165,9 +10247,9 @@ } }, "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -10294,6 +10376,7 @@ "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -10406,9 +10489,9 @@ "license": "MIT" }, "node_modules/node-addon-api": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.6.0.tgz", - "integrity": "sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", "license": "MIT", "engines": { "node": "^18 || ^20 || >= 21" @@ -10454,9 +10537,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.36", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", "dev": true, "license": "MIT" }, @@ -10500,9 +10583,9 @@ } }, "node_modules/nodemon/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10513,13 +10596,13 @@ } }, "node_modules/nodemon/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -10569,9 +10652,9 @@ } }, "node_modules/nypm/node_modules/citty": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.1.tgz", - "integrity": "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz", + "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", "license": "MIT" }, "node_modules/object-assign": { @@ -10595,12 +10678,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "license": "MIT" - }, "node_modules/ohash": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", @@ -10950,9 +11027,9 @@ "license": "ISC" }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "license": "MIT" }, "node_modules/path-type": { @@ -10982,7 +11059,6 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.12.0", "pg-pool": "^3.13.0", @@ -11027,15 +11103,6 @@ "node": ">=4.0.0" } }, - "node_modules/pg-numeric": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", - "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", - "license": "ISC", - "engines": { - "node": ">=4" - } - }, "node_modules/pg-pool": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", @@ -11093,9 +11160,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -11294,9 +11361,9 @@ } }, "node_modules/postal-mime": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/postal-mime/-/postal-mime-2.7.3.tgz", - "integrity": "sha512-MjhXadAJaWgYzevi46+3kLak8y6gbg0ku14O1gO/LNOuay8dO+1PtcSGvAdgDR0DoIsSaiIA8y/Ddw6MnrO0Tw==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/postal-mime/-/postal-mime-2.7.4.tgz", + "integrity": "sha512-0WdnFQYUrPGGTFu1uOqD2s7omwua8xaeYGdO6rb88oD5yJ/4pPHDA4sdWqfD8wQVfCny563n/HQS7zTFft+f/g==", "license": "MIT-0" }, "node_modules/postgres": { @@ -11351,12 +11418,6 @@ "node": ">=0.10.0" } }, - "node_modules/postgres-range": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", - "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", - "license": "MIT" - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -11396,17 +11457,16 @@ } }, "node_modules/prisma": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.5.0.tgz", - "integrity": "sha512-n30qZpWehaYQzigLjmuPisyEsvOzHt7bZeRyg8gZ5DvJo9FGjD+gNaY59Ns3hlLD5/jZH5GBeftIss0jDbUoLg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.7.0.tgz", + "integrity": "sha512-HlgwRBt1uEFB9LStHL4HLYDvoi4BNu1rYA0hPG0zCAEyK9SaZBqp7E5Rjpc3Qh8Lex/ye/svoHZ0OWoFNhWxuQ==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { - "@prisma/config": "7.5.0", - "@prisma/dev": "0.20.0", - "@prisma/engines": "7.5.0", - "@prisma/studio-core": "0.21.1", + "@prisma/config": "7.7.0", + "@prisma/dev": "0.24.3", + "@prisma/engines": "7.7.0", + "@prisma/studio-core": "0.27.3", "mysql2": "3.15.3", "postgres": "3.4.7" }, @@ -11600,9 +11660,9 @@ } }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", + "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", "license": "MIT", "peer": true, "engines": { @@ -11610,16 +11670,16 @@ } }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", "license": "MIT", "peer": true, "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^19.2.5" } }, "node_modules/react-is": { @@ -11658,9 +11718,9 @@ } }, "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -11700,12 +11760,6 @@ "node": ">=4" } }, - "node_modules/regexp-to-ast": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", - "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", - "license": "MIT" - }, "node_modules/remeda": { "version": "2.33.4", "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz", @@ -11729,20 +11783,19 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/resend": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/resend/-/resend-6.9.3.tgz", - "integrity": "sha512-GRXjH9XZBJA+daH7bBVDuTShr22iWCxXA8P7t495G4dM/RC+d+3gHBK/6bz9K6Vpcq11zRQKmD+B+jECwQlyGQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/resend/-/resend-6.10.0.tgz", + "integrity": "sha512-i7CwZpYj4Oho1RxsTpLcCUkO08+HiL4NXrm6jLJ2WzJ89UGI8eROSieLONJA3hnUrf1OYnCyfq5F6POnHUMv1Q==", "license": "MIT", "dependencies": { - "postal-mime": "2.7.3", - "svix": "1.84.1" + "postal-mime": "2.7.4", + "svix": "1.88.0" }, "engines": { "node": ">=20" @@ -11843,6 +11896,7 @@ "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.12.0" } @@ -11920,7 +11974,8 @@ "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/secure-json-parse": { "version": "4.1.0", @@ -12056,13 +12111,13 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -12434,9 +12489,9 @@ } }, "node_modules/svix": { - "version": "1.84.1", - "resolved": "https://registry.npmjs.org/svix/-/svix-1.84.1.tgz", - "integrity": "sha512-K8DPPSZaW/XqXiz1kEyzSHYgmGLnhB43nQCMeKjWGCUpLIpAMMM8kx3rVVOSm6Bo6EHyK1RQLPT4R06skM/MlQ==", + "version": "1.88.0", + "resolved": "https://registry.npmjs.org/svix/-/svix-1.88.0.tgz", + "integrity": "sha512-vm/JrrUd3bVyBE+3L33TIyVSs8gS5fYx7lrISvKlDJXTYX1ACH4REX8P1tHxsSKoZi/rvifM1t0XRc5Vc45THw==", "license": "MIT", "dependencies": { "standardwebhooks": "1.0.0", @@ -12519,9 +12574,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.32.0.tgz", - "integrity": "sha512-nKZB0OuDvacB0s/lC2gbge+RigYvGRGpLLMWMFxaTUwfM+CfndVk9Th2IaTinqXiz6Mn26GK2zriCpv6/+5m3Q==", + "version": "5.32.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.32.2.tgz", + "integrity": "sha512-t6Ns52nS8LU2hqi0+rezMjFO1ZrCsCrnommXrU7Nfrg2va2dWahdvM6TuSwzdHpG29v6BHJyU1c/UWFhgVZzVQ==", "license": "Apache-2.0", "dependencies": { "@scarf/scarf": "=1.4.0" @@ -12593,23 +12648,23 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", - "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -12671,9 +12726,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -12684,19 +12739,19 @@ } }, "node_modules/ts-jest": { - "version": "29.4.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", - "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", + "version": "29.4.9", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.9.tgz", + "integrity": "sha512-LTb9496gYPMCqjeDLdPrKuXtncudeV1yRZnF4Wo5l3SFi0RYEnYRNgMrFIdg+FHvfzjCyQk1cLncWVqiSX+EvQ==", "dev": true, "license": "MIT", "dependencies": { "bs-logger": "^0.2.6", "fast-json-stable-stringify": "^2.1.0", - "handlebars": "^4.7.8", + "handlebars": "^4.7.9", "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.7.3", + "semver": "^7.7.4", "type-fest": "^4.41.0", "yargs-parser": "^21.1.1" }, @@ -12713,7 +12768,7 @@ "babel-jest": "^29.0.0 || ^30.0.0", "jest": "^29.0.0 || ^30.0.0", "jest-util": "^29.0.0 || ^30.0.0", - "typescript": ">=4.3 <6" + "typescript": ">=4.3 <7" }, "peerDependenciesMeta": { "@babel/core": { @@ -12755,7 +12810,6 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -12912,7 +12966,6 @@ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12922,16 +12975,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.0.tgz", - "integrity": "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA==", + "version": "8.58.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.1.tgz", + "integrity": "sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/utils": "8.57.0" + "@typescript-eslint/eslint-plugin": "8.58.1", + "@typescript-eslint/parser": "8.58.1", + "@typescript-eslint/typescript-estree": "8.58.1", + "@typescript-eslint/utils": "8.58.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -12942,7 +12995,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/uglify-js": { @@ -13133,9 +13186,9 @@ } }, "node_modules/validator": { - "version": "13.15.26", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", - "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", + "version": "13.15.35", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz", + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -13208,6 +13261,7 @@ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -13278,6 +13332,7 @@ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -13294,6 +13349,7 @@ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -13306,7 +13362,8 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/wrappy": { "version": "1.0.2", @@ -13368,9 +13425,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -13440,6 +13497,7 @@ "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -13492,7 +13550,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 914de73..b703d23 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "dev": "nodemon", "build": "prisma generate && tsc && tsc-alias", "start": "node dist/index.js", + "worker:email": "ts-node -r tsconfig-paths/register src/workers/email.worker.ts", "postinstall": "prisma generate", "db:migrate": "prisma migrate dev", "db:deploy": "prisma migrate deploy", @@ -26,7 +27,7 @@ "dependencies": { "@asteasolutions/zod-to-openapi": "^8.4.3", "@bufbuild/protobuf": "^2.11.0", - "@coveritlabs/contracts": "^1.3.1", + "@coveritlabs/contracts": "file:vendor/coveritlabs-contracts-1.6.1.tgz", "@prisma/adapter-pg": "^7.4.2", "@prisma/client": "^7.4.2", "argon2": "^0.44.0", @@ -80,4 +81,4 @@ "overrides": { "ioredis": "^5.10.0" } -} +} \ No newline at end of file diff --git a/prisma/migrations/4_add_crawl_sessions/migration.sql b/prisma/migrations/4_add_crawl_sessions/migration.sql new file mode 100644 index 0000000..ba969cb --- /dev/null +++ b/prisma/migrations/4_add_crawl_sessions/migration.sql @@ -0,0 +1,47 @@ +DO $$ BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'CrawlStatus') THEN + CREATE TYPE "CrawlStatus" AS ENUM ( + 'UNSPECIFIED', + 'QUEUED', + 'RUNNING', + 'COMPLETED', + 'FAILED', + 'ABORTED', + 'PAUSED', + 'NEW' + ); + END IF; +END $$; + +DO $$ BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'CrawlTriggerType') THEN + CREATE TYPE "CrawlTriggerType" AS ENUM ( + 'UNSPECIFIED', + 'MANUAL', + 'SCHEDULED', + 'CI_TRIGGER', + 'WEBHOOK' + ); + END IF; +END $$; + +CREATE TABLE IF NOT EXISTS "crawl_sessions" ( + "crawl_session_id" UUID NOT NULL, + "app_version_id" UUID NOT NULL, + "status" "CrawlStatus" NOT NULL DEFAULT 'NEW', + "trigger_type" "CrawlTriggerType" NOT NULL, + "config" JSONB NOT NULL, + "state_count" INTEGER NOT NULL DEFAULT 0, + "transition_count" INTEGER NOT NULL DEFAULT 0, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "started_at" TIMESTAMP(3), + "finished_at" TIMESTAMP(3), + "error" TEXT, + CONSTRAINT "crawl_sessions_pkey" PRIMARY KEY ("crawl_session_id") +); + +ALTER TABLE "crawl_sessions" + ADD CONSTRAINT "crawl_sessions_app_version_id_fkey" + FOREIGN KEY ("app_version_id") + REFERENCES "target_application_versions"("id") + ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index dbbe3e1..53c9aa4 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -62,6 +62,25 @@ enum ProjectRole { VIEWER } +enum CrawlStatus { + UNSPECIFIED + QUEUED + RUNNING + COMPLETED + FAILED + ABORTED + PAUSED + NEW +} + +enum CrawlTriggerType { + UNSPECIFIED + MANUAL + SCHEDULED + CI_TRIGGER + WEBHOOK +} + model ProjectMember { id String @id @default(uuid()) @db.Uuid projectId String @map("project_id") @db.Uuid @@ -105,7 +124,7 @@ model TargetApplicationVersion { updatedAt DateTime @updatedAt @map("updated_at") targetApplication TargetApplication @relation(fields: [targetApplicationId], references: [id], onDelete: Cascade) - + crawlSessions CrawlSession[] @@unique([targetApplicationId, version]) @@map("target_application_versions") } @@ -126,4 +145,21 @@ model RegressionCodebase { targetApplication TargetApplication @relation(fields: [targetApplicationId], references: [id], onDelete: Cascade) @@map("regression_codebases") @@unique([targetApplicationId, repositoryUrl]) +} + +model CrawlSession { + id String @id @default(uuid()) @map("crawl_session_id") @db.Uuid + appVersionId String @map("app_version_id") @db.Uuid + status CrawlStatus @default(NEW) + triggerType CrawlTriggerType @map("trigger_type") + config Json + stateCount Int @default(0) @map("state_count") + transitionCount Int @default(0) @map("transition_count") + createdAt DateTime @default(now()) @map("created_at") + startedAt DateTime? @map("started_at") + finishedAt DateTime? @map("finished_at") + error String? @db.Text + appVersion TargetApplicationVersion @relation(fields: [appVersionId], references: [id], onDelete: Cascade) + + @@map("crawl_sessions") } \ No newline at end of file diff --git a/scripts/api_crawler_smoke_test.py b/scripts/api_crawler_smoke_test.py new file mode 100644 index 0000000..2fe0b93 --- /dev/null +++ b/scripts/api_crawler_smoke_test.py @@ -0,0 +1,385 @@ +# Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +# Proprietary and confidential. Unauthorized use is strictly prohibited. +# See LICENSE file in the project root for full license information. + +import json +import os +import sys +import time +import uuid +import urllib.error +import urllib.request +import urllib.parse +from typing import Any, Dict, Optional, Tuple + +def _json_loads_maybe(text: str) -> Any: + try: + return json.loads(text) + except Exception: + return text + + +def _http_json(method: str, url: str, *, token: Optional[str] = None, body: Optional[Dict[str, Any]] = None, timeout: int = 30) -> Tuple[int, Any]: + data = None + headers = { + "Accept": "application/json", + } + if body is not None: + data = json.dumps(body).encode("utf-8") + headers["Content-Type"] = "application/json" + if token: + headers["Authorization"] = f"Bearer {token}" + + req = urllib.request.Request(url, data=data, headers=headers, method=method.upper()) + + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + raw = resp.read().decode("utf-8") + return resp.status, _json_loads_maybe(raw) if raw else None + except urllib.error.HTTPError as e: + raw = e.read().decode("utf-8") if e.fp else "" + payload = _json_loads_maybe(raw) if raw else None + raise RuntimeError(f"HTTP {e.code} {method} {url} {payload}") from None + except urllib.error.URLError as e: + raise RuntimeError(f"Request failed {method} {url} {e}") from None + + +def _http_text(method: str, url: str, *, timeout: int = 15) -> Tuple[int, str]: + req = urllib.request.Request(url, headers={"Accept": "*/*"}, method=method.upper()) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + raw = resp.read().decode("utf-8", errors="replace") + return resp.status, raw + except urllib.error.HTTPError as e: + raw = e.read().decode("utf-8", errors="replace") if e.fp else "" + raise RuntimeError(f"HTTP {e.code} {method} {url} {raw[:500]}") from None + except urllib.error.URLError as e: + raise RuntimeError(f"Request failed {method} {url} {e}") from None + + +def _join_url(base: str, path: str) -> str: + return base.rstrip("/") + "/" + path.lstrip("/") + + +def _origin(url: str) -> str: + parts = urllib.parse.urlsplit(url) + if not parts.scheme or not parts.netloc: + raise RuntimeError(f"Invalid URL: {url}") + return f"{parts.scheme}://{parts.netloc}" + + +def _as_int(value: Any) -> Optional[int]: + if value is None: + return None + try: + return int(value) + except Exception: + return None + + +_CRAWL_STATUS_BY_NUMBER = { + 0: "UNSPECIFIED", + 1: "QUEUED", + 2: "RUNNING", + 3: "COMPLETED", + 4: "FAILED", + 5: "ABORTED", + 6: "PAUSED", + 7: "NEW", +} + + +def _normalize_crawl_status(value: Any) -> str: + if value is None: + return "UNKNOWN" + + if isinstance(value, int): + return _CRAWL_STATUS_BY_NUMBER.get(value, f"UNKNOWN({value})") + + if isinstance(value, str): + v = value.strip().upper() + for name in _CRAWL_STATUS_BY_NUMBER.values(): + if v == name or v.endswith(f"_{name}"): + return name + return v or "UNKNOWN" + + n = _as_int(value) + if n is not None: + return _CRAWL_STATUS_BY_NUMBER.get(n, f"UNKNOWN({n})") + + return "UNKNOWN" + + +def _parse_trigger_type(value: str) -> int: + v = (value or "").strip() + if v.isdigit(): + n = int(v) + if 0 <= n <= 4: + return n + mapping = { + "UNSPECIFIED": 0, + "MANUAL": 1, + "SCHEDULED": 2, + "CI_TRIGGER": 3, + "WEBHOOK": 4, + } + key = v.upper() + if key in mapping: + return mapping[key] + raise RuntimeError(f"Invalid COVERIT_CRAWL_TRIGGER_TYPE: {value}") + + +def main() -> int: + base = "http://localhost:3000/api/v1" + password = "TestPassword123!@#" + name = "API Smoke Tester" + email = f"api-smoke-{uuid.uuid4().hex[:12]}@example.com" + + project_name = f"api-smoke-{uuid.uuid4().hex[:8]}" + project_description = "A project created by the API crawler" + + target_app_name = f"target-app-{uuid.uuid4().hex[:8]}" + target_base_url = "https://the-internet.herokuapp.com" + target_version = "0.0.1" + + poll_interval = 2.0 + poll_timeout = 600 + + pickup_timeout = 30.0 + precheck_api = True + precheck_target = True + min_states = 0 + min_transitions = 0 + + print( + json.dumps( + { + "base": base, + "email": email, + "project": project_name, + "targetBaseUrl": target_base_url, + "pollIntervalSeconds": poll_interval, + "pollTimeoutSeconds": poll_timeout, + "workerPickupTimeoutSeconds": pickup_timeout, + }, + indent=2, + ) + ) + + if precheck_api: + health_url = _join_url(_origin(base), "/health") + status, payload = _http_json("GET", health_url, timeout=10) + if not isinstance(payload, dict) or payload.get("status") != "ok": + raise RuntimeError(f"API healthcheck unexpected response: {payload}") + print(json.dumps({"apiHealth": "ok", "url": health_url}, indent=2)) + + if precheck_target: + status, _ = _http_text("GET", target_base_url, timeout=10) + if status < 200 or status >= 500: + raise RuntimeError(f"Target base URL not reachable (status {status}): {target_base_url}") + print(json.dumps({"targetPrecheckStatus": status, "url": target_base_url}, indent=2)) + + signup_url = _join_url(base, "/auth/signup") + try: + status, payload = _http_json("POST", signup_url, body={"email": email, "password": password, "name": name}) + print(json.dumps({"signupStatus": status, "signup": payload}, indent=2)) + except RuntimeError as e: + msg = str(e) + if "HTTP 409" in msg or "EMAIL" in msg or "taken" in msg.lower() or "already" in msg.lower(): + print(json.dumps({"signupSkipped": True, "reason": msg}, indent=2)) + else: + raise + + login_url = _join_url(base, "/auth/login") + status, login = _http_json("POST", login_url, body={"email": email, "password": password}) + access_token = (login or {}).get("tokens", {}).get("accessToken") + if not access_token: + raise RuntimeError(f"Login succeeded but accessToken missing: {login}") + print(json.dumps({"loginStatus": status, "user": (login or {}).get("user")}, indent=2)) + + create_project_url = _join_url(base, "/projects") + project_body: Dict[str, Any] = {"name": project_name} + if project_description is not None: + project_body["description"] = project_description + status, project = _http_json("POST", create_project_url, token=access_token, body=project_body) + project_id = (project or {}).get("id") + if not project_id: + raise RuntimeError(f"Create project failed: {project}") + print(json.dumps({"createProjectStatus": status, "projectId": project_id}, indent=2)) + + create_app_url = _join_url(base, f"/projects/{project_id}/target-applications") + status, app = _http_json( + "POST", + create_app_url, + token=access_token, + body={"name": target_app_name, "baseUrl": target_base_url}, + ) + app_id = (app or {}).get("id") + if not app_id: + raise RuntimeError(f"Create target application failed: {app}") + print(json.dumps({"createTargetApplicationStatus": status, "appId": app_id}, indent=2)) + + create_version_url = _join_url(base, f"/projects/{project_id}/target-applications/{app_id}/versions") + status, ver = _http_json("POST", create_version_url, token=access_token, body={"version": target_version}) + version_id = (ver or {}).get("id") + if not version_id: + raise RuntimeError(f"Create version failed: {ver}") + print(json.dumps({"createVersionStatus": status, "versionId": version_id}, indent=2)) + + create_session_url = _join_url( + base, + f"/projects/{project_id}/target-applications/{app_id}/versions/{version_id}/crawl-sessions", + ) + + crawl_config: Dict[str, Any] = { + "crawlerSettings": { + "headless": False, + "timeout_ms": 30000, + "max_states": 50, + "max_transitions": 200, + "max_elements_per_state": 5, + "max_select_options_per_element": 2, + "max_action_repeats_per_url": 1, + "action_retry_count": 1, + "replay_retry_count": 1, + "popup_timeout_ms": 3000, + "dom_quiet_ms": 400, + "dom_settle_timeout_ms": 3000, + "use_dom_quiescence": True, + "page_load_state": "networkidle", + "click_non_http_links": False, + "defer_destructive_actions": "true".lower() == "true", + "destructive_keywords": + "logout,log out,sign out,delete,remove,unsubscribe,cancel,checkout,pay,purchase,order,place order,reset,deactivate,terminate,drop,empty cart,clear cart", + }, + } + + trigger_type = _parse_trigger_type("MANUAL") + + status, session = _http_json( + "POST", + create_session_url, + token=access_token, + body={ + "triggerType": trigger_type, + "crawlConfig": crawl_config, + }, + ) + + session_id = (session or {}).get("id") + if not session_id: + raise RuntimeError(f"Create crawl session failed: {session}") + + initial_status_raw = (session or {}).get("status") + print( + json.dumps( + { + "createSessionStatus": status, + "crawlSessionId": session_id, + "initialStatus": initial_status_raw, + "initialStatusName": _normalize_crawl_status(initial_status_raw), + }, + indent=2, + ) + ) + + start_url = _join_url( + base, + f"/projects/{project_id}/target-applications/{app_id}/versions/{version_id}/crawl-sessions/{session_id}/start", + ) + status, started = _http_json("PUT", start_url, token=access_token, body={}) + print(json.dumps({"startSessionStatus": status, "startResponse": started}, indent=2)) + + details_url = _join_url( + base, + f"/projects/{project_id}/target-applications/{app_id}/versions/{version_id}/crawl-sessions/{session_id}", + ) + + deadline = time.time() + poll_timeout + + pickup_deadline = min(deadline, time.time() + pickup_timeout) + last = None + while time.time() < pickup_deadline: + _, details = _http_json("GET", details_url, token=access_token) + status_raw = (details or {}).get("status") + status_value = _normalize_crawl_status(status_raw) + snapshot = { + "status": status_value, + "rawStatus": status_raw, + "stateCount": (details or {}).get("stateCount"), + "transitionCount": (details or {}).get("transitionCount"), + "errorMessage": (details or {}).get("errorMessage"), + "startedAt": (details or {}).get("startedAt"), + "finishedAt": (details or {}).get("finishedAt"), + } + + if snapshot != last: + print(json.dumps({"crawlSession": snapshot}, indent=2)) + last = snapshot + + if status_value in {"RUNNING", "COMPLETED", "FAILED", "ABORTED", "PAUSED"}: + break + + time.sleep(poll_interval) + + if last is None: + raise RuntimeError("Did not receive crawl session details") + + if last.get("status") == "QUEUED": + raise RuntimeError( + "Crawl session is still QUEUED after pickup timeout — worker likely not consuming. " + "Ensure the crawler consumer is running (coverit-crawler: python -m src.workers.queue_consumer) " + "and that its REDIS_URL and DATABASE_URL point to the same services as the API." + ) + + if last.get("status") == "NEW": + raise RuntimeError("Crawl session never entered QUEUED/RUNNING — start may not have worked") + + while time.time() < deadline: + _, details = _http_json("GET", details_url, token=access_token) + status_raw = (details or {}).get("status") + status_value = _normalize_crawl_status(status_raw) + snapshot = { + "status": status_value, + "rawStatus": status_raw, + "stateCount": (details or {}).get("stateCount"), + "transitionCount": (details or {}).get("transitionCount"), + "errorMessage": (details or {}).get("errorMessage"), + "startedAt": (details or {}).get("startedAt"), + "finishedAt": (details or {}).get("finishedAt"), + } + + if snapshot != last: + print(json.dumps({"crawlSession": snapshot}, indent=2)) + last = snapshot + + if status_value in {"COMPLETED", "FAILED", "ABORTED", "PAUSED"}: + break + + time.sleep(poll_interval) + + if last.get("status") == "COMPLETED": + state_count = _as_int(last.get("stateCount")) or 0 + transition_count = _as_int(last.get("transitionCount")) or 0 + if min_states and state_count < min_states: + raise RuntimeError(f"Crawl completed but stateCount={state_count} < {min_states}") + if min_transitions and transition_count < min_transitions: + raise RuntimeError(f"Crawl completed but transitionCount={transition_count} < {min_transitions}") + if not last.get("startedAt") or not last.get("finishedAt"): + raise RuntimeError(f"Crawl completed but timestamps missing: {last}") + return 0 + + if last.get("status") in {"FAILED", "ABORTED"}: + return 2 + + return 1 + + +if __name__ == "__main__": + try: + raise SystemExit(main()) + except KeyboardInterrupt: + raise SystemExit(130) + except Exception as e: + print(str(e), file=sys.stderr) + raise SystemExit(1) diff --git a/src/api/controllers/crawlSession.controller.ts b/src/api/controllers/crawlSession.controller.ts new file mode 100644 index 0000000..bff693b --- /dev/null +++ b/src/api/controllers/crawlSession.controller.ts @@ -0,0 +1,110 @@ +// Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +// Proprietary and confidential. Unauthorized use is strictly prohibited. +// See LICENSE file in the project root for full license information. + +import { Request, Response } from 'express'; +import * as crawlService from '@services/crawlSession.service'; +import { StatusCodes } from 'http-status-codes'; +import { ZodError } from 'zod'; +import { + AppVersionParamsSchema, + CrawlSessionParamsSchema, + CreateCrawlSessionRequestSchema, + GetSessionsQuerySchema, +} from '@models/crawlSession'; + +function handleControllerError(res: Response, error: unknown): void { + if (error instanceof ZodError) { + res.status(StatusCodes.BAD_REQUEST).json({ + message: 'Validation failed', + details: error.issues, + }); + return; + } + if (typeof error === 'object' && error !== null && 'code' in error && error.code === 'P2025') { + res.status(StatusCodes.NOT_FOUND).json({ message: 'Resource not found' }); + return; + } + if (error instanceof Error) { + res.status(StatusCodes.CONFLICT).json({ message: error.message }); + return; + } + + console.error('[Crawl Controller Error]:', error); + res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + message: 'An unexpected internal server error occurred', + }); +} + + +export const getSessions = async (req: Request, res: Response) => { + try { + const { versionId } = AppVersionParamsSchema.parse(req.params); + const query = GetSessionsQuerySchema.parse(req.query); + const result = await crawlService.getSessions(versionId, query); + res.json(result); + } catch (e) { + handleControllerError(res, e); + } +}; + +export const createSession = async (req: Request, res: Response) => { + try { + const { versionId } = AppVersionParamsSchema.parse(req.params); + const body = CreateCrawlSessionRequestSchema.parse(req.body); + const result = await crawlService.createSession(versionId, body.triggerType, body.crawlConfig); + res.status(StatusCodes.CREATED).json(result); + } catch (e) { + handleControllerError(res, e); + } +}; + +export const getSessionDetails = async (req: Request, res: Response) => { + try { + const { crawlSessionId } = CrawlSessionParamsSchema.parse(req.params); + const result = await crawlService.getSessionDetails(crawlSessionId); + res.json(result); + } catch (e) { + handleControllerError(res, e); + } +}; + +export const deleteSession = async (req: Request, res: Response) => { + try { + const { crawlSessionId } = CrawlSessionParamsSchema.parse(req.params); + await crawlService.deleteSession(crawlSessionId); + res.status(StatusCodes.OK).json({ message: 'Crawl session deleted successfully' }); + } catch (e) { + handleControllerError(res, e); + } +}; + +export const startSession = async (req: Request, res: Response) => { + try { + const { crawlSessionId } = CrawlSessionParamsSchema.parse(req.params); + await crawlService.startSession(crawlSessionId); + res.status(StatusCodes.OK).json({ message: 'Crawl session started successfully' }); + } catch (e) { + handleControllerError(res, e); + } +}; + +export const abortSession = async (req: Request, res: Response) => { + try { + const { crawlSessionId } = CrawlSessionParamsSchema.parse(req.params); + await crawlService.abortSession(crawlSessionId); + res.status(StatusCodes.OK).json({ message: 'Crawl session aborted successfully' }); + } catch (e) { + handleControllerError(res, e); + } +}; + +export const pauseSession = async (req: Request, res: Response) => { + try { + const { crawlSessionId } = CrawlSessionParamsSchema.parse(req.params); + await crawlService.pauseSession(crawlSessionId); + res.status(StatusCodes.OK).json({ message: 'Crawl session paused successfully' }); + } catch (e) { + handleControllerError(res, e); + } +}; \ No newline at end of file diff --git a/src/api/routes/crawlSession.routes.ts b/src/api/routes/crawlSession.routes.ts new file mode 100644 index 0000000..537241d --- /dev/null +++ b/src/api/routes/crawlSession.routes.ts @@ -0,0 +1,31 @@ +// Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +// Proprietary and confidential. Unauthorized use is strictly prohibited. +// See LICENSE file in the project root for full license information. + +import { Router } from "express"; + +import * as crawlSessionController from "@api/controllers/crawlSession.controller"; +import { requireAuth } from "@api/middlewares/requireAuth"; +import { requireProjectAdmin, requireProjectMember, requireProjectMembership } from "@api/middlewares/requireProjectAccess"; +import { validateBody } from "@api/middlewares/validate"; +import { CreateCrawlSessionRequestSchema } from "@models/crawlSession"; + +const router = Router({ mergeParams: true }); + +router.use(requireAuth); + +router.get("/", requireProjectMembership, crawlSessionController.getSessions); + +router.post("/", requireProjectMember, validateBody(CreateCrawlSessionRequestSchema), crawlSessionController.createSession); + +router.get("/:crawlSessionId", requireProjectMembership, crawlSessionController.getSessionDetails); + +router.delete("/:crawlSessionId", requireProjectAdmin, crawlSessionController.deleteSession); + +router.put("/:crawlSessionId/abort", requireProjectMember, crawlSessionController.abortSession); + +router.put("/:crawlSessionId/start", requireProjectMember, crawlSessionController.startSession); + +router.put("/:crawlSessionId/pause", requireProjectMember, crawlSessionController.pauseSession); + +export default router; \ No newline at end of file diff --git a/src/api/routes/targetApplication.routes.ts b/src/api/routes/targetApplication.routes.ts index a72c924..2b9e048 100644 --- a/src/api/routes/targetApplication.routes.ts +++ b/src/api/routes/targetApplication.routes.ts @@ -14,6 +14,7 @@ import { CreateTargetApplicationVersionRequestSchema, } from "@models/targetApplication"; import { CreateRegressionCodebaseRequestSchema, UpdateRegressionCodebaseRequestSchema } from "@models/regressionCodebase"; +import crawlSessionRoutes from "@api/routes/crawlSession.routes"; const router = Router({ mergeParams: true }); @@ -28,6 +29,8 @@ router.get("/:appId", requireProjectMembership, targetController.getTargetApplic router.post("/:appId/versions", requireProjectMember, validateBody(CreateTargetApplicationVersionRequestSchema), targetController.createVersion); router.delete("/:appId/versions/:versionId", requireProjectAdmin, targetController.deleteVersion); +router.use("/:appId/versions/:versionId/crawl-sessions", crawlSessionRoutes); + // Regression codebases router.post( "/:appId/regression-codebases", diff --git a/src/lib/cache.ts b/src/lib/cache.ts index 2dea045..01ee94c 100644 --- a/src/lib/cache.ts +++ b/src/lib/cache.ts @@ -64,6 +64,9 @@ export const cacheKeys = { byId: (codebaseId: string): string => `regression_codebase:${codebaseId}`, byApp: (appId: string): string => `app:regression_codebases:${appId}`, }, + crawlSession: { + pid: (sessionId: string): string => `session:${sessionId}:pid`, + }, } as const; export async function cacheGetJSON(key: string, context?: string): Promise { diff --git a/src/mappers/crawlSession.mapper.ts b/src/mappers/crawlSession.mapper.ts new file mode 100644 index 0000000..52b4b72 --- /dev/null +++ b/src/mappers/crawlSession.mapper.ts @@ -0,0 +1,75 @@ +// Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +// Proprietary and confidential. Unauthorized use is strictly prohibited. +// See LICENSE file in the project root for full license information. + +import { CrawlStatus as PrismaCrawlStatus, CrawlTriggerType as PrismaCrawlTriggerType, type Prisma } from "@generated/prisma/client"; +import { CrawlStatus, CrawlTriggerType, type CrawlConfig } from "@models/crawlSession"; + +export const toDbCrawlStatus = (status: CrawlStatus): PrismaCrawlStatus => { + const key = CrawlStatus[status] as unknown as keyof typeof PrismaCrawlStatus; + return PrismaCrawlStatus[key] ?? PrismaCrawlStatus.UNSPECIFIED; +}; + +export const toDbCrawlTriggerType = (triggerType: CrawlTriggerType): PrismaCrawlTriggerType => { + const key = CrawlTriggerType[triggerType] as unknown as keyof typeof PrismaCrawlTriggerType; + return PrismaCrawlTriggerType[key] ?? PrismaCrawlTriggerType.UNSPECIFIED; +}; + +export const toDbCrawlStatusFilter = (status?: CrawlStatus): TDbStatus | undefined => { + if (status === undefined || status === CrawlStatus.UNSPECIFIED) return undefined; + return toDbCrawlStatus(status) as unknown as TDbStatus; +}; + +export const toDbCrawlTriggerTypeFilter = (triggerType?: CrawlTriggerType): TDbTriggerType | undefined => { + if (triggerType === undefined || triggerType === CrawlTriggerType.UNSPECIFIED) return undefined; + return toDbCrawlTriggerType(triggerType) as unknown as TDbTriggerType; +}; + +export const fromDbCrawlStatus = (status: TDbStatus): CrawlStatus => { + return (CrawlStatus[status as unknown as keyof typeof CrawlStatus] ?? CrawlStatus.UNSPECIFIED) as CrawlStatus; +}; + +export const fromDbCrawlTriggerType = (triggerType: TDbTriggerType): CrawlTriggerType => { + return (CrawlTriggerType[triggerType as unknown as keyof typeof CrawlTriggerType] ?? CrawlTriggerType.UNSPECIFIED) as CrawlTriggerType; +}; + +export const toPersistedCrawlConfig = (config: CrawlConfig): Prisma.InputJsonValue => { + const settings = config.crawlerSettings; + const input = config.inputDefaults; + + const crawlerSettings: Record = {}; + if (settings?.headless !== undefined) crawlerSettings.headless = settings.headless; + if (settings?.timeoutMs !== undefined) crawlerSettings.timeout_ms = settings.timeoutMs; + if (settings?.maxStates !== undefined) crawlerSettings.max_states = settings.maxStates; + if (settings?.maxTransitions !== undefined) crawlerSettings.max_transitions = settings.maxTransitions; + if (settings?.maxElementsPerState !== undefined) crawlerSettings.max_elements_per_state = settings.maxElementsPerState; + if (settings?.maxSelectOptionsPerElement !== undefined) { + crawlerSettings.max_select_options_per_element = settings.maxSelectOptionsPerElement; + } + if (settings?.maxActionRepeatsPerUrl !== undefined) { + crawlerSettings.max_action_repeats_per_url = settings.maxActionRepeatsPerUrl; + } + if (settings?.actionRetryCount !== undefined) crawlerSettings.action_retry_count = settings.actionRetryCount; + if (settings?.replayRetryCount !== undefined) crawlerSettings.replay_retry_count = settings.replayRetryCount; + if (settings?.popupTimeoutMs !== undefined) crawlerSettings.popup_timeout_ms = settings.popupTimeoutMs; + if (settings?.domQuietMs !== undefined) crawlerSettings.dom_quiet_ms = settings.domQuietMs; + if (settings?.domSettleTimeoutMs !== undefined) crawlerSettings.dom_settle_timeout_ms = settings.domSettleTimeoutMs; + if (settings?.useDomQuiescence !== undefined) crawlerSettings.use_dom_quiescence = settings.useDomQuiescence; + if (settings?.pageLoadState !== undefined) crawlerSettings.page_load_state = settings.pageLoadState; + if (settings?.clickNonHttpLinks !== undefined) crawlerSettings.click_non_http_links = settings.clickNonHttpLinks; + if (settings?.deferDestructiveActions !== undefined) { + crawlerSettings.defer_destructive_actions = settings.deferDestructiveActions; + } + if (settings?.destructiveKeywords !== undefined) crawlerSettings.destructive_keywords = settings.destructiveKeywords; + + const persisted: Record = {}; + if (Object.keys(crawlerSettings).length > 0) persisted.crawlerSettings = crawlerSettings; + if (input) { + persisted.inputDefaults = { + field_patterns: input.fieldPatterns, + type_fallbacks: input.typeFallbacks, + }; + } + + return persisted; +} \ No newline at end of file diff --git a/src/models/crawlSession.ts b/src/models/crawlSession.ts new file mode 100644 index 0000000..e7610ec --- /dev/null +++ b/src/models/crawlSession.ts @@ -0,0 +1,143 @@ +// Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +// Proprietary and confidential. Unauthorized use is strictly prohibited. +// See LICENSE file in the project root for full license information. + +// CrawlSession domain DTOs + +import { + CrawlTriggerType, + CrawlStatus, + type CrawlConfig as ContractCrawlConfig, + type CreateCrawlSessionRequest as ContractCreateCrawlSessionRequest, + type CrawlSessionData as ContractCrawlSessionData, + type ApplicationVersionCrawlSessionsResponse as ContractApplicationVersionCrawlSessionsResponse, + type CrawlSessionByIDResponse as ContractCrawlSessionByIDResponse, + type StopCrawlSessionResponse as ContractStopCrawlSessionResponse, +} from "@coveritlabs/contracts"; +import { z } from "@utils/zod"; +import type { infer as ZodInfer, ZodType } from "zod"; +import type { Plain } from "./common"; +import { type InputDefaultsConfig, type CrawlerRunSettings } from "types/crawler"; + +export type CrawlConfig = Plain & { + crawlerSettings?: CrawlerRunSettings; + inputDefaults?: InputDefaultsConfig; +}; +export type CreateCrawlSessionRequest = Omit, "crawlConfig"> & { + crawlConfig: CrawlConfig; +}; +export type CrawlSessionData = Omit, "crawlConfig"> & { + crawlConfig: CrawlConfig; +}; +export type ApplicationVersionCrawlSessionsResponse = Plain; +export type CrawlSessionByIDResponse = Plain; +export type StopCrawlSessionResponse = Plain; +export type GetSessionsQuery = ZodInfer; +export { CrawlTriggerType, CrawlStatus }; + + +function normalizeCrawlerSettings(input: unknown): unknown { + if (typeof input !== 'object' || input === null || Array.isArray(input)) return input; + const src = input as Record; + + const mapped: Record = { ...src }; + const remap = (from: string, to: string) => { + if (mapped[from] !== undefined && mapped[to] === undefined) { + mapped[to] = mapped[from]; + } + }; + + remap('timeout_ms', 'timeoutMs'); + remap('max_states', 'maxStates'); + remap('max_transitions', 'maxTransitions'); + remap('max_elements_per_state', 'maxElementsPerState'); + remap('max_select_options_per_element', 'maxSelectOptionsPerElement'); + remap('max_action_repeats_per_url', 'maxActionRepeatsPerUrl'); + remap('action_retry_count', 'actionRetryCount'); + remap('replay_retry_count', 'replayRetryCount'); + remap('popup_timeout_ms', 'popupTimeoutMs'); + remap('dom_quiet_ms', 'domQuietMs'); + remap('dom_settle_timeout_ms', 'domSettleTimeoutMs'); + remap('use_dom_quiescence', 'useDomQuiescence'); + remap('page_load_state', 'pageLoadState'); + remap('click_non_http_links', 'clickNonHttpLinks'); + remap('defer_destructive_actions', 'deferDestructiveActions'); + remap('destructive_keywords', 'destructiveKeywords'); + + return mapped; +} + +function normalizeInputDefaults(input: unknown): unknown { + if (typeof input !== 'object' || input === null || Array.isArray(input)) return input; + const src = input as Record; + const mapped: Record = { ...src }; + + if (mapped.field_patterns !== undefined && mapped.fieldPatterns === undefined) { + mapped.fieldPatterns = mapped.field_patterns; + } + if (mapped.type_fallbacks !== undefined && mapped.typeFallbacks === undefined) { + mapped.typeFallbacks = mapped.type_fallbacks; + } + return mapped; +} + + +export const CrawlConfigSchema = z.object({ + crawlerSettings: z + .preprocess( + normalizeCrawlerSettings, + z.object({ + headless: z.boolean().optional(), + timeoutMs: z.number().int().min(1).max(86400_000).optional(), + maxStates: z.number().int().min(1).max(100000).optional(), + maxTransitions: z.number().int().min(1).max(1_000_000).optional(), + maxElementsPerState: z.number().int().min(1).max(10000).optional(), + maxSelectOptionsPerElement: z.number().int().min(1).max(1000).optional(), + maxActionRepeatsPerUrl: z.number().int().min(0).max(1000).optional(), + actionRetryCount: z.number().int().min(0).max(100).optional(), + replayRetryCount: z.number().int().min(0).max(100).optional(), + popupTimeoutMs: z.number().int().min(1).max(86400_000).optional(), + domQuietMs: z.number().int().min(0).max(600_000).optional(), + domSettleTimeoutMs: z.number().int().min(1).max(86400_000).optional(), + useDomQuiescence: z.boolean().optional(), + pageLoadState: z.string().min(1).max(100).optional(), + clickNonHttpLinks: z.boolean().optional(), + deferDestructiveActions: z.boolean().optional(), + destructiveKeywords: z.string().min(0).max(5000).optional(), + }) + ) + .optional(), + inputDefaults: z + .preprocess( + normalizeInputDefaults, + z.object({ + fieldPatterns: z.record(z.string(), z.string()), + typeFallbacks: z.record(z.string(), z.string()), + }) + ) + .optional(), +}).loose() satisfies ZodType; + +export const CreateCrawlSessionRequestSchema = z.object({ + triggerType: z.enum(CrawlTriggerType), + crawlConfig: CrawlConfigSchema.optional().default({}), +}) satisfies ZodType; + +export const AppVersionParamsSchema = z.object({ + versionId: z.uuid(), +}); + +export const CrawlSessionParamsSchema = z.object({ + crawlSessionId: z.uuid(), +}); + +export const GetSessionsQuerySchema = z.object({ + page: z.coerce.number().int().min(1).default(1), + pageSize: z.coerce.number().int().min(1).max(100).default(25), + status: z.enum(CrawlStatus).optional(), + triggerType: z.enum(CrawlTriggerType).optional(), +}); + + + + diff --git a/src/queues/crawl.queue.ts b/src/queues/crawl.queue.ts new file mode 100644 index 0000000..bc20beb --- /dev/null +++ b/src/queues/crawl.queue.ts @@ -0,0 +1,14 @@ +// Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +// Proprietary and confidential. Unauthorized use is strictly prohibited. +// See LICENSE file in the project root for full license information. + +import { enqueueCrawlSession, markCrawlSessionCancelled } from "@queues/stream/crawlStream"; + +export async function addCrawlJob(sessionId: string): Promise { + await enqueueCrawlSession(sessionId); +} + +export async function removeCrawlJob(sessionId: string): Promise { + await markCrawlSessionCancelled(sessionId); + return true; +} \ No newline at end of file diff --git a/src/queues/stream/crawlStream.ts b/src/queues/stream/crawlStream.ts new file mode 100644 index 0000000..6e29dac --- /dev/null +++ b/src/queues/stream/crawlStream.ts @@ -0,0 +1,32 @@ +// Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +// Proprietary and confidential. Unauthorized use is strictly prohibited. +// See LICENSE file in the project root for full license information. + +import redis from "@lib/redis"; + +export const crawlStreamConfig = { + streamKey: "crawl:jobs", + cancelPrefix: "crawl:cancelled:", + maxLen: Number(process.env.CRAWL_STREAM_MAXLEN ?? "10000"), + cancelTtlSeconds: Number(process.env.CRAWL_CANCEL_TTL_SECONDS ?? "86400"), +} as const; + +export async function enqueueCrawlSession(sessionId: string): Promise { + const maxLen = Number.isFinite(crawlStreamConfig.maxLen) ? crawlStreamConfig.maxLen : 10000; + await redis.xadd( + crawlStreamConfig.streamKey, + "MAXLEN", + "~", + String(maxLen), + "*", + "sessionId", + sessionId, + "name", + "crawl", + ); +} + +export async function markCrawlSessionCancelled(sessionId: string): Promise { + const ttl = Number.isFinite(crawlStreamConfig.cancelTtlSeconds) ? crawlStreamConfig.cancelTtlSeconds : 86400; + await redis.set(`${crawlStreamConfig.cancelPrefix}${sessionId}`, "1", "EX", ttl); +} diff --git a/src/services/crawlSession.service.ts b/src/services/crawlSession.service.ts new file mode 100644 index 0000000..e38fba3 --- /dev/null +++ b/src/services/crawlSession.service.ts @@ -0,0 +1,184 @@ +// Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +// Proprietary and confidential. Unauthorized use is strictly prohibited. +// See LICENSE file in the project root for full license information. + +import prisma from "@lib/prisma"; +import { CrawlStatus as PrismaCrawlStatus } from "@generated/prisma/client"; +import { + fromDbCrawlStatus, + fromDbCrawlTriggerType, + toDbCrawlStatusFilter, + toDbCrawlTriggerType, + toDbCrawlTriggerTypeFilter, + toPersistedCrawlConfig, +} from "@mappers/crawlSession.mapper"; +import { + type CrawlConfig, + CrawlConfigSchema, + CrawlTriggerType, + type ApplicationVersionCrawlSessionsResponse, + type CrawlSessionData, + type GetSessionsQuery, +} from "@models/crawlSession"; +import { removeCrawlJob, addCrawlJob } from "@queues/crawl.queue"; +import { toIso } from "@utils/date"; + + +type DbCrawlSession = Awaited>; +type DbCrawlStatus = DbCrawlSession["status"]; +type DbCrawlTriggerType = DbCrawlSession["triggerType"]; + + +const mapSession = (session: DbCrawlSession): CrawlSessionData => ({ + id: session.id, + appVersionId: session.appVersionId, + status: fromDbCrawlStatus(session.status), + triggerType: fromDbCrawlTriggerType(session.triggerType), + crawlConfig: (() => { + const parsed = CrawlConfigSchema.safeParse(session.config); + return parsed.success ? parsed.data : {}; + })(), + stateCount: session.stateCount, + transitionCount: session.transitionCount, + createdAt: session.createdAt.toISOString(), + startedAt: toIso(session.startedAt), + finishedAt: toIso(session.finishedAt), + errorMessage: session.error ?? undefined, +}); + +export async function getSessions( + versionId: string, + query: GetSessionsQuery +): Promise { + const { page, pageSize, status, triggerType } = query; + const dbStatus = toDbCrawlStatusFilter(status); + const dbTriggerType = toDbCrawlTriggerTypeFilter(triggerType); + const [sessions, totalCount] = await Promise.all([ + prisma.crawlSession.findMany({ + where: { + appVersionId: versionId, + status: dbStatus, + triggerType: dbTriggerType, + }, + orderBy: { createdAt: 'desc' }, + skip: (page - 1) * pageSize, + take: pageSize, + }), + prisma.crawlSession.count({ + where: { + appVersionId: versionId, + status: dbStatus, + triggerType: dbTriggerType, + } + }) + ]); + + return { + sessions: sessions.map(mapSession), + totalCount: totalCount, + currentPage: page, + pageSize: pageSize, + }; +} + +export async function createSession( + versionId: string, + triggerType: CrawlTriggerType, + crawlConfig: CrawlConfig, +): Promise { + const parsedConfig = CrawlConfigSchema.parse(crawlConfig); + const persistedConfig = toPersistedCrawlConfig(parsedConfig); + + const newSession = await prisma.crawlSession.create({ + data: { + appVersionId: versionId, + triggerType: toDbCrawlTriggerType(triggerType) as unknown as DbCrawlTriggerType, + config: persistedConfig, + } + }); + return mapSession(newSession); +} + +export async function getSessionDetails(sessionId: string): Promise { + const session = await prisma.crawlSession.findUniqueOrThrow({ + where: { id: sessionId } + }); + return mapSession(session); +} + +export async function deleteSession(sessionId: string): Promise { + await removeCrawlJob(sessionId); + await prisma.crawlSession.delete({ + where: { id: sessionId } + }); +} + +export async function startSession(sessionId: string): Promise { + const session = await prisma.crawlSession.findUniqueOrThrow({ + where: { id: sessionId } + }); + + if (session.status === PrismaCrawlStatus.NEW) { + await prisma.crawlSession.update({ + where: { id: sessionId }, + data: { status: PrismaCrawlStatus.QUEUED } + }); + + try { + await addCrawlJob(sessionId); + } catch (error) { + await prisma.crawlSession.update({ + where: { id: sessionId }, + data: { status: PrismaCrawlStatus.NEW } + }); + throw error; + } + + return; + } + + if (session.status === PrismaCrawlStatus.PAUSED) { + await prisma.crawlSession.update({ + where: { id: sessionId }, + data: { status: PrismaCrawlStatus.RUNNING } + }); + return; + } + + throw new Error(`Cannot start session with status ${session.status}`); +}; + +export async function abortSession(sessionId: string): Promise { + const session = await prisma.crawlSession.findUniqueOrThrow({ + where: { id: sessionId } + }); + + if (session.status !== PrismaCrawlStatus.RUNNING && session.status !== PrismaCrawlStatus.PAUSED + && session.status !== PrismaCrawlStatus.QUEUED) { + throw new Error(`Cannot abort session with status ${session.status}`); + } + + await prisma.crawlSession.update({ + where: { id: sessionId }, + data: { status: PrismaCrawlStatus.ABORTED } + }); + + if (session.status === PrismaCrawlStatus.QUEUED) { + await removeCrawlJob(sessionId); + } +}; + +export async function pauseSession(sessionId: string): Promise { + const session = await prisma.crawlSession.findUniqueOrThrow({ + where: { id: sessionId } + }); + + if (session.status !== PrismaCrawlStatus.RUNNING) { + throw new Error(`Cannot pause session with status ${session.status}`); + } + + await prisma.crawlSession.update({ + where: { id: sessionId }, + data: { status: PrismaCrawlStatus.PAUSED } + }); +}; diff --git a/src/types/crawler.ts b/src/types/crawler.ts new file mode 100644 index 0000000..efea897 --- /dev/null +++ b/src/types/crawler.ts @@ -0,0 +1,28 @@ +// Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +// Proprietary and confidential. Unauthorized use is strictly prohibited. +// See LICENSE file in the project root for full license information. + +export type InputDefaultsConfig = { + fieldPatterns: Record; + typeFallbacks: Record; +}; + +export type CrawlerRunSettings = { + headless?: boolean; + timeoutMs?: number; + maxStates?: number; + maxTransitions?: number; + maxElementsPerState?: number; + maxSelectOptionsPerElement?: number; + maxActionRepeatsPerUrl?: number; + actionRetryCount?: number; + replayRetryCount?: number; + popupTimeoutMs?: number; + domQuietMs?: number; + domSettleTimeoutMs?: number; + useDomQuiescence?: boolean; + pageLoadState?: string; + clickNonHttpLinks?: boolean; + deferDestructiveActions?: boolean; + destructiveKeywords?: string; +}; diff --git a/src/utils/date.ts b/src/utils/date.ts new file mode 100644 index 0000000..72787ee --- /dev/null +++ b/src/utils/date.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 CoverIt Labs. All Rights Reserved. +// Proprietary and confidential. Unauthorized use is strictly prohibited. +// See LICENSE file in the project root for full license information. + +export function toIso(value: Date | null): string | undefined { + return value ? value.toISOString() : undefined; +} diff --git a/tsconfig.json b/tsconfig.json index c87e434..d26d1b2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,7 @@ "@lib/*": ["lib/*"], "@services/*": ["services/*"], "@utils/*": ["utils/*"], + "@mappers/*": ["mappers/*"], "@generated/*": ["generated/*"], "@models/*": ["models/*"], "@constants/*": ["constants/*"], diff --git a/vendor/coveritlabs-contracts-1.6.1.tgz b/vendor/coveritlabs-contracts-1.6.1.tgz new file mode 100644 index 0000000..bf90dcf Binary files /dev/null and b/vendor/coveritlabs-contracts-1.6.1.tgz differ