From 493e1b76506c99457aec295130d324645c1fdd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl-Gerhard=20Lindesva=CC=88rd?= Date: Thu, 2 Nov 2023 12:14:37 +0100 Subject: [PATCH] added tooling (eslint, typescript and prettier) --- .gitignore | 1 + .vscode/extensions.json | 7 + .vscode/settings.json | 23 + apps/web/components.json | 2 +- apps/web/next.config.mjs | 6 +- apps/web/package.json | 32 +- apps/web/prettier.config.mjs | 2 +- apps/web/src/_middleware.ts | 4 +- .../components/report/hooks/useReportId.ts | 6 +- apps/web/src/components/report/reportSlice.ts | 56 +- apps/web/src/components/ui/use-toast.ts | 150 ++-- apps/web/src/env.mjs | 14 +- apps/web/src/hooks/useFormatDateInterval.ts | 37 +- apps/web/src/hooks/useMappings.ts | 8 +- apps/web/src/hooks/useOrganizationParams.ts | 9 +- apps/web/src/hooks/useQueryParams.ts | 7 +- apps/web/src/hooks/useRefetchActive.ts | 8 +- apps/web/src/hooks/useRouterBeforeLeave.ts | 12 +- apps/web/src/mappings.json | 290 ++++---- apps/web/src/pages/_app.tsx | 34 +- apps/web/src/pages/api/auth/[...nextauth].ts | 5 +- apps/web/src/pages/api/sdk/events.ts | 38 +- .../api/sdk/profiles/[profileId]/decrement.ts | 15 +- .../api/sdk/profiles/[profileId]/increment.ts | 17 +- .../api/sdk/profiles/[profileId]/index.ts | 27 +- apps/web/src/pages/api/sdk/profiles/index.ts | 14 +- apps/web/src/pages/api/setup.ts | 23 +- apps/web/src/pages/api/trpc/[trpc].ts | 13 +- apps/web/src/pages/index.tsx | 20 +- apps/web/src/redux/index.ts | 25 +- apps/web/src/server/api/root.ts | 21 +- apps/web/src/server/api/routers/chart.ts | 166 +++-- apps/web/src/server/api/routers/client.ts | 23 +- apps/web/src/server/api/routers/dashboard.ts | 19 +- apps/web/src/server/api/routers/event.ts | 12 +- .../src/server/api/routers/organization.ts | 19 +- apps/web/src/server/api/routers/profile.ts | 10 +- apps/web/src/server/api/routers/project.ts | 19 +- apps/web/src/server/api/routers/report.ts | 53 +- apps/web/src/server/api/routers/user.ts | 46 +- apps/web/src/server/api/trpc.ts | 17 +- apps/web/src/server/auth.ts | 62 +- apps/web/src/server/db.ts | 10 +- apps/web/src/server/exceptions.ts | 59 +- apps/web/src/server/getServerSideProps.ts | 37 +- .../src/server/services/dashboard.service.ts | 8 +- apps/web/src/server/services/hash.service.ts | 21 +- .../server/services/organization.service.ts | 8 +- .../src/server/services/profile.service.ts | 33 +- .../src/server/services/project.service.ts | 8 +- apps/web/src/types/index.ts | 50 +- apps/web/src/utils/api.ts | 28 +- apps/web/src/utils/clipboard.ts | 10 +- apps/web/src/utils/cn.ts | 8 +- apps/web/src/utils/constants.ts | 66 +- apps/web/src/utils/date.ts | 16 +- apps/web/src/utils/getRangeLabel.ts | 11 +- apps/web/src/utils/object.ts | 6 +- apps/web/src/utils/slug.ts | 10 +- apps/web/src/utils/theme.ts | 8 +- apps/web/src/utils/validation.ts | 9 +- apps/web/tailwind.config.ts | 104 ++- package.json | 18 +- packages/sdk/index.ts | 287 ++++---- packages/sdk/package.json | 21 +- packages/sdk/tsconfig.json | 4 +- packages/sdk/tsup.config.ts | 6 +- packages/types/index.ts | 96 +-- packages/types/package.json | 20 +- packages/types/tsup.config.ts | 6 +- pnpm-lock.yaml | 687 ++++++++++++------ pnpm-workspace.yaml | 1 + publish.ts | 20 +- tooling/eslint/base.js | 50 ++ tooling/eslint/package.json | 40 + tooling/eslint/react.js | 24 + tooling/eslint/tsconfig.json | 8 + tooling/prettier/index.mjs | 28 + tooling/prettier/package.json | 17 + tooling/prettier/tsconfig.json | 8 + tooling/typescript/base.json | 22 + tooling/typescript/package.json | 8 + 82 files changed, 1890 insertions(+), 1363 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 tooling/eslint/base.js create mode 100644 tooling/eslint/package.json create mode 100644 tooling/eslint/react.js create mode 100644 tooling/eslint/tsconfig.json create mode 100644 tooling/prettier/index.mjs create mode 100644 tooling/prettier/package.json create mode 100644 tooling/prettier/tsconfig.json create mode 100644 tooling/typescript/base.json create mode 100644 tooling/typescript/package.json diff --git a/.gitignore b/.gitignore index 2e015d38..193e7fdd 100644 --- a/.gitignore +++ b/.gitignore @@ -176,3 +176,4 @@ dist # Finder (MacOS) folder config .DS_Store +*.tsbuildinfo \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..0a535e05 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "yoavbls.pretty-ts-errors" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..459d5a75 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,23 @@ +{ + "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "[handlebars]": { + "editor.formatOnSave": false, + "editor.codeActionsOnSave": { "source.fixAll.eslint": false } + }, + "files.associations": { "*.hbs": "handlebars" }, + "eslint.workingDirectories": [ + { "pattern": "apps/*/" }, + { "pattern": "packages/*/" }, + { "pattern": "tooling/*/" } + ], + "typescript.enablePromptUseWorkspaceTsdk": true, + "typescript.tsdk": "node_modules/typescript/lib", + "[yaml]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + "editor.autoIndent": "advanced" + }, + "editor.inlineSuggest.enabled": true +} diff --git a/apps/web/components.json b/apps/web/components.json index 9078e044..9750ef2a 100644 --- a/apps/web/components.json +++ b/apps/web/components.json @@ -13,4 +13,4 @@ "components": "@/components", "utils": "@/utils/cn" } -} \ No newline at end of file +} diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index 61964ea7..bee6f3e3 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -2,7 +2,7 @@ * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful * for Docker builds. */ -await import("./src/env.mjs"); +await import('./src/env.mjs'); /** @type {import("next").NextConfig} */ const config = { @@ -14,8 +14,8 @@ const config = { * @see https://github.com/vercel/next.js/issues/41980 */ i18n: { - locales: ["en"], - defaultLocale: "en", + locales: ['en'], + defaultLocale: 'en', }, }; diff --git a/apps/web/package.json b/apps/web/package.json index 54c2f0ee..e6e1bdb2 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -3,13 +3,13 @@ "version": "0.1.0", "private": true, "scripts": { - "build": "next build", - "db:push": "prisma db push", - "dev": "next dev", "postinstall": "prisma generate", - "lint": "next lint", - "typecheck": "tsc --noEmit", - "start": "next start" + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint .", + "format": "prettier --check \"**/*.{mjs,ts,md,json}\"", + "typecheck": "tsc --noEmit" }, "dependencies": { "@hookform/resolvers": "^3.3.2", @@ -60,26 +60,32 @@ "zod": "^3.22.4" }, "devDependencies": { + "@mixan/eslint-config": "workspace:*", + "@mixan/prettier-config": "workspace:*", "@types/bcrypt": "^5.0.0", - "@types/eslint": "^8.44.2", "@types/node": "^18.16.0", "@types/ramda": "^0.29.6", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", "@types/react-syntax-highlighter": "^15.5.9", - "@typescript-eslint/eslint-plugin": "^6.3.0", - "@typescript-eslint/parser": "^6.3.0", "autoprefixer": "^10.4.14", - "eslint": "^8.47.0", + "eslint": "^8.48.0", "eslint-config-next": "^13.5.4", "postcss": "^8.4.27", - "prettier": "^3.0.0", "prettier-plugin-tailwindcss": "^0.5.1", "prisma": "^5.1.1", "tailwindcss": "^3.3.3", - "typescript": "^5.1.6" + "typescript": "^5.2.0" }, "ct3aMetadata": { "initVersion": "7.21.0" - } + }, + "eslintConfig": { + "root": true, + "extends": [ + "@mixan/eslint-config/base", + "@mixan/eslint-config/react" + ] + }, + "prettier": "@mixan/prettier-config" } diff --git a/apps/web/prettier.config.mjs b/apps/web/prettier.config.mjs index 2d2fa4c9..eee0f31f 100644 --- a/apps/web/prettier.config.mjs +++ b/apps/web/prettier.config.mjs @@ -1,6 +1,6 @@ /** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').options} */ const config = { - plugins: ["prettier-plugin-tailwindcss"], + plugins: ['prettier-plugin-tailwindcss'], }; export default config; diff --git a/apps/web/src/_middleware.ts b/apps/web/src/_middleware.ts index a127de59..ac9dee59 100644 --- a/apps/web/src/_middleware.ts +++ b/apps/web/src/_middleware.ts @@ -1,3 +1,3 @@ -export { default } from "next-auth/middleware" +export { default } from 'next-auth/middleware'; -export const config = { matcher: ["/dashboard"] } \ No newline at end of file +export const config = { matcher: ['/dashboard'] }; diff --git a/apps/web/src/components/report/hooks/useReportId.ts b/apps/web/src/components/report/hooks/useReportId.ts index 26ce59be..434e101c 100644 --- a/apps/web/src/components/report/hooks/useReportId.ts +++ b/apps/web/src/components/report/hooks/useReportId.ts @@ -1,9 +1,9 @@ -import { useQueryParams } from "@/hooks/useQueryParams"; -import { z } from "zod"; +import { useQueryParams } from '@/hooks/useQueryParams'; +import { z } from 'zod'; export const useReportId = () => useQueryParams( z.object({ reportId: z.string().optional(), - }), + }) ); diff --git a/apps/web/src/components/report/reportSlice.ts b/apps/web/src/components/report/reportSlice.ts index 2fc90075..1823419e 100644 --- a/apps/web/src/components/report/reportSlice.ts +++ b/apps/web/src/components/report/reportSlice.ts @@ -1,24 +1,24 @@ import { - type IChartInput, type IChartBreakdown, type IChartEvent, - type IInterval, - type IChartType, + type IChartInput, type IChartRange, -} from "@/types"; -import { alphabetIds } from "@/utils/constants"; -import { type PayloadAction, createSlice } from "@reduxjs/toolkit"; + type IChartType, + type IInterval, +} from '@/types'; +import { alphabetIds } from '@/utils/constants'; +import { createSlice, type PayloadAction } from '@reduxjs/toolkit'; type InitialState = IChartInput & { - startDate: string | null; - endDate: string | null; -} + startDate: string | null; + endDate: string | null; +}; // First approach: define the initial state using that type const initialState: InitialState = { - name: "screen_view", - chartType: "linear", - interval: "day", + name: 'screen_view', + chartType: 'linear', + interval: 'day', breakdowns: [], events: [], range: 30, @@ -27,21 +27,21 @@ const initialState: InitialState = { }; export const reportSlice = createSlice({ - name: "counter", + name: 'counter', initialState, reducers: { reset() { - return initialState + return initialState; }, - setReport(state, action: PayloadAction) { + setReport(state, action: PayloadAction) { return { ...action.payload, startDate: null, endDate: null, - } + }; }, // Events - addEvent: (state, action: PayloadAction>) => { + addEvent: (state, action: PayloadAction>) => { state.events.push({ id: alphabetIds[state.events.length]!, ...action.payload, @@ -51,10 +51,10 @@ export const reportSlice = createSlice({ state, action: PayloadAction<{ id: string; - }>, + }> ) => { state.events = state.events.filter( - (event) => event.id !== action.payload.id, + (event) => event.id !== action.payload.id ); }, changeEvent: (state, action: PayloadAction) => { @@ -69,7 +69,7 @@ export const reportSlice = createSlice({ // Breakdowns addBreakdown: ( state, - action: PayloadAction>, + action: PayloadAction> ) => { state.breakdowns.push({ id: alphabetIds[state.breakdowns.length]!, @@ -80,10 +80,10 @@ export const reportSlice = createSlice({ state, action: PayloadAction<{ id: string; - }>, + }> ) => { state.breakdowns = state.breakdowns.filter( - (event) => event.id !== action.payload.id, + (event) => event.id !== action.payload.id ); }, changeBreakdown: (state, action: PayloadAction) => { @@ -99,7 +99,7 @@ export const reportSlice = createSlice({ changeInterval: (state, action: PayloadAction) => { state.interval = action.payload; }, - + // Chart type changeChartType: (state, action: PayloadAction) => { state.chartType = action.payload; @@ -116,15 +116,15 @@ export const reportSlice = createSlice({ }, changeDateRanges: (state, action: PayloadAction) => { - state.range = action.payload + state.range = action.payload; if (action.payload === 0.3 || action.payload === 0.6) { - state.interval = "minute"; + state.interval = 'minute'; } else if (action.payload === 0 || action.payload === 1) { - state.interval = "hour"; + state.interval = 'hour'; } else if (action.payload <= 30) { - state.interval = "day"; + state.interval = 'day'; } else { - state.interval = "month"; + state.interval = 'month'; } }, }, diff --git a/apps/web/src/components/ui/use-toast.ts b/apps/web/src/components/ui/use-toast.ts index 90d8959b..10a1a1c8 100644 --- a/apps/web/src/components/ui/use-toast.ts +++ b/apps/web/src/components/ui/use-toast.ts @@ -1,104 +1,100 @@ // Inspired by react-hot-toast library -import * as React from "react" +import * as React from 'react'; +import type { ToastActionElement, ToastProps } from '@/components/ui/toast'; -import type { - ToastActionElement, - ToastProps, -} from "@/components/ui/toast" - -const TOAST_LIMIT = 1 -const TOAST_REMOVE_DELAY = 1000000 +const TOAST_LIMIT = 1; +const TOAST_REMOVE_DELAY = 1000000; type ToasterToast = ToastProps & { - id: string - title?: React.ReactNode - description?: React.ReactNode - action?: ToastActionElement -} + id: string; + title?: React.ReactNode; + description?: React.ReactNode; + action?: ToastActionElement; +}; const actionTypes = { - ADD_TOAST: "ADD_TOAST", - UPDATE_TOAST: "UPDATE_TOAST", - DISMISS_TOAST: "DISMISS_TOAST", - REMOVE_TOAST: "REMOVE_TOAST", -} as const + ADD_TOAST: 'ADD_TOAST', + UPDATE_TOAST: 'UPDATE_TOAST', + DISMISS_TOAST: 'DISMISS_TOAST', + REMOVE_TOAST: 'REMOVE_TOAST', +} as const; -let count = 0 +let count = 0; function genId() { - count = (count + 1) % Number.MAX_VALUE - return count.toString() + count = (count + 1) % Number.MAX_VALUE; + return count.toString(); } -type ActionType = typeof actionTypes +type ActionType = typeof actionTypes; type Action = | { - type: ActionType["ADD_TOAST"] - toast: ToasterToast + type: ActionType['ADD_TOAST']; + toast: ToasterToast; } | { - type: ActionType["UPDATE_TOAST"] - toast: Partial + type: ActionType['UPDATE_TOAST']; + toast: Partial; } | { - type: ActionType["DISMISS_TOAST"] - toastId?: ToasterToast["id"] + type: ActionType['DISMISS_TOAST']; + toastId?: ToasterToast['id']; } | { - type: ActionType["REMOVE_TOAST"] - toastId?: ToasterToast["id"] - } + type: ActionType['REMOVE_TOAST']; + toastId?: ToasterToast['id']; + }; interface State { - toasts: ToasterToast[] + toasts: ToasterToast[]; } -const toastTimeouts = new Map>() +const toastTimeouts = new Map>(); const addToRemoveQueue = (toastId: string) => { if (toastTimeouts.has(toastId)) { - return + return; } const timeout = setTimeout(() => { - toastTimeouts.delete(toastId) + toastTimeouts.delete(toastId); dispatch({ - type: "REMOVE_TOAST", + type: 'REMOVE_TOAST', toastId: toastId, - }) - }, TOAST_REMOVE_DELAY) + }); + }, TOAST_REMOVE_DELAY); - toastTimeouts.set(toastId, timeout) -} + toastTimeouts.set(toastId, timeout); +}; export const reducer = (state: State, action: Action): State => { switch (action.type) { - case "ADD_TOAST": + case 'ADD_TOAST': return { ...state, toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), - } + }; - case "UPDATE_TOAST": + case 'UPDATE_TOAST': return { ...state, toasts: state.toasts.map((t) => t.id === action.toast.id ? { ...t, ...action.toast } : t ), - } + }; - case "DISMISS_TOAST": { - const { toastId } = action + case 'DISMISS_TOAST': { + const { toastId } = action; // ! Side effects ! - This could be extracted into a dismissToast() action, // but I'll keep it here for simplicity if (toastId) { - addToRemoveQueue(toastId) + addToRemoveQueue(toastId); } else { state.toasts.forEach((toast) => { - addToRemoveQueue(toast.id) - }) + addToRemoveQueue(toast.id); + }); } return { @@ -111,82 +107,82 @@ export const reducer = (state: State, action: Action): State => { } : t ), - } + }; } - case "REMOVE_TOAST": + case 'REMOVE_TOAST': if (action.toastId === undefined) { return { ...state, toasts: [], - } + }; } return { ...state, toasts: state.toasts.filter((t) => t.id !== action.toastId), - } + }; } -} +}; -const listeners: Array<(state: State) => void> = [] +const listeners: Array<(state: State) => void> = []; -let memoryState: State = { toasts: [] } +let memoryState: State = { toasts: [] }; function dispatch(action: Action) { - memoryState = reducer(memoryState, action) + memoryState = reducer(memoryState, action); listeners.forEach((listener) => { - listener(memoryState) - }) + listener(memoryState); + }); } -type Toast = Omit +type Toast = Omit; function toast({ ...props }: Toast) { - const id = genId() + const id = genId(); const update = (props: ToasterToast) => dispatch({ - type: "UPDATE_TOAST", + type: 'UPDATE_TOAST', toast: { ...props, id }, - }) - const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) + }); + const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id }); dispatch({ - type: "ADD_TOAST", + type: 'ADD_TOAST', toast: { ...props, id, open: true, onOpenChange: (open) => { - if (!open) dismiss() + if (!open) dismiss(); }, }, - }) + }); return { id: id, dismiss, update, - } + }; } function useToast() { - const [state, setState] = React.useState(memoryState) + const [state, setState] = React.useState(memoryState); React.useEffect(() => { - listeners.push(setState) + listeners.push(setState); return () => { - const index = listeners.indexOf(setState) + const index = listeners.indexOf(setState); if (index > -1) { - listeners.splice(index, 1) + listeners.splice(index, 1); } - } - }, [state]) + }; + }, [state]); return { ...state, toast, - dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), - } + dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }), + }; } -export { useToast, toast } +export { useToast, toast }; diff --git a/apps/web/src/env.mjs b/apps/web/src/env.mjs index a95f519c..32ac1455 100644 --- a/apps/web/src/env.mjs +++ b/apps/web/src/env.mjs @@ -1,5 +1,5 @@ -import { createEnv } from "@t3-oss/env-nextjs"; -import { z } from "zod"; +import { createEnv } from '@t3-oss/env-nextjs'; +import { z } from 'zod'; export const env = createEnv({ /** @@ -11,14 +11,14 @@ export const env = createEnv({ .string() .url() .refine( - (str) => !str.includes("YOUR_MYSQL_URL_HERE"), - "You forgot to change the default URL" + (str) => !str.includes('YOUR_MYSQL_URL_HERE'), + 'You forgot to change the default URL' ), NODE_ENV: z - .enum(["development", "test", "production"]) - .default("development"), + .enum(['development', 'test', 'production']) + .default('development'), NEXTAUTH_SECRET: - process.env.NODE_ENV === "production" + process.env.NODE_ENV === 'production' ? z.string() : z.string().optional(), NEXTAUTH_URL: z.preprocess( diff --git a/apps/web/src/hooks/useFormatDateInterval.ts b/apps/web/src/hooks/useFormatDateInterval.ts index 75b013cb..daa97371 100644 --- a/apps/web/src/hooks/useFormatDateInterval.ts +++ b/apps/web/src/hooks/useFormatDateInterval.ts @@ -1,27 +1,32 @@ -import { type IInterval } from "@/types"; - +import { type IInterval } from '@/types'; export function formatDateInterval(interval: IInterval, date: Date): string { - if (interval === "hour" || interval === "minute") { - return new Intl.DateTimeFormat("en-GB", { - hour: "2-digit", - minute: "2-digit", + if (interval === 'hour' || interval === 'minute') { + return new Intl.DateTimeFormat('en-GB', { + hour: '2-digit', + minute: '2-digit', }).format(date); } - - if (interval === "month") { - return new Intl.DateTimeFormat("en-GB", { month: "short" }).format(date); + + if (interval === 'month') { + return new Intl.DateTimeFormat('en-GB', { month: 'short' }).format(date); } - if (interval === "day") { - return new Intl.DateTimeFormat("en-GB", { weekday: "short", day: '2-digit', month: '2-digit' }).format( - date, - ); + if (interval === 'day') { + return new Intl.DateTimeFormat('en-GB', { + weekday: 'short', + day: '2-digit', + month: '2-digit', + }).format(date); } - + return date.toISOString(); } export function useFormatDateInterval(interval: IInterval) { - return (date: Date | string) => formatDateInterval(interval, typeof date === "string" ? new Date(date) : date); -} \ No newline at end of file + return (date: Date | string) => + formatDateInterval( + interval, + typeof date === 'string' ? new Date(date) : date + ); +} diff --git a/apps/web/src/hooks/useMappings.ts b/apps/web/src/hooks/useMappings.ts index 43942bcf..18ecfad9 100644 --- a/apps/web/src/hooks/useMappings.ts +++ b/apps/web/src/hooks/useMappings.ts @@ -1,7 +1,7 @@ -import mappings from '@/mappings.json' +import mappings from '@/mappings.json'; export function useMappings() { return (val: string) => { - return mappings.find((item) => item.id === val)?.name ?? val - } -} \ No newline at end of file + return mappings.find((item) => item.id === val)?.name ?? val; + }; +} diff --git a/apps/web/src/hooks/useOrganizationParams.ts b/apps/web/src/hooks/useOrganizationParams.ts index 236a2ae3..eaf5784e 100644 --- a/apps/web/src/hooks/useOrganizationParams.ts +++ b/apps/web/src/hooks/useOrganizationParams.ts @@ -1,5 +1,6 @@ -import { z } from "zod"; -import { useQueryParams } from "./useQueryParams"; +import { z } from 'zod'; + +import { useQueryParams } from './useQueryParams'; export function useOrganizationParams() { return useQueryParams( @@ -8,6 +9,6 @@ export function useOrganizationParams() { project: z.string(), dashboard: z.string(), profileId: z.string().optional(), - }), + }) ); -} \ No newline at end of file +} diff --git a/apps/web/src/hooks/useQueryParams.ts b/apps/web/src/hooks/useQueryParams.ts index b6b180bc..28cdca0d 100644 --- a/apps/web/src/hooks/useQueryParams.ts +++ b/apps/web/src/hooks/useQueryParams.ts @@ -1,7 +1,6 @@ -import { useMemo } from "react"; - -import { useRouter } from "next/router"; -import { type z } from "zod"; +import { useMemo } from 'react'; +import { useRouter } from 'next/router'; +import { type z } from 'zod'; export function useQueryParams(zod: Z) { const router = useRouter(); diff --git a/apps/web/src/hooks/useRefetchActive.ts b/apps/web/src/hooks/useRefetchActive.ts index f11d64ec..5f96d435 100644 --- a/apps/web/src/hooks/useRefetchActive.ts +++ b/apps/web/src/hooks/useRefetchActive.ts @@ -1,6 +1,6 @@ -import { useQueryClient } from "@tanstack/react-query"; +import { useQueryClient } from '@tanstack/react-query'; export function useRefetchActive() { - const client = useQueryClient() - return () => client.refetchQueries({type: 'active'}) -} \ No newline at end of file + const client = useQueryClient(); + return () => client.refetchQueries({ type: 'active' }); +} diff --git a/apps/web/src/hooks/useRouterBeforeLeave.ts b/apps/web/src/hooks/useRouterBeforeLeave.ts index 4724c190..cfe061f9 100644 --- a/apps/web/src/hooks/useRouterBeforeLeave.ts +++ b/apps/web/src/hooks/useRouterBeforeLeave.ts @@ -1,5 +1,5 @@ -import { useRouter } from "next/router"; -import { useEffect, useRef } from "react"; +import { useEffect, useRef } from 'react'; +import { useRouter } from 'next/router'; export function useRouterBeforeLeave(callback: () => void) { const router = useRouter(); @@ -8,14 +8,14 @@ export function useRouterBeforeLeave(callback: () => void) { useEffect(() => { const handleRouteChange = (url: string) => { if (prevUrl.current !== url) { - callback() + callback(); } prevUrl.current = url; }; - router.events.on("routeChangeStart", handleRouteChange); + router.events.on('routeChangeStart', handleRouteChange); return () => { - router.events.off("routeChangeStart", handleRouteChange); + router.events.off('routeChangeStart', handleRouteChange); }; }, [router, callback]); -} \ No newline at end of file +} diff --git a/apps/web/src/mappings.json b/apps/web/src/mappings.json index f7c535af..d5cb7c91 100644 --- a/apps/web/src/mappings.json +++ b/apps/web/src/mappings.json @@ -1,146 +1,146 @@ [ - { - "id": "clbow140n0228u99ui1t24l85", - "name": "Mjölkproteinfritt" - }, - { - "id": "cl04a3trn0015ix50tzy40pyf", - "name": "Måltider" - }, - { - "id": "cl04a5p7s0401ix505n75yfcn", - "name": "Svårighetsgrad" - }, - { - "id": "cl04a7k3i0813ix50aau6yxqg", - "name": "Tid" - }, - { - "id": "cl04a47fu0103ix50dqckz2vc", - "name": "Frukost" - }, - { - "id": "cl04a4hvu0152ix50o0w4iy8l", - "name": "Mellis" - }, - { - "id": "cl04a58ju0281ix50kdmcwst6", - "name": "Dessert" - }, - { - "id": "cl04a5fjc0321ix50xiwhuydy", - "name": "Smakportioner" - }, - { - "id": "cl04a5kcu0361ix50bnmbhoxz", - "name": "Plockmat" - }, - { - "id": "cl04a60sk0496ix50et419drf", - "name": "Medium" - }, - { - "id": "cl04a67lx0536ix50sstoxnhi", - "name": "Avancerat" - }, - { - "id": "cl04a7qi60850ix50je7vaxo3", - "name": "0-10 min" - }, - { - "id": "cl04a7vxi0890ix50veumcuyu", - "name": "10-20 min" - }, - { - "id": "cl04a82bj0930ix50bboh3tl9", - "name": "20-30 min" - }, - { - "id": "cl04a8a7a0970ix50uet02cqh", - "name": "30-40 min" - }, - { - "id": "cl04a8g151010ix50z4cnf2kg", - "name": "40-50 min" - }, - { - "id": "cl04a8mqy1050ix50z0d1ho1a", - "name": "50-60 min" - }, - { - "id": "cl04a5ujg0447ix50vd3vor87", - "name": "Lätt" - }, - { - "id": "cl04a4qv60201ix50b8q5kn9r", - "name": "Lunch & Middag" - }, - { - "id": "clak50jem0072ri9ugwygg5ko", - "name": "Annat" - }, - { - "id": "clak510qm0120ri9upqkca39s", - "name": "För hela familjen" - }, - { - "id": "clak59l8x0085yd9uzllcuci5", - "name": "Under 3 ingredienser" - }, - { - "id": "clak59l8y0087yd9u53qperp8", - "name": "Under 5 ingredienser" - }, - { - "id": "claslo2sg0404no9uo2tckm5i", - "name": "Huvudingredienser" - }, - { - "id": "claslv9s20491no9ugo4fd9ns", - "name": "Fisk" - }, - { - "id": "claslv9s30493no9umug5po29", - "name": "Kyckling" - }, - { - "id": "claslv9s40495no9umor61pql", - "name": "Kött" - }, - { - "id": "claslv9s40497no9uttwkt47n", - "name": "Korv" - }, - { - "id": "claslv9s50499no9uch0lhs9i", - "name": "Vegetariskt" - }, - { - "id": "clb1y44f40128np9uufck0iqf", - "name": "Årstider" - }, - { - "id": "clb1y4ks80202np9uh43c84ts", - "name": "Jul" - }, - { - "id": "clbovy0fd0081u99u8dr0yplr", - "name": "Allergier" - }, - { - "id": "clbow140p0230u99uk9e7g1u1", - "name": "Äggfritt" - }, - { - "id": "clbow140q0232u99uy3lwukvc", - "name": "Vetefritt" - }, - { - "id": "clbow140q0234u99uiyrujxd4", - "name": "Glutenfritt" - }, - { - "id": "clbow140r0236u99u5333gpei", - "name": "Nötfritt" - } -] \ No newline at end of file + { + "id": "clbow140n0228u99ui1t24l85", + "name": "Mjölkproteinfritt" + }, + { + "id": "cl04a3trn0015ix50tzy40pyf", + "name": "Måltider" + }, + { + "id": "cl04a5p7s0401ix505n75yfcn", + "name": "Svårighetsgrad" + }, + { + "id": "cl04a7k3i0813ix50aau6yxqg", + "name": "Tid" + }, + { + "id": "cl04a47fu0103ix50dqckz2vc", + "name": "Frukost" + }, + { + "id": "cl04a4hvu0152ix50o0w4iy8l", + "name": "Mellis" + }, + { + "id": "cl04a58ju0281ix50kdmcwst6", + "name": "Dessert" + }, + { + "id": "cl04a5fjc0321ix50xiwhuydy", + "name": "Smakportioner" + }, + { + "id": "cl04a5kcu0361ix50bnmbhoxz", + "name": "Plockmat" + }, + { + "id": "cl04a60sk0496ix50et419drf", + "name": "Medium" + }, + { + "id": "cl04a67lx0536ix50sstoxnhi", + "name": "Avancerat" + }, + { + "id": "cl04a7qi60850ix50je7vaxo3", + "name": "0-10 min" + }, + { + "id": "cl04a7vxi0890ix50veumcuyu", + "name": "10-20 min" + }, + { + "id": "cl04a82bj0930ix50bboh3tl9", + "name": "20-30 min" + }, + { + "id": "cl04a8a7a0970ix50uet02cqh", + "name": "30-40 min" + }, + { + "id": "cl04a8g151010ix50z4cnf2kg", + "name": "40-50 min" + }, + { + "id": "cl04a8mqy1050ix50z0d1ho1a", + "name": "50-60 min" + }, + { + "id": "cl04a5ujg0447ix50vd3vor87", + "name": "Lätt" + }, + { + "id": "cl04a4qv60201ix50b8q5kn9r", + "name": "Lunch & Middag" + }, + { + "id": "clak50jem0072ri9ugwygg5ko", + "name": "Annat" + }, + { + "id": "clak510qm0120ri9upqkca39s", + "name": "För hela familjen" + }, + { + "id": "clak59l8x0085yd9uzllcuci5", + "name": "Under 3 ingredienser" + }, + { + "id": "clak59l8y0087yd9u53qperp8", + "name": "Under 5 ingredienser" + }, + { + "id": "claslo2sg0404no9uo2tckm5i", + "name": "Huvudingredienser" + }, + { + "id": "claslv9s20491no9ugo4fd9ns", + "name": "Fisk" + }, + { + "id": "claslv9s30493no9umug5po29", + "name": "Kyckling" + }, + { + "id": "claslv9s40495no9umor61pql", + "name": "Kött" + }, + { + "id": "claslv9s40497no9uttwkt47n", + "name": "Korv" + }, + { + "id": "claslv9s50499no9uch0lhs9i", + "name": "Vegetariskt" + }, + { + "id": "clb1y44f40128np9uufck0iqf", + "name": "Årstider" + }, + { + "id": "clb1y4ks80202np9uh43c84ts", + "name": "Jul" + }, + { + "id": "clbovy0fd0081u99u8dr0yplr", + "name": "Allergier" + }, + { + "id": "clbow140p0230u99uk9e7g1u1", + "name": "Äggfritt" + }, + { + "id": "clbow140q0232u99uy3lwukvc", + "name": "Vetefritt" + }, + { + "id": "clbow140q0234u99uiyrujxd4", + "name": "Glutenfritt" + }, + { + "id": "clbow140r0236u99u5333gpei", + "name": "Nötfritt" + } +] diff --git a/apps/web/src/pages/_app.tsx b/apps/web/src/pages/_app.tsx index 53c41514..5181b6fb 100644 --- a/apps/web/src/pages/_app.tsx +++ b/apps/web/src/pages/_app.tsx @@ -1,26 +1,22 @@ -import { type Session } from "next-auth"; -import { SessionProvider, getSession } from "next-auth/react"; -import App, { - type AppContext, - type AppInitialProps, - type AppType, -} from "next/app"; -import store from "@/redux"; -import { Provider as ReduxProvider } from "react-redux"; -import { Suspense } from "react"; -import { Space_Grotesk } from "next/font/google"; -import { Toaster } from "@/components/ui/toaster"; +import { Suspense } from 'react'; +import { Toaster } from '@/components/ui/toaster'; +import store from '@/redux'; +import { api } from '@/utils/api'; +import { type Session } from 'next-auth'; +import { SessionProvider } from 'next-auth/react'; +import { type AppType } from 'next/app'; +import { Space_Grotesk } from 'next/font/google'; +import { Provider as ReduxProvider } from 'react-redux'; -import { api } from "@/utils/api"; +import '@/styles/globals.css'; -import "@/styles/globals.css"; -import { ModalProvider } from "@/modals"; -import { TooltipProvider } from "@/components/ui/tooltip"; +import { TooltipProvider } from '@/components/ui/tooltip'; +import { ModalProvider } from '@/modals'; const font = Space_Grotesk({ - subsets: ["latin"], - display: "swap", - variable: "--text", + subsets: ['latin'], + display: 'swap', + variable: '--text', }); const MixanApp: AppType<{ session: Session | null }> = ({ diff --git a/apps/web/src/pages/api/auth/[...nextauth].ts b/apps/web/src/pages/api/auth/[...nextauth].ts index 05aa2a35..1e8a60d5 100644 --- a/apps/web/src/pages/api/auth/[...nextauth].ts +++ b/apps/web/src/pages/api/auth/[...nextauth].ts @@ -1,5 +1,4 @@ -import NextAuth from "next-auth"; - -import { authOptions } from "@/server/auth"; +import { authOptions } from '@/server/auth'; +import NextAuth from 'next-auth'; export default NextAuth(authOptions); diff --git a/apps/web/src/pages/api/sdk/events.ts b/apps/web/src/pages/api/sdk/events.ts index 2889fccb..8d4d9d22 100644 --- a/apps/web/src/pages/api/sdk/events.ts +++ b/apps/web/src/pages/api/sdk/events.ts @@ -1,24 +1,22 @@ -import { validateSdkRequest } from '@/server/auth' -import { db } from '@/server/db' -import { createError, handleError } from '@/server/exceptions' -import { type EventPayload } from '@mixan/types' -import type { NextApiRequest, NextApiResponse } from 'next' - +import { validateSdkRequest } from '@/server/auth'; +import { db } from '@/server/db'; +import { createError, handleError } from '@/server/exceptions'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +import { type EventPayload } from '@mixan/types'; + interface Request extends NextApiRequest { - body: Array + body: Array; } -export default async function handler( - req: Request, - res: NextApiResponse -) { - if(req.method !== 'POST') { - return handleError(res, createError(405, 'Method not allowed')) +export default async function handler(req: Request, res: NextApiResponse) { + if (req.method !== 'POST') { + return handleError(res, createError(405, 'Method not allowed')); } try { // Check client id & secret - const projectId = await validateSdkRequest(req) + const projectId = await validateSdkRequest(req); await db.event.createMany({ data: req.body.map((event) => ({ @@ -27,11 +25,11 @@ export default async function handler( createdAt: event.time, project_id: projectId, profile_id: event.profileId, - })) - }) - - res.status(200).end() + })), + }); + + res.status(200).end(); } catch (error) { - handleError(res, error) + handleError(res, error); } -} \ No newline at end of file +} diff --git a/apps/web/src/pages/api/sdk/profiles/[profileId]/decrement.ts b/apps/web/src/pages/api/sdk/profiles/[profileId]/decrement.ts index 494baa61..d3a6b5b4 100644 --- a/apps/web/src/pages/api/sdk/profiles/[profileId]/decrement.ts +++ b/apps/web/src/pages/api/sdk/profiles/[profileId]/decrement.ts @@ -1,16 +1,17 @@ -import { validateSdkRequest } from "@/server/auth"; -import { createError, handleError } from "@/server/exceptions"; -import { tickProfileProperty } from "@/server/services/profile.service"; -import { type ProfileIncrementPayload } from "@mixan/types"; -import type { NextApiRequest, NextApiResponse } from "next"; +import { validateSdkRequest } from '@/server/auth'; +import { createError, handleError } from '@/server/exceptions'; +import { tickProfileProperty } from '@/server/services/profile.service'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +import { type ProfileIncrementPayload } from '@mixan/types'; interface Request extends NextApiRequest { body: ProfileIncrementPayload; } export default async function handler(req: Request, res: NextApiResponse) { - if (req.method !== "PUT") { - return handleError(res, createError(405, "Method not allowed")); + if (req.method !== 'PUT') { + return handleError(res, createError(405, 'Method not allowed')); } try { diff --git a/apps/web/src/pages/api/sdk/profiles/[profileId]/increment.ts b/apps/web/src/pages/api/sdk/profiles/[profileId]/increment.ts index 78133cd1..77ec56e3 100644 --- a/apps/web/src/pages/api/sdk/profiles/[profileId]/increment.ts +++ b/apps/web/src/pages/api/sdk/profiles/[profileId]/increment.ts @@ -1,21 +1,22 @@ -import { validateSdkRequest } from "@/server/auth"; -import { createError, handleError } from "@/server/exceptions"; -import { tickProfileProperty } from "@/server/services/profile.service"; -import { type ProfileIncrementPayload } from "@mixan/types"; -import type { NextApiRequest, NextApiResponse } from "next"; +import { validateSdkRequest } from '@/server/auth'; +import { createError, handleError } from '@/server/exceptions'; +import { tickProfileProperty } from '@/server/services/profile.service'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +import { type ProfileIncrementPayload } from '@mixan/types'; interface Request extends NextApiRequest { body: ProfileIncrementPayload; } export default async function handler(req: Request, res: NextApiResponse) { - if (req.method !== "PUT") { - return handleError(res, createError(405, "Method not allowed")); + if (req.method !== 'PUT') { + return handleError(res, createError(405, 'Method not allowed')); } try { // Check client id & secret - await validateSdkRequest(req) + await validateSdkRequest(req); const profileId = req.query.profileId as string; diff --git a/apps/web/src/pages/api/sdk/profiles/[profileId]/index.ts b/apps/web/src/pages/api/sdk/profiles/[profileId]/index.ts index 4ca9b03e..b31511af 100644 --- a/apps/web/src/pages/api/sdk/profiles/[profileId]/index.ts +++ b/apps/web/src/pages/api/sdk/profiles/[profileId]/index.ts @@ -1,26 +1,27 @@ -import { validateSdkRequest } from "@/server/auth"; -import { db } from "@/server/db"; -import { createError, handleError } from "@/server/exceptions"; -import { getProfile } from "@/server/services/profile.service"; -import { type ProfilePayload } from "@mixan/types"; -import type { NextApiRequest, NextApiResponse } from "next"; +import { validateSdkRequest } from '@/server/auth'; +import { db } from '@/server/db'; +import { createError, handleError } from '@/server/exceptions'; +import { getProfile } from '@/server/services/profile.service'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +import { type ProfilePayload } from '@mixan/types'; interface Request extends NextApiRequest { body: ProfilePayload; } -export default async function handler(req: Request, res: NextApiResponse) { - if (req.method !== "PUT" && req.method !== "POST") { - return handleError(res, createError(405, "Method not allowed")); +export default async function handler(req: Request, res: NextApiResponse) { + if (req.method !== 'PUT' && req.method !== 'POST') { + return handleError(res, createError(405, 'Method not allowed')); } try { // Check client id & secret - await validateSdkRequest(req) + await validateSdkRequest(req); const profileId = req.query.profileId as string; - const profile = await getProfile(profileId) - + const profile = await getProfile(profileId); + const { body } = req; await db.profile.update({ where: { @@ -33,7 +34,7 @@ export default async function handler(req: Request, res: NextApiResponse) { last_name: body.last_name, avatar: body.avatar, properties: { - ...(typeof profile.properties === "object" + ...(typeof profile.properties === 'object' ? profile.properties ?? {} : {}), ...(body.properties ?? {}), diff --git a/apps/web/src/pages/api/sdk/profiles/index.ts b/apps/web/src/pages/api/sdk/profiles/index.ts index e3f976a1..6276e836 100644 --- a/apps/web/src/pages/api/sdk/profiles/index.ts +++ b/apps/web/src/pages/api/sdk/profiles/index.ts @@ -1,8 +1,8 @@ -import { validateSdkRequest } from "@/server/auth"; -import { db } from "@/server/db"; -import { createError, handleError } from "@/server/exceptions"; -import type { NextApiRequest, NextApiResponse } from "next"; -import randomAnimalName from "random-animal-name"; +import { validateSdkRequest } from '@/server/auth'; +import { db } from '@/server/db'; +import { createError, handleError } from '@/server/exceptions'; +import type { NextApiRequest, NextApiResponse } from 'next'; +import randomAnimalName from 'random-animal-name'; interface Request extends NextApiRequest { body: { @@ -12,8 +12,8 @@ interface Request extends NextApiRequest { } export default async function handler(req: Request, res: NextApiResponse) { - if (req.method !== "POST") { - return handleError(res, createError(405, "Method not allowed")); + if (req.method !== 'POST') { + return handleError(res, createError(405, 'Method not allowed')); } try { diff --git a/apps/web/src/pages/api/setup.ts b/apps/web/src/pages/api/setup.ts index bcce7793..934e0f06 100644 --- a/apps/web/src/pages/api/setup.ts +++ b/apps/web/src/pages/api/setup.ts @@ -1,10 +1,13 @@ -import { db } from "@/server/db"; -import { handleError } from "@/server/exceptions"; -import { hashPassword } from "@/server/services/hash.service"; -import { randomUUID } from "crypto"; -import { type NextApiRequest, type NextApiResponse } from "next"; +import { randomUUID } from 'crypto'; +import { db } from '@/server/db'; +import { handleError } from '@/server/exceptions'; +import { hashPassword } from '@/server/services/hash.service'; +import { type NextApiRequest, type NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { try { const counts = await db.$transaction([ db.organization.count(), @@ -13,25 +16,25 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) ]); if (counts.some((count) => count > 0)) { - return res.json("Setup already done"); + return res.json('Setup already done'); } const organization = await db.organization.create({ data: { - name: "Acme Inc.", + name: 'Acme Inc.', }, }); const project = await db.project.create({ data: { - name: "Acme Website", + name: 'Acme Website', organization_id: organization.id, }, }); const secret = randomUUID(); const client = await db.client.create({ data: { - name: "Acme Website Client", + name: 'Acme Website Client', project_id: project.id, organization_id: organization.id, secret: await hashPassword(secret), diff --git a/apps/web/src/pages/api/trpc/[trpc].ts b/apps/web/src/pages/api/trpc/[trpc].ts index 4e981b57..1a6da310 100644 --- a/apps/web/src/pages/api/trpc/[trpc].ts +++ b/apps/web/src/pages/api/trpc/[trpc].ts @@ -1,18 +1,17 @@ -import { createNextApiHandler } from "@trpc/server/adapters/next"; - -import { env } from "@/env.mjs"; -import { appRouter } from "@/server/api/root"; -import { createTRPCContext } from "@/server/api/trpc"; +import { env } from '@/env.mjs'; +import { appRouter } from '@/server/api/root'; +import { createTRPCContext } from '@/server/api/trpc'; +import { createNextApiHandler } from '@trpc/server/adapters/next'; // export API handler export default createNextApiHandler({ router: appRouter, createContext: createTRPCContext, onError: - env.NODE_ENV === "development" + env.NODE_ENV === 'development' ? ({ path, error }) => { console.error( - `❌ tRPC failed on ${path ?? ""}: ${error.message}` + `❌ tRPC failed on ${path ?? ''}: ${error.message}` ); } : undefined, diff --git a/apps/web/src/pages/index.tsx b/apps/web/src/pages/index.tsx index ce489d11..2b3b4967 100644 --- a/apps/web/src/pages/index.tsx +++ b/apps/web/src/pages/index.tsx @@ -1,21 +1,21 @@ -import { MainLayout } from "@/components/layouts/MainLayout"; -import { api } from "@/utils/api"; -import { useEffect } from "react"; -import { useRouter } from "next/router"; -import { createServerSideProps } from "@/server/getServerSideProps"; +import { useEffect } from 'react'; +import { MainLayout } from '@/components/layouts/MainLayout'; +import { createServerSideProps } from '@/server/getServerSideProps'; +import { api } from '@/utils/api'; +import { useRouter } from 'next/router'; -export const getServerSideProps = createServerSideProps() +export const getServerSideProps = createServerSideProps(); export default function Home() { - const router = useRouter() + const router = useRouter(); const query = api.organization.first.useQuery(); const organization = query.data ?? null; useEffect(() => { - if(organization) { - router.replace(`/${organization.slug}`) + if (organization) { + router.replace(`/${organization.slug}`); } - }, [organization]) + }, [organization, router]); return ( diff --git a/apps/web/src/redux/index.ts b/apps/web/src/redux/index.ts index f0c5d4be..82d70145 100644 --- a/apps/web/src/redux/index.ts +++ b/apps/web/src/redux/index.ts @@ -1,18 +1,21 @@ -import reportSlice from '@/components/report/reportSlice' -import { configureStore } from '@reduxjs/toolkit' -import { type TypedUseSelectorHook, useDispatch as useBaseDispatch, useSelector as useBaseSelector } from 'react-redux' +import reportSlice from '@/components/report/reportSlice'; +import { configureStore } from '@reduxjs/toolkit'; +import { + useDispatch as useBaseDispatch, + useSelector as useBaseSelector, + type TypedUseSelectorHook, +} from 'react-redux'; const store = configureStore({ reducer: { - report: reportSlice + report: reportSlice, }, -}) +}); -export type RootState = ReturnType +export type RootState = ReturnType; -export type AppDispatch = typeof store.dispatch -export const useDispatch: () => AppDispatch = useBaseDispatch -export const useSelector: TypedUseSelectorHook = useBaseSelector +export type AppDispatch = typeof store.dispatch; +export const useDispatch: () => AppDispatch = useBaseDispatch; +export const useSelector: TypedUseSelectorHook = useBaseSelector; - -export default store \ No newline at end of file +export default store; diff --git a/apps/web/src/server/api/root.ts b/apps/web/src/server/api/root.ts index 379eb177..68cbe02d 100644 --- a/apps/web/src/server/api/root.ts +++ b/apps/web/src/server/api/root.ts @@ -1,13 +1,14 @@ -import { createTRPCRouter } from "@/server/api/trpc"; -import { chartRouter } from "./routers/chart"; -import { reportRouter } from "./routers/report"; -import { organizationRouter } from "./routers/organization"; -import { userRouter } from "./routers/user"; -import { projectRouter } from "./routers/project"; -import { clientRouter } from "./routers/client"; -import { dashboardRouter } from "./routers/dashboard"; -import { eventRouter } from "./routers/event"; -import { profileRouter } from "./routers/profile"; +import { createTRPCRouter } from '@/server/api/trpc'; + +import { chartRouter } from './routers/chart'; +import { clientRouter } from './routers/client'; +import { dashboardRouter } from './routers/dashboard'; +import { eventRouter } from './routers/event'; +import { organizationRouter } from './routers/organization'; +import { profileRouter } from './routers/profile'; +import { projectRouter } from './routers/project'; +import { reportRouter } from './routers/report'; +import { userRouter } from './routers/user'; /** * This is the primary router for your server. diff --git a/apps/web/src/server/api/routers/chart.ts b/apps/web/src/server/api/routers/chart.ts index 7276a998..d4384ae2 100644 --- a/apps/web/src/server/api/routers/chart.ts +++ b/apps/web/src/server/api/routers/chart.ts @@ -1,15 +1,15 @@ -import { z } from "zod"; -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; -import { db } from "@/server/db"; -import { last, pipe, sort, uniq } from "ramda"; -import { toDots } from "@/utils/object"; -import { zChartInputWithDates } from "@/utils/validation"; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { db } from '@/server/db'; import { - type IChartInputWithDates, type IChartEvent, + type IChartInputWithDates, type IChartRange, -} from "@/types"; -import { getDaysOldDate } from "@/utils/date"; +} from '@/types'; +import { getDaysOldDate } from '@/utils/date'; +import { toDots } from '@/utils/object'; +import { zChartInputWithDates } from '@/utils/validation'; +import { last, pipe, sort, uniq } from 'ramda'; +import { z } from 'zod'; export const config = { api: { @@ -21,7 +21,7 @@ export const chartRouter = createTRPCRouter({ events: protectedProcedure.query(async () => { const events = await db.event.findMany({ take: 500, - distinct: ["name"], + distinct: ['name'], }); return events; @@ -47,12 +47,12 @@ export const chartRouter = createTRPCRouter({ const dotNotation = toDots(properties); return [...acc, ...Object.keys(dotNotation)]; }, [] as string[]) - .map((item) => item.replace(/\.([0-9]+)\./g, ".*.")) - .map((item) => item.replace(/\.([0-9]+)/g, "[*]")); + .map((item) => item.replace(/\.([0-9]+)\./g, '.*.')) + .map((item) => item.replace(/\.([0-9]+)/g, '[*]')); return pipe( sort((a, b) => a.length - b.length), - uniq, + uniq )(properties); }), @@ -62,10 +62,10 @@ export const chartRouter = createTRPCRouter({ if (isJsonPath(input.property)) { const events = await db.$queryRawUnsafe<{ value: string }[]>( `SELECT ${selectJsonPath( - input.property, + input.property )} AS value from events WHERE name = '${ input.event - }' AND "createdAt" >= NOW() - INTERVAL '30 days'`, + }' AND "createdAt" >= NOW() - INTERVAL '30 days'` ); return { values: uniq(events.map((item) => item.value)), @@ -102,12 +102,12 @@ export const chartRouter = createTRPCRouter({ ...(await getChartData({ ...input, event, - })), + })) ); } const sorted = [...series].sort((a, b) => { - if (input.chartType === "linear") { + if (input.chartType === 'linear') { const sumA = a.data.reduce((acc, item) => acc + item.count, 0); const sumB = b.data.reduce((acc, item) => acc + item.count, 0); return sumB - sumA; @@ -132,8 +132,8 @@ export const chartRouter = createTRPCRouter({ } return acc; }, - {} as Record<(typeof series)[number]["event"]["id"], number>, - ), + {} as Record<(typeof series)[number]['event']['id'], number> + ) ).map(([id, count]) => ({ count, ...events.find((event) => event.id === id)!, @@ -148,13 +148,13 @@ export const chartRouter = createTRPCRouter({ function selectJsonPath(property: string) { const jsonPath = property - .replace(/^properties\./, "") - .replace(/\.\*\./g, ".**."); + .replace(/^properties\./, '') + .replace(/\.\*\./g, '.**.'); return `jsonb_path_query(properties, '$.${jsonPath}')`; } function isJsonPath(property: string) { - return property.startsWith("properties"); + return property.startsWith('properties'); } type ResultItem = { @@ -164,12 +164,12 @@ type ResultItem = { }; function propertyNameToSql(name: string) { - if (name.includes(".")) { + if (name.includes('.')) { const str = name - .split(".") + .split('.') .map((item, index) => (index === 0 ? item : `'${item}'`)) - .join("->"); - const findLastOf = "->"; + .join('->'); + const findLastOf = '->'; const lastArrow = str.lastIndexOf(findLastOf); if (lastArrow === -1) { return str; @@ -224,27 +224,34 @@ function getDatesFromRange(range: IChartRange) { }; } -function getChartSql({ event, chartType, breakdowns, interval, startDate, endDate }: Omit) { +function getChartSql({ + event, + chartType, + breakdowns, + interval, + startDate, + endDate, +}: Omit) { const select = []; const where = []; const groupBy = []; const orderBy = []; - if (event.segment === "event") { + if (event.segment === 'event') { select.push(`count(*)::int as count`); } else { select.push(`count(DISTINCT profile_id)::int as count`); } switch (chartType) { - case "bar": { - orderBy.push("count DESC"); + case 'bar': { + orderBy.push('count DESC'); break; } - case "linear": { + case 'linear': { select.push(`date_trunc('${interval}', "createdAt") as date`); - groupBy.push("date"); - orderBy.push("date"); + groupBy.push('date'); + orderBy.push('date'); break; } } @@ -256,38 +263,38 @@ function getChartSql({ event, chartType, breakdowns, interval, startDate, endDat filters.forEach((filter) => { const { name, value } = filter; switch (filter.operator) { - case "is": { - if (name.includes(".*.") || name.endsWith("[*]")) { + case 'is': { + if (name.includes('.*.') || name.endsWith('[*]')) { where.push( `properties @? '$.${name - .replace(/^properties\./, "") - .replace(/\.\*\./g, "[*].")} ? (${value + .replace(/^properties\./, '') + .replace(/\.\*\./g, '[*].')} ? (${value .map((val) => `@ == "${val}"`) - .join(" || ")})'`, + .join(' || ')})'` ); } else { where.push( `${propertyNameToSql(name)} in (${value .map((val) => `'${val}'`) - .join(", ")})`, + .join(', ')})` ); } break; } - case "isNot": { - if (name.includes(".*.") || name.endsWith("[*]")) { + case 'isNot': { + if (name.includes('.*.') || name.endsWith('[*]')) { where.push( `properties @? '$.${name - .replace(/^properties\./, "") - .replace(/\.\*\./g, "[*].")} ? (${value + .replace(/^properties\./, '') + .replace(/\.\*\./g, '[*].')} ? (${value .map((val) => `@ != "${val}"`) - .join(" && ")})'`, + .join(' && ')})'` ); - } else if (name.includes(".")) { + } else if (name.includes('.')) { where.push( `${propertyNameToSql(name)} not in (${value .map((val) => `'${val}'`) - .join(", ")})`, + .join(', ')})` ); } break; @@ -322,24 +329,24 @@ function getChartSql({ event, chartType, breakdowns, interval, startDate, endDat } const sql = [ - `SELECT ${select.join(", ")}`, + `SELECT ${select.join(', ')}`, `FROM events`, - `WHERE ${where.join(" AND ")}`, + `WHERE ${where.join(' AND ')}`, ]; if (groupBy.length) { - sql.push(`GROUP BY ${groupBy.join(", ")}`); + sql.push(`GROUP BY ${groupBy.join(', ')}`); } if (orderBy.length) { - sql.push(`ORDER BY ${orderBy.join(", ")}`); + sql.push(`ORDER BY ${orderBy.join(', ')}`); } - return sql.join("\n"); + return sql.join('\n'); } type IGetChartDataInput = { event: IChartEvent; -} & Omit +} & Omit; async function getChartData({ chartType, @@ -365,23 +372,24 @@ async function getChartData({ interval, startDate, endDate, - }) + }); let result = await db.$queryRawUnsafe(sql); - if(result.length === 0 && breakdowns.length > 0) { - result = await db.$queryRawUnsafe(getChartSql({ - chartType, - event, - breakdowns: [], - interval, - startDate, - endDate, - })); + if (result.length === 0 && breakdowns.length > 0) { + result = await db.$queryRawUnsafe( + getChartSql({ + chartType, + event, + breakdowns: [], + interval, + startDate, + endDate, + }) + ); } console.log(sql); - // group by sql label const series = result.reduce( @@ -401,7 +409,7 @@ async function getChartData({ ...acc, }; }, - {} as Record, + {} as Record ); return Object.keys(series).map((key) => { @@ -416,7 +424,7 @@ async function getChartData({ }, totalCount: getTotalCount(data), data: - chartType === "linear" + chartType === 'linear' ? fillEmptySpotsInTimeline(data, interval, startDate, endDate).map( (item) => { return { @@ -424,7 +432,7 @@ async function getChartData({ count: item.count, date: new Date(item.date).toISOString(), }; - }, + } ) : [], }; @@ -435,17 +443,17 @@ function fillEmptySpotsInTimeline( items: ResultItem[], interval: string, startDate: string, - endDate: string, + endDate: string ) { const result = []; const clonedStartDate = new Date(startDate); const clonedEndDate = new Date(endDate); const today = new Date(); - if(interval === 'minute') {  - clonedStartDate.setSeconds(0, 0) + if (interval === 'minute') { + clonedStartDate.setSeconds(0, 0); clonedEndDate.setMinutes(clonedEndDate.getMinutes() + 1, 0, 0); - } else if (interval === "hour") { + } else if (interval === 'hour') { clonedStartDate.setMinutes(0, 0, 0); clonedEndDate.setMinutes(0, 0, 0); } else { @@ -455,7 +463,7 @@ function fillEmptySpotsInTimeline( // Force if interval is month and the start date is the same month as today const shouldForce = () => - interval === "month" && + interval === 'month' && clonedStartDate.getFullYear() === today.getFullYear() && clonedStartDate.getMonth() === today.getMonth(); @@ -472,20 +480,20 @@ function fillEmptySpotsInTimeline( const item = items.find((item) => { const date = new Date(item.date); - if (interval === "month") { + if (interval === 'month') { return ( getYear(date) === getYear(clonedStartDate) && getMonth(date) === getMonth(clonedStartDate) ); } - if (interval === "day") { + if (interval === 'day') { return ( getYear(date) === getYear(clonedStartDate) && getMonth(date) === getMonth(clonedStartDate) && getDay(date) === getDay(clonedStartDate) ); } - if (interval === "hour") { + if (interval === 'hour') { return ( getYear(date) === getYear(clonedStartDate) && getMonth(date) === getMonth(clonedStartDate) && @@ -493,7 +501,7 @@ function fillEmptySpotsInTimeline( getHour(date) === getHour(clonedStartDate) ); } - if (interval === "minute") { + if (interval === 'minute') { return ( getYear(date) === getYear(clonedStartDate) && getMonth(date) === getMonth(clonedStartDate) && @@ -515,19 +523,19 @@ function fillEmptySpotsInTimeline( } switch (interval) { - case "day": { + case 'day': { clonedStartDate.setDate(clonedStartDate.getDate() + 1); break; } - case "hour": { + case 'hour': { clonedStartDate.setHours(clonedStartDate.getHours() + 1); break; } - case "minute": { + case 'minute': { clonedStartDate.setMinutes(clonedStartDate.getMinutes() + 1); break; } - case "month": { + case 'month': { clonedStartDate.setMonth(clonedStartDate.getMonth() + 1); break; } diff --git a/apps/web/src/server/api/routers/client.ts b/apps/web/src/server/api/routers/client.ts index 6b6f28eb..75455d79 100644 --- a/apps/web/src/server/api/routers/client.ts +++ b/apps/web/src/server/api/routers/client.ts @@ -1,17 +1,16 @@ -import { z } from "zod"; - -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; -import { db } from "@/server/db"; -import { hashPassword } from "@/server/services/hash.service"; -import { randomUUID } from "crypto"; -import { getOrganizationBySlug } from "@/server/services/organization.service"; +import { randomUUID } from 'crypto'; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { db } from '@/server/db'; +import { hashPassword } from '@/server/services/hash.service'; +import { getOrganizationBySlug } from '@/server/services/organization.service'; +import { z } from 'zod'; export const clientRouter = createTRPCRouter({ list: protectedProcedure .input( z.object({ organizationSlug: z.string(), - }), + }) ) .query(async ({ input }) => { const organization = await getOrganizationBySlug(input.organizationSlug); @@ -28,7 +27,7 @@ export const clientRouter = createTRPCRouter({ .input( z.object({ id: z.string(), - }), + }) ) .query(({ input }) => { return db.client.findUniqueOrThrow({ @@ -42,7 +41,7 @@ export const clientRouter = createTRPCRouter({ z.object({ id: z.string(), name: z.string(), - }), + }) ) .mutation(({ input }) => { return db.client.update({ @@ -60,7 +59,7 @@ export const clientRouter = createTRPCRouter({ name: z.string(), projectId: z.string(), organizationSlug: z.string(), - }), + }) ) .mutation(async ({ input }) => { const organization = await getOrganizationBySlug(input.organizationSlug); @@ -83,7 +82,7 @@ export const clientRouter = createTRPCRouter({ .input( z.object({ id: z.string(), - }), + }) ) .mutation(async ({ input }) => { await db.client.delete({ diff --git a/apps/web/src/server/api/routers/dashboard.ts b/apps/web/src/server/api/routers/dashboard.ts index f974deba..db507904 100644 --- a/apps/web/src/server/api/routers/dashboard.ts +++ b/apps/web/src/server/api/routers/dashboard.ts @@ -1,9 +1,8 @@ -import { z } from "zod"; - -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; -import { db } from "@/server/db"; -import { getProjectBySlug } from "@/server/services/project.service"; -import { slug } from "@/utils/slug"; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { db } from '@/server/db'; +import { getProjectBySlug } from '@/server/services/project.service'; +import { slug } from '@/utils/slug'; +import { z } from 'zod'; export const dashboardRouter = createTRPCRouter({ list: protectedProcedure @@ -15,12 +14,12 @@ export const dashboardRouter = createTRPCRouter({ .or( z.object({ projectId: z.string(), - }), - ), + }) + ) ) .query(async ({ input }) => { let projectId = null; - if ("projectId" in input) { + if ('projectId' in input) { projectId = input.projectId; } else { projectId = (await getProjectBySlug(input.projectSlug)).id; @@ -37,7 +36,7 @@ export const dashboardRouter = createTRPCRouter({ z.object({ name: z.string(), projectId: z.string(), - }), + }) ) .mutation(async ({ input: { projectId, name } }) => { return db.dashboard.create({ diff --git a/apps/web/src/server/api/routers/event.ts b/apps/web/src/server/api/routers/event.ts index dc60401d..ec7618fe 100644 --- a/apps/web/src/server/api/routers/event.ts +++ b/apps/web/src/server/api/routers/event.ts @@ -1,6 +1,6 @@ -import { z } from "zod"; -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; -import { db } from "@/server/db"; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { db } from '@/server/db'; +import { z } from 'zod'; export const config = { api: { @@ -16,7 +16,7 @@ export const eventRouter = createTRPCRouter({ take: z.number().default(100), skip: z.number().default(0), profileId: z.string().optional(), - }), + }) ) .query(async ({ input: { take, skip, projectSlug, profileId } }) => { const project = await db.project.findUniqueOrThrow({ @@ -29,10 +29,10 @@ export const eventRouter = createTRPCRouter({ skip, where: { project_id: project.id, - profile_id: profileId + profile_id: profileId, }, orderBy: { - createdAt: "desc", + createdAt: 'desc', }, include: { profile: true, diff --git a/apps/web/src/server/api/routers/organization.ts b/apps/web/src/server/api/routers/organization.ts index 0700d653..f40f8295 100644 --- a/apps/web/src/server/api/routers/organization.ts +++ b/apps/web/src/server/api/routers/organization.ts @@ -1,9 +1,8 @@ -import { z } from "zod"; - -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; -import { db } from "@/server/db"; -import { getOrganizationBySlug } from "@/server/services/organization.service"; -import { slug } from "@/utils/slug"; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { db } from '@/server/db'; +import { getOrganizationBySlug } from '@/server/services/organization.service'; +import { slug } from '@/utils/slug'; +import { z } from 'zod'; export const organizationRouter = createTRPCRouter({ first: protectedProcedure.query(({ ctx }) => { @@ -21,17 +20,17 @@ export const organizationRouter = createTRPCRouter({ .input( z.object({ slug: z.string(), - }), + }) ) .query(({ input }) => { - return getOrganizationBySlug(input.slug) + return getOrganizationBySlug(input.slug); }), update: protectedProcedure .input( z.object({ id: z.string(), name: z.string(), - }), + }) ) .mutation(({ input }) => { return db.organization.update({ @@ -40,7 +39,7 @@ export const organizationRouter = createTRPCRouter({ }, data: { name: input.name, - slug: slug(input.name) + slug: slug(input.name), }, }); }), diff --git a/apps/web/src/server/api/routers/profile.ts b/apps/web/src/server/api/routers/profile.ts index 19220adb..abf32709 100644 --- a/apps/web/src/server/api/routers/profile.ts +++ b/apps/web/src/server/api/routers/profile.ts @@ -1,6 +1,6 @@ -import { z } from "zod"; -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; -import { db } from "@/server/db"; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { db } from '@/server/db'; +import { z } from 'zod'; export const config = { api: { @@ -15,7 +15,7 @@ export const profileRouter = createTRPCRouter({ projectSlug: z.string(), take: z.number().default(100), skip: z.number().default(0), - }), + }) ) .query(async ({ input: { take, skip, projectSlug } }) => { const project = await db.project.findUniqueOrThrow({ @@ -30,7 +30,7 @@ export const profileRouter = createTRPCRouter({ project_id: project.id, }, orderBy: { - createdAt: "desc", + createdAt: 'desc', }, }); }), diff --git a/apps/web/src/server/api/routers/project.ts b/apps/web/src/server/api/routers/project.ts index b46cac49..0fab882b 100644 --- a/apps/web/src/server/api/routers/project.ts +++ b/apps/web/src/server/api/routers/project.ts @@ -1,15 +1,14 @@ -import { z } from "zod"; - -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; -import { db } from "@/server/db"; -import { getOrganizationBySlug } from "@/server/services/organization.service"; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { db } from '@/server/db'; +import { getOrganizationBySlug } from '@/server/services/organization.service'; +import { z } from 'zod'; export const projectRouter = createTRPCRouter({ list: protectedProcedure .input( z.object({ organizationSlug: z.string(), - }), + }) ) .query(async ({ input }) => { const organization = await getOrganizationBySlug(input.organizationSlug); @@ -23,7 +22,7 @@ export const projectRouter = createTRPCRouter({ .input( z.object({ id: z.string(), - }), + }) ) .query(({ input }) => { return db.project.findUniqueOrThrow({ @@ -37,7 +36,7 @@ export const projectRouter = createTRPCRouter({ z.object({ id: z.string(), name: z.string(), - }), + }) ) .mutation(({ input }) => { return db.project.update({ @@ -54,7 +53,7 @@ export const projectRouter = createTRPCRouter({ z.object({ name: z.string(), organizationSlug: z.string(), - }), + }) ) .mutation(async ({ input }) => { const organization = await getOrganizationBySlug(input.organizationSlug); @@ -69,7 +68,7 @@ export const projectRouter = createTRPCRouter({ .input( z.object({ id: z.string(), - }), + }) ) .mutation(async ({ input }) => { await db.project.delete({ diff --git a/apps/web/src/server/api/routers/report.ts b/apps/web/src/server/api/routers/report.ts index 46ddaf31..cd811409 100644 --- a/apps/web/src/server/api/routers/report.ts +++ b/apps/web/src/server/api/routers/report.ts @@ -1,48 +1,54 @@ -import { z } from "zod"; - -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; -import { zChartInput } from "@/utils/validation"; -import { db } from "@/server/db"; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { db } from '@/server/db'; +import { getDashboardBySlug } from '@/server/services/dashboard.service'; +import { getProjectBySlug } from '@/server/services/project.service'; import { - type IChartInput, type IChartBreakdown, type IChartEvent, type IChartEventFilter, + type IChartInput, type IChartRange, -} from "@/types"; -import { type Report as DbReport } from "@prisma/client"; -import { getProjectBySlug } from "@/server/services/project.service"; -import { getDashboardBySlug } from "@/server/services/dashboard.service"; -import { alphabetIds } from "@/utils/constants"; +} from '@/types'; +import { alphabetIds } from '@/utils/constants'; +import { zChartInput } from '@/utils/validation'; +import { type Report as DbReport } from '@prisma/client'; +import { z } from 'zod'; -function transformFilter(filter: Partial, index: number): IChartEventFilter { +function transformFilter( + filter: Partial, + index: number +): IChartEventFilter { return { id: filter.id ?? alphabetIds[index]!, name: filter.name ?? 'Unknown Filter', operator: filter.operator ?? 'is', - value: typeof filter.value === 'string' ? [filter.value] : filter.value ?? [], - } + value: + typeof filter.value === 'string' ? [filter.value] : filter.value ?? [], + }; } -function transformEvent(event: Partial, index: number): IChartEvent { +function transformEvent( + event: Partial, + index: number +): IChartEvent { return { segment: event.segment ?? 'event', filters: (event.filters ?? []).map(transformFilter), id: event.id ?? alphabetIds[index]!, // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing name: event.name || 'Untitled', - } + }; } function transformReport(report: DbReport): IChartInput & { id: string } { return { id: report.id, - events: (report.events as IChartEvent[]).map(transformEvent), + events: (report.events as IChartEvent[]).map(transformEvent), breakdowns: report.breakdowns as IChartBreakdown[], chartType: report.chart_type, interval: report.interval, name: report.name || 'Untitled', - range: report.range as IChartRange ?? 30, + range: (report.range as IChartRange) ?? 30, }; } @@ -51,7 +57,7 @@ export const reportRouter = createTRPCRouter({ .input( z.object({ id: z.string(), - }), + }) ) .query(({ input: { id } }) => { return db.report @@ -67,7 +73,7 @@ export const reportRouter = createTRPCRouter({ z.object({ projectSlug: z.string(), dashboardSlug: z.string(), - }), + }) ) .query(async ({ input: { projectSlug, dashboardSlug } }) => { const project = await getProjectBySlug(projectSlug); @@ -82,7 +88,7 @@ export const reportRouter = createTRPCRouter({ return { reports: reports.map(transformReport), dashboard, - } + }; }), save: protectedProcedure .input( @@ -90,7 +96,7 @@ export const reportRouter = createTRPCRouter({ report: zChartInput, projectId: z.string(), dashboardId: z.string(), - }), + }) ) .mutation(({ input: { report, projectId, dashboardId } }) => { return db.report.create({ @@ -105,7 +111,6 @@ export const reportRouter = createTRPCRouter({ range: report.range, }, }); - }), update: protectedProcedure .input( @@ -114,7 +119,7 @@ export const reportRouter = createTRPCRouter({ report: zChartInput, projectId: z.string(), dashboardId: z.string(), - }), + }) ) .mutation(({ input: { report, projectId, dashboardId, reportId } }) => { return db.report.update({ diff --git a/apps/web/src/server/api/routers/user.ts b/apps/web/src/server/api/routers/user.ts index 46d2a9a4..bacfd0c6 100644 --- a/apps/web/src/server/api/routers/user.ts +++ b/apps/web/src/server/api/routers/user.ts @@ -1,63 +1,59 @@ -import { z } from "zod"; - -import { - createTRPCRouter, - protectedProcedure, -} from "@/server/api/trpc"; -import { db } from "@/server/db"; -import { hashPassword, verifyPassword } from "@/server/services/hash.service"; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { db } from '@/server/db'; +import { hashPassword, verifyPassword } from '@/server/services/hash.service'; +import { z } from 'zod'; export const userRouter = createTRPCRouter({ current: protectedProcedure.query(({ ctx }) => { return db.user.findUniqueOrThrow({ where: { - id: ctx.session.user.id - } - }) + id: ctx.session.user.id, + }, + }); }), update: protectedProcedure .input( z.object({ name: z.string(), email: z.string(), - }), + }) ) .mutation(({ input, ctx }) => { return db.user.update({ where: { - id: ctx.session.user.id + id: ctx.session.user.id, }, data: { name: input.name, email: input.email, - } - }) + }, + }); }), changePassword: protectedProcedure .input( z.object({ password: z.string(), oldPassword: z.string(), - }), + }) ) .mutation(async ({ input, ctx }) => { const user = await db.user.findUniqueOrThrow({ where: { - id: ctx.session.user.id - } - }) + id: ctx.session.user.id, + }, + }); - if(!(await verifyPassword(input.oldPassword, user.password))) { - throw new Error('Old password is incorrect') + if (!(await verifyPassword(input.oldPassword, user.password))) { + throw new Error('Old password is incorrect'); } - + return db.user.update({ where: { - id: ctx.session.user.id + id: ctx.session.user.id, }, data: { password: await hashPassword(input.password), - } - }) + }, + }); }), }); diff --git a/apps/web/src/server/api/trpc.ts b/apps/web/src/server/api/trpc.ts index 23300729..9fa87636 100644 --- a/apps/web/src/server/api/trpc.ts +++ b/apps/web/src/server/api/trpc.ts @@ -7,14 +7,13 @@ * need to use are documented accordingly near the end. */ -import { initTRPC, TRPCError } from "@trpc/server"; -import { type CreateNextContextOptions } from "@trpc/server/adapters/next"; -import { type Session } from "next-auth"; -import superjson from "superjson"; -import { ZodError } from "zod"; - -import { getServerAuthSession } from "@/server/auth"; -import { db } from "@/server/db"; +import { getServerAuthSession } from '@/server/auth'; +import { db } from '@/server/db'; +import { initTRPC, TRPCError } from '@trpc/server'; +import { type CreateNextContextOptions } from '@trpc/server/adapters/next'; +import { type Session } from 'next-auth'; +import superjson from 'superjson'; +import { ZodError } from 'zod'; /** * 1. CONTEXT @@ -109,7 +108,7 @@ export const publicProcedure = t.procedure; /** Reusable middleware that enforces users are logged in before running the procedure. */ const enforceUserIsAuthed = t.middleware(({ ctx, next }) => { if (!ctx.session?.user) { - throw new TRPCError({ code: "UNAUTHORIZED" }); + throw new TRPCError({ code: 'UNAUTHORIZED' }); } return next({ ctx: { diff --git a/apps/web/src/server/auth.ts b/apps/web/src/server/auth.ts index f8e60666..ae7e2d15 100644 --- a/apps/web/src/server/auth.ts +++ b/apps/web/src/server/auth.ts @@ -1,14 +1,14 @@ -import { type NextApiRequest, type GetServerSidePropsContext } from "next"; +import { db } from '@/server/db'; +import { verifyPassword } from '@/server/services/hash.service'; +import { type GetServerSidePropsContext, type NextApiRequest } from 'next'; import { getServerSession, type DefaultSession, type NextAuthOptions, -} from "next-auth"; +} from 'next-auth'; +import Credentials from 'next-auth/providers/credentials'; -import { db } from "@/server/db"; -import Credentials from "next-auth/providers/credentials"; -import { createError } from "./exceptions"; -import { hashPassword, verifyPassword } from "@/server/services/hash.service"; +import { createError } from './exceptions'; /** * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session` @@ -16,9 +16,9 @@ import { hashPassword, verifyPassword } from "@/server/services/hash.service"; * * @see https://next-auth.js.org/getting-started/typescript#module-augmentation */ -declare module "next-auth" { +declare module 'next-auth' { interface Session extends DefaultSession { - user: DefaultSession["user"] & { + user: DefaultSession['user'] & { id: string; }; } @@ -45,35 +45,35 @@ export const authOptions: NextAuthOptions = { }), }, session: { - strategy: "jwt", + strategy: 'jwt', }, providers: [ Credentials({ - name: "Credentials", + name: 'Credentials', credentials: { - email: { label: "Email", type: "text", placeholder: "jsmith" }, - password: { label: "Password", type: "password" }, + email: { label: 'Email', type: 'text', placeholder: 'jsmith' }, + password: { label: 'Password', type: 'password' }, }, async authorize(credentials) { - if(!credentials?.password || !credentials?.email) { - return null + if (!credentials?.password || !credentials?.email) { + return null; } const user = await db.user.findFirst({ where: { email: credentials?.email }, }); - if(!user) { - return null + if (!user) { + return null; } - - if(!await verifyPassword(credentials.password, user.password)) { - return null + + if (!(await verifyPassword(credentials.password, user.password))) { + return null; } return { ...user, - image: 'https://api.dicebear.com/7.x/adventurer/svg?seed=Abby' + image: 'https://api.dicebear.com/7.x/adventurer/svg?seed=Abby', }; }, }), @@ -95,22 +95,22 @@ export const authOptions: NextAuthOptions = { * @see https://next-auth.js.org/configuration/nextjs */ export const getServerAuthSession = (ctx: { - req: GetServerSidePropsContext["req"]; - res: GetServerSidePropsContext["res"]; + req: GetServerSidePropsContext['req']; + res: GetServerSidePropsContext['res']; }) => { return getServerSession(ctx.req, ctx.res, authOptions); }; export async function validateSdkRequest(req: NextApiRequest): Promise { - const clientId = req?.headers["mixan-client-id"] as string | undefined - const clientSecret = req.headers["mixan-client-secret"] as string | undefined - + const clientId = req?.headers['mixan-client-id'] as string | undefined; + const clientSecret = req.headers['mixan-client-secret'] as string | undefined; + if (!clientId) { - throw createError(401, "Misisng client id"); + throw createError(401, 'Misisng client id'); } if (!clientSecret) { - throw createError(401, "Misisng client secret"); + throw createError(401, 'Misisng client secret'); } const client = await db.client.findUnique({ @@ -120,14 +120,12 @@ export async function validateSdkRequest(req: NextApiRequest): Promise { }); if (!client) { - throw createError(401, "Invalid client id"); + throw createError(401, 'Invalid client id'); } - - if (!(await verifyPassword(clientSecret, client.secret))) { - throw createError(401, "Invalid client secret"); + throw createError(401, 'Invalid client secret'); } - return client.project_id + return client.project_id; } diff --git a/apps/web/src/server/db.ts b/apps/web/src/server/db.ts index ebdfa0e4..d8ba8c4e 100644 --- a/apps/web/src/server/db.ts +++ b/apps/web/src/server/db.ts @@ -1,6 +1,5 @@ -import { PrismaClient } from "@prisma/client"; - -import { env } from "@/env.mjs"; +import { env } from '@/env.mjs'; +import { PrismaClient } from '@prisma/client'; const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined; @@ -9,8 +8,7 @@ const globalForPrisma = globalThis as unknown as { export const db = globalForPrisma.prisma ?? new PrismaClient({ - log: - ['error'] + log: ['error'], }); -if (env.NODE_ENV !== "production") globalForPrisma.prisma = db; +if (env.NODE_ENV !== 'production') globalForPrisma.prisma = db; diff --git a/apps/web/src/server/exceptions.ts b/apps/web/src/server/exceptions.ts index f622d43c..f7e480ec 100644 --- a/apps/web/src/server/exceptions.ts +++ b/apps/web/src/server/exceptions.ts @@ -1,55 +1,52 @@ -import { - type MixanIssue, - type MixanErrorResponse -} from '@mixan/types' -import { type NextApiResponse } from 'next' +import { type NextApiResponse } from 'next'; + +import { type MixanErrorResponse, type MixanIssue } from '@mixan/types'; export class HttpError extends Error { - public status: number - public message: string - public issues: MixanIssue[] + public status: number; + public message: string; + public issues: MixanIssue[]; constructor(status: number, message: string | Error, issues?: MixanIssue[]) { - super(message instanceof Error ? message.message : message) - this.status = status - this.message = message instanceof Error ? message.message : message - this.issues = issues ?? [] + super(message instanceof Error ? message.message : message); + this.status = status; + this.message = message instanceof Error ? message.message : message; + this.issues = issues ?? []; } - toJson(): MixanErrorResponse { + toJson(): MixanErrorResponse { return { code: this.status, status: 'error', message: this.message, issues: this.issues.length ? this.issues : undefined, stack: process.env.NODE_ENV !== 'production' ? this.stack : undefined, - } + }; } } export function createIssues(arr: Array) { - throw new HttpError(400, 'Issues', arr) + throw new HttpError(400, 'Issues', arr); } export function createError(status = 500, error: unknown) { - if(error instanceof Error || typeof error === 'string') { - return new HttpError(status, error) - } + if (error instanceof Error || typeof error === 'string') { + return new HttpError(status, error); + } - return new HttpError(500, 'Unexpected error occured') + return new HttpError(500, 'Unexpected error occured'); } export function handleError(res: NextApiResponse, error: unknown) { - if(error instanceof HttpError) { - return res.status(error.status).json(error.toJson()) - } - - if(error instanceof Error) { - const httpError = createError(500, error) - res.status(httpError.status).json(httpError.toJson()) + if (error instanceof HttpError) { + return res.status(error.status).json(error.toJson()); } - - - const httpError = createError(500, error) - res.status(httpError.status).json(httpError.toJson()) -} \ No newline at end of file + + if (error instanceof Error) { + const httpError = createError(500, error); + res.status(httpError.status).json(httpError.toJson()); + } + + const httpError = createError(500, error); + res.status(httpError.status).json(httpError.toJson()); +} diff --git a/apps/web/src/server/getServerSideProps.ts b/apps/web/src/server/getServerSideProps.ts index 8eff24fe..577a93cf 100644 --- a/apps/web/src/server/getServerSideProps.ts +++ b/apps/web/src/server/getServerSideProps.ts @@ -1,45 +1,46 @@ import { type GetServerSidePropsContext, type GetServerSidePropsResult, -} from "next"; -import { getServerAuthSession } from "./auth"; -import { db } from "./db"; +} from 'next'; + +import { getServerAuthSession } from './auth'; +import { db } from './db'; export function createServerSideProps( - cb?: (context: GetServerSidePropsContext) => Promise, + cb?: (context: GetServerSidePropsContext) => Promise ) { return async function getServerSideProps( - context: GetServerSidePropsContext, + context: GetServerSidePropsContext ): Promise> { - const session = await getServerAuthSession(context); + const session = await getServerAuthSession(context); - if(!session) { + if (!session) { return { redirect: { - destination: "/api/auth/signin", + destination: '/api/auth/signin', permanent: false, }, - } + }; } - if(context.params?.organization) { + if (context.params?.organization) { const organization = await db.user.findFirst({ where: { id: session.user.id, organization: { - slug: context.params.organization as string - } - } - }) - - if(!organization) { + slug: context.params.organization as string, + }, + }, + }); + + if (!organization) { return { notFound: true, - } + }; } } - const res = await (typeof cb === "function" + const res = await (typeof cb === 'function' ? cb(context) : Promise.resolve({})); return { diff --git a/apps/web/src/server/services/dashboard.service.ts b/apps/web/src/server/services/dashboard.service.ts index c0074076..ad80ae53 100644 --- a/apps/web/src/server/services/dashboard.service.ts +++ b/apps/web/src/server/services/dashboard.service.ts @@ -1,9 +1,9 @@ -import { db } from "../db"; +import { db } from '../db'; export function getDashboardBySlug(slug: string) { return db.dashboard.findUniqueOrThrow({ where: { - slug + slug, }, - }); -} \ No newline at end of file + }); +} diff --git a/apps/web/src/server/services/hash.service.ts b/apps/web/src/server/services/hash.service.ts index fe402eb8..a030a923 100644 --- a/apps/web/src/server/services/hash.service.ts +++ b/apps/web/src/server/services/hash.service.ts @@ -1,4 +1,4 @@ -import { scrypt, randomBytes, timingSafeEqual } from "crypto"; +import { randomBytes, scrypt, timingSafeEqual } from 'crypto'; const keyLength = 32; /** @@ -6,17 +6,17 @@ const keyLength = 32; * @param {string} password * @returns {string} The salt+hash */ -export async function hashPassword (password: string): Promise { +export async function hashPassword(password: string): Promise { return new Promise((resolve, reject) => { // generate random 16 bytes long salt - recommended by NodeJS Docs - const salt = randomBytes(16).toString("hex"); + const salt = randomBytes(16).toString('hex'); scrypt(password, salt, keyLength, (err, derivedKey) => { if (err) reject(err); // derivedKey is of type Buffer - resolve(`${salt}.${derivedKey.toString("hex")}`); + resolve(`${salt}.${derivedKey.toString('hex')}`); }); }); -}; +} /** * Compare a plain text password with a salt+hash password @@ -24,11 +24,14 @@ export async function hashPassword (password: string): Promise { * @param {string} hash The hash+salt to check against * @returns {boolean} */ -export async function verifyPassword (password: string, hash: string): Promise { +export async function verifyPassword( + password: string, + hash: string +): Promise { return new Promise((resolve, reject) => { - const [salt, hashKey] = hash.split("."); + const [salt, hashKey] = hash.split('.'); // we need to pass buffer values to timingSafeEqual - const hashKeyBuff = Buffer.from(hashKey!, "hex"); + const hashKeyBuff = Buffer.from(hashKey!, 'hex'); scrypt(password, salt!, keyLength, (err, derivedKey) => { if (err) { reject(err); @@ -37,4 +40,4 @@ export async function verifyPassword (password: string, hash: string): Promise - const value = name in properties ? properties[name] : 0 + ) as Record; + const value = name in properties ? properties[name] : 0; if (typeof value !== 'number') { - throw new HttpError(400, `Property "${name}" on user is of type ${typeof value}`) + throw new HttpError( + 400, + `Property "${name}" on user is of type ${typeof value}` + ); } - + if (typeof tick !== 'number') { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw new HttpError(400, `Value is not a number ${tick} (${typeof tick})`) + throw new HttpError(400, `Value is not a number ${tick} (${typeof tick})`); } await db.profile.update({ @@ -48,5 +51,5 @@ export async function tickProfileProperty({ [name]: value + tick, }, }, - }) -} \ No newline at end of file + }); +} diff --git a/apps/web/src/server/services/project.service.ts b/apps/web/src/server/services/project.service.ts index a08f390f..6777cf16 100644 --- a/apps/web/src/server/services/project.service.ts +++ b/apps/web/src/server/services/project.service.ts @@ -1,9 +1,9 @@ -import { db } from "../db"; +import { db } from '../db'; export function getProjectBySlug(slug: string) { return db.project.findUniqueOrThrow({ where: { - slug + slug, }, - }); -} \ No newline at end of file + }); +} diff --git a/apps/web/src/types/index.ts b/apps/web/src/types/index.ts index c792c712..fd82be31 100644 --- a/apps/web/src/types/index.ts +++ b/apps/web/src/types/index.ts @@ -1,27 +1,35 @@ -import { type RouterOutputs } from "@/utils/api"; -import { type timeRanges } from "@/utils/constants"; -import { type zTimeInterval, type zChartBreakdown, type zChartEvent, type zChartInput, type zChartType, type zChartInputWithDates } from "@/utils/validation"; -import { type Client, type Project } from "@prisma/client"; -import { type TooltipProps } from "recharts"; -import { type z } from "zod"; +import { type RouterOutputs } from '@/utils/api'; +import { type timeRanges } from '@/utils/constants'; +import { + type zChartBreakdown, + type zChartEvent, + type zChartInput, + type zChartInputWithDates, + type zChartType, + type zTimeInterval, +} from '@/utils/validation'; +import { type Client, type Project } from '@prisma/client'; +import { type TooltipProps } from 'recharts'; +import { type z } from 'zod'; export type HtmlProps = React.DetailedHTMLProps, T>; -export type IChartInput = z.infer -export type IChartInputWithDates = z.infer -export type IChartEvent = z.infer -export type IChartEventFilter = IChartEvent['filters'][number] -export type IChartEventFilterValue = IChartEvent['filters'][number]['value'][number] -export type IChartBreakdown = z.infer -export type IInterval = z.infer -export type IChartType = z.infer -export type IChartData = RouterOutputs["chart"]["chart"]; -export type IChartRange = typeof timeRanges[number]['range']; +export type IChartInput = z.infer; +export type IChartInputWithDates = z.infer; +export type IChartEvent = z.infer; +export type IChartEventFilter = IChartEvent['filters'][number]; +export type IChartEventFilterValue = + IChartEvent['filters'][number]['value'][number]; +export type IChartBreakdown = z.infer; +export type IInterval = z.infer; +export type IChartType = z.infer; +export type IChartData = RouterOutputs['chart']['chart']; +export type IChartRange = (typeof timeRanges)[number]['range']; export type IToolTipProps = Omit, 'payload'> & { - payload?: Array -} + payload?: Array; +}; -export type IProject = Project +export type IProject = Project; export type IClientWithProject = Client & { - project: IProject -} + project: IProject; +}; diff --git a/apps/web/src/utils/api.ts b/apps/web/src/utils/api.ts index 5f06f7b2..916de3a6 100644 --- a/apps/web/src/utils/api.ts +++ b/apps/web/src/utils/api.ts @@ -4,16 +4,15 @@ * * We also create a few inference helpers for input and output types. */ -import { type TRPCClientErrorBase, httpLink, loggerLink } from "@trpc/client"; -import { createTRPCNext } from "@trpc/next"; -import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server"; -import superjson from "superjson"; - -import { type AppRouter } from "@/server/api/root"; -import { toast } from "@/components/ui/use-toast"; +import { toast } from '@/components/ui/use-toast'; +import { type AppRouter } from '@/server/api/root'; +import { httpLink, loggerLink, type TRPCClientErrorBase } from '@trpc/client'; +import { createTRPCNext } from '@trpc/next'; +import { type inferRouterInputs, type inferRouterOutputs } from '@trpc/server'; +import superjson from 'superjson'; const getBaseUrl = () => { - if (typeof window !== "undefined") return ""; // browser should use relative url + if (typeof window !== 'undefined') return ''; // browser should use relative url if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost }; @@ -28,9 +27,9 @@ export const api = createTRPCNext({ refetchOnWindowFocus: false, refetchOnReconnect: false, refetchOnMount: false, - enabled: typeof window !== "undefined", + enabled: typeof window !== 'undefined', }, - } + }, }, /** * Transformer used for data de-serialization from the server. @@ -47,8 +46,8 @@ export const api = createTRPCNext({ links: [ loggerLink({ enabled: (opts) => - process.env.NODE_ENV === "development" || - (opts.direction === "down" && opts.result instanceof Error), + process.env.NODE_ENV === 'development' || + (opts.direction === 'down' && opts.result instanceof Error), }), httpLink({ url: `${getBaseUrl()}/api/trpc`, @@ -78,10 +77,9 @@ export type RouterInputs = inferRouterInputs; */ export type RouterOutputs = inferRouterOutputs; - export function handleError(error: TRPCClientErrorBase) { toast({ title: 'Error', description: error.message, - }) -} \ No newline at end of file + }); +} diff --git a/apps/web/src/utils/clipboard.ts b/apps/web/src/utils/clipboard.ts index 23615ca8..d2b4d29e 100644 --- a/apps/web/src/utils/clipboard.ts +++ b/apps/web/src/utils/clipboard.ts @@ -1,9 +1,9 @@ -import { toast } from "@/components/ui/use-toast" +import { toast } from '@/components/ui/use-toast'; export function clipboard(value: string | number) { - navigator.clipboard.writeText(value.toString()) + navigator.clipboard.writeText(value.toString()); toast({ - title: "Copied to clipboard", + title: 'Copied to clipboard', description: value.toString(), - }) -} \ No newline at end of file + }); +} diff --git a/apps/web/src/utils/cn.ts b/apps/web/src/utils/cn.ts index a7dc3a13..2819a830 100644 --- a/apps/web/src/utils/cn.ts +++ b/apps/web/src/utils/cn.ts @@ -1,6 +1,6 @@ -import { clsx, type ClassValue } from "clsx" -import { twMerge } from "tailwind-merge" +import { clsx, type ClassValue } from 'clsx'; +import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} \ No newline at end of file + return twMerge(clsx(inputs)); +} diff --git a/apps/web/src/utils/constants.ts b/apps/web/src/utils/constants.ts index 13d3cf56..8368df95 100644 --- a/apps/web/src/utils/constants.ts +++ b/apps/web/src/utils/constants.ts @@ -1,47 +1,47 @@ export const operators = { - is: "Is", - isNot: "Is not", - contains: "Contains", - doesNotContain: "Not contains", + is: 'Is', + isNot: 'Is not', + contains: 'Contains', + doesNotContain: 'Not contains', }; export const chartTypes = { - linear: "Linear", - bar: "Bar", - pie: "Pie", - metric: "Metric", - area: "Area", + linear: 'Linear', + bar: 'Bar', + pie: 'Pie', + metric: 'Metric', + area: 'Area', }; export const intervals = { - minute: "Minute", - day: "Day", - hour: "Hour", - month: "Month", + minute: 'Minute', + day: 'Day', + hour: 'Hour', + month: 'Month', }; export const alphabetIds = [ - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', ] as const; export const timeRanges = [ - { range: 0.3, title: "30m" }, - { range: 0.6, title: "1h" }, - { range: 0, title: "Today" }, - { range: 1, title: "24h" }, - { range: 7, title: "7d" }, - { range: 14, title: "14d" }, - { range: 30, title: "30d" }, - { range: 90, title: "3mo" }, - { range: 180, title: "6mo" }, - { range: 365, title: "1y" }, + { range: 0.3, title: '30m' }, + { range: 0.6, title: '1h' }, + { range: 0, title: 'Today' }, + { range: 1, title: '24h' }, + { range: 7, title: '7d' }, + { range: 14, title: '14d' }, + { range: 30, title: '30d' }, + { range: 90, title: '3mo' }, + { range: 180, title: '6mo' }, + { range: 365, title: '1y' }, ] as const; diff --git a/apps/web/src/utils/date.ts b/apps/web/src/utils/date.ts index b4e36930..bf8179dc 100644 --- a/apps/web/src/utils/date.ts +++ b/apps/web/src/utils/date.ts @@ -10,11 +10,11 @@ export function dateDifferanceInDays(date1: Date, date2: Date) { } export function getLocale() { - if (typeof navigator === "undefined") { - return "en-US"; + if (typeof navigator === 'undefined') { + return 'en-US'; } - return navigator.language ?? "en-US"; + return navigator.language ?? 'en-US'; } export function formatDate(date: Date) { @@ -23,10 +23,10 @@ export function formatDate(date: Date) { export function formatDateTime(date: Date) { return new Intl.DateTimeFormat(getLocale(), { - day: "numeric", - month: "numeric", - year: "numeric", - hour: "numeric", - minute: "numeric", + day: 'numeric', + month: 'numeric', + year: 'numeric', + hour: 'numeric', + minute: 'numeric', }).format(date); } diff --git a/apps/web/src/utils/getRangeLabel.ts b/apps/web/src/utils/getRangeLabel.ts index 8ec9fc55..72c78a9a 100644 --- a/apps/web/src/utils/getRangeLabel.ts +++ b/apps/web/src/utils/getRangeLabel.ts @@ -1,8 +1,7 @@ -import { type IChartRange } from "@/types"; -import { timeRanges } from "./constants"; +import { type IChartRange } from '@/types'; + +import { timeRanges } from './constants'; export function getRangeLabel(range: IChartRange) { - return timeRanges.find( - (item) => item.range === range, - )?.title ?? null -} \ No newline at end of file + return timeRanges.find((item) => item.range === range)?.title ?? null; +} diff --git a/apps/web/src/utils/object.ts b/apps/web/src/utils/object.ts index 37aabe34..6d8fb566 100644 --- a/apps/web/src/utils/object.ts +++ b/apps/web/src/utils/object.ts @@ -1,9 +1,9 @@ export function toDots( obj: Record, - path = "", + path = '' ): Record { return Object.entries(obj).reduce((acc, [key, value]) => { - if (typeof value === "object" && value !== null) { + if (typeof value === 'object' && value !== null) { return { ...acc, ...toDots(value as Record, `${path}${key}.`), @@ -15,4 +15,4 @@ export function toDots( [`${path}${key}`]: value, }; }, {}); -} \ No newline at end of file +} diff --git a/apps/web/src/utils/slug.ts b/apps/web/src/utils/slug.ts index 59625e54..2c448002 100644 --- a/apps/web/src/utils/slug.ts +++ b/apps/web/src/utils/slug.ts @@ -1,4 +1,4 @@ -import _slugify from 'slugify' +import _slugify from 'slugify'; const slugify = (str: string) => { return _slugify( @@ -9,10 +9,10 @@ const slugify = (str: string) => { .replace('Å', 'A') .replace('Ä', 'A') .replace('Ö', 'O'), - { lower: true, strict: true, trim: true }, - ) -} + { lower: true, strict: true, trim: true } + ); +}; export function slug(str: string): string { - return slugify(str) + return slugify(str); } diff --git a/apps/web/src/utils/theme.ts b/apps/web/src/utils/theme.ts index 348f7e73..b81d27fb 100644 --- a/apps/web/src/utils/theme.ts +++ b/apps/web/src/utils/theme.ts @@ -1,5 +1,7 @@ -import resolveConfig from "tailwindcss/resolveConfig"; -import tailwinConfig from "../../tailwind.config"; +import resolveConfig from 'tailwindcss/resolveConfig'; + +import tailwinConfig from '../../tailwind.config'; + // @ts-expect-error const config = resolveConfig(tailwinConfig); @@ -7,7 +9,7 @@ export const theme = config.theme as any; export function getChartColor(index: number): string { const chartColors: string[] = Object.keys(theme?.colors ?? {}) - .filter((key) => key.startsWith("chart-")) + .filter((key) => key.startsWith('chart-')) .map((key) => theme.colors[key] as string); return chartColors[index % chartColors.length]!; diff --git a/apps/web/src/utils/validation.ts b/apps/web/src/utils/validation.ts index 87aafc2d..fed48ef1 100644 --- a/apps/web/src/utils/validation.ts +++ b/apps/web/src/utils/validation.ts @@ -1,5 +1,6 @@ -import { z } from "zod"; -import { operators, chartTypes, intervals } from "./constants"; +import { z } from 'zod'; + +import { chartTypes, intervals, operators } from './constants'; function objectToZodEnums(obj: Record): [K, ...K[]] { const [firstKey, ...otherKeys] = Object.keys(obj) as K[]; @@ -9,14 +10,14 @@ function objectToZodEnums(obj: Record): [K, ...K[]] { export const zChartEvent = z.object({ id: z.string(), name: z.string(), - segment: z.enum(["event", "user"]), + segment: z.enum(['event', 'user']), filters: z.array( z.object({ id: z.string(), name: z.string(), operator: z.enum(objectToZodEnums(operators)), value: z.array(z.string().or(z.number()).or(z.boolean()).or(z.null())), - }), + }) ), }); export const zChartBreakdown = z.object({ diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts index 35127895..f6c2dbc8 100644 --- a/apps/web/tailwind.config.ts +++ b/apps/web/tailwind.config.ts @@ -1,72 +1,70 @@ const colors = [ - "#7856ff", - "#ff7557", - "#7fe1d8", - "#f8bc3c", - "#b3596e", - "#72bef4", - "#ffb27a", - "#0f7ea0", - "#3ba974", - "#febbb2", - "#cb80dc", - "#5cb7af", + '#7856ff', + '#ff7557', + '#7fe1d8', + '#f8bc3c', + '#b3596e', + '#72bef4', + '#ffb27a', + '#0f7ea0', + '#3ba974', + '#febbb2', + '#cb80dc', + '#5cb7af', ]; /** @type {import('tailwindcss').Config} */ const config = { - safelist: [ - ...colors.map((color) => `chart-${color}`), - ], - darkMode: ["class"], + safelist: [...colors.map((color) => `chart-${color}`)], + darkMode: ['class'], content: [ - "./pages/**/*.{ts,tsx}", - "./components/**/*.{ts,tsx}", - "./app/**/*.{ts,tsx}", - "./src/**/*.{ts,tsx}", + './pages/**/*.{ts,tsx}', + './components/**/*.{ts,tsx}', + './app/**/*.{ts,tsx}', + './src/**/*.{ts,tsx}', ], theme: { container: { center: true, - padding: "2rem", + padding: '2rem', screens: { - "2xl": "1400px", + '2xl': '1400px', }, }, extend: { colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", - background: "hsl(var(--background))", - foreground: "hsl(var(--foreground))", + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', primary: { - DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', }, secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', }, destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', }, muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', }, accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', }, popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', }, card: { - DEFAULT: "hsl(var(--card))", - foreground: "hsl(var(--card-foreground))", + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', }, ...colors.reduce((acc, color, index) => { return { @@ -76,30 +74,30 @@ const config = { }, {}), }, borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', }, boxShadow: { - DEFAULT: '0 5px 10px rgb(0 0 0 / 5%)' + DEFAULT: '0 5px 10px rgb(0 0 0 / 5%)', }, keyframes: { - "accordion-down": { + 'accordion-down': { from: { height: 0 }, - to: { height: "var(--radix-accordion-content-height)" }, + to: { height: 'var(--radix-accordion-content-height)' }, }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, to: { height: 0 }, }, }, animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', }, }, }, - plugins: [require("tailwindcss-animate")], + plugins: [require('tailwindcss-animate')], }; -export default config \ No newline at end of file +export default config; diff --git a/package.json b/package.json index 1ed66c46..cae12299 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,25 @@ { "name": "@mixan/root", "version": "1.0.0", - "keywords": [], - "author": "", + "private": true, + "license": "MIT", + "author": "Carl-Gerhard Lindesvärd", "packageManager": "pnpm@8.7.6", - "license": "ISC", "module": "index.ts", "type": "module", "scripts": { - "dev": "pnpm -r dev" + "dev": "pnpm -r dev", + "format": "pnpm -r format --cache --cache-location=\"node_modules/.cache/.prettiercache\"", + "format:fix": "pnpm -r format --write --cache --cache-location=\"node_modules/.cache/.prettiercache\"", + "lint": "pnpm -r lint", + "lint:fix": "pnpm -r lint --fix", + "lint:workspace": "pnpm dlx sherif@latest", + "typecheck": "pnpm -r typecheck" }, "devDependencies": { "semver": "^7.5.4" }, "peerDependencies": { - "typescript": "^5.0.0" + "typescript": "^5.2.0" } -} \ No newline at end of file +} diff --git a/packages/sdk/index.ts b/packages/sdk/index.ts index 24d0af97..74673a4e 100644 --- a/packages/sdk/index.ts +++ b/packages/sdk/index.ts @@ -1,43 +1,43 @@ -import { +import type { EventPayload, MixanErrorResponse, ProfilePayload, -} from '@mixan/types' +} from '@mixan/types'; -type NewMixanOptions = { - url: string - clientId: string - clientSecret: string - batchInterval?: number - maxBatchSize?: number - sessionTimeout?: number - verbose?: boolean - saveProfileId: (profiId: string) => void - getProfileId: () => (string | null) - removeProfileId: () => void +interface NewMixanOptions { + url: string; + clientId: string; + clientSecret: string; + batchInterval?: number; + maxBatchSize?: number; + sessionTimeout?: number; + verbose?: boolean; + saveProfileId: (profiId: string) => void; + getProfileId: () => string | null; + removeProfileId: () => void; } -type MixanOptions = Required +type MixanOptions = Required; class Fetcher { - private url: string - private clientId: string - private clientSecret: string - private logger: (...args: any[]) => void + private url: string; + private clientId: string; + private clientSecret: string; + private logger: (...args: any[]) => void; constructor(options: MixanOptions) { - this.url = options.url - this.clientId = options.clientId - this.clientSecret = options.clientSecret - this.logger = options.verbose ? console.log : () => {} + this.url = options.url; + this.clientId = options.clientId; + this.clientSecret = options.clientSecret; + this.logger = options.verbose ? console.log : () => {}; } - post( + post( path: string, - data: Record = {}, - options: RequestInit = {} - ): Promise { - const url = `${this.url}${path}` - this.logger(`Mixan request: ${url}`, JSON.stringify(data, null, 2)) + data?: PostData, + options?: RequestInit + ): Promise { + const url = `${this.url}${path}`; + this.logger(`Mixan request: ${url}`, JSON.stringify(data, null, 2)); return fetch(url, { headers: { ['mixan-client-id']: this.clientId, @@ -45,103 +45,109 @@ class Fetcher { 'Content-Type': 'application/json', }, method: 'POST', - body: JSON.stringify(data), - ...options, + body: JSON.stringify(data ?? {}), + ...(options ?? {}), }) .then(async (res) => { - const response = await res.json() as (MixanErrorResponse | Response) + const response = (await res.json()) as + | MixanErrorResponse + | PostResponse; - if(!response) { - return null + if (!response) { + return null; } - if (typeof response === 'object' && 'status' in response && response.status === 'error') { + if ( + typeof response === 'object' && + 'status' in response && + response.status === 'error' + ) { this.logger( - `Mixan request failed: [${options.method || 'POST'}] ${url}`, + `Mixan request failed: [${options?.method ?? 'POST'}] ${url}`, JSON.stringify(response, null, 2) - ) - return null + ); + return null; } - return response as Response + return response as PostResponse; }) .catch(() => { this.logger( - `Mixan request failed: [${options.method || 'POST'}] ${url}` - ) - return null - }) + `Mixan request failed: [${options?.method ?? 'POST'}] ${url}` + ); + return null; + }); } } -class Batcher { - queue: T[] = [] - timer?: NodeJS.Timeout - callback: (queue: T[]) => void - maxBatchSize: number - batchInterval: number +class Batcher { + queue: T[] = []; + timer?: NodeJS.Timeout; + callback: (queue: T[]) => void; + maxBatchSize: number; + batchInterval: number; constructor(options: MixanOptions, callback: (queue: T[]) => void) { - this.callback = callback - this.maxBatchSize = options.maxBatchSize - this.batchInterval = options.batchInterval + this.callback = callback; + this.maxBatchSize = options.maxBatchSize; + this.batchInterval = options.batchInterval; } add(payload: T) { - this.queue.push(payload) - this.flush() + this.queue.push(payload); + this.flush(); } flush() { if (this.timer) { - clearTimeout(this.timer) + clearTimeout(this.timer); } if (this.queue.length === 0) { - return + return; } if (this.queue.length >= this.maxBatchSize) { - this.send() - return + this.send(); + return; } - this.timer = setTimeout(this.send.bind(this), this.batchInterval) + this.timer = setTimeout(this.send.bind(this), this.batchInterval); } send() { if (this.timer) { - clearTimeout(this.timer) + clearTimeout(this.timer); } if (this.queue.length > 0) { - this.callback(this.queue) - this.queue = [] + this.callback(this.queue); + this.queue = []; } } } export class Mixan { - private fetch: Fetcher - private eventBatcher: Batcher - private profileId?: string - private options: MixanOptions - private logger: (...args: any[]) => void - private globalProperties: Record = {} - private lastEventAt?: string - private lastScreenViewAt?: string + private fetch: Fetcher; + private eventBatcher: Batcher; + private profileId?: string; + private options: MixanOptions; + private logger: (...args: any[]) => void; + private globalProperties: Record = {}; + private lastEventAt?: string; + private lastScreenViewAt?: string; constructor(options: NewMixanOptions) { - this.logger = options.verbose ? console.log : () => {} + this.logger = options.verbose ? console.log : () => {}; this.options = { sessionTimeout: 1000 * 60 * 30, verbose: false, batchInterval: 10000, maxBatchSize: 10, ...options, - } + }; - this.fetch = new Fetcher(this.options) + this.fetch = new Fetcher(this.options); this.eventBatcher = new Batcher(this.options, (queue) => { this.fetch.post( '/events', @@ -151,103 +157,106 @@ export class Mixan { ...this.globalProperties, ...item.properties, }, - profileId: item.profileId || this.profileId || null, + profileId: item.profileId ?? this.profileId ?? null, })) - ) - }) + ); + }); } timestamp() { - return new Date().toISOString() + return new Date().toISOString(); } init() { - this.logger('Mixan: Init') - this.setAnonymousUser() + this.logger('Mixan: Init'); + this.setAnonymousUser(); } - event(name: string, properties: Record = {}) { - const now = new Date() + event(name: string, properties: Record = {}) { + const now = new Date(); const isSessionStart = now.getTime() - new Date(this.lastEventAt ?? '1970-01-01').getTime() > - this.options.sessionTimeout + this.options.sessionTimeout; if (isSessionStart) { - this.logger('Mixan: Session start') + this.logger('Mixan: Session start'); this.eventBatcher.add({ name: 'session_start', time: this.timestamp(), properties: {}, - profileId: this.profileId || null, - }) + profileId: this.profileId ?? null, + }); } - this.logger('Mixan: Queue event', name) + this.logger('Mixan: Queue event', name); this.eventBatcher.add({ name, properties, time: this.timestamp(), - profileId: this.profileId || null, - }) - this.lastEventAt = this.timestamp() + profileId: this.profileId ?? null, + }); + this.lastEventAt = this.timestamp(); } - private async setAnonymousUser(retryCount: number = 0) { - const profileId = this.options.getProfileId() + private async setAnonymousUser(retryCount = 0) { + const profileId = this.options.getProfileId(); if (profileId) { - this.profileId = profileId - this.logger('Mixan: Use existing profile', this.profileId) + this.profileId = profileId; + this.logger('Mixan: Use existing profile', this.profileId); } else { - const res = await this.fetch.post<{id: string}>('/profiles') - - if(res) { - this.profileId = res.id - this.options.saveProfileId(res.id) - this.logger('Mixan: Create new profile', this.profileId) - } else if(retryCount < 2) { + const res = await this.fetch.post('/profiles'); + + if (res) { + this.profileId = res.id; + this.options.saveProfileId(res.id); + this.logger('Mixan: Create new profile', this.profileId); + } else if (retryCount < 2) { setTimeout(() => { - this.setAnonymousUser(retryCount + 1) + this.setAnonymousUser(retryCount + 1); }, 500); } else { - this.logger('Mixan: Failed to create new profile') + this.logger('Mixan: Failed to create new profile'); } } } async setUser(profile: ProfilePayload) { if (!this.profileId) { - return this.logger('Mixan: Set user failed, no profileId') + return this.logger('Mixan: Set user failed, no profileId'); } - this.logger('Mixan: Set user', profile) + this.logger('Mixan: Set user', profile); await this.fetch.post(`/profiles/${this.profileId}`, profile, { method: 'PUT', - }) + }); } - async setUserProperty(name: string, value: any) { + async setUserProperty( + name: string, + value: string | number | boolean | Record | unknown[] + ) { if (!this.profileId) { - return this.logger('Mixan: Set user property, no profileId') + return this.logger('Mixan: Set user property, no profileId'); } - this.logger('Mixan: Set user property', name, value) + this.logger('Mixan: Set user property', name, value); await this.fetch.post(`/profiles/${this.profileId}`, { properties: { [name]: value, }, - }) + }); } - async setGlobalProperties(properties: Record) { - this.logger('Mixan: Set global properties', properties) - this.globalProperties = properties ?? {} + setGlobalProperties(properties: Record) { + this.logger('Mixan: Set global properties', properties); + this.globalProperties = properties ?? {}; } - async increment(name: string, value: number = 1) { + async increment(name: string, value = 1) { if (!this.profileId) { - this.logger('Mixan: Increment failed, no profileId') - return + this.logger('Mixan: Increment failed, no profileId'); + return; } - this.logger('Mixan: Increment user property', name, value) + this.logger('Mixan: Increment user property', name, value); await this.fetch.post( `/profiles/${this.profileId}/increment`, { @@ -257,16 +266,16 @@ export class Mixan { { method: 'PUT', } - ) + ); } - async decrement(name: string, value: number = 1) { + async decrement(name: string, value = 1) { if (!this.profileId) { - this.logger('Mixan: Decrement failed, no profileId') - return + this.logger('Mixan: Decrement failed, no profileId'); + return; } - this.logger('Mixan: Decrement user property', name, value) + this.logger('Mixan: Decrement user property', name, value); await this.fetch.post( `/profiles/${this.profileId}/decrement`, { @@ -276,38 +285,38 @@ export class Mixan { { method: 'PUT', } - ) + ); } - async screenView(route: string, _properties?: Record) { - const properties = _properties ?? {} - const now = new Date() + screenView(route: string, _properties?: Record) { + const properties = _properties ?? {}; + const now = new Date(); if (this.lastScreenViewAt) { - const last = new Date(this.lastScreenViewAt) - const diff = now.getTime() - last.getTime() - this.logger(`Mixan: Screen view duration: ${diff}ms`) - properties['duration'] = diff + const last = new Date(this.lastScreenViewAt); + const diff = now.getTime() - last.getTime(); + this.logger(`Mixan: Screen view duration: ${diff}ms`); + properties.duration = diff; } - this.lastScreenViewAt = now.toISOString() - await this.event('screen_view', { + this.lastScreenViewAt = now.toISOString(); + this.event('screen_view', { ...properties, route, - }) + }); } flush() { - this.logger('Mixan: Flushing events queue') - this.eventBatcher.send() - this.lastScreenViewAt = undefined + this.logger('Mixan: Flushing events queue'); + this.eventBatcher.send(); + this.lastScreenViewAt = undefined; } clear() { - this.logger('Mixan: Clear, send remaining events and remove profileId') - this.eventBatcher.send() - this.options.removeProfileId() - this.profileId = undefined - this.setAnonymousUser() + this.logger('Mixan: Clear, send remaining events and remove profileId'); + this.eventBatcher.send(); + this.options.removeProfileId(); + this.profileId = undefined; + this.setAnonymousUser(); } } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 87d66a0d..ae2d0050 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -3,12 +3,25 @@ "version": "0.0.1", "type": "module", "module": "index.ts", + "scripts": { + "lint": "eslint .", + "format": "prettier --check \"**/*.{mjs,ts,md,json}\"", + "typecheck": "tsc --noEmit" + }, "dependencies": { "@mixan/types": "workspace:*" }, "devDependencies": { - "@types/uuid": "^9.0.5", + "@mixan/eslint-config": "workspace:*", + "@mixan/prettier-config": "workspace:*", "tsup": "^7.2.0", - "typescript": "^5.0.0" - } -} \ No newline at end of file + "typescript": "^5.2.0" + }, + "eslintConfig": { + "root": true, + "extends": [ + "@mixan/eslint-config/base" + ] + }, + "prettier": "@mixan/prettier-config" +} diff --git a/packages/sdk/tsconfig.json b/packages/sdk/tsconfig.json index 9dfafec0..1260b9f8 100644 --- a/packages/sdk/tsconfig.json +++ b/packages/sdk/tsconfig.json @@ -13,9 +13,9 @@ "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, "allowJs": true, - + "outDir": "dist", "allowImportingTsExtensions": false, - "noEmit": false, + "noEmit": false } } diff --git a/packages/sdk/tsup.config.ts b/packages/sdk/tsup.config.ts index 045c25df..ef86be71 100644 --- a/packages/sdk/tsup.config.ts +++ b/packages/sdk/tsup.config.ts @@ -1,8 +1,8 @@ -import { defineConfig } from "tsup"; +import { defineConfig } from 'tsup'; export default defineConfig({ - entry: ["index.ts"], - format: ["cjs", "esm"], // Build for commonJS and ESmodules + entry: ['index.ts'], + format: ['cjs', 'esm'], // Build for commonJS and ESmodules dts: true, // Generate declaration file (.d.ts) splitting: false, sourcemap: true, diff --git a/packages/types/index.ts b/packages/types/index.ts index 37357e5d..32c48934 100644 --- a/packages/types/index.ts +++ b/packages/types/index.ts @@ -1,76 +1,76 @@ -export type MixanJson = Record +export type MixanJson = Record; -export type EventPayload = { - name: string - time: string - profileId: string | null - properties: MixanJson +export interface EventPayload { + name: string; + time: string; + profileId: string | null; + properties: MixanJson; } -export type ProfilePayload = { - first_name?: string - last_name?: string - email?: string - avatar?: string - id?: string - properties?: MixanJson +export interface ProfilePayload { + first_name?: string; + last_name?: string; + email?: string; + avatar?: string; + id?: string; + properties?: MixanJson; } -export type ProfileIncrementPayload = { - name: string - value: number - id: string +export interface ProfileIncrementPayload { + name: string; + value: number; + id: string; } -export type ProfileDecrementPayload = { - name: string - value: number - id: string +export interface ProfileDecrementPayload { + name: string; + value: number; + id: string; } // Batching -export type BatchEvent = { - type: 'event' - payload: EventPayload +export interface BatchEvent { + type: 'event'; + payload: EventPayload; } -export type BatchProfile = { - type: 'profile' - payload: ProfilePayload +export interface BatchProfile { + type: 'profile'; + payload: ProfilePayload; } -export type BatchProfileIncrement = { - type: 'profile_increment' - payload: ProfileIncrementPayload +export interface BatchProfileIncrement { + type: 'profile_increment'; + payload: ProfileIncrementPayload; } -export type BatchProfileDecrement = { - type: 'profile_decrement' - payload: ProfileDecrementPayload +export interface BatchProfileDecrement { + type: 'profile_decrement'; + payload: ProfileDecrementPayload; } export type BatchItem = | BatchEvent | BatchProfile | BatchProfileIncrement - | BatchProfileDecrement -export type BatchPayload = Array + | BatchProfileDecrement; +export type BatchPayload = BatchItem[]; -export type MixanIssue = { - field: string - message: string - value: any +export interface MixanIssue { + field: string; + message: string; + value: any; } -export type MixanErrorResponse = { - status: 'error' - code: number - message: string - issues?: Array | undefined - stack?: string | undefined +export interface MixanErrorResponse { + status: 'error'; + code: number; + message: string; + issues?: MixanIssue[] | undefined; + stack?: string | undefined; } -export type MixanResponse = { - result: T - status: 'ok' +export interface MixanResponse { + result: T; + status: 'ok'; } diff --git a/packages/types/package.json b/packages/types/package.json index 1c06abb1..cea1460c 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -3,8 +3,22 @@ "version": "0.0.1", "type": "module", "module": "index.ts", + "scripts": { + "lint": "eslint .", + "format": "prettier --check \"**/*.{mjs,ts,md,json}\"", + "typecheck": "tsc --noEmit" + }, "devDependencies": { + "@mixan/eslint-config": "workspace:*", + "@mixan/prettier-config": "workspace:*", "tsup": "^7.2.0", - "typescript": "^5.0.0" - } -} \ No newline at end of file + "typescript": "^5.2.0" + }, + "eslintConfig": { + "root": true, + "extends": [ + "@mixan/eslint-config/base" + ] + }, + "prettier": "@mixan/prettier-config" +} diff --git a/packages/types/tsup.config.ts b/packages/types/tsup.config.ts index 9c84804e..b3de6921 100644 --- a/packages/types/tsup.config.ts +++ b/packages/types/tsup.config.ts @@ -1,8 +1,8 @@ -import { defineConfig } from "tsup"; +import { defineConfig } from 'tsup'; export default defineConfig({ - entry: ["index.ts"], - format: ["cjs", "esm"], // Build for commonJS and ESmodules + entry: ['index.ts'], + format: ['cjs', 'esm'], // Build for commonJS and ESmodules dts: true, // Generate declaration file (.d.ts) splitting: false, sourcemap: false, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84e2e045..dd6e1dba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,7 @@ importers: .: dependencies: typescript: - specifier: ^5.0.0 + specifier: ^5.2.0 version: 5.2.2 devDependencies: semver: @@ -157,12 +157,15 @@ importers: specifier: ^3.22.4 version: 3.22.4 devDependencies: + '@mixan/eslint-config': + specifier: workspace:* + version: link:../../tooling/eslint + '@mixan/prettier-config': + specifier: workspace:* + version: link:../../tooling/prettier '@types/bcrypt': specifier: ^5.0.0 version: 5.0.1 - '@types/eslint': - specifier: ^8.44.2 - version: 8.44.6 '@types/node': specifier: ^18.16.0 version: 18.18.8 @@ -178,17 +181,11 @@ importers: '@types/react-syntax-highlighter': specifier: ^15.5.9 version: 15.5.9 - '@typescript-eslint/eslint-plugin': - specifier: ^6.3.0 - version: 6.9.1(@typescript-eslint/parser@6.9.1)(eslint@8.52.0)(typescript@5.2.2) - '@typescript-eslint/parser': - specifier: ^6.3.0 - version: 6.9.1(eslint@8.52.0)(typescript@5.2.2) autoprefixer: specifier: ^10.4.14 version: 10.4.16(postcss@8.4.31) eslint: - specifier: ^8.47.0 + specifier: ^8.48.0 version: 8.52.0 eslint-config-next: specifier: ^13.5.4 @@ -196,9 +193,6 @@ importers: postcss: specifier: ^8.4.27 version: 8.4.31 - prettier: - specifier: ^3.0.0 - version: 3.0.3 prettier-plugin-tailwindcss: specifier: ^0.5.1 version: 0.5.6(prettier@3.0.3) @@ -209,7 +203,7 @@ importers: specifier: ^3.3.3 version: 3.3.5 typescript: - specifier: ^5.1.6 + specifier: ^5.2.0 version: 5.2.2 packages/sdk: @@ -218,42 +212,310 @@ importers: specifier: workspace:* version: link:../types devDependencies: - '@types/uuid': - specifier: ^9.0.5 - version: 9.0.6 + '@mixan/eslint-config': + specifier: workspace:* + version: link:../../tooling/eslint + '@mixan/prettier-config': + specifier: workspace:* + version: link:../../tooling/prettier tsup: specifier: ^7.2.0 version: 7.2.0(typescript@5.2.2) typescript: - specifier: ^5.0.0 + specifier: ^5.2.0 version: 5.2.2 packages/types: devDependencies: + '@mixan/eslint-config': + specifier: workspace:* + version: link:../../tooling/eslint + '@mixan/prettier-config': + specifier: workspace:* + version: link:../../tooling/prettier tsup: specifier: ^7.2.0 version: 7.2.0(typescript@5.2.2) typescript: - specifier: ^5.0.0 + specifier: ^5.2.0 version: 5.2.2 + tooling/eslint: + dependencies: + '@typescript-eslint/eslint-plugin': + specifier: ^6.6.0 + version: 6.9.1(@typescript-eslint/parser@6.9.1)(eslint@8.52.0)(typescript@5.2.2) + '@typescript-eslint/parser': + specifier: ^6.6.0 + version: 6.9.1(eslint@8.52.0)(typescript@5.2.2) + eslint-config-prettier: + specifier: ^9.0.0 + version: 9.0.0(eslint@8.52.0) + eslint-config-turbo: + specifier: ^1.10.13 + version: 1.10.16(eslint@8.52.0) + eslint-plugin-import: + specifier: ^2.28.1 + version: 2.29.0(@typescript-eslint/parser@6.9.1)(eslint@8.52.0) + eslint-plugin-jsx-a11y: + specifier: ^6.7.1 + version: 6.8.0(eslint@8.52.0) + eslint-plugin-react: + specifier: ^7.33.2 + version: 7.33.2(eslint@8.52.0) + eslint-plugin-react-hooks: + specifier: ^4.6.0 + version: 4.6.0(eslint@8.52.0) + devDependencies: + '@mixan/prettier-config': + specifier: workspace:* + version: link:../prettier + '@mixan/tsconfig': + specifier: workspace:* + version: link:../typescript + '@types/eslint': + specifier: ^8.44.2 + version: 8.44.6 + eslint: + specifier: ^8.48.0 + version: 8.52.0 + typescript: + specifier: ^5.2.0 + version: 5.2.2 + + tooling/prettier: + dependencies: + '@ianvs/prettier-plugin-sort-imports': + specifier: ^4.1.0 + version: 4.1.1(prettier@3.0.3) + prettier: + specifier: ^3.0.3 + version: 3.0.3 + devDependencies: + '@mixan/tsconfig': + specifier: workspace:* + version: link:../typescript + typescript: + specifier: ^5.2.0 + version: 5.2.2 + + tooling/typescript: {} + packages: /@aashutoshrathi/word-wrap@1.2.6: resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} engines: {node: '>=0.10.0'} - dev: true /@alloc/quick-lru@5.2.0: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + dev: false + + /@babel/code-frame@7.22.13: + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.22.20 + chalk: 2.4.2 + dev: false + + /@babel/compat-data@7.23.2: + resolution: {integrity: sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/core@7.23.2: + resolution: {integrity: sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.0 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.23.0(@babel/core@7.23.2) + '@babel/helpers': 7.23.2 + '@babel/parser': 7.23.0 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.2 + '@babel/types': 7.23.0 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/generator@7.23.0: + resolution: {integrity: sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + jsesc: 2.5.2 + dev: false + + /@babel/helper-compilation-targets@7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.23.2 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.22.1 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: false + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.23.0 + dev: false + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + dev: false + + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + dev: false + + /@babel/helper-module-transforms@7.23.0(@babel/core@7.23.2): + resolution: {integrity: sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: false + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + dev: false + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + dev: false + + /@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-validator-option@7.22.15: + resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helpers@7.23.2: + resolution: {integrity: sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.2 + '@babel/types': 7.23.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/highlight@7.22.20: + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: false + + /@babel/parser@7.23.0: + resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.0 + dev: false + /@babel/runtime@7.23.2: resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/parser': 7.23.0 + '@babel/types': 7.23.0 + dev: false + + /@babel/traverse@7.23.2: + resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.0 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.0 + '@babel/types': 7.23.0 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/types@7.23.0: + resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: false + /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -460,12 +722,10 @@ packages: dependencies: eslint: 8.52.0 eslint-visitor-keys: 3.4.3 - dev: true /@eslint-community/regexpp@4.10.0: resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true /@eslint/eslintrc@2.1.2: resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} @@ -482,12 +742,10 @@ packages: strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true /@eslint/js@8.52.0: resolution: {integrity: sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true /@floating-ui/core@1.5.0: resolution: {integrity: sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==} @@ -534,16 +792,33 @@ packages: minimatch: 3.1.2 transitivePeerDependencies: - supports-color - dev: true /@humanwhocodes/module-importer@1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - dev: true /@humanwhocodes/object-schema@2.0.1: resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} - dev: true + + /@ianvs/prettier-plugin-sort-imports@4.1.1(prettier@3.0.3): + resolution: {integrity: sha512-kJhXq63ngpTQ2dxgf5GasbPJWsJA3LgoOdd7WGhpUSzLgLgI4IsIzYkbJf9kmpOHe7Vdm/o3PcRA3jmizXUuAQ==} + peerDependencies: + '@vue/compiler-sfc': '>=3.0.0' + prettier: 2 || 3 + peerDependenciesMeta: + '@vue/compiler-sfc': + optional: true + dependencies: + '@babel/core': 7.23.2 + '@babel/generator': 7.23.0 + '@babel/parser': 7.23.0 + '@babel/traverse': 7.23.2 + '@babel/types': 7.23.0 + prettier: 3.0.3 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: false /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} @@ -1891,11 +2166,9 @@ packages: /@types/json-schema@7.0.14: resolution: {integrity: sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==} - dev: true /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: true /@types/node@18.18.8: resolution: {integrity: sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==} @@ -1935,7 +2208,7 @@ packages: /@types/semver@7.5.4: resolution: {integrity: sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==} - dev: true + dev: false /@types/unist@2.0.9: resolution: {integrity: sha512-zC0iXxAv1C1ERURduJueYzkzZ2zaGyc+P2c95hgkikHPr3z8EdUZOlgEQ5X0DRmwDZn+hekycQnoeiiRVrmilQ==} @@ -1945,10 +2218,6 @@ packages: resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} dev: false - /@types/uuid@9.0.6: - resolution: {integrity: sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==} - dev: true - /@typescript-eslint/eslint-plugin@6.9.1(@typescript-eslint/parser@6.9.1)(eslint@8.52.0)(typescript@5.2.2): resolution: {integrity: sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg==} engines: {node: ^16.0.0 || >=18.0.0} @@ -1976,7 +2245,7 @@ packages: typescript: 5.2.2 transitivePeerDependencies: - supports-color - dev: true + dev: false /@typescript-eslint/parser@6.9.1(eslint@8.52.0)(typescript@5.2.2): resolution: {integrity: sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==} @@ -1997,7 +2266,6 @@ packages: typescript: 5.2.2 transitivePeerDependencies: - supports-color - dev: true /@typescript-eslint/scope-manager@6.9.1: resolution: {integrity: sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==} @@ -2005,7 +2273,6 @@ packages: dependencies: '@typescript-eslint/types': 6.9.1 '@typescript-eslint/visitor-keys': 6.9.1 - dev: true /@typescript-eslint/type-utils@6.9.1(eslint@8.52.0)(typescript@5.2.2): resolution: {integrity: sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg==} @@ -2025,12 +2292,11 @@ packages: typescript: 5.2.2 transitivePeerDependencies: - supports-color - dev: true + dev: false /@typescript-eslint/types@6.9.1: resolution: {integrity: sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==} engines: {node: ^16.0.0 || >=18.0.0} - dev: true /@typescript-eslint/typescript-estree@6.9.1(typescript@5.2.2): resolution: {integrity: sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==} @@ -2051,7 +2317,6 @@ packages: typescript: 5.2.2 transitivePeerDependencies: - supports-color - dev: true /@typescript-eslint/utils@6.9.1(eslint@8.52.0)(typescript@5.2.2): resolution: {integrity: sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==} @@ -2070,7 +2335,7 @@ packages: transitivePeerDependencies: - supports-color - typescript - dev: true + dev: false /@typescript-eslint/visitor-keys@6.9.1: resolution: {integrity: sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==} @@ -2078,11 +2343,9 @@ packages: dependencies: '@typescript-eslint/types': 6.9.1 eslint-visitor-keys: 3.4.3 - dev: true /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - dev: true /abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -2094,13 +2357,11 @@ packages: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: acorn: 8.11.2 - dev: true /acorn@8.11.2: resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} engines: {node: '>=0.4.0'} hasBin: true - dev: true /agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} @@ -2118,18 +2379,23 @@ packages: fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - dev: true /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: false + /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -2158,7 +2424,6 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true /aria-hidden@1.2.3: resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==} @@ -2171,14 +2436,12 @@ packages: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} dependencies: dequal: 2.0.3 - dev: true /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: call-bind: 1.0.5 is-array-buffer: 3.0.2 - dev: true /array-includes@3.1.7: resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} @@ -2189,12 +2452,10 @@ packages: es-abstract: 1.22.3 get-intrinsic: 1.2.2 is-string: 1.0.7 - dev: true /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - dev: true /array.prototype.findlastindex@1.2.3: resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} @@ -2205,7 +2466,6 @@ packages: es-abstract: 1.22.3 es-shim-unscopables: 1.0.2 get-intrinsic: 1.2.2 - dev: true /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} @@ -2215,7 +2475,6 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.3 es-shim-unscopables: 1.0.2 - dev: true /array.prototype.flatmap@1.3.2: resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} @@ -2225,7 +2484,6 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.3 es-shim-unscopables: 1.0.2 - dev: true /array.prototype.tosorted@1.1.2: resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} @@ -2235,7 +2493,6 @@ packages: es-abstract: 1.22.3 es-shim-unscopables: 1.0.2 get-intrinsic: 1.2.2 - dev: true /arraybuffer.prototype.slice@1.0.2: resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} @@ -2248,17 +2505,14 @@ packages: get-intrinsic: 1.2.2 is-array-buffer: 3.0.2 is-shared-array-buffer: 1.0.2 - dev: true /ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - dev: true /asynciterator.prototype@1.0.0: resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} dependencies: has-symbols: 1.0.3 - dev: true /autoprefixer@10.4.16(postcss@8.4.31): resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==} @@ -2279,18 +2533,15 @@ packages: /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} - dev: true /axe-core@4.7.0: resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==} engines: {node: '>=4'} - dev: true /axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} dependencies: dequal: 2.0.3 - dev: true /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2332,7 +2583,6 @@ packages: electron-to-chromium: 1.4.574 node-releases: 2.0.13 update-browserslist-db: 1.0.13(browserslist@4.22.1) - dev: true /bundle-require@4.0.2(esbuild@0.18.20): resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} @@ -2362,12 +2612,10 @@ packages: function-bind: 1.1.2 get-intrinsic: 1.2.2 set-function-length: 1.1.1 - dev: true /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - dev: true /camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} @@ -2376,13 +2624,21 @@ packages: /caniuse-lite@1.0.30001559: resolution: {integrity: sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA==} + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: false + /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true /character-entities-legacy@1.1.4: resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} @@ -2448,16 +2704,24 @@ packages: - '@types/react' dev: false + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: false + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true /color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} @@ -2483,6 +2747,10 @@ packages: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} dev: false + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: false + /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} @@ -2502,7 +2770,6 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true /cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} @@ -2585,7 +2852,6 @@ packages: /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - dev: true /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} @@ -2596,7 +2862,6 @@ packages: optional: true dependencies: ms: 2.1.3 - dev: true /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} @@ -2615,7 +2880,6 @@ packages: /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true /define-data-property@1.1.1: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} @@ -2624,7 +2888,6 @@ packages: get-intrinsic: 1.2.2 gopd: 1.0.1 has-property-descriptors: 1.0.1 - dev: true /define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} @@ -2633,7 +2896,6 @@ packages: define-data-property: 1.1.1 has-property-descriptors: 1.0.1 object-keys: 1.1.1 - dev: true /delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} @@ -2642,7 +2904,6 @@ packages: /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - dev: true /detect-libc@2.0.2: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} @@ -2661,7 +2922,6 @@ packages: engines: {node: '>=8'} dependencies: path-type: 4.0.0 - dev: true /dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -2671,14 +2931,12 @@ packages: engines: {node: '>=0.10.0'} dependencies: esutils: 2.0.3 - dev: true /doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} dependencies: esutils: 2.0.3 - dev: true /dom-helpers@3.4.0: resolution: {integrity: sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==} @@ -2686,9 +2944,13 @@ packages: '@babel/runtime': 7.23.2 dev: false + /dotenv@16.0.3: + resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} + engines: {node: '>=12'} + dev: false + /electron-to-chromium@1.4.574: resolution: {integrity: sha512-bg1m8L0n02xRzx4LsTTMbBPiUd9yIR+74iPtS/Ao65CuXvhVZHP0ym1kSdDG3yHFDXqHQQBKujlN1AQ8qZnyFg==} - dev: true /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2696,7 +2958,6 @@ packages: /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true /enhanced-resolve@5.15.0: resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} @@ -2704,7 +2965,6 @@ packages: dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 - dev: true /es-abstract@1.22.3: resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} @@ -2749,7 +3009,6 @@ packages: typed-array-length: 1.0.4 unbox-primitive: 1.0.2 which-typed-array: 1.1.13 - dev: true /es-iterator-helpers@1.0.15: resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} @@ -2768,7 +3027,6 @@ packages: internal-slot: 1.0.6 iterator.prototype: 1.1.2 safe-array-concat: 1.0.1 - dev: true /es-set-tostringtag@2.0.2: resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} @@ -2777,13 +3035,11 @@ packages: get-intrinsic: 1.2.2 has-tostringtag: 1.0.0 hasown: 2.0.0 - dev: true /es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: hasown: 2.0.0 - dev: true /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} @@ -2792,7 +3048,6 @@ packages: is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 - dev: true /esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} @@ -2827,12 +3082,15 @@ packages: /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} - dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: false /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - dev: true /eslint-config-next@13.5.6(eslint@8.52.0)(typescript@5.2.2): resolution: {integrity: sha512-o8pQsUHTo9aHqJ2YiZDym5gQAMRf7O2HndHo/JZeY7TDD+W4hk6Ma8Vw54RHiBeb7OWWO5dPirQB+Is/aVQ7Kg==} @@ -2859,6 +3117,24 @@ packages: - supports-color dev: true + /eslint-config-prettier@9.0.0(eslint@8.52.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.52.0 + dev: false + + /eslint-config-turbo@1.10.16(eslint@8.52.0): + resolution: {integrity: sha512-O3NQI72bQHV7FvSC6lWj66EGx8drJJjuT1kuInn6nbMLOHdMBhSUX/8uhTAlHRQdlxZk2j9HtgFCIzSc93w42g==} + peerDependencies: + eslint: '>6.6.0' + dependencies: + eslint: 8.52.0 + eslint-plugin-turbo: 1.10.16(eslint@8.52.0) + dev: false + /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: @@ -2867,7 +3143,6 @@ packages: resolve: 1.22.8 transitivePeerDependencies: - supports-color - dev: true /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0)(eslint@8.52.0): resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} @@ -2890,7 +3165,6 @@ packages: - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - dev: true /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.52.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} @@ -2920,7 +3194,6 @@ packages: eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0)(eslint@8.52.0) transitivePeerDependencies: - supports-color - dev: true /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.52.0): resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} @@ -2955,7 +3228,41 @@ packages: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - dev: true + + /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.9.1)(eslint@8.52.0): + resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 6.9.1(eslint@8.52.0)(typescript@5.2.2) + array-includes: 3.1.7 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.52.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.52.0) + hasown: 2.0.0 + is-core-module: 2.13.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.7 + object.groupby: 1.0.1 + object.values: 1.1.7 + semver: 6.3.1 + tsconfig-paths: 3.14.2 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: false /eslint-plugin-jsx-a11y@6.8.0(eslint@8.52.0): resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==} @@ -2980,7 +3287,6 @@ packages: minimatch: 3.1.2 object.entries: 1.1.7 object.fromentries: 2.0.7 - dev: true /eslint-plugin-react-hooks@4.6.0(eslint@8.52.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} @@ -2989,7 +3295,6 @@ packages: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: eslint: 8.52.0 - dev: true /eslint-plugin-react@7.33.2(eslint@8.52.0): resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} @@ -3014,7 +3319,15 @@ packages: resolve: 2.0.0-next.5 semver: 6.3.1 string.prototype.matchall: 4.0.10 - dev: true + + /eslint-plugin-turbo@1.10.16(eslint@8.52.0): + resolution: {integrity: sha512-ZjrR88MTN64PNGufSEcM0tf+V1xFYVbeiMeuIqr0aiABGomxFLo4DBkQ7WI4WzkZtWQSIA2sP+yxqSboEfL9MQ==} + peerDependencies: + eslint: '>6.6.0' + dependencies: + dotenv: 16.0.3 + eslint: 8.52.0 + dev: false /eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} @@ -3022,12 +3335,10 @@ packages: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - dev: true /eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true /eslint@8.52.0: resolution: {integrity: sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==} @@ -3074,7 +3385,6 @@ packages: text-table: 0.2.0 transitivePeerDependencies: - supports-color - dev: true /espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} @@ -3083,31 +3393,26 @@ packages: acorn: 8.11.2 acorn-jsx: 5.3.2(acorn@8.11.2) eslint-visitor-keys: 3.4.3 - dev: true /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 - dev: true /esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} dependencies: estraverse: 5.3.0 - dev: true /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - dev: true /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - dev: true /eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} @@ -3130,7 +3435,6 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true /fast-equals@5.0.1: resolution: {integrity: sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==} @@ -3149,11 +3453,9 @@ packages: /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} @@ -3171,7 +3473,6 @@ packages: engines: {node: ^10.12.0 || >=12.0.0} dependencies: flat-cache: 3.1.1 - dev: true /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} @@ -3185,7 +3486,6 @@ packages: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: true /flat-cache@3.1.1: resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==} @@ -3194,17 +3494,14 @@ packages: flatted: 3.2.9 keyv: 4.5.4 rimraf: 3.0.2 - dev: true /flatted@3.2.9: resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} - dev: true /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 - dev: true /format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} @@ -3243,11 +3540,9 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.3 functions-have-names: 1.2.3 - dev: true /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true /gauge@3.0.2: resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} @@ -3264,6 +3559,11 @@ packages: wide-align: 1.1.5 dev: false + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: false + /get-intrinsic@1.2.2: resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} dependencies: @@ -3271,7 +3571,6 @@ packages: has-proto: 1.0.1 has-symbols: 1.0.3 hasown: 2.0.0 - dev: true /get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} @@ -3289,13 +3588,11 @@ packages: dependencies: call-bind: 1.0.5 get-intrinsic: 1.2.2 - dev: true /get-tsconfig@4.7.2: resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} dependencies: resolve-pkg-maps: 1.0.0 - dev: true /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -3344,19 +3641,22 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: false + /globals@13.23.0: resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 - dev: true /globalthis@1.0.3: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.1 - dev: true /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} @@ -3368,52 +3668,48 @@ packages: ignore: 5.2.4 merge2: 1.4.1 slash: 3.0.0 - dev: true /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.2 - dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: false /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: true /has-property-descriptors@1.0.1: resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} dependencies: get-intrinsic: 1.2.2 - dev: true /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} - dev: true /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} - dev: true /has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 - dev: true /has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} @@ -3467,7 +3763,6 @@ packages: /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} - dev: true /immer@9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} @@ -3479,12 +3774,10 @@ packages: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - dev: true /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} @@ -3502,7 +3795,6 @@ packages: get-intrinsic: 1.2.2 hasown: 2.0.0 side-channel: 1.0.4 - dev: true /internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} @@ -3532,20 +3824,17 @@ packages: call-bind: 1.0.5 get-intrinsic: 1.2.2 is-typed-array: 1.1.12 - dev: true /is-async-function@2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: true /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: has-bigints: 1.0.2 - dev: true /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} @@ -3559,12 +3848,10 @@ packages: dependencies: call-bind: 1.0.5 has-tostringtag: 1.0.0 - dev: true /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - dev: true /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} @@ -3576,7 +3863,6 @@ packages: engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: true /is-decimal@1.0.4: resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} @@ -3590,7 +3876,6 @@ packages: resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} dependencies: call-bind: 1.0.5 - dev: true /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -3602,7 +3887,6 @@ packages: engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: true /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} @@ -3616,19 +3900,16 @@ packages: /is-map@2.0.2: resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} - dev: true /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} - dev: true /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: true /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} @@ -3637,7 +3918,6 @@ packages: /is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} - dev: true /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} @@ -3645,17 +3925,14 @@ packages: dependencies: call-bind: 1.0.5 has-tostringtag: 1.0.0 - dev: true /is-set@2.0.2: resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} - dev: true /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: call-bind: 1.0.5 - dev: true /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} @@ -3667,38 +3944,32 @@ packages: engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: true /is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 - dev: true /is-typed-array@1.1.12: resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} engines: {node: '>= 0.4'} dependencies: which-typed-array: 1.1.13 - dev: true /is-weakmap@2.0.1: resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} - dev: true /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.5 - dev: true /is-weakset@2.0.2: resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} dependencies: call-bind: 1.0.5 get-intrinsic: 1.2.2 - dev: true /is-what@4.1.16: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} @@ -3707,11 +3978,9 @@ packages: /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - dev: true /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true /iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} @@ -3721,7 +3990,6 @@ packages: has-symbols: 1.0.3 reflect.getprototypeof: 1.0.4 set-function-name: 2.0.1 - dev: true /jiti@1.21.0: resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} @@ -3744,26 +4012,33 @@ packages: hasBin: true dependencies: argparse: 2.0.1 - dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: false /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true dependencies: minimist: 1.2.8 - dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: false /jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} @@ -3773,24 +4048,20 @@ packages: array.prototype.flat: 1.3.2 object.assign: 4.1.4 object.values: 1.1.7 - dev: true /keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} dependencies: json-buffer: 3.0.1 - dev: true /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} - dev: true /language-tags@1.0.9: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} dependencies: language-subtag-registry: 0.3.22 - dev: true /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} @@ -3798,7 +4069,6 @@ packages: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} @@ -3817,11 +4087,9 @@ packages: engines: {node: '>=10'} dependencies: p-locate: 5.0.0 - dev: true /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true /lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} @@ -3844,6 +4112,12 @@ packages: highlight.js: 10.7.3 dev: false + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: false + /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -3892,7 +4166,6 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} @@ -3929,7 +4202,6 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true /mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -3945,7 +4217,6 @@ packages: /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true /next-auth@4.24.4(next@13.4.19)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-5DGffi+OpkbU62vPQIJ1z+hFnmow+ec5Qrn9m6eoglIO51m0DlrmLxBduZEwKAYDEg9k2joi1yelgmq1vqK3aQ==} @@ -4030,7 +4301,6 @@ packages: /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} - dev: true /nopt@5.0.0: resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} @@ -4084,12 +4354,10 @@ packages: /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - dev: true /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - dev: true /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} @@ -4099,7 +4367,6 @@ packages: define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 - dev: true /object.entries@1.1.7: resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} @@ -4108,7 +4375,6 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - dev: true /object.fromentries@2.0.7: resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} @@ -4117,7 +4383,6 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - dev: true /object.groupby@1.0.1: resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} @@ -4126,14 +4391,12 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.3 get-intrinsic: 1.2.2 - dev: true /object.hasown@1.1.3: resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} dependencies: define-properties: 1.2.1 es-abstract: 1.22.3 - dev: true /object.values@1.1.7: resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} @@ -4142,7 +4405,6 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - dev: true /oidc-token-hash@5.0.3: resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==} @@ -4180,28 +4442,24 @@ packages: levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} dependencies: yocto-queue: 0.1.0 - dev: true /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} dependencies: p-limit: 3.1.0 - dev: true /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} dependencies: callsites: 3.1.0 - dev: true /parse-entities@2.0.0: resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} @@ -4217,7 +4475,6 @@ packages: /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - dev: true /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} @@ -4226,7 +4483,6 @@ packages: /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - dev: true /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -4234,7 +4490,6 @@ packages: /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - dev: true /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -4339,7 +4594,6 @@ packages: /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - dev: true /prettier-plugin-tailwindcss@0.5.6(prettier@3.0.3): resolution: {integrity: sha512-2Xgb+GQlkPAUCFi3sV+NOYcSI5XgduvDBL2Zt/hwJudeKXkyvRS65c38SB0yb9UB40+1rL83I6m0RtlOQ8eHdg==} @@ -4400,7 +4654,6 @@ packages: resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} engines: {node: '>=14'} hasBin: true - dev: true /pretty-format@3.8.0: resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} @@ -4440,7 +4693,6 @@ packages: /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - dev: true /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -4737,7 +4989,6 @@ packages: get-intrinsic: 1.2.2 globalthis: 1.0.3 which-builtin-type: 1.1.3 - dev: true /refractor@3.6.0: resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} @@ -4757,7 +5008,6 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 set-function-name: 2.0.1 - dev: true /reselect@4.1.8: resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==} @@ -4766,7 +5016,6 @@ packages: /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - dev: true /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} @@ -4775,7 +5024,6 @@ packages: /resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - dev: true /resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} @@ -4792,7 +5040,6 @@ packages: is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -4825,7 +5072,6 @@ packages: get-intrinsic: 1.2.2 has-symbols: 1.0.3 isarray: 2.0.5 - dev: true /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -4837,7 +5083,6 @@ packages: call-bind: 1.0.5 get-intrinsic: 1.2.2 is-regex: 1.1.4 - dev: true /scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} @@ -4868,7 +5113,6 @@ packages: get-intrinsic: 1.2.2 gopd: 1.0.1 has-property-descriptors: 1.0.1 - dev: true /set-function-name@2.0.1: resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} @@ -4877,19 +5121,16 @@ packages: define-data-property: 1.1.1 functions-have-names: 1.2.3 has-property-descriptors: 1.0.1 - dev: true /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - dev: true /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - dev: true /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} @@ -4897,7 +5138,6 @@ packages: call-bind: 1.0.5 get-intrinsic: 1.2.2 object-inspect: 1.13.1 - dev: true /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -4905,7 +5145,6 @@ packages: /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - dev: true /slugify@1.6.6: resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==} @@ -4953,7 +5192,6 @@ packages: regexp.prototype.flags: 1.5.1 set-function-name: 2.0.1 side-channel: 1.0.4 - dev: true /string.prototype.trim@1.2.8: resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} @@ -4962,7 +5200,6 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - dev: true /string.prototype.trimend@1.0.7: resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} @@ -4970,7 +5207,6 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - dev: true /string.prototype.trimstart@1.0.7: resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} @@ -4978,7 +5214,6 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - dev: true /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -4995,7 +5230,6 @@ packages: /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - dev: true /strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} @@ -5005,7 +5239,6 @@ packages: /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - dev: true /styled-jsx@5.1.1(react@18.2.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} @@ -5044,12 +5277,18 @@ packages: copy-anything: 3.0.5 dev: false + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: false + /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} dependencies: has-flag: 4.0.0 - dev: true /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -5100,7 +5339,6 @@ packages: /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - dev: true /tar@6.2.0: resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} @@ -5116,7 +5354,6 @@ packages: /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true /thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} @@ -5133,6 +5370,11 @@ packages: resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} dev: false + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + dev: false + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -5161,7 +5403,6 @@ packages: typescript: '>=4.2.0' dependencies: typescript: 5.2.2 - dev: true /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -5177,7 +5418,6 @@ packages: json5: 1.0.2 minimist: 1.2.8 strip-bom: 3.0.0 - dev: true /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} @@ -5224,12 +5464,10 @@ packages: engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.2.1 - dev: true /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} - dev: true /typed-array-buffer@1.0.0: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} @@ -5238,7 +5476,6 @@ packages: call-bind: 1.0.5 get-intrinsic: 1.2.2 is-typed-array: 1.1.12 - dev: true /typed-array-byte-length@1.0.0: resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} @@ -5248,7 +5485,6 @@ packages: for-each: 0.3.3 has-proto: 1.0.1 is-typed-array: 1.1.12 - dev: true /typed-array-byte-offset@1.0.0: resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} @@ -5259,7 +5495,6 @@ packages: for-each: 0.3.3 has-proto: 1.0.1 is-typed-array: 1.1.12 - dev: true /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} @@ -5267,7 +5502,6 @@ packages: call-bind: 1.0.5 for-each: 0.3.3 is-typed-array: 1.1.12 - dev: true /types-ramda@0.29.5: resolution: {integrity: sha512-u+bAYXHDPJR+amB0qMrMU/NXRB2PG8QqpO2v6j7yK/0mPZhlaaZj++ynYjnVpkPEpCkZEGxNpWY3X7qyLCGE3w==} @@ -5287,7 +5521,6 @@ packages: has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - dev: true /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -5302,13 +5535,11 @@ packages: browserslist: 4.22.1 escalade: 3.1.1 picocolors: 1.0.0 - dev: true /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.1 - dev: true /use-callback-ref@1.3.0(@types/react@18.2.34)(react@18.2.0): resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==} @@ -5426,7 +5657,6 @@ packages: is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 - dev: true /which-builtin-type@1.1.3: resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} @@ -5444,7 +5674,6 @@ packages: which-boxed-primitive: 1.0.2 which-collection: 1.0.1 which-typed-array: 1.1.13 - dev: true /which-collection@1.0.1: resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} @@ -5453,7 +5682,6 @@ packages: is-set: 2.0.2 is-weakmap: 2.0.1 is-weakset: 2.0.2 - dev: true /which-typed-array@1.1.13: resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} @@ -5464,7 +5692,6 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 - dev: true /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} @@ -5472,7 +5699,6 @@ packages: hasBin: true dependencies: isexe: 2.0.0 - dev: true /wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} @@ -5488,6 +5714,10 @@ packages: engines: {node: '>=0.4'} dev: false + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: false + /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -5498,7 +5728,6 @@ packages: /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - dev: true /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e9b0dad6..44a69b0f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,4 @@ packages: - 'apps/*' - 'packages/*' + - 'tooling/*' diff --git a/publish.ts b/publish.ts index 2f770686..dd0fb8ba 100644 --- a/publish.ts +++ b/publish.ts @@ -1,7 +1,7 @@ import sdkPkg from './packages/sdk/package.json' import typesPkg from './packages/types/package.json' import fs from 'node:fs' -import {execSync} from 'node:child_process' +import { execSync } from 'node:child_process' import semver from 'semver' function savePackageJson(path: string, data: Record) { @@ -10,15 +10,15 @@ function savePackageJson(path: string, data: Record) { function main() { const [version] = process.argv.slice(2) - - if(!version) { + + if (!version) { return console.error('Missing version') } - - if(!semver.valid(version)) { + + if (!semver.valid(version)) { return console.error('Version is not valid') } - + const properties = { private: false, version, @@ -53,12 +53,12 @@ function main() { execSync('pnpm dlx tsup', { cwd: './packages/types', }) - } catch(error) { - console.log('Build failed'); - console.log(error); + } catch (error) { + console.log('Build failed') + console.log(error) process.exit(1) } - + execSync('npm publish --access=public', { cwd: './packages/sdk', }) diff --git a/tooling/eslint/base.js b/tooling/eslint/base.js new file mode 100644 index 00000000..b641843a --- /dev/null +++ b/tooling/eslint/base.js @@ -0,0 +1,50 @@ +/** @type {import("eslint").Linter.Config} */ +const config = { + extends: [ + 'turbo', + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended-type-checked', + 'plugin:@typescript-eslint/stylistic-type-checked', + 'prettier', + ], + env: { + es2022: true, + node: true, + }, + parser: '@typescript-eslint/parser', + parserOptions: { + project: true, + }, + plugins: ['@typescript-eslint', 'import'], + rules: { + 'turbo/no-undeclared-env-vars': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }, + ], + '@typescript-eslint/consistent-type-imports': [ + 'warn', + { prefer: 'type-imports', fixStyle: 'separate-type-imports' }, + ], + '@typescript-eslint/no-misused-promises': [ + 2, + { checksVoidReturn: { attributes: false } }, + ], + 'import/consistent-type-specifier-style': ['error', 'prefer-top-level'], + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-floating-promises": "off", + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/ban-ts-comment": "off" + }, + ignorePatterns: [ + '**/.eslintrc.cjs', + '**/*.config.js', + '**/*.config.cjs', + '.next', + 'dist', + 'pnpm-lock.yaml', + ], + reportUnusedDisableDirectives: true, +}; + +module.exports = config; diff --git a/tooling/eslint/package.json b/tooling/eslint/package.json new file mode 100644 index 00000000..f0734cbb --- /dev/null +++ b/tooling/eslint/package.json @@ -0,0 +1,40 @@ +{ + "name": "@mixan/eslint-config", + "version": "0.1.0", + "private": true, + "license": "MIT", + "files": [ + "./base.js", + "./react.js" + ], + "scripts": { + "clean": "rm -rf .turbo node_modules", + "lint": "eslint .", + "format": "prettier --check \"**/*.{mjs,ts,md,json}\"", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^6.6.0", + "@typescript-eslint/parser": "^6.6.0", + "eslint-config-prettier": "^9.0.0", + "eslint-config-turbo": "^1.10.13", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0" + }, + "devDependencies": { + "@types/eslint": "^8.44.2", + "@mixan/prettier-config": "workspace:*", + "@mixan/tsconfig": "workspace:*", + "eslint": "^8.48.0", + "typescript": "^5.2.0" + }, + "eslintConfig": { + "root": true, + "extends": [ + "./base.js" + ] + }, + "prettier": "@mixan/prettier-config" +} diff --git a/tooling/eslint/react.js b/tooling/eslint/react.js new file mode 100644 index 00000000..34a289f8 --- /dev/null +++ b/tooling/eslint/react.js @@ -0,0 +1,24 @@ +/** @type {import('eslint').Linter.Config} */ +const config = { + extends: [ + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + 'plugin:jsx-a11y/recommended', + ], + rules: { + 'react/prop-types': 'off', + }, + globals: { + React: 'writable', + }, + settings: { + react: { + version: 'detect', + }, + }, + env: { + browser: true, + }, +}; + +module.exports = config; diff --git a/tooling/eslint/tsconfig.json b/tooling/eslint/tsconfig.json new file mode 100644 index 00000000..115d8a35 --- /dev/null +++ b/tooling/eslint/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@mixan/tsconfig/base.json", + "compilerOptions": { + "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" + }, + "include": ["."], + "exclude": ["node_modules"] +} diff --git a/tooling/prettier/index.mjs b/tooling/prettier/index.mjs new file mode 100644 index 00000000..a3526936 --- /dev/null +++ b/tooling/prettier/index.mjs @@ -0,0 +1,28 @@ +/** @typedef {import("prettier").Config} PrettierConfig */ +/** @typedef {import("@ianvs/prettier-plugin-sort-imports").PluginConfig} SortImportsConfig */ + +/** @type { PrettierConfig | SortImportsConfig } */ +const config = { + plugins: [ + '@ianvs/prettier-plugin-sort-imports', + ], + importOrder: [ + '^(react/(.*)$)|^(react$)|^(react-native(.*)$)', + '', + '', + '^@mixan/(.*)$', + '', + '^~/', + '^[../]', + '^[./]', + ], + importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'], + importOrderTypeScriptVersion: '4.4.0', + singleQuote: true, + semi: true, + trailingComma: 'es5', + printWidth: 80, + tabWidth: 2, +}; + +export default config; diff --git a/tooling/prettier/package.json b/tooling/prettier/package.json new file mode 100644 index 00000000..d2a34f4b --- /dev/null +++ b/tooling/prettier/package.json @@ -0,0 +1,17 @@ +{ + "name": "@mixan/prettier-config", + "version": "0.1.0", + "private": true, + "main": "index.mjs", + "scripts": { + "clean": "rm -rf .turbo node_modules" + }, + "dependencies": { + "@ianvs/prettier-plugin-sort-imports": "^4.1.0", + "prettier": "^3.0.3" + }, + "devDependencies": { + "@mixan/tsconfig": "workspace:*", + "typescript": "^5.2.0" + } +} diff --git a/tooling/prettier/tsconfig.json b/tooling/prettier/tsconfig.json new file mode 100644 index 00000000..115d8a35 --- /dev/null +++ b/tooling/prettier/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@mixan/tsconfig/base.json", + "compilerOptions": { + "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" + }, + "include": ["."], + "exclude": ["node_modules"] +} diff --git a/tooling/typescript/base.json b/tooling/typescript/base.json new file mode 100644 index 00000000..bd981df1 --- /dev/null +++ b/tooling/typescript/base.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "checkJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "noUncheckedIndexedAccess": true + }, + "exclude": ["node_modules", "build", "dist"] +} diff --git a/tooling/typescript/package.json b/tooling/typescript/package.json new file mode 100644 index 00000000..21d3d700 --- /dev/null +++ b/tooling/typescript/package.json @@ -0,0 +1,8 @@ +{ + "name": "@mixan/tsconfig", + "version": "0.1.0", + "private": true, + "files": [ + "base.json" + ] +}