diff --git a/scripts/.env.example b/scripts/.env.example index 5b41a99..4160342 100644 --- a/scripts/.env.example +++ b/scripts/.env.example @@ -1,2 +1,3 @@ SUPABASE_PROJECT_ID="TODO" -SUPABASE_FUNCTIONS_KEY="TODO" \ No newline at end of file +SUPABASE_SERVICE_ROLE_KEY="TODO" +SUPABASE_ANON_KEY="TODO" \ No newline at end of file diff --git a/scripts/deploy-and-run/fetch-mp-data.sh b/scripts/deploy-and-run/fetch-mp-data.sh index 9b2655b..7593786 100644 --- a/scripts/deploy-and-run/fetch-mp-data.sh +++ b/scripts/deploy-and-run/fetch-mp-data.sh @@ -8,4 +8,4 @@ source ../lib/functions/run.sh FUNCTION_NAME="fetch-mp-data" deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" -run "$SUPABASE_PROJECT_ID" "$SUPABASE_FUNCTIONS_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/fill-debate-bill-ids.sh b/scripts/deploy-and-run/fill-debate-bill-ids.sh new file mode 100644 index 0000000..c498205 --- /dev/null +++ b/scripts/deploy-and-run/fill-debate-bill-ids.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +source ../.env +source ../lib/functions/deploy.sh +source ../lib/functions/run.sh + +FUNCTION_NAME="fill-debate-bill-ids" + +deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/fill-debate-speaker-ids.sh b/scripts/deploy-and-run/fill-debate-speaker-ids.sh new file mode 100644 index 0000000..5c91dda --- /dev/null +++ b/scripts/deploy-and-run/fill-debate-speaker-ids.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +source ../.env +source ../lib/functions/deploy.sh +source ../lib/functions/run.sh + +FUNCTION_NAME="fill-debate-speaker-ids" + +deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/generate-bills-summary.sh b/scripts/deploy-and-run/generate-bills-summary.sh index 4398e18..d758ad8 100644 --- a/scripts/deploy-and-run/generate-bills-summary.sh +++ b/scripts/deploy-and-run/generate-bills-summary.sh @@ -8,4 +8,4 @@ source ../lib/functions/run.sh FUNCTION_NAME="generate-bills-summary" deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" -run "$SUPABASE_PROJECT_ID" "$SUPABASE_FUNCTIONS_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/generate-debate-summary.sh b/scripts/deploy-and-run/generate-debate-summary.sh new file mode 100644 index 0000000..a115320 --- /dev/null +++ b/scripts/deploy-and-run/generate-debate-summary.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +source ../.env +source ../lib/functions/deploy.sh +source ../lib/functions/run.sh + +FUNCTION_NAME="generate-debate-summary" + +deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/per-1-hour.sh b/scripts/deploy-and-run/per-1-hour.sh index b602e7b..49cdb78 100644 --- a/scripts/deploy-and-run/per-1-hour.sh +++ b/scripts/deploy-and-run/per-1-hour.sh @@ -8,4 +8,4 @@ source ../lib/functions/run.sh FUNCTION_NAME="per-1-hour" deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" -run "$SUPABASE_PROJECT_ID" "$SUPABASE_FUNCTIONS_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/per-10-min.sh b/scripts/deploy-and-run/per-10-min.sh index 1ecd4c2..569d1c6 100644 --- a/scripts/deploy-and-run/per-10-min.sh +++ b/scripts/deploy-and-run/per-10-min.sh @@ -8,4 +8,4 @@ source ../lib/functions/run.sh FUNCTION_NAME="per-10-min" deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" -run "$SUPABASE_PROJECT_ID" "$SUPABASE_FUNCTIONS_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/scrape-bills-introduced.sh b/scripts/deploy-and-run/scrape-bills-introduced.sh index 9363b54..95accd8 100644 --- a/scripts/deploy-and-run/scrape-bills-introduced.sh +++ b/scripts/deploy-and-run/scrape-bills-introduced.sh @@ -8,4 +8,4 @@ source ../lib/functions/run.sh FUNCTION_NAME="scrape-bills-introduced" deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" -run "$SUPABASE_PROJECT_ID" "$SUPABASE_FUNCTIONS_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/scrape-bills-pdf.sh b/scripts/deploy-and-run/scrape-bills-pdf.sh index 18d9463..a8943c4 100644 --- a/scripts/deploy-and-run/scrape-bills-pdf.sh +++ b/scripts/deploy-and-run/scrape-bills-pdf.sh @@ -8,4 +8,4 @@ source ../lib/functions/run.sh FUNCTION_NAME="scrape-bills-pdf" deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" -run "$SUPABASE_PROJECT_ID" "$SUPABASE_FUNCTIONS_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/scrape-sitting-dates.sh b/scripts/deploy-and-run/scrape-sitting-dates.sh new file mode 100644 index 0000000..6b8eb02 --- /dev/null +++ b/scripts/deploy-and-run/scrape-sitting-dates.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +source ../.env +source ../lib/functions/deploy.sh +source ../lib/functions/run.sh + +FUNCTION_NAME="scrape-sitting-dates" + +deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/scrape-sitting-report.sh b/scripts/deploy-and-run/scrape-sitting-report.sh index 71cbec4..2ba562e 100644 --- a/scripts/deploy-and-run/scrape-sitting-report.sh +++ b/scripts/deploy-and-run/scrape-sitting-report.sh @@ -8,4 +8,4 @@ source ../lib/functions/run.sh FUNCTION_NAME="scrape-sitting-report" deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" -run "$SUPABASE_PROJECT_ID" "$SUPABASE_FUNCTIONS_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file +run "$SUPABASE_PROJECT_ID" "$SUPABASE_SERVICE_ROLE_KEY" "$FUNCTION_NAME" "{}" \ No newline at end of file diff --git a/scripts/deploy-and-run/search.sh b/scripts/deploy-and-run/search.sh new file mode 100644 index 0000000..641d9d6 --- /dev/null +++ b/scripts/deploy-and-run/search.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +source ../.env +source ../lib/functions/deploy.sh +source ../lib/functions/run.sh + +FUNCTION_NAME="search" + +deploy "$SUPABASE_PROJECT_ID" "$FUNCTION_NAME" +run "$SUPABASE_PROJECT_ID" "$SUPABASE_ANON_KEY" "$FUNCTION_NAME" '{"query": "30 by 30"}' \ No newline at end of file diff --git a/site/.env.example b/site/.env.example index 2197d26..758e94d 100644 --- a/site/.env.example +++ b/site/.env.example @@ -1,4 +1,5 @@ NEXT_PUBLIC_SUPABASE_URL="TODO" NEXT_PUBLIC_SUPABASE_ANON_KEY="TODO" -SITE_NAME="Parliament Summary" -ITEMS_PER_PAGE="20" \ No newline at end of file +NEXT_PUBLIC_SITE_NAME="Parliament Summary" +NEXT_PUBLIC_ITEMS_PER_PAGE="20" +NEXT_PUBLIC_REPOSITORY_URL="https://github.com/limdingwen/parliament-summary" \ No newline at end of file diff --git a/site/package-lock.json b/site/package-lock.json index d9d5279..c4ee134 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -30,11 +30,12 @@ "dayjs": "^1.11.12", "embla-carousel-react": "^8.1.7", "moment": "^2.30.1", - "next": "14.1.0", + "next": "^14.2.5", "react": "^18", "react-dom": "^18", "react-markdown": "^9.0.1", - "recharts": "^2.12.7" + "recharts": "^2.12.7", + "use-debounce": "^10.0.2" }, "devDependencies": { "@cloudflare/next-on-pages": "^1.12.1", @@ -51,7 +52,7 @@ "postcss-simple-vars": "^7.0.1", "tailwindcss": "^3.3.0", "typescript": "^5", - "vercel": "^35.1.0", + "vercel": "^32.3.0", "wrangler": "^3.65.1" } }, @@ -321,49 +322,52 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@edge-runtime/format": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@edge-runtime/format/-/format-2.2.1.tgz", - "integrity": "sha512-JQTRVuiusQLNNLe2W9tnzBlV/GvSVcozLl4XZHk5swnRZ/v6jp8TqR8P7sqmJsQqblDZ3EztcWmLDbhRje/+8g==", + "node_modules/@edge-runtime/cookies": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@edge-runtime/cookies/-/cookies-3.4.1.tgz", + "integrity": "sha512-z27BvgPxI73CgSlxU/NAUf1Q/shnqi6cobHEowf6VuLdSjGR3NjI2Y5dZUIBbK2zOJVZbXcHsVzJjz8LklteFQ==", "dev": true, "engines": { "node": ">=16" } }, - "node_modules/@edge-runtime/node-utils": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@edge-runtime/node-utils/-/node-utils-2.3.0.tgz", - "integrity": "sha512-uUtx8BFoO1hNxtHjp3eqVPC/mWImGb2exOfGjMLUoipuWgjej+f4o/VP4bUI8U40gu7Teogd5VTeZUkGvJSPOQ==", + "node_modules/@edge-runtime/format": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/format/-/format-2.2.0.tgz", + "integrity": "sha512-gPrS6AVw/qJJL0vcxMXv4kFXCU3ZTCD1uuJpwX15YxHV8BgU9OG5v9LrkkXcr96PBT/9epypfNJMhlWADuEziw==", "dev": true, "engines": { "node": ">=16" } }, - "node_modules/@edge-runtime/ponyfill": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@edge-runtime/ponyfill/-/ponyfill-2.4.2.tgz", - "integrity": "sha512-oN17GjFr69chu6sDLvXxdhg0Qe8EZviGSuqzR9qOiKh4MhFYGdBBcqRNzdmYeAdeRzOW2mM9yil4RftUQ7sUOA==", + "node_modules/@edge-runtime/node-utils": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@edge-runtime/node-utils/-/node-utils-2.2.1.tgz", + "integrity": "sha512-RUl/439BHKshkhSGFRlZ1kzy68wL4mn8VNKDSZr3p0tciyZ33Mjfpl+vofqnHqXRmDI6nLnZpfJvhY3D88o0pA==", "dev": true, + "dependencies": { + "@edge-runtime/cookies": "3.4.1" + }, "engines": { "node": ">=16" } }, "node_modules/@edge-runtime/primitives": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-4.1.0.tgz", - "integrity": "sha512-Vw0lbJ2lvRUqc7/soqygUX216Xb8T3WBZ987oywz6aJqRxcwSVWwr9e+Nqo2m9bxobA9mdbWNNoRY6S9eko1EQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-3.1.1.tgz", + "integrity": "sha512-ROO22py+KdAfzqWZu6CtVMC4qV6mS0W1jPI51jGXE+uenyBUN7cQTWB9ReQc8Bm4cnjqmhajvpqEx3j7Y9iSOg==", "dev": true, "engines": { "node": ">=16" } }, "node_modules/@edge-runtime/vm": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-3.2.0.tgz", - "integrity": "sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-3.1.1.tgz", + "integrity": "sha512-6NJRRG04/91qnWLZj+wZm27q6fJkTbkZdIJdo/Ig++GTxkAv8Wh/45nIcz9Xg7AzIAMpAkflFdiCrCoZ3hp1Iw==", "dev": true, "dependencies": { - "@edge-runtime/primitives": "4.1.0" + "@edge-runtime/primitives": "3.1.1" }, "engines": { "node": ">=16" @@ -1195,112 +1199,10 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@next/env": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.0.tgz", - "integrity": "sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==" + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", + "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==" }, "node_modules/@next/eslint-plugin-next": { "version": "14.1.0", @@ -1312,9 +1214,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.0.tgz", - "integrity": "sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", + "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", "cpu": [ "arm64" ], @@ -1327,9 +1229,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.0.tgz", - "integrity": "sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", + "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", "cpu": [ "x64" ], @@ -1342,9 +1244,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.0.tgz", - "integrity": "sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", + "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", "cpu": [ "arm64" ], @@ -1357,9 +1259,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.0.tgz", - "integrity": "sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", + "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", "cpu": [ "arm64" ], @@ -1372,9 +1274,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.0.tgz", - "integrity": "sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz", + "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==", "cpu": [ "x64" ], @@ -1387,9 +1289,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.0.tgz", - "integrity": "sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz", + "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==", "cpu": [ "x64" ], @@ -1402,9 +1304,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.0.tgz", - "integrity": "sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", + "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", "cpu": [ "arm64" ], @@ -1417,9 +1319,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.0.tgz", - "integrity": "sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", + "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", "cpu": [ "ia32" ], @@ -1432,9 +1334,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.0.tgz", - "integrity": "sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", + "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", "cpu": [ "x64" ], @@ -1638,11 +1540,17 @@ "@supabase/storage-js": "2.6.0" } }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" + }, "node_modules/@swc/helpers": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", - "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", "dependencies": { + "@swc/counter": "^0.1.3", "tslib": "^2.4.0" } }, @@ -2032,15 +1940,6 @@ "url": "https://github.com/sponsors/ueberdosis" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/@ts-morph/common": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.11.1.tgz", @@ -2053,18 +1952,6 @@ "path-browserify": "^1.0.1" } }, - "node_modules/@ts-morph/common/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", @@ -2393,95 +2280,15 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@vercel/build-utils": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-8.3.5.tgz", - "integrity": "sha512-lJNcA1XKMbQg6npC8grQBEVg11w8BSBr8bXUSZokYmvtNXheL/5cKGAD01Uba9x1P/ae9lJ9zDorpoSq4AWSfw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-7.2.1.tgz", + "integrity": "sha512-WCqSBCPNlANEOsmroCzCZq6ZxArV20RHBbdaZzhZjkGtEReSZx5BSOsrnkewFJFuu5pNGYegAaVi0VCkA1irZQ==", "dev": true }, "node_modules/@vercel/error-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vercel/error-utils/-/error-utils-2.0.2.tgz", - "integrity": "sha512-Sj0LFafGpYr6pfCqrQ82X6ukRl5qpmVrHM/191kNYFqkkB9YkjlMAj6QcEsvCG259x4QZ7Tya++0AB85NDPbKQ==", - "dev": true - }, - "node_modules/@vercel/fun": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vercel/fun/-/fun-1.1.0.tgz", - "integrity": "sha512-SpuPAo+MlAYMtcMcC0plx7Tv4Mp7SQhJJj1iIENlOnABL24kxHpL09XLQMGzZIzIW7upR8c3edwgfpRtp+dhVw==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2.0.0", - "async-listen": "1.2.0", - "debug": "4.1.1", - "execa": "3.2.0", - "fs-extra": "8.1.0", - "generic-pool": "3.4.2", - "micro": "9.3.5-canary.3", - "ms": "2.1.1", - "node-fetch": "2.6.7", - "path-match": "1.2.4", - "promisepipe": "3.0.0", - "semver": "7.3.5", - "stat-mode": "0.3.0", - "stream-to-promise": "2.2.0", - "tar": "4.4.18", - "tree-kill": "1.2.2", - "uid-promise": "1.0.0", - "uuid": "3.3.2", - "xdg-app-paths": "5.1.0", - "yauzl-promise": "2.1.3" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@vercel/fun/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/@vercel/fun/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@vercel/fun/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "node_modules/@vercel/fun/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@vercel/fun/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@vercel/error-utils/-/error-utils-2.0.1.tgz", + "integrity": "sha512-ZUVpRFArh5eyKpJmdfEuCaMpZKQvZgUq0pQ7PdK8m5FgRYEvF4I0TMJH3JnkbYaMMUH82aYWZr+/hFJtEBcmTQ==", "dev": true }, "node_modules/@vercel/gatsby-plugin-vercel-analytics": { @@ -2494,14 +2301,14 @@ } }, "node_modules/@vercel/gatsby-plugin-vercel-builder": { - "version": "2.0.39", - "resolved": "https://registry.npmjs.org/@vercel/gatsby-plugin-vercel-builder/-/gatsby-plugin-vercel-builder-2.0.39.tgz", - "integrity": "sha512-rvShSeoiUvw1JoQ5r9EJBwELmA6lZDH2agG9KCBgKowd8YQZIm7r3DddvWPJ8s2x7P4kv0eCbr5e89Z2wsiygw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vercel/gatsby-plugin-vercel-builder/-/gatsby-plugin-vercel-builder-2.0.6.tgz", + "integrity": "sha512-ne6Xkqm/Naxc6KON3RwhE3irJVevCRwdMp+VMSXgC8ik+q9tWxtmMa4tbdnregKWEk1cw3ToHN6MkXRdcchpYA==", "dev": true, "dependencies": { "@sinclair/typebox": "0.25.24", - "@vercel/build-utils": "8.3.5", - "@vercel/routing-utils": "3.1.0", + "@vercel/build-utils": "7.2.1", + "@vercel/routing-utils": "3.0.0", "esbuild": "0.14.47", "etag": "1.8.1", "fs-extra": "11.1.0" @@ -2862,51 +2669,16 @@ "node": ">=12" } }, - "node_modules/@vercel/gatsby-plugin-vercel-builder/node_modules/fs-extra": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", - "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@vercel/gatsby-plugin-vercel-builder/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@vercel/gatsby-plugin-vercel-builder/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/@vercel/go": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@vercel/go/-/go-3.1.1.tgz", - "integrity": "sha512-mrzomNYltxkjvtUmaYry5YEyvwTz6c/QQHE5Gr/pPGRIniUiP6T6OFOJ49RBN7e6pRXaNzHPVuidiuBhvHh5+Q==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@vercel/go/-/go-3.0.2.tgz", + "integrity": "sha512-g1i1X/h6SfIiCj+wVfNPZPqxhoOQbQXDximoGywTgKpRWZD40ReAjYIL4siemsHHX26ihhaJX2eHX8vWyQ57EQ==", "dev": true }, "node_modules/@vercel/hydrogen": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@vercel/hydrogen/-/hydrogen-1.0.4.tgz", - "integrity": "sha512-Sc0lpmI/J6O3o2cL75k8klL7ir2gi6kYI92O5+MrR3hh4fwz/atUIL9UWsTGuFjKTm69VAoJrmn3VKf0/0SGLw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@vercel/hydrogen/-/hydrogen-1.0.1.tgz", + "integrity": "sha512-4PYk4LeIWPTjGtgnxvB0Hdw7aqCau843/96K2xX3z9pa0Hn//pUnZBMz2jrs5MRseCm1Li1LdQAK3u8/vaUnVQ==", "dev": true, "dependencies": { "@vercel/static-config": "3.0.0", @@ -2914,24 +2686,23 @@ } }, "node_modules/@vercel/next": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@vercel/next/-/next-4.3.6.tgz", - "integrity": "sha512-qUHp79xX07qYtz7DGSogyWgEMrf+eu/IGV/92YnVA1xzDBogIFc8XFvMlN8QwDrsWWsR+I2eMSiGD+P8znlsaA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@vercel/next/-/next-4.0.7.tgz", + "integrity": "sha512-/YSXwhJk5+fhUCt9FKY8NM9iHpQG6gV7IGbPnkwY11+Pmuf5igXU+q5Kpe2cHWWrJNuK/ZT/ctRU8ArP+1ToEw==", "dev": true, "dependencies": { - "@vercel/nft": "0.27.3" + "@vercel/nft": "0.24.1" } }, "node_modules/@vercel/nft": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.27.3.tgz", - "integrity": "sha512-oySTdDSzUAFDXpsSLk9Q943o+/Yu/+TCFxnehpFQEf/3khi2stMpTHPVNwFdvZq/Z4Ky93lE+MGHpXCRpMkSCA==", + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.24.1.tgz", + "integrity": "sha512-bGYrA/w98LNl9edxXcAezKs+Ixa2a+RkAvxXK38gH3815v+WkNa2AGY+wQv59vu2f9il9+zIKj6YrnlYIbh+jA==", "dev": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.5", "@rollup/pluginutils": "^4.0.0", "acorn": "^8.6.0", - "acorn-import-attributes": "^1.9.5", "async-sema": "^3.1.1", "bindings": "^1.4.0", "estree-walker": "2.0.2", @@ -2985,48 +2756,38 @@ } }, "node_modules/@vercel/node": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vercel/node/-/node-3.2.7.tgz", - "integrity": "sha512-/eWXgkkjBm1Es6oRmltw5m0SLT8tnOdlSKYpQhPfpJlWVzLb8h3cWhTS+cSsnn3gZ0c6w4XSjiZBbGKQJevxoQ==", - "dev": true, - "dependencies": { - "@edge-runtime/node-utils": "2.3.0", - "@edge-runtime/primitives": "4.1.0", - "@edge-runtime/vm": "3.2.0", - "@types/node": "16.18.11", - "@vercel/build-utils": "8.3.5", - "@vercel/error-utils": "2.0.2", - "@vercel/nft": "0.27.3", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@vercel/node/-/node-3.0.6.tgz", + "integrity": "sha512-QYsmc5rtuyjSAryAo4qRwsEw9NXhapAbF/OBM0Fdq3kPiwHDfbElJpb7UbeQH19u3q4d+E7Z6wZTbO6bsrzw4g==", + "dev": true, + "dependencies": { + "@edge-runtime/node-utils": "2.2.1", + "@edge-runtime/primitives": "3.1.1", + "@edge-runtime/vm": "3.1.1", + "@types/node": "14.18.33", + "@vercel/build-utils": "7.2.1", + "@vercel/error-utils": "2.0.1", + "@vercel/nft": "0.24.1", "@vercel/static-config": "3.0.0", "async-listen": "3.0.0", - "cjs-module-lexer": "1.2.3", - "edge-runtime": "2.5.9", - "es-module-lexer": "1.4.1", + "edge-runtime": "2.5.1", "esbuild": "0.14.47", "etag": "1.8.1", + "exit-hook": "2.2.1", "node-fetch": "2.6.9", "path-to-regexp": "6.2.1", "ts-morph": "12.0.0", "ts-node": "10.9.1", "typescript": "4.9.5", - "undici": "5.28.4" + "undici": "5.23.0" } }, "node_modules/@vercel/node/node_modules/@types/node": { - "version": "16.18.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", - "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "version": "14.18.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", "dev": true }, - "node_modules/@vercel/node/node_modules/async-listen": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/async-listen/-/async-listen-3.0.0.tgz", - "integrity": "sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, "node_modules/@vercel/node/node_modules/esbuild": { "version": "0.14.47", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", @@ -3421,23 +3182,33 @@ "node": ">=4.2.0" } }, + "node_modules/@vercel/node/node_modules/undici": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.23.0.tgz", + "integrity": "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/@vercel/python": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@vercel/python/-/python-4.3.0.tgz", - "integrity": "sha512-tj6ffEh+ligmQoo/ONOg7DNX0VGKJt9FyswyOIIp6lZufs5oGzHAfan4+5QzF/2INxvXobN0aMYgcbFHJ81ZKg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@vercel/python/-/python-4.0.2.tgz", + "integrity": "sha512-mmUeR3GBuDnaJK3IIHRoPl3bNevcWO3N/YrNAx+zxLPSHzfzmCLZbFVVXbzoKBi/cALiOPcApVhlQXwU26y7xg==", "dev": true }, "node_modules/@vercel/redwood": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vercel/redwood/-/redwood-2.1.3.tgz", - "integrity": "sha512-lpsdQSHS2hvSX29/rJNm4q38dVXKstS4MVg875KE6zyXpACwviXuet0Cadyv0E60w7f2B6Ra+nJMpwKz6oJ5xg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@vercel/redwood/-/redwood-2.0.3.tgz", + "integrity": "sha512-efUqJjRxRhB+nw6OpYw3ptQyXAoWKA/qnzz1UKWfcL2yunCDrdvh2IL3O+Kjt2YqixJAH6DTK1B8lc6NhMoY/g==", "dev": true, "dependencies": { - "@vercel/nft": "0.27.3", - "@vercel/routing-utils": "3.1.0", - "@vercel/static-config": "3.0.0", - "semver": "6.3.1", - "ts-morph": "12.0.0" + "@vercel/nft": "0.24.1", + "@vercel/routing-utils": "3.0.0", + "semver": "6.3.1" } }, "node_modules/@vercel/redwood/node_modules/semver": { @@ -3450,21 +3221,20 @@ } }, "node_modules/@vercel/remix-builder": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@vercel/remix-builder/-/remix-builder-2.2.1.tgz", - "integrity": "sha512-3mM8XNWEo5HmPv/FT2pseGk6MIHcRcLgNHwVQxWe+CSgEXt4QcNQYtwF6v9pb4HDTt09Y1rRkSED5HXvMO38/A==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@vercel/remix-builder/-/remix-builder-2.0.7.tgz", + "integrity": "sha512-RFfMCpRJHIRSV8DLhu7GkPpoxy2A55iqI9qSurSOdMtSAe2CCx2HAD6nXvyR3btfb1s4vLCe2AtxG4CQ5qvdDg==", "dev": true, "dependencies": { - "@vercel/error-utils": "2.0.2", - "@vercel/nft": "0.27.3", + "@vercel/nft": "0.24.1", "@vercel/static-config": "3.0.0", "ts-morph": "12.0.0" } }, "node_modules/@vercel/routing-utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@vercel/routing-utils/-/routing-utils-3.1.0.tgz", - "integrity": "sha512-Ci5xTjVTJY/JLZXpCXpLehMft97i9fH34nu9PGav6DtwkVUF6TOPX86U0W0niQjMZ5n6/ZP0BwcJK2LOozKaGw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@vercel/routing-utils/-/routing-utils-3.0.0.tgz", + "integrity": "sha512-u+SoHnL+RzRQIRP+YxvigzzKXQcbgYQF9qCTIuWuoLw5h9thIYWcDJvz3KxrUzxjGZ3dWboXA29KAlT6eeaeFw==", "dev": true, "dependencies": { "path-to-regexp": "6.1.0" @@ -3480,19 +3250,19 @@ "dev": true }, "node_modules/@vercel/ruby": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@vercel/ruby/-/ruby-2.1.0.tgz", - "integrity": "sha512-UZYwlSEEfVnfzTmgkD+kxex9/gkZGt7unOWNyWFN7V/ZnZSsGBUgv6hXLnwejdRi3EztgRQEBd1kUKlXdIeC0Q==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vercel/ruby/-/ruby-2.0.2.tgz", + "integrity": "sha512-MqFynhtZ905L210DWAbgkiEQEK39LTtp9eL2Nm6PjzhjNzU6hV0UfK8Z24vU9CC6J4mrUTTZx396fH7XTYJWqg==", "dev": true }, "node_modules/@vercel/static-build": { - "version": "2.5.17", - "resolved": "https://registry.npmjs.org/@vercel/static-build/-/static-build-2.5.17.tgz", - "integrity": "sha512-i7fp4wCUgNvZIv06qlQFtFhZJ5WZcwOyg7KmWWhLBsyx/U+LBzUKP80lWAedqB6xmZ7zvNnruGUArzJvI+DnjA==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@vercel/static-build/-/static-build-2.0.7.tgz", + "integrity": "sha512-MjEgxf9HaK7tjVqS/bSlVSGBxFw3hNHdrVEoGJNwMZEfocgBiFxFGaw0Vxki8FTs+F3cciXdxwi6+O1bjj91GA==", "dev": true, "dependencies": { "@vercel/gatsby-plugin-vercel-analytics": "1.0.11", - "@vercel/gatsby-plugin-vercel-builder": "2.0.39", + "@vercel/gatsby-plugin-vercel-builder": "2.0.6", "@vercel/static-config": "3.0.0", "ts-morph": "12.0.0" } @@ -3548,15 +3318,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -3876,10 +3637,13 @@ "dev": true }, "node_modules/async-listen": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/async-listen/-/async-listen-1.2.0.tgz", - "integrity": "sha512-CcEtRh/oc9Jc4uWeUwdpG/+Mb2YUHKmdaTf0gUr7Wa+bfp4xx70HOb3RuSTJMvqKNB1TkdTfjLdrcz2X4rkkZA==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/async-listen/-/async-listen-3.0.0.tgz", + "integrity": "sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg==", + "dev": true, + "engines": { + "node": ">= 14" + } }, "node_modules/async-sema": { "version": "3.1.1", @@ -4053,15 +3817,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -4073,15 +3828,6 @@ "node": ">=10.16.0" } }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -4246,16 +3992,13 @@ } }, "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } }, "node_modules/client-only": { "version": "0.0.1", @@ -4351,15 +4094,6 @@ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "dev": true }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/convert-hrtime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-3.0.0.tgz", @@ -4726,15 +4460,6 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -4830,17 +4555,17 @@ "dev": true }, "node_modules/edge-runtime": { - "version": "2.5.9", - "resolved": "https://registry.npmjs.org/edge-runtime/-/edge-runtime-2.5.9.tgz", - "integrity": "sha512-pk+k0oK0PVXdlT4oRp4lwh+unuKB7Ng4iZ2HB+EZ7QCEQizX360Rp/F4aRpgpRgdP2ufB35N+1KppHmYjqIGSg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/edge-runtime/-/edge-runtime-2.5.1.tgz", + "integrity": "sha512-E0kY1Dqvwvk9yh7dvR56KnCjXf/dlbrrGjO5Sjnz9Ja3WqYT3csv2B8O4erxJiOWfWy9NTukBk4Kb3yrR66gBw==", "dev": true, "dependencies": { - "@edge-runtime/format": "2.2.1", - "@edge-runtime/ponyfill": "2.4.2", - "@edge-runtime/vm": "3.2.0", + "@edge-runtime/format": "2.2.0", + "@edge-runtime/vm": "3.1.1", "async-listen": "3.0.1", "mri": "1.2.0", "picocolors": "1.0.0", + "pretty-bytes": "5.6.0", "pretty-ms": "7.0.1", "signal-exit": "4.0.2", "time-span": "4.0.0" @@ -4916,15 +4641,6 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", @@ -5076,12 +4792,6 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", - "dev": true - }, "node_modules/es-object-atoms": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", @@ -5965,39 +5675,6 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, - "node_modules/events-intercept": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/events-intercept/-/events-intercept-2.0.0.tgz", - "integrity": "sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==", - "dev": true - }, - "node_modules/execa": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-3.2.0.tgz", - "integrity": "sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "p-finally": "^2.0.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": "^8.12.0 || >=9.7.0" - } - }, - "node_modules/execa/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "node_modules/exit-hook": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", @@ -6077,15 +5754,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6191,36 +5859,41 @@ } }, "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=14.14" } }, "node_modules/fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, "dependencies": { - "minipass": "^2.6.0" + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" } }, "node_modules/fs-minipass/node_modules/minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/fs.realpath": { @@ -6326,15 +5999,6 @@ "node": ">=8" } }, - "node_modules/generic-pool": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.4.2.tgz", - "integrity": "sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -6372,21 +6036,6 @@ "source-map": "^0.6.1" } }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-symbol-description": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", @@ -6696,25 +6345,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/http-errors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.4.0.tgz", - "integrity": "sha512-oLjPqve1tuOl5aRhv8GK5eHpqP1C9fb+Ol+XTLjKfLltE44zdDbEdjPSbU7Ch5rSNsVFqZn97SrMmZLdu1/YMw==", - "dev": true, - "dependencies": { - "inherits": "2.0.1", - "statuses": ">= 1.2.1 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-errors/node_modules/inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", - "dev": true - }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -6728,27 +6358,6 @@ "node": ">= 6" } }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -7187,18 +6796,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -7394,10 +6991,13 @@ } }, "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -7753,12 +7353,6 @@ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "peer": true }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -7768,29 +7362,6 @@ "node": ">= 8" } }, - "node_modules/micro": { - "version": "9.3.5-canary.3", - "resolved": "https://registry.npmjs.org/micro/-/micro-9.3.5-canary.3.tgz", - "integrity": "sha512-viYIo9PefV+w9dvoIBh1gI44Mvx1BOk67B4BpC2QK77qdY0xZF0Q+vWLt/BII6cLkIc8rLmSIcJaB/OrXXKe1g==", - "dev": true, - "dependencies": { - "arg": "4.1.0", - "content-type": "1.0.4", - "raw-body": "2.4.1" - }, - "bin": { - "micro": "bin/micro.js" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/micro/node_modules/arg": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", - "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", - "dev": true - }, "node_modules/micromark": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", @@ -8237,15 +7808,6 @@ "node": ">=10.0.0" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/miniflare": { "version": "3.20240718.0", "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240718.0.tgz", @@ -8303,34 +7865,40 @@ } }, "node_modules/minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, "dependencies": { - "minipass": "^2.9.0" + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" } }, "node_modules/minizlib/node_modules/minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, "bin": { "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/moment": { @@ -8399,12 +7967,12 @@ "dev": true }, "node_modules/next": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/next/-/next-14.1.0.tgz", - "integrity": "sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz", + "integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==", "dependencies": { - "@next/env": "14.1.0", - "@swc/helpers": "0.5.2", + "@next/env": "14.2.5", + "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "graceful-fs": "^4.2.11", @@ -8418,18 +7986,19 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.1.0", - "@next/swc-darwin-x64": "14.1.0", - "@next/swc-linux-arm64-gnu": "14.1.0", - "@next/swc-linux-arm64-musl": "14.1.0", - "@next/swc-linux-x64-gnu": "14.1.0", - "@next/swc-linux-x64-musl": "14.1.0", - "@next/swc-win32-arm64-msvc": "14.1.0", - "@next/swc-win32-ia32-msvc": "14.1.0", - "@next/swc-win32-x64-msvc": "14.1.0" + "@next/swc-darwin-arm64": "14.2.5", + "@next/swc-darwin-x64": "14.2.5", + "@next/swc-linux-arm64-gnu": "14.2.5", + "@next/swc-linux-arm64-musl": "14.2.5", + "@next/swc-linux-x64-gnu": "14.2.5", + "@next/swc-linux-x64-musl": "14.2.5", + "@next/swc-win32-arm64-msvc": "14.2.5", + "@next/swc-win32-ia32-msvc": "14.2.5", + "@next/swc-win32-x64-msvc": "14.2.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -8438,6 +8007,9 @@ "@opentelemetry/api": { "optional": true }, + "@playwright/test": { + "optional": true + }, "sass": { "optional": true } @@ -8471,9 +8043,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -8555,18 +8127,6 @@ "node": ">=0.10.0" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", @@ -8724,21 +8284,6 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -8762,24 +8307,6 @@ "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", "peer": true }, - "node_modules/os-paths": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/os-paths/-/os-paths-4.4.0.tgz", - "integrity": "sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==", - "dev": true, - "engines": { - "node": ">= 6.0" - } - }, - "node_modules/p-finally": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", - "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8898,31 +8425,6 @@ "node": ">=8" } }, - "node_modules/path-match": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/path-match/-/path-match-1.2.4.tgz", - "integrity": "sha512-UWlehEdqu36jmh4h5CWJ7tARp1OEVKGHKm6+dg9qMq5RKUTV5WJrGgaZ3dN2m7WFAXDbjlHzvJvL/IUpy84Ktw==", - "dev": true, - "dependencies": { - "http-errors": "~1.4.0", - "path-to-regexp": "^1.0.0" - } - }, - "node_modules/path-match/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/path-match/node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "dependencies": { - "isarray": "0.0.1" - } - }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -8972,12 +8474,6 @@ "integrity": "sha512-KF9XxmUQJ2DIlMj3TqNqY1AWvyvTuIuq11CuuekxyaYMiFuMKGgQrePYMX5bXKLhLG3sDI4CsGAYHPaT7VV7+g==", "dev": true }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, "node_modules/picocolors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", @@ -9237,6 +8733,18 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pretty-ms": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", @@ -9258,12 +8766,6 @@ "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", "dev": true }, - "node_modules/promisepipe": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/promisepipe/-/promisepipe-3.0.0.tgz", - "integrity": "sha512-V6TbZDJ/ZswevgkDNpGt/YqNCiZP9ASfgU+p83uJE6NrGtvSGoOcHLiDCqkMs2+yg7F5qHdLV8d0aS8O26G/KA==", - "dev": true - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -9477,16 +8979,6 @@ "prosemirror-transform": "^1.1.0" } }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -9525,37 +9017,6 @@ } ] }, - "node_modules/raw-body": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", - "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", - "dev": true, - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.3", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -10107,12 +9568,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -10184,12 +9639,6 @@ "node": ">= 0.4" } }, - "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -10302,21 +9751,6 @@ "get-source": "^2.0.12" } }, - "node_modules/stat-mode": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.3.0.tgz", - "integrity": "sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng==", - "dev": true - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -10339,44 +9773,6 @@ "npm": ">=6" } }, - "node_modules/stream-to-array": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz", - "integrity": "sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==", - "dev": true, - "dependencies": { - "any-promise": "^1.1.0" - } - }, - "node_modules/stream-to-promise": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/stream-to-promise/-/stream-to-promise-2.2.0.tgz", - "integrity": "sha512-HAGUASw8NT0k8JvIVutB2Y/9iBk7gpgEyAudXwNJmZERdMITGdajOa4VJfD/kNiA3TppQpTP4J+CtcHwdzKBAw==", - "dev": true, - "dependencies": { - "any-promise": "~1.3.0", - "end-of-stream": "~1.1.0", - "stream-to-array": "~2.3.0" - } - }, - "node_modules/stream-to-promise/node_modules/end-of-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz", - "integrity": "sha512-EoulkdKF/1xa92q25PbjuDcgJ9RDHYU2Rs3SCIvs2/dSQ3BpmxneNHmA/M7fe60M3PrV7nNGTTNbkK62l6vXiQ==", - "dev": true, - "dependencies": { - "once": "~1.3.0" - } - }, - "node_modules/stream-to-promise/node_modules/once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -10601,15 +9997,6 @@ "node": ">=4" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -10766,31 +10153,29 @@ } }, "node_modules/tar": { - "version": "4.4.18", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.18.tgz", - "integrity": "sha512-ZuOtqqmkV9RE1+4odd+MhBpibmCxNP6PJhH/h2OqNuotTX7/XHPZQJv2pKvWMplFH9SIZZhitehh6vBH6LO8Pg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, "dependencies": { - "chownr": "^1.1.4", - "fs-minipass": "^1.2.7", - "minipass": "^2.9.0", - "minizlib": "^1.3.3", - "mkdirp": "^0.5.5", - "safe-buffer": "^5.2.1", - "yallist": "^3.1.1" + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" }, "engines": { - "node": ">=4.5" + "node": ">=10" } }, "node_modules/tar/node_modules/minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "engines": { + "node": ">=8" } }, "node_modules/text-table": { @@ -10860,29 +10245,11 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" - } - }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -11123,12 +10490,6 @@ "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", "dev": true }, - "node_modules/uid-promise": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uid-promise/-/uid-promise-1.0.0.tgz", - "integrity": "sha512-R8375j0qwXyIu/7R0tjdF06/sElHqbmdmWC9M2qQHpEVbvE4I5+38KJI7LUUmQMp7NVq4tKHiBMkT0NFM453Ig==", - "dev": true - }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -11271,21 +10632,12 @@ } }, "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "engines": { - "node": ">= 0.8" + "node": ">= 10.0.0" } }, "node_modules/update-browserslist-db": { @@ -11355,6 +10707,17 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/use-debounce": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.2.tgz", + "integrity": "sha512-MwBiJK2dk+2qhMDVDCPRPeLuIekKfH2t1UYMnrW9pwcJJGFDbTLliSMBz2UKGmE1PJs8l3XoMqbIU1MemMAJ8g==", + "engines": { + "node": ">= 16.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/use-isomorphic-layout-effect": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", @@ -11419,16 +10782,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "node_modules/uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -11436,23 +10789,21 @@ "dev": true }, "node_modules/vercel": { - "version": "35.1.0", - "resolved": "https://registry.npmjs.org/vercel/-/vercel-35.1.0.tgz", - "integrity": "sha512-q9vHaeMGQaOPPOEtzABuvN7qO2+hwKnDIzV7GprPECXpcvP3J2Ge8yJls1erESa0uvjcKU55T8fI4RS3rWzXgA==", - "dev": true, - "dependencies": { - "@vercel/build-utils": "8.3.5", - "@vercel/fun": "1.1.0", - "@vercel/go": "3.1.1", - "@vercel/hydrogen": "1.0.4", - "@vercel/next": "4.3.6", - "@vercel/node": "3.2.7", - "@vercel/python": "4.3.0", - "@vercel/redwood": "2.1.3", - "@vercel/remix-builder": "2.2.1", - "@vercel/ruby": "2.1.0", - "@vercel/static-build": "2.5.17", - "chokidar": "3.3.1" + "version": "32.3.0", + "resolved": "https://registry.npmjs.org/vercel/-/vercel-32.3.0.tgz", + "integrity": "sha512-CnZaP/40Jme5Mn7RdG2t3jcwRC5huststljnFxuyuOD0RVMHGequJy95eDR1+yCQDylhZ5W9KFGX82eCFJ+T2w==", + "dev": true, + "dependencies": { + "@vercel/build-utils": "7.2.1", + "@vercel/go": "3.0.2", + "@vercel/hydrogen": "1.0.1", + "@vercel/next": "4.0.7", + "@vercel/node": "3.0.6", + "@vercel/python": "4.0.2", + "@vercel/redwood": "2.0.3", + "@vercel/remix-builder": "2.0.7", + "@vercel/ruby": "2.0.2", + "@vercel/static-build": "2.0.7" }, "bin": { "vc": "dist/index.js", @@ -11462,66 +10813,6 @@ "node": ">= 16" } }, - "node_modules/vercel/node_modules/chokidar": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", - "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.3.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.1.2" - } - }, - "node_modules/vercel/node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/vercel/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/vercel/node_modules/readdirp": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", - "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", - "dev": true, - "dependencies": { - "picomatch": "^2.0.7" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/vfile": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.2.tgz", @@ -11910,30 +11201,6 @@ } } }, - "node_modules/xdg-app-paths": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xdg-app-paths/-/xdg-app-paths-5.1.0.tgz", - "integrity": "sha512-RAQ3WkPf4KTU1A8RtFx3gWywzVKe00tfOPFfl2NDGqbIFENQO4kqAJp7mhQjNj/33W5x5hiWWUdyfPq/5SU3QA==", - "dev": true, - "dependencies": { - "xdg-portable": "^7.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/xdg-portable": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/xdg-portable/-/xdg-portable-7.3.0.tgz", - "integrity": "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==", - "dev": true, - "dependencies": { - "os-paths": "^4.0.1" - }, - "engines": { - "node": ">= 6.0" - } - }, "node_modules/xxhash-wasm": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz", @@ -11941,9 +11208,9 @@ "dev": true }, "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "node_modules/yaml": { @@ -11958,41 +11225,6 @@ "node": ">= 14" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yauzl-clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/yauzl-clone/-/yauzl-clone-1.0.4.tgz", - "integrity": "sha512-igM2RRCf3k8TvZoxR2oguuw4z1xasOnA31joCqHIyLkeWrvAc2Jgay5ISQ2ZplinkoGaJ6orCz56Ey456c5ESA==", - "dev": true, - "dependencies": { - "events-intercept": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yauzl-promise": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/yauzl-promise/-/yauzl-promise-2.1.3.tgz", - "integrity": "sha512-A1pf6fzh6eYkK0L4Qp7g9jzJSDrM6nN0bOn5T0IbY4Yo3w+YkWlHFkJP7mzknMXjqusHFHlKsK2N+4OLsK2MRA==", - "dev": true, - "dependencies": { - "yauzl": "^2.9.1", - "yauzl-clone": "^1.0.4" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/site/package.json b/site/package.json index 82606c3..ef0be45 100644 --- a/site/package.json +++ b/site/package.json @@ -35,11 +35,12 @@ "dayjs": "^1.11.12", "embla-carousel-react": "^8.1.7", "moment": "^2.30.1", - "next": "14.1.0", + "next": "^14.2.5", "react": "^18", "react-dom": "^18", "react-markdown": "^9.0.1", - "recharts": "^2.12.7" + "recharts": "^2.12.7", + "use-debounce": "^10.0.2" }, "devDependencies": { "@cloudflare/next-on-pages": "^1.12.1", @@ -56,7 +57,7 @@ "postcss-simple-vars": "^7.0.1", "tailwindcss": "^3.3.0", "typescript": "^5", - "vercel": "^35.1.0", + "vercel": "^32.3.0", "wrangler": "^3.65.1" } } diff --git a/site/src/app/bills/page.tsx b/site/src/app/bills/page.tsx index 43ada59..db03aca 100644 --- a/site/src/app/bills/page.tsx +++ b/site/src/app/bills/page.tsx @@ -4,7 +4,7 @@ import ShortBill from "@/app/components/ShortBill"; import HumanFriendlyColumn from "@/app/components/HumanFriendlyColumn"; import StandardStack from "@/app/components/StandardStack"; import type { Metadata } from "next"; -import StandardPagination from "@/components/StandardPagination"; +import StandardPagination from "@/app/components/StandardPagination"; import StandardCard from "@/app/components/StandardCard"; import StandardCardTitle from "@/app/components/StandardCardTitle"; import StandardCardDescription from "@/app/components/StandardCardDescription"; @@ -17,7 +17,7 @@ const title = "Recent Bills"; const subtitle = "Bills, including constitutional amendments, are proposals to change Singapore's laws. A bill needs a majority to pass, while amendments require a two-thirds majority. Below are the most recent proposals."; -const itemsPerPage = parseInt(process.env.ITEMS_PER_PAGE!); +const itemsPerPage = parseInt(process.env.NEXT_PUBLIC_ITEMS_PER_PAGE!); export const metadata: Metadata = { title, @@ -79,10 +79,10 @@ export default async function RecentBills({ View More Bills - You've reached the end of our list of parliament bill summaries. - Due to technical constraints, we can only provide summaries for a - limited number of bills. To see more bills, visit the original - source. + You've reached the end of our list of parliament bill + summaries. Due to technical constraints, we can only provide + summaries for a limited number of bills. To see more bills, visit + the original source. diff --git a/site/src/app/components/DebateSpeechCard.tsx b/site/src/app/components/DebateSpeechCard.tsx new file mode 100644 index 0000000..54c7ced --- /dev/null +++ b/site/src/app/components/DebateSpeechCard.tsx @@ -0,0 +1,38 @@ +import StandardCard from "@/app/components/StandardCard"; +import StandardCardTitle from "@/app/components/StandardCardTitle"; +import StandardCardDescription from "@/app/components/StandardCardDescription"; +import Markdown from "react-markdown"; +import React from "react"; +import { Text } from "@mantine/core"; +import StandardMarkdown from "./StandardMarkdown"; + +function formatProcText(content: string) { + return content + .replaceAll("[(proc text) ", "*") + .replaceAll(" (proc text)]", "*"); +} + +export default function DebateSummary({ + debateSpeech, +}: { + debateSpeech: { speaker_name: string | null; content: string }; +}) { + return ( + + {debateSpeech.speaker_name ? ( + <> + {debateSpeech.speaker_name} + + {formatProcText(debateSpeech.content)} + + + ) : ( + + + {formatProcText(debateSpeech.content)} + + + )} + + ); +} diff --git a/site/src/app/components/DebateSummary.tsx b/site/src/app/components/DebateSummary.tsx new file mode 100644 index 0000000..aebb7e6 --- /dev/null +++ b/site/src/app/components/DebateSummary.tsx @@ -0,0 +1,31 @@ +import StandardCard from "@/app/components/StandardCard"; +import StandardCardTitle from "@/app/components/StandardCardTitle"; +import StandardCardDescription from "@/app/components/StandardCardDescription"; +import { Stack } from "@mantine/core"; +import SummaryAiDisclaimer from "@/app/components/SummaryAiDisclaimer"; +import SummaryNotAvailableApology from "@/app/components/SummaryNotAvailableApology"; +import React from "react"; +import StandardMarkdown from "@/app/components/StandardMarkdown"; + +export default function DebateSummary({ + debate, +}: { + debate: { summary: string | null }; +}) { + return ( + + Summary + + + {debate.summary ? ( + + {debate.summary} + + + ) : ( + + )} + + + ); +} diff --git a/site/src/app/components/NavbarSimple.module.css b/site/src/app/components/NavbarSimple.module.css deleted file mode 100644 index 4fd24e9..0000000 --- a/site/src/app/components/NavbarSimple.module.css +++ /dev/null @@ -1,63 +0,0 @@ -.navbar { - height: rem(700px); - width: rem(300px); - padding: var(--mantine-spacing-md); - display: flex; - flex-direction: column; - border-right: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4)); -} - -.navbarMain { - flex: 1; -} - -.header { - padding-bottom: var(--mantine-spacing-md); - margin-bottom: calc(var(--mantine-spacing-md) * 1.5); - border-bottom: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4)); -} - -.footer { - padding-top: var(--mantine-spacing-md); - margin-top: var(--mantine-spacing-md); - border-top: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4)); -} - -.link { - display: flex; - align-items: center; - text-decoration: none; - font-size: var(--mantine-font-size-sm); - color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-1)); - padding: var(--mantine-spacing-xs) var(--mantine-spacing-sm); - border-radius: var(--mantine-radius-sm); - font-weight: 500; - - @mixin hover { - background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6)); - color: light-dark(var(--mantine-color-black), var(--mantine-color-white)); - - .linkIcon { - color: light-dark(var(--mantine-color-black), var(--mantine-color-white)); - } - } - - /*&[data-active] {*/ - /* &,*/ - /* &:hover {*/ - /* background-color: var(--mantine-color-blue-light);*/ - /* color: var(--mantine-color-blue-light-color);*/ - - /* .linkIcon {*/ - /* color: var(--mantine-color-blue-light-color);*/ - /* }*/ - /* }*/ - /*}*/ -} - -.linkIcon { - color: light-dark(var(--mantine-color-gray-6), var(--mantine-color-dark-2)); - margin-right: var(--mantine-spacing-sm); - width: rem(25px); - height: rem(25px); -} \ No newline at end of file diff --git a/site/src/app/components/NavbarSimple.tsx b/site/src/app/components/NavbarSimple.tsx deleted file mode 100644 index 2ba65cc..0000000 --- a/site/src/app/components/NavbarSimple.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { - IconBellRinging, - IconZoom, - IconGavel, - IconMessage2Question, - IconCodeDots, - IconInfoCircle, -} from "@tabler/icons-react"; -import classes from "./NavbarSimple.module.css"; - -const data = [ - // { link: "/findmp", label: "Find MP", icon: IconZoom }, - // { link: "/alerts", label: "My alerts", icon: IconBellRinging }, - { link: "/bills", label: "Bills", icon: IconGavel }, - // { link: "/qa", label: "Q&A", icon: IconMessage2Question }, -]; - -export function NavbarSimple() { - const links = data.map((item) => ( - - - {item.label} - - )); - - return ( -
-
{links}
- - {/**/} -
- ); -} diff --git a/site/src/app/components/PageFooter.tsx b/site/src/app/components/PageFooter.tsx new file mode 100644 index 0000000..7cdd03a --- /dev/null +++ b/site/src/app/components/PageFooter.tsx @@ -0,0 +1,27 @@ +import HumanFriendlyColumn from "@/app/components/HumanFriendlyColumn"; +import { Box } from "@mantine/core"; +import StandardCardDescription from "./StandardCardDescription"; +import StandardCardTitle from "./StandardCardTitle"; +import StandardCard from "./StandardCard"; +import React from "react"; + +export default function PageFooter() { + return ( + + + + Disclaimer + + The information provided on this webpage is intended for reference + purposes only. The summaries are generated by artificial + intelligence and should not be regarded as fully accurate or + comprehensive. The data is sourced exclusively from publicly + available parliamentary sources online such as parliament.gov.sg. + Users are advised to consult original parliamentary documents and + official records for precise and authoritative information. + + + + + ); +} diff --git a/site/src/app/components/SearchSpotlight.tsx b/site/src/app/components/SearchSpotlight.tsx new file mode 100644 index 0000000..462d801 --- /dev/null +++ b/site/src/app/components/SearchSpotlight.tsx @@ -0,0 +1,124 @@ +"use client"; + +import { Spotlight, SpotlightActionGroupData } from "@mantine/spotlight"; +import { useEffect, useState } from "react"; +import { useDebounce } from "use-debounce"; +import { useRouter } from "next/navigation"; +import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime"; + +type ClientFriendlyData = { + href: string; + title: string; +}; + +async function getResults(query: string): Promise<{ + debate: ClientFriendlyData[]; + bill: ClientFriendlyData[]; +}> { + const url = `${process.env.NEXT_PUBLIC_SUPABASE_URL}/functions/v1/search`; + const headers = new Headers({ + Authorization: `Bearer ${process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY}`, + }); + const request = new Request(url, { + headers: headers, + method: "POST", + body: JSON.stringify({ query }), + }); + const response = await fetch(request); + return response.json(); +} + +function convertDataToActions( + router: AppRouterInstance, + data: ClientFriendlyData[], +) { + return data.map((item) => ({ + id: item.href, + label: item.title, + onClick: () => router.push(item.href), + })); +} + +function convertResultsToActionGroups( + router: AppRouterInstance, + results: { + debate: ClientFriendlyData[]; + bill: ClientFriendlyData[]; + }, +): SpotlightActionGroupData[] { + return [ + { + group: "Debates", + actions: convertDataToActions(router, results.debate), + }, + { + group: "Bills", + actions: convertDataToActions(router, results.bill), + }, + ]; +} + +// Empty action groups make nothingFound not work properly, and empty headers ain't that good anyway +function clearEmptyActionGroups(actionGroups: SpotlightActionGroupData[]) { + return actionGroups.filter((group) => group.actions.length > 0); +} + +export default function SearchSpotlight() { + const router = useRouter(); + + const [query, setQuery] = useState(""); + const [debouncedQuery] = useDebounce(query, 500); + const [results, setResults] = useState<{ + searchHappened: boolean; + actionGroups: SpotlightActionGroupData[]; + }>({ + searchHappened: false, + actionGroups: [], + }); + + useEffect(() => { + let isCanceled = false; + (async () => { + if (debouncedQuery != "") { + const results = await getResults(debouncedQuery); + if (isCanceled) { + return; + } + setResults({ + searchHappened: true, + actionGroups: clearEmptyActionGroups( + convertResultsToActionGroups(router, results), + ), + }); + } else { + setResults({ searchHappened: false, actionGroups: [] }); + } + })(); + // If the debouncedQuery changes before the request completes, cancel the request's setActions call + return () => { + isCanceled = true; + }; + }, [debouncedQuery]); + + return ( + { + setQuery(query); + }} + actions={results.actionGroups} + shortcut={null} + filter={(_, actions) => + // Don't filter; search is already done + actions + } + scrollable + highlightQuery + nothingFound={ + results.searchHappened ? "No results found" : "Start typing to search" + } + radius="lg" + /> + ); +} diff --git a/site/src/app/components/ShortBill.tsx b/site/src/app/components/ShortBill.tsx index 45059e5..68aaf14 100644 --- a/site/src/app/components/ShortBill.tsx +++ b/site/src/app/components/ShortBill.tsx @@ -1,6 +1,5 @@ import { Badge, Group, Stack } from "@mantine/core"; import moment from "moment/moment"; -import Markdown from "react-markdown"; import SummaryAiDisclaimer from "@/app/components/SummaryAiDisclaimer"; import StandardCard from "@/app/components/StandardCard"; import StandardCardTitle from "@/app/components/StandardCardTitle"; @@ -8,6 +7,7 @@ import StandardCardDescription from "@/app/components/StandardCardDescription"; import SummaryNotAvailableApology from "@/app/components/SummaryNotAvailableApology"; import StandardButton from "@/app/components/StandardButton"; import BillOriginalPdfButton from "@/app/components/BillOriginalPdfButton"; +import StandardMarkdown from "./StandardMarkdown"; function flipBillNo(billNo: string) { const [billOfYear, year] = billNo.split("/"); @@ -47,7 +47,7 @@ export default async function ShortBill({ {bill.summary ? ( - {bill.summary} + {bill.summary} ) : ( diff --git a/site/src/app/components/ShortDebate.tsx b/site/src/app/components/ShortDebate.tsx new file mode 100644 index 0000000..9082b84 --- /dev/null +++ b/site/src/app/components/ShortDebate.tsx @@ -0,0 +1,57 @@ +import { Group, Stack } from "@mantine/core"; +import StandardCardTitle from "@/app/components/StandardCardTitle"; +import moment from "moment"; +import StandardCardDescription from "@/app/components/StandardCardDescription"; +import SummaryAiDisclaimer from "@/app/components/SummaryAiDisclaimer"; +import SummaryNotAvailableApology from "@/app/components/SummaryNotAvailableApology"; +import StandardButton from "@/app/components/StandardButton"; +import StandardCard from "@/app/components/StandardCard"; +import StandardCardSubtitle from "@/app/components/StandardCardSubtitle"; +import StandardMarkdown from "@/app/components/StandardMarkdown"; + +export default function ShortDebate({ + debate, +}: { + debate: { + id: number | null; + title: string | null; + summary: string | null; + order_no: number | null; + sitting_date: string | null; + }; +}) { + return ( + + + {debate.title} + + + + {moment(debate.sitting_date).format("D MMM YYYY")} + + + + {debate.summary ? ( + + {debate.summary} + + + ) : ( + + )} + + + + + Overview + + + Original source + + + + ); +} diff --git a/site/src/app/components/StandardCardDescription.tsx b/site/src/app/components/StandardCardDescription.tsx index 5855367..1e3fe19 100644 --- a/site/src/app/components/StandardCardDescription.tsx +++ b/site/src/app/components/StandardCardDescription.tsx @@ -7,7 +7,7 @@ export default function StandardCardDescription({ children: React.ReactNode; }) { return ( - + {children} ); diff --git a/site/src/app/components/StandardCardSubtitle.tsx b/site/src/app/components/StandardCardSubtitle.tsx new file mode 100644 index 0000000..cbc3c74 --- /dev/null +++ b/site/src/app/components/StandardCardSubtitle.tsx @@ -0,0 +1,14 @@ +import { Text } from "@mantine/core"; +import React from "react"; + +export default function StandardCardSubtitle({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} diff --git a/site/src/app/components/StandardMarkdown.tsx b/site/src/app/components/StandardMarkdown.tsx new file mode 100644 index 0000000..51fb5fd --- /dev/null +++ b/site/src/app/components/StandardMarkdown.tsx @@ -0,0 +1,11 @@ +import Markdown from "react-markdown"; +import { Box } from "@mantine/core"; +import React from "react"; + +export default function StandardMarkdown({ children }: { children: string }) { + return ( + + {children} + + ); +} diff --git a/site/src/components/StandardPagination.tsx b/site/src/app/components/StandardPagination.tsx similarity index 100% rename from site/src/components/StandardPagination.tsx rename to site/src/app/components/StandardPagination.tsx diff --git a/site/src/app/components/StandardShell.module.css b/site/src/app/components/StandardShell.module.css new file mode 100644 index 0000000..4a2a57b --- /dev/null +++ b/site/src/app/components/StandardShell.module.css @@ -0,0 +1,10 @@ +.control { + display: block; + padding: var(--mantine-spacing-xs) var(--mantine-spacing-md); + border-radius: var(--mantine-radius-md); + font-weight: 500; +} + +.control:hover { + background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6)); +} \ No newline at end of file diff --git a/site/src/app/components/StandardShell.tsx b/site/src/app/components/StandardShell.tsx new file mode 100644 index 0000000..00b8c2a --- /dev/null +++ b/site/src/app/components/StandardShell.tsx @@ -0,0 +1,103 @@ +"use client"; + +import { + AppShell, + AppShellHeader, + AppShellMain, + Burger, + Group, + rem, + UnstyledButton, +} from "@mantine/core"; +import React from "react"; +import { useDisclosure, useHeadroom } from "@mantine/hooks"; +import classes from "./StandardShell.module.css"; +import PageFooter from "@/app/components/PageFooter"; +import Link from "next/link"; +import { spotlight } from "@mantine/spotlight"; +import SearchSpotlight from "@/app/components/SearchSpotlight"; + +type PageLink = { + name: string; + href: string; +}; + +function generateButtonsFromLinks(links: PageLink[], closeNavbar: () => void) { + return ( + <> + { + closeNavbar(); + spotlight.open(); + }} + > + Search + + {links.map(({ name, href }) => ( + + {name} + + ))} + + ); +} + +export default function StandardShell({ + children, + logo, + links, +}: { + children: React.ReactNode; + logo: React.ReactNode; + links: PageLink[]; +}) { + const [opened, { toggle, close }] = useDisclosure(); + const pinned = useHeadroom({ fixedAt: 120 }); + const generatedButtons = generateButtonsFromLinks(links, close); + + return ( + + + + + + + {logo} + + + {generatedButtons} + + + + + + + {generatedButtons} + + + + {children} + + + + + {/* I think this can be anywhere since it's a modal */} + + + ); +} diff --git a/site/src/app/components/SummaryAiDisclaimer.tsx b/site/src/app/components/SummaryAiDisclaimer.tsx index 9a9cecd..076094b 100644 --- a/site/src/app/components/SummaryAiDisclaimer.tsx +++ b/site/src/app/components/SummaryAiDisclaimer.tsx @@ -4,7 +4,7 @@ export default function SummaryAiDisclaimer() { return ( ); } diff --git a/site/src/app/components/SummaryNotAvailableApology.tsx b/site/src/app/components/SummaryNotAvailableApology.tsx index 959ae63..22950e5 100644 --- a/site/src/app/components/SummaryNotAvailableApology.tsx +++ b/site/src/app/components/SummaryNotAvailableApology.tsx @@ -1,7 +1,9 @@ +import { Text } from "@mantine/core"; + export default function SummaryNotAvailableApology() { return ( - <> - We're processing this bill's summary right now! Check back soon. - + + We're processing this summary right now! Check back soon. + ); } diff --git a/site/src/app/debates/[debateId]/page.tsx b/site/src/app/debates/[debateId]/page.tsx new file mode 100644 index 0000000..d1b4718 --- /dev/null +++ b/site/src/app/debates/[debateId]/page.tsx @@ -0,0 +1,79 @@ +import { createClient } from "@/utils/supabase/client"; +import PageTitle from "@/app/components/PageTitle"; +import React from "react"; +import HumanFriendlyColumn from "@/app/components/HumanFriendlyColumn"; +import StandardStack from "@/app/components/StandardStack"; +import { Metadata } from "next"; +import moment from "moment"; +import DebateSummary from "@/app/components/DebateSummary"; +import DebateSpeechCard from "@/app/components/DebateSpeechCard"; +import { Title } from "@mantine/core"; + +export const runtime = "edge"; + +const subtitle = (debate: { + sitting: { sitting_date: { sitting_date: string } | null } | null; +}) => + `Debated in Parliament on ${moment(debate.sitting!.sitting_date!.sitting_date).format("D MMM YYYY")}.`; + +export async function generateMetadata({ + params, +}: { + params: { debateId: string }; +}): Promise { + const debate = await getDebate(parseInt(params.debateId)); + + return { + title: debate.title, + description: subtitle(debate), + }; +} + +async function getDebate(debateId: number) { + const supabase = createClient(); + const { error, data } = await supabase + .from("debate") + .select("id, title, summary, sitting ( sitting_date ( sitting_date ) )") + .eq("id", debateId) + .single(); + if (error) throw error; + return data; +} + +async function getDebateSpeeches(debateId: number) { + const supabase = createClient(); + const { error, data } = await supabase + .from("debate_speech") + .select("speaker_name, content") + .eq("debate_id", debateId) + .order("order_no", { ascending: true }); + if (error) throw error; + return data; +} + +export default async function FullBill({ + params, +}: { + params: { debateId: string }; +}) { + const debate = await getDebate(parseInt(params.debateId)); + const debateSpeeches = await getDebateSpeeches(parseInt(params.debateId)); + + return ( + + + + + + + + Full Transcript + + + {debateSpeeches.map((debateSpeech, index) => ( + + ))} + + + ); +} diff --git a/site/src/app/debates/page.tsx b/site/src/app/debates/page.tsx new file mode 100644 index 0000000..ef13ac9 --- /dev/null +++ b/site/src/app/debates/page.tsx @@ -0,0 +1,100 @@ +import { createClient } from "@/utils/supabase/client"; +import PageTitle from "@/app/components/PageTitle"; +import HumanFriendlyColumn from "@/app/components/HumanFriendlyColumn"; +import StandardStack from "@/app/components/StandardStack"; +import type { Metadata } from "next"; +import StandardPagination from "@/app/components/StandardPagination"; +import StandardCard from "@/app/components/StandardCard"; +import StandardCardTitle from "@/app/components/StandardCardTitle"; +import StandardCardDescription from "@/app/components/StandardCardDescription"; +import StandardButton from "@/app/components/StandardButton"; +import { Group } from "@mantine/core"; +import ShortDebate from "@/app/components/ShortDebate"; + +export const runtime = "edge"; + +const title = "Recent Debates"; +const subtitle = + "Explore the latest parliamentary debates, where Members of Parliament discuss key issues and proposed legislation in detail. Stay informed about the topics shaping Singapore's laws and policies, and access the official records in the Hansard."; + +const itemsPerPage = parseInt(process.env.NEXT_PUBLIC_ITEMS_PER_PAGE!); + +export const metadata: Metadata = { + title, + description: subtitle, +}; + +// First and last are both assumed inclusive as per Supabase API. +function calculatePaginationOffset(page: number) { + const first = (page - 1) * itemsPerPage; + const last = first + itemsPerPage - 1; + return [first, last]; +} + +async function getRecentDebates(page: number) { + const supabase = createClient(); + const [first, last] = calculatePaginationOffset(page); + const { data, error } = await supabase + .from("debate_sortable_view") + .select("id, title, order_no, summary, sitting_date") + .order("sitting_date", { ascending: false }) + .order("order_no", { ascending: false }) + .range(first, last); + if (error) throw error; + return data; +} + +async function getDebateCount() { + const supabase = createClient(); + const { error, count } = await supabase + .from("debate") + .select("id", { count: "exact" }) + .limit(0); + if (error) throw error; + return count!; +} + +export default async function RecentDebates({ + searchParams, +}: { + searchParams: { page: string | undefined }; +}) { + const page = parseInt(searchParams.page ?? "1"); + const debateCount = await getDebateCount(); + const pageCount = Math.ceil(debateCount / itemsPerPage); + const isLastPage = page === pageCount; + + return ( + + + + + {(await getRecentDebates(page)).map((debate) => ( + + ))} + + {isLastPage && ( + + View More Debates + + You've reached the end of our list of parliament debate + summaries. Due to technical constraints, we can only provide + summaries for a limited number of debates. To see more debates, + visit the original source. + + + + Visit original source + + + + )} + + + + + ); +} diff --git a/site/src/app/layout.tsx b/site/src/app/layout.tsx index 93dc08e..d972046 100644 --- a/site/src/app/layout.tsx +++ b/site/src/app/layout.tsx @@ -5,65 +5,32 @@ import "./globals.css"; // Import styles of packages that you've installed. // All packages except `@mantine/hooks` require styles imports import "@mantine/core/styles.css"; -import { - AppShell, - AppShellMain, - Text, - Box, - ColorSchemeScript, - MantineProvider, -} from "@mantine/core"; -import { NavbarSimple } from "@/app/components/NavbarSimple"; -import HumanFriendlyColumn from "@/app/components/HumanFriendlyColumn"; +import "@mantine/spotlight/styles.css"; +import { ColorSchemeScript, MantineProvider, Text } from "@mantine/core"; +import StandardShell from "@/app/components/StandardShell"; export const metadata: Metadata = { title: { - template: `%s | ${process.env.SITE_NAME}`, - default: process.env.SITE_NAME!, + template: `%s | ${process.env.NEXT_PUBLIC_SITE_NAME}`, + default: process.env.NEXT_PUBLIC_SITE_NAME!, }, }; -function Shell({ children }: { children: React.ReactNode }) { - return ( - - {/**/} - {/* */} - {/**/} - - {children} - - - - - Disclaimer: -
-
- The information provided on this webpage is intended for reference - purposes only. The summaries are generated by artificial - intelligence and should not be regarded as fully accurate or - comprehensive. The data is sourced exclusively from publicly - available parliamentary sources online such as parliament.gov.sg. - Users are advised to consult original parliamentary documents and - official records for precise and authoritative information. -
-
-
-
- ); -} - export default function RootLayout({ children, }: { children: React.ReactNode; }) { const defaultColorScheme = "auto"; + const logo = Parliament Summary; + const links = [ + { name: "Bills", href: "/bills" }, + { name: "Debates", href: "/debates" }, + { + name: "GitHub", + href: process.env.NEXT_PUBLIC_REPOSITORY_URL!, + }, + ]; // noinspection HtmlRequiredTitleElement return ( @@ -73,7 +40,9 @@ export default function RootLayout({ - {children} + + {children} + diff --git a/site/src/utils/supabase/database.types.ts b/site/src/utils/supabase/database.types.ts index 45fe702..8fb541c 100644 --- a/site/src/utils/supabase/database.types.ts +++ b/site/src/utils/supabase/database.types.ts @@ -23,6 +23,7 @@ export type Database = { second_reading_date: string | null second_reading_date_type: string summary: string | null + summary_backup: string | null } Insert: { bill_no: string @@ -37,6 +38,7 @@ export type Database = { second_reading_date?: string | null second_reading_date_type: string summary?: string | null + summary_backup?: string | null } Update: { bill_no?: string @@ -51,6 +53,7 @@ export type Database = { second_reading_date?: string | null second_reading_date_type?: string summary?: string | null + summary_backup?: string | null } Relationships: [] } @@ -62,6 +65,7 @@ export type Database = { order_no: number sitting_id: number summary: string | null + summary_backup: string | null title: string } Insert: { @@ -71,6 +75,7 @@ export type Database = { order_no: number sitting_id: number summary?: string | null + summary_backup?: string | null title: string } Update: { @@ -80,6 +85,7 @@ export type Database = { order_no?: number sitting_id?: number summary?: string | null + summary_backup?: string | null title?: string } Relationships: [ @@ -107,6 +113,7 @@ export type Database = { id: number order_no: number speaker_id: number | null + speaker_name: string | null } Insert: { content: string @@ -115,6 +122,7 @@ export type Database = { id?: number order_no: number speaker_id?: number | null + speaker_name?: string | null } Update: { content?: string @@ -123,6 +131,7 @@ export type Database = { id?: number order_no?: number speaker_id?: number | null + speaker_name?: string | null } Relationships: [ { @@ -132,6 +141,20 @@ export type Database = { referencedRelation: "debate" referencedColumns: ["id"] }, + { + foreignKeyName: "debate_speech_debate_id_fkey" + columns: ["debate_id"] + isOneToOne: false + referencedRelation: "debate_sortable_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "debate_speech_speaker_id_fkey" + columns: ["speaker_id"] + isOneToOne: false + referencedRelation: "combined_mp_names_view" + referencedColumns: ["mp_id"] + }, { foreignKeyName: "debate_speech_speaker_id_fkey" columns: ["speaker_id"] @@ -191,6 +214,42 @@ export type Database = { }, ] } + mp_aliases: { + Row: { + alias_name: string + created_at: string + id: number + mp_id: number + } + Insert: { + alias_name: string + created_at?: string + id?: number + mp_id: number + } + Update: { + alias_name?: string + created_at?: string + id?: number + mp_id?: number + } + Relationships: [ + { + foreignKeyName: "mp_aliases_mp_id_fkey" + columns: ["mp_id"] + isOneToOne: false + referencedRelation: "combined_mp_names_view" + referencedColumns: ["mp_id"] + }, + { + foreignKeyName: "mp_aliases_mp_id_fkey" + columns: ["mp_id"] + isOneToOne: false + referencedRelation: "mp" + referencedColumns: ["id"] + }, + ] + } party: { Row: { colour: string @@ -286,6 +345,24 @@ export type Database = { } } Views: { + combined_mp_names_view: { + Row: { + alias_name: string | null + full_name: string | null + mp_id: number | null + } + Relationships: [] + } + debate_sortable_view: { + Row: { + id: number | null + order_no: number | null + sitting_date: string | null + summary: string | null + title: string | null + } + Relationships: [] + } unscraped_sitting_dates_view: { Row: { created_at: string | null diff --git a/supabase/.gitignore b/supabase/.gitignore index 4c43fe6..7a952e6 100644 --- a/supabase/.gitignore +++ b/supabase/.gitignore @@ -1 +1,2 @@ -*.js \ No newline at end of file +*.js +functions/lib/sensitive/*.ts \ No newline at end of file diff --git a/supabase/.temp/cli-latest b/supabase/.temp/cli-latest index a2f2436..ea6995c 100644 --- a/supabase/.temp/cli-latest +++ b/supabase/.temp/cli-latest @@ -1 +1 @@ -v1.187.3 \ No newline at end of file +v1.187.10 \ No newline at end of file diff --git a/supabase/functions/database.types.ts b/supabase/functions/database.types.ts index 45fe702..8fb541c 100644 --- a/supabase/functions/database.types.ts +++ b/supabase/functions/database.types.ts @@ -23,6 +23,7 @@ export type Database = { second_reading_date: string | null second_reading_date_type: string summary: string | null + summary_backup: string | null } Insert: { bill_no: string @@ -37,6 +38,7 @@ export type Database = { second_reading_date?: string | null second_reading_date_type: string summary?: string | null + summary_backup?: string | null } Update: { bill_no?: string @@ -51,6 +53,7 @@ export type Database = { second_reading_date?: string | null second_reading_date_type?: string summary?: string | null + summary_backup?: string | null } Relationships: [] } @@ -62,6 +65,7 @@ export type Database = { order_no: number sitting_id: number summary: string | null + summary_backup: string | null title: string } Insert: { @@ -71,6 +75,7 @@ export type Database = { order_no: number sitting_id: number summary?: string | null + summary_backup?: string | null title: string } Update: { @@ -80,6 +85,7 @@ export type Database = { order_no?: number sitting_id?: number summary?: string | null + summary_backup?: string | null title?: string } Relationships: [ @@ -107,6 +113,7 @@ export type Database = { id: number order_no: number speaker_id: number | null + speaker_name: string | null } Insert: { content: string @@ -115,6 +122,7 @@ export type Database = { id?: number order_no: number speaker_id?: number | null + speaker_name?: string | null } Update: { content?: string @@ -123,6 +131,7 @@ export type Database = { id?: number order_no?: number speaker_id?: number | null + speaker_name?: string | null } Relationships: [ { @@ -132,6 +141,20 @@ export type Database = { referencedRelation: "debate" referencedColumns: ["id"] }, + { + foreignKeyName: "debate_speech_debate_id_fkey" + columns: ["debate_id"] + isOneToOne: false + referencedRelation: "debate_sortable_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "debate_speech_speaker_id_fkey" + columns: ["speaker_id"] + isOneToOne: false + referencedRelation: "combined_mp_names_view" + referencedColumns: ["mp_id"] + }, { foreignKeyName: "debate_speech_speaker_id_fkey" columns: ["speaker_id"] @@ -191,6 +214,42 @@ export type Database = { }, ] } + mp_aliases: { + Row: { + alias_name: string + created_at: string + id: number + mp_id: number + } + Insert: { + alias_name: string + created_at?: string + id?: number + mp_id: number + } + Update: { + alias_name?: string + created_at?: string + id?: number + mp_id?: number + } + Relationships: [ + { + foreignKeyName: "mp_aliases_mp_id_fkey" + columns: ["mp_id"] + isOneToOne: false + referencedRelation: "combined_mp_names_view" + referencedColumns: ["mp_id"] + }, + { + foreignKeyName: "mp_aliases_mp_id_fkey" + columns: ["mp_id"] + isOneToOne: false + referencedRelation: "mp" + referencedColumns: ["id"] + }, + ] + } party: { Row: { colour: string @@ -286,6 +345,24 @@ export type Database = { } } Views: { + combined_mp_names_view: { + Row: { + alias_name: string | null + full_name: string | null + mp_id: number | null + } + Relationships: [] + } + debate_sortable_view: { + Row: { + id: number | null + order_no: number | null + sitting_date: string | null + summary: string | null + title: string | null + } + Relationships: [] + } unscraped_sitting_dates_view: { Row: { created_at: string | null diff --git a/supabase/functions/fill-debate-bill-ids/index.ts b/supabase/functions/fill-debate-bill-ids/index.ts new file mode 100644 index 0000000..adcd137 --- /dev/null +++ b/supabase/functions/fill-debate-bill-ids/index.ts @@ -0,0 +1,5 @@ +import "https://esm.sh/@supabase/functions-js/src/edge-runtime.d.ts"; +import proxyToResponseWrapper from "../lib/utils/proxy-to-response-wrapper.ts"; +import fillDebateBillIds from "../lib/shared-functions/fill-debate-bill-ids.ts"; + +Deno.serve(proxyToResponseWrapper(fillDebateBillIds)); diff --git a/supabase/functions/fill-debate-speaker-ids/index.ts b/supabase/functions/fill-debate-speaker-ids/index.ts new file mode 100644 index 0000000..0f8c917 --- /dev/null +++ b/supabase/functions/fill-debate-speaker-ids/index.ts @@ -0,0 +1,5 @@ +import "https://esm.sh/@supabase/functions-js/src/edge-runtime.d.ts"; +import proxyToResponseWrapper from "../lib/utils/proxy-to-response-wrapper.ts"; +import fillDebateSpeakerIds from "../lib/shared-functions/fill-debate-speaker-ids.ts"; + +Deno.serve(proxyToResponseWrapper(fillDebateSpeakerIds)); diff --git a/supabase/functions/generate-debate-summary/index.ts b/supabase/functions/generate-debate-summary/index.ts new file mode 100644 index 0000000..3063e2d --- /dev/null +++ b/supabase/functions/generate-debate-summary/index.ts @@ -0,0 +1,5 @@ +import "https://esm.sh/@supabase/functions-js/src/edge-runtime.d.ts"; +import proxyToResponseWrapper from "../lib/utils/proxy-to-response-wrapper.ts"; +import generateDebateSummary from "../lib/shared-functions/generate-debate-summary.ts"; + +Deno.serve(proxyToResponseWrapper(generateDebateSummary)); diff --git a/supabase/functions/lib/sensitive/README.md b/supabase/functions/lib/sensitive/README.md new file mode 100644 index 0000000..e69dcd8 --- /dev/null +++ b/supabase/functions/lib/sensitive/README.md @@ -0,0 +1,2 @@ +This folder should not be committed to git, because it +contains sensitive or copyrighted data. \ No newline at end of file diff --git a/supabase/functions/lib/sensitive/prompt-examples.ts.example b/supabase/functions/lib/sensitive/prompt-examples.ts.example new file mode 100644 index 0000000..cafefce --- /dev/null +++ b/supabase/functions/lib/sensitive/prompt-examples.ts.example @@ -0,0 +1,10 @@ +export const summaryBulletPointExamples = [ + { + user: "Example prompt", + assistant: "Example summary", + }, + { + user: "Example prompt 2", + assistant: "Example summary 2", + } +]; diff --git a/supabase/functions/lib/shared-functions/fill-debate-bill-ids.ts b/supabase/functions/lib/shared-functions/fill-debate-bill-ids.ts new file mode 100644 index 0000000..03daaf4 --- /dev/null +++ b/supabase/functions/lib/shared-functions/fill-debate-bill-ids.ts @@ -0,0 +1,78 @@ +import buildResponseProxy from "../utils/build-response-proxy.ts"; +import { createSupabase } from "../utils/create-supabase.ts"; +import { isAdmin } from "../utils/check-admin.ts"; +import { SupabaseClient } from "https://esm.sh/v135/@supabase/supabase-js@2.24.0/dist/module/index.d.ts"; + +async function getDebatesWithNoBillLinked(supabase: SupabaseClient) { + const { data, error } = await supabase + .from("debate") + .select("id, title, bill_id") + .is("bill_id", null); + if (error) throw error; + return data; +} + +async function fetchBillIdFromBillName( + supabase: SupabaseClient, + billName: string, +) { + const { data, error } = await supabase + .from("bill") + .select("id") + .eq("name", billName) + .limit(1) + .maybeSingle(); + if (error) throw error; + + const result = data ? data.id : null; + console.log(`Found bill ID for ${billName}: ${result}`); + + return result; +} + +async function updateDebateWithBillId( + supabase: SupabaseClient, + rowId: number, + billId: number, +) { + const { error } = await supabase + .from("debate") + .update({ bill_id: billId }) + .eq("id", rowId); + if (error) throw error; +} + +// Goes through all debate speeches and fills in the bill_id field via the title field +// This is to enable dynamic aliasing without needing to re-scrape the entire database +export default async function fillDebateBillIds(req: Request) { + const supabase = createSupabase(); + + if (!isAdmin(req)) { + return buildResponseProxy({ message: "Unauthorised." }, 401); + } + + let rowCount = 0; + let potentialRowCount = 0; + + const debatesWithNoBillLinked = await getDebatesWithNoBillLinked(supabase); + + for (const debateWithNoBillLinked of debatesWithNoBillLinked) { + const billId = await fetchBillIdFromBillName( + supabase, + debateWithNoBillLinked.title, + ); + + // We assume that we are only working with billId = null rows, so if billId is still null, + // don't bother updating it. + if (billId) { + await updateDebateWithBillId(supabase, debateWithNoBillLinked.id, billId); + rowCount++; + } + + potentialRowCount++; + } + + return buildResponseProxy({ + message: `Filled bill IDs for ${rowCount} out of ${potentialRowCount} debates.`, + }); +} diff --git a/supabase/functions/lib/shared-functions/fill-debate-speaker-ids.ts b/supabase/functions/lib/shared-functions/fill-debate-speaker-ids.ts new file mode 100644 index 0000000..bb43168 --- /dev/null +++ b/supabase/functions/lib/shared-functions/fill-debate-speaker-ids.ts @@ -0,0 +1,79 @@ +import buildResponseProxy from "../utils/build-response-proxy.ts"; +import { createSupabase } from "../utils/create-supabase.ts"; +import { isAdmin } from "../utils/check-admin.ts"; +import { SupabaseClient } from "https://esm.sh/v135/@supabase/supabase-js@2.24.0/dist/module/index.d.ts"; + +async function getDebateSpeechRows(supabase: SupabaseClient) { + const { data, error } = await supabase + .from("debate_speech") + .select("id, speaker_name, fill_debate_speaker_ids_updated_at") + .is("speaker_id", null) + // Update the earliest-updated ones first + .order("fill_debate_speaker_ids_updated_at", { ascending: true }) + // Just make it explicit; Supabase already limits to 1000 by default + .limit(100); + if (error) throw error; + return data; +} + +async function fetchSpeakerIdWithSpeakerName( + supabase: SupabaseClient, + speakerName: string, +) { + const { data, error } = await supabase + .from("combined_mp_names_view") + .select("mp_id") + .or(`full_name.eq."${speakerName}", alias_name.eq."${speakerName}"`) + .limit(1) + .maybeSingle(); + if (error) throw error; + return data ? data.mp_id : null; +} + +async function updateDebateSpeechRowWithSpeakerId( + supabase: SupabaseClient, + rowId: number, + speakerId: number, +) { + const { error } = await supabase + .from("debate_speech") + .update({ + speaker_id: speakerId, + fill_debate_speaker_ids_updated_at: new Date(), + }) + .eq("id", rowId); + if (error) throw error; +} + +// Goes through all debate speeches and fills in the speaker_id field via the speaker_name field +// This is to enable dynamic aliasing without needing to re-scrape the entire database +export default async function fillDebateSpeakerIds(req: Request) { + const supabase = createSupabase(); + + if (!isAdmin(req)) { + return buildResponseProxy({ message: "Unauthorised." }, 401); + } + + let rowCount = 0; + let potentialRowCount = 0; + + const debateSpeechRows = await getDebateSpeechRows(supabase); + + for (const row of debateSpeechRows) { + const speakerId = await fetchSpeakerIdWithSpeakerName( + supabase, + row.speaker_name, + ); + + await updateDebateSpeechRowWithSpeakerId(supabase, row.id, speakerId); + if (speakerId) { + rowCount++; + } + + potentialRowCount++; + } + + return buildResponseProxy({ + message: `Filled speaker IDs for ${rowCount} out of ${potentialRowCount} debate speeches.`, + }); +} diff --git a/supabase/functions/lib/shared-functions/generate-bills-summary.ts b/supabase/functions/lib/shared-functions/generate-bills-summary.ts index e0e888f..8e462e1 100644 --- a/supabase/functions/lib/shared-functions/generate-bills-summary.ts +++ b/supabase/functions/lib/shared-functions/generate-bills-summary.ts @@ -2,7 +2,13 @@ import { createSupabase } from "../utils/create-supabase.ts"; import createOpenAi from "../utils/create-openai.ts"; import { isAdmin } from "../utils/check-admin.ts"; import buildResponseProxy from "../utils/build-response-proxy.ts"; -import { TextContentBlock } from "https://deno.land/x/openai@v4.53.0/resources/beta/threads/messages.ts"; +import promptExamplesToMessages from "../utils/prompt-examples-to-messages.ts"; +import { summaryBulletPointExamples } from "../sensitive/prompt-examples.ts"; +import { + ChatCompletionAssistantMessageParam, + ChatCompletionSystemMessageParam, + ChatCompletionUserMessageParam, +} from "https://deno.land/x/openai@v4.53.0/resources/chat/completions.ts"; function restrictInputLength(input: string, length: number) { return input.length <= length ? input : input.substring(0, length); @@ -34,10 +40,16 @@ export default async function generateBillsSummary(req: Request) { console.log( `Attempting to generate summary for bill from row ID ${row_with_null_summary.id}...`, ); - const run = await openai.beta.threads.createAndRunPoll({ - assistant_id: Deno.env.get("OPENAI_BILL_SUMMARY_ASSISTANT_ID")!, - thread: { - messages: [ + const response = await openai.chat.completions.create({ + messages: [ + { + role: "system", + content: + "You are a helpful assistant. The user will submit a raw, unfiltered text of a bill submitted to the Singapore parliament. Please SUMMARIZE the bill into a THREE to FIVE CONCISE bullet points. The bullet points must be FLAT (there should NOT be headers and sub-bullet points).", + }, + ] + .concat(promptExamplesToMessages(summaryBulletPointExamples)) + .concat([ { role: "user", // The input length limit is 256,000 characters for GPT 4o mini, independent of the token limit @@ -46,30 +58,24 @@ export default async function generateBillsSummary(req: Request) { 256000, ), }, - ], - }, + ]) as ( + | ChatCompletionAssistantMessageParam + | ChatCompletionUserMessageParam + | ChatCompletionSystemMessageParam + )[], + model: "gpt-4o-mini", }); - if (run.status == "completed") { - const responses = await openai.beta.threads.messages.list(run.thread_id, { - run_id: run.id, - }); - const summary = (responses.data[0].content[0] as TextContentBlock).text - .value; - console.log(`Summary generated: ${summary}`); + const summary = response.choices[0].message.content; + console.log(`Summary generated: ${summary}`); - const { error: updateError } = await supabase - .from("bill") - .update({ summary }) - .eq("id", row_with_null_summary.id); - if (updateError) throw updateError; + const { error: updateError } = await supabase + .from("bill") + .update({ summary }) + .eq("id", row_with_null_summary.id); + if (updateError) throw updateError; - return buildResponseProxy({ - message: `Added generated summary to row ID ${row_with_null_summary.id}.`, - }); - } else { - throw new Error( - `Summary generation failed. The run dump is as follows: ${JSON.stringify(run)}`, - ); - } + return buildResponseProxy({ + message: `Added generated summary to row ID ${row_with_null_summary.id}.`, + }); } diff --git a/supabase/functions/lib/shared-functions/generate-debate-summary.ts b/supabase/functions/lib/shared-functions/generate-debate-summary.ts new file mode 100644 index 0000000..9473d6c --- /dev/null +++ b/supabase/functions/lib/shared-functions/generate-debate-summary.ts @@ -0,0 +1,107 @@ +import { createSupabase } from "../utils/create-supabase.ts"; +import createOpenAi from "../utils/create-openai.ts"; +import { isAdmin } from "../utils/check-admin.ts"; +import buildResponseProxy from "../utils/build-response-proxy.ts"; +import { SupabaseClient } from "https://esm.sh/v135/@supabase/supabase-js@2.24.0/dist/module/index.d.ts"; +import promptExamplesToMessages from "../utils/prompt-examples-to-messages.ts"; +import { summaryBulletPointExamples } from "../sensitive/prompt-examples.ts"; +import { + ChatCompletionAssistantMessageParam, + ChatCompletionSystemMessageParam, + ChatCompletionUserMessageParam, +} from "https://deno.land/x/openai@v4.53.0/resources/chat/completions.ts"; + +function restrictInputLength(input: string, length: number) { + return input.length <= length ? input : input.substring(0, length); +} + +async function getDebateNeedingSummary(supabase: SupabaseClient) { + // Generate the summary for the most recent debates first because we assume they are the most important + const { data, error } = await supabase + .from("debate_sortable_view") + .select("id, order_no, summary, sitting_date") + .is("summary", null) + .order("sitting_date", { ascending: false }) + .order("order_no", { ascending: false }) + .limit(1) + .maybeSingle(); + if (error) throw error; + return data; +} + +async function getDebateSpeechInputForAi( + supabase: SupabaseClient, + debateId: number, +) { + const { data, error } = await supabase + .from("debate_speech") + .select("speaker_name, content") + .eq("debate_id", debateId) + .order("order_no", { ascending: true }); + if (error) throw error; + return data + .map((speech) => `${speech.speaker_name}: ${speech.content}`) + .join("\n\n"); +} + +export default async function generateDebateSummary(req: Request) { + const supabase = createSupabase(); + const openai = createOpenAi(); + + if (!isAdmin(req)) { + return buildResponseProxy({ message: "Unauthorised." }, 401); + } + + const debate = await getDebateNeedingSummary(supabase); + if (!debate) { + return buildResponseProxy({ + message: "No debates need summary generation.", + }); + } + + console.log(`Creating AI-friendly input of debate speeches...`); + const debateSpeechInput = await getDebateSpeechInputForAi( + supabase, + debate.id, + ); + console.log(`AI-friendly input created: ${debateSpeechInput}`); + + console.log( + `Attempting to generate summary for debate from row ID ${debate.id}...`, + ); + const response = await openai.chat.completions.create({ + messages: [ + { + role: "system", + content: + "You are a helpful assistant. The user will submit a raw, unfiltered text of a debate from the Singapore parliament. Please SUMMARIZE the debate into a THREE to FIVE CONCISE bullet points. The bullet points must be FLAT (there should NOT be headers and sub-bullet points).", + }, + ] + .concat(promptExamplesToMessages(summaryBulletPointExamples)) + .concat([ + { + role: "user", + // The input length limit is 256,000 characters for GPT 4o mini, independent of the token limit + content: restrictInputLength(debateSpeechInput, 256000), + }, + ]) as ( + | ChatCompletionAssistantMessageParam + | ChatCompletionUserMessageParam + | ChatCompletionSystemMessageParam + )[], + model: "gpt-4o-mini", + }); + + const summary = response.choices[0].message.content; + console.log(`Summary generated: ${summary}`); + + const { error: updateError } = await supabase + .from("debate") + .update({ summary }) + .eq("id", debate.id); + if (updateError) throw updateError; + + return buildResponseProxy({ + message: `Added generated summary to row ID ${debate.id}.`, + }); +} diff --git a/supabase/functions/lib/shared-functions/scrape-sitting-dates.ts b/supabase/functions/lib/shared-functions/scrape-sitting-dates.ts new file mode 100644 index 0000000..3be08e1 --- /dev/null +++ b/supabase/functions/lib/shared-functions/scrape-sitting-dates.ts @@ -0,0 +1,85 @@ +import { createSupabase } from "../utils/create-supabase.ts"; +import { isAdmin } from "../utils/check-admin.ts"; +import { + DOMParser, + Element, + HTMLDocument, +} from "https://deno.land/x/deno_dom@v0.1.46/deno-dom-wasm.ts"; +import buildResponseProxy from "../utils/build-response-proxy.ts"; +import moment from "https://deno.land/x/momentjs@2.29.1-deno/mod.ts"; +import { SupabaseClient } from "https://esm.sh/v135/@supabase/supabase-js@2.24.0/dist/module/index.d.ts"; + +async function getSittingDatesHtml() { + const url = + "https://www.parliament.gov.sg/parliamentary-business/votes-and-proceedings"; + const pageSize = "40"; + return ( + await fetch(url, { + method: "POST", + body: new URLSearchParams({ PageSize: pageSize }), + }) + ).text(); +} + +function parseSittingDates(response: string) { + return new DOMParser().parseFromString(response, "text/html"); +} + +function scrapeRawStringFromContainer(container: Element) { + return container.querySelector(".xs-boxgap")!.textContent; +} + +function parseRawStringToIsoDate(rawString: string) { + const rawDateString = rawString + .trim() + .match(/Sitting on (\d{1,2} \w+ \d{4})/gm)![0]; + const date = moment(rawDateString, "D MMM YYYY"); + return date.toISOString(); +} + +function scrapeFromParsedHtml(doc: HTMLDocument) { + const containers = doc.querySelectorAll(".indv-votes") as Iterable; + return Array.from(containers).map((container) => { + const rawString = scrapeRawStringFromContainer(container); + const sittingDate = parseRawStringToIsoDate(rawString); + return { + sitting_date: sittingDate, + }; + }); +} + +async function uploadSittingDates( + supabase: SupabaseClient, + sittingDates: { sitting_date: string }[], +) { + const { error } = await supabase.from("sitting_date").upsert(sittingDates, { + onConflict: "sitting_date", + ignoreDuplicates: true, + }); + if (error) throw error; +} + +// Scrapes recent bills metadata +// Does not scrape the actual bill text and does not actually summarise them +export default async function scrapeSittingDates(req: Request) { + const supabase = createSupabase(); + + if (!isAdmin(req)) { + return buildResponseProxy({ message: "Unauthorised." }, 401); + } + + console.log("Getting sitting dates HTML from URL..."); + const response = await getSittingDatesHtml(); + + console.log("Parsing the downloaded HTML..."); + console.log(response); + const doc = parseSittingDates(response); + + console.log("Scraping and uploading relevant data..."); + const sittingDates = scrapeFromParsedHtml(doc); + await uploadSittingDates(supabase, sittingDates); + + return buildResponseProxy({ + message: `Scraped and uploaded the following sitting dates, ignoring any duplication: ${JSON.stringify(sittingDates)}`, + }); +} diff --git a/supabase/functions/lib/shared-functions/scrape-sitting-report.ts b/supabase/functions/lib/shared-functions/scrape-sitting-report.ts index e2329e3..521e737 100644 --- a/supabase/functions/lib/shared-functions/scrape-sitting-report.ts +++ b/supabase/functions/lib/shared-functions/scrape-sitting-report.ts @@ -13,13 +13,13 @@ async function insertSpeech( supabase: SupabaseClient, orderNo: number, debateId: number, - speakerId: number | null, + speakerName: string | null, content: string, ) { const debateSpeechData = { order_no: orderNo, debate_id: debateId, - speaker_id: speakerId, + speaker_name: speakerName, content: content, }; const { error: insertDebateSpeechError } = await supabase @@ -46,6 +46,7 @@ export default async function scrapeSittingReport(req: Request) { const { data: unscrapedDateData, error: unscrapedDateError } = await supabase .from("unscraped_sitting_dates_view") .select("id, sitting_date") + .order("sitting_date", { ascending: false }) .limit(1) .maybeSingle(); if (unscrapedDateError) throw unscrapedDateError; @@ -131,7 +132,7 @@ export default async function scrapeSittingReport(req: Request) { // We insert the content buffer one last time after the loop ends to ensure that the last speech is inserted. // Also, beware not to insert an empty contentBuffer (e.g. if the first paragraph has a speaker's name). let contentBuffer = ""; - let speakerIdBuffer: number | null = null; + let speakerNameBuffer: string | null = null; let debateSpeechOrderNo = 0; for (const paragraph of paragraphs) { // Note: Trimming the raw speaker name is important, because later when we're removing the speaker name, the @@ -154,41 +155,23 @@ export default async function scrapeSittingReport(req: Request) { supabase, debateSpeechOrderNo, debateId.id, - speakerIdBuffer, + speakerNameBuffer, contentBuffer, ); debateSpeechCount++; contentBuffer = ""; - speakerIdBuffer = null; debateSpeechOrderNo++; } - let speakerNameFoundInDatabase = false; if (speakerName) { - const { data: speakerIdData, error: speakerIdError } = await supabase - .from("mp") - .select("id") - .eq("full_name", speakerName) - .maybeSingle(); - if (speakerIdError) throw speakerIdError; - if (speakerIdData) { - console.log( - `Speaker ${speakerName} found in database as ID ${speakerIdData.id}.`, - ); - speakerIdBuffer = speakerIdData.id; - speakerNameFoundInDatabase = true; - } else { - console.log(`Speaker ${speakerName} not found in database.`); - } + speakerNameBuffer = speakerName; } let content = paragraph.textContent.trim(); content = removeParagraphNumber(content); - if (speakerNameFoundInDatabase) { - // Remove (probably) the speaker name from the paragraph. - // Note that we only remove it if it's actually found in the database, - // so we don't end up with completely unknown speakers. + if (speakerName) { + // Remove (probably) the speaker name from the paragraph const needle = `${speakerNameRaw}:`; const originalContentLength = content.length; console.log( @@ -207,7 +190,10 @@ export default async function scrapeSittingReport(req: Request) { content = "\n\n" + content; } - contentBuffer += content; + // Only insert if there's actually anything to insert + if (content.trim() != "") { + contentBuffer += content; + } } if (contentBuffer.trim() != "") { console.log("Inserting last speech..."); @@ -215,7 +201,7 @@ export default async function scrapeSittingReport(req: Request) { supabase, debateSpeechOrderNo, debateId.id, - speakerIdBuffer, + speakerNameBuffer, contentBuffer, ); debateSpeechCount++; diff --git a/supabase/functions/lib/utils/build-response-proxy.ts b/supabase/functions/lib/utils/build-response-proxy.ts index daf070d..bc65e79 100644 --- a/supabase/functions/lib/utils/build-response-proxy.ts +++ b/supabase/functions/lib/utils/build-response-proxy.ts @@ -1,10 +1,12 @@ +import { corsHeaders } from "./cors.ts"; + export default function buildResponseProxy(data: object, status: number = 200) { const dataStr = JSON.stringify(data); console.info(`Proxy response ${status}: ${dataStr}`); return { body: dataStr, init: { - headers: { "Content-Type": "application/json" }, + headers: { ...corsHeaders, "Content-Type": "application/json" }, status, }, }; diff --git a/supabase/functions/lib/utils/build-response.ts b/supabase/functions/lib/utils/build-response.ts index a7cd0e6..36a0423 100644 --- a/supabase/functions/lib/utils/build-response.ts +++ b/supabase/functions/lib/utils/build-response.ts @@ -1,8 +1,10 @@ +import { corsHeaders } from "./cors.ts"; + export function buildResponse(data: object, status: number = 200) { const dataStr = JSON.stringify(data); console.info(`Response ${status}: ${dataStr}`); return new Response(dataStr, { - headers: { "Content-Type": "application/json" }, + headers: { ...corsHeaders, "Content-Type": "application/json" }, status, }); } diff --git a/supabase/functions/lib/utils/cors.ts b/supabase/functions/lib/utils/cors.ts new file mode 100644 index 0000000..02b087a --- /dev/null +++ b/supabase/functions/lib/utils/cors.ts @@ -0,0 +1,5 @@ +export const corsHeaders = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": + "authorization, x-client-info, apikey, content-type", +}; diff --git a/supabase/functions/lib/utils/prompt-examples-to-messages.ts b/supabase/functions/lib/utils/prompt-examples-to-messages.ts new file mode 100644 index 0000000..1674231 --- /dev/null +++ b/supabase/functions/lib/utils/prompt-examples-to-messages.ts @@ -0,0 +1,11 @@ +export default function promptExamplesToMessages( + promptExamples: { + user: string; + assistant: string; + }[], +) { + return promptExamples.flatMap(({ user, assistant }) => [ + { role: "user", content: user }, + { role: "assistant", content: assistant }, + ]); +} diff --git a/supabase/functions/per-1-hour/index.ts b/supabase/functions/per-1-hour/index.ts index a8107eb..432040f 100644 --- a/supabase/functions/per-1-hour/index.ts +++ b/supabase/functions/per-1-hour/index.ts @@ -1,7 +1,15 @@ import "https://esm.sh/@supabase/functions-js/src/edge-runtime.d.ts"; import { buildResponse } from "../lib/utils/build-response.ts"; import scrapeBillsIntroduced from "../lib/shared-functions/scrape-bills-introduced.ts"; +import fetchMpData from "../lib/shared-functions/fetch-mp-data.ts"; +import scrapeSittingReport from "../lib/shared-functions/scrape-sitting-report.ts"; +import scrapeSittingDates from "../lib/shared-functions/scrape-sitting-dates.ts"; Deno.serve(async (req) => { - return buildResponse([await scrapeBillsIntroduced(req)]); + return buildResponse([ + await fetchMpData(req), + await scrapeSittingDates(req), + await scrapeSittingReport(req), + await scrapeBillsIntroduced(req), + ]); }); diff --git a/supabase/functions/per-10-min/index.ts b/supabase/functions/per-10-min/index.ts index 7575193..1bf0090 100644 --- a/supabase/functions/per-10-min/index.ts +++ b/supabase/functions/per-10-min/index.ts @@ -2,10 +2,16 @@ import "https://esm.sh/@supabase/functions-js/src/edge-runtime.d.ts"; import scrapeBillsPdf from "../lib/shared-functions/scrape-bills-pdf.ts"; import generateBillsSummary from "../lib/shared-functions/generate-bills-summary.ts"; import { buildResponse } from "../lib/utils/build-response.ts"; +// import fillDebateSpeakerIds from "../lib/shared-functions/fill-debate-speaker-ids.ts"; +import generateDebateSummary from "../lib/shared-functions/generate-debate-summary.ts"; +// import fillDebateBillIds from "../lib/shared-functions/fill-debate-bill-ids.ts"; Deno.serve(async (req) => { return buildResponse([ + // await fillDebateSpeakerIds(req), + // await fillDebateBillIds(req), await scrapeBillsPdf(req), await generateBillsSummary(req), + await generateDebateSummary(req), ]); }); diff --git a/supabase/functions/scrape-sitting-dates/index.ts b/supabase/functions/scrape-sitting-dates/index.ts new file mode 100644 index 0000000..00113bb --- /dev/null +++ b/supabase/functions/scrape-sitting-dates/index.ts @@ -0,0 +1,5 @@ +import "https://esm.sh/@supabase/functions-js/src/edge-runtime.d.ts"; +import proxyToResponseWrapper from "../lib/utils/proxy-to-response-wrapper.ts"; +import scrapeSittingDates from "../lib/shared-functions/scrape-sitting-dates.ts"; + +Deno.serve(proxyToResponseWrapper(scrapeSittingDates)); diff --git a/supabase/functions/search/index.ts b/supabase/functions/search/index.ts new file mode 100644 index 0000000..738dd4e --- /dev/null +++ b/supabase/functions/search/index.ts @@ -0,0 +1,76 @@ +import "https://esm.sh/@supabase/functions-js/src/edge-runtime.d.ts"; +import { createSupabase } from "../lib/utils/create-supabase.ts"; +import { SupabaseClient } from "https://esm.sh/v135/@supabase/supabase-js@2.24.0/dist/module/index.d.ts"; +import { buildResponse } from "../lib/utils/build-response.ts"; +import { corsHeaders } from "../lib/utils/cors.ts"; + +type ClientFriendlyData = { + href: string; + title: string; +}; + +function removeDuplicates(data: T[], propertyKeyToDeduplicate: keyof T) { + const seen = new Set(); + return data.filter((item) => { + const value = item[propertyKeyToDeduplicate]; + if (seen.has(value)) { + return false; + } + seen.add(value); + return true; + }); +} + +async function getDebateSearchResults( + supabase: SupabaseClient, + query: string, +): Promise { + const { data, error } = await supabase + .from("debate_speech_full_text_view") + .select("debate_id, title") + .textSearch("full_text", query, { type: "websearch" }); + if (error) throw error; + const dedupData = removeDuplicates(data, "debate_id"); + return dedupData.map((debate) => ({ + href: `/debates/${debate.debate_id}`, + title: debate.title, + })); +} + +function flipBillNo(billNo: string) { + const [billOfYear, year] = billNo.split("/"); + return `${year}/${billOfYear}`; +} + +async function getBillSearchResults( + supabase: SupabaseClient, + query: string, +): Promise { + const { data, error } = await supabase + .from("bill_full_text_view") + .select("bill_no, name") + .textSearch("full_text", query, { type: "websearch" }); + if (error) throw error; + const dedupData = removeDuplicates(data, "bill_no"); + return dedupData.map((bill) => ({ + href: `/bills/${flipBillNo(bill.bill_no)}`, + title: bill.name, + })); +} + +Deno.serve(async (req) => { + if (req.method === "OPTIONS") { + return new Response("ok", { headers: corsHeaders }); + } + + const supabase = createSupabase(); + + const { query } = await req.json(); + const debateSearchResults = await getDebateSearchResults(supabase, query); + const billSearchResults = await getBillSearchResults(supabase, query); + + return buildResponse({ + debate: debateSearchResults, + bill: billSearchResults, + }); +});