diff --git a/.eslintrc.js b/.eslintrc.js index 86db7fe..ef51ff1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,6 +5,7 @@ module.exports = { 'linebreak-style': ['error', 'unix'], 'quotes': ['error', 'single'], 'semi': ['error', 'always'], + 'comma-dangle': ['error', 'always-multiline'], 'jsx-quotes': ['error', 'prefer-single'], 'react/prop-types': 'off', 'react-hooks/rules-of-hooks': 'off', @@ -19,6 +20,6 @@ module.exports = { 'react/react-in-jsx-scope': 'error', 'react/require-render-return': 'error', 'react/style-prop-object': 'warn', - '@next/next/no-img-element': 'off' - } + '@next/next/no-img-element': 'off', + }, }; diff --git a/Dockerfile b/Dockerfile index db5c5c5..5f513c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ COPY package.json yarn.lock next.config.js next-env.d.ts zip-env.d.ts tsconfig.j RUN yarn install # create a mock config.toml to spoof next build! -RUN echo -e "[uploader]\nroute = '/u'" > config.toml +RUN echo -e "[core]\nsecret = '12345678'\ndatabase_url = 'postgres://postgres:postgres@postgres/postgres'\n[uploader]\nroute = '/u'\ndirectory = './uploads'\n[urls]\nroute = '/go'" > config.toml RUN yarn build diff --git a/package.json b/package.json index a3f6777..6ca48b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zip3", - "version": "3.2.3", + "version": "3.2.4", "scripts": { "prepare": "husky install", "dev": "NODE_ENV=development node server", @@ -9,7 +9,7 @@ "build:schema": "prisma generate --schema=prisma/schema.prisma", "start": "node server", "lint": "next lint", - "ts-node": "ts-node --compiler-options \"{\\\"module\\\":\\\"commonjs\\\"}\" --transpile-only", + "seed": "ts-node --compiler-options \"{\\\"module\\\":\\\"commonjs\\\"}\" --transpile-only prisma/seed.ts", "semantic-release": "semantic-release" }, "dependencies": { @@ -19,7 +19,7 @@ "@material-ui/core": "^5.0.0-alpha.37", "@material-ui/icons": "^5.0.0-alpha.37", "@material-ui/styles": "^5.0.0-alpha.35", - "@prisma/client": "^3.0.2", + "@prisma/client": "^3.1.1", "@reduxjs/toolkit": "^1.6.0", "argon2": "^0.28.2", "colorette": "^1.2.2", @@ -29,7 +29,7 @@ "formik": "^2.2.9", "multer": "^1.4.2", "next": "11.1.1", - "prisma": "^3.0.2", + "prisma": "^3.1.1", "react": "17.0.2", "react-dom": "17.0.2", "react-dropzone": "^11.3.2", diff --git a/prisma/migrations/20210924045900_delete_url/migration.sql b/prisma/migrations/20210924045900_delete_url/migration.sql new file mode 100644 index 0000000..37ffc11 --- /dev/null +++ b/prisma/migrations/20210924045900_delete_url/migration.sql @@ -0,0 +1,39 @@ +/* + Warnings: + + - You are about to drop the `InvisibleUrl` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `Url` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "Image" DROP CONSTRAINT "Image_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "InvisibleImage" DROP CONSTRAINT "InvisibleImage_imageId_fkey"; + +-- DropForeignKey +ALTER TABLE "InvisibleUrl" DROP CONSTRAINT "InvisibleUrl_id_fkey"; + +-- DropForeignKey +ALTER TABLE "Theme" DROP CONSTRAINT "Theme_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "Url" DROP CONSTRAINT "Url_userId_fkey"; + +-- DropTable +DROP TABLE "InvisibleUrl"; + +-- DropTable +DROP TABLE "Url"; + +-- AddForeignKey +ALTER TABLE "Theme" ADD CONSTRAINT "Theme_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Image" ADD CONSTRAINT "Image_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "InvisibleImage" ADD CONSTRAINT "InvisibleImage_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "Image"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- RenameIndex +ALTER INDEX "InvisibleImage.invis_unique" RENAME TO "InvisibleImage_invis_key"; diff --git a/prisma/migrations/20210924050753_new_url/migration.sql b/prisma/migrations/20210924050753_new_url/migration.sql new file mode 100644 index 0000000..fc01f93 --- /dev/null +++ b/prisma/migrations/20210924050753_new_url/migration.sql @@ -0,0 +1,34 @@ +-- CreateTable +CREATE TABLE "Url" ( + "id" TEXT NOT NULL, + "destination" TEXT NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "views" INTEGER NOT NULL DEFAULT 0, + "userId" INTEGER NOT NULL, + + CONSTRAINT "Url_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "InvisibleUrl" ( + "id" SERIAL NOT NULL, + "invis" TEXT NOT NULL, + "urlId" TEXT NOT NULL, + + CONSTRAINT "InvisibleUrl_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Url_id_key" ON "Url"("id"); + +-- CreateIndex +CREATE UNIQUE INDEX "InvisibleUrl_invis_key" ON "InvisibleUrl"("invis"); + +-- CreateIndex +CREATE UNIQUE INDEX "InvisibleUrl_urlId_unique" ON "InvisibleUrl"("urlId"); + +-- AddForeignKey +ALTER TABLE "Url" ADD CONSTRAINT "Url_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "InvisibleUrl" ADD CONSTRAINT "InvisibleUrl_urlId_fkey" FOREIGN KEY ("urlId") REFERENCES "Url"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20210925030428_vanity_url/migration.sql b/prisma/migrations/20210925030428_vanity_url/migration.sql new file mode 100644 index 0000000..41aefc8 --- /dev/null +++ b/prisma/migrations/20210925030428_vanity_url/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Url" ADD COLUMN "vanity" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c56f665..56aa597 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -57,17 +57,19 @@ model InvisibleImage { } model Url { - id Int @id @default(autoincrement()) - to String - created_at DateTime @default(now()) - views Int @default(0) - invisible InvisibleUrl? - user User @relation(fields: [userId], references: [id]) - userId Int + id String @id @unique + destination String + vanity String? + created_at DateTime @default(now()) + views Int @default(0) + invisible InvisibleUrl? + user User @relation(fields: [userId], references: [id]) + userId Int } model InvisibleUrl { - id Int - url Url @relation(fields: [id], references: [id]) + id Int @id @default(autoincrement()) invis String @unique + urlId String + url Url @relation(fields: [urlId], references: [id]) } diff --git a/server/index.js b/server/index.js index ad85ee0..9297bec 100644 --- a/server/index.js +++ b/server/index.js @@ -34,10 +34,11 @@ function shouldUseYarn() { (async () => { try { - const config = await validateConfig(readConfig()); + const a = readConfig(); + const config = await validateConfig(a); const data = await prismaRun(config.core.database_url, ['migrate', 'status'], true); - if (data.includes('Following migration have not yet been applied:')) { + if (data.includes('Following migrations have not yet been applied:')) { Logger.get('database').info('some migrations are not applied, applying them now...'); await deployDb(config); Logger.get('database').info('finished applying migrations'); @@ -49,7 +50,7 @@ function shouldUseYarn() { const app = next({ dir: '.', dev, - quiet: dev + quiet: dev, }, config.core.port, config.core.host); await app.prepare(); @@ -67,15 +68,15 @@ function shouldUseYarn() { where: { OR: [ { file: parts[2] }, - { invisible:{ invis: decodeURI(parts[2]) } } - ] + { invisible:{ invis: decodeURI(parts[2]) } }, + ], }, select: { mimetype: true, id: true, file: true, - invisible: true - } + invisible: true, + }, }); if (!image) { @@ -92,7 +93,7 @@ function shouldUseYarn() { await prisma.image.update({ where: { id: image.id }, - data: { views: { increment: 1 } } + data: { views: { increment: 1 } }, }); res.setHeader('Content-Type', image.mimetype); res.end(data); diff --git a/server/validateConfig.js b/server/validateConfig.js index a211630..26c86bc 100644 --- a/server/validateConfig.js +++ b/server/validateConfig.js @@ -18,11 +18,16 @@ const validator = yup.object({ user_limit: yup.number().default(104900000), disabled_extensions: yup.array().default([]), }).required(), + urls: yup.object({ + route: yup.string().required(), + length: yup.number().default(6), + }).required(), }); -module.exports = async config => { + +module.exports = config => { try { - return await validator.validate(config, { abortEarly: false }); + return validator.validateSync(config, { abortEarly: false }); } catch (e) { throw `${e.errors.length} errors occured\n${e.errors.map(x => '\t' + x).join('\n')}`; } diff --git a/src/lib/config.ts b/src/lib/config.ts index 13f3886..a54937a 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -1,6 +1,7 @@ import type { Config } from './types'; import readConfig from './readConfig'; +import validateConfig from '../../server/validateConfig'; -if (!global.config) global.config = readConfig() as Config; +if (!global.config) global.config = validateConfig(readConfig()) as unknown as Config; export default global.config; \ No newline at end of file diff --git a/src/lib/logger.js b/src/lib/logger.js index 2f1518f..4ac1360 100644 --- a/src/lib/logger.js +++ b/src/lib/logger.js @@ -1,5 +1,5 @@ const { format } = require('fecha'); -const { yellow, blueBright, magenta, red, cyan } = require('colorette'); +const { blueBright, red, cyan } = require('colorette'); class Logger { static get(clas) { diff --git a/src/lib/readConfig.js b/src/lib/readConfig.js index c42a433..3050bd9 100644 --- a/src/lib/readConfig.js +++ b/src/lib/readConfig.js @@ -10,12 +10,16 @@ const envValues = [ e('HOST', 'string', (c, v) => c.core.host = v), e('PORT', 'number', (c, v) => c.core.port = v), e('DATABASE_URL', 'string', (c, v) => c.core.database_url = v), + e('UPLOADER_ROUTE', 'string', (c, v) => c.uploader.route = v), e('UPLOADER_LENGTH', 'number', (c, v) => c.uploader.length = v), e('UPLOADER_DIRECTORY', 'string', (c, v) => c.uploader.directory = v), e('UPLOADER_ADMIN_LIMIT', 'number', (c, v) => c.uploader.admin_limit = v), e('UPLOADER_USER_LIMIT', 'number', (c, v) => c.uploader.user_limit = v), e('UPLOADER_DISABLED_EXTS', 'array', (c, v) => v ? c.uploader.disabled_extentions = v : c.uploader.disabled_extentions = []), + + e('URLS_ROUTE', 'string', (c, v) => c.urls.route = v), + e('URLS_LENGTH', 'number', (c, v) => c.urls.length = v), ]; module.exports = () => { @@ -46,8 +50,12 @@ function tryReadEnv() { directory: undefined, admin_limit: undefined, user_limit: undefined, - disabled_extentions: undefined - } + disabled_extentions: undefined, + }, + urls: { + route: undefined, + length: undefined, + }, }; for (let i = 0, L = envValues.length; i !== L; ++i) { diff --git a/src/lib/types.ts b/src/lib/types.ts index c9758f8..07aa294 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -35,7 +35,16 @@ export interface ConfigUploader { disabled_extentions: string[]; } +export interface ConfigUrls { + // The route urls will be served on + route: string; + + // Length of random chars to generate for urls + length: number; +} + export interface Config { core: ConfigCore; uploader: ConfigUploader; + urls: ConfigUrls; } \ No newline at end of file diff --git a/src/lib/util.ts b/src/lib/util.ts index 6a0e7c9..7e2a2ab 100644 --- a/src/lib/util.ts +++ b/src/lib/util.ts @@ -3,7 +3,7 @@ import { hash, verify } from 'argon2'; import { readdir, stat } from 'fs/promises'; import { join } from 'path'; import prisma from './prisma'; -import { InvisibleImage } from '@prisma/client'; +import { InvisibleImage, InvisibleUrl } from '@prisma/client'; export async function hashPassword(s: string): Promise { return await hash(s); @@ -89,21 +89,21 @@ export function bytesToRead(bytes: number) { return `${bytes.toFixed(1)} ${units[num]}`; } -export function createInvisURL(length: number) { +export function randomInvis(length: number) { // some parts from https://github.com/tycrek/ass/blob/master/generators/lengthGen.js const invisibleCharset = ['\u200B', '\u2060', '\u200C', '\u200D']; return [...randomBytes(length)].map((byte) => invisibleCharset[Number(byte) % invisibleCharset.length]).join('').slice(1).concat(invisibleCharset[0]); } -export function createInvis(length: number, imageId: number) { +export function createInvisImage(length: number, imageId: number) { const retry = async (): Promise => { - const invis = createInvisURL(length); + const invis = randomInvis(length); const existing = await prisma.invisibleImage.findUnique({ where: { - invis - } + invis, + }, }); if (existing) return retry(); @@ -111,12 +111,37 @@ export function createInvis(length: number, imageId: number) { const inv = await prisma.invisibleImage.create({ data: { invis, - imageId - } + imageId, + }, }); return inv; }; + return retry(); +} + +export function createInvisURL(length: number, urlId: string) { + const retry = async (): Promise => { + const invis = randomInvis(length); + + const existing = await prisma.invisibleUrl.findUnique({ + where: { + invis, + }, + }); + + if (existing) return retry(); + + const ur = await prisma.invisibleUrl.create({ + data: { + invis, + urlId, + }, + }); + + return ur; + }; + return retry(); } \ No newline at end of file diff --git a/src/pages/[...id].tsx b/src/pages/[...id].tsx index 11f4b55..c1d1491 100644 --- a/src/pages/[...id].tsx +++ b/src/pages/[...id].tsx @@ -58,62 +58,86 @@ export default function EmbeddedImage({ image, title, username, color, normal, e export const getServerSideProps: GetServerSideProps = async (context) => { const id = context.params.id[1]; const route = context.params.id[0]; - if (route !== config.uploader.route.substring(1)) return { notFound: true }; + const routes = [config.uploader.route.substring(1), config.urls.route.substring(1)]; + if (!routes.includes(route)) return { notFound: true }; - const image = await prisma.image.findFirst({ - where: { - OR: [ - { file: id }, - { invisible: { invis: id } } - ] - }, - select: { - mimetype: true, - id: true, - file: true, - invisible: true, - userId: true, - embed: true - } - }); + if (route === routes[1]) { + const url = await prisma.url.findFirst({ + where: { + OR: [ + { id }, + { vanity: id }, + { invisible: { invis: id } }, + ], + }, + select: { + destination: true, + }, + }); + if (!url) return { notFound: true }; - if (!image) return { notFound: true }; + return { + props: {}, + redirect: { + destination: url.destination, + }, + }; - if (!image.embed) { - const data = await getFile(config.uploader.directory, id); - if (!data) return { notFound: true }; + } else { + const image = await prisma.image.findFirst({ + where: { + OR: [ + { file: id }, + { invisible: { invis: id } }, + ], + }, + select: { + mimetype: true, + id: true, + file: true, + invisible: true, + userId: true, + embed: true, + }, + }); + if (!image) return { notFound: true }; - context.res.end(data); - return { props: {} }; - }; + if (!image.embed) { + const data = await getFile(config.uploader.directory, id); + if (!data) return { notFound: true }; - const user = await prisma.user.findFirst({ - select: { - embedTitle: true, - embedColor: true, - username: true - }, - where: { - id: image.userId - } - }); + context.res.end(data); + return { props: {} }; + }; + + const user = await prisma.user.findFirst({ + select: { + embedTitle: true, + embedColor: true, + username: true, + }, + where: { + id: image.userId, + }, + }); - if (!image.mimetype.startsWith('image')) { - const data = await getFile(config.uploader.directory, id); - if (!data) return { notFound: true }; + if (!image.mimetype.startsWith('image')) { + const data = await getFile(config.uploader.directory, id); + if (!data) return { notFound: true }; - context.res.end(data); - return { props: {} }; - }; + context.res.end(data); + return { props: {} }; + }; - return { - props: { - image, - title: user.embedTitle, - color: user.embedColor, - username: user.username, - normal: config.uploader.route, - embed: image.embed - } - }; + return { + props: { + image, + title: user.embedTitle, + color: user.embedColor, + username: user.username, + normal: config.uploader.route, + embed: image.embed, + }, + }; + } }; diff --git a/src/pages/api/shorten.ts b/src/pages/api/shorten.ts new file mode 100644 index 0000000..da7d34d --- /dev/null +++ b/src/pages/api/shorten.ts @@ -0,0 +1,39 @@ +import prisma from 'lib/prisma'; +import zconfig from 'lib/config'; +import { NextApiReq, NextApiRes, withZipline } from 'lib/middleware/withZipline'; +import { createInvisURL, randomChars } from 'lib/util'; +import Logger from 'lib/logger'; + +async function handler(req: NextApiReq, res: NextApiRes) { + if (req.method !== 'POST') return res.forbid('no allow'); + if (!req.headers.authorization) return res.forbid('no authorization'); + + const user = await prisma.user.findFirst({ + where: { + token: req.headers.authorization, + }, + }); + + if (!user) return res.forbid('authorization incorect'); + if (!req.body) return res.error('no body'); + if (!req.body.url) return res.error('no url'); + const rand = randomChars(zconfig.urls.length); + + let invis; + const url = await prisma.url.create({ + data: { + id: rand, + vanity: req.body.vanity ?? null, + destination: req.body.url, + userId: user.id, + }, + }); + + if (req.headers.zws) invis = await createInvisURL(zconfig.urls.length, url.id); + + Logger.get('url').info(`User ${user.username} (${user.id}) shortenned a url ${url.destination} (${url.id})`); + + return res.json({ url: `${zconfig.core.secure ? 'https' : 'http'}://${req.headers.host}${zconfig.urls.route}/${req.body.vanity ? req.body.vanity : invis ? invis.invis : url.id}` }); +} + +export default withZipline(handler); \ No newline at end of file diff --git a/src/pages/api/upload.ts b/src/pages/api/upload.ts index ce22543..10c7a83 100644 --- a/src/pages/api/upload.ts +++ b/src/pages/api/upload.ts @@ -2,7 +2,7 @@ import multer from 'multer'; import prisma from 'lib/prisma'; import zconfig from 'lib/config'; import { NextApiReq, NextApiRes, withZipline } from 'lib/middleware/withZipline'; -import { createInvis, randomChars } from 'lib/util'; +import { createInvisImage, randomChars } from 'lib/util'; import { writeFile } from 'fs/promises'; import { join } from 'path'; import Logger from 'lib/logger'; @@ -46,7 +46,7 @@ async function handler(req: NextApiReq, res: NextApiRes) { } }); - if (req.headers.zws) invis = await createInvis(zconfig.uploader.length, image.id); + if (req.headers.zws) invis = await createInvisImage(zconfig.uploader.length, image.id); await writeFile(join(process.cwd(), zconfig.uploader.directory, image.file), file.buffer); Logger.get('image').info(`User ${user.username} (${user.id}) uploaded an image ${image.file} (${image.id})`); diff --git a/src/pages/dashboard/upload.tsx b/src/pages/dashboard/upload.tsx index e45b0a8..59a9928 100644 --- a/src/pages/dashboard/upload.tsx +++ b/src/pages/dashboard/upload.tsx @@ -24,8 +24,8 @@ export default function UploadPage({ route }) { export const getStaticProps: GetStaticProps = async (context) => { return { props: { - route: config.uploader.route - } + route: config.uploader.route, + }, }; }; diff --git a/yarn.lock b/yarn.lock index 1a0e8f9..ea694af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -602,22 +602,22 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353" integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q== -"@prisma/client@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.0.2.tgz#f04d9b252f3d0c6918df43ad228eac27d03f6db1" - integrity sha512-6SrDYY2Yr5AmYpVB3XAXFqfzxKMdDTemXR7FmfXthnxWhQHoBwRLNZ3B3GyI/MmWa5tr+kaaGDJjp1LU0vuYvQ== +"@prisma/client@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.1.1.tgz#f4012631528049c22d12b212846dcf503db33cfe" + integrity sha512-8ud8vVFMIg37yrkZ4wPpjKoMxFbCL0Pesq5eyLnag/s0LTKsVEN7ZBIQq9JzWW+AUqOzGKXr2Jt4Sl8xdGI99w== dependencies: - "@prisma/engines-version" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" + "@prisma/engines-version" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" -"@prisma/engines-version@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db": - version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#c45323e420f47dd950b22c873bdcf38f75e65779" - integrity sha512-iArSApZZImVmT9oC/rGOjzvpG2AOqlIeqYcVnop9poA3FxD4zfVPbNPH9DTgOWhc06OkBHujJZeAcsNddVabIQ== +"@prisma/engines-version@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f": + version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#f9908eb7808f2a546634398063942eaecb2474ef" + integrity sha512-EuEMKLuwIcBO7uInZQHeG1yaywcfl32Tq8TDf5tgLvblk+ka70sej7S67lh3BV5gXMLTc3GdthSHPfDqZEK5uA== -"@prisma/engines@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db": - version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#b6cf70bc05dd2a62168a16f3ea58a1b011074621" - integrity sha512-Q9CwN6e5E5Abso7J3A1fHbcF4NXGRINyMnf7WQ07fXaebxTTARY5BNUzy2Mo5uH82eRVO5v7ImNuR044KTjLJg== +"@prisma/engines@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f": + version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#7b45708e6a42523dc9bc2214e5c62781f608dc3a" + integrity sha512-6NEp0VlLho3hVtIvj2P4h0e19AYqQSXtFGts8gSIXDnV+l5pRFZaDMfGo2RiLMR0Kfrs8c3ZYxYX0sWmVL0tWw== "@reduxjs/toolkit@^1.6.0": version "1.6.0" @@ -4434,12 +4434,12 @@ prepend-http@^1.0.1: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= -prisma@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.0.2.tgz#e86cb6abf4a815c7ac97b9d0ed383f01c253ce34" - integrity sha512-TyOCbtWGDVdWvsM1RhUzJXoGClXGalHhyYWIc5eizSF8T1ScGiOa34asBUdTnXOUBFSErbsqMNw40DHAteBm1A== +prisma@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.1.1.tgz#4c13c35dd3a58af9134008c8ed0fdc21a632802c" + integrity sha512-+eZtWIL6hnOKUOvqq9WLBzSw2d/EbTmOx1Td1LI8/0XE40ctXMLG2N1p6NK5/+yivGaoNJ9PDpPsPL9lO4nJrQ== dependencies: - "@prisma/engines" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" + "@prisma/engines" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" process-nextick-args@~2.0.0: version "2.0.1"