refactor: new eslint changes

This commit is contained in:
diced 2023-03-21 17:53:22 -07:00
parent 25606a80ec
commit 1b505d463c
No known key found for this signature in database
GPG key ID: 370BD1BA142842D1
48 changed files with 370 additions and 164 deletions

7
.eslintignore Normal file
View file

@ -0,0 +1,7 @@
node_modules
dist
.yarn
.devcontainer
.github
.next
.vscode

View file

@ -1,5 +1,13 @@
{
"extends": ["next", "next/core-web-vitals", "plugin:prettier/recommended"],
"root": true,
"extends": [
"next",
"next/core-web-vitals",
"plugin:prettier/recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": ["unused-imports", "@typescript-eslint"],
"parser": "@typescript-eslint/parser",
"rules": {
"linebreak-style": ["error", "unix"],
"quotes": [
@ -28,6 +36,14 @@
"react/style-prop-object": "warn",
"@next/next/no-img-element": "off",
"jsx-a11y/alt-text": "off",
"react/display-name": "off"
"react/display-name": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"error",
{ "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" }
],
"@typescript-eslint/ban-ts-comment": "off"
}
}

View file

@ -81,15 +81,18 @@
"@types/qrcode": "^1.5.0",
"@types/react": "^18.0.28",
"@types/sharp": "^0.31.1",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"cross-env": "^7.0.3",
"eslint": "^8.35.0",
"eslint": "^8.36.0",
"eslint-config-next": "^13.2.1",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-unused-imports": "^2.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.4",
"tsup": "^6.6.3",
"typescript": "^4.9.5"
"typescript": "^5.0.2"
},
"repository": {
"type": "git",

View file

@ -22,7 +22,6 @@ import {
IconFile,
IconFileDownload,
IconFolderMinus,
IconFolderOff,
IconFolderPlus,
IconFolderX,
IconHash,
@ -31,10 +30,9 @@ import {
IconPhotoCancel,
IconPhotoMinus,
IconPhotoStar,
IconStarFilled,
} from '@tabler/icons-react';
import useFetch from 'hooks/useFetch';
import { useFileDelete, useFileFavorite } from 'lib/queries/files';
import useFetch, { ApiError } from 'hooks/useFetch';
import { useFileDelete, useFileFavorite, UserFilesResponse } from 'lib/queries/files';
import { useFolders } from 'lib/queries/folders';
import { bytesToHuman } from 'lib/utils/bytes';
import { relativeTime } from 'lib/utils/client';
@ -54,7 +52,7 @@ export default function FileModal({
}: {
open: boolean;
setOpen: (open: boolean) => void;
file: any;
file: UserFilesResponse;
loading: boolean;
refresh: () => void;
reducedActions?: boolean;
@ -79,7 +77,7 @@ export default function FileModal({
});
},
onError: (res: any) => {
onError: (res: ApiError) => {
showNotification({
title: 'Failed to delete file',
message: res.error,
@ -123,7 +121,7 @@ export default function FileModal({
});
},
onError: (res: any) => {
onError: (res: { error: string }) => {
showNotification({
title: 'Failed to favorite file',
message: res.error,

View file

@ -48,6 +48,7 @@ import useFetch from 'hooks/useFetch';
import { useVersion } from 'lib/queries/version';
import { userSelector } from 'lib/recoil/user';
import { capitalize } from 'lib/utils/client';
import { UserExtended } from 'middleware/withZipline';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useState } from 'react';
@ -60,7 +61,7 @@ export type NavbarItems = {
text: string;
link?: string;
children?: NavbarItems[];
if?: (user: any, props: any) => boolean;
if?: (user: UserExtended, props: unknown) => boolean;
};
const items: NavbarItems[] = [
@ -120,7 +121,7 @@ const items: NavbarItems[] = [
icon: <IconTag size={18} />,
text: 'Invites',
link: '/dashboard/invites',
if: (_, props) => props.invites,
if: (_, props: { invites: boolean }) => props.invites,
},
],
},
@ -290,9 +291,9 @@ export default function Layout({ children, props }) {
</Navbar.Section>
<Navbar.Section>
{external_links.length
? external_links.map(({ label, link }, i) => (
? external_links.map(({ label, link }, i: number) => (
<NavLink
key={label}
key={i}
label={label}
target='_blank'
variant='light'

View file

@ -2,7 +2,7 @@
import Image from 'next/image';
export default function GoogleIcon({ colorScheme, ...props }) {
export default function GoogleIcon({ ...props }) {
return (
<Image
alt='google'

View file

@ -1,15 +1,4 @@
import {
ActionIcon,
Anchor,
Avatar,
Card,
Group,
SimpleGrid,
Skeleton,
Stack,
Title,
Tooltip,
} from '@mantine/core';
import { ActionIcon, Avatar, Card, Group, SimpleGrid, Skeleton, Stack, Title, Tooltip } from '@mantine/core';
import { useClipboard } from '@mantine/hooks';
import { useModals } from '@mantine/modals';
import { showNotification } from '@mantine/notifications';
@ -34,7 +23,6 @@ import { useFolders } from 'lib/queries/folders';
import { listViewFoldersSelector } from 'lib/recoil/settings';
import { relativeTime } from 'lib/utils/client';
import { DataTable, DataTableSortStatus } from 'mantine-datatable';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { useRecoilState } from 'recoil';

View file

@ -340,8 +340,7 @@ export default function Invites() {
</Tooltip>
<Tooltip label={new Date(invite.expiresAt).toLocaleString()}>
<div>
{/* @ts-ignore */}
<MutedText size='sm'>{expireText(new Date(invite.expiresAt))}</MutedText>
<MutedText size='sm'>{expireText(invite.expiresAt.toString())}</MutedText>
</div>
</Tooltip>
</Stack>

View file

@ -1,6 +1,5 @@
import { Anchor, Code } from '@mantine/core';
import { Code } from '@mantine/core';
import AnchorNext from 'components/AnchorNext';
import Link from 'next/link';
import { GeneratorModal } from './GeneratorModal';
export default function Flameshot({ user, open, setOpen }) {

View file

@ -1,5 +1,4 @@
import {
Anchor,
Box,
Button,
Checkbox,
@ -18,7 +17,6 @@ import { useForm } from '@mantine/form';
import { IconFileDownload, IconWorld } from '@tabler/icons-react';
import AnchorNext from 'components/AnchorNext';
import MutedText from 'components/MutedText';
import Link from 'next/link';
import { useReducer, useState } from 'react';
const DEFAULT_OD_DESC = 'Override the default domain(s). Type in a URL, e.g https://example.com';

View file

@ -1,4 +1,3 @@
import { useReducer, useState } from 'react';
import { GeneratorModal } from './GeneratorModal';
export default function ShareX({ user, open, setOpen }) {

View file

@ -2,7 +2,7 @@ import { Box, Card, Grid, LoadingOverlay, Title, useMantineTheme } from '@mantin
import { useStats } from 'lib/queries/stats';
import { bytesToHuman } from 'lib/utils/bytes';
import { useEffect, useMemo, useState } from 'react';
import { useMemo } from 'react';
import { CartesianGrid, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';

View file

@ -3,7 +3,7 @@ import { Box, Card, Center, Grid, LoadingOverlay, Title, useMantineTheme } from
import { SmallTable } from 'components/SmallTable';
import { useStats } from 'lib/queries/stats';
import { colorHash } from 'lib/utils/client';
import { useEffect, useMemo, useState } from 'react';
import { useMemo } from 'react';
import { Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts';

View file

@ -11,7 +11,7 @@ import {
Title,
} from '@mantine/core';
import { IconAlarm, IconEye, IconFileInfo, IconKey, IconPhotoDown, IconWorld } from '@tabler/icons-react';
import React, { Dispatch, SetStateAction, useReducer, useState } from 'react';
import React, { Dispatch, ReactNode, SetStateAction, useReducer, useState } from 'react';
export type UploadOptionsState = {
expires: string;
@ -37,7 +37,11 @@ export function OptionsModal({
opened: boolean;
setOpened: Dispatch<SetStateAction<boolean>>;
state: UploadOptionsState;
setState: Dispatch<SetStateAction<any>>;
setState: Dispatch<
SetStateAction<{
[key in keyof UploadOptionsState]?: UploadOptionsState[key];
}>
>;
reset: () => void;
}) {
const [odState, setODState] = useReducer((state, newState) => ({ ...state, ...newState }), {
@ -79,7 +83,7 @@ export function OptionsModal({
label='Max Views'
description='The maximum number of times this file can be viewed. Leave blank for unlimited views.'
value={state.maxViews}
onChange={(e) => setState({ maxViews: e })}
onChange={(e) => setState({ maxViews: e === '' ? undefined : e })}
min={0}
icon={<IconEye size='1rem' />}
/>
@ -206,7 +210,11 @@ export function OptionsModal({
);
}
export default function useUploadOptions(): [UploadOptionsState, Dispatch<SetStateAction<boolean>>, any] {
export default function useUploadOptions(): [
UploadOptionsState,
Dispatch<SetStateAction<boolean>>,
ReactNode
] {
const [state, setState] = useReducer((state, newState) => ({ ...state, ...newState }), {
expires: 'never',
password: '',

View file

@ -1,9 +1,9 @@
import { ActionIcon, Anchor, Card, Group, Stack, Title, Tooltip } from '@mantine/core';
import { ActionIcon, Card, Group, Stack, Title, Tooltip } from '@mantine/core';
import { IconClipboardCopy, IconExternalLink, IconTrash } from '@tabler/icons-react';
import AnchorNext from 'components/AnchorNext';
import MutedText from 'components/MutedText';
import { URLResponse } from 'lib/queries/url';
import { relativeTime } from 'lib/utils/client';
import Link from 'next/link';
export default function URLCard({
url,

View file

@ -1,6 +1,5 @@
import {
ActionIcon,
Anchor,
Button,
Card,
Center,
@ -28,11 +27,11 @@ import {
} from '@tabler/icons-react';
import AnchorNext from 'components/AnchorNext';
import MutedText from 'components/MutedText';
import { ApiError } from 'hooks/useFetch';
import { useURLDelete, useURLs } from 'lib/queries/url';
import { listViewUrlsSelector } from 'lib/recoil/settings';
import { userSelector } from 'lib/recoil/user';
import { DataTable, DataTableSortStatus } from 'mantine-datatable';
import Link from 'next/link';
import { useEffect, useState } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import URLCard from './URLCard';
@ -196,7 +195,7 @@ export default function Urls() {
});
},
onError: (url: any) => {
onError: (url: ApiError) => {
showNotification({
title: 'Failed to delete URL',
message: url.error,

View file

@ -2,24 +2,24 @@ import { Code } from '@mantine/core';
import { Prism } from '@mantine/prism';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { Language } from 'prism-react-renderer';
export default function Markdown({ code, ...props }) {
return (
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={{
code({ node, inline, className, children, ...props }) {
code({ inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
// @ts-ignore
<Prism language={match[1]} {...props}>
<Prism language={match[1] as Language} {...props}>
{String(children).replace(/\n$/, '')}
</Prism>
) : (
<Code {...props}>{children}</Code>
);
},
img({ node, ...props }) {
img(props) {
return <img {...props} style={{ maxWidth: '100%' }} />;
},
}}

View file

@ -7,5 +7,6 @@ if (!global.config) global.config = validateConfig(readConfig());
export default global.config as Config;
declare global {
// eslint-disable-next-line no-var
var config: Config;
}

View file

@ -7,11 +7,11 @@ import { humanToBytes } from 'utils/bytes';
export type ValueType = 'string' | 'number' | 'boolean' | 'array' | 'json-array' | 'human-to-byte' | 'path';
function isObject(value: any): value is Record<string, any> {
function isObject(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null;
}
function set(object: Record<string, any>, property: string, value: any) {
function set(object: Record<string, unknown> | unknown, property: string, value: unknown) {
const parts = property.split('.');
for (let i = 0; i < parts.length; ++i) {
@ -176,14 +176,14 @@ export default function readConfig() {
const value = process.env[map.env];
if (value) {
let parsed: any;
let parsed: unknown;
switch (map.type) {
case 'array':
parsed = value.split(',');
break;
case 'number':
parsed = Number(value);
if (isNaN(parsed)) {
if (isNaN(parsed as number)) {
parsed = undefined;
logger.debug(`Failed to parse number ${map.env}=${value}`);
}
@ -205,7 +205,8 @@ export default function readConfig() {
break;
case 'path':
parsed = resolve(value);
if (!existsSync(parsed)) logger.debug(`Unable to find ${map.env}=${value} (path does not exist)`);
if (!existsSync(parsed as string))
logger.debug(`Unable to find ${map.env}=${value} (path does not exist)`);
break;
default:
parsed = value;

View file

@ -26,5 +26,6 @@ if (!global.datasource) {
export default global.datasource as Datasource;
declare global {
// eslint-disable-next-line no-var
var datasource: Datasource;
}

View file

@ -4,7 +4,7 @@ import { join } from 'path';
import { Datasource } from '.';
export class Local extends Datasource {
public name: string = 'local';
public name = 'local';
public constructor(public path: string) {
super();

View file

@ -4,7 +4,7 @@ import { ConfigS3Datasource } from 'lib/config/Config';
import { Client } from 'minio';
export class S3 extends Datasource {
public name: string = 'S3';
public name = 'S3';
public s3: Client;
public constructor(public config: ConfigS3Datasource) {
@ -41,7 +41,7 @@ export class S3 extends Datasource {
}
public get(file: string): Promise<Readable> {
return new Promise((res, rej) => {
return new Promise((res) => {
this.s3.getObject(this.config.bucket, file, (err, stream) => {
if (err) res(null);
else res(stream);

View file

@ -5,7 +5,7 @@ import Logger from 'lib/logger';
import { Readable } from 'stream';
export class Supabase extends Datasource {
public name: string = 'Supabase';
public name = 'Supabase';
public logger: Logger = Logger.get('datasource::supabase');
public constructor(public config: ConfigSupabaseDatasource) {
@ -81,11 +81,12 @@ export class Supabase extends Datasource {
},
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return Readable.fromWeb(r.body as any);
}
public size(file: string): Promise<number> {
return new Promise(async (res, rej) => {
return new Promise(async (res) => {
fetch(`${this.config.url}/storage/v1/object/list/${this.config.bucket}`, {
method: 'POST',
headers: {
@ -114,7 +115,7 @@ export class Supabase extends Datasource {
}
public async fullSize(): Promise<number> {
return new Promise((res, rej) => {
return new Promise((res) => {
fetch(`${this.config.url}/storage/v1/object/list/${this.config.bucket}`, {
method: 'POST',
headers: {

View file

@ -1,7 +1,13 @@
export type ApiError = {
error: string;
code: number;
[key: string]: unknown;
};
export default async function useFetch(
url: string,
method: 'GET' | 'POST' | 'PATCH' | 'DELETE' = 'GET',
body: Record<string, any> = null
body: ApiError | Record<string, unknown> = null
) {
const headers = {};
if (body) headers['content-type'] = 'application/json';

View file

@ -21,10 +21,11 @@ export default class Logger {
return (process.env.LOGGER_FILTERS ?? '').split(',').filter((x) => x !== '');
}
static get(klass: any) {
// eslint-disable-next-line @typescript-eslint/ban-types
static get(klass: Function | string) {
if (typeof klass !== 'function') if (typeof klass !== 'string') throw new Error('not string/function');
const name = klass.name ?? klass;
const name = typeof klass === 'string' ? klass : klass.name;
return new Logger(name);
}
@ -44,7 +45,7 @@ export default class Logger {
return filters.includes(this.name);
}
info(...args: any[]): this {
info(...args: unknown[]): this {
if (!this.show()) return this;
process.stdout.write(this.formatMessage(LoggerLevel.INFO, this.name, args.join(' ')));
@ -52,17 +53,21 @@ export default class Logger {
return this;
}
error(...args: any[]): this {
error(...args: unknown[]): this {
if (!this.show()) return this;
process.stdout.write(
this.formatMessage(LoggerLevel.ERROR, this.name, args.map((error) => error.stack ?? error).join(' '))
this.formatMessage(
LoggerLevel.ERROR,
this.name,
args.map((error) => (typeof error === 'string' ? error : (error as Error).stack)).join(' ')
)
);
return this;
}
debug(...args: any[]): this {
debug(...args: unknown[]): this {
if (!process.env.DEBUG) return this;
if (!this.show()) return this;

View file

@ -143,7 +143,7 @@ export const withOAuth =
logger.debug(`attempting to refresh ${provider} account for ${user.username}`);
await prisma.oAuth.update({
where: {
id: userOauth!.id,
id: userOauth?.id,
},
data: {
token: oauth_resp.access_token,
@ -160,7 +160,7 @@ export const withOAuth =
} else if ((existingOauth && existingOauth.fallback) || existingOauth) {
await prisma.oAuth.update({
where: {
id: existingOauth!.id,
id: existingOauth?.id,
},
data: {
token: oauth_resp.access_token,

View file

@ -47,12 +47,12 @@ export type NextApiResExtra =
| 'notFound'
| 'error';
export type NextApiResExtraObj = {
[key in NextApiResExtra]: (message: any, extra?: Record<string, any>) => void;
[key in NextApiResExtra]: (message: string | number, extra?: Record<string, unknown>) => void;
};
export type NextApiRes = NextApiResponse &
NextApiResExtraObj & {
json: (json: Record<string, any>, status?: number) => void;
json: (json: Record<string, unknown>, status?: number) => void;
setCookie: (name: string, value: unknown, options: CookieSerializeOptions) => void;
setUserCookie: (id: number) => void;
};
@ -80,7 +80,7 @@ export const withZipline =
if (req.method === 'OPTIONS') return res.status(204).end();
// Used when the client sends wrong information, etc.
res.badRequest = (message: string, extra: Record<string, any> = {}) => {
res.badRequest = (message: string, extra: Record<string, unknown> = {}) => {
res.json(
{
error: message,
@ -92,7 +92,7 @@ export const withZipline =
};
// If the user is not logged in
res.unauthorized = (message: string, extra: Record<string, any> = {}) => {
res.unauthorized = (message: string, extra: Record<string, unknown> = {}) => {
res.json(
{
error: message,
@ -104,7 +104,7 @@ export const withZipline =
};
// If the user is logged in but doesn't have permission to do something
res.forbidden = (message: string, extra: Record<string, any> = {}) => {
res.forbidden = (message: string, extra: Record<string, unknown> = {}) => {
res.json(
{
error: message,
@ -115,7 +115,7 @@ export const withZipline =
);
};
res.notFound = (message: string, extra: Record<string, any> = {}) => {
res.notFound = (message: string, extra: Record<string, unknown> = {}) => {
res.json(
{
error: message,
@ -126,7 +126,7 @@ export const withZipline =
);
};
res.ratelimited = (message: number, extra: Record<string, any> = {}) => {
res.ratelimited = (message: number, extra: Record<string, unknown> = {}) => {
const retry = Math.floor(message / 1000);
res.setHeader('X-Ratelimit-Remaining', retry);
@ -140,7 +140,7 @@ export const withZipline =
);
};
res.json = (json: any, status: number = 200) => {
res.json = (json: unknown, status = 200) => {
res.setHeader('Content-Type', 'application/json');
res.status(status);
res.end(JSON.stringify(json));

View file

@ -7,5 +7,6 @@ if (!global.prisma) {
export default global.prisma as PrismaClient;
declare global {
// eslint-disable-next-line no-var
var prisma: PrismaClient;
}

View file

@ -10,6 +10,9 @@ export type UserFilesResponse = {
favorite: boolean;
url: string;
size: number;
maxViews: number;
views: number;
folderId?: number;
};
export const useFiles = (query: { [key: string]: string } = {}) => {
@ -30,7 +33,7 @@ export const useFiles = (query: { [key: string]: string } = {}) => {
);
});
};
export const usePaginatedFiles = (page?: number, filter: string = 'media', favorite = null) => {
export const usePaginatedFiles = (page?: number, filter = 'media', favorite = null) => {
const queryBuilder = new URLSearchParams({
page: Number(page || '1').toString(),
filter,

View file

@ -1,4 +1,4 @@
import { useMutation, useQuery } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import queryClient from './client';
import { UserFilesResponse } from './files';
@ -29,7 +29,7 @@ export const useFolders = (query: { [key: string]: string } = {}) => {
});
};
export const useFolder = (id: string, withFiles: boolean = false) => {
export const useFolder = (id: string, withFiles = false) => {
return useQuery<UserFoldersResponse>(['folder', id], async () => {
return fetch('/api/user/folders/' + id + (withFiles ? '?files=true' : ''))
.then((res) => res.json() as Promise<UserFoldersResponse>)

View file

@ -10,7 +10,7 @@ export type Stats = {
id: number;
data: {
count: number;
count_by_user: any[];
count_by_user: unknown[];
count_users: number;
size: string;
size_num: number;

View file

@ -15,6 +15,7 @@ import {
IconUser,
} from '@tabler/icons-react';
import { NextRouter } from 'next/router';
import { ReactNode } from 'react';
import { useRecoilValue } from 'recoil';
import { userSelector } from './recoil/user';
@ -35,7 +36,7 @@ export const createSpotlightActions = (router: NextRouter): SpotlightAction[] =>
title: string,
description: string,
link: string,
icon: any
icon: ReactNode
): SpotlightAction => {
return actionDo(group, title, description, icon, () => linkTo(link));
};
@ -44,7 +45,7 @@ export const createSpotlightActions = (router: NextRouter): SpotlightAction[] =>
group: string,
title: string,
description: string,
icon: any,
icon: ReactNode,
action: () => void
): SpotlightAction => {
return {

View file

@ -120,6 +120,6 @@ export async function getBase64URLFromURL(url: string) {
return `data:${res.headers.get('content-type')};base64,${base64}`;
}
export function notNull(a: any, b: any) {
export function notNull(a: unknown, b: unknown) {
return a !== null && b !== null;
}

View file

@ -5,7 +5,7 @@ import ms, { StringValue } from 'ms';
dayjs.extend(duration);
dayjs.extend(dayjsRelativeTime);
export function jsonUserReplacer(key: string, value: any) {
export function jsonUserReplacer(key: string, value: unknown) {
if (key === 'avatar') return 'data:image/*;base64,***';
return value;
@ -137,7 +137,7 @@ export function colorHash(str: string) {
let color = '#';
for (let i = 0; i < 3; i++) {
let value = (hash >> (i * 8)) & 0xff;
const value = (hash >> (i * 8)) & 0xff;
color += ('00' + value.toString(16)).substr(-2);
}

View file

@ -61,7 +61,7 @@ export function parseString(str: string, value: ParseValue) {
return str;
}
function modifier(mod: string, value: any): string {
function modifier(mod: string, value: unknown): string {
mod = mod.toLowerCase();
if (value instanceof Date) {

View file

@ -3,7 +3,7 @@ import MutedText from 'components/MutedText';
import Head from 'next/head';
import Link from 'next/link';
export default function Error({ statusCode, oauthError }) {
export default function Error({ statusCode }) {
return (
<>
<Head>

View file

@ -1,4 +1,3 @@
import datasource from 'lib/datasource';
import Logger from 'lib/logger';
import prisma from 'lib/prisma';
import { NextApiReq, NextApiRes, UserExtended, withZipline } from 'middleware/withZipline';

View file

@ -19,7 +19,7 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) {
return res.json(stats_data);
} else {
let amount = typeof req.query.amount === 'string' ? Number(req.query.amount) : 2;
const amount = typeof req.query.amount === 'string' ? Number(req.query.amount) : 2;
if (isNaN(amount)) return res.badRequest('invalid amount');
// get stats per day
@ -38,7 +38,7 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) {
if (!config.website.show_files_per_user) {
stats = stats.map((stat) => {
(stat.data as any).count_by_user = [];
(stat.data as Record<string, unknown>).count_by_user = [];
return stat;
});
}

View file

@ -1,6 +1,4 @@
import { InvisibleFile } from '@prisma/client';
import { randomUUID } from 'crypto';
import dayjs from 'dayjs';
import { readdir, readFile, unlink, writeFile } from 'fs/promises';
import zconfig from 'lib/config';
import datasource from 'lib/datasource';
@ -9,7 +7,7 @@ import formatFileName, { NameFormat, NameFormats } from 'lib/format';
import Logger from 'lib/logger';
import { NextApiReq, NextApiRes, withZipline } from 'lib/middleware/withZipline';
import prisma from 'lib/prisma';
import { createInvisImage, hashPassword, randomChars } from 'lib/util';
import { createInvisImage, hashPassword } from 'lib/util';
import { parseExpiry } from 'lib/utils/client';
import { removeGPSData } from 'lib/utils/exif';
import multer from 'multer';
@ -32,7 +30,7 @@ async function handler(req: NextApiReq, res: NextApiRes) {
if (!user) return res.forbidden('authorization incorrect');
await new Promise((resolve, reject) => {
uploader.array('file')(req as any, res as any, (result: unknown) => {
uploader.array('file')(req as never, res as never, (result: unknown) => {
if (result instanceof Error) reject(result.message);
resolve(result);
});
@ -127,7 +125,7 @@ async function handler(req: NextApiReq, res: NextApiRes) {
const ext = filename.split('.').length === 1 ? '' : filename.split('.').pop();
if (zconfig.uploader.disabled_extensions.includes(ext))
return res.error('disabled extension recieved: ' + ext);
let fileName = await formatFileName(format, filename);
const fileName = await formatFileName(format, filename);
let password = null;
if (req.headers.password) {

View file

@ -21,7 +21,7 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) {
if (req.method === 'DELETE') {
if (target.id === user.id) return res.badRequest("you can't delete your own account");
if (target.administrator && !user.superAdmin) return res.forbidden('cannot delete administrator');
let promises = [];
const promises = [];
promises.push(
prisma.user.delete({

View file

@ -34,7 +34,7 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) {
};
const backpressureThreshold = 65536;
let backpressure = [];
const backpressure = [];
let backpressureBytes = 0;
const push = stream.push;
stream.push = (dat, final) => {

View file

@ -48,7 +48,7 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) {
if (!page) return res.badRequest('no page');
if (isNaN(Number(page))) return res.badRequest('page is not a number');
let files: {
const files: {
favorite: boolean;
createdAt: Date;
id: number;

View file

@ -18,7 +18,7 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) {
return res.json(url);
} else {
let urls = await prisma.url.findMany({
const urls = await prisma.url.findMany({
where: {
userId: user.id,
},

View file

@ -21,7 +21,6 @@ import Link from 'next/link';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
export { getServerSideProps } from 'middleware/getServerSideProps';
import AnchorNext from 'components/AnchorNext';
export default function Login({ title, user_registration, oauth_registration, oauth_providers: unparsed }) {
const router = useRouter();

View file

@ -259,6 +259,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
},
};
}
// @ts-ignore
if (file.password) file.password = true;

View file

@ -1,9 +1,6 @@
import { PrismaClient } from '@prisma/client';
import { readdir, readFile } from 'fs/promises';
import { join } from 'path';
import config from 'lib/config';
import datasource from 'lib/datasource';
import { guess } from 'lib/mimes';
import { migrations } from 'server/util';
async function main() {

View file

@ -15,7 +15,7 @@ async function nextPlugin(fastify: FastifyInstance, options: NextServerOptions)
return nextServer.prepare();
function route(path, opts: any = { method: 'GET' }) {
function route(path, opts: { method: string | string[] } = { method: 'GET' }) {
if (typeof opts.method === 'string') this[opts.method.toLowerCase()](path, opts, handler);
else if (Array.isArray(opts.method)) {
for (const method of opts.method) this[method.toLowerCase()](path, opts, handler);

291
yarn.lock
View file

@ -1430,27 +1430,45 @@ __metadata:
languageName: node
linkType: hard
"@eslint/eslintrc@npm:^2.0.0":
version: 2.0.0
resolution: "@eslint/eslintrc@npm:2.0.0"
"@eslint-community/eslint-utils@npm:^4.2.0":
version: 4.3.0
resolution: "@eslint-community/eslint-utils@npm:4.3.0"
dependencies:
eslint-visitor-keys: ^3.3.0
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
checksum: f487760a692f0f1fef76e248ad72976919576ba57edc2b1b1dc1d182553bae6b5bf7b078e654da85d04f0af8a485d20bd26280002768f4fbcd2e330078340cb0
languageName: node
linkType: hard
"@eslint-community/regexpp@npm:^4.4.0":
version: 4.4.0
resolution: "@eslint-community/regexpp@npm:4.4.0"
checksum: 2d127af0c752b80e8a782eacfe996a86925d21de92da3ffc6f9e615e701145e44a62e26bdd88bfac2cd76779c39ba8d9875a91046ec5e7e5f23cb647c247ea6a
languageName: node
linkType: hard
"@eslint/eslintrc@npm:^2.0.1":
version: 2.0.1
resolution: "@eslint/eslintrc@npm:2.0.1"
dependencies:
ajv: ^6.12.4
debug: ^4.3.2
espree: ^9.4.0
espree: ^9.5.0
globals: ^13.19.0
ignore: ^5.2.0
import-fresh: ^3.2.1
js-yaml: ^4.1.0
minimatch: ^3.1.2
strip-json-comments: ^3.1.1
checksum: 31119c8ca06723d80384f18f5c78e0530d8e6306ad36379868650131a8b10dd7cffd7aff79a5deb3a2e9933660823052623d268532bae9538ded53d5b19a69a6
checksum: 56b9192a687a450db53a7b883daf9f0f447c43b3510189cf88808a7a2467c2a302a42a50f184cc6d5a9faf3d1df890a2ef0fd0d60b751f32a3e9dfea717c6b48
languageName: node
linkType: hard
"@eslint/js@npm:8.35.0":
version: 8.35.0
resolution: "@eslint/js@npm:8.35.0"
checksum: 6687ceff659a6d617e37823f809dc9c4b096535961a81acead27d26b1a51a4cf608a5e59d831ddd57f24f6f8bb99340a4a0e19f9c99b390fbb4b275f51ed5f5e
"@eslint/js@npm:8.36.0":
version: 8.36.0
resolution: "@eslint/js@npm:8.36.0"
checksum: b7d6b84b823c8c7784be390741196617565527b1f7c0977fde9455bfb57fd88f81c074a03dd878757d2c33fa29f24291e9ecbc1425710f067917324b55e1bf3a
languageName: node
linkType: hard
@ -2625,6 +2643,13 @@ __metadata:
languageName: node
linkType: hard
"@types/json-schema@npm:^7.0.9":
version: 7.0.11
resolution: "@types/json-schema@npm:7.0.11"
checksum: 527bddfe62db9012fccd7627794bd4c71beb77601861055d87e3ee464f2217c85fca7a4b56ae677478367bbd248dbde13553312b7d4dbc702a2f2bbf60c4018d
languageName: node
linkType: hard
"@types/json5@npm:^0.0.29":
version: 0.0.29
resolution: "@types/json5@npm:0.0.29"
@ -2777,6 +2802,13 @@ __metadata:
languageName: node
linkType: hard
"@types/semver@npm:^7.3.12":
version: 7.3.13
resolution: "@types/semver@npm:7.3.13"
checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0
languageName: node
linkType: hard
"@types/serve-static@npm:*":
version: 1.15.0
resolution: "@types/serve-static@npm:1.15.0"
@ -2820,6 +2852,30 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/eslint-plugin@npm:^5.56.0":
version: 5.56.0
resolution: "@typescript-eslint/eslint-plugin@npm:5.56.0"
dependencies:
"@eslint-community/regexpp": ^4.4.0
"@typescript-eslint/scope-manager": 5.56.0
"@typescript-eslint/type-utils": 5.56.0
"@typescript-eslint/utils": 5.56.0
debug: ^4.3.4
grapheme-splitter: ^1.0.4
ignore: ^5.2.0
natural-compare-lite: ^1.4.0
semver: ^7.3.7
tsutils: ^3.21.0
peerDependencies:
"@typescript-eslint/parser": ^5.0.0
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
typescript:
optional: true
checksum: 2eed4a4ed8279950ad553252e8623e947ffdee39b0d677a13f6e4e2d863ea1cbc5d683ff189e55d0de6fd5a25afd72d3c3a9ab7ae417d5405a21ead907e1b154
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:^5.42.0":
version: 5.46.0
resolution: "@typescript-eslint/parser@npm:5.46.0"
@ -2837,6 +2893,23 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:^5.56.0":
version: 5.56.0
resolution: "@typescript-eslint/parser@npm:5.56.0"
dependencies:
"@typescript-eslint/scope-manager": 5.56.0
"@typescript-eslint/types": 5.56.0
"@typescript-eslint/typescript-estree": 5.56.0
debug: ^4.3.4
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
typescript:
optional: true
checksum: eb25490290bd5e22f9c42603dedc0d2d8ee845553e3cf48ea377bd5dc22440d3463f8b84be637b6a2b37cd9ea56b21e4e43007a0a69998948d9c8965c03fe1aa
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:5.46.0":
version: 5.46.0
resolution: "@typescript-eslint/scope-manager@npm:5.46.0"
@ -2847,6 +2920,33 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:5.56.0":
version: 5.56.0
resolution: "@typescript-eslint/scope-manager@npm:5.56.0"
dependencies:
"@typescript-eslint/types": 5.56.0
"@typescript-eslint/visitor-keys": 5.56.0
checksum: bacac255ee52148cee6622be2811c0d7e25419058b89f1a11f4c1303faef4535a0a1237549f9556ec1d7a297c640ce4357183a1a8465d72e1393b7d8fb43874b
languageName: node
linkType: hard
"@typescript-eslint/type-utils@npm:5.56.0":
version: 5.56.0
resolution: "@typescript-eslint/type-utils@npm:5.56.0"
dependencies:
"@typescript-eslint/typescript-estree": 5.56.0
"@typescript-eslint/utils": 5.56.0
debug: ^4.3.4
tsutils: ^3.21.0
peerDependencies:
eslint: "*"
peerDependenciesMeta:
typescript:
optional: true
checksum: 3dd1fcfadad18790b900a3d90f6617904adb6b0e2bd1e1edb6ebf239e1399865ca9098647405385feb4252d8b2b4577883e6fd3ef8d00bdd521d6070972d486b
languageName: node
linkType: hard
"@typescript-eslint/types@npm:5.46.0":
version: 5.46.0
resolution: "@typescript-eslint/types@npm:5.46.0"
@ -2854,6 +2954,13 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/types@npm:5.56.0":
version: 5.56.0
resolution: "@typescript-eslint/types@npm:5.56.0"
checksum: 82ca11553bbb1bbfcaf7e7760b03c0d898940238dc002552c21af3e58f7d482c64c3c6cf0666521aff2a1e7b4b58bb6e4d9a00b1e4998a16b5039f5d288d003a
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:5.46.0":
version: 5.46.0
resolution: "@typescript-eslint/typescript-estree@npm:5.46.0"
@ -2872,6 +2979,42 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:5.56.0":
version: 5.56.0
resolution: "@typescript-eslint/typescript-estree@npm:5.56.0"
dependencies:
"@typescript-eslint/types": 5.56.0
"@typescript-eslint/visitor-keys": 5.56.0
debug: ^4.3.4
globby: ^11.1.0
is-glob: ^4.0.3
semver: ^7.3.7
tsutils: ^3.21.0
peerDependenciesMeta:
typescript:
optional: true
checksum: ec3e85201786aa9adddba7cb834a9f330a7f55c729ee9ccf847dbdc2f7437b760f3774152ccad6d0aa48d13fd78df766c880e3a7ca42e01a20aba0e1a1ed61c5
languageName: node
linkType: hard
"@typescript-eslint/utils@npm:5.56.0":
version: 5.56.0
resolution: "@typescript-eslint/utils@npm:5.56.0"
dependencies:
"@eslint-community/eslint-utils": ^4.2.0
"@types/json-schema": ^7.0.9
"@types/semver": ^7.3.12
"@typescript-eslint/scope-manager": 5.56.0
"@typescript-eslint/types": 5.56.0
"@typescript-eslint/typescript-estree": 5.56.0
eslint-scope: ^5.1.1
semver: ^7.3.7
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
checksum: 413e8d4bf7023ee5ba4f695b62e796a1f94930bb92fe5aa0cee58f63b9837116c23f618825a9c671f610e50f5630188b6059b4ed6b05a2a3336f01d8e977becb
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:5.46.0":
version: 5.46.0
resolution: "@typescript-eslint/visitor-keys@npm:5.46.0"
@ -2882,6 +3025,16 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:5.56.0":
version: 5.56.0
resolution: "@typescript-eslint/visitor-keys@npm:5.56.0"
dependencies:
"@typescript-eslint/types": 5.56.0
eslint-visitor-keys: ^3.3.0
checksum: 568fda40134e153d7befb59b55698f7919ba780d2d3431d8745feabf2e0fbb8aa7a02173b3c467dd20a0f6594e5248a1f82bb25d6c37827716d77452e86cad29
languageName: node
linkType: hard
"@zxing/text-encoding@npm:0.9.0":
version: 0.9.0
resolution: "@zxing/text-encoding@npm:0.9.0"
@ -5052,6 +5205,38 @@ __metadata:
languageName: node
linkType: hard
"eslint-plugin-unused-imports@npm:^2.0.0":
version: 2.0.0
resolution: "eslint-plugin-unused-imports@npm:2.0.0"
dependencies:
eslint-rule-composer: ^0.3.0
peerDependencies:
"@typescript-eslint/eslint-plugin": ^5.0.0
eslint: ^8.0.0
peerDependenciesMeta:
"@typescript-eslint/eslint-plugin":
optional: true
checksum: 8aa1e03e75da2a62a354065e0cb8fe370118c6f8d9720a32fe8c1da937de6adb81a4fed7d0d391d115ac9453b49029fb19f970d180a2cf3dba451fd4c20f0dc4
languageName: node
linkType: hard
"eslint-rule-composer@npm:^0.3.0":
version: 0.3.0
resolution: "eslint-rule-composer@npm:0.3.0"
checksum: c2f57cded8d1c8f82483e0ce28861214347e24fd79fd4144667974cd334d718f4ba05080aaef2399e3bbe36f7d6632865110227e6b176ed6daa2d676df9281b1
languageName: node
linkType: hard
"eslint-scope@npm:^5.1.1":
version: 5.1.1
resolution: "eslint-scope@npm:5.1.1"
dependencies:
esrecurse: ^4.3.0
estraverse: ^4.1.1
checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb
languageName: node
linkType: hard
"eslint-scope@npm:^7.1.1":
version: 7.1.1
resolution: "eslint-scope@npm:7.1.1"
@ -5062,24 +5247,6 @@ __metadata:
languageName: node
linkType: hard
"eslint-utils@npm:^3.0.0":
version: 3.0.0
resolution: "eslint-utils@npm:3.0.0"
dependencies:
eslint-visitor-keys: ^2.0.0
peerDependencies:
eslint: ">=5"
checksum: 0668fe02f5adab2e5a367eee5089f4c39033af20499df88fe4e6aba2015c20720404d8c3d6349b6f716b08fdf91b9da4e5d5481f265049278099c4c836ccb619
languageName: node
linkType: hard
"eslint-visitor-keys@npm:^2.0.0":
version: 2.1.0
resolution: "eslint-visitor-keys@npm:2.1.0"
checksum: e3081d7dd2611a35f0388bbdc2f5da60b3a3c5b8b6e928daffff7391146b434d691577aa95064c8b7faad0b8a680266bcda0a42439c18c717b80e6718d7e267d
languageName: node
linkType: hard
"eslint-visitor-keys@npm:^3.3.0":
version: 3.3.0
resolution: "eslint-visitor-keys@npm:3.3.0"
@ -5087,12 +5254,14 @@ __metadata:
languageName: node
linkType: hard
"eslint@npm:^8.35.0":
version: 8.35.0
resolution: "eslint@npm:8.35.0"
"eslint@npm:^8.36.0":
version: 8.36.0
resolution: "eslint@npm:8.36.0"
dependencies:
"@eslint/eslintrc": ^2.0.0
"@eslint/js": 8.35.0
"@eslint-community/eslint-utils": ^4.2.0
"@eslint-community/regexpp": ^4.4.0
"@eslint/eslintrc": ^2.0.1
"@eslint/js": 8.36.0
"@humanwhocodes/config-array": ^0.11.8
"@humanwhocodes/module-importer": ^1.0.1
"@nodelib/fs.walk": ^1.2.8
@ -5103,9 +5272,8 @@ __metadata:
doctrine: ^3.0.0
escape-string-regexp: ^4.0.0
eslint-scope: ^7.1.1
eslint-utils: ^3.0.0
eslint-visitor-keys: ^3.3.0
espree: ^9.4.0
espree: ^9.5.0
esquery: ^1.4.2
esutils: ^2.0.2
fast-deep-equal: ^3.1.3
@ -5127,24 +5295,23 @@ __metadata:
minimatch: ^3.1.2
natural-compare: ^1.4.0
optionator: ^0.9.1
regexpp: ^3.2.0
strip-ansi: ^6.0.1
strip-json-comments: ^3.1.0
text-table: ^0.2.0
bin:
eslint: bin/eslint.js
checksum: 6212173691d90b1bc94dd3d640e1f210374b30c3905fc0a15e501cf71c6ca52aa3d80ea7a9a245adaaed26d6019169e01fb6881b3f2885b188d37069c749308c
checksum: e9a961fc3b3de5cff5a1cb2c92eeffaa7e155a715489e30b3e1e76f186bd1255e0481e09564f2094733c0b1dbd3453499fb72ae7c043c83156e11e6d965b2304
languageName: node
linkType: hard
"espree@npm:^9.4.0":
version: 9.4.1
resolution: "espree@npm:9.4.1"
"espree@npm:^9.5.0":
version: 9.5.0
resolution: "espree@npm:9.5.0"
dependencies:
acorn: ^8.8.0
acorn-jsx: ^5.3.2
eslint-visitor-keys: ^3.3.0
checksum: 4d266b0cf81c7dfe69e542c7df0f246e78d29f5b04dda36e514eb4c7af117ee6cfbd3280e560571ed82ff6c9c3f0003c05b82583fc7a94006db7497c4fe4270e
checksum: a7f110aefb6407e0d3237aa635ab3cea87106ae63748dd23c67031afccc640d04c4209fca2daf16e2233c82efb505faead0fb84097478fd9cc6e8f8dd80bf99d
languageName: node
linkType: hard
@ -5166,6 +5333,13 @@ __metadata:
languageName: node
linkType: hard
"estraverse@npm:^4.1.1":
version: 4.3.0
resolution: "estraverse@npm:4.3.0"
checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827
languageName: node
linkType: hard
"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0":
version: 5.3.0
resolution: "estraverse@npm:5.3.0"
@ -8141,6 +8315,13 @@ __metadata:
languageName: node
linkType: hard
"natural-compare-lite@npm:^1.4.0":
version: 1.4.0
resolution: "natural-compare-lite@npm:1.4.0"
checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225
languageName: node
linkType: hard
"natural-compare@npm:^1.4.0":
version: 1.4.0
resolution: "natural-compare@npm:1.4.0"
@ -9680,13 +9861,6 @@ __metadata:
languageName: node
linkType: hard
"regexpp@npm:^3.2.0":
version: 3.2.0
resolution: "regexpp@npm:3.2.0"
checksum: a78dc5c7158ad9ddcfe01aa9144f46e192ddbfa7b263895a70a5c6c73edd9ce85faf7c0430e59ac38839e1734e275b9c3de5c57ee3ab6edc0e0b1bdebefccef8
languageName: node
linkType: hard
"remark-gfm@npm:^3.0.1":
version: 3.0.1
resolution: "remark-gfm@npm:3.0.1"
@ -11070,23 +11244,23 @@ __metadata:
languageName: node
linkType: hard
"typescript@npm:^4.9.5":
version: 4.9.5
resolution: "typescript@npm:4.9.5"
"typescript@npm:^5.0.2":
version: 5.0.2
resolution: "typescript@npm:5.0.2"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: ee000bc26848147ad423b581bd250075662a354d84f0e06eb76d3b892328d8d4440b7487b5a83e851b12b255f55d71835b008a66cbf8f255a11e4400159237db
checksum: bef1dcd166acfc6934b2ec4d72f93edb8961a5fab36b8dd2aaf6f4f4cd5c0210f2e0850aef4724f3b4913d5aef203a94a28ded731b370880c8bcff7e4ff91fc1
languageName: node
linkType: hard
"typescript@patch:typescript@^4.9.5#~builtin<compat/typescript>":
version: 4.9.5
resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin<compat/typescript>::version=4.9.5&hash=ad5954"
"typescript@patch:typescript@^5.0.2#~builtin<compat/typescript>":
version: 5.0.2
resolution: "typescript@patch:typescript@npm%3A5.0.2#~builtin<compat/typescript>::version=5.0.2&hash=ad5954"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 8f6260acc86b56bfdda6004bc53f32ea548f543e8baef7071c8e34d29d292f3e375c8416556c8de10b24deef6933cd1c16a8233dc84a3dd43a13a13265d0faab
checksum: bdbf3d0aac0d6cf010fbe0536753dc19f278eb4aba88140dcd25487dfe1c56ca8b33abc0dcd42078790a939b08ebc4046f3e9bb961d77d3d2c3cfa9829da4d53
languageName: node
linkType: hard
@ -11713,16 +11887,19 @@ __metadata:
"@types/qrcode": ^1.5.0
"@types/react": ^18.0.28
"@types/sharp": ^0.31.1
"@typescript-eslint/eslint-plugin": ^5.56.0
"@typescript-eslint/parser": ^5.56.0
argon2: ^0.30.3
cookie: ^0.5.0
cross-env: ^7.0.3
dayjs: ^1.11.7
dotenv: ^16.0.3
dotenv-expand: ^10.0.0
eslint: ^8.35.0
eslint: ^8.36.0
eslint-config-next: ^13.2.1
eslint-config-prettier: ^8.6.0
eslint-plugin-prettier: ^4.2.1
eslint-plugin-unused-imports: ^2.0.0
exiftool-vendored: ^21.2.0
fastify: ^4.13.0
fastify-plugin: ^4.5.0
@ -11748,7 +11925,7 @@ __metadata:
remark-gfm: ^3.0.1
sharp: ^0.31.3
tsup: ^6.6.3
typescript: ^4.9.5
typescript: ^5.0.2
languageName: unknown
linkType: soft