From e820d6dd7e731decade044bbec0de7fdd7b954b4 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Wed, 24 Jan 2024 19:05:28 +0500 Subject: [PATCH 01/22] Add metadata field to AnalyticsEventBase and make error a js Error --- packages/analytics/src/index.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index c917cfc5..1208c05e 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -14,6 +14,7 @@ export type AnalyticsEventBase = { | "ProtocolInstalled" | "AppSetup" | "Error"; + metadata?: Record; }; export type AnalyticsEvent = AnalyticsEventBase & { @@ -23,17 +24,11 @@ export type AnalyticsEvent = AnalyticsEventBase & { | "InterviewStarted" | "ProtocolInstalled" | "AppSetup"; - metadata?: Record; }; export type AnalyticsError = AnalyticsEventBase & { type: "Error"; - error: { - message: string; - details: string; - stacktrace: string; - path: string; - }; + error: Error; }; export type AnalyticsEventOrError = AnalyticsEvent | AnalyticsError; From c65d246cb09c9e3dc9207bb12d13b0eac08156a8 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Thu, 25 Jan 2024 12:59:59 +0500 Subject: [PATCH 02/22] remove unused imports in ErrorsTable and add error details and path to database --- .../app/_components/errors/ErrorsTable/ErrorsTable.tsx | 1 - apps/analytics/app/api/event/route.ts | 10 +++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/analytics/app/_components/errors/ErrorsTable/ErrorsTable.tsx b/apps/analytics/app/_components/errors/ErrorsTable/ErrorsTable.tsx index 449e07d9..80fd958c 100644 --- a/apps/analytics/app/_components/errors/ErrorsTable/ErrorsTable.tsx +++ b/apps/analytics/app/_components/errors/ErrorsTable/ErrorsTable.tsx @@ -2,7 +2,6 @@ import { DataTable } from "~/components/DataTable/data-table"; import getErrors from "~/db/getErrors"; import { columns } from "./Columns"; import ExportButton from "~/components/ExportButton"; -import { Card, CardHeader, CardContent } from "~/components/ui/card"; export default async function ErrorsTable() { const errors = await getErrors(); diff --git a/apps/analytics/app/api/event/route.ts b/apps/analytics/app/api/event/route.ts index efc7f23d..92066d0f 100644 --- a/apps/analytics/app/api/event/route.ts +++ b/apps/analytics/app/api/event/route.ts @@ -18,8 +18,16 @@ export async function POST(request: NextRequest) { // determine if this is an error and push it to the errors table if (event.type === "Error") { const errorPayload = event.error; + const errorDetails = event.metadata?.details; + const errorPath = event.metadata?.path; try { - await sql`INSERT INTO Errors (message, details, stacktrace, timestamp, installationid, path) VALUES (${errorPayload.message}, ${errorPayload.details}, ${errorPayload.stacktrace}, ${timestamp}, ${event.installationId}, ${errorPayload.path});`; + await sql`INSERT INTO Errors (message, details, stacktrace, timestamp, installationid, path) VALUES (${ + errorPayload.message + }, ${errorDetails ? JSON.stringify(errorDetails) : null}, ${ + errorPayload.stack + }, ${timestamp}, ${event.installationId}, ${ + errorPath ? JSON.stringify(errorPath) : null + });`; return NextResponse.json( { errorPayload }, { status: 200, headers: corsHeaders } From 06efaf3f38431824deff5b9a29b0b123f9eaf112 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Thu, 25 Jan 2024 14:34:21 +0500 Subject: [PATCH 03/22] remove console logs from createRouteHandler function --- packages/analytics/src/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index 1208c05e..b105f6ae 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -109,9 +109,6 @@ export const createRouteHandler = ({ ); } - console.info(`🚀 Analytics event forwarded successfully.`); - console.info(JSON.stringify(dispatchableEvent, null, 2)); - return new Response( JSON.stringify({ message: "Event forwarded successfully" }), { From db3b0f9478c81d3110d27c891a6e4ca9796e1d0c Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Thu, 25 Jan 2024 15:38:42 +0500 Subject: [PATCH 04/22] wip: add AnalyticsEventExtensible --- apps/analytics/app/api/event/route.ts | 2 +- packages/analytics/src/index.ts | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/apps/analytics/app/api/event/route.ts b/apps/analytics/app/api/event/route.ts index 92066d0f..2807fca0 100644 --- a/apps/analytics/app/api/event/route.ts +++ b/apps/analytics/app/api/event/route.ts @@ -1,6 +1,6 @@ import { NextRequest, NextResponse } from "next/server"; import { sql } from "@vercel/postgres"; -import type { DispatchableAnalyticsEvent } from "@codaco/analytics"; +import { DispatchableAnalyticsEvent } from "../../../packages/analytics/src"; //Todo: fix this import path const corsHeaders = { "Access-Control-Allow-Origin": "*", diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index b105f6ae..ac9a64d0 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -6,32 +6,30 @@ type GeoLocation = { countryCode: string; }; -export type AnalyticsEventBase = { - type: - | "DataExported" - | "InterviewCompleted" - | "InterviewStarted" - | "ProtocolInstalled" - | "AppSetup" - | "Error"; +export type AnalyticsEventExtensible = { + type: string; metadata?: Record; }; -export type AnalyticsEvent = AnalyticsEventBase & { +export type AnalyticsEvent = { type: | "InterviewCompleted" | "DataExported" | "InterviewStarted" | "ProtocolInstalled" | "AppSetup"; + metadata?: Record; }; -export type AnalyticsError = AnalyticsEventBase & { +export type AnalyticsError = { type: "Error"; error: Error; + metadata?: Record; }; -export type AnalyticsEventOrError = AnalyticsEvent | AnalyticsError; +export type AnalyticsMainEvent = AnalyticsEvent | AnalyticsEventExtensible; + +export type AnalyticsEventOrError = AnalyticsMainEvent | AnalyticsError; export type AnalyticsEventOrErrorWithTimestamp = AnalyticsEventOrError & { timestamp: Date; From e6a67dabf3091289771579afd5c79c1bbc8c1d18 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Thu, 25 Jan 2024 15:56:02 +0500 Subject: [PATCH 05/22] remove AnalyticsEventExtensible --- apps/analytics/app/api/event/route.ts | 2 +- packages/analytics/src/index.ts | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/analytics/app/api/event/route.ts b/apps/analytics/app/api/event/route.ts index 2807fca0..92066d0f 100644 --- a/apps/analytics/app/api/event/route.ts +++ b/apps/analytics/app/api/event/route.ts @@ -1,6 +1,6 @@ import { NextRequest, NextResponse } from "next/server"; import { sql } from "@vercel/postgres"; -import { DispatchableAnalyticsEvent } from "../../../packages/analytics/src"; //Todo: fix this import path +import type { DispatchableAnalyticsEvent } from "@codaco/analytics"; const corsHeaders = { "Access-Control-Allow-Origin": "*", diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index ac9a64d0..b105f6ae 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -6,30 +6,32 @@ type GeoLocation = { countryCode: string; }; -export type AnalyticsEventExtensible = { - type: string; +export type AnalyticsEventBase = { + type: + | "DataExported" + | "InterviewCompleted" + | "InterviewStarted" + | "ProtocolInstalled" + | "AppSetup" + | "Error"; metadata?: Record; }; -export type AnalyticsEvent = { +export type AnalyticsEvent = AnalyticsEventBase & { type: | "InterviewCompleted" | "DataExported" | "InterviewStarted" | "ProtocolInstalled" | "AppSetup"; - metadata?: Record; }; -export type AnalyticsError = { +export type AnalyticsError = AnalyticsEventBase & { type: "Error"; error: Error; - metadata?: Record; }; -export type AnalyticsMainEvent = AnalyticsEvent | AnalyticsEventExtensible; - -export type AnalyticsEventOrError = AnalyticsMainEvent | AnalyticsError; +export type AnalyticsEventOrError = AnalyticsEvent | AnalyticsError; export type AnalyticsEventOrErrorWithTimestamp = AnalyticsEventOrError & { timestamp: Date; From a1ac5084e7c212c763dfd3d1bcc432d29673be94 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Thu, 25 Jan 2024 16:05:53 +0500 Subject: [PATCH 06/22] Update version to 3.0.0 in analytics package.json --- packages/analytics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 98f7fb26..7122209a 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -1,6 +1,6 @@ { "name": "@codaco/analytics", - "version": "2.1.1", + "version": "3.0.0", "module": "./dist/index.mjs", "types": "./dist/index.d.mts", "author": "Complex Data Collective ", From 60f94b624ba9c2ba55b9936b9a6d441a890ca4b8 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Thu, 25 Jan 2024 21:01:06 +0500 Subject: [PATCH 07/22] wip: trying to integrate drizzle --- apps/analytics/drizzle.config.ts | 16 + apps/analytics/drizzle/0000_known_menace.sql | 13 + .../analytics/drizzle/meta/0000_snapshot.json | 87 +++ apps/analytics/drizzle/meta/_journal.json | 13 + apps/analytics/lib/config.ts | 5 + apps/analytics/lib/db.ts | 6 + apps/analytics/lib/schema.ts | 22 + apps/analytics/package.json | 2 + apps/analytics/scripts/getEvent.ts | 13 + apps/analytics/scripts/migrate.ts | 15 + apps/analytics/scripts/seed.ts | 76 ++ apps/analytics/tsconfig.json | 25 +- pnpm-lock.yaml | 667 +++++++++++++++++- 13 files changed, 920 insertions(+), 40 deletions(-) create mode 100644 apps/analytics/drizzle.config.ts create mode 100644 apps/analytics/drizzle/0000_known_menace.sql create mode 100644 apps/analytics/drizzle/meta/0000_snapshot.json create mode 100644 apps/analytics/drizzle/meta/_journal.json create mode 100644 apps/analytics/lib/config.ts create mode 100644 apps/analytics/lib/db.ts create mode 100644 apps/analytics/lib/schema.ts create mode 100644 apps/analytics/scripts/getEvent.ts create mode 100644 apps/analytics/scripts/migrate.ts create mode 100644 apps/analytics/scripts/seed.ts diff --git a/apps/analytics/drizzle.config.ts b/apps/analytics/drizzle.config.ts new file mode 100644 index 00000000..4b7a8f39 --- /dev/null +++ b/apps/analytics/drizzle.config.ts @@ -0,0 +1,16 @@ +import "~/lib/config"; +import dotenv from "dotenv"; +import { defineConfig } from "drizzle-kit"; + +dotenv.config(); + +export default defineConfig({ + schema: "./lib/schema.ts", + out: "./drizzle", + driver: "pg", + dbCredentials: { + connectionString: process.env.POSTGRES_URL!, + }, + verbose: true, + strict: true, +}); diff --git a/apps/analytics/drizzle/0000_known_menace.sql b/apps/analytics/drizzle/0000_known_menace.sql new file mode 100644 index 00000000..48cc044c --- /dev/null +++ b/apps/analytics/drizzle/0000_known_menace.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS "events" ( + "id" serial PRIMARY KEY NOT NULL, + "type" text NOT NULL, + "installationId" text NOT NULL, + "timestamp" text NOT NULL, + "isocode" text, + "message" text, + "name" text, + "stack" text, + "metadata" json +); +--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "unique_idx" ON "events" ("id"); \ No newline at end of file diff --git a/apps/analytics/drizzle/meta/0000_snapshot.json b/apps/analytics/drizzle/meta/0000_snapshot.json new file mode 100644 index 00000000..2c740cc3 --- /dev/null +++ b/apps/analytics/drizzle/meta/0000_snapshot.json @@ -0,0 +1,87 @@ +{ + "id": "94097300-298d-42a1-9333-f2973dd0e898", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "5", + "dialect": "pg", + "tables": { + "events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "installationId": { + "name": "installationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isocode": { + "name": "isocode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stack": { + "name": "stack", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "unique_idx": { + "name": "unique_idx", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/analytics/drizzle/meta/_journal.json b/apps/analytics/drizzle/meta/_journal.json new file mode 100644 index 00000000..dcee72ce --- /dev/null +++ b/apps/analytics/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "5", + "dialect": "pg", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1706192371067, + "tag": "0000_known_menace", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/apps/analytics/lib/config.ts b/apps/analytics/lib/config.ts new file mode 100644 index 00000000..b56adbcb --- /dev/null +++ b/apps/analytics/lib/config.ts @@ -0,0 +1,5 @@ +import dotenv from "dotenv"; +import { join } from "node:path"; + +const envPath = join(process.cwd(), ".env"); +dotenv.config({ path: envPath }); diff --git a/apps/analytics/lib/db.ts b/apps/analytics/lib/db.ts new file mode 100644 index 00000000..42ffaaa6 --- /dev/null +++ b/apps/analytics/lib/db.ts @@ -0,0 +1,6 @@ +import { sql } from "@vercel/postgres"; +import { drizzle } from "drizzle-orm/vercel-postgres"; +import * as schema from "./schema"; + +// Use this object to send drizzle queries to your DB +export const db = drizzle(sql, { schema }); diff --git a/apps/analytics/lib/schema.ts b/apps/analytics/lib/schema.ts new file mode 100644 index 00000000..ea02ff34 --- /dev/null +++ b/apps/analytics/lib/schema.ts @@ -0,0 +1,22 @@ +import { json, pgTable, serial, text, uniqueIndex } from "drizzle-orm/pg-core"; + +// Create a pgTable that maps to a table in your DB +export const events = pgTable( + "events", + { + id: serial("id").primaryKey(), + type: text("type").notNull(), + installationId: text("installationId").notNull(), + timestamp: text("timestamp").notNull(), + isocode: text("isocode"), + message: text("message"), + name: text("name"), + stack: text("stack"), + metadata: json("metadata"), + }, + (events) => { + return { + uniqueIdx: uniqueIndex("unique_idx").on(events.id), + }; + } +); diff --git a/apps/analytics/package.json b/apps/analytics/package.json index 45dd0029..db32abf8 100644 --- a/apps/analytics/package.json +++ b/apps/analytics/package.json @@ -25,6 +25,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "dotenv": "^16.3.1", + "drizzle-orm": "^0.29.3", "i18n-iso-countries": "^7.7.0", "lucide-react": "^0.292.0", "next": "14.0.1", @@ -41,6 +42,7 @@ "@types/papaparse": "^5.3.14", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", + "drizzle-kit": "^0.20.13", "eslint-config-custom": "workspace:*", "tailwindcss": "^3.3.0", "tsconfig": "workspace:*", diff --git a/apps/analytics/scripts/getEvent.ts b/apps/analytics/scripts/getEvent.ts new file mode 100644 index 00000000..21dd1508 --- /dev/null +++ b/apps/analytics/scripts/getEvent.ts @@ -0,0 +1,13 @@ +import dotenv from "dotenv"; +dotenv.config(); + +import { db } from "~/lib/db"; +import { events } from "~/lib/schema"; + +async function getEvent() { + const result = await db.select().from(events); + + console.log("Events: ", result); +} + +getEvent(); diff --git a/apps/analytics/scripts/migrate.ts b/apps/analytics/scripts/migrate.ts new file mode 100644 index 00000000..704e91fe --- /dev/null +++ b/apps/analytics/scripts/migrate.ts @@ -0,0 +1,15 @@ +import dotenv from "dotenv"; +dotenv.config(); + +import { migrate } from "drizzle-orm/vercel-postgres/migrator"; +import { db } from "~/lib/db"; + +export async function runMigration() { + try { + await migrate(db, { migrationsFolder: "./drizzle" }); + } catch (error) { + console.error("Error running migration:", error); + } +} + +runMigration(); diff --git a/apps/analytics/scripts/seed.ts b/apps/analytics/scripts/seed.ts new file mode 100644 index 00000000..cd66f643 --- /dev/null +++ b/apps/analytics/scripts/seed.ts @@ -0,0 +1,76 @@ +import dotenv from "dotenv"; +dotenv.config(); + +import { db } from "~/lib/db"; +import { events } from "~/lib/schema"; +import { faker } from "@faker-js/faker"; +import { sql } from "@vercel/postgres"; + +type Event = typeof events.$inferInsert; + +let installationIds: string[] = []; +for (let i = 0; i < 20; i++) { + installationIds.push(faker.string.uuid()); +} + +const eventTypes = [ + "AppSetup", + "ProtocolInstalled", + "InterviewStarted", + "InterviewCompleted", + "InterviewCompleted", + "DataExported", + "Error", +]; + +async function seedEvents() { + console.info("Starting to seed events"); + + try { + for (let i = 0; i < 100; i++) { + const type = faker.helpers.arrayElement(eventTypes); + const installationId = faker.helpers.arrayElement(installationIds); + const timestamp = faker.date.recent().toDateString(); + const metadata = { + details: faker.lorem.sentence(), + path: faker.lorem.sentence(), + }; + const isocode = faker.location.countryCode(); + const message = faker.lorem.sentence(); + const name = faker.lorem.sentence(); + const stack = faker.lorem.sentence(); + + const event: Event = { + type, + metadata, + timestamp, + installationId, + isocode, + message, + name, + stack, + }; + + await db.insert(events).values(event).returning(); + } + } catch (error) { + console.error("Error seeding events", error); + } + + process.exit(); +} + +async function checkTables() { + const result = await sql` + SELECT table_name + FROM information_schema.tables + WHERE table_schema='public' + AND table_type='BASE TABLE'; + `; + + console.log(result.rows); +} + +(async () => { + await seedEvents(); +})(); diff --git a/apps/analytics/tsconfig.json b/apps/analytics/tsconfig.json index 2c9ff0a7..0084eb9a 100644 --- a/apps/analytics/tsconfig.json +++ b/apps/analytics/tsconfig.json @@ -1,12 +1,8 @@ { "extends": "tsconfig/nextjs.json", "compilerOptions": { - "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "target": "ES6", + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -17,18 +13,9 @@ "resolveJsonModule": true, "isolatedModules": true, "paths": { - "~/*": [ - "./*" - ] + "~/*": ["./*"] } }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d7c65f2..b37be21e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,7 +26,7 @@ importers: version: link:packages/tsconfig turbo: specifier: latest - version: 1.10.16 + version: 1.11.3 apps/analytics: dependencies: @@ -75,6 +75,9 @@ importers: dotenv: specifier: ^16.3.1 version: 16.3.1 + drizzle-orm: + specifier: ^0.29.3 + version: 0.29.3(@types/react@18.2.14)(@vercel/postgres@0.5.1)(react@18.2.0) i18n-iso-countries: specifier: ^7.7.0 version: 7.7.0 @@ -118,6 +121,9 @@ importers: '@types/react-dom': specifier: ^18.2.6 version: 18.2.6 + drizzle-kit: + specifier: ^0.20.13 + version: 0.20.13 eslint-config-custom: specifier: workspace:* version: link:../../packages/eslint-config-custom @@ -665,6 +671,35 @@ packages: csstype: 3.1.1 dev: false + /@drizzle-team/studio@0.0.39: + resolution: {integrity: sha512-c5Hkm7MmQC2n5qAsKShjQrHoqlfGslB8+qWzsGGZ+2dHMRTNG60UuzalF0h0rvBax5uzPXuGkYLGaQ+TUX3yMw==} + dependencies: + superjson: 2.2.1 + dev: true + + /@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'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -674,6 +709,15 @@ packages: dev: true optional: true + /@esbuild/android-arm64@0.19.12: + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.18.20: resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} @@ -683,6 +727,15 @@ packages: dev: true optional: true + /@esbuild/android-arm@0.19.12: + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.18.20: resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} @@ -692,6 +745,15 @@ packages: dev: true optional: true + /@esbuild/android-x64@0.19.12: + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.18.20: resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} @@ -701,6 +763,15 @@ packages: dev: true optional: true + /@esbuild/darwin-arm64@0.19.12: + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.18.20: resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} @@ -710,6 +781,15 @@ packages: dev: true optional: true + /@esbuild/darwin-x64@0.19.12: + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.18.20: resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} @@ -719,6 +799,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-arm64@0.19.12: + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.18.20: resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} @@ -728,6 +817,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-x64@0.19.12: + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.18.20: resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} @@ -737,6 +835,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm64@0.19.12: + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.18.20: resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} @@ -746,6 +853,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm@0.19.12: + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.18.20: resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} @@ -755,6 +871,15 @@ packages: dev: true optional: true + /@esbuild/linux-ia32@0.19.12: + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.18.20: resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} @@ -764,6 +889,15 @@ packages: dev: true optional: true + /@esbuild/linux-loong64@0.19.12: + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.18.20: resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} @@ -773,6 +907,15 @@ packages: dev: true optional: true + /@esbuild/linux-mips64el@0.19.12: + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.18.20: resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} @@ -782,6 +925,15 @@ packages: dev: true optional: true + /@esbuild/linux-ppc64@0.19.12: + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-riscv64@0.18.20: resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} @@ -791,6 +943,15 @@ packages: dev: true optional: true + /@esbuild/linux-riscv64@0.19.12: + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-s390x@0.18.20: resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} @@ -800,6 +961,15 @@ packages: dev: true optional: true + /@esbuild/linux-s390x@0.19.12: + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.18.20: resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} @@ -809,6 +979,15 @@ packages: dev: true optional: true + /@esbuild/linux-x64@0.19.12: + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.18.20: resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} @@ -818,6 +997,15 @@ packages: dev: true optional: true + /@esbuild/netbsd-x64@0.19.12: + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.18.20: resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} @@ -827,6 +1015,15 @@ packages: dev: true optional: true + /@esbuild/openbsd-x64@0.19.12: + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.18.20: resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} @@ -836,6 +1033,15 @@ packages: dev: true optional: true + /@esbuild/sunos-x64@0.19.12: + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.18.20: resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} @@ -845,6 +1051,15 @@ packages: dev: true optional: true + /@esbuild/win32-arm64@0.19.12: + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.18.20: resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} @@ -854,6 +1069,15 @@ packages: dev: true optional: true + /@esbuild/win32-ia32@0.19.12: + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.18.20: resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} @@ -863,6 +1087,15 @@ packages: dev: true optional: true + /@esbuild/win32-x64@0.19.12: + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.48.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2592,6 +2825,12 @@ packages: balanced-match: 1.0.2 concat-map: 0.0.1 + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -2614,6 +2853,10 @@ packages: node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.10) + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + /bufferutil@4.0.8: resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} engines: {node: '>=6.14.2'} @@ -2685,6 +2928,11 @@ packages: engines: {node: '>=6'} dev: false + /camelcase@7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} + engines: {node: '>=14.16'} + dev: true + /caniuse-lite@1.0.30001562: resolution: {integrity: sha512-kfte3Hym//51EdX4239i+Rmp20EsLIYGdPkERegTgU19hQWCRhsRFGKHTliUlsry53tv17K7n077Kqa0WJU4ng==} @@ -2703,6 +2951,11 @@ packages: ansi-styles: 4.3.0 supports-color: 7.2.0 + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + /chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: false @@ -2738,6 +2991,17 @@ packages: escape-string-regexp: 1.0.5 dev: true + /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 + /client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} dev: false @@ -2797,6 +3061,11 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: true + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -2809,6 +3078,13 @@ packages: engines: {node: '>= 0.6'} dev: false + /copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + dependencies: + is-what: 4.1.16 + dev: true + /core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} dev: false @@ -2868,6 +3144,13 @@ packages: stream-transform: 2.1.3 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 @@ -3007,6 +3290,12 @@ packages: /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + /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'} @@ -3047,6 +3336,111 @@ packages: engines: {node: '>=12'} 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.13: + resolution: {integrity: sha512-j9oZSQXNWG+KBJm0Sg3S/zJpncHGKnpqNfFuM4NUxUMGTcihDHhP9SW6Jncqwb5vsP1Xm0a8JLm3PZUIspC/oA==} + 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(@types/react@18.2.14)(@vercel/postgres@0.5.1)(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: + '@types/react': 18.2.14 + '@vercel/postgres': 0.5.1 + react: 18.2.0 + dev: false + /electron-to-chromium@1.4.498: resolution: {integrity: sha512-4LODxAzKGVy7CJyhhN5mebwe7U2L29P+0G+HUriHnabm0d7LSff8Yn7t+Wq+2/9ze2Fu1dhX7mww090xfv7qXQ==} @@ -3074,6 +3468,11 @@ packages: strip-ansi: 6.0.1 dev: false + /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 + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -3177,6 +3576,51 @@ packages: is-date-object: 1.0.5 is-symbol: 1.0.4 + /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-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 + esbuild: 0.19.12 + transitivePeerDependencies: + - supports-color + dev: true + /esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} @@ -3207,6 +3651,37 @@ packages: '@esbuild/win32-x64': 0.18.20 dev: true + /esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 + dev: true + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -3836,6 +4311,13 @@ packages: engines: {node: '>=0.10.0'} 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 + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -3866,6 +4348,12 @@ packages: strip-final-newline: 3.0.0 dev: true + /ext@1.7.0: + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + dependencies: + type: 2.7.2 + dev: true + /extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} dev: false @@ -4072,6 +4560,12 @@ packages: resolution: {integrity: sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==} dev: true + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + /git-hooks-list@3.1.0: resolution: {integrity: sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==} dev: true @@ -4124,6 +4618,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 + /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -4187,6 +4692,13 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 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 + /hard-rejection@2.1.0: resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} @@ -4228,6 +4740,10 @@ packages: dependencies: function-bind: 1.1.1 + /heap@0.2.7: + resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} + dev: true + /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -4463,6 +4979,10 @@ packages: engines: {node: '>=12'} dev: true + /is-promise@2.2.2: + resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + dev: true + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -4534,6 +5054,11 @@ packages: get-intrinsic: 1.2.1 dev: true + /is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + dev: true + /is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -4614,6 +5139,15 @@ packages: hasBin: true 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==} @@ -4740,6 +5274,10 @@ packages: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} dev: false + /lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + dev: true + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true @@ -4774,6 +5312,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 + /lucide-react@0.292.0(react@18.2.0): resolution: {integrity: sha512-rRgUkpEHWpa5VCT66YscInCQmQuPCB1RFRzkkxMxg4b+jaL0V12E3riWWR2Sh5OIiUhCwGW/ZExuEO4Az32E6Q==} peerDependencies: @@ -4800,6 +5344,19 @@ packages: tiny-lru: 11.2.5 dev: false + /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 + /meow@6.1.1: resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==} engines: {node: '>=8'} @@ -4863,6 +5420,20 @@ packages: dependencies: brace-expansion: 1.1.11 + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + 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 + /minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} engines: {node: '>= 6'} @@ -4910,6 +5481,10 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /next-tick@1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + dev: true + /next@14.0.1(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-s4YaLpE4b0gmb3ggtmpmV+wt+lPRuGtANzojMQ2+gmBpgX9w5fTbjsy6dXByBuENsdCX5pukZH/GxdFgO62+pA==} engines: {node: '>=18.17.0'} @@ -5597,6 +6172,10 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + /resolve@1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} dependencies: @@ -5731,6 +6310,10 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: true + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -5798,6 +6381,18 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + /source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} @@ -5957,6 +6552,13 @@ packages: pirates: 4.0.6 ts-interface-checker: 0.1.13 + /superjson@2.2.1: + resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} + engines: {node: '>=16'} + dependencies: + copy-anything: 3.0.5 + dev: true + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -6059,6 +6661,13 @@ packages: dependencies: any-promise: 1.3.0 + /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-lru@11.2.5: resolution: {integrity: sha512-JpqM0K33lG6iQGKiigcwuURAKZlq6rHXfrgeL4/I8/REoyJTGU+tEMszvT/oTRVHG2OiylhGDjqPp1jWMlr3bw==} engines: {node: '>=12'} @@ -6220,64 +6829,64 @@ packages: yargs: 17.7.2 dev: false - /turbo-darwin-64@1.10.16: - resolution: {integrity: sha512-+Jk91FNcp9e9NCLYlvDDlp2HwEDp14F9N42IoW3dmHI5ZkGSXzalbhVcrx3DOox3QfiNUHxzWg4d7CnVNCuuMg==} + /turbo-darwin-64@1.11.3: + resolution: {integrity: sha512-IsOOg2bVbIt3o/X8Ew9fbQp5t1hTHN3fGNQYrPQwMR2W1kIAC6RfbVD4A9OeibPGyEPUpwOH79hZ9ydFH5kifw==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-darwin-arm64@1.10.16: - resolution: {integrity: sha512-jqGpFZipIivkRp/i+jnL8npX0VssE6IAVNKtu573LXtssZdV/S+fRGYA16tI46xJGxSAivrZ/IcgZrV6Jk80bw==} + /turbo-darwin-arm64@1.11.3: + resolution: {integrity: sha512-FsJL7k0SaPbJzI/KCnrf/fi3PgCDCjTliMc/kEFkuWVA6Httc3Q4lxyLIIinz69q6JTx8wzh6yznUMzJRI3+dg==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-linux-64@1.10.16: - resolution: {integrity: sha512-PpqEZHwLoizQ6sTUvmImcRmACyRk9EWLXGlqceogPZsJ1jTRK3sfcF9fC2W56zkSIzuLEP07k5kl+ZxJd8JMcg==} + /turbo-linux-64@1.11.3: + resolution: {integrity: sha512-SvW7pvTVRGsqtSkII5w+wriZXvxqkluw5FO/MNAdFw0qmoov+PZ237+37/NgArqE3zVn1GX9P6nUx9VO+xcQAg==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-linux-arm64@1.10.16: - resolution: {integrity: sha512-TMjFYz8to1QE0fKVXCIvG/4giyfnmqcQIwjdNfJvKjBxn22PpbjeuFuQ5kNXshUTRaTJihFbuuCcb5OYFNx4uw==} + /turbo-linux-arm64@1.11.3: + resolution: {integrity: sha512-YhUfBi1deB3m+3M55X458J6B7RsIS7UtM3P1z13cUIhF+pOt65BgnaSnkHLwETidmhRh8Dl3GelaQGrB3RdCDw==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-windows-64@1.10.16: - resolution: {integrity: sha512-+jsf68krs0N66FfC4/zZvioUap/Tq3sPFumnMV+EBo8jFdqs4yehd6+MxIwYTjSQLIcpH8KoNMB0gQYhJRLZzw==} + /turbo-windows-64@1.11.3: + resolution: {integrity: sha512-s+vEnuM2TiZuAUUUpmBHDr6vnNbJgj+5JYfnYmVklYs16kXh+EppafYQOAkcRIMAh7GjV3pLq5/uGqc7seZeHA==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /turbo-windows-arm64@1.10.16: - resolution: {integrity: sha512-sKm3hcMM1bl0B3PLG4ifidicOGfoJmOEacM5JtgBkYM48ncMHjkHfFY7HrJHZHUnXM4l05RQTpLFoOl/uIo2HQ==} + /turbo-windows-arm64@1.11.3: + resolution: {integrity: sha512-ZR5z5Zpc7cASwfdRAV5yNScCZBsgGSbcwiA/u3farCacbPiXsfoWUkz28iyrx21/TRW0bi6dbsB2v17swa8bjw==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /turbo@1.10.16: - resolution: {integrity: sha512-2CEaK4FIuSZiP83iFa9GqMTQhroW2QryckVqUydmg4tx78baftTOS0O+oDAhvo9r9Nit4xUEtC1RAHoqs6ZEtg==} + /turbo@1.11.3: + resolution: {integrity: sha512-RCJOUFcFMQNIGKSjC9YmA5yVP1qtDiBA0Lv9VIgrXraI5Da1liVvl3VJPsoDNIR9eFMyA/aagx1iyj6UWem5hA==} hasBin: true optionalDependencies: - turbo-darwin-64: 1.10.16 - turbo-darwin-arm64: 1.10.16 - turbo-linux-64: 1.10.16 - turbo-linux-arm64: 1.10.16 - turbo-windows-64: 1.10.16 - turbo-windows-arm64: 1.10.16 + turbo-darwin-64: 1.11.3 + turbo-darwin-arm64: 1.11.3 + turbo-linux-64: 1.11.3 + turbo-linux-arm64: 1.11.3 + turbo-windows-64: 1.11.3 + turbo-windows-arm64: 1.11.3 dev: true /type-check@0.4.0: @@ -6310,6 +6919,14 @@ packages: engines: {node: '>=12.20'} dev: false + /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'} @@ -6563,6 +7180,10 @@ packages: isexe: 2.0.0 dev: true + /wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + dev: true + /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -6675,3 +7296,7 @@ packages: /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + + /zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + dev: true From 13e63a1c89c6f94066158e81ebbbfab4ef39b57e Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Fri, 26 Jan 2024 16:01:20 +0500 Subject: [PATCH 08/22] integrate Drizzle and update dashboard --- .../analytics/EventsTable/Columns.tsx | 14 ++- .../analytics/EventsTable/EventsTable.tsx | 3 +- .../errors/ErrorsTable/Columns.tsx | 38 ++++--- .../errors/ErrorsTable/StackTraceDialog.tsx | 8 +- apps/analytics/app/api/event/route.ts | 54 ++++----- apps/analytics/app/layout.tsx | 4 +- apps/analytics/app/page.tsx | 4 +- apps/analytics/components/ExportButton.tsx | 6 +- .../MetadataDialog.tsx | 5 +- apps/analytics/{lib => db}/db.ts | 3 + apps/analytics/db/getErrors.ts | 22 ++-- apps/analytics/db/getEvents.ts | 27 +++-- apps/analytics/db/insertEvent.ts | 16 +++ apps/analytics/db/schema.ts | 45 +++++--- apps/analytics/db/seed.js | 103 ------------------ apps/analytics/drizzle.config.ts | 7 +- ...enace.sql => 0000_yellow_the_watchers.sql} | 2 +- .../analytics/drizzle/meta/0000_snapshot.json | 4 +- apps/analytics/drizzle/meta/_journal.json | 4 +- apps/analytics/lib/config.ts | 5 - apps/analytics/lib/schema.ts | 22 ---- apps/analytics/package.json | 4 +- apps/analytics/scripts/getEvent.ts | 13 --- apps/analytics/scripts/migrate.ts | 2 +- apps/analytics/scripts/seed.ts | 25 +---- apps/analytics/utils/getRegionsTotals.ts | 3 +- 26 files changed, 165 insertions(+), 278 deletions(-) rename apps/analytics/{app/_components/analytics/EventsTable => components}/MetadataDialog.tsx (58%) rename apps/analytics/{lib => db}/db.ts (68%) create mode 100644 apps/analytics/db/insertEvent.ts delete mode 100644 apps/analytics/db/seed.js rename apps/analytics/drizzle/{0000_known_menace.sql => 0000_yellow_the_watchers.sql} (90%) delete mode 100644 apps/analytics/lib/config.ts delete mode 100644 apps/analytics/lib/schema.ts delete mode 100644 apps/analytics/scripts/getEvent.ts diff --git a/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx b/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx index 425dec0d..e7210900 100644 --- a/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx +++ b/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx @@ -1,8 +1,10 @@ "use client"; -import { DataTableColumnHeader } from "~/components/DataTable/column-header"; + import { ColumnDef } from "@tanstack/react-table"; -import type { Event } from "~/db/schema"; -import { MetadataDialog } from "./MetadataDialog"; +import { DataTableColumnHeader } from "~/components/DataTable/column-header"; +import { MetadataDialog } from "~/components/MetadataDialog"; +import type { Event } from "~/db/getEvents"; + export const columns: ColumnDef[] = [ { accessorKey: "type", @@ -17,16 +19,16 @@ export const columns: ColumnDef[] = [ ), }, { - accessorKey: "installationid", + accessorKey: "installationId", header: ({ column }) => ( ), cell: ({ row }) => { - return
{row.original.installationid}
; + return
{row.original.installationId}
; }, }, { - accessorKey: "stacktrace", + accessorKey: "metadata", header: "", cell: ({ row }) => { return ( diff --git a/apps/analytics/app/_components/analytics/EventsTable/EventsTable.tsx b/apps/analytics/app/_components/analytics/EventsTable/EventsTable.tsx index b0c2766c..cd8b25c6 100644 --- a/apps/analytics/app/_components/analytics/EventsTable/EventsTable.tsx +++ b/apps/analytics/app/_components/analytics/EventsTable/EventsTable.tsx @@ -1,9 +1,8 @@ // EventsTable.tsx -import React from "react"; import { DataTable } from "~/components/DataTable/data-table"; +import ExportButton from "~/components/ExportButton"; import getEvents from "~/db/getEvents"; import { columns } from "./Columns"; -import ExportButton from "~/components/ExportButton"; export default async function EventsTable() { const events = await getEvents(); diff --git a/apps/analytics/app/_components/errors/ErrorsTable/Columns.tsx b/apps/analytics/app/_components/errors/ErrorsTable/Columns.tsx index accb6b11..26f265df 100644 --- a/apps/analytics/app/_components/errors/ErrorsTable/Columns.tsx +++ b/apps/analytics/app/_components/errors/ErrorsTable/Columns.tsx @@ -1,29 +1,26 @@ "use client"; -import { DataTableColumnHeader } from "~/components/DataTable/column-header"; + import { ColumnDef } from "@tanstack/react-table"; -import { Error } from "~/db/schema"; import { StackTraceDialog } from "~/app/_components/errors/ErrorsTable/StackTraceDialog"; -export const columns: ColumnDef[] = [ - { - accessorKey: "message", - header: ({ column }) => ( - - ), - }, +import { DataTableColumnHeader } from "~/components/DataTable/column-header"; +import { MetadataDialog } from "~/components/MetadataDialog"; +import { type ErrorEvent } from "~/db/getErrors"; + +export const columns: ColumnDef[] = [ { - accessorKey: "details", + accessorKey: "name", header: ({ column }) => ( - + ), }, { - accessorKey: "path", + accessorKey: "message", header: ({ column }) => ( - + ), }, { - accessorKey: "installationid", + accessorKey: "installationId", header: ({ column }) => ( ), @@ -35,7 +32,7 @@ export const columns: ColumnDef[] = [ ), }, { - accessorKey: "stacktrace", + accessorKey: "stack", header: "", cell: ({ row }) => { return ( @@ -45,4 +42,15 @@ export const columns: ColumnDef[] = [ ); }, }, + { + accessorKey: "metadata", + header: "", + cell: ({ row }) => { + return ( +
+ +
+ ); + }, + }, ]; diff --git a/apps/analytics/app/_components/errors/ErrorsTable/StackTraceDialog.tsx b/apps/analytics/app/_components/errors/ErrorsTable/StackTraceDialog.tsx index 8245f1f5..e3e063e8 100644 --- a/apps/analytics/app/_components/errors/ErrorsTable/StackTraceDialog.tsx +++ b/apps/analytics/app/_components/errors/ErrorsTable/StackTraceDialog.tsx @@ -1,13 +1,13 @@ import { DialogButton } from "~/components/DialogButton"; -import type { Error } from "~/db/schema"; +import { type ErrorEvent } from "~/db/getErrors"; -export function StackTraceDialog({ error }: { error: Error }) { +export function StackTraceDialog({ error }: { error: ErrorEvent }) { return ( ); } diff --git a/apps/analytics/app/api/event/route.ts b/apps/analytics/app/api/event/route.ts index 92066d0f..292637d7 100644 --- a/apps/analytics/app/api/event/route.ts +++ b/apps/analytics/app/api/event/route.ts @@ -1,6 +1,7 @@ +import { type DispatchableAnalyticsEvent } from "@codaco/analytics"; import { NextRequest, NextResponse } from "next/server"; -import { sql } from "@vercel/postgres"; -import type { DispatchableAnalyticsEvent } from "@codaco/analytics"; +import { type EventInsertType } from "~/db/db"; +import insertEvent from "~/db/insertEvent"; const corsHeaders = { "Access-Control-Allow-Origin": "*", @@ -13,44 +14,27 @@ export const runtime = "edge"; export async function POST(request: NextRequest) { const event = (await request.json()) as DispatchableAnalyticsEvent; - const timestamp = JSON.stringify(event.timestamp || new Date().toISOString()); + let generalEvent: EventInsertType = { + type: event.type, + metadata: event.metadata, + timestamp: event.timestamp, + installationId: event.installationId, + isocode: event.geolocation?.countryCode, + }; - // determine if this is an error and push it to the errors table if (event.type === "Error") { - const errorPayload = event.error; - const errorDetails = event.metadata?.details; - const errorPath = event.metadata?.path; - try { - await sql`INSERT INTO Errors (message, details, stacktrace, timestamp, installationid, path) VALUES (${ - errorPayload.message - }, ${errorDetails ? JSON.stringify(errorDetails) : null}, ${ - errorPayload.stack - }, ${timestamp}, ${event.installationId}, ${ - errorPath ? JSON.stringify(errorPath) : null - });`; - return NextResponse.json( - { errorPayload }, - { status: 200, headers: corsHeaders } - ); - } catch (error) { - return NextResponse.json( - { error }, - { status: 500, headers: corsHeaders } - ); - } + generalEvent = { + ...generalEvent, + message: event.error.message, + name: event.error.name, + stack: event.error.stack, + }; } - // event is not an error - // push the event to the events table - try { - await sql`INSERT INTO EVENTS (type, metadata, timestamp, installationid, isocode) VALUES( - ${event.type}, - ${JSON.stringify(event.metadata)}, - ${timestamp}, - ${event.installationId}, - ${event.geolocation?.countryCode} - );`; + const result = await insertEvent(generalEvent); + if (result.error) throw new Error(result.error); + return NextResponse.json({ event }, { status: 200, headers: corsHeaders }); } catch (error) { return NextResponse.json({ error }, { status: 500, headers: corsHeaders }); diff --git a/apps/analytics/app/layout.tsx b/apps/analytics/app/layout.tsx index 28e0e802..821e92c8 100644 --- a/apps/analytics/app/layout.tsx +++ b/apps/analytics/app/layout.tsx @@ -6,8 +6,8 @@ import { ClerkProvider } from "@clerk/nextjs"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Fresco Analytics ", + description: "This is the analytics dashboard for Fresco.", }; export default function RootLayout({ diff --git a/apps/analytics/app/page.tsx b/apps/analytics/app/page.tsx index f327d961..57e5fde4 100644 --- a/apps/analytics/app/page.tsx +++ b/apps/analytics/app/page.tsx @@ -1,7 +1,7 @@ -import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"; +import { UserButton } from "@clerk/nextjs"; import AnalyticsView from "~/app/_components/analytics/AnalyticsView"; import ErrorsView from "~/app/_components/errors/ErrorsView"; -import { UserButton } from "@clerk/nextjs"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"; import UserManagementDialog from "./_components/users/UserManagementDialog"; export default function DashboardPage() { diff --git a/apps/analytics/components/ExportButton.tsx b/apps/analytics/components/ExportButton.tsx index 10018ed6..130cde30 100644 --- a/apps/analytics/components/ExportButton.tsx +++ b/apps/analytics/components/ExportButton.tsx @@ -1,11 +1,13 @@ "use client"; -import type { Event, Error } from "~/db/schema"; + import Papa from "papaparse"; import { Button } from "~/components/ui/button"; import { Download } from "lucide-react"; +import { type Event } from "~/db/getEvents"; +import { type ErrorEvent } from "~/db/getErrors"; interface ExportButtonProps { - data: (Event | Error)[]; + data: (Event | ErrorEvent)[]; filename: string; } diff --git a/apps/analytics/app/_components/analytics/EventsTable/MetadataDialog.tsx b/apps/analytics/components/MetadataDialog.tsx similarity index 58% rename from apps/analytics/app/_components/analytics/EventsTable/MetadataDialog.tsx rename to apps/analytics/components/MetadataDialog.tsx index 5553df0e..ded6bdd6 100644 --- a/apps/analytics/app/_components/analytics/EventsTable/MetadataDialog.tsx +++ b/apps/analytics/components/MetadataDialog.tsx @@ -1,7 +1,8 @@ import { DialogButton } from "~/components/DialogButton"; -import type { Event } from "~/db/schema"; +import { type ErrorEvent } from "~/db/getErrors"; +import { type Event } from "~/db/getEvents"; -export function MetadataDialog({ event }: { event: Event }) { +export function MetadataDialog({ event }: { event: Event | ErrorEvent }) { return ( eq(events.type, "Error"), + orderBy: (events, { desc }) => [desc(events.timestamp)], + }); - // sort by timestamp to display errros in order of most recent first - errors.rows.sort((a, b) => { - return b.timestamp - a.timestamp; - }); - return errors.rows as Error[]; + return errorEvents; + } catch (error) { + console.error("Error getting events", error); + return []; + } } + +type ErrorEvents = Awaited>; +export type ErrorEvent = ErrorEvents[0]; diff --git a/apps/analytics/db/getEvents.ts b/apps/analytics/db/getEvents.ts index 8dc95754..027a9a17 100644 --- a/apps/analytics/db/getEvents.ts +++ b/apps/analytics/db/getEvents.ts @@ -1,12 +1,23 @@ -import { sql } from "@vercel/postgres"; -import type { Event } from "~/db/schema"; +import { db } from "./db"; export default async function getEvents() { - const events = await sql`SELECT * FROM Events ;`; + try { + const events = await db.query.eventsTable.findMany({ + where: (events, { ne }) => ne(events.type, "Error"), + orderBy: (events, { desc }) => [desc(events.timestamp)], + columns: { + name: false, + message: false, + stack: false, + }, + }); - // sort by timestamp to display events in order of most recent first - events.rows.sort((a, b) => { - return b.timestamp - a.timestamp; - }); - return events.rows as Event[]; + return events; + } catch (error) { + console.error("Error getting events", error); + return []; + } } + +type Events = Awaited>; +export type Event = Events[0]; diff --git a/apps/analytics/db/insertEvent.ts b/apps/analytics/db/insertEvent.ts new file mode 100644 index 00000000..0461eda8 --- /dev/null +++ b/apps/analytics/db/insertEvent.ts @@ -0,0 +1,16 @@ +import { type EventInsertType, db } from "./db"; +import { eventsTable } from "~/db/schema"; + +export default async function insertEvent(event: EventInsertType) { + try { + const insertedEvent = await db + .insert(eventsTable) + .values(event) + .returning(); + + return { data: insertedEvent, error: null }; + } catch (error) { + console.error("Error getting events", error); + return { data: null, error: "Error getting events" }; + } +} diff --git a/apps/analytics/db/schema.ts b/apps/analytics/db/schema.ts index 2de8b521..ac16d764 100644 --- a/apps/analytics/db/schema.ts +++ b/apps/analytics/db/schema.ts @@ -1,18 +1,29 @@ -// Postgres database schema +import { + json, + pgTable, + serial, + text, + uniqueIndex, + timestamp, +} from "drizzle-orm/pg-core"; -export interface Event { - type: string; - metadata: string; - timestamp: string; - installationid: string; - isocode: string; -} - -export interface Error { - message: string; - details: string; - stacktrace: string; - timestamp: string; - installationid: string; - path: string; -} +// Create a pgTable that maps to a table in your DB +export const eventsTable = pgTable( + "events", + { + id: serial("id").primaryKey(), + type: text("type").notNull(), + installationId: text("installationId").notNull(), + timestamp: timestamp("timestamp").notNull(), + isocode: text("isocode"), + message: text("message"), + name: text("name"), + stack: text("stack"), + metadata: json("metadata"), + }, + (events) => { + return { + uniqueIdx: uniqueIndex("unique_idx").on(events.id), + }; + } +); diff --git a/apps/analytics/db/seed.js b/apps/analytics/db/seed.js deleted file mode 100644 index f89d207e..00000000 --- a/apps/analytics/db/seed.js +++ /dev/null @@ -1,103 +0,0 @@ -const { sql } = require("@vercel/postgres"); -const { faker } = require("@faker-js/faker"); - -let installationids = []; -for (let i = 0; i < 20; i++) { - installationids.push(faker.string.uuid()); -} - -async function dropTables() { - try { - await sql` - DROP TABLE IF EXISTS Events; - `; - await sql` - DROP TABLE IF EXISTS Errors; - `; - } catch (error) { - console.error("Error dropping tables:", error); - } -} - -async function seedEvents() { - const eventTypes = [ - "AppSetup", - "ProtocolInstalled", - "InterviewStarted", - "InterviewCompleted", - "InterviewCompleted", - ]; - - try { - await sql` - CREATE TABLE IF NOT EXISTS Events ( - type varchar, - metadata varchar, - timestamp timestamp, - installationid varchar, - isocode varchar - ); - `; - for (let i = 0; i < 100; i++) { - const type = faker.helpers.arrayElement(eventTypes); - const installationid = faker.helpers.arrayElement(installationids); - const timestamp = faker.date.recent(); - const metadata = { - [faker.lorem.word()]: faker.lorem.sentence(), - [faker.lorem.word()]: faker.lorem.sentence(), - }; - - await sql` - INSERT INTO Events (type, metadata, timestamp, installationid, isocode) - VALUES (${type}, ${metadata}, ${timestamp}, ${installationid}, ${faker.location.countryCode()}); - `; - } - } catch (error) { - console.error("Error seeding data:", error); - } -} - -async function seedErrors() { - const messages = [ - "Database connection error", - "Database query error: Invalid syntax", - "Database query error: Invalid column name", - "Page not found", - "Internal server error", - "Authentication Failure", - "File Upload Error: Invalid file type", - ]; - try { - await sql` - CREATE TABLE IF NOT EXISTS Errors ( - message varchar, - details varchar, - stacktrace varchar, - timestamp timestamp, - installationid varchar, - path varchar - ); - `; - for (let i = 0; i < 100; i++) { - const message = faker.helpers.arrayElement(messages); - const details = faker.lorem.paragraph(); - const stacktrace = faker.lorem.lines(); - const installationid = faker.helpers.arrayElement(installationids); - const path = faker.system.directoryPath(); - const timestamp = faker.date.recent(); - - await sql` - INSERT INTO Errors (message, details, stacktrace, timestamp, installationid, path) - VALUES (${message}, ${details}, ${stacktrace}, ${timestamp}, ${installationid}, ${path}); - `; - } - } catch (error) { - console.error("Error seeding data:", error); - } -} - -(async () => { - await dropTables(); - await seedEvents(); - await seedErrors(); -})(); diff --git a/apps/analytics/drizzle.config.ts b/apps/analytics/drizzle.config.ts index 4b7a8f39..20d27380 100644 --- a/apps/analytics/drizzle.config.ts +++ b/apps/analytics/drizzle.config.ts @@ -1,11 +1,10 @@ -import "~/lib/config"; import dotenv from "dotenv"; -import { defineConfig } from "drizzle-kit"; - dotenv.config(); +import { defineConfig } from "drizzle-kit"; + export default defineConfig({ - schema: "./lib/schema.ts", + schema: "./db/schema.ts", out: "./drizzle", driver: "pg", dbCredentials: { diff --git a/apps/analytics/drizzle/0000_known_menace.sql b/apps/analytics/drizzle/0000_yellow_the_watchers.sql similarity index 90% rename from apps/analytics/drizzle/0000_known_menace.sql rename to apps/analytics/drizzle/0000_yellow_the_watchers.sql index 48cc044c..fbc2c0ff 100644 --- a/apps/analytics/drizzle/0000_known_menace.sql +++ b/apps/analytics/drizzle/0000_yellow_the_watchers.sql @@ -2,7 +2,7 @@ CREATE TABLE IF NOT EXISTS "events" ( "id" serial PRIMARY KEY NOT NULL, "type" text NOT NULL, "installationId" text NOT NULL, - "timestamp" text NOT NULL, + "timestamp" timestamp NOT NULL, "isocode" text, "message" text, "name" text, diff --git a/apps/analytics/drizzle/meta/0000_snapshot.json b/apps/analytics/drizzle/meta/0000_snapshot.json index 2c740cc3..857f0bc0 100644 --- a/apps/analytics/drizzle/meta/0000_snapshot.json +++ b/apps/analytics/drizzle/meta/0000_snapshot.json @@ -1,5 +1,5 @@ { - "id": "94097300-298d-42a1-9333-f2973dd0e898", + "id": "8314d6f3-51e8-44a2-a9ec-d3128c1a7775", "prevId": "00000000-0000-0000-0000-000000000000", "version": "5", "dialect": "pg", @@ -28,7 +28,7 @@ }, "timestamp": { "name": "timestamp", - "type": "text", + "type": "timestamp", "primaryKey": false, "notNull": true }, diff --git a/apps/analytics/drizzle/meta/_journal.json b/apps/analytics/drizzle/meta/_journal.json index dcee72ce..1382ce18 100644 --- a/apps/analytics/drizzle/meta/_journal.json +++ b/apps/analytics/drizzle/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "5", - "when": 1706192371067, - "tag": "0000_known_menace", + "when": 1706248816583, + "tag": "0000_yellow_the_watchers", "breakpoints": true } ] diff --git a/apps/analytics/lib/config.ts b/apps/analytics/lib/config.ts deleted file mode 100644 index b56adbcb..00000000 --- a/apps/analytics/lib/config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import dotenv from "dotenv"; -import { join } from "node:path"; - -const envPath = join(process.cwd(), ".env"); -dotenv.config({ path: envPath }); diff --git a/apps/analytics/lib/schema.ts b/apps/analytics/lib/schema.ts deleted file mode 100644 index ea02ff34..00000000 --- a/apps/analytics/lib/schema.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { json, pgTable, serial, text, uniqueIndex } from "drizzle-orm/pg-core"; - -// Create a pgTable that maps to a table in your DB -export const events = pgTable( - "events", - { - id: serial("id").primaryKey(), - type: text("type").notNull(), - installationId: text("installationId").notNull(), - timestamp: text("timestamp").notNull(), - isocode: text("isocode"), - message: text("message"), - name: text("name"), - stack: text("stack"), - metadata: json("metadata"), - }, - (events) => { - return { - uniqueIdx: uniqueIndex("unique_idx").on(events.id), - }; - } -); diff --git a/apps/analytics/package.json b/apps/analytics/package.json index db32abf8..ed8e1b49 100644 --- a/apps/analytics/package.json +++ b/apps/analytics/package.json @@ -7,7 +7,9 @@ "build": "next build", "start": "next start", "lint": "next lint", - "seed": "node -r dotenv/config ./db/seed.js" + "generate": "npx drizzle-kit generate:pg", + "migrate": "npx tsx scripts/migrate.ts", + "seed": "pnpm run generate && pnpm run migrate && npx tsx scripts/seed.ts" }, "dependencies": { "@clerk/nextjs": "^4.26.2", diff --git a/apps/analytics/scripts/getEvent.ts b/apps/analytics/scripts/getEvent.ts deleted file mode 100644 index 21dd1508..00000000 --- a/apps/analytics/scripts/getEvent.ts +++ /dev/null @@ -1,13 +0,0 @@ -import dotenv from "dotenv"; -dotenv.config(); - -import { db } from "~/lib/db"; -import { events } from "~/lib/schema"; - -async function getEvent() { - const result = await db.select().from(events); - - console.log("Events: ", result); -} - -getEvent(); diff --git a/apps/analytics/scripts/migrate.ts b/apps/analytics/scripts/migrate.ts index 704e91fe..b15e3e3f 100644 --- a/apps/analytics/scripts/migrate.ts +++ b/apps/analytics/scripts/migrate.ts @@ -2,7 +2,7 @@ import dotenv from "dotenv"; dotenv.config(); import { migrate } from "drizzle-orm/vercel-postgres/migrator"; -import { db } from "~/lib/db"; +import { db } from "~/db/db"; export async function runMigration() { try { diff --git a/apps/analytics/scripts/seed.ts b/apps/analytics/scripts/seed.ts index cd66f643..46d467be 100644 --- a/apps/analytics/scripts/seed.ts +++ b/apps/analytics/scripts/seed.ts @@ -1,12 +1,10 @@ import dotenv from "dotenv"; dotenv.config(); -import { db } from "~/lib/db"; -import { events } from "~/lib/schema"; import { faker } from "@faker-js/faker"; -import { sql } from "@vercel/postgres"; - -type Event = typeof events.$inferInsert; +import { db } from "~/db/db"; +import { eventsTable } from "~/db/schema"; +import { type EventInsertType } from "~/db/db"; let installationIds: string[] = []; for (let i = 0; i < 20; i++) { @@ -30,7 +28,7 @@ async function seedEvents() { for (let i = 0; i < 100; i++) { const type = faker.helpers.arrayElement(eventTypes); const installationId = faker.helpers.arrayElement(installationIds); - const timestamp = faker.date.recent().toDateString(); + const timestamp = faker.date.recent(); const metadata = { details: faker.lorem.sentence(), path: faker.lorem.sentence(), @@ -40,7 +38,7 @@ async function seedEvents() { const name = faker.lorem.sentence(); const stack = faker.lorem.sentence(); - const event: Event = { + const event: EventInsertType = { type, metadata, timestamp, @@ -51,7 +49,7 @@ async function seedEvents() { stack, }; - await db.insert(events).values(event).returning(); + await db.insert(eventsTable).values(event).returning(); } } catch (error) { console.error("Error seeding events", error); @@ -60,17 +58,6 @@ async function seedEvents() { process.exit(); } -async function checkTables() { - const result = await sql` - SELECT table_name - FROM information_schema.tables - WHERE table_schema='public' - AND table_type='BASE TABLE'; - `; - - console.log(result.rows); -} - (async () => { await seedEvents(); })(); diff --git a/apps/analytics/utils/getRegionsTotals.ts b/apps/analytics/utils/getRegionsTotals.ts index 049183b3..4c8ba304 100644 --- a/apps/analytics/utils/getRegionsTotals.ts +++ b/apps/analytics/utils/getRegionsTotals.ts @@ -1,5 +1,4 @@ -import { Event } from "~/db/schema"; -import getEvents from "~/db/getEvents"; +import getEvents, { type Event } from "~/db/getEvents"; export type RegionTotal = { country: string; From de1de4e9bb90073441b8ba3ebeb5621e75b0d35a Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Fri, 26 Jan 2024 17:13:39 +0500 Subject: [PATCH 09/22] Refactor DialogButton and MetadataDialog components --- apps/analytics/components/DialogButton.tsx | 4 +++- apps/analytics/components/MetadataDialog.tsx | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/analytics/components/DialogButton.tsx b/apps/analytics/components/DialogButton.tsx index 0efae9bc..ae4307b2 100644 --- a/apps/analytics/components/DialogButton.tsx +++ b/apps/analytics/components/DialogButton.tsx @@ -32,7 +32,9 @@ export function DialogButton({ {title} {description} -
{content}
+
+ {content} +
); diff --git a/apps/analytics/components/MetadataDialog.tsx b/apps/analytics/components/MetadataDialog.tsx index ded6bdd6..ab6eb6cf 100644 --- a/apps/analytics/components/MetadataDialog.tsx +++ b/apps/analytics/components/MetadataDialog.tsx @@ -5,10 +5,10 @@ import { type Event } from "~/db/getEvents"; export function MetadataDialog({ event }: { event: Event | ErrorEvent }) { return ( ); } From 85dcf4ac8cc6b8687aca81edd25843e76cfe2261 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Fri, 26 Jan 2024 17:23:13 +0500 Subject: [PATCH 10/22] fix timestamp render --- .../app/_components/analytics/EventsTable/Columns.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx b/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx index e7210900..11d449af 100644 --- a/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx +++ b/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx @@ -17,6 +17,11 @@ export const columns: ColumnDef[] = [ header: ({ column }) => ( ), + cell: ({ row }) => { + return ( +
{row.original.timestamp.toUTCString()}
+ ); + }, }, { accessorKey: "installationId", From 16eba2c7051e86ad40adcd7602e8ab0fba273342 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Fri, 26 Jan 2024 22:49:29 +0500 Subject: [PATCH 11/22] add filter for event table and refactor --- .../_components/analytics/AnalyticsView.tsx | 17 +++- .../analytics/EventsTable/Columns.tsx | 23 +++++ .../analytics/EventsTable/EventsTable.tsx | 41 ++++++-- .../EventsTable}/StackTraceDialog.tsx | 4 +- .../analytics/EventsTable/TableFilter.tsx | 93 +++++++++++++++++++ .../analytics/cards/TotalDataExported.tsx | 15 +++ .../analytics/cards/TotalErrorsCard.tsx | 15 +++ .../errors/ErrorsTable/Columns.tsx | 56 ----------- .../errors/ErrorsTable/ErrorsTable.tsx | 15 --- .../app/_components/errors/ErrorsView.tsx | 13 --- .../errors/cards/TotalErrorsCard.tsx | 10 -- apps/analytics/app/page.tsx | 15 +-- .../DataTable/data-table-pagination.tsx | 6 +- apps/analytics/components/ExportButton.tsx | 5 +- apps/analytics/components/MetadataDialog.tsx | 4 +- apps/analytics/components/ui/checkbox.tsx | 30 ++++++ apps/analytics/db/getErrors.ts | 18 ---- apps/analytics/db/getEvents.ts | 6 -- apps/analytics/package.json | 1 + apps/analytics/utils/getTotalDataExported.ts | 14 +++ apps/analytics/utils/getTotalErrors.ts | 14 +++ pnpm-lock.yaml | 31 +++++++ 22 files changed, 293 insertions(+), 153 deletions(-) rename apps/analytics/app/_components/{errors/ErrorsTable => analytics/EventsTable}/StackTraceDialog.tsx (65%) create mode 100644 apps/analytics/app/_components/analytics/EventsTable/TableFilter.tsx create mode 100644 apps/analytics/app/_components/analytics/cards/TotalDataExported.tsx create mode 100644 apps/analytics/app/_components/analytics/cards/TotalErrorsCard.tsx delete mode 100644 apps/analytics/app/_components/errors/ErrorsTable/Columns.tsx delete mode 100644 apps/analytics/app/_components/errors/ErrorsTable/ErrorsTable.tsx delete mode 100644 apps/analytics/app/_components/errors/ErrorsView.tsx delete mode 100644 apps/analytics/app/_components/errors/cards/TotalErrorsCard.tsx create mode 100644 apps/analytics/components/ui/checkbox.tsx delete mode 100644 apps/analytics/db/getErrors.ts create mode 100644 apps/analytics/utils/getTotalDataExported.ts create mode 100644 apps/analytics/utils/getTotalErrors.ts diff --git a/apps/analytics/app/_components/analytics/AnalyticsView.tsx b/apps/analytics/app/_components/analytics/AnalyticsView.tsx index c7533a4d..e32024ee 100644 --- a/apps/analytics/app/_components/analytics/AnalyticsView.tsx +++ b/apps/analytics/app/_components/analytics/AnalyticsView.tsx @@ -5,8 +5,13 @@ import TotalInterviewsCompletedCard from "./cards/TotalInterviewsCompletedCard"; import TotalInterviewsStartedCard from "./cards/TotalInterviewsStartedCard"; import TotalProtocolsInstalledCard from "./cards/TotalProtocolsInstalledCard"; import RegionsTable from "./RegionsTable/RegionsTable"; +import getEvents from "~/db/getEvents"; +import TotalErrorsCard from "./cards/TotalErrorsCard"; +import TotalDataExported from "./cards/TotalDataExported"; + +export default async function AnalyticsView() { + const events = await getEvents(); -export default function AnalyticsView() { return (
@@ -14,10 +19,14 @@ export default function AnalyticsView() { + +
-
- - +
+
+ +
+ Regions diff --git a/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx b/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx index 11d449af..91bc7274 100644 --- a/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx +++ b/apps/analytics/app/_components/analytics/EventsTable/Columns.tsx @@ -4,6 +4,7 @@ import { ColumnDef } from "@tanstack/react-table"; import { DataTableColumnHeader } from "~/components/DataTable/column-header"; import { MetadataDialog } from "~/components/MetadataDialog"; import type { Event } from "~/db/getEvents"; +import { StackTraceDialog } from "./StackTraceDialog"; export const columns: ColumnDef[] = [ { @@ -32,6 +33,28 @@ export const columns: ColumnDef[] = [ return
{row.original.installationId}
; }, }, + { + accessorKey: "name", + header: ({ column }) => ( + + ), + }, + { + accessorKey: "message", + header: ({ column }) => ( + + ), + }, + { + accessorKey: "stack", + header: "", + cell: ({ row }) => + row.original.stack && ( +
+ +
+ ), + }, { accessorKey: "metadata", header: "", diff --git a/apps/analytics/app/_components/analytics/EventsTable/EventsTable.tsx b/apps/analytics/app/_components/analytics/EventsTable/EventsTable.tsx index cd8b25c6..9b7a57a3 100644 --- a/apps/analytics/app/_components/analytics/EventsTable/EventsTable.tsx +++ b/apps/analytics/app/_components/analytics/EventsTable/EventsTable.tsx @@ -1,21 +1,48 @@ -// EventsTable.tsx +"use client"; + +import { useEffect, useMemo, useState } from "react"; import { DataTable } from "~/components/DataTable/data-table"; import ExportButton from "~/components/ExportButton"; -import getEvents from "~/db/getEvents"; +import { Event } from "~/db/getEvents"; import { columns } from "./Columns"; +import TableFilter from "./TableFilter"; + +export type EventType = { + text: string; + isSelected: boolean; +}; + +export default function EventsTable({ events }: { events: Event[] }) { + const [eventTypes, setEventTypes] = useState([]); + + useEffect(() => { + const eventTypesMap = new Map(); + events.forEach((event) => + eventTypesMap.set(event.type, { text: event.type, isSelected: true }) + ); -export default async function EventsTable() { - const events = await getEvents(); + setEventTypes([...Array.from(eventTypesMap.values())]); + }, [events]); + + const filteredEvents = useMemo(() => { + const filters = eventTypes + .filter((type) => type.isSelected) + .map((type) => type.text); + + return events.filter((event) => filters.includes(event.type)); + }, [eventTypes, events]); return (
-
+ + +

Events

-
- +
+
); diff --git a/apps/analytics/app/_components/errors/ErrorsTable/StackTraceDialog.tsx b/apps/analytics/app/_components/analytics/EventsTable/StackTraceDialog.tsx similarity index 65% rename from apps/analytics/app/_components/errors/ErrorsTable/StackTraceDialog.tsx rename to apps/analytics/app/_components/analytics/EventsTable/StackTraceDialog.tsx index e3e063e8..ed049cf2 100644 --- a/apps/analytics/app/_components/errors/ErrorsTable/StackTraceDialog.tsx +++ b/apps/analytics/app/_components/analytics/EventsTable/StackTraceDialog.tsx @@ -1,7 +1,7 @@ import { DialogButton } from "~/components/DialogButton"; -import { type ErrorEvent } from "~/db/getErrors"; +import { Event } from "~/db/getEvents"; -export function StackTraceDialog({ error }: { error: ErrorEvent }) { +export function StackTraceDialog({ error }: { error: Event }) { return ( >; +}; + +const TableFilter = ({ eventTypes, setEventTypes }: TableFilterProps) => { + const [allSelected, setAllSelected] = useState(true); + + useEffect(() => { + const updatedEventTypes = eventTypes.map((t) => ({ + ...t, + isSelected: allSelected, + })); + setEventTypes(updatedEventTypes); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [allSelected]); + + const handleCheckedChange = (value: boolean, currentType: string) => { + const updatedEventTypes = eventTypes.map((t) => { + if (t.text === currentType) { + return { ...t, isSelected: value }; + } + return t; + }); + + // If all event types are selected, set allSelected to true + if (updatedEventTypes.every((t) => t.isSelected)) { + setAllSelected(true); + return; + } + + // If no event types are selected, set allSelected to false + if (updatedEventTypes.every((t) => !t.isSelected)) { + setAllSelected(false); + return; + } + + setEventTypes(updatedEventTypes); + }; + + return ( + + + + + + Select events + + +
+ + + {eventTypes.map((type) => ( + + ))} +
+
+
+ ); +}; + +export default TableFilter; diff --git a/apps/analytics/app/_components/analytics/cards/TotalDataExported.tsx b/apps/analytics/app/_components/analytics/cards/TotalDataExported.tsx new file mode 100644 index 00000000..8325614d --- /dev/null +++ b/apps/analytics/app/_components/analytics/cards/TotalDataExported.tsx @@ -0,0 +1,15 @@ +import { getTotalInterviewsStarted } from "~/utils/getTotalInterviewsStarted"; +import { SummaryCard } from "~/components/SummaryCard"; + +const TotalDataExported = async () => { + const totalInterviewsStarted = await getTotalInterviewsStarted(); + return ( + + ); +}; + +export default TotalDataExported; diff --git a/apps/analytics/app/_components/analytics/cards/TotalErrorsCard.tsx b/apps/analytics/app/_components/analytics/cards/TotalErrorsCard.tsx new file mode 100644 index 00000000..fb0a3757 --- /dev/null +++ b/apps/analytics/app/_components/analytics/cards/TotalErrorsCard.tsx @@ -0,0 +1,15 @@ +import { SummaryCard } from "~/components/SummaryCard"; +import { getTotalErrors } from "~/utils/getTotalErrors"; + +const TotalErrorsCard = async () => { + const totalErrors = await getTotalErrors(); + return ( + + ); +}; + +export default TotalErrorsCard; diff --git a/apps/analytics/app/_components/errors/ErrorsTable/Columns.tsx b/apps/analytics/app/_components/errors/ErrorsTable/Columns.tsx deleted file mode 100644 index 26f265df..00000000 --- a/apps/analytics/app/_components/errors/ErrorsTable/Columns.tsx +++ /dev/null @@ -1,56 +0,0 @@ -"use client"; - -import { ColumnDef } from "@tanstack/react-table"; -import { StackTraceDialog } from "~/app/_components/errors/ErrorsTable/StackTraceDialog"; -import { DataTableColumnHeader } from "~/components/DataTable/column-header"; -import { MetadataDialog } from "~/components/MetadataDialog"; -import { type ErrorEvent } from "~/db/getErrors"; - -export const columns: ColumnDef[] = [ - { - accessorKey: "name", - header: ({ column }) => ( - - ), - }, - { - accessorKey: "message", - header: ({ column }) => ( - - ), - }, - { - accessorKey: "installationId", - header: ({ column }) => ( - - ), - }, - { - accessorKey: "timestamp", - header: ({ column }) => ( - - ), - }, - { - accessorKey: "stack", - header: "", - cell: ({ row }) => { - return ( -
- -
- ); - }, - }, - { - accessorKey: "metadata", - header: "", - cell: ({ row }) => { - return ( -
- -
- ); - }, - }, -]; diff --git a/apps/analytics/app/_components/errors/ErrorsTable/ErrorsTable.tsx b/apps/analytics/app/_components/errors/ErrorsTable/ErrorsTable.tsx deleted file mode 100644 index 80fd958c..00000000 --- a/apps/analytics/app/_components/errors/ErrorsTable/ErrorsTable.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { DataTable } from "~/components/DataTable/data-table"; -import getErrors from "~/db/getErrors"; -import { columns } from "./Columns"; -import ExportButton from "~/components/ExportButton"; - -export default async function ErrorsTable() { - const errors = await getErrors(); - - return ( - <> - - - - ); -} diff --git a/apps/analytics/app/_components/errors/ErrorsView.tsx b/apps/analytics/app/_components/errors/ErrorsView.tsx deleted file mode 100644 index 45d81e43..00000000 --- a/apps/analytics/app/_components/errors/ErrorsView.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import ErrorsTable from "./ErrorsTable/ErrorsTable"; -import TotalErrorsCard from "./cards/TotalErrorsCard"; - -export default function ErrorsView() { - return ( -
-
- -
- -
- ); -} diff --git a/apps/analytics/app/_components/errors/cards/TotalErrorsCard.tsx b/apps/analytics/app/_components/errors/cards/TotalErrorsCard.tsx deleted file mode 100644 index 50246c5a..00000000 --- a/apps/analytics/app/_components/errors/cards/TotalErrorsCard.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { SummaryCard } from "~/components/SummaryCard"; -import getErrors from "~/db/getErrors"; - -const TotalErrorsCard = async () => { - const errors = await getErrors(); - const totalErrors = errors.length; - return ; -}; - -export default TotalErrorsCard; diff --git a/apps/analytics/app/page.tsx b/apps/analytics/app/page.tsx index 57e5fde4..74d54fbe 100644 --- a/apps/analytics/app/page.tsx +++ b/apps/analytics/app/page.tsx @@ -1,7 +1,5 @@ import { UserButton } from "@clerk/nextjs"; import AnalyticsView from "~/app/_components/analytics/AnalyticsView"; -import ErrorsView from "~/app/_components/errors/ErrorsView"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"; import UserManagementDialog from "./_components/users/UserManagementDialog"; export default function DashboardPage() { @@ -16,18 +14,7 @@ export default function DashboardPage() {
- - - Analytics - Errors - - - - - - - - +
); diff --git a/apps/analytics/components/DataTable/data-table-pagination.tsx b/apps/analytics/components/DataTable/data-table-pagination.tsx index 356c62c1..f731c9cf 100644 --- a/apps/analytics/components/DataTable/data-table-pagination.tsx +++ b/apps/analytics/components/DataTable/data-table-pagination.tsx @@ -25,11 +25,11 @@ export function DataTablePagination({ }: DataTablePaginationProps) { return (
-
+ {/*
{table.getFilteredSelectedRowModel().rows.length} of{" "} {table.getFilteredRowModel().rows.length} row(s) selected. -
-
+
*/} +

Rows per page

toggleAllOptions(!isAllSelected)} + /> + All + + {selectedOptions.map((option) => ( + + ))} +
+ ); +}; + +export default DropdownMenu; diff --git a/apps/analytics/components/DataTable/column-header.tsx b/apps/analytics/components/DataTable/column-header.tsx index b70fc25f..7a1e2378 100644 --- a/apps/analytics/components/DataTable/column-header.tsx +++ b/apps/analytics/components/DataTable/column-header.tsx @@ -13,7 +13,7 @@ import { cn } from "~/utils/shadcn"; interface DataTableColumnHeaderProps extends React.HTMLAttributes { column: Column; - title: string; + title?: string; } export function DataTableColumnHeader({ @@ -36,11 +36,15 @@ export function DataTableColumnHeader({ > {title} {column.getIsSorted() === "desc" ? ( - + ) : column.getIsSorted() === "asc" ? ( - + ) : ( - + )} From 8a85637c1788453eeb25b90930e844013cd98e9c Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Mon, 29 Jan 2024 21:42:09 +0500 Subject: [PATCH 15/22] remove testing file --- apps/analytics/app/options/page.tsx | 64 ----------------------------- 1 file changed, 64 deletions(-) delete mode 100644 apps/analytics/app/options/page.tsx diff --git a/apps/analytics/app/options/page.tsx b/apps/analytics/app/options/page.tsx deleted file mode 100644 index adaba41c..00000000 --- a/apps/analytics/app/options/page.tsx +++ /dev/null @@ -1,64 +0,0 @@ -"use client"; - -import React, { useState } from "react"; - -const eventTypes = [ - "AppSetup", - "ProtocolInstalled", - "InterviewStarted", - "InterviewCompleted", - "DataExported", - "Error", -]; - -const DropdownMenu = () => { - const [selectedOptions, setSelectedOptions] = useState( - eventTypes.map((eventType) => ({ text: eventType, isSelected: true })) - ); - - const toggleOption = (option: string) => { - setSelectedOptions((prevOptions) => - prevOptions.map((prevOption) => - prevOption.text === option - ? { ...prevOption, isSelected: !prevOption.isSelected } - : prevOption - ) - ); - }; - - const toggleAllOptions = (isSelected: boolean) => { - setSelectedOptions((prevOptions) => - prevOptions.map((prevOption) => ({ ...prevOption, isSelected })) - ); - }; - - const isAllSelected = selectedOptions.every((option) => option.isSelected); - - return ( -
- - {selectedOptions.map((option) => ( - - ))} -
- ); -}; - -export default DropdownMenu; From f01c5af44dbf1bb8c374d81c156a2cfd8aeb8bd8 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Tue, 30 Jan 2024 19:28:23 +0500 Subject: [PATCH 16/22] wip: test api route handler --- apps/analytics/app/api/event/route.test.ts | 107 ++ apps/analytics/app/api/event/route.ts | 59 +- apps/analytics/db/db.ts | 2 + apps/analytics/jest.config.js | 8 + apps/analytics/package.json | 10 +- apps/analytics/scripts/seed.ts | 14 +- pnpm-lock.yaml | 1683 ++++++++++++++++++-- 7 files changed, 1733 insertions(+), 150 deletions(-) create mode 100644 apps/analytics/app/api/event/route.test.ts create mode 100644 apps/analytics/jest.config.js diff --git a/apps/analytics/app/api/event/route.test.ts b/apps/analytics/app/api/event/route.test.ts new file mode 100644 index 00000000..9dd23dd6 --- /dev/null +++ b/apps/analytics/app/api/event/route.test.ts @@ -0,0 +1,107 @@ +import insertEvent from "~/db/insertEvent"; +import { Event, POST } from "./route"; + +import { createMocks as _createMocks } from "node-mocks-http"; +import type { RequestOptions, ResponseOptions } from "node-mocks-http"; +import { NextRequest, NextResponse } from "next/server"; + +const createMocks = _createMocks as ( + reqOptions?: RequestOptions, + resOptions?: ResponseOptions + // @ts-ignore: Fixing this: https://github.com/howardabrams/node-mocks-http/issues/245 +) => Mocks; + +jest.mock("~/db/insertEvent", () => jest.fn()); + +describe("/api/event", () => { + test("should insert event to the database", async () => { + const eventData = { + type: "AppSetup", + metadata: { + details: "testing details", + path: "testing path", + }, + installationId: "21321546453213123", + timestamp: new Date(), + isocode: "US", + }; + + const mockInsertEvent = async (eventData: Event) => { + return { data: eventData, error: null }; + }; + + const { req } = createMocks({ + method: "POST", + body: eventData, + }); + + const response = await POST(req); + expect(mockInsertEvent).toHaveBeenCalledWith(eventData); + expect(response.status).toBe(200); + expect(response.headers).toEqual({ + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }); + expect(await response.json()).toEqual(eventData); + }), + test("should return 401 if event is invalid", async () => { + const eventData = { + type: "InvalidEvent", + metadata: { + details: "testing details", + path: "testing path", + }, + timestamp: new Date(), + isocode: "US", + }; + + const { req } = createMocks({ + method: "POST", + body: eventData, + }); + + const response = await POST(req as any); + expect(insertEvent).not.toHaveBeenCalled(); + expect(response.status).toBe(401); + expect(response.headers).toEqual({ + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }); + expect(await response.json()).toEqual({ error: "Invalid event" }); + }), + test("should return 500 if there is an error inserting the event to the database", async () => { + const eventData = { + type: "AppSetup", + metadata: { + details: "testing details", + path: "testing path", + }, + installationId: "21321546453213123", + timestamp: new Date(), + isocode: "US", + }; + + const mockInsertEvent = async (eventData: Event) => { + return { data: null, error: "Error inserting events" }; + }; + + const { req } = createMocks({ + method: "POST", + body: eventData, + }); + + const response = await POST(req as any); + expect(mockInsertEvent).toHaveBeenCalledWith(eventData); + expect(response.status).toBe(500); + expect(response.headers).toEqual({ + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }); + expect(await response.json()).toEqual({ + error: "Error inserting events", + }); + }); +}); diff --git a/apps/analytics/app/api/event/route.ts b/apps/analytics/app/api/event/route.ts index 350c3d98..2b37f330 100644 --- a/apps/analytics/app/api/event/route.ts +++ b/apps/analytics/app/api/event/route.ts @@ -2,6 +2,37 @@ import { type DispatchableAnalyticsEvent } from "@codaco/analytics"; import { NextRequest, NextResponse } from "next/server"; import { type EventInsertType } from "~/db/db"; import insertEvent from "~/db/insertEvent"; +import z from "zod"; + +export const eventTypes = [ + "AppSetup", + "ProtocolInstalled", + "InterviewStarted", + "InterviewCompleted", + "InterviewCompleted", + "DataExported", + "Error", +] as const; + +export type EventType = (typeof eventTypes)[number]; + +export const EventsSchema = z.object({ + type: z.enum(eventTypes), + installationId: z.string(), + timestamp: z.date(), + isocode: z.string().optional(), + message: z.string().optional(), + name: z.string().optional(), + stack: z.string().optional(), + metadata: z + .object({ + details: z.string(), + path: z.string(), + }) + .optional(), +}); + +export type Event = z.infer; const corsHeaders = { "Access-Control-Allow-Origin": "*", @@ -12,27 +43,19 @@ const corsHeaders = { export const runtime = "edge"; export async function POST(request: NextRequest) { - const event = (await request.json()) as DispatchableAnalyticsEvent; - - let generalEvent: EventInsertType = { - type: event.type, - metadata: event.metadata, - timestamp: new Date(event.timestamp), - installationId: event.installationId, - isocode: event.geolocation?.countryCode, - }; - - if (event.type === "Error") { - generalEvent = { - ...generalEvent, - message: event.error.message, - name: event.error.name, - stack: event.error.stack, - }; + const event = (await request.json()) as unknown; + + const parsedEvent = EventsSchema.safeParse(event); + + if (parsedEvent.success === false) { + return NextResponse.json( + { error: "Invalid event" }, + { status: 401, headers: corsHeaders } + ); } try { - const result = await insertEvent(generalEvent); + const result = await insertEvent(parsedEvent.data); if (result.error) throw new Error(result.error); return NextResponse.json({ event }, { status: 200, headers: corsHeaders }); diff --git a/apps/analytics/db/db.ts b/apps/analytics/db/db.ts index 5ad4fc1a..0b0a1baa 100644 --- a/apps/analytics/db/db.ts +++ b/apps/analytics/db/db.ts @@ -7,3 +7,5 @@ import { eventsTable } from "./schema"; export const db = drizzle(sql, { schema }); export type EventInsertType = typeof eventsTable.$inferInsert; + +// derive a zod schema from the table schema and use it inside analytics package diff --git a/apps/analytics/jest.config.js b/apps/analytics/jest.config.js new file mode 100644 index 00000000..edf75ad9 --- /dev/null +++ b/apps/analytics/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + testMatch: ["**/*.test.ts"], + moduleNameMapper: { + "^~/(.*)$": "/$1", + }, +}; diff --git a/apps/analytics/package.json b/apps/analytics/package.json index 24ea4f38..96362c30 100644 --- a/apps/analytics/package.json +++ b/apps/analytics/package.json @@ -36,18 +36,24 @@ "react": "^18", "react-dom": "^18", "tailwind-merge": "^2.0.0", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zod": "^3.22.4" }, "devDependencies": { "@faker-js/faker": "^8.2.0", "@next/eslint-plugin-next": "^13.4.19", - "@types/node": "^20", + "@testing-library/react": "^14.1.2", + "@types/jest": "^29.5.11", + "@types/node": "^20.5.2", "@types/papaparse": "^5.3.14", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", "drizzle-kit": "^0.20.13", "eslint-config-custom": "workspace:*", + "jest": "^29.7.0", + "node-mocks-http": "^1.14.1", "tailwindcss": "^3.3.0", + "ts-jest": "^29.1.2", "tsconfig": "workspace:*", "typescript": "^5.2.2" } diff --git a/apps/analytics/scripts/seed.ts b/apps/analytics/scripts/seed.ts index 46d467be..ef6b1614 100644 --- a/apps/analytics/scripts/seed.ts +++ b/apps/analytics/scripts/seed.ts @@ -2,25 +2,15 @@ import dotenv from "dotenv"; dotenv.config(); import { faker } from "@faker-js/faker"; -import { db } from "~/db/db"; +import { eventTypes } from "~/app/api/event/route"; +import { db, type EventInsertType } from "~/db/db"; import { eventsTable } from "~/db/schema"; -import { type EventInsertType } from "~/db/db"; let installationIds: string[] = []; for (let i = 0; i < 20; i++) { installationIds.push(faker.string.uuid()); } -const eventTypes = [ - "AppSetup", - "ProtocolInstalled", - "InterviewStarted", - "InterviewCompleted", - "InterviewCompleted", - "DataExported", - "Error", -]; - async function seedEvents() { console.info("Starting to seed events"); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 70f4bbc8..73169922 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,7 +89,7 @@ importers: version: 0.292.0(react@18.2.0) next: specifier: 14.0.1 - version: 14.0.1(react-dom@18.2.0)(react@18.2.0) + version: 14.0.1(@babel/core@7.22.11)(react-dom@18.2.0)(react@18.2.0) papaparse: specifier: ^5.4.1 version: 5.4.1 @@ -105,6 +105,9 @@ importers: tailwindcss-animate: specifier: ^1.0.7 version: 1.0.7(tailwindcss@3.3.5) + zod: + specifier: ^3.22.4 + version: 3.22.4 devDependencies: '@faker-js/faker': specifier: ^8.2.0 @@ -112,8 +115,14 @@ importers: '@next/eslint-plugin-next': specifier: ^13.4.19 version: 13.4.19 + '@testing-library/react': + specifier: ^14.1.2 + version: 14.1.2(react-dom@18.2.0)(react@18.2.0) + '@types/jest': + specifier: ^29.5.11 + version: 29.5.11 '@types/node': - specifier: ^20 + specifier: ^20.5.2 version: 20.5.2 '@types/papaparse': specifier: ^5.3.14 @@ -130,9 +139,18 @@ importers: eslint-config-custom: specifier: workspace:* version: link:../../packages/eslint-config-custom + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.5.2) + node-mocks-http: + specifier: ^1.14.1 + version: 1.14.1 tailwindcss: specifier: ^3.3.0 version: 3.3.5 + ts-jest: + specifier: ^29.1.2 + version: 29.1.2(@babel/core@7.22.11)(esbuild@0.19.12)(jest@29.7.0)(typescript@5.2.2) tsconfig: specifier: workspace:* version: link:../../packages/tsconfig @@ -147,7 +165,7 @@ importers: version: 5.0.0 next: specifier: 13 || 14 - version: 14.0.1(react-dom@18.2.0)(react@18.2.0) + version: 14.0.1(@babel/core@7.22.11)(react-dom@18.2.0)(react@18.2.0) devDependencies: eslint-config-custom: specifier: workspace:* @@ -193,7 +211,6 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.19 - dev: true /@babel/code-frame@7.22.10: resolution: {integrity: sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==} @@ -205,7 +222,6 @@ packages: /@babel/compat-data@7.22.9: resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} engines: {node: '>=6.9.0'} - dev: true /@babel/core@7.22.11: resolution: {integrity: sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==} @@ -228,7 +244,6 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color - dev: true /@babel/eslint-parser@7.22.11(@babel/core@7.22.11)(eslint@8.52.0): resolution: {integrity: sha512-YjOYZ3j7TjV8OhLW6NCtyg8G04uStATEUe5eiLuCZaXz2VSDQ3dsAtm2D+TuQyAqNMUK2WacGo0/uma9Pein1w==} @@ -252,7 +267,6 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.19 jsesc: 2.5.2 - dev: true /@babel/helper-compilation-targets@7.22.10: resolution: {integrity: sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==} @@ -263,12 +277,10 @@ packages: browserslist: 4.21.10 lru-cache: 5.1.1 semver: 6.3.1 - dev: true /@babel/helper-environment-visitor@7.22.5: resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-function-name@7.22.5: resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} @@ -276,21 +288,18 @@ packages: dependencies: '@babel/template': 7.22.5 '@babel/types': 7.22.11 - dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.11 - dev: true /@babel/helper-module-imports@7.22.5: resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.11 - dev: true /@babel/helper-module-transforms@7.22.9(@babel/core@7.22.11): resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} @@ -304,6 +313,10 @@ packages: '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.5 + + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} dev: true /@babel/helper-simple-access@7.22.5: @@ -311,19 +324,16 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.11 - dev: true /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.11 - dev: true /@babel/helper-string-parser@7.22.5: resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-identifier@7.22.5: resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} @@ -332,7 +342,6 @@ packages: /@babel/helper-validator-option@7.22.5: resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} engines: {node: '>=6.9.0'} - dev: true /@babel/helpers@7.22.11: resolution: {integrity: sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==} @@ -343,7 +352,6 @@ packages: '@babel/types': 7.22.11 transitivePeerDependencies: - supports-color - dev: true /@babel/highlight@7.22.10: resolution: {integrity: sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==} @@ -359,6 +367,134 @@ packages: hasBin: true dependencies: '@babel/types': 7.22.11 + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.11): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.22.11): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.11): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.22.11): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.11): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.22.11): + resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.11): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.11): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.11): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.11): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.11): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.11): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.11): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.22.11): + resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/runtime@7.23.2: @@ -374,7 +510,6 @@ packages: '@babel/code-frame': 7.22.10 '@babel/parser': 7.22.13 '@babel/types': 7.22.11 - dev: true /@babel/traverse@7.22.11: resolution: {integrity: sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==} @@ -392,7 +527,6 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true /@babel/types@7.22.11: resolution: {integrity: sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==} @@ -401,6 +535,9 @@ packages: '@babel/helper-string-parser': 7.22.5 '@babel/helper-validator-identifier': 7.22.5 to-fast-properties: 2.0.0 + + /@bcoe/v8-coverage@0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true /@changesets/apply-release-plan@6.1.4: @@ -646,7 +783,7 @@ packages: '@clerk/clerk-sdk-node': 4.12.21(react@18.2.0) '@clerk/shared': 1.1.0(react@18.2.0) '@clerk/types': 3.58.0 - next: 14.0.1(react-dom@18.2.0)(react@18.2.0) + next: 14.0.1(@babel/core@7.22.11)(react-dom@18.2.0)(react@18.2.0) path-to-regexp: 6.2.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -1136,7 +1273,7 @@ packages: ajv: 6.12.6 debug: 4.3.4 espree: 9.6.1 - globals: 13.20.0 + globals: 13.23.0 ignore: 5.2.4 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -1224,6 +1361,236 @@ packages: resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} dev: true + /@istanbuljs/load-nyc-config@1.1.0: + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + dev: true + + /@istanbuljs/schema@0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jest/console@29.7.0: + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/core@29.7.0: + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.8.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.5.2) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /@jest/environment@29.7.0: + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + jest-mock: 29.7.0 + dev: true + + /@jest/expect-utils@29.7.0: + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + dev: true + + /@jest/expect@29.7.0: + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/fake-timers@29.7.0: + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.5.2 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /@jest/globals@29.7.0: + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/reporters@29.7.0: + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.19 + '@types/node': 20.5.2 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.1 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.6 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/schemas@29.6.3: + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.27.8 + dev: true + + /@jest/source-map@29.6.3: + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jridgewell/trace-mapping': 0.3.19 + callsites: 3.1.0 + graceful-fs: 4.2.11 + dev: true + + /@jest/test-result@29.7.0: + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + dev: true + + /@jest/test-sequencer@29.7.0: + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/transform@29.7.0: + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.22.11 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.19 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.5 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/types@29.6.3: + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.5.2 + '@types/yargs': 17.0.32 + chalk: 4.1.2 + dev: true + /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} @@ -2124,6 +2491,22 @@ packages: resolution: {integrity: sha512-0xd7qez0AQ+MbHatZTlI1gu5vkG8r7MYRUJAHPAHJBmGLs16zpkrpAVLvjQKQOqaXPDUBwOiJzNc00znHSCVBw==} dev: true + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + + /@sinonjs/commons@3.0.1: + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + dependencies: + type-detect: 4.0.8 + dev: true + + /@sinonjs/fake-timers@10.3.0: + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + dependencies: + '@sinonjs/commons': 3.0.1 + dev: true + /@swc/helpers@0.5.2: resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} dependencies: @@ -2147,36 +2530,94 @@ packages: engines: {node: '>=12'} dev: false - /@types/body-parser@1.19.5: - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + /@testing-library/dom@9.3.4: + resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==} + engines: {node: '>=14'} dependencies: - '@types/connect': 3.4.38 - '@types/node': 20.5.2 - dev: false + '@babel/code-frame': 7.22.10 + '@babel/runtime': 7.23.2 + '@types/aria-query': 5.0.4 + aria-query: 5.1.3 + chalk: 4.1.2 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + pretty-format: 27.5.1 + dev: true - /@types/connect@3.4.38: - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + /@testing-library/react@14.1.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-z4p7DVBTPjKM5qDZ0t5ZjzkpSNb+fZy1u6bzO7kk8oeGagpPCAtgh4cx1syrfp7a+QWkM021jGqjJaxJJnXAZg==} + engines: {node: '>=14'} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 dependencies: - '@types/node': 20.5.2 - dev: false + '@babel/runtime': 7.23.2 + '@testing-library/dom': 9.3.4 + '@types/react-dom': 18.2.6 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true - /@types/cookies@0.7.7: - resolution: {integrity: sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==} - dependencies: - '@types/connect': 3.4.38 - '@types/express': 4.17.14 - '@types/keygrip': 1.0.5 - '@types/node': 20.5.2 - dev: false + /@types/aria-query@5.0.4: + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + dev: true - /@types/express-serve-static-core@4.17.41: - resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==} + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@types/node': 20.5.2 - '@types/qs': 6.9.10 + '@babel/parser': 7.22.13 + '@babel/types': 7.22.11 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.5 + dev: true + + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + dependencies: + '@babel/types': 7.22.11 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.22.13 + '@babel/types': 7.22.11 + dev: true + + /@types/babel__traverse@7.20.5: + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + dependencies: + '@babel/types': 7.22.11 + dev: true + + /@types/body-parser@1.19.5: + resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + dependencies: + '@types/connect': 3.4.38 + '@types/node': 20.11.10 + + /@types/connect@3.4.38: + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + dependencies: + '@types/node': 20.11.10 + + /@types/cookies@0.7.7: + resolution: {integrity: sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==} + dependencies: + '@types/connect': 3.4.38 + '@types/express': 4.17.14 + '@types/keygrip': 1.0.5 + '@types/node': 20.5.2 + dev: false + + /@types/express-serve-static-core@4.17.41: + resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==} + dependencies: + '@types/node': 20.11.10 + '@types/qs': 6.9.10 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 - dev: false /@types/express@4.17.14: resolution: {integrity: sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==} @@ -2187,9 +2628,23 @@ packages: '@types/serve-static': 1.15.5 dev: false + /@types/express@4.17.21: + resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + dependencies: + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 4.17.41 + '@types/qs': 6.9.10 + '@types/serve-static': 1.15.5 + dev: true + + /@types/graceful-fs@4.1.9: + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + dependencies: + '@types/node': 20.5.2 + dev: true + /@types/http-errors@2.0.4: resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} - dev: false /@types/is-ci@3.0.4: resolution: {integrity: sha512-AkCYCmwlXeuH89DagDCzvCAyltI2v9lh3U3DqSg/GrBYoReAaWwxfXCqMx9UV5MajLZ4ZFwZzV4cABGIxk2XRw==} @@ -2197,6 +2652,29 @@ packages: ci-info: 3.8.0 dev: false + /@types/istanbul-lib-coverage@2.0.6: + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + dev: true + + /@types/istanbul-lib-report@3.0.3: + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + dev: true + + /@types/istanbul-reports@3.0.4: + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + dependencies: + '@types/istanbul-lib-report': 3.0.3 + dev: true + + /@types/jest@29.5.11: + resolution: {integrity: sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==} + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + dev: true + /@types/json-schema@7.0.12: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true @@ -2211,11 +2689,9 @@ packages: /@types/mime@1.3.5: resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - dev: false /@types/mime@3.0.4: resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} - dev: false /@types/minimist@1.2.5: resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} @@ -2236,6 +2712,11 @@ packages: resolution: {integrity: sha512-vmYJF0REqDyyU0gviezF/KHq/fYaUbFhkcNbQCuPGFQj6VTbXuHZoxs/Y7mutWe73C8AC6l9fFu8mSYiBAqkGA==} dev: false + /@types/node@20.11.10: + resolution: {integrity: sha512-rZEfe/hJSGYmdfX9tvcPMYeYPW2sNl50nsw4jZmRcaG0HIAb0WYEpsB05GOb53vjqpyE9GUhlDQ4jLSoB5q9kg==} + dependencies: + undici-types: 5.26.5 + /@types/node@20.5.2: resolution: {integrity: sha512-5j/lXt7unfPOUlrKC34HIaedONleyLtwkKggiD/0uuMfT8gg2EOpg0dz4lCD15Ga7muC+1WzJZAjIB9simWd6Q==} @@ -2261,11 +2742,9 @@ packages: /@types/qs@6.9.10: resolution: {integrity: sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==} - dev: false /@types/range-parser@1.2.7: resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - dev: false /@types/react-dom@18.2.6: resolution: {integrity: sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==} @@ -2289,16 +2768,28 @@ packages: resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} dependencies: '@types/mime': 1.3.5 - '@types/node': 20.5.2 - dev: false + '@types/node': 20.11.10 /@types/serve-static@1.15.5: resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==} dependencies: '@types/http-errors': 2.0.4 '@types/mime': 3.0.4 - '@types/node': 20.5.2 - dev: false + '@types/node': 20.11.10 + + /@types/stack-utils@2.0.3: + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + dev: true + + /@types/yargs-parser@21.0.3: + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + dev: true + + /@types/yargs@17.0.32: + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + dependencies: + '@types/yargs-parser': 21.0.3 + dev: true /@typescript-eslint/eslint-plugin@6.5.0(@typescript-eslint/parser@6.5.0)(eslint@8.52.0)(typescript@5.2.2): resolution: {integrity: sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==} @@ -2609,6 +3100,14 @@ packages: - supports-color dev: true + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: true + /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2636,6 +3135,13 @@ packages: engines: {node: '>=6'} dev: false + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2652,6 +3158,11 @@ packages: dependencies: color-convert: 2.0.1 + /ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -2669,7 +3180,6 @@ packages: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: sprintf-js: 1.0.3 - dev: false /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -2824,6 +3334,78 @@ packages: deep-equal: 2.2.1 dev: true + /babel-jest@29.7.0(@babel/core@7.22.11): + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + dependencies: + '@babel/core': 7.22.11 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.22.11) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + dependencies: + '@babel/helper-plugin-utils': 7.22.5 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/template': 7.22.5 + '@babel/types': 7.22.11 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.5 + dev: true + + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.22.11): + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.11) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.11) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.11) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.11) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.11) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.11) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.22.11): + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.11) + dev: true + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2884,6 +3466,19 @@ packages: node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.10) + /bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + dependencies: + fast-json-stable-stringify: 2.1.0 + dev: true + + /bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + dev: true + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true @@ -2957,7 +3552,11 @@ packages: /camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} - dev: false + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true /camelcase@7.0.1: resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} @@ -2987,6 +3586,11 @@ packages: engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} dev: true + /char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + dev: true + /chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: false @@ -3009,6 +3613,10 @@ packages: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} + /cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + dev: true + /class-variance-authority@0.7.0: resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} dependencies: @@ -3052,7 +3660,6 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: false /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} @@ -3064,6 +3671,15 @@ packages: engines: {node: '>=6'} dev: false + /co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: true + + /collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + dev: true + /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -3100,8 +3716,18 @@ packages: /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + /content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: true + /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true /cookie@0.5.0: @@ -3120,6 +3746,25 @@ packages: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} dev: false + /create-jest@29.7.0(@types/node@20.5.2): + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.5.2) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + /cross-spawn@5.1.0: resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} dependencies: @@ -3207,7 +3852,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true /decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} @@ -3222,6 +3866,15 @@ packages: engines: {node: '>=0.10.0'} dev: false + /dedent@1.5.1: + resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + dev: true + /deep-equal@2.2.1: resolution: {integrity: sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==} dependencies: @@ -3252,7 +3905,6 @@ packages: /deepmerge@4.2.2: resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} engines: {node: '>=0.10.0'} - dev: false /default-browser-id@3.0.0: resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} @@ -3295,6 +3947,11 @@ packages: engines: {node: '>=0.4.0'} dev: false + /depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + dev: true + /detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -3305,6 +3962,11 @@ packages: engines: {node: '>=12.20'} dev: true + /detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + dev: true + /detect-newline@4.0.0: resolution: {integrity: sha512-1aXUEPdfGdzVPFpzGJJNgq9o81bGg1s09uxTWsqBlo9PI332uyJRQq13+LK/UN4JfxJbFdCXonUFQ9R/p7yCtw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3321,6 +3983,11 @@ packages: /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + /difflib@0.2.4: resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} dependencies: @@ -3350,6 +4017,10 @@ packages: esutils: 2.0.3 dev: true + /dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dev: true + /dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: @@ -3475,9 +4146,13 @@ packages: /electron-to-chromium@1.4.498: resolution: {integrity: sha512-4LODxAzKGVy7CJyhhN5mebwe7U2L29P+0G+HUriHnabm0d7LSff8Yn7t+Wq+2/9ze2Fu1dhX7mww090xfv7qXQ==} + /emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + dev: true + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: false /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} @@ -3721,6 +4396,11 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -4311,7 +4991,6 @@ packages: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - dev: false /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} @@ -4379,6 +5058,22 @@ packages: strip-final-newline: 3.0.0 dev: true + /exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + dev: true + + /expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + dev: true + /ext@1.7.0: resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} dependencies: @@ -4440,6 +5135,12 @@ packages: dependencies: reusify: 1.0.4 + /fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + dependencies: + bser: 2.1.1 + dev: true + /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -4504,6 +5205,11 @@ packages: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: false + /fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + dev: true + /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -4550,12 +5256,10 @@ packages: /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - dev: true /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - dev: false /get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} @@ -4570,6 +5274,11 @@ packages: engines: {node: '>=6'} dev: false + /get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + /get-stdin@9.0.0: resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==} engines: {node: '>=12'} @@ -4663,7 +5372,6 @@ packages: /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - dev: true /globals@13.20.0: resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} @@ -4778,6 +5486,10 @@ packages: /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + /human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} dev: false @@ -4818,6 +5530,15 @@ packages: resolve-from: 4.0.0 dev: true + /import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + dev: true + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -4954,7 +5675,11 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: false + + /is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + dev: true /is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} @@ -5073,49 +5798,518 @@ packages: resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} dev: true - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.2 + + /is-weakset@2.0.2: + resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + dev: true + + /is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + dev: true + + /is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + dev: false + + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + /istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.22.11 + '@babel/parser': 7.22.13 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-instrument@6.0.1: + resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} + engines: {node: '>=10'} + dependencies: + '@babel/core': 7.22.11 + '@babel/parser': 7.22.13 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + dev: true + + /iterator.prototype@1.1.0: + resolution: {integrity: sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw==} + dependencies: + define-properties: 1.2.0 + get-intrinsic: 1.2.1 + has-symbols: 1.0.3 + has-tostringtag: 1.0.0 + reflect.getprototypeof: 1.0.3 + dev: true + + /jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + dev: true + + /jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.1 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.0.4 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-cli@29.7.0(@types/node@20.5.2): + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.5.2) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@20.5.2) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /jest-config@29.7.0(@types/node@20.5.2): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.22.11 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + babel-jest: 29.7.0(@babel/core@7.22.11) + chalk: 4.1.2 + ci-info: 3.8.0 + deepmerge: 4.2.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + detect-newline: 3.1.0 + dev: true + + /jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 20.5.2 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.5 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/code-frame': 7.22.10 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + dev: true + + /jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + jest-util: 29.7.0 + dev: true + + /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + dependencies: + jest-resolve: 29.7.0 + dev: true + + /jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.2 + resolve.exports: 2.0.2 + slash: 3.0.0 + dev: true + + /jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - call-bind: 1.0.2 + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + chalk: 4.1.2 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true - /is-weakset@2.0.2: - resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + /jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + '@babel/core': 7.22.11 + '@babel/generator': 7.22.10 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.22.11) + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.22.11) + '@babel/types': 7.22.11 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.11) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color dev: true - /is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} + /jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + chalk: 4.1.2 + ci-info: 3.8.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 dev: true - /is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - dev: false - - /is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} + /jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - is-docker: 2.2.1 + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 dev: true - /isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + /jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.5.2 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + dev: true - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + /jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@types/node': 20.5.2 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true - /iterator.prototype@1.1.0: - resolution: {integrity: sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw==} + /jest@29.7.0(@types/node@20.5.2): + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true dependencies: - define-properties: 1.2.0 - get-intrinsic: 1.2.1 - has-symbols: 1.0.3 - has-tostringtag: 1.0.0 - reflect.getprototypeof: 1.0.3 + '@jest/core': 29.7.0 + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0(@types/node@20.5.2) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node dev: true /jiti@1.21.0: @@ -5145,7 +6339,6 @@ packages: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: false /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} @@ -5162,7 +6355,6 @@ packages: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true - dev: true /jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} @@ -5205,7 +6397,6 @@ packages: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - dev: true /jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -5236,6 +6427,11 @@ packages: engines: {node: '>=0.10.0'} dev: false + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: true + /kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -5251,6 +6447,11 @@ packages: language-subtag-registry: 0.3.22 dev: true + /leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + dev: true + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -5293,6 +6494,10 @@ packages: dependencies: p-locate: 5.0.0 + /lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: true + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -5335,7 +6540,6 @@ packages: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: yallist: 3.1.1 - dev: true /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} @@ -5357,6 +6561,28 @@ packages: react: 18.2.0 dev: false + /lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + dev: true + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: true + + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + dependencies: + tmpl: 1.0.5 + dev: true + /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -5375,6 +6601,11 @@ packages: tiny-lru: 11.2.5 dev: false + /media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + dev: true + /memoizee@0.4.15: resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} dependencies: @@ -5405,6 +6636,10 @@ packages: yargs-parser: 18.1.3 dev: false + /merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + dev: true + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: true @@ -5413,6 +6648,11 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + /methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + dev: true + /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -5423,14 +6663,18 @@ packages: /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} - dev: false /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} dependencies: mime-db: 1.52.0 - dev: false + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + dev: true /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} @@ -5490,7 +6734,6 @@ packages: /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -5512,11 +6755,16 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + dev: true + /next-tick@1.1.0: resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} dev: true - /next@14.0.1(react-dom@18.2.0)(react@18.2.0): + /next@14.0.1(@babel/core@7.22.11)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-s4YaLpE4b0gmb3ggtmpmV+wt+lPRuGtANzojMQ2+gmBpgX9w5fTbjsy6dXByBuENsdCX5pukZH/GxdFgO62+pA==} engines: {node: '>=18.17.0'} hasBin: true @@ -5538,7 +6786,7 @@ packages: postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.22.11)(react@18.2.0) watchpack: 2.4.0 optionalDependencies: '@next/swc-darwin-arm64': 14.0.1 @@ -5571,6 +6819,28 @@ packages: hasBin: true dev: false + /node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + dev: true + + /node-mocks-http@1.14.1: + resolution: {integrity: sha512-mfXuCGonz0A7uG1FEjnypjm34xegeN5+HI6xeGhYKecfgaZhjsmYoLE9LEFmT+53G1n8IuagPZmVnEL/xNsFaA==} + engines: {node: '>=14'} + dependencies: + '@types/express': 4.17.21 + '@types/node': 20.11.10 + accepts: 1.3.8 + content-disposition: 0.5.4 + depd: 1.1.2 + fresh: 0.5.2 + merge-descriptors: 1.0.3 + methods: 1.1.2 + mime: 1.6.0 + parseurl: 1.3.3 + range-parser: 1.2.1 + type-is: 1.6.18 + dev: true + /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} @@ -5790,6 +7060,11 @@ packages: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: true + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -5864,7 +7139,6 @@ packages: engines: {node: '>=8'} dependencies: find-up: 4.1.0 - dev: false /pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} @@ -5995,6 +7269,32 @@ packages: engines: {node: '>=14'} dev: true + /pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + dev: true + + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: true + /prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: @@ -6012,6 +7312,10 @@ packages: engines: {node: '>=6'} dev: true + /pure-rand@6.0.4: + resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} + dev: true + /pvtsutils@1.3.5: resolution: {integrity: sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==} dependencies: @@ -6031,6 +7335,11 @@ packages: engines: {node: '>=8'} dev: false + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + dev: true + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -6039,12 +7348,19 @@ packages: loose-envify: 1.4.0 react: 18.2.0 scheduler: 0.23.0 - dev: false /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: true + /react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + dev: true + + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: true + /react-remove-scroll-bar@2.3.4(@types/react@18.2.14)(react@18.2.0): resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==} engines: {node: '>=10'} @@ -6102,7 +7418,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - dev: false /read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -6188,12 +7503,18 @@ packages: /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - dev: false /require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} dev: false + /resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -6207,6 +7528,11 @@ packages: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} dev: true + /resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + dev: true + /resolve@1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} dependencies: @@ -6270,6 +7596,10 @@ packages: has-symbols: 1.0.3 isarray: 2.0.5 + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: @@ -6285,7 +7615,6 @@ packages: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: loose-envify: 1.4.0 - dev: false /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} @@ -6294,7 +7623,6 @@ packages: /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - dev: true /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} @@ -6412,6 +7740,13 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + /source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: @@ -6458,7 +7793,13 @@ packages: /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: false + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true /stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} @@ -6478,6 +7819,14 @@ packages: engines: {node: '>=10.0.0'} dev: false + /string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + dev: true + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -6485,7 +7834,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: false /string.prototype.matchall@4.0.8: resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} @@ -6532,6 +7880,11 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + /strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + dev: true + /strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} @@ -6553,7 +7906,7 @@ packages: engines: {node: '>=8'} dev: true - /styled-jsx@5.1.1(react@18.2.0): + /styled-jsx@5.1.1(@babel/core@7.22.11)(react@18.2.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} peerDependencies: @@ -6566,6 +7919,7 @@ packages: babel-plugin-macros: optional: true dependencies: + '@babel/core': 7.22.11 client-only: 0.0.1 react: 18.2.0 dev: false @@ -6602,6 +7956,13 @@ packages: dependencies: has-flag: 4.0.0 + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true + /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -6677,6 +8038,15 @@ packages: engines: {node: '>=8'} dev: false + /test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + dev: true + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -6716,10 +8086,13 @@ packages: os-tmpdir: 1.0.2 dev: false + /tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: true + /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} - dev: true /to-no-case@1.0.2: resolution: {integrity: sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==} @@ -6780,6 +8153,41 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + /ts-jest@29.1.2(@babel/core@7.22.11)(esbuild@0.19.12)(jest@29.7.0)(typescript@5.2.2): + resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} + engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + dependencies: + '@babel/core': 7.22.11 + bs-logger: 0.2.6 + esbuild: 0.19.12 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@20.5.2) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.5.4 + typescript: 5.2.2 + yargs-parser: 21.1.1 + dev: true + /tsconfig-paths@3.14.2: resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} dependencies: @@ -6927,6 +8335,11 @@ packages: prelude-ls: 1.2.1 dev: true + /type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + /type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} @@ -6937,6 +8350,11 @@ packages: engines: {node: '>=10'} dev: true + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + /type-fest@0.6.0: resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} engines: {node: '>=8'} @@ -6950,6 +8368,14 @@ packages: engines: {node: '>=12.20'} dev: false + /type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + dev: true + /type@1.2.0: resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} dev: true @@ -7012,6 +8438,9 @@ packages: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -7088,6 +8517,15 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.19 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + dev: true + /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -7103,6 +8541,12 @@ packages: extsprintf: 1.3.0 dev: false + /walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + dev: true + /watchpack@2.4.0: resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} engines: {node: '>=10.13.0'} @@ -7207,6 +8651,7 @@ packages: /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} + hasBin: true dependencies: isexe: 2.0.0 dev: true @@ -7231,11 +8676,18 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: false /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + 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'} @@ -7264,7 +8716,6 @@ packages: /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - dev: false /yallist@2.1.2: resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} @@ -7272,7 +8723,6 @@ packages: /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -7292,7 +8742,6 @@ packages: /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - dev: false /yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} @@ -7322,7 +8771,6 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: false /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} @@ -7330,4 +8778,3 @@ packages: /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - dev: true From 962a058f2e7bf89ccfd3fc8efb328c5669da6e27 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Tue, 30 Jan 2024 21:54:30 +0500 Subject: [PATCH 17/22] add tests for api/event/route.ts and use zod schema to validate request --- apps/analytics/app/api/event/route.test.ts | 154 ++++++++++----------- apps/analytics/app/api/event/route.ts | 46 ++---- apps/analytics/db/db.ts | 2 +- apps/analytics/lib/shared_consts.ts | 34 +++++ apps/analytics/package.json | 2 + apps/analytics/scripts/seed.ts | 2 +- pnpm-lock.yaml | 97 ++++++++++--- 7 files changed, 199 insertions(+), 138 deletions(-) create mode 100644 apps/analytics/lib/shared_consts.ts diff --git a/apps/analytics/app/api/event/route.test.ts b/apps/analytics/app/api/event/route.test.ts index 9dd23dd6..839685c0 100644 --- a/apps/analytics/app/api/event/route.test.ts +++ b/apps/analytics/app/api/event/route.test.ts @@ -1,20 +1,12 @@ +import { testApiHandler } from "next-test-api-route-handler"; import insertEvent from "~/db/insertEvent"; -import { Event, POST } from "./route"; - -import { createMocks as _createMocks } from "node-mocks-http"; -import type { RequestOptions, ResponseOptions } from "node-mocks-http"; -import { NextRequest, NextResponse } from "next/server"; - -const createMocks = _createMocks as ( - reqOptions?: RequestOptions, - resOptions?: ResponseOptions - // @ts-ignore: Fixing this: https://github.com/howardabrams/node-mocks-http/issues/245 -) => Mocks; +import * as appHandler from "./route"; +import { Event } from "~/lib/shared_consts"; jest.mock("~/db/insertEvent", () => jest.fn()); describe("/api/event", () => { - test("should insert event to the database", async () => { + it("should insert event to the database", async () => { const eventData = { type: "AppSetup", metadata: { @@ -22,86 +14,84 @@ describe("/api/event", () => { path: "testing path", }, installationId: "21321546453213123", - timestamp: new Date(), - isocode: "US", + timestamp: new Date().toString(), }; - const mockInsertEvent = async (eventData: Event) => { + (insertEvent as jest.Mock).mockImplementation(async (eventData: Event) => { return { data: eventData, error: null }; - }; - - const { req } = createMocks({ - method: "POST", - body: eventData, }); - const response = await POST(req); - expect(mockInsertEvent).toHaveBeenCalledWith(eventData); - expect(response.status).toBe(200); - expect(response.headers).toEqual({ - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "POST, OPTIONS", - "Access-Control-Allow-Headers": "Content-Type, Authorization", + await testApiHandler({ + appHandler, + test: async ({ fetch }) => { + const response = await fetch({ + method: "POST", + body: JSON.stringify(eventData), + }); + expect(insertEvent).toHaveBeenCalledWith({ + ...eventData, + timestamp: new Date(eventData.timestamp), + }); + expect(response.status).toBe(200); + expect(await response.json()).toEqual({ event: eventData }); + }, }); - expect(await response.json()).toEqual(eventData); - }), - test("should return 401 if event is invalid", async () => { - const eventData = { - type: "InvalidEvent", - metadata: { - details: "testing details", - path: "testing path", - }, - timestamp: new Date(), - isocode: "US", - }; + }); - const { req } = createMocks({ - method: "POST", - body: eventData, - }); + it("should return 400 if event is invalid", async () => { + const eventData = { + type: "InvalidEvent", + metadata: { + details: "testing details", + path: "testing path", + }, + timestamp: new Date().toString(), + }; - const response = await POST(req as any); - expect(insertEvent).not.toHaveBeenCalled(); - expect(response.status).toBe(401); - expect(response.headers).toEqual({ - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "POST, OPTIONS", - "Access-Control-Allow-Headers": "Content-Type, Authorization", - }); - expect(await response.json()).toEqual({ error: "Invalid event" }); - }), - test("should return 500 if there is an error inserting the event to the database", async () => { - const eventData = { - type: "AppSetup", - metadata: { - details: "testing details", - path: "testing path", - }, - installationId: "21321546453213123", - timestamp: new Date(), - isocode: "US", - }; + await testApiHandler({ + appHandler, + test: async ({ fetch }) => { + const response = await fetch({ + method: "POST", + body: JSON.stringify(eventData), + }); + expect(response.status).toBe(400); + expect(await response.json()).toEqual({ error: "Invalid event" }); + }, + }); + }); - const mockInsertEvent = async (eventData: Event) => { - return { data: null, error: "Error inserting events" }; - }; + it("should return 500 if there is an error inserting the event to the database", async () => { + const eventData = { + type: "AppSetup", + metadata: { + details: "testing details", + path: "testing path", + }, + installationId: "21321546453213123", + timestamp: new Date().toString(), + }; - const { req } = createMocks({ - method: "POST", - body: eventData, - }); + (insertEvent as jest.Mock).mockImplementation(async (eventData: Event) => { + return { data: null, error: "Error inserting events" }; + }); - const response = await POST(req as any); - expect(mockInsertEvent).toHaveBeenCalledWith(eventData); - expect(response.status).toBe(500); - expect(response.headers).toEqual({ - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "POST, OPTIONS", - "Access-Control-Allow-Headers": "Content-Type, Authorization", - }); - expect(await response.json()).toEqual({ - error: "Error inserting events", - }); + await testApiHandler({ + appHandler, + test: async ({ fetch }) => { + const response = await fetch({ + method: "POST", + body: JSON.stringify(eventData), + }); + expect(insertEvent).toHaveBeenCalledWith({ + ...eventData, + timestamp: new Date(eventData.timestamp), + }); + expect(response.status).toBe(500); + expect(await response.json()).toEqual({ + error: "Error inserting events", + }); + }, }); + }); }); diff --git a/apps/analytics/app/api/event/route.ts b/apps/analytics/app/api/event/route.ts index 2b37f330..d24c8607 100644 --- a/apps/analytics/app/api/event/route.ts +++ b/apps/analytics/app/api/event/route.ts @@ -1,38 +1,6 @@ -import { type DispatchableAnalyticsEvent } from "@codaco/analytics"; import { NextRequest, NextResponse } from "next/server"; -import { type EventInsertType } from "~/db/db"; import insertEvent from "~/db/insertEvent"; -import z from "zod"; - -export const eventTypes = [ - "AppSetup", - "ProtocolInstalled", - "InterviewStarted", - "InterviewCompleted", - "InterviewCompleted", - "DataExported", - "Error", -] as const; - -export type EventType = (typeof eventTypes)[number]; - -export const EventsSchema = z.object({ - type: z.enum(eventTypes), - installationId: z.string(), - timestamp: z.date(), - isocode: z.string().optional(), - message: z.string().optional(), - name: z.string().optional(), - stack: z.string().optional(), - metadata: z - .object({ - details: z.string(), - path: z.string(), - }) - .optional(), -}); - -export type Event = z.infer; +import { EventsSchema } from "~/lib/shared_consts"; const corsHeaders = { "Access-Control-Allow-Origin": "*", @@ -50,17 +18,23 @@ export async function POST(request: NextRequest) { if (parsedEvent.success === false) { return NextResponse.json( { error: "Invalid event" }, - { status: 401, headers: corsHeaders } + { status: 400, headers: corsHeaders } ); } try { - const result = await insertEvent(parsedEvent.data); + const result = await insertEvent({ + ...parsedEvent.data, + timestamp: new Date(parsedEvent.data.timestamp), + }); if (result.error) throw new Error(result.error); return NextResponse.json({ event }, { status: 200, headers: corsHeaders }); } catch (error) { - return NextResponse.json({ error }, { status: 500, headers: corsHeaders }); + return NextResponse.json( + { error: "Error inserting events" }, + { status: 500, headers: corsHeaders } + ); } } diff --git a/apps/analytics/db/db.ts b/apps/analytics/db/db.ts index 0b0a1baa..f5288af8 100644 --- a/apps/analytics/db/db.ts +++ b/apps/analytics/db/db.ts @@ -8,4 +8,4 @@ export const db = drizzle(sql, { schema }); export type EventInsertType = typeof eventsTable.$inferInsert; -// derive a zod schema from the table schema and use it inside analytics package +// Todo: derive a zod schema from the table schema and use it inside analytics package diff --git a/apps/analytics/lib/shared_consts.ts b/apps/analytics/lib/shared_consts.ts new file mode 100644 index 00000000..93a96829 --- /dev/null +++ b/apps/analytics/lib/shared_consts.ts @@ -0,0 +1,34 @@ +// This file is a single source of truth for shared constants +// between the analytics app and analytics package. + +import z from "zod"; + +export const eventTypes = [ + "AppSetup", + "ProtocolInstalled", + "InterviewStarted", + "InterviewCompleted", + "InterviewCompleted", + "DataExported", + "Error", +] as const; + +export type EventType = (typeof eventTypes)[number]; + +export const EventsSchema = z.object({ + type: z.enum(eventTypes), + installationId: z.string(), + timestamp: z.string(), + isocode: z.string().optional(), + message: z.string().optional(), + name: z.string().optional(), + stack: z.string().optional(), + metadata: z + .object({ + details: z.string().optional(), + path: z.string().optional(), + }) + .optional(), +}); + +export type Event = z.infer; diff --git a/apps/analytics/package.json b/apps/analytics/package.json index 96362c30..e424f5a9 100644 --- a/apps/analytics/package.json +++ b/apps/analytics/package.json @@ -7,6 +7,7 @@ "build": "next build", "start": "next start", "lint": "next lint", + "test:event": "jest app/api/event/route.test.ts", "generate": "npx drizzle-kit generate:pg", "migrate": "npx tsx scripts/migrate.ts", "seed": "pnpm run generate && pnpm run migrate && npx tsx scripts/seed.ts" @@ -51,6 +52,7 @@ "drizzle-kit": "^0.20.13", "eslint-config-custom": "workspace:*", "jest": "^29.7.0", + "next-test-api-route-handler": "^4.0.3", "node-mocks-http": "^1.14.1", "tailwindcss": "^3.3.0", "ts-jest": "^29.1.2", diff --git a/apps/analytics/scripts/seed.ts b/apps/analytics/scripts/seed.ts index ef6b1614..a16d4372 100644 --- a/apps/analytics/scripts/seed.ts +++ b/apps/analytics/scripts/seed.ts @@ -2,9 +2,9 @@ import dotenv from "dotenv"; dotenv.config(); import { faker } from "@faker-js/faker"; -import { eventTypes } from "~/app/api/event/route"; import { db, type EventInsertType } from "~/db/db"; import { eventsTable } from "~/db/schema"; +import { eventTypes } from "~/lib/shared_consts"; let installationIds: string[] = []; for (let i = 0; i < 20; i++) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 73169922..8f81b2c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -142,6 +142,9 @@ importers: jest: specifier: ^29.7.0 version: 29.7.0(@types/node@20.5.2) + next-test-api-route-handler: + specifier: ^4.0.3 + version: 4.0.3(next@14.0.1) node-mocks-http: specifier: ^1.14.1 version: 1.14.1 @@ -1616,6 +1619,10 @@ packages: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + /@kamilkisiela/fast-url-parser@1.1.4: + resolution: {integrity: sha512-gbkePEBupNydxCelHCESvFSFM8XPh1Zs/OAVRW/rKpEqPAl5PbOM90Si8mv9bvnR53uPD2s/FiRxdvSejpRJew==} + dev: true + /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: @@ -1664,7 +1671,6 @@ packages: /@next/env@14.0.1: resolution: {integrity: sha512-Ms8ZswqY65/YfcjrlcIwMPD7Rg/dVjdLapMcSHG26W6O67EJDF435ShW4H4LXi1xKO1oRc97tLXUpx8jpLe86A==} - dev: false /@next/eslint-plugin-next@13.4.19: resolution: {integrity: sha512-N/O+zGb6wZQdwu6atMZHbR7T9Np5SUFUjZqCbj0sXm+MwQO35M8TazVB4otm87GkXYs2l6OPwARd3/PUWhZBVQ==} @@ -1684,7 +1690,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@next/swc-darwin-x64@14.0.1: @@ -1693,7 +1698,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm64-gnu@14.0.1: @@ -1702,7 +1706,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm64-musl@14.0.1: @@ -1711,7 +1714,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-x64-gnu@14.0.1: @@ -1720,7 +1722,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-x64-musl@14.0.1: @@ -1729,7 +1730,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-win32-arm64-msvc@14.0.1: @@ -1738,7 +1738,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@next/swc-win32-ia32-msvc@14.0.1: @@ -1747,7 +1746,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: false optional: true /@next/swc-win32-x64-msvc@14.0.1: @@ -1756,7 +1754,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1: @@ -2511,7 +2508,6 @@ packages: resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} dependencies: tslib: 2.6.2 - dev: false /@tanstack/react-table@8.10.7(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-bXhjA7xsTcsW8JPTTYlUg/FuBpn8MNjiEPhkNhIGCUR6iRQM2+WEco4OBpvDeVcR9SE+bmWLzdfiY7bCbCSVuA==} @@ -3100,6 +3096,38 @@ packages: - supports-color dev: true + /@whatwg-node/events@0.1.1: + resolution: {integrity: sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w==} + engines: {node: '>=16.0.0'} + dev: true + + /@whatwg-node/fetch@0.9.16: + resolution: {integrity: sha512-mqasZiUNquRe3ea9+aCAuo81BR6vq5opUKprPilIHTnrg8a21Z1T1OrI+KiMFX8OmwO5HUJe/vro47lpj2JPWQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@whatwg-node/node-fetch': 0.5.5 + urlpattern-polyfill: 10.0.0 + dev: true + + /@whatwg-node/node-fetch@0.5.5: + resolution: {integrity: sha512-LhE0Oo95+dOrrzrJncrpCaR3VHSjJ5Gvkl5g9WVfkPKSKkxCbMeOsRQ+v9LrU9lRvXBJn8JicXqSufKFEpyRbQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@kamilkisiela/fast-url-parser': 1.1.4 + '@whatwg-node/events': 0.1.1 + busboy: 1.6.0 + fast-querystring: 1.1.2 + tslib: 2.6.2 + dev: true + + /@whatwg-node/server@0.9.24: + resolution: {integrity: sha512-ctBZf+DQU9mq62evvAuO3F9cKV7FUR9loJNvirByQreR35xayjpYUjuEok0LI2hwrrxIJmRs8EdnO+wJw4GuOg==} + engines: {node: '>=16.0.0'} + dependencies: + '@whatwg-node/fetch': 0.9.16 + tslib: 2.6.2 + dev: true + /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -3518,7 +3546,6 @@ packages: engines: {node: '>=10.16.0'} dependencies: streamsearch: 1.1.0 - dev: false /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} @@ -3643,7 +3670,6 @@ packages: /client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - dev: false /cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -3735,6 +3761,11 @@ packages: engines: {node: '>= 0.6'} dev: false + /cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + dev: true + /copy-anything@3.0.5: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} @@ -3742,6 +3773,11 @@ packages: is-what: 4.1.16 dev: true + /core-js@3.35.1: + resolution: {integrity: sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw==} + requiresBuild: true + dev: true + /core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} dev: false @@ -5098,6 +5134,10 @@ packages: engines: {'0': node >=0.6.0} dev: false + /fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + dev: true + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true @@ -5130,6 +5170,12 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + dependencies: + fast-decode-uri-component: 1.0.1 + dev: true + /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: @@ -5324,7 +5370,6 @@ packages: /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - dev: false /glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} @@ -6760,6 +6805,22 @@ packages: engines: {node: '>= 0.6'} dev: true + /next-test-api-route-handler@4.0.3(next@14.0.1): + resolution: {integrity: sha512-rfvU7bmaQ36aV99OkOOfQ3EKQDNEZfbhT3HHZim4xmcioBr65ufs2QlhkB+remJyuLVktko5btcO6rG4R81Z7A==} + engines: {node: ^18.18.2 || ^20.10.0 || >=21.2.0} + peerDependencies: + msw: '>=2' + next: '>=9' + peerDependenciesMeta: + msw: + optional: true + dependencies: + '@whatwg-node/server': 0.9.24 + cookie: 0.6.0 + core-js: 3.35.1 + next: 14.0.1(@babel/core@7.22.11)(react-dom@18.2.0)(react@18.2.0) + dev: true + /next-tick@1.1.0: resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} dev: true @@ -6801,7 +6862,6 @@ packages: transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - dev: false /no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -7817,7 +7877,6 @@ packages: /streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} - dev: false /string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} @@ -7922,7 +7981,6 @@ packages: '@babel/core': 7.22.11 client-only: 0.0.1 react: 18.2.0 - dev: false /sucrase@3.34.0: resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==} @@ -8467,6 +8525,10 @@ packages: punycode: 2.3.0 dev: true + /urlpattern-polyfill@10.0.0: + resolution: {integrity: sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==} + dev: true + /use-callback-ref@1.3.0(@types/react@18.2.14)(react@18.2.0): resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==} engines: {node: '>=10'} @@ -8553,7 +8615,6 @@ packages: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - dev: false /wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} From f5919dcdf597a6954b9baf4d6abead67b5c96854 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Tue, 30 Jan 2024 21:58:36 +0500 Subject: [PATCH 18/22] Remove node-mocks-http dependency --- apps/analytics/package.json | 1 - pnpm-lock.yaml | 116 +++++------------------------------- 2 files changed, 14 insertions(+), 103 deletions(-) diff --git a/apps/analytics/package.json b/apps/analytics/package.json index e424f5a9..d7fe9746 100644 --- a/apps/analytics/package.json +++ b/apps/analytics/package.json @@ -53,7 +53,6 @@ "eslint-config-custom": "workspace:*", "jest": "^29.7.0", "next-test-api-route-handler": "^4.0.3", - "node-mocks-http": "^1.14.1", "tailwindcss": "^3.3.0", "ts-jest": "^29.1.2", "tsconfig": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f81b2c4..49ac4c0d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -145,9 +145,6 @@ importers: next-test-api-route-handler: specifier: ^4.0.3 version: 4.0.3(next@14.0.1) - node-mocks-http: - specifier: ^1.14.1 - version: 1.14.1 tailwindcss: specifier: ^3.3.0 version: 3.3.5 @@ -2592,11 +2589,13 @@ packages: dependencies: '@types/connect': 3.4.38 '@types/node': 20.11.10 + dev: false /@types/connect@3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: '@types/node': 20.11.10 + dev: false /@types/cookies@0.7.7: resolution: {integrity: sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==} @@ -2614,6 +2613,7 @@ packages: '@types/qs': 6.9.10 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 + dev: false /@types/express@4.17.14: resolution: {integrity: sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==} @@ -2624,15 +2624,6 @@ packages: '@types/serve-static': 1.15.5 dev: false - /@types/express@4.17.21: - resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} - dependencies: - '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.17.41 - '@types/qs': 6.9.10 - '@types/serve-static': 1.15.5 - dev: true - /@types/graceful-fs@4.1.9: resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} dependencies: @@ -2641,6 +2632,7 @@ packages: /@types/http-errors@2.0.4: resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + dev: false /@types/is-ci@3.0.4: resolution: {integrity: sha512-AkCYCmwlXeuH89DagDCzvCAyltI2v9lh3U3DqSg/GrBYoReAaWwxfXCqMx9UV5MajLZ4ZFwZzV4cABGIxk2XRw==} @@ -2685,9 +2677,11 @@ packages: /@types/mime@1.3.5: resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + dev: false /@types/mime@3.0.4: resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} + dev: false /@types/minimist@1.2.5: resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} @@ -2712,6 +2706,7 @@ packages: resolution: {integrity: sha512-rZEfe/hJSGYmdfX9tvcPMYeYPW2sNl50nsw4jZmRcaG0HIAb0WYEpsB05GOb53vjqpyE9GUhlDQ4jLSoB5q9kg==} dependencies: undici-types: 5.26.5 + dev: false /@types/node@20.5.2: resolution: {integrity: sha512-5j/lXt7unfPOUlrKC34HIaedONleyLtwkKggiD/0uuMfT8gg2EOpg0dz4lCD15Ga7muC+1WzJZAjIB9simWd6Q==} @@ -2738,9 +2733,11 @@ packages: /@types/qs@6.9.10: resolution: {integrity: sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==} + dev: false /@types/range-parser@1.2.7: resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + dev: false /@types/react-dom@18.2.6: resolution: {integrity: sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==} @@ -2765,6 +2762,7 @@ packages: dependencies: '@types/mime': 1.3.5 '@types/node': 20.11.10 + dev: false /@types/serve-static@1.15.5: resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==} @@ -2772,6 +2770,7 @@ packages: '@types/http-errors': 2.0.4 '@types/mime': 3.0.4 '@types/node': 20.11.10 + dev: false /@types/stack-utils@2.0.3: resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -3128,14 +3127,6 @@ packages: tslib: 2.6.2 dev: true - /accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - dev: true - /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -3742,13 +3733,6 @@ packages: /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - /content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - dependencies: - safe-buffer: 5.2.1 - dev: true - /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -3983,11 +3967,6 @@ packages: engines: {node: '>=0.4.0'} dev: false - /depd@1.1.2: - resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} - engines: {node: '>= 0.6'} - dev: true - /detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -5251,11 +5230,6 @@ packages: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: false - /fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - dev: true - /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -6646,11 +6620,6 @@ packages: tiny-lru: 11.2.5 dev: false - /media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - dev: true - /memoizee@0.4.15: resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} dependencies: @@ -6681,10 +6650,6 @@ packages: yargs-parser: 18.1.3 dev: false - /merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - dev: true - /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: true @@ -6693,11 +6658,6 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - /methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - dev: true - /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -6708,18 +6668,14 @@ packages: /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + dev: false /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} dependencies: mime-db: 1.52.0 - - /mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - dev: true + dev: false /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} @@ -6800,11 +6756,6 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - dev: true - /next-test-api-route-handler@4.0.3(next@14.0.1): resolution: {integrity: sha512-rfvU7bmaQ36aV99OkOOfQ3EKQDNEZfbhT3HHZim4xmcioBr65ufs2QlhkB+remJyuLVktko5btcO6rG4R81Z7A==} engines: {node: ^18.18.2 || ^20.10.0 || >=21.2.0} @@ -6883,24 +6834,6 @@ packages: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true - /node-mocks-http@1.14.1: - resolution: {integrity: sha512-mfXuCGonz0A7uG1FEjnypjm34xegeN5+HI6xeGhYKecfgaZhjsmYoLE9LEFmT+53G1n8IuagPZmVnEL/xNsFaA==} - engines: {node: '>=14'} - dependencies: - '@types/express': 4.17.21 - '@types/node': 20.11.10 - accepts: 1.3.8 - content-disposition: 0.5.4 - depd: 1.1.2 - fresh: 0.5.2 - merge-descriptors: 1.0.3 - methods: 1.1.2 - mime: 1.6.0 - parseurl: 1.3.3 - range-parser: 1.2.1 - type-is: 1.6.18 - dev: true - /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} @@ -7120,11 +7053,6 @@ packages: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - /parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - dev: true - /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -7395,11 +7323,6 @@ packages: engines: {node: '>=8'} dev: false - /range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - dev: true - /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -7656,10 +7579,6 @@ packages: has-symbols: 1.0.3 isarray: 2.0.5 - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true - /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: @@ -8426,14 +8345,6 @@ packages: engines: {node: '>=12.20'} dev: false - /type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - dev: true - /type@1.2.0: resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} dev: true @@ -8498,6 +8409,7 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: false /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} From 394b9a6bfb4b15da01b8c464a39af4d1d46ca146 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Wed, 31 Jan 2024 15:34:07 +0500 Subject: [PATCH 19/22] add 'Apply' button for event filters --- .../analytics/EventsTable/TableFilter.tsx | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/apps/analytics/app/_components/analytics/EventsTable/TableFilter.tsx b/apps/analytics/app/_components/analytics/EventsTable/TableFilter.tsx index 73ca6c19..191ebad4 100644 --- a/apps/analytics/app/_components/analytics/EventsTable/TableFilter.tsx +++ b/apps/analytics/app/_components/analytics/EventsTable/TableFilter.tsx @@ -1,6 +1,6 @@ "use client"; -import { type Dispatch, type SetStateAction } from "react"; +import { useState, type Dispatch, type SetStateAction } from "react"; import { Button } from "~/components/ui/button"; import { Checkbox } from "~/components/ui/checkbox"; import { @@ -18,8 +18,10 @@ type TableFilterProps = { }; const TableFilter = ({ eventTypes, setEventTypes }: TableFilterProps) => { + const [options, setOptions] = useState(eventTypes); + const toggleOption = (option: string) => { - setEventTypes((prevState) => + setOptions((prevState) => prevState.map((t) => t.text === option ? { ...t, isSelected: !t.isSelected } : t ) @@ -27,10 +29,10 @@ const TableFilter = ({ eventTypes, setEventTypes }: TableFilterProps) => { }; const toggleAllOptions = (isSelected: boolean) => { - setEventTypes((prevState) => prevState.map((t) => ({ ...t, isSelected }))); + setOptions((prevState) => prevState.map((t) => ({ ...t, isSelected }))); }; - const isAllSelected = eventTypes.every((option) => option.isSelected); + const isAllSelected = options.every((option) => option.isSelected); return ( @@ -53,18 +55,26 @@ const TableFilter = ({ eventTypes, setEventTypes }: TableFilterProps) => { - {eventTypes.map((type) => ( + {options.map((option) => ( ))} + +
From 361ce58e91bc482fa1514b043d6f0fb76dd9b50a Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Wed, 31 Jan 2024 17:58:21 +0500 Subject: [PATCH 20/22] move EventsSchema and types into the analytics package --- apps/analytics/app/api/event/route.test.ts | 2 +- apps/analytics/app/api/event/route.ts | 6 +- apps/analytics/lib/shared_consts.ts | 34 ----------- apps/analytics/scripts/seed.ts | 2 +- packages/analytics/package.json | 8 ++- packages/analytics/src/index.ts | 71 ++++++++++++---------- pnpm-lock.yaml | 59 +++++++++--------- 7 files changed, 78 insertions(+), 104 deletions(-) delete mode 100644 apps/analytics/lib/shared_consts.ts diff --git a/apps/analytics/app/api/event/route.test.ts b/apps/analytics/app/api/event/route.test.ts index 839685c0..a95d815f 100644 --- a/apps/analytics/app/api/event/route.test.ts +++ b/apps/analytics/app/api/event/route.test.ts @@ -1,7 +1,7 @@ import { testApiHandler } from "next-test-api-route-handler"; import insertEvent from "~/db/insertEvent"; import * as appHandler from "./route"; -import { Event } from "~/lib/shared_consts"; +import { Event } from "@codaco/analytics"; jest.mock("~/db/insertEvent", () => jest.fn()); diff --git a/apps/analytics/app/api/event/route.ts b/apps/analytics/app/api/event/route.ts index d24c8607..421fbf26 100644 --- a/apps/analytics/app/api/event/route.ts +++ b/apps/analytics/app/api/event/route.ts @@ -1,6 +1,6 @@ import { NextRequest, NextResponse } from "next/server"; import insertEvent from "~/db/insertEvent"; -import { EventsSchema } from "~/lib/shared_consts"; +import { EventsSchema } from "@codaco/analytics"; const corsHeaders = { "Access-Control-Allow-Origin": "*", @@ -12,7 +12,6 @@ export const runtime = "edge"; export async function POST(request: NextRequest) { const event = (await request.json()) as unknown; - const parsedEvent = EventsSchema.safeParse(event); if (parsedEvent.success === false) { @@ -26,6 +25,9 @@ export async function POST(request: NextRequest) { const result = await insertEvent({ ...parsedEvent.data, timestamp: new Date(parsedEvent.data.timestamp), + message: parsedEvent.data.error?.message, + name: parsedEvent.data.error?.name, + stack: parsedEvent.data.error?.stack, }); if (result.error) throw new Error(result.error); diff --git a/apps/analytics/lib/shared_consts.ts b/apps/analytics/lib/shared_consts.ts deleted file mode 100644 index 93a96829..00000000 --- a/apps/analytics/lib/shared_consts.ts +++ /dev/null @@ -1,34 +0,0 @@ -// This file is a single source of truth for shared constants -// between the analytics app and analytics package. - -import z from "zod"; - -export const eventTypes = [ - "AppSetup", - "ProtocolInstalled", - "InterviewStarted", - "InterviewCompleted", - "InterviewCompleted", - "DataExported", - "Error", -] as const; - -export type EventType = (typeof eventTypes)[number]; - -export const EventsSchema = z.object({ - type: z.enum(eventTypes), - installationId: z.string(), - timestamp: z.string(), - isocode: z.string().optional(), - message: z.string().optional(), - name: z.string().optional(), - stack: z.string().optional(), - metadata: z - .object({ - details: z.string().optional(), - path: z.string().optional(), - }) - .optional(), -}); - -export type Event = z.infer; diff --git a/apps/analytics/scripts/seed.ts b/apps/analytics/scripts/seed.ts index a16d4372..cd190615 100644 --- a/apps/analytics/scripts/seed.ts +++ b/apps/analytics/scripts/seed.ts @@ -4,7 +4,7 @@ dotenv.config(); import { faker } from "@faker-js/faker"; import { db, type EventInsertType } from "~/db/db"; import { eventsTable } from "~/db/schema"; -import { eventTypes } from "~/lib/shared_consts"; +import { eventTypes } from "@codaco/analytics"; let installationIds: string[] = []; for (let i = 0; i < 20; i++) { diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 7122209a..cff55365 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -11,8 +11,8 @@ "dev": "npm run build -- --watch" }, "peerDependencies": { - "next": "13 || 14", - "@maxmind/geoip2-node": "^5.0.0" + "@maxmind/geoip2-node": "^5.0.0", + "next": "13 || 14" }, "devDependencies": { "eslint-config-custom": "workspace:*", @@ -20,5 +20,7 @@ "tsup": "^7.2.0", "typescript": "^5.3.2" }, - "dependencies": {} + "dependencies": { + "zod": "^3.22.4" + } } diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index b105f6ae..321b0a71 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -1,45 +1,52 @@ import type { NextRequest } from "next/server"; import { WebServiceClient } from "@maxmind/geoip2-node"; import { ensureError, getBaseUrl } from "./utils"; - -type GeoLocation = { - countryCode: string; -}; - -export type AnalyticsEventBase = { - type: - | "DataExported" - | "InterviewCompleted" - | "InterviewStarted" - | "ProtocolInstalled" - | "AppSetup" - | "Error"; +import z from "zod"; + +export const eventTypes = [ + "AppSetup", + "ProtocolInstalled", + "InterviewStarted", + "InterviewCompleted", + "DataExported", + "Error", +] as const; + +export type EventType = (typeof eventTypes)[number]; +type EventTypeWithoutError = Exclude; + +export const EventsSchema = z.object({ + type: z.enum(eventTypes), + installationId: z.string(), + timestamp: z.string(), + isocode: z.string().optional(), + error: z + .object({ + message: z.string(), + name: z.string(), + stack: z.string().optional(), + }) + .optional(), + metadata: z.record(z.unknown()).optional(), +}); + +export type Event = z.infer; + +export type AnalyticsEvent = { + type: EventTypeWithoutError; metadata?: Record; }; -export type AnalyticsEvent = AnalyticsEventBase & { - type: - | "InterviewCompleted" - | "DataExported" - | "InterviewStarted" - | "ProtocolInstalled" - | "AppSetup"; -}; - -export type AnalyticsError = AnalyticsEventBase & { +export type AnalyticsError = { type: "Error"; error: Error; + metadata?: Record; }; export type AnalyticsEventOrError = AnalyticsEvent | AnalyticsError; export type AnalyticsEventOrErrorWithTimestamp = AnalyticsEventOrError & { - timestamp: Date; -}; - -export type DispatchableAnalyticsEvent = AnalyticsEventOrErrorWithTimestamp & { - installationId: string; - geolocation?: GeoLocation; + timestamp: string; }; type RouteHandlerConfiguration = { @@ -65,12 +72,10 @@ export const createRouteHandler = ({ const { country } = await maxMindClient.country(ip); const countryCode = country?.isoCode ?? "Unknown"; - const dispatchableEvent: DispatchableAnalyticsEvent = { + const dispatchableEvent: Event = { ...event, installationId, - geolocation: { - countryCode, - }, + isocode: countryCode, }; // Forward to microservice diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9933a3d9..8070c31d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,7 +26,7 @@ importers: version: link:packages/tsconfig turbo: specifier: latest - version: 1.11.3 + version: 1.12.0 apps/analytics: dependencies: @@ -166,6 +166,9 @@ importers: next: specifier: 13 || 14 version: 14.0.1(@babel/core@7.22.11)(react-dom@18.2.0)(react@18.2.0) + zod: + specifier: ^3.22.4 + version: 3.22.4 devDependencies: eslint-config-custom: specifier: workspace:* @@ -778,14 +781,12 @@ packages: react: ^17.0.2 || ^18.0.0-0 react-dom: ^17.0.2 || ^18.0.0-0 dependencies: - '@clerk/backend': 0.37.3(react@18.2.0) '@clerk/clerk-react': 4.30.3(react@18.2.0) '@clerk/clerk-sdk-node': 4.13.7(react@18.2.0) '@clerk/shared': 1.3.1(react@18.2.0) '@clerk/types': 3.60.0 - next: 14.0.1(react-dom@18.2.0)(react@18.2.0) - + next: 14.0.1(@babel/core@7.22.11)(react-dom@18.2.0)(react@18.2.0) path-to-regexp: 6.2.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -1275,7 +1276,7 @@ packages: ajv: 6.12.6 debug: 4.3.4 espree: 9.6.1 - globals: 13.23.0 + globals: 13.24.0 ignore: 5.2.4 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -2630,7 +2631,6 @@ packages: dependencies: '@types/node': 20.5.2 '@types/qs': 6.9.11 - '@types/range-parser': 1.2.7 '@types/send': 0.17.4 dev: false @@ -2806,8 +2806,7 @@ packages: '@types/yargs-parser': 21.0.3 dev: true - /@typescript-eslint/eslint-plugin@6.5.0(@typescript-eslint/parser@6.5.0)(eslint@8.52.0)(typescript@5.2.2): - + /@typescript-eslint/eslint-plugin@6.5.0(@typescript-eslint/parser@6.5.0)(eslint@8.56.0)(typescript@5.2.2): resolution: {integrity: sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2827,7 +2826,7 @@ packages: debug: 4.3.4 eslint: 8.56.0 graphemer: 1.4.0 - ignore: 5.2.4 + ignore: 5.3.0 natural-compare: 1.4.0 semver: 7.5.4 ts-api-utils: 1.0.2(typescript@5.2.2) @@ -5450,7 +5449,7 @@ packages: dependencies: dir-glob: 3.0.1 fast-glob: 3.3.1 - ignore: 5.2.4 + ignore: 5.3.0 merge2: 1.4.1 slash: 4.0.0 dev: true @@ -8286,64 +8285,64 @@ packages: yargs: 17.7.2 dev: false - /turbo-darwin-64@1.11.3: - resolution: {integrity: sha512-IsOOg2bVbIt3o/X8Ew9fbQp5t1hTHN3fGNQYrPQwMR2W1kIAC6RfbVD4A9OeibPGyEPUpwOH79hZ9ydFH5kifw==} + /turbo-darwin-64@1.12.0: + resolution: {integrity: sha512-z3zZPFQAPO+vBks7Ybir33ovaJP8U/Ikr/NMGsewHsL5SjetHsd9ZAs6G1zBbAgWXcy7COpgWZbQF0Giq/6hJA==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-darwin-arm64@1.11.3: - resolution: {integrity: sha512-FsJL7k0SaPbJzI/KCnrf/fi3PgCDCjTliMc/kEFkuWVA6Httc3Q4lxyLIIinz69q6JTx8wzh6yznUMzJRI3+dg==} + /turbo-darwin-arm64@1.12.0: + resolution: {integrity: sha512-vVDDjw7rjVHB+S/CrHiDoAMXWsqjG7mVCCXWvL8AhDhTT1u4a3KS2dWsqUFprbzC1X4cHnzmGktXfAo8ro5Mng==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-linux-64@1.11.3: - resolution: {integrity: sha512-SvW7pvTVRGsqtSkII5w+wriZXvxqkluw5FO/MNAdFw0qmoov+PZ237+37/NgArqE3zVn1GX9P6nUx9VO+xcQAg==} + /turbo-linux-64@1.12.0: + resolution: {integrity: sha512-CQMr/B9T1d5JCOgCQk/EX3oUzlNlgUdMaH1is7eU8lBz+NIc1vbC9bunNwgFcM+WsjZORk4ffvYjKx49VtmOkQ==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-linux-arm64@1.11.3: - resolution: {integrity: sha512-YhUfBi1deB3m+3M55X458J6B7RsIS7UtM3P1z13cUIhF+pOt65BgnaSnkHLwETidmhRh8Dl3GelaQGrB3RdCDw==} + /turbo-linux-arm64@1.12.0: + resolution: {integrity: sha512-sDHezEXcZjZ+aRIN5gzCH0qQjfSnHvnmN5Rr/V+TAk+SeyALh7uRcUxzTrWcl85sK4qDLna9o7bkllgtXXy8LA==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-windows-64@1.11.3: - resolution: {integrity: sha512-s+vEnuM2TiZuAUUUpmBHDr6vnNbJgj+5JYfnYmVklYs16kXh+EppafYQOAkcRIMAh7GjV3pLq5/uGqc7seZeHA==} + /turbo-windows-64@1.12.0: + resolution: {integrity: sha512-yPkL+mRmG22q5V1qRWJkt/U/qK3dYUUiw4aHrmaNm9+5vzDxcZo2Ft60AZsyrl2HMFI6aHBZOjCct/a2Jmc14g==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /turbo-windows-arm64@1.11.3: - resolution: {integrity: sha512-ZR5z5Zpc7cASwfdRAV5yNScCZBsgGSbcwiA/u3farCacbPiXsfoWUkz28iyrx21/TRW0bi6dbsB2v17swa8bjw==} + /turbo-windows-arm64@1.12.0: + resolution: {integrity: sha512-v0O71TaAja9l3W7DEnHRhehUatgNfu4B24QNBEkHyR6B0w8pxNB1Vorv9auubXMcZzP/nhwtsQTM6U2ZINAd6A==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /turbo@1.11.3: - resolution: {integrity: sha512-RCJOUFcFMQNIGKSjC9YmA5yVP1qtDiBA0Lv9VIgrXraI5Da1liVvl3VJPsoDNIR9eFMyA/aagx1iyj6UWem5hA==} + /turbo@1.12.0: + resolution: {integrity: sha512-gOrh05sU7Njws7MMklBH71TZNx0LLGD+sjp+o4d/m4cngQ6r9/l7/+fZichXd4suh8Id700p9aTMiF80uh69Xg==} hasBin: true optionalDependencies: - turbo-darwin-64: 1.11.3 - turbo-darwin-arm64: 1.11.3 - turbo-linux-64: 1.11.3 - turbo-linux-arm64: 1.11.3 - turbo-windows-64: 1.11.3 - turbo-windows-arm64: 1.11.3 + turbo-darwin-64: 1.12.0 + turbo-darwin-arm64: 1.12.0 + turbo-linux-64: 1.12.0 + turbo-linux-arm64: 1.12.0 + turbo-windows-64: 1.12.0 + turbo-windows-arm64: 1.12.0 dev: true /type-check@0.4.0: From cc8e4e1803204caa5cd3bf69d57110043d7631b0 Mon Sep 17 00:00:00 2001 From: mrkarimoff Date: Wed, 31 Jan 2024 18:02:26 +0500 Subject: [PATCH 21/22] bump analytics package version to 3.1.0 --- packages/analytics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/analytics/package.json b/packages/analytics/package.json index cff55365..8a75900e 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -1,6 +1,6 @@ { "name": "@codaco/analytics", - "version": "3.0.0", + "version": "3.1.0", "module": "./dist/index.mjs", "types": "./dist/index.d.mts", "author": "Complex Data Collective ", From 3940b294a4b8dc2a7a8aec76f2499f2a2271cb0a Mon Sep 17 00:00:00 2001 From: Joshua Melville Date: Thu, 1 Feb 2024 10:27:17 +0200 Subject: [PATCH 22/22] Update tsconfig.json - remove es6 so that app can inherit from es2020 in base.json Drizzle issue here:https://github.com/drizzle-team/drizzle-orm/issues/803 Drizzle requires target newer than es5, but next was shipping es5 until recently (even though it didn't use it). Fix is to remove override in this config file and let it use the base.json target, which is es2020. --- apps/analytics/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/analytics/tsconfig.json b/apps/analytics/tsconfig.json index 39088ae7..976477c8 100644 --- a/apps/analytics/tsconfig.json +++ b/apps/analytics/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "tsconfig/nextjs.json", "compilerOptions": { - "target": "ES6", // update to ES6 because of Drizzle issue here:https://github.com/drizzle-team/drizzle-orm/issues/803 "lib": ["dom", "dom.iterable", "esnext"], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true,