From 5b1da4877a920a9704f1bbbf74209825ee65939d Mon Sep 17 00:00:00 2001 From: Pedro Pupo Sa da Costa Date: Fri, 9 Feb 2024 09:50:25 +0000 Subject: [PATCH 1/3] feat: reimagine analytics --- apps/next-app/next.config.js | 1 + apps/next-app/pages/analytics/index.page.tsx | 51 +++++++++++ libs/react/components/src/theme/theme.ts | 11 +++ package.json | 1 + pnpm-lock.yaml | 90 ++++++++++++++++++++ 5 files changed, 154 insertions(+) create mode 100644 apps/next-app/pages/analytics/index.page.tsx diff --git a/apps/next-app/next.config.js b/apps/next-app/next.config.js index 2d5ab77b8..0604ab17a 100644 --- a/apps/next-app/next.config.js +++ b/apps/next-app/next.config.js @@ -13,6 +13,7 @@ const nextConfig = { emotion: true, }, pageExtensions: ["page.tsx", "api.ts"], + transpilePackages: ["@mui/x-charts"], async rewrites() { const aboutUsRewrite = [ { diff --git a/apps/next-app/pages/analytics/index.page.tsx b/apps/next-app/pages/analytics/index.page.tsx new file mode 100644 index 000000000..8426e08a1 --- /dev/null +++ b/apps/next-app/pages/analytics/index.page.tsx @@ -0,0 +1,51 @@ +import * as fs from "node:fs/promises"; +import { GlobalStyles } from "@mui/joy"; +import { BarChart } from "@mui/x-charts/BarChart"; +import { LineChart } from "@mui/x-charts/LineChart"; +import { AppHead, BackgroundFadedImage } from "@chair-flight/react/components"; +import { BlogIndex, LayoutPublic } from "@chair-flight/react/containers"; +import { staticHandler } from "@chair-flight/trpc/server"; +import type { NextPage } from "next"; + +const Page: NextPage = () => { + return ( + }> + + ({ + ".MuiChartsTooltip-table": { + backgroundColor: t.vars.palette.background.surface, + }, + })} + /> + + + + ); +}; + +export const getStaticProps = staticHandler(async ({ helper }) => { + await BlogIndex.getData({ params: {}, helper }); + return { props: {} }; +}, fs); + +export default Page; diff --git a/libs/react/components/src/theme/theme.ts b/libs/react/components/src/theme/theme.ts index c81e73052..32c2d1189 100644 --- a/libs/react/components/src/theme/theme.ts +++ b/libs/react/components/src/theme/theme.ts @@ -80,6 +80,16 @@ const lightBackground = { }, }; +// @mui-x relies on some mui theme props that do not exist in joy themes. +const muiThemeBackwardsCompatibility = { + shape: { + borderRadius: 8, + }, + transitions: { + create: () => "ok", + }, +}; + export const theme = extendTheme({ typography: { h1: { @@ -145,4 +155,5 @@ export const theme = extendTheme({ }, }, }, + ...muiThemeBackwardsCompatibility, }); diff --git a/package.json b/package.json index 5a8bf405b..45bc8a158 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@mui/icons-material": "^5.15.7", "@mui/joy": "5.0.0-beta.25", "@mui/material": "npm:@mui/joy@5.0.0-beta.25", + "@mui/x-charts": "^6.19.3", "@napi-rs/image": "^1.7.0", "@prisma/client": "^5.9.1", "@react-three/drei": "^9.97.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1c7870ca1..52d86a0e3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ dependencies: '@mui/material': specifier: npm:@mui/joy@5.0.0-beta.25 version: /@mui/joy@5.0.0-beta.25(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0) + '@mui/x-charts': + specifier: ^6.19.3 + version: 6.19.3(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@mui/joy@5.0.0-beta.25)(@mui/system@5.15.7)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0) '@napi-rs/image': specifier: ^1.7.0 version: 1.7.0 @@ -3525,6 +3528,41 @@ packages: react-is: 18.2.0 dev: false + /@mui/x-charts@6.19.3(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@mui/joy@5.0.0-beta.25)(@mui/system@5.15.7)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-VxF+mHXtmR2LxalH2KRzF4gLT6KFDbYMvis6rkcyr+w6J17KBxMsEGx8V0nn1CIEslzcSXgbv41jIzodhiFyMQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@emotion/react': ^11.9.0 + '@emotion/styled': ^11.8.1 + '@mui/material': ^5.4.1 + '@mui/system': ^5.4.1 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@emotion/react': + optional: true + '@emotion/styled': + optional: true + dependencies: + '@babel/runtime': 7.23.9 + '@emotion/react': 11.11.3(@types/react@18.2.52)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.52)(react@18.2.0) + '@mui/base': 5.0.0-beta.34(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0) + '@mui/material': /@mui/joy@5.0.0-beta.25(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0) + '@mui/system': 5.15.7(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.52)(react@18.2.0) + '@react-spring/rafz': 9.7.3 + '@react-spring/web': 9.7.3(react-dom@18.2.0)(react@18.2.0) + clsx: 2.1.0 + d3-color: 3.1.0 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + dev: false + /@napi-rs/image-android-arm-eabi@1.7.0: resolution: {integrity: sha512-lpyqxaIYUrdk096xoJjvPGin5jY1Ehor0RxryqDvowGUhVU3TDgolsjjuFPEki3cfvV6zzAm7bWUkmxIci2zaw==} engines: {node: '>= 10'} @@ -5541,6 +5579,16 @@ packages: react: 18.2.0 dev: false + /@react-spring/animated@9.7.3(react@18.2.0): + resolution: {integrity: sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/shared': 9.7.3(react@18.2.0) + '@react-spring/types': 9.7.3 + react: 18.2.0 + dev: false + /@react-spring/core@9.6.1(react@18.2.0): resolution: {integrity: sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==} peerDependencies: @@ -5553,10 +5601,25 @@ packages: react: 18.2.0 dev: false + /@react-spring/core@9.7.3(react@18.2.0): + resolution: {integrity: sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/animated': 9.7.3(react@18.2.0) + '@react-spring/shared': 9.7.3(react@18.2.0) + '@react-spring/types': 9.7.3 + react: 18.2.0 + dev: false + /@react-spring/rafz@9.6.1: resolution: {integrity: sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==} dev: false + /@react-spring/rafz@9.7.3: + resolution: {integrity: sha512-9vzW1zJPcC4nS3aCV+GgcsK/WLaB520Iyvm55ARHfM5AuyBqycjvh1wbmWmgCyJuX4VPoWigzemq1CaaeRSHhQ==} + dev: false + /@react-spring/shared@9.6.1(react@18.2.0): resolution: {integrity: sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==} peerDependencies: @@ -5567,6 +5630,15 @@ packages: react: 18.2.0 dev: false + /@react-spring/shared@9.7.3(react@18.2.0): + resolution: {integrity: sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/types': 9.7.3 + react: 18.2.0 + dev: false + /@react-spring/three@9.6.1(@react-three/fiber@8.15.16)(react@18.2.0)(three@0.161.0): resolution: {integrity: sha512-Tyw2YhZPKJAX3t2FcqvpLRb71CyTe1GvT3V+i+xJzfALgpk10uPGdGaQQ5Xrzmok1340DAeg2pR/MCfaW7b8AA==} peerDependencies: @@ -5587,6 +5659,24 @@ packages: resolution: {integrity: sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==} dev: false + /@react-spring/types@9.7.3: + resolution: {integrity: sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==} + dev: false + + /@react-spring/web@9.7.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/animated': 9.7.3(react@18.2.0) + '@react-spring/core': 9.7.3(react@18.2.0) + '@react-spring/shared': 9.7.3(react@18.2.0) + '@react-spring/types': 9.7.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@react-three/drei@9.97.0(@react-three/fiber@8.15.16)(@types/react@18.2.52)(@types/three@0.161.2)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0)(three@0.161.0): resolution: {integrity: sha512-D7qNQDbEoYHMlJU0tr/f/rCmw1TQmI+INEGGrfoAEA+sIvqLw9wLCra+1+t22lEPCpdpmVSMmdv6PynMcv5tCQ==} peerDependencies: From 6206820ba73d5e7cef46dcc342e507f4b5c2fca6 Mon Sep 17 00:00:00 2001 From: Pedro Pupo Sa da Costa Date: Fri, 9 Feb 2024 14:57:13 +0000 Subject: [PATCH 2/3] refactor: drop prisma for drizzle --- .env.example | 3 +- README.md | 58 +- apps/next-app/pages/_app.page.tsx | 6 +- .../analytics/{index.page.tsx => index.tsx} | 21 +- apps/next-app/project.json | 7 +- libs/core/analytics/.eslintrc.json | 5 - libs/core/analytics/project.json | 22 - .../core/analytics/src/entities/page-event.ts | 23 - .../analytics/src/entities/track-event.ts | 27 - libs/core/analytics/src/index.ts | 2 - libs/core/analytics/tsconfig.json | 8 - libs/providers/analytics/drizzle.config.ts | 11 + libs/providers/analytics/drizzle/index.ts | 6 + libs/providers/analytics/drizzle/schema.ts | 36 ++ .../migration.sql | 40 -- .../prisma/migrations/migration_lock.toml | 3 - libs/providers/analytics/prisma/schema.prisma | 41 -- libs/providers/analytics/project.json | 64 +- libs/providers/analytics/src/analytics.ts | 29 +- .../analytics/src/entities/page-event.ts | 20 +- .../analytics/src/entities/track-event.ts | 31 +- .../analytics/src/functions/create-events.ts | 42 -- .../src/functions/get-daily-users.ts | 17 + libs/providers/analytics/src/index.ts | 2 + libs/providers/analytics/src/schema.ts | 0 libs/providers/analytics/tsconfig.json | 2 +- .../src/components/analytics-page-logger.tsx | 19 + .../src/components/analytics-provider.tsx | 26 + .../src/{ => hooks}/use-analytics-plugin.ts | 7 +- .../analytics/src/hooks/use-track-event.ts | 23 + libs/react/analytics/src/index.ts | 4 +- libs/react/analytics/src/use-analytics.tsx | 49 -- .../components/app-buttons/app-buttons.tsx | 6 +- .../use-page-transition.ts | 17 +- .../src/routers/common/analytics-router.ts | 11 +- package.json | 8 +- pnpm-lock.yaml | 587 ++++++++++++++++-- tsconfig.base.json | 1 - 38 files changed, 776 insertions(+), 508 deletions(-) rename apps/next-app/pages/analytics/{index.page.tsx => index.tsx} (67%) delete mode 100644 libs/core/analytics/.eslintrc.json delete mode 100644 libs/core/analytics/project.json delete mode 100644 libs/core/analytics/src/entities/page-event.ts delete mode 100644 libs/core/analytics/src/entities/track-event.ts delete mode 100644 libs/core/analytics/src/index.ts delete mode 100644 libs/core/analytics/tsconfig.json create mode 100644 libs/providers/analytics/drizzle.config.ts create mode 100644 libs/providers/analytics/drizzle/index.ts create mode 100644 libs/providers/analytics/drizzle/schema.ts delete mode 100644 libs/providers/analytics/prisma/migrations/20231119122436_create_initial_tables/migration.sql delete mode 100644 libs/providers/analytics/prisma/migrations/migration_lock.toml delete mode 100644 libs/providers/analytics/prisma/schema.prisma delete mode 100644 libs/providers/analytics/src/functions/create-events.ts create mode 100644 libs/providers/analytics/src/functions/get-daily-users.ts create mode 100644 libs/providers/analytics/src/schema.ts create mode 100644 libs/react/analytics/src/components/analytics-page-logger.tsx create mode 100644 libs/react/analytics/src/components/analytics-provider.tsx rename libs/react/analytics/src/{ => hooks}/use-analytics-plugin.ts (87%) create mode 100644 libs/react/analytics/src/hooks/use-track-event.ts delete mode 100644 libs/react/analytics/src/use-analytics.tsx diff --git a/.env.example b/.env.example index ee43c5058..4a5266b0d 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,6 @@ ENV_FILE_NAME=LOCAL VERCEL_URL=localhost:4200 -PROVIDER_POSTGRES_ANALYTICS_PRISMA_URL="postgres://default:this0is0a0secret0password@localhost:5432/verceldb" -PROVIDER_POSTGRES_ANALYTICS_URL_NON_POOLING="postgres://default:this0is0a0secret0password@localhost:5432/verceldb" +PROVIDER_POSTGRES_ANALYTICS="postgres://default:this0is0a0secret0password@localhost:5432/verceldb" PROVIDER_GITHUB_TOKEN= PROVIDER_GITHUB_PROJECT_UPSTREAM_OWNER=PupoSDC PROVIDER_GITHUB_PROJECT_UPSTREAM_REPO=chair-flight diff --git a/README.md b/README.md index 87516688e..f61c2fe07 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Built with [`Next`](https://nextjs.org/), [`Vitest`](https://vitest.dev/), [`Storybook`](https://storybook.js.org/), -[`Prisma`](https://www.prisma.io/), +[`Drizzle`](https://orm.drizzle.team/), [`Trpc`](https://trpc.io/), [`Zustand`](https://github.com/pmndrs/zustand), and [`MDX`](https://mdxjs.com/). @@ -59,27 +59,31 @@ can and will be introduced in patch releases. ### Libs -| Name | Desc | -| -------------------------- | ----------------------------------------------------------- | -| base-env | Utility to safely access env variables | -| base-errors | Errors that can be handled in the front or in the backend | -| base-types | Base Business types used across the app | -| content-blog | Blog posts | -| content-question-bank-prep | Content bank for the interview prep module | -| content-question-bank-type | Content bank for the Type Rating module | -| content-question-bank-atpl | Content bank for the ATPL theory module | -| core-analytics | Analytics provider (currently a custom solution) | -| core-app | Business logic blocks sharable between React SPA/SSR and RN | -| core-blog | Blog posts compiler and core functions | -| core-github | Github related functionalities | -| core-schemas | Zod Schemas shared across our application (from base-types) | -| react-analytics | React hooks to interact with our analytics provider | -| react-components | Shared react (DOM) components | -| react-containers | Next.js specific components | -| react-games | Shared react (three.js) components | -| trpc-client | trpc next js specific client | -| trpc-mock | trpc mock server, for storybook and RTL tests | -| trpc-server | main trpc server. All our backend logic starts here | +| Name | Desc | +| -------------------------- | --------------------------------------------------------- | +| base-env | Utility to safely access env variables | +| base-errors | Errors that can be handled in the front or in the backend | +| base-utils | Common JS utilities | +| content-blog | Blog posts | +| content-question-bank-prep | Content bank for the interview prep module | +| content-question-bank-type | Content bank for the Type Rating module | +| content-question-bank-atpl | Content bank for the ATPL theory module | +| core-github | Github related functionalities | +| core-question-bank | Question Bank entities and functions | +| core-search | Search API entities | +| core-tests | Test related entities and functions | +| providers-analytics | Provides analytics postgres DB interactions | +| providers-blog | Blog Pages compiler and server side provider | +| providers-github | Github API provider using octokit | +| providers-question-bank | Question Bank compiler and server side provider | +| providers-search | Minisearch powered search provider | +| react-analytics | React hooks to interact with our analytics provider | +| react-components | Shared react (DOM) components | +| react-containers | Next.js specific components | +| react-games | Shared react (three.js) components | +| trpc-client | trpc next js specific client | +| trpc-mock | trpc mock server, for storybook and RTL tests | +| trpc-server | main trpc server. All our backend logic starts here | ### .env @@ -94,16 +98,16 @@ If you create the required services remotely, you can create other env files to point to those services. For example: ```sh -cp .env.example .env.production +cp .env.example .env.prod ``` You can then run specific configurations using the nx `-c` flag: ```sh -pnpm run dev -c production -pnpm run build -c production -pnpm run migrate -c production -pnpm run generate -c production +pnpm run dev -c prod +pnpm run build -c prod +pnpm run migrate -c prod +pnpm run generate -c prod ``` For more information on managing `.env` variables within an `nx` project you can diff --git a/apps/next-app/pages/_app.page.tsx b/apps/next-app/pages/_app.page.tsx index 26ee1012d..7cc727bad 100644 --- a/apps/next-app/pages/_app.page.tsx +++ b/apps/next-app/pages/_app.page.tsx @@ -1,7 +1,10 @@ import React, { StrictMode } from "react"; import { default as Head } from "next/head"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; -import { AnalyticsProvider } from "@chair-flight/react/analytics"; +import { + AnalyticsProvider, + AnalyticsPageLogger, +} from "@chair-flight/react/analytics"; import { ThemeProvider, Toaster } from "@chair-flight/react/components"; import { trpc } from "@chair-flight/trpc/client"; import type { AppProps } from "next/app"; @@ -16,6 +19,7 @@ const App: FunctionComponent = ({ Component, pageProps }) => { return ( + Welcome to chair-flight! diff --git a/apps/next-app/pages/analytics/index.page.tsx b/apps/next-app/pages/analytics/index.tsx similarity index 67% rename from apps/next-app/pages/analytics/index.page.tsx rename to apps/next-app/pages/analytics/index.tsx index 8426e08a1..22d139dcb 100644 --- a/apps/next-app/pages/analytics/index.page.tsx +++ b/apps/next-app/pages/analytics/index.tsx @@ -1,13 +1,15 @@ import * as fs from "node:fs/promises"; import { GlobalStyles } from "@mui/joy"; -import { BarChart } from "@mui/x-charts/BarChart"; import { LineChart } from "@mui/x-charts/LineChart"; import { AppHead, BackgroundFadedImage } from "@chair-flight/react/components"; import { BlogIndex, LayoutPublic } from "@chair-flight/react/containers"; +import { trpc } from "@chair-flight/trpc/client"; import { staticHandler } from "@chair-flight/trpc/server"; import type { NextPage } from "next"; const Page: NextPage = () => { + const { data = [] } = trpc.common.analytics.getDailyUsers.useQuery(); + return ( }> @@ -18,22 +20,13 @@ const Page: NextPage = () => { }, })} /> - + v.uniqueVisitors), + label: "Unique Visitors", + color: "primary", }, ]} width={500} diff --git a/apps/next-app/project.json b/apps/next-app/project.json index e112f5ae9..1f92a51d8 100644 --- a/apps/next-app/project.json +++ b/apps/next-app/project.json @@ -6,11 +6,16 @@ "targets": { "dev": { "executor": "@nx/next:server", - "dependsOn": ["^deploy", "^compile", "^generate"], + "dependsOn": ["^compile", "^migrate"], "options": { "port": 4200, "buildTarget": "next-app:build", "dev": true + }, + "configurations": { + "prod": {}, + "dev": {}, + "local": {} } }, "build": { diff --git a/libs/core/analytics/.eslintrc.json b/libs/core/analytics/.eslintrc.json deleted file mode 100644 index 8ba3202ba..000000000 --- a/libs/core/analytics/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": ["../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [] -} diff --git a/libs/core/analytics/project.json b/libs/core/analytics/project.json deleted file mode 100644 index a99eb36f4..000000000 --- a/libs/core/analytics/project.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "core-analytics", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/core/analytics/src", - "projectType": "library", - "targets": { - "lint": { - "executor": "@nx/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["libs/core/analytics/**/*.ts"] - } - }, - "typecheck": { - "executor": "nx:run-commands", - "options": { - "commands": ["tsc -p libs/core/analytics/tsconfig.json"] - } - } - }, - "tags": [] -} diff --git a/libs/core/analytics/src/entities/page-event.ts b/libs/core/analytics/src/entities/page-event.ts deleted file mode 100644 index 0d1102a1c..000000000 --- a/libs/core/analytics/src/entities/page-event.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { z } from "zod"; - -export type PageEvent = { - anonymousId: string; - title: string; - path: string; - resolvedPath: string; - height: number; - width: number; - referrer?: string; - timestamp: number; -}; - -export const PageEventSchema: z.ZodSchema = z.object({ - anonymousId: z.string(), - title: z.string(), - path: z.string(), - resolvedPath: z.string(), - height: z.number(), - width: z.number(), - referrer: z.string().optional(), - timestamp: z.number(), -}); diff --git a/libs/core/analytics/src/entities/track-event.ts b/libs/core/analytics/src/entities/track-event.ts deleted file mode 100644 index a1e6aa56f..000000000 --- a/libs/core/analytics/src/entities/track-event.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { z } from "zod"; - -type TrackEventMap = { - "themeButton.switch": Record; -}; - -type TrackEventBase = { - eventName: T; - anonymousId: string; - timestamp: number; - path: string; - resolvedPath: string; - properties: TrackEventMap[T]; -}; - -export type TrackEvent = TrackEventBase; -export type TrackEventName = TrackEvent["eventName"]; -export type TrackEventPayload = TrackEventMap[T]; - -export const TrackEventSchema: z.ZodSchema = z.object({ - eventName: z.string(), - anonymousId: z.string(), - path: z.string(), - resolvedPath: z.string(), - timestamp: z.number(), - properties: z.object({}).passthrough(), -}) as unknown as z.ZodSchema; diff --git a/libs/core/analytics/src/index.ts b/libs/core/analytics/src/index.ts deleted file mode 100644 index c8c8a5b76..000000000 --- a/libs/core/analytics/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./entities/page-event"; -export * from "./entities/track-event"; diff --git a/libs/core/analytics/tsconfig.json b/libs/core/analytics/tsconfig.json deleted file mode 100644 index cdde824ae..000000000 --- a/libs/core/analytics/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "include": ["src/**/*.ts"], - "files": ["../../../types.d.ts"], - "compilerOptions": { - "types": ["vitest/globals"] - } -} diff --git a/libs/providers/analytics/drizzle.config.ts b/libs/providers/analytics/drizzle.config.ts new file mode 100644 index 000000000..45a5c1b81 --- /dev/null +++ b/libs/providers/analytics/drizzle.config.ts @@ -0,0 +1,11 @@ +import { getEnvVariableOrThrow } from "@chair-flight/base/env"; +import type { Config } from "drizzle-kit"; + +export default { + schema: "./drizzle/schema.ts", + out: "./drizzle", + driver: "pg", + dbCredentials: { + connectionString: getEnvVariableOrThrow("PROVIDER_POSTGRES_ANALYTICS"), + }, +} satisfies Config; diff --git a/libs/providers/analytics/drizzle/index.ts b/libs/providers/analytics/drizzle/index.ts new file mode 100644 index 000000000..2897b8505 --- /dev/null +++ b/libs/providers/analytics/drizzle/index.ts @@ -0,0 +1,6 @@ +import * as schema from "./schema"; +import type { NodePgDatabase } from "drizzle-orm/node-postgres"; + +export const analyticsSchema = schema; +export type AnalyticsSchema = typeof schema; +export type AnalyticsDb = NodePgDatabase; diff --git a/libs/providers/analytics/drizzle/schema.ts b/libs/providers/analytics/drizzle/schema.ts new file mode 100644 index 000000000..a8a434d5b --- /dev/null +++ b/libs/providers/analytics/drizzle/schema.ts @@ -0,0 +1,36 @@ +import { randomUUID } from "crypto"; +import { sql } from "drizzle-orm"; +import { pgTable, timestamp, text, integer, jsonb } from "drizzle-orm/pg-core"; +import { getEnvVariableOrThrow } from "@chair-flight/base/env"; + +const getEnv = () => getEnvVariableOrThrow("NODE_ENV"); + +export const pageEvent = pgTable("PageEvent", { + id: text("id").primaryKey().notNull().$defaultFn(randomUUID), + timestamp: timestamp("timestamp") + .notNull() + .default(sql`CURRENT_TIMESTAMP`), + environment: text("environment").notNull().$default(getEnv), + anonymousId: text("anonymousId").notNull(), + title: text("title").notNull(), + height: integer("height").notNull(), + width: integer("width").notNull(), + path: text("path").notNull(), + resolvedPath: text("resolvedPath").notNull(), +}); + +export const trackEvent = pgTable("TrackEvent", { + id: text("id") + .primaryKey() + .notNull() + .$defaultFn(() => randomUUID()), + timestamp: timestamp("timestamp") + .notNull() + .default(sql`CURRENT_TIMESTAMP`), + environment: text("environment").notNull().$default(getEnv), + anonymousId: text("anonymousId").notNull(), + eventName: text("eventName").notNull(), + properties: jsonb("properties").notNull(), + path: text("path").notNull(), + resolvedPath: text("resolvedPath").notNull(), +}); diff --git a/libs/providers/analytics/prisma/migrations/20231119122436_create_initial_tables/migration.sql b/libs/providers/analytics/prisma/migrations/20231119122436_create_initial_tables/migration.sql deleted file mode 100644 index db1b6646b..000000000 --- a/libs/providers/analytics/prisma/migrations/20231119122436_create_initial_tables/migration.sql +++ /dev/null @@ -1,40 +0,0 @@ --- CreateTable -CREATE TABLE "PageEvent" ( - "id" TEXT NOT NULL, - "timestamp" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "anonymousId" TEXT NOT NULL, - "title" TEXT NOT NULL, - "referrer" TEXT NOT NULL, - "height" INTEGER NOT NULL, - "width" INTEGER NOT NULL, - "environment" TEXT NOT NULL, - "path" TEXT NOT NULL, - "resolvedPath" TEXT NOT NULL, - - CONSTRAINT "PageEvent_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "PageEventDailyCount" ( - "id" TEXT NOT NULL, - "environment" TEXT NOT NULL, - "count" INTEGER NOT NULL, - "path" TEXT NOT NULL, - "timestamp" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "PageEventDailyCount_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "TrackEvent" ( - "id" TEXT NOT NULL, - "timestamp" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "anonymousId" TEXT NOT NULL, - "eventName" TEXT NOT NULL, - "properties" JSONB NOT NULL, - "environment" TEXT NOT NULL, - "path" TEXT NOT NULL, - "resolvedPath" TEXT NOT NULL, - - CONSTRAINT "TrackEvent_pkey" PRIMARY KEY ("id") -); diff --git a/libs/providers/analytics/prisma/migrations/migration_lock.toml b/libs/providers/analytics/prisma/migrations/migration_lock.toml deleted file mode 100644 index fbffa92c2..000000000 --- a/libs/providers/analytics/prisma/migrations/migration_lock.toml +++ /dev/null @@ -1,3 +0,0 @@ -# Please do not edit this file manually -# It should be added in your version-control system (i.e. Git) -provider = "postgresql" \ No newline at end of file diff --git a/libs/providers/analytics/prisma/schema.prisma b/libs/providers/analytics/prisma/schema.prisma deleted file mode 100644 index 4707ae19c..000000000 --- a/libs/providers/analytics/prisma/schema.prisma +++ /dev/null @@ -1,41 +0,0 @@ -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "postgresql" - url = env("PROVIDER_POSTGRES_ANALYTICS_PRISMA_URL") - directUrl = env("PROVIDER_POSTGRES_ANALYTICS_URL_NON_POOLING") -} - -model PageEvent { - id String @id @default(uuid()) - timestamp DateTime @default(now()) - anonymousId String - title String - referrer String - height Int - width Int - environment String - path String - resolvedPath String -} - -model PageEventDailyCount { - id String @id @default(uuid()) - environment String - count Int - path String - timestamp DateTime -} - -model TrackEvent { - id String @id @default(uuid()) - timestamp DateTime @default(now()) - anonymousId String - eventName String - properties Json - environment String - path String - resolvedPath String -} diff --git a/libs/providers/analytics/project.json b/libs/providers/analytics/project.json index 27ae3ddb3..a2ab9f31a 100644 --- a/libs/providers/analytics/project.json +++ b/libs/providers/analytics/project.json @@ -4,76 +4,28 @@ "sourceRoot": "libs/providers/analytics/src", "projectType": "library", "targets": { - "generate": { - "executor": "nx:run-commands", - "options": { - "cwd": "libs/providers/analytics", - "command": "prisma generate" - }, - "configurations": { - "local": { - "command": "env-cmd -f ../../../.env.local prisma generate" - }, - "dev": { - "command": "env-cmd -f ../../../.env.dev prisma migrate dev" - }, - "prod": { - "command": "env-cmd -f ../../../.env.prod prisma migrate dev" - } - } - }, "migrate": { "executor": "nx:run-commands", "options": { "cwd": "libs/providers/analytics", - "command": "prisma migrate dev" - }, - "configurations": { - "local": { - "command": "env-cmd -f ../../../.env.local prisma migrate dev" - }, - "dev": { - "command": "env-cmd -f ../../../.env.dev prisma migrate dev" - }, - "prod": { - "command": "env-cmd -f ../../../.env.prod prisma migrate dev" - } - } - }, - "deploy": { - "executor": "nx:run-commands", - "options": { - "cwd": "libs/providers/analytics", - "command": "prisma migrate deploy" + "command": "drizzle-kit push:pg" }, "configurations": { - "local": { - "command": "env-cmd -f ../../../.env.local prisma migrate deploy" - }, - "dev": { - "command": "env-cmd -f ../../../.env.dev prisma migrate deploy" - }, - "prod": { - "command": "env-cmd -f ../../../.env.prod prisma migrate deploy" - } + "prod": {}, + "dev": {}, + "local": {} } }, "studio": { "executor": "nx:run-commands", "options": { "cwd": "libs/providers/analytics", - "command": "prisma studio" + "command": "drizzle-kit studio" }, "configurations": { - "local": { - "command": "env-cmd -f ../../../.env.local prisma studio" - }, - "dev": { - "command": "env-cmd -f ../../../.env.dev prisma studio" - }, - "prod": { - "command": "env-cmd -f ../../../.env.prod prisma studio" - } + "prod": {}, + "dev": {}, + "local": {} } }, "lint": { diff --git a/libs/providers/analytics/src/analytics.ts b/libs/providers/analytics/src/analytics.ts index 16de60cca..3635f751c 100644 --- a/libs/providers/analytics/src/analytics.ts +++ b/libs/providers/analytics/src/analytics.ts @@ -1,6 +1,9 @@ -import { PrismaClient } from "@prisma/client"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { Client } from "pg"; import { getEnvVariableOrThrow } from "@chair-flight/base/env"; -import { createPageEvent, createTrackEvent } from "./functions/create-events"; +import { analyticsSchema } from "../drizzle"; +import { getDailyUsers } from "./functions/get-daily-users"; +import type { AnalyticsDb } from "../drizzle"; import type { PageEvent } from "./entities/page-event"; import type { TrackEvent } from "./entities/track-event"; @@ -10,23 +13,25 @@ interface AnalyticsProvider { } export class Analytics implements AnalyticsProvider { - private prisma: PrismaClient; + private db: AnalyticsDb; constructor() { - this.prisma = new PrismaClient({ - datasources: { - db: { - url: getEnvVariableOrThrow("PROVIDER_POSTGRES_ANALYTICS_PRISMA_URL"), - }, - }, - }); + const schema = analyticsSchema; + const pgProvider = getEnvVariableOrThrow("PROVIDER_POSTGRES_ANALYTICS"); + const client = new Client({ connectionString: pgProvider }); + this.db = drizzle(client, { schema }); + client.connect(); } async createPageEvent(event: PageEvent) { - return createPageEvent(this.prisma, event); + await this.db.insert(analyticsSchema.pageEvent).values(event); } async createTrackEvent(event: TrackEvent) { - return createTrackEvent(this.prisma, event); + await this.db.insert(analyticsSchema.trackEvent).values(event); + } + + async getDailyUsers() { + return getDailyUsers(this.db); } } diff --git a/libs/providers/analytics/src/entities/page-event.ts b/libs/providers/analytics/src/entities/page-event.ts index 0d1102a1c..cb60cff02 100644 --- a/libs/providers/analytics/src/entities/page-event.ts +++ b/libs/providers/analytics/src/entities/page-event.ts @@ -1,23 +1,17 @@ +import { type InferSelectModel } from "drizzle-orm"; import { z } from "zod"; +import type { pageEvent } from "../../drizzle/schema"; -export type PageEvent = { - anonymousId: string; - title: string; - path: string; - resolvedPath: string; - height: number; - width: number; - referrer?: string; - timestamp: number; -}; +export type PageEvent = Pick< + InferSelectModel, + "anonymousId" | "title" | "path" | "resolvedPath" | "height" | "width" +>; -export const PageEventSchema: z.ZodSchema = z.object({ +export const pageEventSchema: z.ZodSchema = z.strictObject({ anonymousId: z.string(), title: z.string(), path: z.string(), resolvedPath: z.string(), height: z.number(), width: z.number(), - referrer: z.string().optional(), - timestamp: z.number(), }); diff --git a/libs/providers/analytics/src/entities/track-event.ts b/libs/providers/analytics/src/entities/track-event.ts index 148f306cd..a9cf84559 100644 --- a/libs/providers/analytics/src/entities/track-event.ts +++ b/libs/providers/analytics/src/entities/track-event.ts @@ -1,30 +1,13 @@ +import { type InferSelectModel } from "drizzle-orm"; import { z } from "zod"; +import type { trackEvent } from "../../drizzle/schema"; -type TrackEventMap = { - "themeButton.switch": Record; -}; +export type TrackEvent = Pick< + InferSelectModel, + "anonymousId" | "eventName" | "properties" | "path" | "resolvedPath" +>; -type TrackEventBase = { - eventName: T; - anonymousId: string; - timestamp: number; - path: string; - resolvedPath: string; - properties: TrackEventMap[T]; -}; - -type SimplifiedTrackEvent = { - eventName: string; - anonymousId: string; - timestamp: number; - path: string; - resolvedPath: string; - properties: Record; -}; - -export type TrackEvent = TrackEventBase; - -export const TrackEventSchema: z.ZodSchema = z.object({ +export const trackEventSchema: z.ZodSchema = z.strictObject({ eventName: z.string(), anonymousId: z.string(), path: z.string(), diff --git a/libs/providers/analytics/src/functions/create-events.ts b/libs/providers/analytics/src/functions/create-events.ts deleted file mode 100644 index dc2d2e39a..000000000 --- a/libs/providers/analytics/src/functions/create-events.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { getEnvVariableOrThrow } from "@chair-flight/base/env"; -import type { PageEvent } from "../entities/page-event"; -import type { TrackEvent } from "../entities/track-event"; -import type { PrismaClient } from "@prisma/client"; - -const environment = getEnvVariableOrThrow("NODE_ENV"); - -export const createPageEvent = async ( - prisma: PrismaClient, - event: PageEvent, -) => { - await prisma.pageEvent.create({ - data: { - environment, - timestamp: new Date(event.timestamp), - anonymousId: event.anonymousId, - title: event.title, - path: event.path, - resolvedPath: event.resolvedPath, - height: event.height, - width: event.width, - referrer: event.referrer ?? "", - }, - }); -}; - -export const createTrackEvent = async ( - prisma: PrismaClient, - event: TrackEvent, -) => { - await prisma.trackEvent.create({ - data: { - environment, - timestamp: new Date(event.timestamp), - anonymousId: event.anonymousId, - eventName: event.eventName, - path: event.path, - resolvedPath: event.resolvedPath, - properties: event.properties, - }, - }); -}; diff --git a/libs/providers/analytics/src/functions/get-daily-users.ts b/libs/providers/analytics/src/functions/get-daily-users.ts new file mode 100644 index 000000000..9df16afc7 --- /dev/null +++ b/libs/providers/analytics/src/functions/get-daily-users.ts @@ -0,0 +1,17 @@ +import { countDistinct, desc } from "drizzle-orm"; +import { sql } from "drizzle-orm"; +import { analyticsSchema } from "../../drizzle"; +import type { AnalyticsDb } from "../../drizzle"; + +export const getDailyUsers = async (db: AnalyticsDb) => { + const pageEvent = analyticsSchema.pageEvent; + return (await db + .select({ + date: sql`to_char(${pageEvent.timestamp}, 'YYYY-MM-DD')`, + uniqueVisitors: countDistinct(pageEvent.anonymousId), + }) + .from(pageEvent) + .groupBy((q) => q.date) + .orderBy((q) => desc(q.date)) + .limit(31)) as { date: string; uniqueVisitors: number }[]; +}; diff --git a/libs/providers/analytics/src/index.ts b/libs/providers/analytics/src/index.ts index a1f1e9b83..0f09f7d8a 100644 --- a/libs/providers/analytics/src/index.ts +++ b/libs/providers/analytics/src/index.ts @@ -1 +1,3 @@ export { Analytics } from "./analytics"; +export * from "./entities/page-event"; +export * from "./entities/track-event"; diff --git a/libs/providers/analytics/src/schema.ts b/libs/providers/analytics/src/schema.ts new file mode 100644 index 000000000..e69de29bb diff --git a/libs/providers/analytics/tsconfig.json b/libs/providers/analytics/tsconfig.json index 38b50d525..da4c3480b 100644 --- a/libs/providers/analytics/tsconfig.json +++ b/libs/providers/analytics/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "../../../tsconfig.base.json", "compilerOptions": {}, - "include": ["src/**/*.ts"] + "include": ["src/**/*.ts", "drizzle.config.ts", "drizzle/schema.ts"] } diff --git a/libs/react/analytics/src/components/analytics-page-logger.tsx b/libs/react/analytics/src/components/analytics-page-logger.tsx new file mode 100644 index 000000000..2a18099d5 --- /dev/null +++ b/libs/react/analytics/src/components/analytics-page-logger.tsx @@ -0,0 +1,19 @@ +import { useContext, useEffect, useRef } from "react"; +import { useRouter } from "next/router"; +import { analyticsContext } from "./analytics-provider"; +import type { FunctionComponent } from "react"; + +export const AnalyticsPageLogger: FunctionComponent = () => { + const analytics = useContext(analyticsContext); + const oldRoute = useRef(""); + const router = useRouter(); + + useEffect(() => { + const pathWithoutQuery = router.asPath.split("?")[0]; + if (oldRoute.current === pathWithoutQuery) return; + oldRoute.current = pathWithoutQuery; + analytics.then((a) => a.page()); + }); + + return null; +}; diff --git a/libs/react/analytics/src/components/analytics-provider.tsx b/libs/react/analytics/src/components/analytics-provider.tsx new file mode 100644 index 000000000..330a7f189 --- /dev/null +++ b/libs/react/analytics/src/components/analytics-provider.tsx @@ -0,0 +1,26 @@ +import { createContext, useState } from "react"; +import { useAnalyticsPlugin } from "../hooks/use-analytics-plugin"; +import type { AnalyticsInstance } from "analytics"; +import type { FunctionComponent, PropsWithChildren } from "react"; + +export const analyticsContext = createContext>( + null as unknown as Promise, +); + +export const AnalyticsProvider: FunctionComponent = ({ + children, +}) => { + const plugin = useAnalyticsPlugin(); + const [analytics] = useState(async () => + (await import("analytics")).default({ + app: "chair-flight", + version: "1", + plugins: [plugin], + }), + ); + return ( + + {children} + + ); +}; diff --git a/libs/react/analytics/src/use-analytics-plugin.ts b/libs/react/analytics/src/hooks/use-analytics-plugin.ts similarity index 87% rename from libs/react/analytics/src/use-analytics-plugin.ts rename to libs/react/analytics/src/hooks/use-analytics-plugin.ts index 09a6f71bf..779476a6d 100644 --- a/libs/react/analytics/src/use-analytics-plugin.ts +++ b/libs/react/analytics/src/hooks/use-analytics-plugin.ts @@ -1,7 +1,6 @@ import { useRouter } from "next/dist/client/router"; import { NOOP } from "@chair-flight/base/utils"; import { trpc } from "@chair-flight/trpc/client"; -import type { TrackEventName } from "@chair-flight/core/analytics"; import type { AnalyticsPlugin } from "analytics"; type OriginalPageViewProps = { @@ -13,7 +12,6 @@ type OriginalPageViewProps = { url: string; height: number; width: number; - referrer: string; }; }; }; @@ -21,7 +19,7 @@ type OriginalPageViewProps = { type OriginalTrackEventProps = { payload: { type: "track"; - event: TrackEventName; + event: string; anonymousId: string; properties: Record; }; @@ -46,8 +44,6 @@ export const useAnalyticsPlugin = (): AnalyticsPlugin => { title: props.payload.properties.title, height: props.payload.properties.height, width: props.payload.properties.width, - referrer: props.payload.properties.referrer, - timestamp: Date.now(), }); }, track: (props: OriginalTrackEventProps) => { @@ -57,7 +53,6 @@ export const useAnalyticsPlugin = (): AnalyticsPlugin => { path: router.pathname, resolvedPath: router.asPath, properties: props.payload.properties as Record, - timestamp: Date.now(), }); }, }; diff --git a/libs/react/analytics/src/hooks/use-track-event.ts b/libs/react/analytics/src/hooks/use-track-event.ts new file mode 100644 index 000000000..8fe8fd889 --- /dev/null +++ b/libs/react/analytics/src/hooks/use-track-event.ts @@ -0,0 +1,23 @@ +import { useCallback, useContext, useRef } from "react"; +import { analyticsContext } from "../components/analytics-provider"; + +type TrackEventMap = { + "themeButton.switch": Record; +}; + +type TrackEventName = keyof TrackEventMap; + +export const useTrackEvent = () => { + const analytics = useContext(analyticsContext); + const ref = useRef(analytics); + ref.current = analytics; + + const trackEvent = useCallback( + (name: T, payload: TrackEventMap[T]) => { + ref.current?.then((a) => a.track(name, payload)); + }, + [], + ); + + return { trackEvent }; +}; diff --git a/libs/react/analytics/src/index.ts b/libs/react/analytics/src/index.ts index ffc2131a1..7e8abebb9 100644 --- a/libs/react/analytics/src/index.ts +++ b/libs/react/analytics/src/index.ts @@ -1 +1,3 @@ -export { AnalyticsProvider, useAnalytics } from "./use-analytics"; +export { AnalyticsProvider } from "./components/analytics-provider"; +export { AnalyticsPageLogger } from "./components/analytics-page-logger"; +export { useTrackEvent } from "./hooks/use-track-event"; diff --git a/libs/react/analytics/src/use-analytics.tsx b/libs/react/analytics/src/use-analytics.tsx deleted file mode 100644 index 007e8201f..000000000 --- a/libs/react/analytics/src/use-analytics.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { createContext, useContext, useState } from "react"; -import { useAnalyticsPlugin } from "./use-analytics-plugin"; -import type { - TrackEventName, - TrackEventPayload, -} from "@chair-flight/core/analytics"; -import type { AnalyticsInstance } from "analytics"; -import type { FunctionComponent, PropsWithChildren } from "react"; - -const analyticsContext = createContext>( - null as unknown as Promise, -); - -export const AnalyticsProvider: FunctionComponent = ({ - children, -}) => { - const plugin = useAnalyticsPlugin(); - const [analytics] = useState(async () => - (await import("analytics")).default({ - app: "chair-flight", - version: "1", - plugins: [plugin], - }), - ); - return ( - - {children} - - ); -}; - -export const useAnalytics = () => { - const analytics = useContext(analyticsContext); - - return { - page: () => { - if (!analytics) return; - analytics.then((a) => a.page()); - }, - - track: ( - name: T, - payload: TrackEventPayload = {}, - ) => { - if (!analytics) return; - analytics.then((a) => a.track(name, payload)); - }, - }; -}; diff --git a/libs/react/containers/src/layouts/components/app-buttons/app-buttons.tsx b/libs/react/containers/src/layouts/components/app-buttons/app-buttons.tsx index 7f0586d7b..af5080e36 100644 --- a/libs/react/containers/src/layouts/components/app-buttons/app-buttons.tsx +++ b/libs/react/containers/src/layouts/components/app-buttons/app-buttons.tsx @@ -15,7 +15,7 @@ import { Stack, } from "@mui/joy"; import { DateTime } from "luxon"; -import { useAnalytics } from "@chair-flight/react/analytics"; +import { useTrackEvent } from "@chair-flight/react/analytics"; import { useSidebar } from "@chair-flight/react/components"; import { trpc } from "@chair-flight/trpc/client"; import { useUserVoyage } from "../../../user/hooks/use-user-voyage"; @@ -53,11 +53,11 @@ export const ThemeButton: FunctionComponent = noSsr( () => { const [isMounted, setIsMounted] = useState(false); const { mode, setMode } = useColorScheme(); - const { track } = useAnalytics(); + const { trackEvent } = useTrackEvent(); const showDarkModeButton = !isMounted || mode === "light"; const toggleTheme = () => { - track("themeButton.switch"); + trackEvent("themeButton.switch", {}); setMode(mode === "dark" ? "light" : "dark"); }; diff --git a/libs/react/containers/src/layouts/hooks/use-page-transition/use-page-transition.ts b/libs/react/containers/src/layouts/hooks/use-page-transition/use-page-transition.ts index ce6d8e9b5..2be15706e 100644 --- a/libs/react/containers/src/layouts/hooks/use-page-transition/use-page-transition.ts +++ b/libs/react/containers/src/layouts/hooks/use-page-transition/use-page-transition.ts @@ -1,27 +1,12 @@ import { useEffect, useRef, useState } from "react"; import { useRouter } from "next/router"; -import { useAnalytics } from "@chair-flight/react/analytics"; export const usePageTransition = () => { - const hasMounted = useRef(false); + const [isTransitioning, setIsTransitioning] = useState(false); const router = useRouter(); - const analytics = useAnalytics(); const oldRoute = useRef(router.asPath); - const [isTransitioning, setIsTransitioning] = useState(false); oldRoute.current = router.asPath; - useEffect(() => { - if (!hasMounted.current) analytics.page(); - hasMounted.current = true; - }); - - useEffect(() => { - router.events.on("routeChangeComplete", analytics.page); - return () => { - router.events.off("routeChangeComplete", analytics.page); - }; - }, [analytics.page, router.events]); - useEffect(() => { const onStart = (e: string) => { if (e.split("?")[0] === oldRoute.current.split("?")[0]) return; diff --git a/libs/trpc/server/src/routers/common/analytics-router.ts b/libs/trpc/server/src/routers/common/analytics-router.ts index 2145a0a2c..33a840b08 100644 --- a/libs/trpc/server/src/routers/common/analytics-router.ts +++ b/libs/trpc/server/src/routers/common/analytics-router.ts @@ -1,15 +1,16 @@ import { - PageEventSchema, - TrackEventSchema, -} from "@chair-flight/core/analytics"; + pageEventSchema, + trackEventSchema, +} from "@chair-flight/providers/analytics"; import { analytics } from "../../common/providers"; import { publicProcedure, router } from "../../config/trpc"; export const analyticsRouter = router({ createPageEvent: publicProcedure - .input(PageEventSchema) + .input(pageEventSchema) .mutation(async ({ input }) => analytics.createPageEvent(input)), trackEvent: publicProcedure - .input(TrackEventSchema) + .input(trackEventSchema) .mutation(async ({ input }) => analytics.createTrackEvent(input)), + getDailyUsers: publicProcedure.query(async () => analytics.getDailyUsers()), }); diff --git a/package.json b/package.json index 45bc8a158..a4971be93 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@mui/material": "npm:@mui/joy@5.0.0-beta.25", "@mui/x-charts": "^6.19.3", "@napi-rs/image": "^1.7.0", - "@prisma/client": "^5.9.1", + "@neondatabase/serverless": "^0.8.1", "@react-three/drei": "^9.97.0", "@react-three/fiber": "^8.15.16", "@tanstack/react-query": "^4.36.1", @@ -46,8 +46,11 @@ "@trpc/next": "^10.45.0", "@trpc/react-query": "^10.45.0", "@trpc/server": "^10.45.0", + "@types/pg": "^8.11.0", "@uiw/react-textarea-code-editor": "^3.0.2", + "@vercel/postgres": "^0.7.2", "analytics": "^0.8.9", + "drizzle-orm": "^0.29.3", "immer": "^10.0.3", "konva": "^9.3.2", "luxon": "^3.4.4", @@ -120,6 +123,7 @@ "@vitest/coverage-istanbul": "^1.2.2", "@vitest/ui": "^1.2.2", "cypress": "^13.6.4", + "drizzle-kit": "^0.20.14", "env-cmd": "^10.1.0", "esbuild": "^0.20.0", "eslint": "^8.56.0", @@ -136,8 +140,8 @@ "msw-storybook-addon": "2.0.0--canary.122.b3ed3b1.0", "msw-trpc": "2.0.0-beta.0", "nx": "^18.0.1", + "pg": "^8.11.3", "prettier": "^3.2.5", - "prisma": "^5.9.1", "storybook-dark-mode": "^3.0.3", "tslib": "^2.6.2", "typescript": "^5.3.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52d86a0e3..c21c9641e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,9 +47,9 @@ dependencies: '@napi-rs/image': specifier: ^1.7.0 version: 1.7.0 - '@prisma/client': - specifier: ^5.9.1 - version: 5.9.1(prisma@5.9.1) + '@neondatabase/serverless': + specifier: ^0.8.1 + version: 0.8.1 '@react-three/drei': specifier: ^9.97.0 version: 9.97.0(@react-three/fiber@8.15.16)(@types/react@18.2.52)(@types/three@0.161.2)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0)(three@0.161.0) @@ -74,12 +74,21 @@ dependencies: '@trpc/server': specifier: ^10.45.0 version: 10.45.0 + '@types/pg': + specifier: ^8.11.0 + version: 8.11.0 '@uiw/react-textarea-code-editor': specifier: ^3.0.2 version: 3.0.2(@babel/runtime@7.23.9)(react-dom@18.2.0)(react@18.2.0) + '@vercel/postgres': + specifier: ^0.7.2 + version: 0.7.2 analytics: specifier: ^0.8.9 version: 0.8.9(@types/dlv@1.1.4) + drizzle-orm: + specifier: ^0.29.3 + version: 0.29.3(@neondatabase/serverless@0.8.1)(@types/pg@8.11.0)(@types/react@18.2.52)(@vercel/postgres@0.7.2)(pg@8.11.3)(react@18.2.0) immer: specifier: ^10.0.3 version: 10.0.3 @@ -292,6 +301,9 @@ devDependencies: cypress: specifier: ^13.6.4 version: 13.6.4 + drizzle-kit: + specifier: ^0.20.14 + version: 0.20.14 env-cmd: specifier: ^10.1.0 version: 10.1.0 @@ -340,12 +352,12 @@ devDependencies: nx: specifier: ^18.0.1 version: 18.0.1(@swc-node/register@1.8.0)(@swc/core@1.3.107) + pg: + specifier: ^8.11.3 + version: 8.11.3 prettier: specifier: ^3.2.5 version: 3.2.5 - prisma: - specifier: ^5.9.1 - version: 5.9.1 storybook-dark-mode: specifier: ^3.0.3 version: 3.0.3(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0) @@ -1917,6 +1929,12 @@ packages: engines: {node: '>=10.0.0'} dev: true + /@drizzle-team/studio@0.0.39: + resolution: {integrity: sha512-c5Hkm7MmQC2n5qAsKShjQrHoqlfGslB8+qWzsGGZ+2dHMRTNG60UuzalF0h0rvBax5uzPXuGkYLGaQ+TUX3yMw==} + dependencies: + superjson: 2.2.1 + dev: true + /@edge-runtime/cookies@3.4.1: resolution: {integrity: sha512-z27BvgPxI73CgSlxU/NAUf1Q/shnqi6cobHEowf6VuLdSjGR3NjI2Y5dZUIBbK2zOJVZbXcHsVzJjz8LklteFQ==} engines: {node: '>=16'} @@ -2074,6 +2092,20 @@ packages: resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==} dev: false + /@esbuild-kit/core-utils@3.3.2: + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + dependencies: + esbuild: 0.18.20 + source-map-support: 0.5.21 + dev: true + + /@esbuild-kit/esm-loader@2.6.5: + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.7.2 + dev: true + /@esbuild/aix-ppc64@0.19.12: resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} engines: {node: '>=12'} @@ -3689,6 +3721,18 @@ packages: '@napi-rs/image-win32-x64-msvc': 1.7.0 dev: false + /@neondatabase/serverless@0.7.2: + resolution: {integrity: sha512-wU3WA2uTyNO7wjPs3Mg0G01jztAxUxzd9/mskMmtPwPTjf7JKWi9AW5/puOGXLxmZ9PVgRFeBVRVYq5nBPhsCg==} + dependencies: + '@types/pg': 8.6.6 + dev: false + + /@neondatabase/serverless@0.8.1: + resolution: {integrity: sha512-nxZfTLbGqvDrw0W9WnQxzoPn4KC6SLjkvK4grdf6eWVMQSc24X+8udz9inZWOGu8f0O3wJAq586fCZ32r22lwg==} + dependencies: + '@types/pg': 8.6.6 + dev: false + /@next/bundle-analyzer@14.1.0: resolution: {integrity: sha512-RJWjnlMp/1WSW0ahAdawV22WgJiC6BVaFS5Xfhw6gP7NJEX3cAJjh4JqSHKGr8GnLNRaFCVTQdDPoX84E421BA==} dependencies: @@ -4969,46 +5013,6 @@ packages: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false - /@prisma/client@5.9.1(prisma@5.9.1): - resolution: {integrity: sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ==} - engines: {node: '>=16.13'} - requiresBuild: true - peerDependencies: - prisma: '*' - peerDependenciesMeta: - prisma: - optional: true - dependencies: - prisma: 5.9.1 - dev: false - - /@prisma/debug@5.9.1: - resolution: {integrity: sha512-yAHFSFCg8KVoL0oRUno3m60GAjsUKYUDkQ+9BA2X2JfVR3kRVSJFc/GpQ2fSORi4pSHZR9orfM4UC9OVXIFFTA==} - - /@prisma/engines-version@5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64: - resolution: {integrity: sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==} - - /@prisma/engines@5.9.1: - resolution: {integrity: sha512-gkdXmjxQ5jktxWNdDA5aZZ6R8rH74JkoKq6LD5mACSvxd2vbqWeWIOV0Py5wFC8vofOYShbt6XUeCIUmrOzOnQ==} - requiresBuild: true - dependencies: - '@prisma/debug': 5.9.1 - '@prisma/engines-version': 5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64 - '@prisma/fetch-engine': 5.9.1 - '@prisma/get-platform': 5.9.1 - - /@prisma/fetch-engine@5.9.1: - resolution: {integrity: sha512-l0goQOMcNVOJs1kAcwqpKq3ylvkD9F04Ioe1oJoCqmz05mw22bNAKKGWuDd3zTUoUZr97va0c/UfLNru+PDmNA==} - dependencies: - '@prisma/debug': 5.9.1 - '@prisma/engines-version': 5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64 - '@prisma/get-platform': 5.9.1 - - /@prisma/get-platform@5.9.1: - resolution: {integrity: sha512-6OQsNxTyhvG+T2Ksr8FPFpuPeL4r9u0JF0OZHUBI/Uy9SS43sPyAIutt4ZEAyqWQt104ERh70EZedkHZKsnNbg==} - dependencies: - '@prisma/debug': 5.9.1 - /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: @@ -7551,6 +7555,22 @@ packages: /@types/parse-json@4.0.2: resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + /@types/pg@8.11.0: + resolution: {integrity: sha512-sDAlRiBNthGjNFfvt0k6mtotoVYVQ63pA8R4EMWka7crawSR60waVYR0HAgmPRs/e2YaeJTD/43OoZ3PFw80pw==} + dependencies: + '@types/node': 20.11.16 + pg-protocol: 1.6.0 + pg-types: 4.0.2 + dev: false + + /@types/pg@8.6.6: + resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} + dependencies: + '@types/node': 20.11.16 + pg-protocol: 1.6.0 + pg-types: 2.2.0 + dev: false + /@types/pretty-hrtime@1.0.3: resolution: {integrity: sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==} dev: true @@ -7988,6 +8008,16 @@ packages: - supports-color dev: true + /@vercel/postgres@0.7.2: + resolution: {integrity: sha512-IqR/ZAvoPGcPaXl9eWWB5KaA+w/81RzZa/18P4izQRHpNBkTGt9HwGfYi9+wut5UgxNq4QSX9A7HIQR6QDvX2Q==} + engines: {node: '>=14.6'} + dependencies: + '@neondatabase/serverless': 0.7.2 + bufferutil: 4.0.8 + utf-8-validate: 6.0.3 + ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) + dev: false + /@vercel/python@4.1.1: resolution: {integrity: sha512-EbAdKOZ0hPd5b59tLt7R3RQK1azNvuZTrCFRAVHNjqcIHNCmrSvjag5zBGn7Memkk8qWb3+CgBw9K/3LJKei0w==} dev: true @@ -9249,6 +9279,10 @@ packages: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true + /buffer-writer@2.0.0: + resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} + engines: {node: '>=4'} + /buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} dev: true @@ -9266,6 +9300,14 @@ packages: base64-js: 1.5.1 ieee754: 1.2.1 + /bufferutil@4.0.8: + resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.8.0 + dev: false + /builtin-status-codes@3.0.0: resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} dev: true @@ -9336,6 +9378,11 @@ packages: engines: {node: '>=10'} dev: true + /camelcase@7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} + engines: {node: '>=14.16'} + dev: true + /camera-controls@2.7.4(three@0.161.0): resolution: {integrity: sha512-cW2T+eZDD0IdHTqZMRcbEZUHIqVJGnRTA1W7RRbr6Pi/LS6SL15s7w4JEe/JdPaVkbgcqPju1dUCsmFfKdop+A==} peerDependencies: @@ -9526,6 +9573,17 @@ packages: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} + /cli-color@2.0.3: + resolution: {integrity: sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==} + engines: {node: '>=0.10'} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + es6-iterator: 2.0.3 + memoizee: 0.4.15 + timers-ext: 0.1.7 + dev: true + /cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -9728,6 +9786,11 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: true + /common-path-prefix@3.0.0: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} dev: true @@ -9836,7 +9899,6 @@ packages: engines: {node: '>=12.13'} dependencies: is-what: 4.1.16 - dev: false /copy-webpack-plugin@10.2.4(webpack@5.90.1): resolution: {integrity: sha512-xFVltahqlsRcyyJqQbDY6EYTtyQZF9rf+JPjwHObLdPFMEISqkFkr7mFoVOC6BfYS/dNThyoQKvziugm+OnwBg==} @@ -10298,6 +10360,13 @@ packages: engines: {node: '>=12'} dev: false + /d@1.0.1: + resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} + dependencies: + es5-ext: 0.10.62 + type: 1.2.0 + dev: true + /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true @@ -10597,6 +10666,12 @@ packages: randombytes: 2.1.0 dev: true + /difflib@0.2.4: + resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} + dependencies: + heap: 0.2.7 + dev: true + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -10730,6 +10805,114 @@ packages: resolution: {integrity: sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==} dev: false + /dreamopt@0.8.0: + resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==} + engines: {node: '>=0.4.0'} + dependencies: + wordwrap: 1.0.0 + dev: true + + /drizzle-kit@0.20.14: + resolution: {integrity: sha512-0fHv3YIEaUcSVPSGyaaBfOi9bmpajjhbJNdPsRMIUvYdLVxBu9eGjH8mRc3Qk7HVmEidFc/lhG1YyJhoXrn5yA==} + hasBin: true + dependencies: + '@drizzle-team/studio': 0.0.39 + '@esbuild-kit/esm-loader': 2.6.5 + camelcase: 7.0.1 + chalk: 5.3.0 + commander: 9.5.0 + env-paths: 3.0.0 + esbuild: 0.19.12 + esbuild-register: 3.5.0(esbuild@0.19.12) + glob: 8.1.0 + hanji: 0.0.5 + json-diff: 0.9.0 + minimatch: 7.4.6 + semver: 7.5.4 + zod: 3.22.4 + transitivePeerDependencies: + - supports-color + dev: true + + /drizzle-orm@0.29.3(@neondatabase/serverless@0.8.1)(@types/pg@8.11.0)(@types/react@18.2.52)(@vercel/postgres@0.7.2)(pg@8.11.3)(react@18.2.0): + resolution: {integrity: sha512-uSE027csliGSGYD0pqtM+SAQATMREb3eSM/U8s6r+Y0RFwTKwftnwwSkqx3oS65UBgqDOM0gMTl5UGNpt6lW0A==} + peerDependencies: + '@aws-sdk/client-rds-data': '>=3' + '@cloudflare/workers-types': '>=3' + '@libsql/client': '*' + '@neondatabase/serverless': '>=0.1' + '@opentelemetry/api': ^1.4.1 + '@planetscale/database': '>=1' + '@types/better-sqlite3': '*' + '@types/pg': '*' + '@types/react': '>=18' + '@types/sql.js': '*' + '@vercel/postgres': '*' + better-sqlite3: '>=7' + bun-types: '*' + expo-sqlite: '>=13.2.0' + knex: '*' + kysely: '*' + mysql2: '>=2' + pg: '>=8' + postgres: '>=3' + react: '>=18' + sql.js: '>=1' + sqlite3: '>=5' + peerDependenciesMeta: + '@aws-sdk/client-rds-data': + optional: true + '@cloudflare/workers-types': + optional: true + '@libsql/client': + optional: true + '@neondatabase/serverless': + optional: true + '@opentelemetry/api': + optional: true + '@planetscale/database': + optional: true + '@types/better-sqlite3': + optional: true + '@types/pg': + optional: true + '@types/react': + optional: true + '@types/sql.js': + optional: true + '@vercel/postgres': + optional: true + better-sqlite3: + optional: true + bun-types: + optional: true + expo-sqlite: + optional: true + knex: + optional: true + kysely: + optional: true + mysql2: + optional: true + pg: + optional: true + postgres: + optional: true + react: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + dependencies: + '@neondatabase/serverless': 0.8.1 + '@types/pg': 8.11.0 + '@types/react': 18.2.52 + '@vercel/postgres': 0.7.2 + pg: 8.11.3 + react: 18.2.0 + dev: false + /duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} dev: true @@ -10881,6 +11064,11 @@ packages: cross-spawn: 7.0.3 dev: true + /env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /errno@0.1.8: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true @@ -11012,6 +11200,40 @@ packages: is-symbol: 1.0.4 dev: true + /es5-ext@0.10.62: + resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} + engines: {node: '>=0.10'} + requiresBuild: true + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.3 + next-tick: 1.1.0 + dev: true + + /es6-iterator@2.0.3: + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + es6-symbol: 3.1.3 + dev: true + + /es6-symbol@3.1.3: + resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} + dependencies: + d: 1.0.1 + ext: 1.7.0 + dev: true + + /es6-weak-map@2.0.3: + resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + es6-iterator: 2.0.3 + es6-symbol: 3.1.3 + dev: true + /esbuild-android-64@0.14.47: resolution: {integrity: sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==} engines: {node: '>=12'} @@ -11171,6 +11393,17 @@ packages: - supports-color dev: true + /esbuild-register@3.5.0(esbuild@0.19.12): + resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} + peerDependencies: + esbuild: '>=0.12 <1' + dependencies: + debug: 4.3.4(supports-color@8.1.1) + esbuild: 0.19.12 + transitivePeerDependencies: + - supports-color + dev: true + /esbuild-sunos-64@0.14.47: resolution: {integrity: sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==} engines: {node: '>=12'} @@ -11716,6 +11949,13 @@ packages: engines: {node: '>= 0.6'} dev: true + /event-emitter@0.3.5: + resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + dev: true + /event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -11876,6 +12116,12 @@ packages: - supports-color dev: true + /ext@1.7.0: + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + dependencies: + type: 2.7.2 + dev: true + /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -12495,6 +12741,17 @@ packages: path-is-absolute: 1.0.1 dev: true + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: true + /global-dirs@3.0.1: resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} engines: {node: '>=10'} @@ -12594,6 +12851,13 @@ packages: uglify-js: 3.17.4 dev: true + /hanji@0.0.5: + resolution: {integrity: sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==} + dependencies: + lodash.throttle: 4.1.1 + sisteransi: 1.0.5 + dev: true + /harmony-reflect@1.6.2: resolution: {integrity: sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==} dev: true @@ -12872,6 +13136,10 @@ packages: resolution: {integrity: sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw==} dev: true + /heap@0.2.7: + resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} + dev: true + /hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} dependencies: @@ -13551,6 +13819,10 @@ packages: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: true + /is-promise@2.2.2: + resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + dev: true + /is-reference@3.0.2: resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} dependencies: @@ -13639,7 +13911,6 @@ packages: /is-what@4.1.16: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} - dev: false /is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} @@ -14202,6 +14473,15 @@ packages: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true + /json-diff@0.9.0: + resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==} + hasBin: true + dependencies: + cli-color: 2.0.3 + difflib: 0.2.4 + dreamopt: 0.8.0 + dev: true + /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -14607,6 +14887,10 @@ packages: /lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + /lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + dev: true + /lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} dev: true @@ -14680,6 +14964,12 @@ packages: dependencies: yallist: 4.0.0 + /lru-queue@0.1.0: + resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} + dependencies: + es5-ext: 0.10.62 + dev: true + /luxon@3.4.4: resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==} engines: {node: '>=12'} @@ -15018,6 +15308,19 @@ packages: fs-monkey: 1.0.5 dev: true + /memoizee@0.4.15: + resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + es6-weak-map: 2.0.3 + event-emitter: 0.3.5 + is-promise: 2.2.2 + lru-queue: 0.1.0 + next-tick: 1.1.0 + timers-ext: 0.1.7 + dev: true + /memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} dependencies: @@ -15494,6 +15797,13 @@ packages: brace-expansion: 2.0.1 dev: true + /minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -15697,6 +16007,10 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: true + /next-tick@1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + dev: true + /next@14.1.0(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==} engines: {node: '>=18.17.0'} @@ -15801,7 +16115,6 @@ packages: /node-gyp-build@4.8.0: resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} hasBin: true - dev: true /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -16062,7 +16375,6 @@ packages: /obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - dev: true /octokit@3.1.2: resolution: {integrity: sha512-MG5qmrTL5y8KYwFgE1A4JWmgfQBaIETE/lOlfwNYx1QOtCQHGVxkRJmdUJltFc1HVn73d61TlMhMyNTOtMl+ng==} @@ -16268,6 +16580,9 @@ packages: engines: {node: '>=6'} dev: true + /packet-reader@1.0.0: + resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} + /pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} dev: true @@ -16459,6 +16774,80 @@ packages: is-reference: 3.0.2 dev: false + /pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + requiresBuild: true + optional: true + + /pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + + /pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + /pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + dev: false + + /pg-pool@3.6.1(pg@8.11.3): + resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} + peerDependencies: + pg: '>=8.0' + dependencies: + pg: 8.11.3 + + /pg-protocol@1.6.0: + resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} + + /pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + /pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + dev: false + + /pg@8.11.3: + resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + dependencies: + buffer-writer: 2.0.0 + packet-reader: 1.0.0 + pg-connection-string: 2.6.2 + pg-pool: 3.6.1(pg@8.11.3) + pg-protocol: 1.6.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + + /pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + dependencies: + split2: 4.2.0 + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -16940,6 +17329,50 @@ packages: source-map-js: 1.0.2 dev: true + /postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + /postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + dev: false + + /postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + /postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + dependencies: + obuf: 1.1.2 + dev: false + + /postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + /postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + dev: false + + /postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + dependencies: + xtend: 4.0.2 + + /postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + dev: false + + /postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + dev: false + /potpack@1.0.2: resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} dev: false @@ -17016,14 +17449,6 @@ packages: parse-ms: 2.1.0 dev: true - /prisma@5.9.1: - resolution: {integrity: sha512-Hy/8KJZz0ELtkw4FnG9MS9rNWlXcJhf98Z2QMqi0QiVMoS8PzsBkpla0/Y5hTlob8F3HeECYphBjqmBxrluUrQ==} - engines: {node: '>=16.13'} - hasBin: true - requiresBuild: true - dependencies: - '@prisma/engines': 5.9.1 - /proc-log@3.0.0: resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -18592,6 +19017,10 @@ packages: - supports-color dev: true + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -19009,7 +19438,6 @@ packages: engines: {node: '>=16'} dependencies: copy-anything: 3.0.5 - dev: false /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} @@ -19252,6 +19680,13 @@ packages: setimmediate: 1.0.5 dev: true + /timers-ext@0.1.7: + resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==} + dependencies: + es5-ext: 0.10.62 + next-tick: 1.1.0 + dev: true + /tiny-invariant@1.3.1: resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} @@ -19633,6 +20068,14 @@ packages: mime-types: 2.1.35 dev: true + /type@1.2.0: + resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} + dev: true + + /type@2.7.2: + resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} + dev: true + /typed-array-buffer@1.0.0: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} engines: {node: '>= 0.4'} @@ -20059,6 +20502,14 @@ packages: react: 18.2.0 dev: false + /utf-8-validate@6.0.3: + resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.8.0 + dev: false + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true @@ -20828,6 +21279,22 @@ packages: optional: true dev: true + /ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3): + resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.3 + dev: false + /ws@8.16.0: resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} engines: {node: '>=10.0.0'} @@ -20881,7 +21348,6 @@ packages: /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - dev: true /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} @@ -20960,7 +21426,6 @@ packages: /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - dev: false /zustand@3.7.2(react@18.2.0): resolution: {integrity: sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==} diff --git a/tsconfig.base.json b/tsconfig.base.json index e56a8df74..f7742ef39 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -30,7 +30,6 @@ "@chair-flight/base/env": ["libs/base/env/src/index.ts"], "@chair-flight/base/errors": ["libs/base/errors/src/index.ts"], "@chair-flight/base/utils": ["libs/base/utils/src/index.ts"], - "@chair-flight/core/analytics": ["libs/core/analytics/src/index.ts"], "@chair-flight/core/blog": ["libs/core/blog/src/index.ts"], "@chair-flight/core/github": ["libs/core/github/src/index.ts"], "@chair-flight/core/question-bank": ["libs/core/question-bank/src/index.ts"], From 2bf795d3ce00b459c761f94f4ca8be07cca6d9f8 Mon Sep 17 00:00:00 2001 From: Pedro Pupo Sa da Costa Date: Fri, 9 Feb 2024 15:02:17 +0000 Subject: [PATCH 3/3] chore: review deps --- package.json | 3 +-- pnpm-lock.yaml | 28 +++++----------------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index a4971be93..92e5501e9 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "@mui/material": "npm:@mui/joy@5.0.0-beta.25", "@mui/x-charts": "^6.19.3", "@napi-rs/image": "^1.7.0", - "@neondatabase/serverless": "^0.8.1", "@react-three/drei": "^9.97.0", "@react-three/fiber": "^8.15.16", "@tanstack/react-query": "^4.36.1", @@ -46,7 +45,6 @@ "@trpc/next": "^10.45.0", "@trpc/react-query": "^10.45.0", "@trpc/server": "^10.45.0", - "@types/pg": "^8.11.0", "@uiw/react-textarea-code-editor": "^3.0.2", "@vercel/postgres": "^0.7.2", "analytics": "^0.8.9", @@ -114,6 +112,7 @@ "@trivago/prettier-plugin-sort-imports": "4.1.0", "@types/luxon": "^3.4.2", "@types/node": "^20.11.16", + "@types/pg": "^8.11.0", "@types/react": "^18.2.52", "@types/react-dom": "^18.2.18", "@types/three": "^0.161.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c21c9641e..f2923d5e8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,9 +47,6 @@ dependencies: '@napi-rs/image': specifier: ^1.7.0 version: 1.7.0 - '@neondatabase/serverless': - specifier: ^0.8.1 - version: 0.8.1 '@react-three/drei': specifier: ^9.97.0 version: 9.97.0(@react-three/fiber@8.15.16)(@types/react@18.2.52)(@types/three@0.161.2)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0)(three@0.161.0) @@ -74,9 +71,6 @@ dependencies: '@trpc/server': specifier: ^10.45.0 version: 10.45.0 - '@types/pg': - specifier: ^8.11.0 - version: 8.11.0 '@uiw/react-textarea-code-editor': specifier: ^3.0.2 version: 3.0.2(@babel/runtime@7.23.9)(react-dom@18.2.0)(react@18.2.0) @@ -88,7 +82,7 @@ dependencies: version: 0.8.9(@types/dlv@1.1.4) drizzle-orm: specifier: ^0.29.3 - version: 0.29.3(@neondatabase/serverless@0.8.1)(@types/pg@8.11.0)(@types/react@18.2.52)(@vercel/postgres@0.7.2)(pg@8.11.3)(react@18.2.0) + version: 0.29.3(@types/pg@8.11.0)(@types/react@18.2.52)(@vercel/postgres@0.7.2)(pg@8.11.3)(react@18.2.0) immer: specifier: ^10.0.3 version: 10.0.3 @@ -274,6 +268,9 @@ devDependencies: '@types/node': specifier: ^20.11.16 version: 20.11.16 + '@types/pg': + specifier: ^8.11.0 + version: 8.11.0 '@types/react': specifier: ^18.2.52 version: 18.2.52 @@ -3727,12 +3724,6 @@ packages: '@types/pg': 8.6.6 dev: false - /@neondatabase/serverless@0.8.1: - resolution: {integrity: sha512-nxZfTLbGqvDrw0W9WnQxzoPn4KC6SLjkvK4grdf6eWVMQSc24X+8udz9inZWOGu8f0O3wJAq586fCZ32r22lwg==} - dependencies: - '@types/pg': 8.6.6 - dev: false - /@next/bundle-analyzer@14.1.0: resolution: {integrity: sha512-RJWjnlMp/1WSW0ahAdawV22WgJiC6BVaFS5Xfhw6gP7NJEX3cAJjh4JqSHKGr8GnLNRaFCVTQdDPoX84E421BA==} dependencies: @@ -7561,7 +7552,6 @@ packages: '@types/node': 20.11.16 pg-protocol: 1.6.0 pg-types: 4.0.2 - dev: false /@types/pg@8.6.6: resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} @@ -10834,7 +10824,7 @@ packages: - supports-color dev: true - /drizzle-orm@0.29.3(@neondatabase/serverless@0.8.1)(@types/pg@8.11.0)(@types/react@18.2.52)(@vercel/postgres@0.7.2)(pg@8.11.3)(react@18.2.0): + /drizzle-orm@0.29.3(@types/pg@8.11.0)(@types/react@18.2.52)(@vercel/postgres@0.7.2)(pg@8.11.3)(react@18.2.0): resolution: {integrity: sha512-uSE027csliGSGYD0pqtM+SAQATMREb3eSM/U8s6r+Y0RFwTKwftnwwSkqx3oS65UBgqDOM0gMTl5UGNpt6lW0A==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' @@ -10905,7 +10895,6 @@ packages: sqlite3: optional: true dependencies: - '@neondatabase/serverless': 0.8.1 '@types/pg': 8.11.0 '@types/react': 18.2.52 '@vercel/postgres': 0.7.2 @@ -16789,7 +16778,6 @@ packages: /pg-numeric@1.0.2: resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} engines: {node: '>=4'} - dev: false /pg-pool@3.6.1(pg@8.11.3): resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} @@ -16822,7 +16810,6 @@ packages: postgres-date: 2.1.0 postgres-interval: 3.0.0 postgres-range: 1.1.4 - dev: false /pg@8.11.3: resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} @@ -17336,7 +17323,6 @@ packages: /postgres-array@3.0.2: resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} engines: {node: '>=12'} - dev: false /postgres-bytea@1.0.0: resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} @@ -17347,7 +17333,6 @@ packages: engines: {node: '>= 6'} dependencies: obuf: 1.1.2 - dev: false /postgres-date@1.0.7: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} @@ -17356,7 +17341,6 @@ packages: /postgres-date@2.1.0: resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} engines: {node: '>=12'} - dev: false /postgres-interval@1.2.0: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} @@ -17367,11 +17351,9 @@ packages: /postgres-interval@3.0.0: resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} engines: {node: '>=12'} - dev: false /postgres-range@1.1.4: resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} - dev: false /potpack@1.0.2: resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==}