From 2364fc23b3fbdfc2a7e2313b1efe57052e6b96ee Mon Sep 17 00:00:00 2001
From: Christina Holland <chholland@google.com>
Date: Thu, 4 Apr 2024 16:31:06 -0700
Subject: [PATCH 01/82] set up a project

---
 vertexai/.prettierrc       |    3 +
 vertexai/README.md         |   34 +
 vertexai/config.ts         |   17 +
 vertexai/index.html        |   27 +
 vertexai/main.ts           |   29 +
 vertexai/package-lock.json | 1485 ++++++++++++++++++++++++++++++++++++
 vertexai/package.json      |   31 +
 vertexai/vite-env.d.ts     |    1 +
 vertexai/vite.config.js    |   10 +
 9 files changed, 1637 insertions(+)
 create mode 100644 vertexai/.prettierrc
 create mode 100644 vertexai/README.md
 create mode 100644 vertexai/config.ts
 create mode 100644 vertexai/index.html
 create mode 100644 vertexai/main.ts
 create mode 100644 vertexai/package-lock.json
 create mode 100644 vertexai/package.json
 create mode 100644 vertexai/vite-env.d.ts
 create mode 100644 vertexai/vite.config.js

diff --git a/vertexai/.prettierrc b/vertexai/.prettierrc
new file mode 100644
index 000000000..544138be4
--- /dev/null
+++ b/vertexai/.prettierrc
@@ -0,0 +1,3 @@
+{
+  "singleQuote": true
+}
diff --git a/vertexai/README.md b/vertexai/README.md
new file mode 100644
index 000000000..c363bf6be
--- /dev/null
+++ b/vertexai/README.md
@@ -0,0 +1,34 @@
+Firebase SDK for Vertex AI Quickstart
+=========================================
+
+Introduction
+------------
+
+This is a sample app for the preview version of the Firebase Vertex AI SDK.
+This will not run if you don't have access to the preview.
+
+<!-- Introduction
+------------
+
+[Read more about Firebase SDK for Vertex AI ](https://firebase.google.com/docs/vertexai/) -->
+
+Getting Started
+---------------
+
+ 1. Create your project on the [Firebase Console](https://console.firebase.google.com).
+ 2. Enable Gemini in the console.
+ 3. Create a ReCAPTCHA Enterprise key in the same project.
+ 4. Enable App Check in the Firebase console with the ReCAPTCHA Enterprise site key you created.
+ 5. Copy your Firebase project config and your ReCAPTCHA Enterprise site key into the appropraite places in `config.ts` in this directory.
+ 6. In this directory, run `npm install`
+ 7. In this directory, run `npm run dev`
+
+<!-- Support
+-------
+
+- [Firebase Support](https://firebase.google.com/support/) -->
+
+License
+-------
+
+© Google, 2024. Licensed under an [Apache-2](../LICENSE) license.
diff --git a/vertexai/config.ts b/vertexai/config.ts
new file mode 100644
index 000000000..29c1251da
--- /dev/null
+++ b/vertexai/config.ts
@@ -0,0 +1,17 @@
+export const firebaseConfig = {
+  // Your web app's Firebase configuration here
+  // See https://firebase.google.com/docs/web/setup#add-sdks-initialize
+  apiKey: 'API_KEY',
+  authDomain: 'PROJECT_ID.firebaseapp.com',
+  databaseURL: 'https://PROJECT_ID.firebaseio.com',
+  projectId: 'PROJECT_ID',
+  storageBucket: 'PROJECT_ID.appspot.com',
+  messagingSenderId: 'SENDER_ID',
+  appId: 'APP_ID',
+  measurementId: 'G-MEASUREMENT_ID',
+};
+
+  // Your ReCAPTCHA Enterprise site key (must be from the same project
+  // as the Firebase config above).
+export const RECAPTCHA_ENTERPRISE_SITE_KEY =
+  "YOUR_SITE_KEY";
diff --git a/vertexai/index.html b/vertexai/index.html
new file mode 100644
index 000000000..8a4986a1d
--- /dev/null
+++ b/vertexai/index.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<!--
+Copyright (c) 2016 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Firebase SDK for Vertex AI Quickstart</title>
+  </head>
+  <body>
+    <div>Open browser's developer console to view console.log output.</div>
+    <script type="module" src="main.ts"></script>
+  </body>
+</html>
diff --git a/vertexai/main.ts b/vertexai/main.ts
new file mode 100644
index 000000000..b2d9c799c
--- /dev/null
+++ b/vertexai/main.ts
@@ -0,0 +1,29 @@
+import { initializeApp } from 'firebase/app';
+import { firebaseConfig, RECAPTCHA_ENTERPRISE_SITE_KEY } from './config';
+import {
+  initializeAppCheck,
+  ReCaptchaEnterpriseProvider,
+} from "firebase/app-check";
+import { getVertexAI, getGenerativeModel } from "firebase/vertexai";
+
+async function main() {
+  const app = initializeApp(firebaseConfig);
+
+  // initialize app check
+  initializeAppCheck(app, {
+    provider: new ReCaptchaEnterpriseProvider(RECAPTCHA_ENTERPRISE_SITE_KEY),
+  });
+
+  // Get vertex instance
+  const vertexAI = getVertexAI(app);
+  // Get a gemini model
+  const model = getGenerativeModel(
+    vertexAI,
+    { model: "gemini-1.0-pro" }
+  );
+  // Call generateContent with a string or Content(s)
+  const generateContentResult = await model.generateContent("what is a cat?");
+  console.log(generateContentResult.response.text());
+}
+
+main();
diff --git a/vertexai/package-lock.json b/vertexai/package-lock.json
new file mode 100644
index 000000000..5941aeb4d
--- /dev/null
+++ b/vertexai/package-lock.json
@@ -0,0 +1,1485 @@
+{
+  "name": "quickstart-js-storage",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "quickstart-js-storage",
+      "version": "1.0.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "firebase": "10.10.0-vertexai-preview.cdcc49eb9"
+      },
+      "devDependencies": {
+        "typescript": "^5.1.6",
+        "vite": "^4.4.9"
+      },
+      "engines": {
+        "node": ">=18.0.0 <=20.0.0",
+        "npm": ">=9.0.0 <10.0.0"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
+      "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
+      "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
+      "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
+      "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
+      "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
+      "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
+      "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
+      "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
+      "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
+      "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
+      "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
+      "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
+      "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
+      "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
+      "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
+      "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
+      "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
+      "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
+      "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
+      "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
+      "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
+      "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@fastify/busboy": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
+      "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@firebase/analytics": {
+      "version": "0.10.2-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.2-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-qEr8ugckOMCmJ6ZY5K3iafzzpxabh8ny3L46mjFE+VC+t3CsiJcEsAgtFJz8kvwf98yg5y2I8UVgBoqvXbLvxQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/analytics-compat": {
+      "version": "0.2.8-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.8-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-8Gw1m6eFLTUpwk/oTSVZMVWC8AcUM2NYiFGGnxa/z+3t7cbIcquw4t43G7RqTkAeiGKvFVLWrwkG+OHVd2wQXw==",
+      "dependencies": {
+        "@firebase/analytics": "0.10.2-vertexai-preview.cdcc49eb9",
+        "@firebase/analytics-types": "0.8.1-vertexai-preview.cdcc49eb9",
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/analytics-types": {
+      "version": "0.8.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-hhxXpMMJXZsK5ye68j3bwfPvHQtEdUXGTy5X28HN+q+l8xH8zjtcKsV86DAIarf6XB4QDDlurmiantj8kP1B1Q=="
+    },
+    "node_modules/@firebase/app": {
+      "version": "0.10.0-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.0-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-DZOOkkR4nSxdNkzL1b28ZTLVLt//CDy+hekvTJQTd9zt/NXk6xcRA7VcV5C7hxmj/j5J+nljNoBzzU9J2yaFmw==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/app-check": {
+      "version": "0.8.3-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.3-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-G35xeFLhoR0T73rRzMW3jHFhwi/2vscW+Sgm47ScP94Iak6wbKbmqTCeGzhDgzk0XWc2eIKYXz/J6ZDmgJcOsQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/app-check-compat": {
+      "version": "0.3.10-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.10-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-CpHVhLFmDtk6TrrhoGYj0hg1A4L6/08UqLNa2v7qxjgJt+iNuQuc0dHf2bq+pHCdRbNJR3NlbkBAYqo/tY670w==",
+      "dependencies": {
+        "@firebase/app-check": "0.8.3-vertexai-preview.cdcc49eb9",
+        "@firebase/app-check-types": "0.5.1-vertexai-preview.cdcc49eb9",
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/app-check-interop-types": {
+      "version": "0.3.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-x2INt1H0UoQICzA1U9IPA4LN98TrJXe37QioZkE5X7hDrpQlBNQNiNXJCenKO2qjrBffM2DtzTP5Sg653zgftQ=="
+    },
+    "node_modules/@firebase/app-check-types": {
+      "version": "0.5.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-QsZmTShocp7zRwPF+YfOOy57E/Okf2Xx9CeKdpF4EOfM6PX32GmXqY9OskAXhfoXtpapzyZUOc5hL7bdZcR2tA=="
+    },
+    "node_modules/@firebase/app-compat": {
+      "version": "0.2.30-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.30-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-557LV5WD89NoLwX9Rvdkg27vHVgaz2DWDmBZ8KoLoWYQWlIgXVINCtKNZy/hzx81DUj39+i6jd4ZJmR6Z0Kabg==",
+      "dependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9",
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/app-types": {
+      "version": "0.9.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-dVUM9xoGTZbZA9u88yOWeM94nyPqr8h3ktpKN4C0tdeHDjcj1M+BOMuNsoodKkzIrjJleCY3cLzkon18PWbuOw=="
+    },
+    "node_modules/@firebase/auth": {
+      "version": "1.7.0-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.0-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-F6KJV+WQE61TJ495fVYT8/6dcEeqv3jxQjeAY3Ecdw92XGNodenKPB8Cc4ZwYQrfVzdk1CdeTzhv0tVX95rwkg==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0",
+        "undici": "5.28.3"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9",
+        "@react-native-async-storage/async-storage": "^1.18.1"
+      },
+      "peerDependenciesMeta": {
+        "@react-native-async-storage/async-storage": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@firebase/auth-compat": {
+      "version": "0.5.5-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.5-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-77Hoq5W2gcQUtOEOF+4mlH6xD7tl65cCrhKbm/E0COSQycBgLBdgN0X7LJLLR4q9J5CTBQVLYKkW8IRHlbcg5A==",
+      "dependencies": {
+        "@firebase/auth": "1.7.0-vertexai-preview.cdcc49eb9",
+        "@firebase/auth-types": "0.12.1-vertexai-preview.cdcc49eb9",
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0",
+        "undici": "5.28.3"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/auth-interop-types": {
+      "version": "0.2.2-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.2-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-YP12+H5e1ythsDtObLRGucc3tBe8Gv0dSOpw3/vHVtlTnS13t2K5cxLoSDXt1kG2hMeUpc4YwRHsjyzZjcBZAg=="
+    },
+    "node_modules/@firebase/auth-types": {
+      "version": "0.12.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-pb3LAtFCTqCQFx0WQBqmLrs8qmbrk6Y9j5sGNianpGGV5kzJrGOwMuamdDaCbxyYJUaPOb0UmMGvUIv4jCqXrw==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/component": {
+      "version": "0.6.6-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.6-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-Zd9aLXQf3qWLDhK+5X4ZFTMBSvV97f2bF//NbWbGfFX2ix35uIpGiajziMLyw04TcPiiZ6t50ep5WlhQJLA8ig==",
+      "dependencies": {
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/database": {
+      "version": "1.0.4-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.4-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-H6UpDKrws1swyatqG8XX7MarmuEAe+alpH2pD2nc1qF2E8dUxDgQU45MjP/lpjewLXGvfZfcnyMu8blua5/P2w==",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.1-vertexai-preview.cdcc49eb9",
+        "@firebase/auth-interop-types": "0.2.2-vertexai-preview.cdcc49eb9",
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "faye-websocket": "0.11.4",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/database-compat": {
+      "version": "1.0.4-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.4-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-7FiE4P+K8BAovzCjFUYuaNXnJN0FoT08NQlfYUopAHuhCQdtXA2F3HSOgXWk73Wf7eozzGCmDB1xXDvrjtCS8g==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/database": "1.0.4-vertexai-preview.cdcc49eb9",
+        "@firebase/database-types": "1.0.2-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/database-types": {
+      "version": "1.0.2-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.2-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-C0J1K4tt6V1yQwyuYZeX1BvygyOpzB41RLsC6awnGb3RvkdF+3+nB0kUdO691aWHhRcXE3ADE9rQykIkbd9lfA==",
+      "dependencies": {
+        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/firestore": {
+      "version": "4.5.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.5.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-4suHqELbQr5YOUJ39pItLJPxe9dqLieyNCnu3SCML5NmjMGipInbSvBsaPeALsg+ln1VD38GT+RfLn03wgEYLA==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "@firebase/webchannel-wrapper": "0.10.6-vertexai-preview.cdcc49eb9",
+        "@grpc/grpc-js": "~1.9.0",
+        "@grpc/proto-loader": "^0.7.8",
+        "tslib": "^2.1.0",
+        "undici": "5.28.3"
+      },
+      "engines": {
+        "node": ">=10.10.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/firestore-compat": {
+      "version": "0.3.28-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.28-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-8d4NjeAGlw1jlMwzS83D71UnFPGC9PoSc12YobfuBKaT3mA99mHD3jQrskF7p1bUWHuNDu3+zSFC7GNazAu/lg==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/firestore": "4.5.1-vertexai-preview.cdcc49eb9",
+        "@firebase/firestore-types": "3.0.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/firestore-types": {
+      "version": "3.0.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-PGrbBAStLQIWlSkdH55qllCACteWHHcs4zbZYBd6d1dItg53HN3LIor7avqx33gGma+xFdtk4clXOdHILIQiVQ==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/functions": {
+      "version": "0.11.3-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.3-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-xBy/1+kVe8IaTQfWbI/QJS5a6SHycr6dmyZ2KNZNSA5C56Kgdq4CK62whmVp06SgvspXis5XkhNwt5427d+dUw==",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.1-vertexai-preview.cdcc49eb9",
+        "@firebase/auth-interop-types": "0.2.2-vertexai-preview.cdcc49eb9",
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/messaging-interop-types": "0.2.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0",
+        "undici": "5.28.3"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/functions-compat": {
+      "version": "0.3.9-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.9-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-MQVWu4P7TlQJZ8YHB94atK7ZE9uwKTIljBUQrpeM/rgp9orX4WYjVfaZR/Mz9BHC827IGi3XVl8WAE+3J9vTKQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/functions": "0.11.3-vertexai-preview.cdcc49eb9",
+        "@firebase/functions-types": "0.6.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/functions-types": {
+      "version": "0.6.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-vuPC8YVWygIcAOfHroQuuWbIlSJqwXlrhX0TkripGns07DK3awLiZ6MLUlAQMIyEMQY8uhEQMdg9OX6eJY3l6w=="
+    },
+    "node_modules/@firebase/installations": {
+      "version": "0.6.6-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.6-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-Y5AzABFnv6AfXIdTG1gz8OGuZyRXP21KRmr6vLv145MsLii83UyZ7A6GBvtweJMqEaY2Py3K5eR0VDVUR9npbQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/installations-compat": {
+      "version": "0.2.6-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.6-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-qMj/v5V9KlAZ1/a8orp8OCz51bA4CpLYoUIIYdkk6mCswCJ6cWgxPGF+Br2LW3oHlsJS9AqRK/eqy6nfzGDeuw==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/installations-types": "0.5.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/installations-types": {
+      "version": "0.5.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-1q5su0TDGNstaLLEfXtmNK19UyFh1Oux3DBOo36EF3v9j0XrQUhkyObagqMw6e6Fcxme/bxmluC1ba4tXLW6lw==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/logger": {
+      "version": "0.4.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-f0slz1qiXo5DvC3QaogS0vk6wBlBjNS2o0iuG5BqPEFQqjxZ5UU6+Yutq44Pzm6+j153t8/i/epzd9NGWQUZ4A==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/messaging": {
+      "version": "0.12.7-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.7-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-j2tf1EX+czhM+PLHnRxD0Vppr5NzV1Sxw4anETAhJlYkNfgNMV1ycN+39cSlwOio7tmb+HmxDo6b6KKor+pVsw==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/messaging-interop-types": "0.2.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/messaging-compat": {
+      "version": "0.2.7-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.7-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-2zgsgrSoGl+lOP9yh2i+C6WUcIDA6EgIUhquKR7BHmPLhMpunfYHzf5je+SnGDNrXz4nsI++qqBrZDNETNxV/g==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/messaging": "0.12.7-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/messaging-interop-types": {
+      "version": "0.2.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-1xv+vcy8KV98gYq1ezbHYsWPOvr8FWCdzoCJ4KYA2LksizVgO87bDCTT+xy4wqdmS04hZCagKdaMjanus/Hufg=="
+    },
+    "node_modules/@firebase/performance": {
+      "version": "0.6.6-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.6-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-5g25iALetNRGQq6E2v93qx1oDujPrvsyxPY1tcjbSgJZC6l19Yn0RxcyoMzoaq6ZFy3SegeESLhi44vhB2wkww==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/performance-compat": {
+      "version": "0.2.6-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.6-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-fTfariqtN+XO/rSe36Ik0/eAqsScKDvJwHh8WU5DsLNl5Gm9KS6eMN6ZXvts8ytDcpFZnproSpiWqcI1t3+bpQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/performance": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/performance-types": "0.2.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/performance-types": {
+      "version": "0.2.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-El7jehLnPbvNmlt42qt5VPcmZVfyR5xMT2EQRPUBYsMcczHFV/aAhykQYckrTFMqsBrOTymUvvmeLznbGjeOBA=="
+    },
+    "node_modules/@firebase/remote-config": {
+      "version": "0.4.6-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.6-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-G9BtzLMw/K4S5QCTs9soiDedBB/Yj3+GOgnmn7Xb9TKKTQDm6srqtKPv/0n1fkreBZ1Xnviv7vU2Gn3CeCGT0Q==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/remote-config-compat": {
+      "version": "0.2.6-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.6-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-FiEhgRoR+Y9VGQ9QNO6kdWfLQitW8jdAX9ju3ypkjTR1SVGsFUYYfmzBrxn1AOYVbJLcrL3X916l9tcMsUBcJA==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/remote-config": "0.4.6-vertexai-preview.cdcc49eb9",
+        "@firebase/remote-config-types": "0.3.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/remote-config-types": {
+      "version": "0.3.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-mJBNvZLU3mxX08Dat156cI6XB/RQ5NGJ9k464yMkK3slN021pO47VwEdudodt/RDwksemyG5AUDFzLzi/a7b8w=="
+    },
+    "node_modules/@firebase/storage": {
+      "version": "0.12.3-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.3-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-UcPOfZsjOppMJX21UDy1CS1XzKdoLWdQ0M0ywl7ONulkUIkm9SbdYtn3VpT6yOMgfTAGwkG7ujn+vqT41yxsmw==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0",
+        "undici": "5.28.3"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/storage-compat": {
+      "version": "0.3.6-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.6-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-PwZnndgz2dfxNDIPDkBnhbTnvkVAO0/vlJNLYQtxYrzmRh/ZkJw54u4uYkabwJfa6IrdSs4BW0D6UoNnLjh4BQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/storage": "0.12.3-vertexai-preview.cdcc49eb9",
+        "@firebase/storage-types": "0.8.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/storage-types": {
+      "version": "0.8.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-6t4BdPWxZekVgNWphAbQ0lEyedwRH72F465pH1rt7yGKvRvXzyvfGxYJA8E1zl2YmZQIT1cq64+zmV7wqX29gQ==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/util": {
+      "version": "1.9.5-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.5-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-Y8h9N+UitIbUbDwm6XBJISb2lupeBh5ShMheWfIAaFdzs58eWW6aEGrW/MtWGhf5mXBqcF91zBnLmo1dn22uSw==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/vertexai": {
+      "version": "0.0.1-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-0.0.1-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-lzDjq4BVrkqI2A5YMzLCSLQWNDkOMgjVuNn0pHjGh19XizUxcn31n9P+b2Dd9+pSoR1mB7E/C2J+lZXlwK+76A==",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.1-vertexai-preview.cdcc49eb9",
+        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9",
+        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/@firebase/webchannel-wrapper": {
+      "version": "0.10.6-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.6-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-EF5ULMUh51ZwmRN48NknnpTTlGxW5tx0lGUh2sYlZMROpmtpsSpn5kLoLF64igU+GEEkVc4i0Dym2XyuHveirQ=="
+    },
+    "node_modules/@grpc/grpc-js": {
+      "version": "1.9.14",
+      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz",
+      "integrity": "sha512-nOpuzZ2G3IuMFN+UPPpKrC6NsLmWsTqSsm66IRfnBt1D4pwTqE27lmbpcPM+l2Ua4gE7PfjRHI6uedAy7hoXUw==",
+      "dependencies": {
+        "@grpc/proto-loader": "^0.7.8",
+        "@types/node": ">=12.12.47"
+      },
+      "engines": {
+        "node": "^8.13.0 || >=10.10.0"
+      }
+    },
+    "node_modules/@grpc/proto-loader": {
+      "version": "0.7.12",
+      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.12.tgz",
+      "integrity": "sha512-DCVwMxqYzpUCiDMl7hQ384FqP4T3DbNpXU8pt681l3UWCip1WUiD5JrkImUwCB9a7f2cq4CUTmi5r/xIMRPY1Q==",
+      "dependencies": {
+        "lodash.camelcase": "^4.3.0",
+        "long": "^5.0.0",
+        "protobufjs": "^7.2.4",
+        "yargs": "^17.7.2"
+      },
+      "bin": {
+        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+    },
+    "node_modules/@types/node": {
+      "version": "20.12.4",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz",
+      "integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==",
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+    },
+    "node_modules/esbuild": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
+      "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "@esbuild/android-arm": "0.18.20",
+        "@esbuild/android-arm64": "0.18.20",
+        "@esbuild/android-x64": "0.18.20",
+        "@esbuild/darwin-arm64": "0.18.20",
+        "@esbuild/darwin-x64": "0.18.20",
+        "@esbuild/freebsd-arm64": "0.18.20",
+        "@esbuild/freebsd-x64": "0.18.20",
+        "@esbuild/linux-arm": "0.18.20",
+        "@esbuild/linux-arm64": "0.18.20",
+        "@esbuild/linux-ia32": "0.18.20",
+        "@esbuild/linux-loong64": "0.18.20",
+        "@esbuild/linux-mips64el": "0.18.20",
+        "@esbuild/linux-ppc64": "0.18.20",
+        "@esbuild/linux-riscv64": "0.18.20",
+        "@esbuild/linux-s390x": "0.18.20",
+        "@esbuild/linux-x64": "0.18.20",
+        "@esbuild/netbsd-x64": "0.18.20",
+        "@esbuild/openbsd-x64": "0.18.20",
+        "@esbuild/sunos-x64": "0.18.20",
+        "@esbuild/win32-arm64": "0.18.20",
+        "@esbuild/win32-ia32": "0.18.20",
+        "@esbuild/win32-x64": "0.18.20"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+      "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/faye-websocket": {
+      "version": "0.11.4",
+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+      "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+      "dependencies": {
+        "websocket-driver": ">=0.5.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/firebase": {
+      "version": "10.10.0-vertexai-preview.cdcc49eb9",
+      "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.10.0-vertexai-preview.cdcc49eb9.tgz",
+      "integrity": "sha512-viCfzUAEyTejZ2tFx0Oc1xmbNOSZ5Fn6e2Obv7Rm9Uk27uMDDS5/og86MRlFvlUsFrQrku24ddJcnbNfiko0Kw==",
+      "dependencies": {
+        "@firebase/analytics": "0.10.2-vertexai-preview.cdcc49eb9",
+        "@firebase/analytics-compat": "0.2.8-vertexai-preview.cdcc49eb9",
+        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9",
+        "@firebase/app-check": "0.8.3-vertexai-preview.cdcc49eb9",
+        "@firebase/app-check-compat": "0.3.10-vertexai-preview.cdcc49eb9",
+        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9",
+        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
+        "@firebase/auth": "1.7.0-vertexai-preview.cdcc49eb9",
+        "@firebase/auth-compat": "0.5.5-vertexai-preview.cdcc49eb9",
+        "@firebase/database": "1.0.4-vertexai-preview.cdcc49eb9",
+        "@firebase/database-compat": "1.0.4-vertexai-preview.cdcc49eb9",
+        "@firebase/firestore": "4.5.1-vertexai-preview.cdcc49eb9",
+        "@firebase/firestore-compat": "0.3.28-vertexai-preview.cdcc49eb9",
+        "@firebase/functions": "0.11.3-vertexai-preview.cdcc49eb9",
+        "@firebase/functions-compat": "0.3.9-vertexai-preview.cdcc49eb9",
+        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/installations-compat": "0.2.6-vertexai-preview.cdcc49eb9",
+        "@firebase/messaging": "0.12.7-vertexai-preview.cdcc49eb9",
+        "@firebase/messaging-compat": "0.2.7-vertexai-preview.cdcc49eb9",
+        "@firebase/performance": "0.6.6-vertexai-preview.cdcc49eb9",
+        "@firebase/performance-compat": "0.2.6-vertexai-preview.cdcc49eb9",
+        "@firebase/remote-config": "0.4.6-vertexai-preview.cdcc49eb9",
+        "@firebase/remote-config-compat": "0.2.6-vertexai-preview.cdcc49eb9",
+        "@firebase/storage": "0.12.3-vertexai-preview.cdcc49eb9",
+        "@firebase/storage-compat": "0.3.6-vertexai-preview.cdcc49eb9",
+        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
+        "@firebase/vertexai": "0.0.1-vertexai-preview.cdcc49eb9"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/http-parser-js": {
+      "version": "0.5.8",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+      "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q=="
+    },
+    "node_modules/idb": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
+      "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
+    },
+    "node_modules/long": {
+      "version": "5.2.3",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
+      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.7",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+      "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+      "dev": true
+    },
+    "node_modules/postcss": {
+      "version": "8.4.38",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
+      "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "nanoid": "^3.3.7",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.2.0"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/protobufjs": {
+      "version": "7.2.6",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz",
+      "integrity": "sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "3.29.4",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
+      "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
+      "dev": true,
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=14.18.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+      "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+      "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+    },
+    "node_modules/typescript": {
+      "version": "5.4.4",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
+      "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
+      "dev": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/undici": {
+      "version": "5.28.3",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
+      "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
+      "dependencies": {
+        "@fastify/busboy": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=14.0"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
+    },
+    "node_modules/vite": {
+      "version": "4.5.3",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz",
+      "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==",
+      "dev": true,
+      "dependencies": {
+        "esbuild": "^0.18.10",
+        "postcss": "^8.4.27",
+        "rollup": "^3.27.1"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      },
+      "peerDependencies": {
+        "@types/node": ">= 14",
+        "less": "*",
+        "lightningcss": "^1.21.0",
+        "sass": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/websocket-driver": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+      "dependencies": {
+        "http-parser-js": ">=0.5.1",
+        "safe-buffer": ">=5.1.0",
+        "websocket-extensions": ">=0.1.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/websocket-extensions": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs": {
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "engines": {
+        "node": ">=12"
+      }
+    }
+  }
+}
diff --git a/vertexai/package.json b/vertexai/package.json
new file mode 100644
index 000000000..dcd5106e4
--- /dev/null
+++ b/vertexai/package.json
@@ -0,0 +1,31 @@
+{
+  "name": "quickstart-js-storage",
+  "version": "1.0.0",
+  "description": "JavaScript quickstarts for Firebase Storage.",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/firebase/quickstart-js.git"
+  },
+  "author": "",
+  "license": "Apache-2.0",
+  "bugs": {
+    "url": "https://github.com/firebase/quickstart-js/issues"
+  },
+  "engines": {
+    "npm": ">=9.0.0 <10.0.0",
+    "node": ">=18.0.0 <=20.0.0"
+  },
+  "homepage": "https://github.com/firebase/quickstart-js#readme",
+  "devDependencies": {
+    "typescript": "^5.1.6",
+    "vite": "^4.4.9"
+  },
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "format": "prettier --write ."
+  },
+  "dependencies": {
+    "firebase": "10.10.0-vertexai-preview.cdcc49eb9"
+  }
+}
diff --git a/vertexai/vite-env.d.ts b/vertexai/vite-env.d.ts
new file mode 100644
index 000000000..11f02fe2a
--- /dev/null
+++ b/vertexai/vite-env.d.ts
@@ -0,0 +1 @@
+/// <reference types="vite/client" />
diff --git a/vertexai/vite.config.js b/vertexai/vite.config.js
new file mode 100644
index 000000000..c2afa66fa
--- /dev/null
+++ b/vertexai/vite.config.js
@@ -0,0 +1,10 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+  base: '/',
+  build: {
+    rollupOptions: {
+      input: ['index.html'],
+    },
+  },
+});

From 39878abb79dab81a46a18bc52c64c1147305a860 Mon Sep 17 00:00:00 2001
From: Christina Holland <chholland@google.com>
Date: Thu, 9 May 2024 10:01:42 -0700
Subject: [PATCH 02/82] point to vertex public preview

---
 vertexai/main.ts           |    2 +-
 vertexai/package-lock.json | 1485 ------------------------------------
 vertexai/package.json      |    2 +-
 3 files changed, 2 insertions(+), 1487 deletions(-)
 delete mode 100644 vertexai/package-lock.json

diff --git a/vertexai/main.ts b/vertexai/main.ts
index b2d9c799c..9375976fa 100644
--- a/vertexai/main.ts
+++ b/vertexai/main.ts
@@ -4,7 +4,7 @@ import {
   initializeAppCheck,
   ReCaptchaEnterpriseProvider,
 } from "firebase/app-check";
-import { getVertexAI, getGenerativeModel } from "firebase/vertexai";
+import { getVertexAI, getGenerativeModel } from "firebase/vertexai-preview";
 
 async function main() {
   const app = initializeApp(firebaseConfig);
diff --git a/vertexai/package-lock.json b/vertexai/package-lock.json
deleted file mode 100644
index 5941aeb4d..000000000
--- a/vertexai/package-lock.json
+++ /dev/null
@@ -1,1485 +0,0 @@
-{
-  "name": "quickstart-js-storage",
-  "version": "1.0.0",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "name": "quickstart-js-storage",
-      "version": "1.0.0",
-      "license": "Apache-2.0",
-      "dependencies": {
-        "firebase": "10.10.0-vertexai-preview.cdcc49eb9"
-      },
-      "devDependencies": {
-        "typescript": "^5.1.6",
-        "vite": "^4.4.9"
-      },
-      "engines": {
-        "node": ">=18.0.0 <=20.0.0",
-        "npm": ">=9.0.0 <10.0.0"
-      }
-    },
-    "node_modules/@esbuild/android-arm": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
-      "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/android-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
-      "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/android-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
-      "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
-      "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/darwin-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
-      "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
-      "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
-      "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/linux-arm": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
-      "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/linux-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
-      "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/linux-ia32": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
-      "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/linux-loong64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
-      "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
-      "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
-      "cpu": [
-        "mips64el"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
-      "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
-      "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/linux-s390x": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
-      "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/linux-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
-      "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
-      "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
-      "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/sunos-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
-      "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "sunos"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/win32-arm64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
-      "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/win32-ia32": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
-      "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@esbuild/win32-x64": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
-      "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@fastify/busboy": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
-      "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
-      "engines": {
-        "node": ">=14"
-      }
-    },
-    "node_modules/@firebase/analytics": {
-      "version": "0.10.2-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.2-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-qEr8ugckOMCmJ6ZY5K3iafzzpxabh8ny3L46mjFE+VC+t3CsiJcEsAgtFJz8kvwf98yg5y2I8UVgBoqvXbLvxQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/analytics-compat": {
-      "version": "0.2.8-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.8-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-8Gw1m6eFLTUpwk/oTSVZMVWC8AcUM2NYiFGGnxa/z+3t7cbIcquw4t43G7RqTkAeiGKvFVLWrwkG+OHVd2wQXw==",
-      "dependencies": {
-        "@firebase/analytics": "0.10.2-vertexai-preview.cdcc49eb9",
-        "@firebase/analytics-types": "0.8.1-vertexai-preview.cdcc49eb9",
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/analytics-types": {
-      "version": "0.8.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-hhxXpMMJXZsK5ye68j3bwfPvHQtEdUXGTy5X28HN+q+l8xH8zjtcKsV86DAIarf6XB4QDDlurmiantj8kP1B1Q=="
-    },
-    "node_modules/@firebase/app": {
-      "version": "0.10.0-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.0-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-DZOOkkR4nSxdNkzL1b28ZTLVLt//CDy+hekvTJQTd9zt/NXk6xcRA7VcV5C7hxmj/j5J+nljNoBzzU9J2yaFmw==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "idb": "7.1.1",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/app-check": {
-      "version": "0.8.3-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.3-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-G35xeFLhoR0T73rRzMW3jHFhwi/2vscW+Sgm47ScP94Iak6wbKbmqTCeGzhDgzk0XWc2eIKYXz/J6ZDmgJcOsQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/app-check-compat": {
-      "version": "0.3.10-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.10-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-CpHVhLFmDtk6TrrhoGYj0hg1A4L6/08UqLNa2v7qxjgJt+iNuQuc0dHf2bq+pHCdRbNJR3NlbkBAYqo/tY670w==",
-      "dependencies": {
-        "@firebase/app-check": "0.8.3-vertexai-preview.cdcc49eb9",
-        "@firebase/app-check-types": "0.5.1-vertexai-preview.cdcc49eb9",
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/app-check-interop-types": {
-      "version": "0.3.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-x2INt1H0UoQICzA1U9IPA4LN98TrJXe37QioZkE5X7hDrpQlBNQNiNXJCenKO2qjrBffM2DtzTP5Sg653zgftQ=="
-    },
-    "node_modules/@firebase/app-check-types": {
-      "version": "0.5.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-QsZmTShocp7zRwPF+YfOOy57E/Okf2Xx9CeKdpF4EOfM6PX32GmXqY9OskAXhfoXtpapzyZUOc5hL7bdZcR2tA=="
-    },
-    "node_modules/@firebase/app-compat": {
-      "version": "0.2.30-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.30-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-557LV5WD89NoLwX9Rvdkg27vHVgaz2DWDmBZ8KoLoWYQWlIgXVINCtKNZy/hzx81DUj39+i6jd4ZJmR6Z0Kabg==",
-      "dependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9",
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/app-types": {
-      "version": "0.9.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-dVUM9xoGTZbZA9u88yOWeM94nyPqr8h3ktpKN4C0tdeHDjcj1M+BOMuNsoodKkzIrjJleCY3cLzkon18PWbuOw=="
-    },
-    "node_modules/@firebase/auth": {
-      "version": "1.7.0-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.0-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-F6KJV+WQE61TJ495fVYT8/6dcEeqv3jxQjeAY3Ecdw92XGNodenKPB8Cc4ZwYQrfVzdk1CdeTzhv0tVX95rwkg==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0",
-        "undici": "5.28.3"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9",
-        "@react-native-async-storage/async-storage": "^1.18.1"
-      },
-      "peerDependenciesMeta": {
-        "@react-native-async-storage/async-storage": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@firebase/auth-compat": {
-      "version": "0.5.5-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.5-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-77Hoq5W2gcQUtOEOF+4mlH6xD7tl65cCrhKbm/E0COSQycBgLBdgN0X7LJLLR4q9J5CTBQVLYKkW8IRHlbcg5A==",
-      "dependencies": {
-        "@firebase/auth": "1.7.0-vertexai-preview.cdcc49eb9",
-        "@firebase/auth-types": "0.12.1-vertexai-preview.cdcc49eb9",
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0",
-        "undici": "5.28.3"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/auth-interop-types": {
-      "version": "0.2.2-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.2-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-YP12+H5e1ythsDtObLRGucc3tBe8Gv0dSOpw3/vHVtlTnS13t2K5cxLoSDXt1kG2hMeUpc4YwRHsjyzZjcBZAg=="
-    },
-    "node_modules/@firebase/auth-types": {
-      "version": "0.12.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-pb3LAtFCTqCQFx0WQBqmLrs8qmbrk6Y9j5sGNianpGGV5kzJrGOwMuamdDaCbxyYJUaPOb0UmMGvUIv4jCqXrw==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/component": {
-      "version": "0.6.6-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.6-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-Zd9aLXQf3qWLDhK+5X4ZFTMBSvV97f2bF//NbWbGfFX2ix35uIpGiajziMLyw04TcPiiZ6t50ep5WlhQJLA8ig==",
-      "dependencies": {
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/database": {
-      "version": "1.0.4-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.4-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-H6UpDKrws1swyatqG8XX7MarmuEAe+alpH2pD2nc1qF2E8dUxDgQU45MjP/lpjewLXGvfZfcnyMu8blua5/P2w==",
-      "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.1-vertexai-preview.cdcc49eb9",
-        "@firebase/auth-interop-types": "0.2.2-vertexai-preview.cdcc49eb9",
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "faye-websocket": "0.11.4",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/database-compat": {
-      "version": "1.0.4-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.4-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-7FiE4P+K8BAovzCjFUYuaNXnJN0FoT08NQlfYUopAHuhCQdtXA2F3HSOgXWk73Wf7eozzGCmDB1xXDvrjtCS8g==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/database": "1.0.4-vertexai-preview.cdcc49eb9",
-        "@firebase/database-types": "1.0.2-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/database-types": {
-      "version": "1.0.2-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.2-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-C0J1K4tt6V1yQwyuYZeX1BvygyOpzB41RLsC6awnGb3RvkdF+3+nB0kUdO691aWHhRcXE3ADE9rQykIkbd9lfA==",
-      "dependencies": {
-        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/firestore": {
-      "version": "4.5.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.5.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-4suHqELbQr5YOUJ39pItLJPxe9dqLieyNCnu3SCML5NmjMGipInbSvBsaPeALsg+ln1VD38GT+RfLn03wgEYLA==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "@firebase/webchannel-wrapper": "0.10.6-vertexai-preview.cdcc49eb9",
-        "@grpc/grpc-js": "~1.9.0",
-        "@grpc/proto-loader": "^0.7.8",
-        "tslib": "^2.1.0",
-        "undici": "5.28.3"
-      },
-      "engines": {
-        "node": ">=10.10.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/firestore-compat": {
-      "version": "0.3.28-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.28-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-8d4NjeAGlw1jlMwzS83D71UnFPGC9PoSc12YobfuBKaT3mA99mHD3jQrskF7p1bUWHuNDu3+zSFC7GNazAu/lg==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/firestore": "4.5.1-vertexai-preview.cdcc49eb9",
-        "@firebase/firestore-types": "3.0.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/firestore-types": {
-      "version": "3.0.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-PGrbBAStLQIWlSkdH55qllCACteWHHcs4zbZYBd6d1dItg53HN3LIor7avqx33gGma+xFdtk4clXOdHILIQiVQ==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/functions": {
-      "version": "0.11.3-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.3-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-xBy/1+kVe8IaTQfWbI/QJS5a6SHycr6dmyZ2KNZNSA5C56Kgdq4CK62whmVp06SgvspXis5XkhNwt5427d+dUw==",
-      "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.1-vertexai-preview.cdcc49eb9",
-        "@firebase/auth-interop-types": "0.2.2-vertexai-preview.cdcc49eb9",
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/messaging-interop-types": "0.2.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0",
-        "undici": "5.28.3"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/functions-compat": {
-      "version": "0.3.9-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.9-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-MQVWu4P7TlQJZ8YHB94atK7ZE9uwKTIljBUQrpeM/rgp9orX4WYjVfaZR/Mz9BHC827IGi3XVl8WAE+3J9vTKQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/functions": "0.11.3-vertexai-preview.cdcc49eb9",
-        "@firebase/functions-types": "0.6.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/functions-types": {
-      "version": "0.6.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-vuPC8YVWygIcAOfHroQuuWbIlSJqwXlrhX0TkripGns07DK3awLiZ6MLUlAQMIyEMQY8uhEQMdg9OX6eJY3l6w=="
-    },
-    "node_modules/@firebase/installations": {
-      "version": "0.6.6-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.6-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-Y5AzABFnv6AfXIdTG1gz8OGuZyRXP21KRmr6vLv145MsLii83UyZ7A6GBvtweJMqEaY2Py3K5eR0VDVUR9npbQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "idb": "7.1.1",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/installations-compat": {
-      "version": "0.2.6-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.6-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-qMj/v5V9KlAZ1/a8orp8OCz51bA4CpLYoUIIYdkk6mCswCJ6cWgxPGF+Br2LW3oHlsJS9AqRK/eqy6nfzGDeuw==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/installations-types": "0.5.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/installations-types": {
-      "version": "0.5.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-1q5su0TDGNstaLLEfXtmNK19UyFh1Oux3DBOo36EF3v9j0XrQUhkyObagqMw6e6Fcxme/bxmluC1ba4tXLW6lw==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/logger": {
-      "version": "0.4.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-f0slz1qiXo5DvC3QaogS0vk6wBlBjNS2o0iuG5BqPEFQqjxZ5UU6+Yutq44Pzm6+j153t8/i/epzd9NGWQUZ4A==",
-      "dependencies": {
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/messaging": {
-      "version": "0.12.7-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.7-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-j2tf1EX+czhM+PLHnRxD0Vppr5NzV1Sxw4anETAhJlYkNfgNMV1ycN+39cSlwOio7tmb+HmxDo6b6KKor+pVsw==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/messaging-interop-types": "0.2.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "idb": "7.1.1",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/messaging-compat": {
-      "version": "0.2.7-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.7-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-2zgsgrSoGl+lOP9yh2i+C6WUcIDA6EgIUhquKR7BHmPLhMpunfYHzf5je+SnGDNrXz4nsI++qqBrZDNETNxV/g==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/messaging": "0.12.7-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/messaging-interop-types": {
-      "version": "0.2.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-1xv+vcy8KV98gYq1ezbHYsWPOvr8FWCdzoCJ4KYA2LksizVgO87bDCTT+xy4wqdmS04hZCagKdaMjanus/Hufg=="
-    },
-    "node_modules/@firebase/performance": {
-      "version": "0.6.6-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.6-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-5g25iALetNRGQq6E2v93qx1oDujPrvsyxPY1tcjbSgJZC6l19Yn0RxcyoMzoaq6ZFy3SegeESLhi44vhB2wkww==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/performance-compat": {
-      "version": "0.2.6-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.6-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-fTfariqtN+XO/rSe36Ik0/eAqsScKDvJwHh8WU5DsLNl5Gm9KS6eMN6ZXvts8ytDcpFZnproSpiWqcI1t3+bpQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/performance": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/performance-types": "0.2.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/performance-types": {
-      "version": "0.2.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-El7jehLnPbvNmlt42qt5VPcmZVfyR5xMT2EQRPUBYsMcczHFV/aAhykQYckrTFMqsBrOTymUvvmeLznbGjeOBA=="
-    },
-    "node_modules/@firebase/remote-config": {
-      "version": "0.4.6-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.6-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-G9BtzLMw/K4S5QCTs9soiDedBB/Yj3+GOgnmn7Xb9TKKTQDm6srqtKPv/0n1fkreBZ1Xnviv7vU2Gn3CeCGT0Q==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/remote-config-compat": {
-      "version": "0.2.6-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.6-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-FiEhgRoR+Y9VGQ9QNO6kdWfLQitW8jdAX9ju3ypkjTR1SVGsFUYYfmzBrxn1AOYVbJLcrL3X916l9tcMsUBcJA==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/remote-config": "0.4.6-vertexai-preview.cdcc49eb9",
-        "@firebase/remote-config-types": "0.3.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/remote-config-types": {
-      "version": "0.3.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-mJBNvZLU3mxX08Dat156cI6XB/RQ5NGJ9k464yMkK3slN021pO47VwEdudodt/RDwksemyG5AUDFzLzi/a7b8w=="
-    },
-    "node_modules/@firebase/storage": {
-      "version": "0.12.3-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.3-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-UcPOfZsjOppMJX21UDy1CS1XzKdoLWdQ0M0ywl7ONulkUIkm9SbdYtn3VpT6yOMgfTAGwkG7ujn+vqT41yxsmw==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0",
-        "undici": "5.28.3"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/storage-compat": {
-      "version": "0.3.6-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.6-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-PwZnndgz2dfxNDIPDkBnhbTnvkVAO0/vlJNLYQtxYrzmRh/ZkJw54u4uYkabwJfa6IrdSs4BW0D6UoNnLjh4BQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/storage": "0.12.3-vertexai-preview.cdcc49eb9",
-        "@firebase/storage-types": "0.8.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/storage-types": {
-      "version": "0.8.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-6t4BdPWxZekVgNWphAbQ0lEyedwRH72F465pH1rt7yGKvRvXzyvfGxYJA8E1zl2YmZQIT1cq64+zmV7wqX29gQ==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/util": {
-      "version": "1.9.5-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.5-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-Y8h9N+UitIbUbDwm6XBJISb2lupeBh5ShMheWfIAaFdzs58eWW6aEGrW/MtWGhf5mXBqcF91zBnLmo1dn22uSw==",
-      "dependencies": {
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/vertexai": {
-      "version": "0.0.1-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-0.0.1-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-lzDjq4BVrkqI2A5YMzLCSLQWNDkOMgjVuNn0pHjGh19XizUxcn31n9P+b2Dd9+pSoR1mB7E/C2J+lZXlwK+76A==",
-      "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.1-vertexai-preview.cdcc49eb9",
-        "@firebase/component": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/logger": "0.4.1-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9",
-        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/@firebase/webchannel-wrapper": {
-      "version": "0.10.6-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.6-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-EF5ULMUh51ZwmRN48NknnpTTlGxW5tx0lGUh2sYlZMROpmtpsSpn5kLoLF64igU+GEEkVc4i0Dym2XyuHveirQ=="
-    },
-    "node_modules/@grpc/grpc-js": {
-      "version": "1.9.14",
-      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz",
-      "integrity": "sha512-nOpuzZ2G3IuMFN+UPPpKrC6NsLmWsTqSsm66IRfnBt1D4pwTqE27lmbpcPM+l2Ua4gE7PfjRHI6uedAy7hoXUw==",
-      "dependencies": {
-        "@grpc/proto-loader": "^0.7.8",
-        "@types/node": ">=12.12.47"
-      },
-      "engines": {
-        "node": "^8.13.0 || >=10.10.0"
-      }
-    },
-    "node_modules/@grpc/proto-loader": {
-      "version": "0.7.12",
-      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.12.tgz",
-      "integrity": "sha512-DCVwMxqYzpUCiDMl7hQ384FqP4T3DbNpXU8pt681l3UWCip1WUiD5JrkImUwCB9a7f2cq4CUTmi5r/xIMRPY1Q==",
-      "dependencies": {
-        "lodash.camelcase": "^4.3.0",
-        "long": "^5.0.0",
-        "protobufjs": "^7.2.4",
-        "yargs": "^17.7.2"
-      },
-      "bin": {
-        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/@protobufjs/aspromise": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
-      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
-    },
-    "node_modules/@protobufjs/base64": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
-      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
-    },
-    "node_modules/@protobufjs/codegen": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
-      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
-    },
-    "node_modules/@protobufjs/eventemitter": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
-      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
-    },
-    "node_modules/@protobufjs/fetch": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
-      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
-      "dependencies": {
-        "@protobufjs/aspromise": "^1.1.1",
-        "@protobufjs/inquire": "^1.1.0"
-      }
-    },
-    "node_modules/@protobufjs/float": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
-      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
-    },
-    "node_modules/@protobufjs/inquire": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
-      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
-    },
-    "node_modules/@protobufjs/path": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
-      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
-    },
-    "node_modules/@protobufjs/pool": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
-      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
-    },
-    "node_modules/@protobufjs/utf8": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
-      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
-    },
-    "node_modules/@types/node": {
-      "version": "20.12.4",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz",
-      "integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==",
-      "dependencies": {
-        "undici-types": "~5.26.4"
-      }
-    },
-    "node_modules/ansi-regex": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/ansi-styles": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-      "dependencies": {
-        "color-convert": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-      }
-    },
-    "node_modules/cliui": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
-      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
-      "dependencies": {
-        "string-width": "^4.2.0",
-        "strip-ansi": "^6.0.1",
-        "wrap-ansi": "^7.0.0"
-      },
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/color-convert": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "dependencies": {
-        "color-name": "~1.1.4"
-      },
-      "engines": {
-        "node": ">=7.0.0"
-      }
-    },
-    "node_modules/color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
-    },
-    "node_modules/emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
-    },
-    "node_modules/esbuild": {
-      "version": "0.18.20",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
-      "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
-      "dev": true,
-      "hasInstallScript": true,
-      "bin": {
-        "esbuild": "bin/esbuild"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "optionalDependencies": {
-        "@esbuild/android-arm": "0.18.20",
-        "@esbuild/android-arm64": "0.18.20",
-        "@esbuild/android-x64": "0.18.20",
-        "@esbuild/darwin-arm64": "0.18.20",
-        "@esbuild/darwin-x64": "0.18.20",
-        "@esbuild/freebsd-arm64": "0.18.20",
-        "@esbuild/freebsd-x64": "0.18.20",
-        "@esbuild/linux-arm": "0.18.20",
-        "@esbuild/linux-arm64": "0.18.20",
-        "@esbuild/linux-ia32": "0.18.20",
-        "@esbuild/linux-loong64": "0.18.20",
-        "@esbuild/linux-mips64el": "0.18.20",
-        "@esbuild/linux-ppc64": "0.18.20",
-        "@esbuild/linux-riscv64": "0.18.20",
-        "@esbuild/linux-s390x": "0.18.20",
-        "@esbuild/linux-x64": "0.18.20",
-        "@esbuild/netbsd-x64": "0.18.20",
-        "@esbuild/openbsd-x64": "0.18.20",
-        "@esbuild/sunos-x64": "0.18.20",
-        "@esbuild/win32-arm64": "0.18.20",
-        "@esbuild/win32-ia32": "0.18.20",
-        "@esbuild/win32-x64": "0.18.20"
-      }
-    },
-    "node_modules/escalade": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
-      "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/faye-websocket": {
-      "version": "0.11.4",
-      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
-      "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
-      "dependencies": {
-        "websocket-driver": ">=0.5.1"
-      },
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/firebase": {
-      "version": "10.10.0-vertexai-preview.cdcc49eb9",
-      "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.10.0-vertexai-preview.cdcc49eb9.tgz",
-      "integrity": "sha512-viCfzUAEyTejZ2tFx0Oc1xmbNOSZ5Fn6e2Obv7Rm9Uk27uMDDS5/og86MRlFvlUsFrQrku24ddJcnbNfiko0Kw==",
-      "dependencies": {
-        "@firebase/analytics": "0.10.2-vertexai-preview.cdcc49eb9",
-        "@firebase/analytics-compat": "0.2.8-vertexai-preview.cdcc49eb9",
-        "@firebase/app": "0.10.0-vertexai-preview.cdcc49eb9",
-        "@firebase/app-check": "0.8.3-vertexai-preview.cdcc49eb9",
-        "@firebase/app-check-compat": "0.3.10-vertexai-preview.cdcc49eb9",
-        "@firebase/app-compat": "0.2.30-vertexai-preview.cdcc49eb9",
-        "@firebase/app-types": "0.9.1-vertexai-preview.cdcc49eb9",
-        "@firebase/auth": "1.7.0-vertexai-preview.cdcc49eb9",
-        "@firebase/auth-compat": "0.5.5-vertexai-preview.cdcc49eb9",
-        "@firebase/database": "1.0.4-vertexai-preview.cdcc49eb9",
-        "@firebase/database-compat": "1.0.4-vertexai-preview.cdcc49eb9",
-        "@firebase/firestore": "4.5.1-vertexai-preview.cdcc49eb9",
-        "@firebase/firestore-compat": "0.3.28-vertexai-preview.cdcc49eb9",
-        "@firebase/functions": "0.11.3-vertexai-preview.cdcc49eb9",
-        "@firebase/functions-compat": "0.3.9-vertexai-preview.cdcc49eb9",
-        "@firebase/installations": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/installations-compat": "0.2.6-vertexai-preview.cdcc49eb9",
-        "@firebase/messaging": "0.12.7-vertexai-preview.cdcc49eb9",
-        "@firebase/messaging-compat": "0.2.7-vertexai-preview.cdcc49eb9",
-        "@firebase/performance": "0.6.6-vertexai-preview.cdcc49eb9",
-        "@firebase/performance-compat": "0.2.6-vertexai-preview.cdcc49eb9",
-        "@firebase/remote-config": "0.4.6-vertexai-preview.cdcc49eb9",
-        "@firebase/remote-config-compat": "0.2.6-vertexai-preview.cdcc49eb9",
-        "@firebase/storage": "0.12.3-vertexai-preview.cdcc49eb9",
-        "@firebase/storage-compat": "0.3.6-vertexai-preview.cdcc49eb9",
-        "@firebase/util": "1.9.5-vertexai-preview.cdcc49eb9",
-        "@firebase/vertexai": "0.0.1-vertexai-preview.cdcc49eb9"
-      }
-    },
-    "node_modules/fsevents": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
-      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
-      "dev": true,
-      "hasInstallScript": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-      }
-    },
-    "node_modules/get-caller-file": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-      "engines": {
-        "node": "6.* || 8.* || >= 10.*"
-      }
-    },
-    "node_modules/http-parser-js": {
-      "version": "0.5.8",
-      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
-      "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q=="
-    },
-    "node_modules/idb": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
-      "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="
-    },
-    "node_modules/is-fullwidth-code-point": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/lodash.camelcase": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
-      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
-    },
-    "node_modules/long": {
-      "version": "5.2.3",
-      "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
-      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
-    },
-    "node_modules/nanoid": {
-      "version": "3.3.7",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
-      "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "bin": {
-        "nanoid": "bin/nanoid.cjs"
-      },
-      "engines": {
-        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
-      }
-    },
-    "node_modules/picocolors": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
-      "dev": true
-    },
-    "node_modules/postcss": {
-      "version": "8.4.38",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
-      "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/postcss"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "dependencies": {
-        "nanoid": "^3.3.7",
-        "picocolors": "^1.0.0",
-        "source-map-js": "^1.2.0"
-      },
-      "engines": {
-        "node": "^10 || ^12 || >=14"
-      }
-    },
-    "node_modules/protobufjs": {
-      "version": "7.2.6",
-      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz",
-      "integrity": "sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==",
-      "hasInstallScript": true,
-      "dependencies": {
-        "@protobufjs/aspromise": "^1.1.2",
-        "@protobufjs/base64": "^1.1.2",
-        "@protobufjs/codegen": "^2.0.4",
-        "@protobufjs/eventemitter": "^1.1.0",
-        "@protobufjs/fetch": "^1.1.0",
-        "@protobufjs/float": "^1.0.2",
-        "@protobufjs/inquire": "^1.1.0",
-        "@protobufjs/path": "^1.1.2",
-        "@protobufjs/pool": "^1.1.0",
-        "@protobufjs/utf8": "^1.1.0",
-        "@types/node": ">=13.7.0",
-        "long": "^5.0.0"
-      },
-      "engines": {
-        "node": ">=12.0.0"
-      }
-    },
-    "node_modules/require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/rollup": {
-      "version": "3.29.4",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
-      "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
-      "dev": true,
-      "bin": {
-        "rollup": "dist/bin/rollup"
-      },
-      "engines": {
-        "node": ">=14.18.0",
-        "npm": ">=8.0.0"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      }
-    },
-    "node_modules/safe-buffer": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ]
-    },
-    "node_modules/source-map-js": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
-      "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/string-width": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "dependencies": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/strip-ansi": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-      "dependencies": {
-        "ansi-regex": "^5.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/tslib": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
-      "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
-    },
-    "node_modules/typescript": {
-      "version": "5.4.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
-      "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
-      "dev": true,
-      "bin": {
-        "tsc": "bin/tsc",
-        "tsserver": "bin/tsserver"
-      },
-      "engines": {
-        "node": ">=14.17"
-      }
-    },
-    "node_modules/undici": {
-      "version": "5.28.3",
-      "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
-      "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
-      "dependencies": {
-        "@fastify/busboy": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=14.0"
-      }
-    },
-    "node_modules/undici-types": {
-      "version": "5.26.5",
-      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
-      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
-    },
-    "node_modules/vite": {
-      "version": "4.5.3",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz",
-      "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==",
-      "dev": true,
-      "dependencies": {
-        "esbuild": "^0.18.10",
-        "postcss": "^8.4.27",
-        "rollup": "^3.27.1"
-      },
-      "bin": {
-        "vite": "bin/vite.js"
-      },
-      "engines": {
-        "node": "^14.18.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/vitejs/vite?sponsor=1"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      },
-      "peerDependencies": {
-        "@types/node": ">= 14",
-        "less": "*",
-        "lightningcss": "^1.21.0",
-        "sass": "*",
-        "stylus": "*",
-        "sugarss": "*",
-        "terser": "^5.4.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/node": {
-          "optional": true
-        },
-        "less": {
-          "optional": true
-        },
-        "lightningcss": {
-          "optional": true
-        },
-        "sass": {
-          "optional": true
-        },
-        "stylus": {
-          "optional": true
-        },
-        "sugarss": {
-          "optional": true
-        },
-        "terser": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/websocket-driver": {
-      "version": "0.7.4",
-      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
-      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
-      "dependencies": {
-        "http-parser-js": ">=0.5.1",
-        "safe-buffer": ">=5.1.0",
-        "websocket-extensions": ">=0.1.1"
-      },
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/websocket-extensions": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
-      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/wrap-ansi": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-      "dependencies": {
-        "ansi-styles": "^4.0.0",
-        "string-width": "^4.1.0",
-        "strip-ansi": "^6.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-      }
-    },
-    "node_modules/y18n": {
-      "version": "5.0.8",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
-      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/yargs": {
-      "version": "17.7.2",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
-      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
-      "dependencies": {
-        "cliui": "^8.0.1",
-        "escalade": "^3.1.1",
-        "get-caller-file": "^2.0.5",
-        "require-directory": "^2.1.1",
-        "string-width": "^4.2.3",
-        "y18n": "^5.0.5",
-        "yargs-parser": "^21.1.1"
-      },
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/yargs-parser": {
-      "version": "21.1.1",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-      "engines": {
-        "node": ">=12"
-      }
-    }
-  }
-}
diff --git a/vertexai/package.json b/vertexai/package.json
index dcd5106e4..4b9ba8f88 100644
--- a/vertexai/package.json
+++ b/vertexai/package.json
@@ -26,6 +26,6 @@
     "format": "prettier --write ."
   },
   "dependencies": {
-    "firebase": "10.10.0-vertexai-preview.cdcc49eb9"
+    "firebase": "10.12.0"
   }
 }

From 79a88fe920df8cfea166712e8b20c3f29833ca2c Mon Sep 17 00:00:00 2001
From: Christina Holland <chholland@google.com>
Date: Thu, 9 May 2024 16:05:49 -0700
Subject: [PATCH 03/82] put in a model that works

---
 vertexai/main.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/vertexai/main.ts b/vertexai/main.ts
index 9375976fa..e4bb2e51b 100644
--- a/vertexai/main.ts
+++ b/vertexai/main.ts
@@ -19,7 +19,7 @@ async function main() {
   // Get a gemini model
   const model = getGenerativeModel(
     vertexAI,
-    { model: "gemini-1.0-pro" }
+    { model: "gemini-1.5-pro-preview-0409" }
   );
   // Call generateContent with a string or Content(s)
   const generateContentResult = await model.generateContent("what is a cat?");

From 4af78f11992cb6b188d3855082ae99d4b1442531 Mon Sep 17 00:00:00 2001
From: Christina Holland <chholland@google.com>
Date: Fri, 10 May 2024 10:54:55 -0700
Subject: [PATCH 04/82] addressed PR comments

---
 vertexai/README.md    |  2 +-
 vertexai/index.html   |  4 ++--
 vertexai/main.ts      | 25 ++++++++++++++++++++++---
 vertexai/package.json |  6 +++---
 4 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/vertexai/README.md b/vertexai/README.md
index c363bf6be..5782c6520 100644
--- a/vertexai/README.md
+++ b/vertexai/README.md
@@ -19,7 +19,7 @@ Getting Started
  2. Enable Gemini in the console.
  3. Create a ReCAPTCHA Enterprise key in the same project.
  4. Enable App Check in the Firebase console with the ReCAPTCHA Enterprise site key you created.
- 5. Copy your Firebase project config and your ReCAPTCHA Enterprise site key into the appropraite places in `config.ts` in this directory.
+ 5. Copy your Firebase project config and your ReCAPTCHA Enterprise site key into the appropriate places in `config.ts` in this directory.
  6. In this directory, run `npm install`
  7. In this directory, run `npm run dev`
 
diff --git a/vertexai/index.html b/vertexai/index.html
index 8a4986a1d..49ba64654 100644
--- a/vertexai/index.html
+++ b/vertexai/index.html
@@ -1,6 +1,6 @@
 <!doctype html>
 <!--
-Copyright (c) 2016 Google Inc.
+Copyright (c) 2024 Google Inc.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
   <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Firebase SDK for Vertex AI Quickstart</title>
+    <title>Vertex AI for Firebase SDK Quickstart</title>
   </head>
   <body>
     <div>Open browser's developer console to view console.log output.</div>
diff --git a/vertexai/main.ts b/vertexai/main.ts
index e4bb2e51b..87e4652c6 100644
--- a/vertexai/main.ts
+++ b/vertexai/main.ts
@@ -1,3 +1,20 @@
+/**
+ * @license
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 import { initializeApp } from 'firebase/app';
 import { firebaseConfig, RECAPTCHA_ENTERPRISE_SITE_KEY } from './config';
 import {
@@ -9,14 +26,16 @@ import { getVertexAI, getGenerativeModel } from "firebase/vertexai-preview";
 async function main() {
   const app = initializeApp(firebaseConfig);
 
-  // initialize app check
+  // Initialize App Check
+  // This line can be removed if you do not want to enable App Check for
+  // your project. App Check is recommended to limit unauthorized usage.
   initializeAppCheck(app, {
     provider: new ReCaptchaEnterpriseProvider(RECAPTCHA_ENTERPRISE_SITE_KEY),
   });
 
-  // Get vertex instance
+  // Get VertexAI instance
   const vertexAI = getVertexAI(app);
-  // Get a gemini model
+  // Get a Gemini model
   const model = getGenerativeModel(
     vertexAI,
     { model: "gemini-1.5-pro-preview-0409" }
diff --git a/vertexai/package.json b/vertexai/package.json
index 4b9ba8f88..f24867eae 100644
--- a/vertexai/package.json
+++ b/vertexai/package.json
@@ -1,7 +1,7 @@
 {
-  "name": "quickstart-js-storage",
+  "name": "quickstart-js-vertexai",
   "version": "1.0.0",
-  "description": "JavaScript quickstarts for Firebase Storage.",
+  "description": "JavaScript quickstarts for Vertex AI for Firebase.",
   "repository": {
     "type": "git",
     "url": "git+https://github.com/firebase/quickstart-js.git"
@@ -26,6 +26,6 @@
     "format": "prettier --write ."
   },
   "dependencies": {
-    "firebase": "10.12.0"
+    "firebase": "^10.12.0"
   }
 }

From 3d3ced4fb06919b72dd41b72a58f76e57b8d37e7 Mon Sep 17 00:00:00 2001
From: Christina Holland <chholland@google.com>
Date: Mon, 13 May 2024 09:40:20 -0700
Subject: [PATCH 05/82] update package-lock

---
 vertexai/package-lock.json | 1136 ++++++++++++++++++++++++++++++++++++
 1 file changed, 1136 insertions(+)
 create mode 100644 vertexai/package-lock.json

diff --git a/vertexai/package-lock.json b/vertexai/package-lock.json
new file mode 100644
index 000000000..83601a631
--- /dev/null
+++ b/vertexai/package-lock.json
@@ -0,0 +1,1136 @@
+{
+  "name": "quickstart-js-vertexai",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "quickstart-js-vertexai",
+      "version": "1.0.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "firebase": "^10.12.0"
+      },
+      "devDependencies": {
+        "typescript": "^5.1.6",
+        "vite": "^4.4.9"
+      },
+      "engines": {
+        "node": ">=18.0.0 <=20.0.0",
+        "npm": ">=9.0.0 <10.0.0"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.18.20",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@fastify/busboy": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
+      "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@firebase/analytics": {
+      "version": "0.10.3",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.3.tgz",
+      "integrity": "sha512-pMADbAgmfM3vDSeINCw0qSTBA9nn6so8min2KaBfu5eda5kfemb/DeawNUKOIxrP3yV4teJgCKA3JFomfnozEg==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/installations": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/analytics-compat": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.9.tgz",
+      "integrity": "sha512-ZKXaUixA+drbf3meX1bhPCG90UWrpw1KDrCydhe2Uf0VFZmZyVVr0bAcVpqLm29W4td7qp2RpFjVwercZ5mxTg==",
+      "dependencies": {
+        "@firebase/analytics": "0.10.3",
+        "@firebase/analytics-types": "0.8.2",
+        "@firebase/component": "0.6.7",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/analytics-types": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.2.tgz",
+      "integrity": "sha512-EnzNNLh+9/sJsimsA/FGqzakmrAUKLeJvjRHlg8df1f97NLUlFidk9600y0ZgWOp3CAxn6Hjtk+08tixlUOWyw=="
+    },
+    "node_modules/@firebase/app": {
+      "version": "0.10.3",
+      "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.3.tgz",
+      "integrity": "sha512-+pW2wNjijh88aFRjNWhDNlVJI5vB7q1IKYEE79a7ErxwNS/Bo+oh16aAAPvunhT06EF5I8y9gAlNuHNN8u4z8g==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/app-check": {
+      "version": "0.8.4",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.4.tgz",
+      "integrity": "sha512-2tjRDaxcM5G7BEpytiDcIl+NovV99q8yEqRMKDbn4J4i/XjjuThuB4S+4PkmTnZiCbdLXQiBhkVxNlUDcfog5Q==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/app-check-compat": {
+      "version": "0.3.11",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.11.tgz",
+      "integrity": "sha512-t01zaH3RJpKEey0nGduz3Is+uSz7Sj4U5nwOV6lWb+86s5xtxpIvBJzu/lKxJfYyfZ29eJwpdjEgT1/lm4iQyA==",
+      "dependencies": {
+        "@firebase/app-check": "0.8.4",
+        "@firebase/app-check-types": "0.5.2",
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/app-check-interop-types": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz",
+      "integrity": "sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ=="
+    },
+    "node_modules/@firebase/app-check-types": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.2.tgz",
+      "integrity": "sha512-FSOEzTzL5bLUbD2co3Zut46iyPWML6xc4x+78TeaXMSuJap5QObfb+rVvZJtla3asN4RwU7elaQaduP+HFizDA=="
+    },
+    "node_modules/@firebase/app-compat": {
+      "version": "0.2.33",
+      "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.33.tgz",
+      "integrity": "sha512-CLXhYJBtLuHXCUvs894gpXEXhZ7Nhytn2icLLIesH+hPLnyBeBf2CSve6Wjig+TOxTdwOQUzdtYpdjmeeYDfpw==",
+      "dependencies": {
+        "@firebase/app": "0.10.3",
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/app-types": {
+      "version": "0.9.2",
+      "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2.tgz",
+      "integrity": "sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ=="
+    },
+    "node_modules/@firebase/auth": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.3.tgz",
+      "integrity": "sha512-RiU1PjziOxLuyswtYtLK2qSjHIQJQGCk1h986SUFRbMQfzLXbQg8ZgXwxac1UAfDOzgzqPNCXhBuIlSK2UomoQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x",
+        "@react-native-async-storage/async-storage": "^1.18.1"
+      },
+      "peerDependenciesMeta": {
+        "@react-native-async-storage/async-storage": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@firebase/auth-compat": {
+      "version": "0.5.8",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.8.tgz",
+      "integrity": "sha512-qUgmv/mcth9wHPTOCKgAOeHe5c+BIOJVcbX2RfcjlXO3xnd8nRafwEkZKBNJUjy4oihYhqFMEMnTHLhwLJwLig==",
+      "dependencies": {
+        "@firebase/auth": "1.7.3",
+        "@firebase/auth-types": "0.12.2",
+        "@firebase/component": "0.6.7",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/auth-interop-types": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz",
+      "integrity": "sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ=="
+    },
+    "node_modules/@firebase/auth-types": {
+      "version": "0.12.2",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.2.tgz",
+      "integrity": "sha512-qsEBaRMoGvHO10unlDJhaKSuPn4pyoTtlQuP1ghZfzB6rNQPuhp/N/DcFZxm9i4v0SogjCbf9reWupwIvfmH6w==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.x",
+        "@firebase/util": "1.x"
+      }
+    },
+    "node_modules/@firebase/component": {
+      "version": "0.6.7",
+      "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.7.tgz",
+      "integrity": "sha512-baH1AA5zxfaz4O8w0vDwETByrKTQqB5CDjRls79Sa4eAGAoERw4Tnung7XbMl3jbJ4B/dmmtsMrdki0KikwDYA==",
+      "dependencies": {
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/database": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.5.tgz",
+      "integrity": "sha512-cAfwBqMQuW6HbhwI3Cb/gDqZg7aR0OmaJ85WUxlnoYW2Tm4eR0hFl5FEijI3/gYPUiUcUPQvTkGV222VkT7KPw==",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.2",
+        "@firebase/auth-interop-types": "0.2.3",
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "faye-websocket": "0.11.4",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/database-compat": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.5.tgz",
+      "integrity": "sha512-NDSMaDjQ+TZEMDMmzJwlTL05kh1+0Y84C+kVMaOmNOzRGRM7VHi29I6YUhCetXH+/b1Wh4ZZRyp1CuWkd8s6hg==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/database": "1.0.5",
+        "@firebase/database-types": "1.0.3",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/database-types": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.3.tgz",
+      "integrity": "sha512-39V/Riv2R3O/aUjYKh0xypj7NTNXNAK1bcgY5Kx+hdQPRS/aPTS8/5c0CGFYKgVuFbYlnlnhrCTYsh2uNhGwzA==",
+      "dependencies": {
+        "@firebase/app-types": "0.9.2",
+        "@firebase/util": "1.9.6"
+      }
+    },
+    "node_modules/@firebase/firestore": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.6.2.tgz",
+      "integrity": "sha512-sxHtvmfH/1689aPQRxOXBWDumaPqg5AjQVkfwpt+Z3rnaa0aLJlrt2PZs9Xh04qbmWiwtkDgztFmoR/aQdMQJQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "@firebase/webchannel-wrapper": "1.0.0",
+        "@grpc/grpc-js": "~1.9.0",
+        "@grpc/proto-loader": "^0.7.8",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "engines": {
+        "node": ">=10.10.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/firestore-compat": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.31.tgz",
+      "integrity": "sha512-YbR9GGLfYY9A5Qh2SyyNz7EsNeC5SRjzgRxtMtqz2s2es+p+5sDfFUUNKqpgVaIcnoPGOtvCLhNNWG/TBmlQjw==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/firestore": "4.6.2",
+        "@firebase/firestore-types": "3.0.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/firestore-types": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.2.tgz",
+      "integrity": "sha512-wp1A+t5rI2Qc/2q7r2ZpjUXkRVPtGMd6zCLsiWurjsQpqPgFin3AhNibKcIzoF2rnToNa/XYtyWXuifjOOwDgg==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.x",
+        "@firebase/util": "1.x"
+      }
+    },
+    "node_modules/@firebase/functions": {
+      "version": "0.11.5",
+      "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.5.tgz",
+      "integrity": "sha512-qrHJ+l62mZiU5UZiVi84t/iLXZlhRuSvBQsa2qvNLgPsEWR7wdpWhRmVdB7AU8ndkSHJjGlMICqrVnz47sgU7Q==",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.2",
+        "@firebase/auth-interop-types": "0.2.3",
+        "@firebase/component": "0.6.7",
+        "@firebase/messaging-interop-types": "0.2.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/functions-compat": {
+      "version": "0.3.11",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.11.tgz",
+      "integrity": "sha512-Qn+ts/M6Lj2/6i1cp5V5TRR+Hi9kyXyHbo+w9GguINJ87zxrCe6ulx3TI5AGQkoQa8YFHUhT3DMGmLFiJjWTSQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/functions": "0.11.5",
+        "@firebase/functions-types": "0.6.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/functions-types": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.2.tgz",
+      "integrity": "sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w=="
+    },
+    "node_modules/@firebase/installations": {
+      "version": "0.6.7",
+      "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.7.tgz",
+      "integrity": "sha512-i6iGoXRu5mX4rTsiMSSKrgh9pSEzD4hwBEzRh5kEhOTr8xN/wvQcCPZDSMVYKwM2XyCPBLVq0JzjyerwL0Rihg==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/util": "1.9.6",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/installations-compat": {
+      "version": "0.2.7",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.7.tgz",
+      "integrity": "sha512-RPcbD+3nqHbnhVjIOpWK2H5qzZ8pAAAScceiWph0VNTqpKyPQ5tDcp4V5fS0ELpfgsHYvroMLDKfeHxpfvm8cw==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/installations": "0.6.7",
+        "@firebase/installations-types": "0.5.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/installations-types": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.2.tgz",
+      "integrity": "sha512-que84TqGRZJpJKHBlF2pkvc1YcXrtEDOVGiDjovP/a3s6W4nlbohGXEsBJo0JCeeg/UG9A+DEZVDUV9GpklUzA==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.x"
+      }
+    },
+    "node_modules/@firebase/logger": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.2.tgz",
+      "integrity": "sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/messaging": {
+      "version": "0.12.9",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.9.tgz",
+      "integrity": "sha512-IH+JJmzbFGZXV3+TDyKdqqKPVfKRqBBg2BfYYOy7cm7J+SwV+uJMe8EnDKYeQLEQhtpwciPfJ3qQXJs2lbxDTw==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/installations": "0.6.7",
+        "@firebase/messaging-interop-types": "0.2.2",
+        "@firebase/util": "1.9.6",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/messaging-compat": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.9.tgz",
+      "integrity": "sha512-5jN6wyhwPgBH02zOtmmoOeyfsmoD7ty48D1m0vVPsFg55RqN2Z3Q9gkZ5GmPklFPjTPLcxB1ObcHOZvThTkm7g==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/messaging": "0.12.9",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/messaging-interop-types": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2.tgz",
+      "integrity": "sha512-l68HXbuD2PPzDUOFb3aG+nZj5KA3INcPwlocwLZOzPp9rFM9yeuI9YLl6DQfguTX5eAGxO0doTR+rDLDvQb5tA=="
+    },
+    "node_modules/@firebase/performance": {
+      "version": "0.6.7",
+      "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.7.tgz",
+      "integrity": "sha512-d+Q4ltjdJZqjzcdms5i0UC9KLYX7vKGcygZ+7zHA/Xk+bAbMD2CPU0nWTnlNFWifZWIcXZ/2mAMvaGMW3lypUA==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/installations": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/performance-compat": {
+      "version": "0.2.7",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.7.tgz",
+      "integrity": "sha512-cb8ge/5iTstxfIGW+iiY+7l3FtN8gobNh9JSQNZgLC9xmcfBYWEs8IeEWMI6S8T+At0oHc3lv+b2kpRMUWr8zQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/performance": "0.6.7",
+        "@firebase/performance-types": "0.2.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/performance-types": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.2.tgz",
+      "integrity": "sha512-gVq0/lAClVH5STrIdKnHnCo2UcPLjJlDUoEB/tB4KM+hAeHUxWKnpT0nemUPvxZ5nbdY/pybeyMe8Cs29gEcHA=="
+    },
+    "node_modules/@firebase/remote-config": {
+      "version": "0.4.7",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.7.tgz",
+      "integrity": "sha512-5oPNrPFLsbsjpq0lUEIXoDF2eJK7vAbyXe/DEuZQxnwJlfR7aQbtUlEkRgQWcicXpyDmAmDLo7q7lDbCYa6CpA==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/installations": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/remote-config-compat": {
+      "version": "0.2.7",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.7.tgz",
+      "integrity": "sha512-Fq0oneQ4SluLnfr5/HfzRS1TZf1ANj1rWbCCW3+oC98An3nE+sCdp+FSuHsEVNwgMg4Tkwx9Oom2lkKeU+Vn+w==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/remote-config": "0.4.7",
+        "@firebase/remote-config-types": "0.3.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/remote-config-types": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.2.tgz",
+      "integrity": "sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA=="
+    },
+    "node_modules/@firebase/storage": {
+      "version": "0.12.5",
+      "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.5.tgz",
+      "integrity": "sha512-nGWBOGFNr10j0LA4NJ3/Yh3us/lb0Q1xSIKZ38N6FcS+vY54nqJ7k3zE3PENregHC8+8txRow++A568G3v8hOA==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/storage-compat": {
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.8.tgz",
+      "integrity": "sha512-qDfY9kMb6Ch2hZb40sBjDQ8YPxbjGOxuT+gU1Z0iIVSSpSX0f4YpGJCypUXiA0T11n6InCXB+T/Dknh2yxVTkg==",
+      "dependencies": {
+        "@firebase/component": "0.6.7",
+        "@firebase/storage": "0.12.5",
+        "@firebase/storage-types": "0.8.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/storage-types": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.2.tgz",
+      "integrity": "sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.x",
+        "@firebase/util": "1.x"
+      }
+    },
+    "node_modules/@firebase/util": {
+      "version": "1.9.6",
+      "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.6.tgz",
+      "integrity": "sha512-IBr1MZbp4d5MjBCXL3TW1dK/PDXX4yOGbiwRNh1oAbE/+ci5Uuvy9KIrsFYY80as1I0iOaD5oOMA9Q8j4TJWcw==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/vertexai-preview": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/@firebase/vertexai-preview/-/vertexai-preview-0.0.1.tgz",
+      "integrity": "sha512-N8m9Xr0YZKy0t9SpQDuHrL2ppEAT/iqf88Y/O00QNA/Td/BMCL8sJ0c+Savh1TVrqh0rNp9n6HkZ39e/O5mwhA==",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.2",
+        "@firebase/component": "0.6.7",
+        "@firebase/logger": "0.4.2",
+        "@firebase/util": "1.9.6",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x",
+        "@firebase/app-types": "0.x"
+      }
+    },
+    "node_modules/@firebase/webchannel-wrapper": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.0.tgz",
+      "integrity": "sha512-zuWxyfXNbsKbm96HhXzainONPFqRcoZblQ++e9cAIGUuHfl2cFSBzW01jtesqWG/lqaUyX3H8O1y9oWboGNQBA=="
+    },
+    "node_modules/@grpc/grpc-js": {
+      "version": "1.9.14",
+      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz",
+      "integrity": "sha512-nOpuzZ2G3IuMFN+UPPpKrC6NsLmWsTqSsm66IRfnBt1D4pwTqE27lmbpcPM+l2Ua4gE7PfjRHI6uedAy7hoXUw==",
+      "dependencies": {
+        "@grpc/proto-loader": "^0.7.8",
+        "@types/node": ">=12.12.47"
+      },
+      "engines": {
+        "node": "^8.13.0 || >=10.10.0"
+      }
+    },
+    "node_modules/@grpc/proto-loader": {
+      "version": "0.7.13",
+      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz",
+      "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==",
+      "dependencies": {
+        "lodash.camelcase": "^4.3.0",
+        "long": "^5.0.0",
+        "protobufjs": "^7.2.5",
+        "yargs": "^17.7.2"
+      },
+      "bin": {
+        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+    },
+    "node_modules/@types/node": {
+      "version": "20.12.4",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+    },
+    "node_modules/esbuild": {
+      "version": "0.18.20",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "@esbuild/android-arm": "0.18.20",
+        "@esbuild/android-arm64": "0.18.20",
+        "@esbuild/android-x64": "0.18.20",
+        "@esbuild/darwin-arm64": "0.18.20",
+        "@esbuild/darwin-x64": "0.18.20",
+        "@esbuild/freebsd-arm64": "0.18.20",
+        "@esbuild/freebsd-x64": "0.18.20",
+        "@esbuild/linux-arm": "0.18.20",
+        "@esbuild/linux-arm64": "0.18.20",
+        "@esbuild/linux-ia32": "0.18.20",
+        "@esbuild/linux-loong64": "0.18.20",
+        "@esbuild/linux-mips64el": "0.18.20",
+        "@esbuild/linux-ppc64": "0.18.20",
+        "@esbuild/linux-riscv64": "0.18.20",
+        "@esbuild/linux-s390x": "0.18.20",
+        "@esbuild/linux-x64": "0.18.20",
+        "@esbuild/netbsd-x64": "0.18.20",
+        "@esbuild/openbsd-x64": "0.18.20",
+        "@esbuild/sunos-x64": "0.18.20",
+        "@esbuild/win32-arm64": "0.18.20",
+        "@esbuild/win32-ia32": "0.18.20",
+        "@esbuild/win32-x64": "0.18.20"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+      "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/faye-websocket": {
+      "version": "0.11.4",
+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+      "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+      "dependencies": {
+        "websocket-driver": ">=0.5.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/firebase": {
+      "version": "10.12.0",
+      "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.12.0.tgz",
+      "integrity": "sha512-31UZyAK0+VZmF9jR/+6g31uyqWjBKsG+TV3ndRJEkw6+Skctb5ZX0+Ezq/pbC68iIRJ5TujOjyl632vTOqyS1w==",
+      "dependencies": {
+        "@firebase/analytics": "0.10.3",
+        "@firebase/analytics-compat": "0.2.9",
+        "@firebase/app": "0.10.3",
+        "@firebase/app-check": "0.8.4",
+        "@firebase/app-check-compat": "0.3.11",
+        "@firebase/app-compat": "0.2.33",
+        "@firebase/app-types": "0.9.2",
+        "@firebase/auth": "1.7.3",
+        "@firebase/auth-compat": "0.5.8",
+        "@firebase/database": "1.0.5",
+        "@firebase/database-compat": "1.0.5",
+        "@firebase/firestore": "4.6.2",
+        "@firebase/firestore-compat": "0.3.31",
+        "@firebase/functions": "0.11.5",
+        "@firebase/functions-compat": "0.3.11",
+        "@firebase/installations": "0.6.7",
+        "@firebase/installations-compat": "0.2.7",
+        "@firebase/messaging": "0.12.9",
+        "@firebase/messaging-compat": "0.2.9",
+        "@firebase/performance": "0.6.7",
+        "@firebase/performance-compat": "0.2.7",
+        "@firebase/remote-config": "0.4.7",
+        "@firebase/remote-config-compat": "0.2.7",
+        "@firebase/storage": "0.12.5",
+        "@firebase/storage-compat": "0.3.8",
+        "@firebase/util": "1.9.6",
+        "@firebase/vertexai-preview": "0.0.1"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/http-parser-js": {
+      "version": "0.5.8",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+      "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q=="
+    },
+    "node_modules/idb": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
+      "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
+    },
+    "node_modules/long": {
+      "version": "5.2.3",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
+      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.7",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/postcss": {
+      "version": "8.4.38",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.7",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.2.0"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/protobufjs": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.0.tgz",
+      "integrity": "sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "3.29.4",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=14.18.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.0",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+      "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+    },
+    "node_modules/typescript": {
+      "version": "5.4.4",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/undici": {
+      "version": "5.28.4",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
+      "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
+      "dependencies": {
+        "@fastify/busboy": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=14.0"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "5.26.5",
+      "license": "MIT"
+    },
+    "node_modules/vite": {
+      "version": "4.5.3",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.18.10",
+        "postcss": "^8.4.27",
+        "rollup": "^3.27.1"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      },
+      "peerDependencies": {
+        "@types/node": ">= 14",
+        "less": "*",
+        "lightningcss": "^1.21.0",
+        "sass": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/websocket-driver": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+      "dependencies": {
+        "http-parser-js": ">=0.5.1",
+        "safe-buffer": ">=5.1.0",
+        "websocket-extensions": ">=0.1.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/websocket-extensions": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs": {
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "engines": {
+        "node": ">=12"
+      }
+    }
+  }
+}

From 168e7be81b91d518d590a1b6996849985834a8dc Mon Sep 17 00:00:00 2001
From: Christina Holland <chholland@google.com>
Date: Mon, 20 May 2024 12:27:55 -0700
Subject: [PATCH 06/82] Update model names to use gemini-1.5-flash-preview-0514

---
 vertexai/main.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/vertexai/main.ts b/vertexai/main.ts
index 87e4652c6..6c96971df 100644
--- a/vertexai/main.ts
+++ b/vertexai/main.ts
@@ -38,7 +38,7 @@ async function main() {
   // Get a Gemini model
   const model = getGenerativeModel(
     vertexAI,
-    { model: "gemini-1.5-pro-preview-0409" }
+    { model: "gemini-1.5-flash-preview-0514" }
   );
   // Call generateContent with a string or Content(s)
   const generateContentResult = await model.generateContent("what is a cat?");

From 427c4deed467f9753b46f30f20927a376beedc52 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Thu, 30 May 2024 17:32:20 -0400
Subject: [PATCH 07/82] feat: fdc quickstart

---
 .gitignore                                    |    1 +
 dataconnect/README.md                         |   39 +
 .../.dataconnect/schema/main/implicit.gql     |   27 +
 .../.dataconnect/schema/main/input.gql        |  316 ++
 .../.dataconnect/schema/main/mutation.gql     |  218 ++
 .../.dataconnect/schema/main/query.gql        |   79 +
 .../.dataconnect/schema/main/relation.gql     |   94 +
 .../.dataconnect/schema/prelude.gql           |  947 ++++++
 dataconnect/dataconnect/1_movie_insert.gql    |  241 ++
 dataconnect/dataconnect/2_actor_insert.gql    |  141 +
 .../dataconnect/3_movie_actor_insert.gql      |  283 ++
 .../4_user_favorites_review_insert.gql        |  184 ++
 .../dataconnect/connector/connector.yaml      |   14 +
 .../dataconnect/connector/mutations.gql       |  113 +
 dataconnect/dataconnect/connector/queries.gql |  565 ++++
 dataconnect/dataconnect/dataconnect.yaml      |   10 +
 dataconnect/dataconnect/schema/schema.gql     |  104 +
 dataconnect/firebase.json                     |   32 +
 dataconnect/movie/.env.local                  |    6 +
 dataconnect/movie/app/actor/[id]/page.tsx     |  138 +
 dataconnect/movie/app/advancedsearch/page.tsx |  219 ++
 dataconnect/movie/app/genre/[genre]/page.tsx  |   70 +
 dataconnect/movie/app/layout.tsx              |   19 +
 dataconnect/movie/app/movie/[id]/page.tsx     |  280 ++
 dataconnect/movie/app/myprofile/page.tsx      |  210 ++
 dataconnect/movie/app/page.tsx                |   41 +
 dataconnect/movie/app/vectors/page.tsx        |   82 +
 dataconnect/movie/assets/firebase_logo.svg    |    6 +
 dataconnect/movie/components/carousel.tsx     |   38 +
 dataconnect/movie/components/moviecard.tsx    |  144 +
 dataconnect/movie/components/navbar.tsx       |   97 +
 .../lib/dataconnect-sdk/esm/index.esm.js      |  318 ++
 .../lib/dataconnect-sdk/esm/package.json      |    1 +
 .../movie/lib/dataconnect-sdk/index.cjs.js    |  403 +++
 .../movie/lib/dataconnect-sdk/index.d.ts      | 1144 +++++++
 .../movie/lib/dataconnect-sdk/package.json    |   25 +
 dataconnect/movie/lib/firebase.tsx            |   33 +
 dataconnect/movie/next-env.d.ts               |    5 +
 dataconnect/movie/package-lock.json           | 2653 +++++++++++++++++
 dataconnect/movie/package.json                |   26 +
 dataconnect/movie/postcss.config.js           |    6 +
 dataconnect/movie/styles.css                  |    3 +
 dataconnect/movie/tailwind.config.js          |   13 +
 dataconnect/movie/tsconfig.json               |   25 +
 44 files changed, 9413 insertions(+)
 create mode 100644 dataconnect/README.md
 create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql
 create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/input.gql
 create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql
 create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/query.gql
 create mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/relation.gql
 create mode 100755 dataconnect/dataconnect/.dataconnect/schema/prelude.gql
 create mode 100644 dataconnect/dataconnect/1_movie_insert.gql
 create mode 100644 dataconnect/dataconnect/2_actor_insert.gql
 create mode 100644 dataconnect/dataconnect/3_movie_actor_insert.gql
 create mode 100644 dataconnect/dataconnect/4_user_favorites_review_insert.gql
 create mode 100644 dataconnect/dataconnect/connector/connector.yaml
 create mode 100644 dataconnect/dataconnect/connector/mutations.gql
 create mode 100644 dataconnect/dataconnect/connector/queries.gql
 create mode 100644 dataconnect/dataconnect/dataconnect.yaml
 create mode 100644 dataconnect/dataconnect/schema/schema.gql
 create mode 100644 dataconnect/firebase.json
 create mode 100644 dataconnect/movie/.env.local
 create mode 100644 dataconnect/movie/app/actor/[id]/page.tsx
 create mode 100644 dataconnect/movie/app/advancedsearch/page.tsx
 create mode 100644 dataconnect/movie/app/genre/[genre]/page.tsx
 create mode 100644 dataconnect/movie/app/layout.tsx
 create mode 100644 dataconnect/movie/app/movie/[id]/page.tsx
 create mode 100644 dataconnect/movie/app/myprofile/page.tsx
 create mode 100644 dataconnect/movie/app/page.tsx
 create mode 100644 dataconnect/movie/app/vectors/page.tsx
 create mode 100644 dataconnect/movie/assets/firebase_logo.svg
 create mode 100644 dataconnect/movie/components/carousel.tsx
 create mode 100644 dataconnect/movie/components/moviecard.tsx
 create mode 100644 dataconnect/movie/components/navbar.tsx
 create mode 100644 dataconnect/movie/lib/dataconnect-sdk/esm/index.esm.js
 create mode 100644 dataconnect/movie/lib/dataconnect-sdk/esm/package.json
 create mode 100644 dataconnect/movie/lib/dataconnect-sdk/index.cjs.js
 create mode 100644 dataconnect/movie/lib/dataconnect-sdk/index.d.ts
 create mode 100644 dataconnect/movie/lib/dataconnect-sdk/package.json
 create mode 100644 dataconnect/movie/lib/firebase.tsx
 create mode 100644 dataconnect/movie/next-env.d.ts
 create mode 100644 dataconnect/movie/package-lock.json
 create mode 100644 dataconnect/movie/package.json
 create mode 100644 dataconnect/movie/postcss.config.js
 create mode 100644 dataconnect/movie/styles.css
 create mode 100644 dataconnect/movie/tailwind.config.js
 create mode 100644 dataconnect/movie/tsconfig.json

diff --git a/.gitignore b/.gitignore
index 0d634a8e1..dee8c505e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@
 .firebaserc
 dist/
 **/ui-debug.log
+.next
diff --git a/dataconnect/README.md b/dataconnect/README.md
new file mode 100644
index 000000000..c2b0dca3c
--- /dev/null
+++ b/dataconnect/README.md
@@ -0,0 +1,39 @@
+Firebase DataConnect Quickstart
+=======================================
+
+Introduction
+------------
+
+This is a sample app for the preview version of the Firebase DataConnect.
+This will not work if you don't have access to the preview.
+
+<!-- Introduction
+------------
+
+[Read more about Firebase DataConnect ](https://firebase.google.com/docs/dataconnect/) -->
+
+Getting Started
+---------------
+
+1. Sign up for early access [here](https://firebase.google.com/products/data-connect) and receive an invitation.
+2. Upgrade your Firebase project billing to the Blaze plan, you will not be charged for the duration of gated preview.
+3. Initialize DataConnect in the [Firebase Console](https://console.firebase.google.com/u/0/).
+4. Clone this repository to your local machine.
+5. Update `firebase-tools` with `npm install -g firebase-tools`.
+6. Enable the DataConnect CLI with `firebase experiments:enable dataconnect`.
+7. Initialize your Firebase project in the `dataconnect` folder with `firebase init` and select DataConnect.
+8. Replace variables in `.env.local` with your project-specific values.
+9. Allow domains for Firebase Auth (e.g., http://localhost or http://127.0.0.1).
+10. Deploy DataConnect with `firebase deploy --only dataconnect` (this unlocks hidden vectors search).
+11. Navigate to the `movie` directory and install dependencies with `npm i` and start the development server with `npm run dev`.
+12. Run the four `_insert.gql` files in the `./dataconnect` directory in order.
+
+<!-- Support
+-------
+
+- [Firebase Support](https://firebase.google.com/support/) -->
+
+License
+-------
+
+© Google, 2024. Licensed under an [Apache-2](../LICENSE) license.
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql
new file mode 100755
index 000000000..a3860ad40
--- /dev/null
+++ b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql
@@ -0,0 +1,27 @@
+extend type FavoriteActor {
+  userId: String!
+  actorId: UUID!
+}
+extend type FavoriteMovie {
+  userId: String!
+  movieId: UUID!
+}
+extend type Movie {
+  sequelToId: UUID
+}
+extend type MovieActor {
+  movieId: UUID!
+  actorId: UUID!
+}
+extend type MovieMetadata {
+  id: UUID! @default(expr: "uuidV4()")
+  movieId: UUID!
+}
+extend type Review {
+  movieId: UUID!
+  userId: String!
+}
+extend type WatchedMovie {
+  userId: String!
+  movieId: UUID!
+}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/input.gql b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql
new file mode 100755
index 000000000..b7d1c62ae
--- /dev/null
+++ b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql
@@ -0,0 +1,316 @@
+scalar Actor_Key
+scalar FavoriteActor_Key
+scalar FavoriteMovie_Key
+scalar Movie_Key
+scalar MovieActor_Key
+scalar MovieMetadata_Key
+scalar Review_Key
+scalar User_Key
+scalar WatchedMovie_Key
+input Actor_Data {
+  id: UUID
+  id_expr: UUID_Expr
+  biography: String
+  biography_expr: String_Expr
+  imageUrl: String
+  imageUrl_expr: String_Expr
+  name: String
+  name_expr: String_Expr
+}
+input Actor_Filter {
+  _and: [Actor_Filter!]
+  _not: Actor_Filter
+  _or: [Actor_Filter!]
+  id: UUID_Filter
+  biography: String_Filter
+  imageUrl: String_Filter
+  name: String_Filter
+  favoriteActors_on_actor: FavoriteActor_ListFilter
+  movieActors_on_actor: MovieActor_ListFilter
+  movies_via_MovieActor: Movie_ListFilter
+  users_via_FavoriteActor: User_ListFilter
+}
+input Actor_ListFilter {
+  count: Int_Filter
+  exist: Actor_Filter
+}
+input Actor_Order {
+  id: OrderDirection
+  biography: OrderDirection
+  imageUrl: OrderDirection
+  name: OrderDirection
+}
+input FavoriteActor_Data {
+  userId: String
+  userId_expr: String_Expr
+  actorId: UUID
+  actorId_expr: UUID_Expr
+  actor: Actor_Key
+  user: User_Key
+}
+input FavoriteActor_Filter {
+  _and: [FavoriteActor_Filter!]
+  _not: FavoriteActor_Filter
+  _or: [FavoriteActor_Filter!]
+  userId: String_Filter
+  actorId: UUID_Filter
+  actor: Actor_Filter
+  user: User_Filter
+}
+input FavoriteActor_ListFilter {
+  count: Int_Filter
+  exist: FavoriteActor_Filter
+}
+input FavoriteActor_Order {
+  userId: OrderDirection
+  actorId: OrderDirection
+  actor: Actor_Order
+  user: User_Order
+}
+input FavoriteMovie_Data {
+  userId: String
+  userId_expr: String_Expr
+  movieId: UUID
+  movieId_expr: UUID_Expr
+  movie: Movie_Key
+  user: User_Key
+}
+input FavoriteMovie_Filter {
+  _and: [FavoriteMovie_Filter!]
+  _not: FavoriteMovie_Filter
+  _or: [FavoriteMovie_Filter!]
+  userId: String_Filter
+  movieId: UUID_Filter
+  movie: Movie_Filter
+  user: User_Filter
+}
+input FavoriteMovie_ListFilter {
+  count: Int_Filter
+  exist: FavoriteMovie_Filter
+}
+input FavoriteMovie_Order {
+  userId: OrderDirection
+  movieId: OrderDirection
+  movie: Movie_Order
+  user: User_Order
+}
+input Movie_Data {
+  id: UUID
+  id_expr: UUID_Expr
+  sequelToId: UUID
+  sequelToId_expr: UUID_Expr
+  sequelTo: Movie_Key
+  description: String
+  description_expr: String_Expr
+  descriptionEmbedding: Vector
+  descriptionEmbedding_embed: Vector_Embed
+  genre: String
+  genre_expr: String_Expr
+  imageUrl: String
+  imageUrl_expr: String_Expr
+  rating: Float
+  releaseYear: Int
+  tags: [String!]
+  title: String
+  title_expr: String_Expr
+}
+input Movie_Filter {
+  _and: [Movie_Filter!]
+  _not: Movie_Filter
+  _or: [Movie_Filter!]
+  id: UUID_Filter
+  sequelToId: UUID_Filter
+  sequelTo: Movie_Filter
+  description: String_Filter
+  descriptionEmbedding: Vector_Filter
+  genre: String_Filter
+  imageUrl: String_Filter
+  rating: Float_Filter
+  releaseYear: Int_Filter
+  tags: String_ListFilter
+  title: String_Filter
+  favoriteMovies_on_movie: FavoriteMovie_ListFilter
+  movies_on_sequelTo: Movie_ListFilter
+  movieActors_on_movie: MovieActor_ListFilter
+  movieMetadatas_on_movie: MovieMetadata_ListFilter
+  reviews_on_movie: Review_ListFilter
+  watchedMovies_on_movie: WatchedMovie_ListFilter
+  actors_via_MovieActor: Actor_ListFilter
+  users_via_FavoriteMovie: User_ListFilter
+  users_via_Review: User_ListFilter
+  users_via_WatchedMovie: User_ListFilter
+}
+input Movie_ListFilter {
+  count: Int_Filter
+  exist: Movie_Filter
+}
+input Movie_Order {
+  id: OrderDirection
+  sequelToId: OrderDirection
+  sequelTo: Movie_Order
+  description: OrderDirection
+  descriptionEmbedding: OrderDirection
+  genre: OrderDirection
+  imageUrl: OrderDirection
+  rating: OrderDirection
+  releaseYear: OrderDirection
+  title: OrderDirection
+}
+input MovieActor_Data {
+  movieId: UUID
+  movieId_expr: UUID_Expr
+  actorId: UUID
+  actorId_expr: UUID_Expr
+  actor: Actor_Key
+  movie: Movie_Key
+  role: String
+  role_expr: String_Expr
+}
+input MovieActor_Filter {
+  _and: [MovieActor_Filter!]
+  _not: MovieActor_Filter
+  _or: [MovieActor_Filter!]
+  movieId: UUID_Filter
+  actorId: UUID_Filter
+  actor: Actor_Filter
+  movie: Movie_Filter
+  role: String_Filter
+}
+input MovieActor_ListFilter {
+  count: Int_Filter
+  exist: MovieActor_Filter
+}
+input MovieActor_Order {
+  movieId: OrderDirection
+  actorId: OrderDirection
+  actor: Actor_Order
+  movie: Movie_Order
+  role: OrderDirection
+}
+input MovieMetadata_Data {
+  id: UUID
+  id_expr: UUID_Expr
+  movieId: UUID
+  movieId_expr: UUID_Expr
+  movie: Movie_Key
+  director: String
+  director_expr: String_Expr
+}
+input MovieMetadata_Filter {
+  _and: [MovieMetadata_Filter!]
+  _not: MovieMetadata_Filter
+  _or: [MovieMetadata_Filter!]
+  id: UUID_Filter
+  movieId: UUID_Filter
+  movie: Movie_Filter
+  director: String_Filter
+}
+input MovieMetadata_ListFilter {
+  count: Int_Filter
+  exist: MovieMetadata_Filter
+}
+input MovieMetadata_Order {
+  id: OrderDirection
+  movieId: OrderDirection
+  movie: Movie_Order
+  director: OrderDirection
+}
+input Review_Data {
+  movieId: UUID
+  movieId_expr: UUID_Expr
+  userId: String
+  userId_expr: String_Expr
+  movie: Movie_Key
+  user: User_Key
+  id: UUID
+  id_expr: UUID_Expr
+  rating: Int
+  reviewDate: Date
+  reviewDate_date: Date_Relative
+  reviewDate_expr: Date_Expr
+  reviewText: String
+  reviewText_expr: String_Expr
+}
+input Review_Filter {
+  _and: [Review_Filter!]
+  _not: Review_Filter
+  _or: [Review_Filter!]
+  movieId: UUID_Filter
+  userId: String_Filter
+  movie: Movie_Filter
+  user: User_Filter
+  id: UUID_Filter
+  rating: Int_Filter
+  reviewDate: Date_Filter
+  reviewText: String_Filter
+}
+input Review_ListFilter {
+  count: Int_Filter
+  exist: Review_Filter
+}
+input Review_Order {
+  movieId: OrderDirection
+  userId: OrderDirection
+  movie: Movie_Order
+  user: User_Order
+  id: OrderDirection
+  rating: OrderDirection
+  reviewDate: OrderDirection
+  reviewText: OrderDirection
+}
+input User_Data {
+  id: String
+  id_expr: String_Expr
+  username: String
+  username_expr: String_Expr
+}
+input User_Filter {
+  _and: [User_Filter!]
+  _not: User_Filter
+  _or: [User_Filter!]
+  id: String_Filter
+  username: String_Filter
+  favoriteActors_on_user: FavoriteActor_ListFilter
+  favoriteMovies_on_user: FavoriteMovie_ListFilter
+  reviews_on_user: Review_ListFilter
+  watchedMovies_on_user: WatchedMovie_ListFilter
+  actors_via_FavoriteActor: Actor_ListFilter
+  movies_via_FavoriteMovie: Movie_ListFilter
+  movies_via_Review: Movie_ListFilter
+  movies_via_WatchedMovie: Movie_ListFilter
+}
+input User_ListFilter {
+  count: Int_Filter
+  exist: User_Filter
+}
+input User_Order {
+  id: OrderDirection
+  username: OrderDirection
+}
+input WatchedMovie_Data {
+  userId: String
+  userId_expr: String_Expr
+  movieId: UUID
+  movieId_expr: UUID_Expr
+  movie: Movie_Key
+  user: User_Key
+}
+input WatchedMovie_Filter {
+  _and: [WatchedMovie_Filter!]
+  _not: WatchedMovie_Filter
+  _or: [WatchedMovie_Filter!]
+  userId: String_Filter
+  movieId: UUID_Filter
+  movie: Movie_Filter
+  user: User_Filter
+}
+input WatchedMovie_ListFilter {
+  count: Int_Filter
+  exist: WatchedMovie_Filter
+}
+input WatchedMovie_Order {
+  userId: OrderDirection
+  movieId: OrderDirection
+  movie: Movie_Order
+  user: User_Order
+}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql
new file mode 100755
index 000000000..89c6e66db
--- /dev/null
+++ b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql
@@ -0,0 +1,218 @@
+extend type Mutation {
+  """
+  Insert a single Actor into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+  """
+  actor_insert(data: Actor_Data!): Actor_Key!
+  """
+  Insert a single FavoriteActor into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+  """
+  favoriteActor_insert(data: FavoriteActor_Data!): FavoriteActor_Key!
+  """
+  Insert a single FavoriteMovie into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+  """
+  favoriteMovie_insert(data: FavoriteMovie_Data!): FavoriteMovie_Key!
+  """
+  Insert a single Movie into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+  """
+  movie_insert(data: Movie_Data!): Movie_Key!
+  """
+  Insert a single MovieActor into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+  """
+  movieActor_insert(data: MovieActor_Data!): MovieActor_Key!
+  """
+  Insert a single MovieMetadata into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+  """
+  movieMetadata_insert(data: MovieMetadata_Data!): MovieMetadata_Key!
+  """
+  Insert a single Review into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+  """
+  review_insert(data: Review_Data!): Review_Key!
+  """
+  Insert a single User into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+  """
+  user_insert(data: User_Data!): User_Key!
+  """
+  Insert a single WatchedMovie into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+  """
+  watchedMovie_insert(data: WatchedMovie_Data!): WatchedMovie_Key!
+  """
+  Insert or update a single Actor into the table, based on the primary key. Returns the key of the newly inserted Actor.
+  """
+  actor_upsert(data: Actor_Data!): Actor_Key!
+  """
+  Insert or update a single FavoriteActor into the table, based on the primary key. Returns the key of the newly inserted FavoriteActor.
+  """
+  favoriteActor_upsert(data: FavoriteActor_Data!): FavoriteActor_Key!
+  """
+  Insert or update a single FavoriteMovie into the table, based on the primary key. Returns the key of the newly inserted FavoriteMovie.
+  """
+  favoriteMovie_upsert(data: FavoriteMovie_Data!): FavoriteMovie_Key!
+  """
+  Insert or update a single Movie into the table, based on the primary key. Returns the key of the newly inserted Movie.
+  """
+  movie_upsert(data: Movie_Data!): Movie_Key!
+  """
+  Insert or update a single MovieActor into the table, based on the primary key. Returns the key of the newly inserted MovieActor.
+  """
+  movieActor_upsert(data: MovieActor_Data!): MovieActor_Key!
+  """
+  Insert or update a single MovieMetadata into the table, based on the primary key. Returns the key of the newly inserted MovieMetadata.
+  """
+  movieMetadata_upsert(data: MovieMetadata_Data!): MovieMetadata_Key!
+  """
+  Insert or update a single Review into the table, based on the primary key. Returns the key of the newly inserted Review.
+  """
+  review_upsert(data: Review_Data!): Review_Key!
+  """
+  Insert or update a single User into the table, based on the primary key. Returns the key of the newly inserted User.
+  """
+  user_upsert(data: User_Data!): User_Key!
+  """
+  Insert or update a single WatchedMovie into the table, based on the primary key. Returns the key of the newly inserted WatchedMovie.
+  """
+  watchedMovie_upsert(data: WatchedMovie_Data!): WatchedMovie_Key!
+  """
+  Update a single Actor based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
+  """
+  actor_update(id: UUID, key: Actor_Key, data: Actor_Data!): Actor_Key
+  """
+  Update a single FavoriteActor based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
+  """
+  favoriteActor_update(key: FavoriteActor_Key, data: FavoriteActor_Data!): FavoriteActor_Key
+  """
+  Update a single FavoriteMovie based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
+  """
+  favoriteMovie_update(key: FavoriteMovie_Key, data: FavoriteMovie_Data!): FavoriteMovie_Key
+  """
+  Update a single Movie based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
+  """
+  movie_update(id: UUID, key: Movie_Key, data: Movie_Data!): Movie_Key
+  """
+  Update a single MovieActor based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
+  """
+  movieActor_update(key: MovieActor_Key, data: MovieActor_Data!): MovieActor_Key
+  """
+  Update a single MovieMetadata based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
+  """
+  movieMetadata_update(id: UUID, key: MovieMetadata_Key, data: MovieMetadata_Data!): MovieMetadata_Key
+  """
+  Update a single Review based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
+  """
+  review_update(key: Review_Key, data: Review_Data!): Review_Key
+  """
+  Update a single User based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
+  """
+  user_update(id: String, id_expr: String_Expr, key: User_Key, data: User_Data!): User_Key
+  """
+  Update a single WatchedMovie based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
+  """
+  watchedMovie_update(key: WatchedMovie_Key, data: WatchedMovie_Data!): WatchedMovie_Key
+  """
+  Update Actor entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+  """
+  actor_updateMany(where: Actor_Filter, all: Boolean = false, data: Actor_Data!): Int!
+  """
+  Update FavoriteActor entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+  """
+  favoriteActor_updateMany(where: FavoriteActor_Filter, all: Boolean = false, data: FavoriteActor_Data!): Int!
+  """
+  Update FavoriteMovie entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+  """
+  favoriteMovie_updateMany(where: FavoriteMovie_Filter, all: Boolean = false, data: FavoriteMovie_Data!): Int!
+  """
+  Update Movie entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+  """
+  movie_updateMany(where: Movie_Filter, all: Boolean = false, data: Movie_Data!): Int!
+  """
+  Update MovieActor entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+  """
+  movieActor_updateMany(where: MovieActor_Filter, all: Boolean = false, data: MovieActor_Data!): Int!
+  """
+  Update MovieMetadata entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+  """
+  movieMetadata_updateMany(where: MovieMetadata_Filter, all: Boolean = false, data: MovieMetadata_Data!): Int!
+  """
+  Update Review entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+  """
+  review_updateMany(where: Review_Filter, all: Boolean = false, data: Review_Data!): Int!
+  """
+  Update User entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+  """
+  user_updateMany(where: User_Filter, all: Boolean = false, data: User_Data!): Int!
+  """
+  Update WatchedMovie entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+  """
+  watchedMovie_updateMany(where: WatchedMovie_Filter, all: Boolean = false, data: WatchedMovie_Data!): Int!
+  """
+  Delete a single Actor based on `id` or `key` and return its key (or `null` if not found).
+  """
+  actor_delete(id: UUID, key: Actor_Key): Actor_Key
+  """
+  Delete a single FavoriteActor based on `id` or `key` and return its key (or `null` if not found).
+  """
+  favoriteActor_delete(key: FavoriteActor_Key): FavoriteActor_Key
+  """
+  Delete a single FavoriteMovie based on `id` or `key` and return its key (or `null` if not found).
+  """
+  favoriteMovie_delete(key: FavoriteMovie_Key): FavoriteMovie_Key
+  """
+  Delete a single Movie based on `id` or `key` and return its key (or `null` if not found).
+  """
+  movie_delete(id: UUID, key: Movie_Key): Movie_Key
+  """
+  Delete a single MovieActor based on `id` or `key` and return its key (or `null` if not found).
+  """
+  movieActor_delete(key: MovieActor_Key): MovieActor_Key
+  """
+  Delete a single MovieMetadata based on `id` or `key` and return its key (or `null` if not found).
+  """
+  movieMetadata_delete(id: UUID, key: MovieMetadata_Key): MovieMetadata_Key
+  """
+  Delete a single Review based on `id` or `key` and return its key (or `null` if not found).
+  """
+  review_delete(key: Review_Key): Review_Key
+  """
+  Delete a single User based on `id` or `key` and return its key (or `null` if not found).
+  """
+  user_delete(id: String, id_expr: String_Expr, key: User_Key): User_Key
+  """
+  Delete a single WatchedMovie based on `id` or `key` and return its key (or `null` if not found).
+  """
+  watchedMovie_delete(key: WatchedMovie_Key): WatchedMovie_Key
+  """
+  Delete Actor entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+  """
+  actor_deleteMany(where: Actor_Filter, all: Boolean = false): Int!
+  """
+  Delete FavoriteActor entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+  """
+  favoriteActor_deleteMany(where: FavoriteActor_Filter, all: Boolean = false): Int!
+  """
+  Delete FavoriteMovie entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+  """
+  favoriteMovie_deleteMany(where: FavoriteMovie_Filter, all: Boolean = false): Int!
+  """
+  Delete Movie entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+  """
+  movie_deleteMany(where: Movie_Filter, all: Boolean = false): Int!
+  """
+  Delete MovieActor entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+  """
+  movieActor_deleteMany(where: MovieActor_Filter, all: Boolean = false): Int!
+  """
+  Delete MovieMetadata entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+  """
+  movieMetadata_deleteMany(where: MovieMetadata_Filter, all: Boolean = false): Int!
+  """
+  Delete Review entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+  """
+  review_deleteMany(where: Review_Filter, all: Boolean = false): Int!
+  """
+  Delete User entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+  """
+  user_deleteMany(where: User_Filter, all: Boolean = false): Int!
+  """
+  Delete WatchedMovie entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+  """
+  watchedMovie_deleteMany(where: WatchedMovie_Filter, all: Boolean = false): Int!
+}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/query.gql b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql
new file mode 100755
index 000000000..2784eb715
--- /dev/null
+++ b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql
@@ -0,0 +1,79 @@
+extend type Query {
+  """
+  Look up a single Actor based on `id` or `key` and return selected fields (or `null` if not found).
+  """
+  actor(id: UUID, key: Actor_Key): Actor
+  """
+  Look up a single FavoriteActor based on `id` or `key` and return selected fields (or `null` if not found).
+  """
+  favoriteActor(key: FavoriteActor_Key): FavoriteActor
+  """
+  Look up a single FavoriteMovie based on `id` or `key` and return selected fields (or `null` if not found).
+  """
+  favoriteMovie(key: FavoriteMovie_Key): FavoriteMovie
+  """
+  Look up a single Movie based on `id` or `key` and return selected fields (or `null` if not found).
+  """
+  movie(id: UUID, key: Movie_Key): Movie
+  """
+  Look up a single MovieActor based on `id` or `key` and return selected fields (or `null` if not found).
+  """
+  movieActor(key: MovieActor_Key): MovieActor
+  """
+  Look up a single MovieMetadata based on `id` or `key` and return selected fields (or `null` if not found).
+  """
+  movieMetadata(id: UUID, key: MovieMetadata_Key): MovieMetadata
+  """
+  Look up a single Review based on `id` or `key` and return selected fields (or `null` if not found).
+  """
+  review(key: Review_Key): Review
+  """
+  Look up a single User based on `id` or `key` and return selected fields (or `null` if not found).
+  """
+  user(id: String, id_expr: String_Expr, key: User_Key): User
+  """
+  Look up a single WatchedMovie based on `id` or `key` and return selected fields (or `null` if not found).
+  """
+  watchedMovie(key: WatchedMovie_Key): WatchedMovie
+  """
+  List Actor entries in the table, optionally filtered by `where` conditions.
+  """
+  actors(where: Actor_Filter, orderBy: [Actor_Order!], limit: Int = 100): [Actor!]!
+  """
+  List FavoriteActor entries in the table, optionally filtered by `where` conditions.
+  """
+  favoriteActors(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [FavoriteActor!]!
+  """
+  List FavoriteMovie entries in the table, optionally filtered by `where` conditions.
+  """
+  favoriteMovies(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [FavoriteMovie!]!
+  """
+  List Movie entries in the table, optionally filtered by `where` conditions.
+  """
+  movies(where: Movie_Filter, orderBy: [Movie_Order!], limit: Int = 100): [Movie!]!
+  """
+  List MovieActor entries in the table, optionally filtered by `where` conditions.
+  """
+  movieActors(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [MovieActor!]!
+  """
+  List MovieMetadata entries in the table, optionally filtered by `where` conditions.
+  """
+  movieMetadatas(where: MovieMetadata_Filter, orderBy: [MovieMetadata_Order!], limit: Int = 100): [MovieMetadata!]!
+  """
+  List Review entries in the table, optionally filtered by `where` conditions.
+  """
+  reviews(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Review!]!
+  """
+  List User entries in the table, optionally filtered by `where` conditions.
+  """
+  users(where: User_Filter, orderBy: [User_Order!], limit: Int = 100): [User!]!
+  """
+  List WatchedMovie entries in the table, optionally filtered by `where` conditions.
+  """
+  watchedMovies(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [WatchedMovie!]!
+  """
+  List Movie entries ordered by vector similarity between the `descriptionEmbedding` field and `compare_embed`.
+  (Alternatively, `compare` can be used if the input is a raw Vector.)
+  """
+  movies_descriptionEmbedding_similarity(compare: Vector, compare_embed: Vector_Embed, method: VectorSimilarityMethod = INNER_PRODUCT, within: Float, where: Movie_Filter, limit: Int = 100): [Movie!]!
+}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql
new file mode 100755
index 000000000..7cc34201b
--- /dev/null
+++ b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql
@@ -0,0 +1,94 @@
+extend type Actor {
+  """
+  ✨ List FavoriteActor entries in a one-to-many relationship with this object (i.e. where `FavoriteActor.actor` equals this object).
+  """
+  favoriteActors_on_actor(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [FavoriteActor!]!
+  """
+  ✨ List MovieActor entries in a one-to-many relationship with this object (i.e. where `MovieActor.actor` equals this object).
+  """
+  movieActors_on_actor(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [MovieActor!]!
+  """
+  ✨ List related Movie entries using MovieActor as a join table (i.e. where an entry of MovieActor exists whose actor == this and movie == that).
+  """
+  movies_via_MovieActor(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [Movie!]!
+  """
+  ✨ List related User entries using FavoriteActor as a join table (i.e. where an entry of FavoriteActor exists whose actor == this and user == that).
+  """
+  users_via_FavoriteActor(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [User!]!
+}
+extend type Movie {
+  """
+  ✨ List FavoriteMovie entries in a one-to-many relationship with this object (i.e. where `FavoriteMovie.movie` equals this object).
+  """
+  favoriteMovies_on_movie(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [FavoriteMovie!]!
+  """
+  ✨ List Movie entries in a one-to-many relationship with this object (i.e. where `Movie.sequelTo` equals this object).
+  """
+  movies_on_sequelTo(where: Movie_Filter, orderBy: [Movie_Order!], limit: Int = 100): [Movie!]!
+  """
+  ✨ List MovieActor entries in a one-to-many relationship with this object (i.e. where `MovieActor.movie` equals this object).
+  """
+  movieActors_on_movie(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [MovieActor!]!
+  """
+  ✨ List MovieMetadata entries in a one-to-many relationship with this object (i.e. where `MovieMetadata.movie` equals this object).
+  """
+  movieMetadatas_on_movie(where: MovieMetadata_Filter, orderBy: [MovieMetadata_Order!], limit: Int = 100): [MovieMetadata!]!
+  """
+  ✨ List Review entries in a one-to-many relationship with this object (i.e. where `Review.movie` equals this object).
+  """
+  reviews_on_movie(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Review!]!
+  """
+  ✨ List WatchedMovie entries in a one-to-many relationship with this object (i.e. where `WatchedMovie.movie` equals this object).
+  """
+  watchedMovies_on_movie(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [WatchedMovie!]!
+  """
+  ✨ List related Actor entries using MovieActor as a join table (i.e. where an entry of MovieActor exists whose movie == this and actor == that).
+  """
+  actors_via_MovieActor(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [Actor!]!
+  """
+  ✨ List related User entries using FavoriteMovie as a join table (i.e. where an entry of FavoriteMovie exists whose movie == this and user == that).
+  """
+  users_via_FavoriteMovie(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [User!]!
+  """
+  ✨ List related User entries using Review as a join table (i.e. where an entry of Review exists whose movie == this and user == that).
+  """
+  users_via_Review(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [User!]!
+  """
+  ✨ List related User entries using WatchedMovie as a join table (i.e. where an entry of WatchedMovie exists whose movie == this and user == that).
+  """
+  users_via_WatchedMovie(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [User!]!
+}
+extend type User {
+  """
+  ✨ List FavoriteActor entries in a one-to-many relationship with this object (i.e. where `FavoriteActor.user` equals this object).
+  """
+  favoriteActors_on_user(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [FavoriteActor!]!
+  """
+  ✨ List FavoriteMovie entries in a one-to-many relationship with this object (i.e. where `FavoriteMovie.user` equals this object).
+  """
+  favoriteMovies_on_user(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [FavoriteMovie!]!
+  """
+  ✨ List Review entries in a one-to-many relationship with this object (i.e. where `Review.user` equals this object).
+  """
+  reviews_on_user(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Review!]!
+  """
+  ✨ List WatchedMovie entries in a one-to-many relationship with this object (i.e. where `WatchedMovie.user` equals this object).
+  """
+  watchedMovies_on_user(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [WatchedMovie!]!
+  """
+  ✨ List related Actor entries using FavoriteActor as a join table (i.e. where an entry of FavoriteActor exists whose user == this and actor == that).
+  """
+  actors_via_FavoriteActor(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [Actor!]!
+  """
+  ✨ List related Movie entries using FavoriteMovie as a join table (i.e. where an entry of FavoriteMovie exists whose user == this and movie == that).
+  """
+  movies_via_FavoriteMovie(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [Movie!]!
+  """
+  ✨ List related Movie entries using Review as a join table (i.e. where an entry of Review exists whose user == this and movie == that).
+  """
+  movies_via_Review(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Movie!]!
+  """
+  ✨ List related Movie entries using WatchedMovie as a join table (i.e. where an entry of WatchedMovie exists whose user == this and movie == that).
+  """
+  movies_via_WatchedMovie(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [Movie!]!
+}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/prelude.gql b/dataconnect/dataconnect/.dataconnect/schema/prelude.gql
new file mode 100755
index 000000000..3782971fe
--- /dev/null
+++ b/dataconnect/dataconnect/.dataconnect/schema/prelude.gql
@@ -0,0 +1,947 @@
+"AccessLevel specifies coarse access policies for common situations."
+enum AccessLevel {
+  """
+  This operation can be executed by anyone with or without authentication.
+  Equivalent to @auth(expr: "true")
+  """
+  PUBLIC
+
+  """
+  This operation can only be executed with a valid Firebase Auth ID token.
+  Note: it allows anonymous auth and unverified accounts, so may be subjected to abuses.
+  It’s equivalent to @auth(expr: "auth.uid != nil")
+  """
+  USER_ANON
+
+  """
+  This operation can only be executed by a non-anonymous Firebase Auth account.
+  It’s equivalent to @auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")"
+  """
+  USER
+
+  """
+  This operation can only be executed by a verified Firebase Auth account.
+  It’s equivalent to @auth(expr: "auth.uid != nil && auth.token.email_verified")"
+  """
+  USER_EMAIL_VERIFIED
+
+  """
+  This operation can not be executed with no IAM credentials.
+  It’s equivalent to @auth(expr: "false")
+  """
+  NO_ACCESS
+}
+
+"""
+Defines the auth policy for a query or mutation. This directive must be added to
+any operation you wish to be accessible from a client application. If left
+unspecified, defaults to `@auth(level: NO_ACCESS)`.
+"""
+directive @auth(
+  "The minimal level of access required to perform this operation."
+  level: AccessLevel @fdc_oneOf(required: true)
+  """
+  A CEL expression that allows access to this operation if the expression
+  evaluates to `true`.
+  """
+  expr: Boolean_Expr @fdc_oneOf(required: true)
+) on QUERY | MUTATION
+"Conditions on a string value"
+input String_Filter {
+  isNull: Boolean
+  eq: String @fdc_oneOf(group: "eq")
+  eq_expr: String_Expr @fdc_oneOf(group: "eq")
+  ne: String @fdc_oneOf(group: "ne")
+  ne_expr: String_Expr @fdc_oneOf(group: "ne")
+  in: [String!]
+  nin: [String!]
+  gt: String
+  ge: String
+  lt: String
+  le: String
+  contains: String
+  startsWith: String
+  endsWith: String
+  pattern: String_Pattern
+}
+
+"""
+The pattern match condition on a string. Specify either like or regex.
+https://www.postgresql.org/docs/current/functions-matching.html
+"""
+input String_Pattern {
+  "the LIKE expression to use"
+  like: String
+  "the POSIX regular expression"
+  regex: String
+  "when true, it's case-insensitive. In Postgres: ILIKE, ~*"
+  ignoreCase: Boolean
+  "when true, invert the condition. In Postgres: NOT LIKE, !~"
+  invert: Boolean
+}
+
+"Conditions on a string list"
+input String_ListFilter {
+  includes: String
+  excludes: String
+  includesAll: [String!]
+  excludesAll: [String!]
+}
+
+"Conditions on a UUID value"
+input UUID_Filter {
+  isNull: Boolean
+  eq: UUID
+  ne: UUID
+  in: [UUID!]
+  nin: [UUID!]
+}
+
+"Conditions on a UUID list"
+input UUID_ListFilter {
+  includes: UUID
+  excludes: UUID
+  includesAll: [UUID!]
+  excludesAll: [UUID!]
+}
+
+"Conditions on an Int value"
+input Int_Filter {
+  isNull: Boolean
+  eq: Int
+  ne: Int
+  in: [Int!]
+  nin: [Int!]
+  gt: Int
+  ge: Int
+  lt: Int
+  le: Int
+}
+
+"Conditions on an Int list"
+input Int_ListFilter {
+  includes: Int
+  excludes: Int
+  includesAll: [Int!]
+  excludesAll: [Int!]
+}
+
+"Conditions on an Int64 value"
+input Int64_Filter {
+  isNull: Boolean
+  eq: Int64
+  ne: Int64
+  in: [Int64!]
+  nin: [Int64!]
+  gt: Int64
+  ge: Int64
+  lt: Int64
+  le: Int64
+}
+
+"Conditions on an Int64 list"
+input Int64_ListFilter {
+  includes: Int64
+  excludes: Int64
+  includesAll: [Int64!]
+  excludesAll: [Int64!]
+}
+
+"Conditions on a Float value"
+input Float_Filter {
+  isNull: Boolean
+  eq: Float
+  ne: Float
+  in: [Float!]
+  nin: [Float!]
+  gt: Float
+  ge: Float
+  lt: Float
+  le: Float
+}
+
+"Conditions on a Float list"
+input Float_ListFilter {
+  includes: Float
+  excludes: Float
+  includesAll: [Float!]
+  excludesAll: [Float!]
+}
+
+"Conditions on a Boolean value"
+input Boolean_Filter {
+  isNull: Boolean
+  eq: Boolean
+  ne: Boolean
+  in: [Boolean!]
+  nin: [Boolean!]
+}
+
+"Conditions on a Boolean list"
+input Boolean_ListFilter {
+  includes: Boolean
+  excludes: Boolean
+  includesAll: [Boolean!]
+  excludesAll: [Boolean!]
+}
+
+"Conditions on an Any value"
+input Any_Filter {
+  isNull: Boolean
+  eq: Any
+  ne: Any
+  in: [Any!]
+  nin: [Any!]
+}
+
+"Conditions on a Any list"
+input Any_ListFilter {
+  includes: Any
+  excludes: Any
+  includesAll: [Any!]
+  excludesAll: [Any!]
+}
+type Query {
+  _service: _Service!
+}
+
+type Mutation {
+  # This is just a dummy field so that Mutation is always non-empty.
+  _firebase: Void @fdc_deprecated(reason: "dummy field -- does nothing useful")
+}
+
+type _Service {
+  sdl: String!
+}
+
+"(Internal) Added to things that may be removed from FDC and will soon be no longer usable in schema or operations."
+directive @fdc_deprecated(reason: String = "No longer supported") on
+  | SCHEMA
+  | SCALAR
+  | OBJECT
+  | FIELD_DEFINITION
+  | ARGUMENT_DEFINITION
+  | INTERFACE
+  | UNION
+  | ENUM
+  | ENUM_VALUE
+  | INPUT_OBJECT
+  | INPUT_FIELD_DEFINITION
+
+"(Internal) Added to scalars representing quoted CEL expressions."
+directive @fdc_celExpression(
+  "The expected CEL type that the expression should evaluate to."
+  returnType: String
+) on SCALAR
+
+"(Internal) Added to scalars representing quoted SQL expressions."
+directive @fdc_sqlExpression(
+  "The expected SQL type that the expression should evaluate to."
+  dataType: String
+) on SCALAR
+
+"(Internal) Added to types that may not be used as variables."
+directive @fdc_forbiddenAsVariableType on SCALAR | OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT
+
+"(Internal) Added to types that may not be used as fields in schema."
+directive @fdc_forbiddenAsFieldType on SCALAR | OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT
+
+"Provides a frequently used example for this type / field / argument."
+directive @fdc_example(
+  "A GraphQL literal value (verbatim) whose type matches the target."
+  value: Any
+  "A human-readable text description of what `value` means in this context."
+  description: String
+) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | INPUT_OBJECT | INPUT_FIELD_DEFINITION
+
+"(Internal) Marks this field / argument as conflicting with others in the same group."
+directive @fdc_oneOf(
+  "The group name where fields / arguments conflict with each other."
+  group: String! = ""
+  "If true, exactly one field / argument in the group must be specified."
+  required: Boolean! = false
+) repeatable on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
+"""
+UUID is a string with hex digits representing an RFC4122 value.
+
+Outputs will always be 32 lower-case hex digits with no delimiters or curly
+braces. Inputs in the following formats are also accepted (case insensitive):
+
+    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+    urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+    {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
+"""
+scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
+scalar Int64
+
+scalar Any
+scalar Void
+"""
+The `True` scalar type only accepts the boolean `true`.
+
+An optional field / argument typed `True` may either be set to `true` or omitted
+(not provided at all). `false` or `null` is not accepted.
+"""
+scalar True
+  @fdc_forbiddenAsFieldType
+  @fdc_forbiddenAsVariableType
+  @fdc_example(value: true, description: "The only allowed value.")
+"Define the intervals used in timestamps and dates (subset)"
+enum TimestampInterval @fdc_deprecated {
+  second
+  minute
+  hour
+  day
+  week
+  month
+  year
+}
+"""
+A Common Expression Language (CEL) expression that returns a boolean at runtime.
+
+The expression can reference the `auth` variable, which is null if Firebase Auth
+is not used. Otherwise, it contains the following fields:
+
+    - `auth.uid`: The current user ID.
+    - `auth.token`: A map of all token fields (i.e. "claims").
+"""
+scalar Boolean_Expr
+  @specifiedBy(url: "https://github.com/google/cel-spec")
+  @fdc_celExpression(returnType: "bool")
+  @fdc_forbiddenAsVariableType
+  @fdc_forbiddenAsFieldType
+  @fdc_example(value: "auth != null", description: "Allow only if a Firebase Auth user is present.")
+
+"""
+A Common Expression Language (CEL) expression that returns a string at runtime.
+
+Limitation: Right now, only a few expressions are supported. Those are listed
+using the @fdc_example directive on this scalar.
+"""
+scalar String_Expr
+  @specifiedBy(url: "https://github.com/google/cel-spec")
+  @fdc_celExpression(returnType: "string")
+  @fdc_forbiddenAsVariableType
+  @fdc_forbiddenAsFieldType
+  @fdc_example(value: "auth.uid", description: "The ID of the currently logged in user in Firebase Auth. (Errors if not logged in.)")
+  @fdc_example(value: "uuidV4()", description: "Generates a new random UUID (version 4) string, formatted as 32 lower-case hex digits without delimiters.")
+
+"""
+A Common Expression Language (CEL) expression that returns a UUID string at runtime.
+
+Limitation: Right now, only a few expressions are supported. Those are listed
+using the @fdc_example directive on this scalar.
+"""
+scalar UUID_Expr
+  @specifiedBy(url: "https://github.com/google/cel-spec")
+  @fdc_celExpression(returnType: "string")
+  @fdc_forbiddenAsVariableType
+  @fdc_forbiddenAsFieldType
+  @fdc_example(value: "uuidV4()", description: "Generates a new random UUID (version 4) every time.")
+
+"""
+A Common Expression Language (CEL) expression whose return type is unspecified.
+
+Limitation: Only a limited set of expressions are supported for now for each
+type. For type XXX, see the @fdc_example directives on XXX_Expr for a full list.
+"""
+scalar Any_Expr
+  @specifiedBy(url: "https://github.com/google/cel-spec")
+  @fdc_celExpression
+  @fdc_forbiddenAsVariableType
+  @fdc_forbiddenAsFieldType
+  @fdc_example(value: "auth.uid", description: "The ID of the currently logged in user in Firebase Auth. (Errors if not logged in.)")
+  @fdc_example(value: "uuidV4()", description: "Generates a new random UUID version 4 (formatted as 32 lower-case hex digits without delimiters if result type is String).")
+  @fdc_example(value: "request.time", description: "The timestamp when the request is received (with microseconds precision).")
+
+"""
+A PostgreSQL value expression whose return type is unspecified.
+"""
+scalar Any_SQL
+  @specifiedBy(url: "https://www.postgresql.org/docs/current/sql-expressions.html")
+  @fdc_sqlExpression
+  @fdc_forbiddenAsVariableType
+  @fdc_forbiddenAsFieldType
+"""
+Defines a relational database table.
+
+Given `type TableName @table`,
+
+ - `TableName` is the GQL type name.
+ - `tableName` is the singular name. Override with `@table(singular)`.
+ - `tableNames` is the plural name. Override with `@table(plural)`.
+ - `table_name` is the SQL table id. Override with `@table(name)`.
+
+Only a table type can be configured further with:
+
+ - Customized data types. See `@col`.
+ - Index. See `@index`
+ - Unique constraint. See `@unqiue`
+ - Relation. See `@ref`
+ - Embedded Json. See `@embed`
+
+A scalar field map to a SQL database column.
+An object field (like `type TableName @table { field: AnotherType }`) are either
+
+ - a relation reference field if `AnotherType` is annotated with `@table`.
+ - an embedded json field if `field` is annotated with `@embed`.
+
+"""
+directive @table(
+  "Override the SQL database table name. Defaults to <table_name>."
+  name: String
+  "Override the singular name. Default is the camel case of the type name."
+  singular: String
+  "Override the plural name. Default is generated based on English patterns."
+  plural: String
+  "The primary key of the table. Defaults to a single field `id: UUID!`. Generate if missing."
+  key: [String!]
+) on OBJECT
+
+"""
+Defines a relational database view.
+
+Given `type ViewName @view`,
+ - `ViewName` is the GQL type name.
+ - `viewName` is the singular name. Override with `@view(singular)`.
+ - `viewNames` is the plural name. Override with `@view(plural)`.
+ - `view_name` is the SQL view id. Override with `@view(name)`.
+    When `@view(sql)` is defined, it uses the given raw SQL as the view instead.
+
+A view type can be used just as a table type with queries.
+A view type may have a nullable `@ref` field to another table, but cannot be
+referenced in a `@ref`.
+
+WARNING: Firebase Data Connect does not validate the SQL of the view or
+evaluate whether it matches the defined fields.
+
+If the SQL view is invalid or undefined, related requests may fail.
+If the SQL view return incompatible types. Firebase Data Connect will surface
+an error in the response.
+"""
+directive @view(
+  """
+  The SQL view name. If no `name` or `sql` are provided, defaults to
+  snake_case of the singular type name.
+  """
+  name: String @fdc_oneOf
+  """
+  SQL SELECT statement to use as the basis for this type. Note that all SQL
+  identifiers should be snake_case and all GraphQL identifiers should be
+  camelCase.
+  """
+  sql: String @fdc_oneOf
+  "Override the singular name. Default is the camel case of the type name."
+  singular: String
+  "Override the plural name. Default is generated based on English patterns."
+  plural: String
+) on OBJECT
+
+"""
+Specify additional column options.
+
+Given `type TableName @table { fieldName: Int } `
+
+ - `field_name` is the SQL column name. Override with `@col(name)`.
+
+"""
+directive @col(
+  "The SQL database column name. Defaults to <field_name>."
+  name: String
+  """
+  Override SQL columns data type.
+  Each GraphQL type could map to many SQL data types.
+  Refer to Postgres supported data types and mappings to GQL.
+  """
+  dataType: String
+  """
+  Defines a fixed column size for certain scalar types.
+
+  - For Vector, size is required. It establishes the length of the vector.
+  - For String, size converts `text` type to `varchar(size)`.
+  """
+  size: Int
+) on FIELD_DEFINITION
+
+
+"""
+Define a reference field to another table.
+
+Given `type TableName @table { refField: AnotherTableName }`, it defines a foreign-key constraint
+
+ - with id `table_name_ref_field_fkey` (override with `@ref(constraintName)`)
+ - from `table_name.ref_field` (override with `@ref(fields)`)
+ - to `another_table_name.id` (override with `@ref(references)`)
+
+Does not support `[AnotherTableName]` because array fields cannot have foreign-key constraints.
+Nullability determines whether the reference is required.
+
+ - `refField: AnotherTableName`: optional reference, SET_NULL on delete.
+ - `refField: AnotherTableName!`: required reference, CASCADE on delete.
+
+Consider all types of SQL relations:
+
+ - many-to-one relations involve a reference field on the many-side.
+    - many-to-maybe-one if `refField: AnotherTableName`.
+    - many-to-exactly-one if `refField: AnotherTableName!`.
+ - one-to-one relations involve a unique reference field on one side.
+    - maybe-one-to-maybe-one if `refField: AnotherTableName @unique`.
+    - maybe-one-to-exact-one if `refField: AnotherTableName! @unique`.
+    - exact-one-to-exact-one shall be represented as a single table instead.
+ - many-to-many relations involve a join table.
+    - Its primary keys must be two non-null reference fields to tables bridged together to guarantee at most one relation per pair.
+
+type TableNameToAnotherTableName @table(key: ["refField", "anotherRefField"]) {
+  refField: TableName!
+  anotherRefField: AnotherTableName!
+}
+
+"""
+directive @ref(
+  "The SQL database foreign key constraint name. Default to <table_name>_<field_name>_fkey."
+  constraintName: String
+  """
+  Foreign key fields. Default to <tableName><PrimaryIdName>.
+  """
+  fields: [String!]
+  "The fields that the foreign key references in the other table. Default to the primary key."
+  references: [String!]
+) on FIELD_DEFINITION
+
+"Define the direction of an orderby query"
+enum OrderDirection {
+  ASC
+  DESC
+}
+
+enum ColDefault @fdc_deprecated {
+  """
+  Generates a random UUID (v4) as the default column value.
+  Compatible with String or UUID typed fields.
+  """
+  UUID
+  """
+  Generates an auto-incrementing sequence as the default column value.
+  Compatible with Int and Int64 typed fields.
+  """
+  SEQUENCE
+  """
+  Populates the default column value with the current date or timestamp.
+  Compatible with Date and Timestamp typed fields.
+  """
+  NOW
+}
+
+"""
+Specify the default column value.
+
+The supported arguments vary based on the field type.
+"""
+directive @default(
+  "A constant value. Validated against the field GraphQL type at compile-time."
+  value: Any @fdc_oneOf(required: true)
+  "(Deprecated) Built-in common ways to generate initial value."
+  generate: ColDefault @fdc_oneOf(required: true) @deprecated
+  "A CEL expression, whose return value must match the field data type."
+  expr: Any_Expr @fdc_oneOf(required: true)
+  """
+  A raw SQL expression, whose SQL data type must match the underlying column.
+
+  The value is any variable-free expression (in particular, cross-references to
+  other columns in the current table are not allowed). Subqueries are not allowed either.
+  https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-DEFAULT
+  """
+  sql: Any_SQL @fdc_oneOf(required: true)
+) on FIELD_DEFINITION
+"""
+Date is a string in the YYYY-MM-DD format representing a local-only date.
+
+See the description for Timestamp for range and limitations.
+
+As a FDC-specific extension, inputs that includes time portions (as specified by
+the Timestamp scalar) are accepted but only the date portion is used. In other
+words, only the part before "T" is used and the rest discarded. This effectively
+truncates it to the local date in the specified time-zone.
+
+Outputs will always be in the canonical YYYY-MM-DD format.
+"""
+scalar Date @specifiedBy(url: "https://scalars.graphql.org/andimarek/local-date.html")
+
+"""
+Timestamp is a RFC 3339 string that represents an exact point in time.
+
+The serialization format follows https://scalars.graphql.org/andimarek/date-time
+except the "Non-optional exact milliseconds" Section. As a FDC-specific
+extension, inputs and outputs may contain 0, 3, 6, or 9 fractional digits.
+
+Specifically, output precision varies by server-side factors such as data source
+support and clients must not rely on an exact number of digits. Clients may
+truncate extra digits as fit, with the caveat that there may be information loss
+if the truncated value is subsequently sent back to the server.
+
+FDC only supports year 1583 to 9999 (inclusive) and uses the ISO-8601 calendar
+system for all date-time calculations. Notably, the expanded year representation
+(+/-YYYYY) is rejected and Year 1582 and before may either be rejected or cause
+undefined behavior.
+"""
+scalar Timestamp @specifiedBy(url: "https://scalars.graphql.org/andimarek/date-time")
+
+"""
+A Common Expression Language (CEL) expression that returns a Timestamp at runtime.
+
+Limitation: Right now, only a few expressions are supported. Those are listed
+using the @fdc_example directive on this scalar.
+"""
+scalar Timestamp_Expr
+  @specifiedBy(url: "https://github.com/google/cel-spec")
+  @fdc_celExpression(returnType: "google.protobuf.Timestamp")
+  @fdc_forbiddenAsVariableType
+  @fdc_forbiddenAsFieldType
+  @fdc_example(value: "request.time", description: "The timestamp when the request is received (with microseconds precision).")
+
+"""
+A Common Expression Language (CEL) expression that returns a Timestamp at runtime,
+which is then truncated to UTC date only. The time-of-day parts are discarded.
+
+Limitation: Right now, only a few expressions are supported. Those are listed
+using the @fdc_example directive on this scalar.
+"""
+scalar Date_Expr
+  @specifiedBy(url: "https://github.com/google/cel-spec")
+  @fdc_celExpression(returnType: "google.protobuf.Timestamp")
+  @fdc_forbiddenAsVariableType
+  @fdc_forbiddenAsFieldType
+  @fdc_example(value: "request.time", description: "The UTC date on which the request is received.")
+
+"Conditions on a Date value"
+input Date_Filter {
+  isNull: Boolean
+  eq: Date @fdc_oneOf(group: "eq")
+  eq_expr: Date_Expr @fdc_oneOf(group: "eq")
+  eq_date: Date_Relative @fdc_oneOf(group: "eq")
+  ne: Date @fdc_oneOf(group: "ne")
+  ne_expr: Date_Expr @fdc_oneOf(group: "ne")
+  ne_date: Date_Relative @fdc_oneOf(group: "ne")
+  in: [Date!]
+  nin: [Date!]
+  gt: Date @fdc_oneOf(group: "gt")
+  gt_expr: Date_Expr @fdc_oneOf(group: "gt")
+  gt_date: Date_Relative @fdc_oneOf(group: "gt")
+  ge: Date @fdc_oneOf(group: "ge")
+  ge_expr: Date_Expr @fdc_oneOf(group: "ge")
+  ge_date: Date_Relative @fdc_oneOf(group: "ge")
+  lt: Date @fdc_oneOf(group: "lt")
+  lt_expr: Date_Expr @fdc_oneOf(group: "lt")
+  lt_date: Date_Relative @fdc_oneOf(group: "lt")
+  le: Date @fdc_oneOf(group: "le")
+  le_expr: Date_Expr @fdc_oneOf(group: "le")
+  le_date: Date_Relative @fdc_oneOf(group: "le")
+}
+
+"Conditions on a Date list"
+input Date_ListFilter {
+  includes: Date @fdc_oneOf(group: "includes")
+  includes_expr: Date_Expr @fdc_oneOf(group: "includes")
+  includes_date: Date_Relative @fdc_oneOf(group: "includes")
+  excludes: Date @fdc_oneOf(group: "excludes")
+  excludes_expr: Date_Expr @fdc_oneOf(group: "excludes")
+  excludes_date: Date_Relative @fdc_oneOf(group: "excludes")
+  includesAll: [Date!]
+  excludesAll: [Date!]
+}
+
+"Conditions on an Timestamp value"
+input Timestamp_Filter {
+  isNull: Boolean
+  eq: Timestamp @fdc_oneOf(group: "eq")
+  eq_expr: Timestamp_Expr @fdc_oneOf(group: "eq")
+  eq_time: Timestamp_Relative @fdc_oneOf(group: "eq")
+  ne: Timestamp @fdc_oneOf(group: "ne")
+  ne_expr: Timestamp_Expr @fdc_oneOf(group: "ne")
+  ne_time: Timestamp_Relative @fdc_oneOf(group: "ne")
+  in: [Timestamp!]
+  nin: [Timestamp!]
+  gt: Timestamp @fdc_oneOf(group: "gt")
+  gt_expr: Timestamp_Expr @fdc_oneOf(group: "gt")
+  gt_time: Timestamp_Relative @fdc_oneOf(group: "gt")
+  ge: Timestamp @fdc_oneOf(group: "ge")
+  ge_expr: Timestamp_Expr @fdc_oneOf(group: "ge")
+  ge_time: Timestamp_Relative @fdc_oneOf(group: "ge")
+  lt: Timestamp @fdc_oneOf(group: "lt")
+  lt_expr: Timestamp_Expr @fdc_oneOf(group: "lt")
+  lt_time: Timestamp_Relative @fdc_oneOf(group: "lt")
+  le: Timestamp @fdc_oneOf(group: "le")
+  le_expr: Timestamp_Expr @fdc_oneOf(group: "le")
+  le_time: Timestamp_Relative @fdc_oneOf(group: "le")
+}
+
+"Conditions on a Timestamp list"
+input Timestamp_ListFilter {
+  includes: Timestamp @fdc_oneOf(group: "includes")
+  includes_expr: Timestamp_Expr @fdc_oneOf(group: "includes")
+  includes_time: Timestamp_Relative @fdc_oneOf(group: "includes")
+  excludes: Timestamp @fdc_oneOf(group: "excludes")
+  excludes_expr: Timestamp_Expr @fdc_oneOf(group: "excludes")
+  excludes_time: Timestamp_Relative @fdc_oneOf(group: "excludes")
+  includesAll: [Timestamp!]
+  excludesAll: [Timestamp!]
+}
+
+"Update input of a Date value"
+input Date_Update {
+  set: Date @fdc_oneOf(group: "set")
+  set_expr: Date_Expr @fdc_oneOf(group: "set")
+  set_date: Date_Relative @fdc_oneOf(group: "set")
+}
+
+"Update input of a Date list value"
+input Date_ListUpdate {
+  set: [Date!]
+  append: [Date!]
+  prepend: [Date!]
+  delete: Int
+  i: Int
+  update: Date
+}
+
+"Update input of a Timestamp value"
+input Timestamp_Update {
+  set: Timestamp @fdc_oneOf(group: "set")
+  set_expr: Timestamp_Expr @fdc_oneOf(group: "set")
+  set_time: Timestamp_Relative @fdc_oneOf(group: "set")
+}
+
+"Update input of a Timestamp list value"
+input Timestamp_ListUpdate {
+  set: [Timestamp!]
+  append: [Timestamp!]
+  prepend: [Timestamp!]
+  delete: Int
+  i: Int
+  update: Timestamp
+}
+
+"A runtime-calculated Timestamp value relative to `now` or `at`."
+input Timestamp_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
+  now: True @fdc_oneOf(group: "from", required: true)
+  at: Timestamp @fdc_oneOf(group: "from", required: true)
+
+  add: Timestamp_Duration
+  sub: Timestamp_Duration
+
+  truncateTo: Timestamp_Interval
+}
+
+input Timestamp_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
+  milliseconds: Int! = 0
+  seconds: Int! = 0
+  minutes: Int! = 0
+  hours: Int! = 0
+  days: Int! = 0
+  weeks: Int! = 0
+  months: Int! = 0
+  years: Int! = 0
+}
+
+enum Timestamp_Interval @fdc_forbiddenAsFieldType {
+  SECOND
+  MINUTE
+  HOUR
+  DAY
+  WEEK
+  MONTH
+  YEAR
+}
+
+"A runtime-calculated Date value relative to `today` or `on`."
+input Date_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
+  today: True @fdc_oneOf(group: "from", required: true)
+  on: Date @fdc_oneOf(group: "from", required: true)
+
+  add: Date_Duration
+  sub: Date_Duration
+
+  truncateTo: Date_Interval
+}
+
+input Date_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
+  days: Int! = 0
+  weeks: Int! = 0
+  months: Int! = 0
+  years: Int! = 0
+}
+
+enum Date_Interval @fdc_forbiddenAsFieldType {
+  WEEK
+  MONTH
+  YEAR
+}
+"Update input of a String value"
+input String_Update {
+  set: String @fdc_oneOf(group: "set")
+  set_expr: String_Expr @fdc_oneOf(group: "set")
+}
+
+"Update input of a String list value"
+input String_ListUpdate {
+  set: [String!]
+  append: [String!]
+  prepend: [String!]
+}
+
+"Update input of a UUID value"
+input UUID_Update {
+  set: UUID @fdc_oneOf(group: "set")
+  set_expr: UUID_Expr @fdc_oneOf(group: "set")
+}
+
+"Update input of an ID list value"
+input UUID_ListUpdate {
+  set: [UUID!]
+  append: [UUID!]
+  prepend: [UUID!]
+}
+
+"Update input of an Int value"
+input Int_Update {
+  set: Int
+  inc: Int
+  dec: Int
+}
+
+"Update input of an Int list value"
+input Int_ListUpdate {
+  set: [Int!]
+  append: [Int!]
+  prepend: [Int!]
+}
+
+"Update input of an Int64 value"
+input Int64_Update {
+  set: Int64
+  inc: Int64
+  dec: Int64
+}
+
+"Update input of an Int64 list value"
+input Int64_ListUpdate {
+  set: [Int64!]
+  append: [Int64!]
+  prepend: [Int64!]
+}
+
+"Update input of a Float value"
+input Float_Update {
+  set: Float
+  inc: Float
+  dec: Float
+}
+
+"Update input of a Float list value"
+input Float_ListUpdate {
+  set: [Float!]
+  append: [Float!]
+  prepend: [Float!]
+}
+
+"Update input of a Boolean value"
+input Boolean_Update {
+  set: Boolean
+}
+
+"Update input of a Boolean list value"
+input Boolean_ListUpdate {
+  set: [Boolean!]
+  append: [Boolean!]
+  prepend: [Boolean!]
+}
+
+"Update input of an Any value"
+input Any_Update {
+  set: Any
+}
+
+"Update input of an Any list value"
+input Any_ListUpdate {
+  set: [Any!]
+  append: [Any!]
+  prepend: [Any!]
+}
+"""
+Vector is an array of single-precision floating-point numbers, serialized
+as a JSON array. All elements must be finite (no NaN, Infinity or -Infinity).
+
+Example: [1.1, 2, 3.3]
+"""
+scalar Vector
+
+"""
+Defines what siliarlity function to use for fetching vectors.
+Details here: https://github.com/pgvector/pgvector?tab=readme-ov-file#vector-functions
+"""
+enum VectorSimilarityMethod {
+  L2
+  COSINE
+  INNER_PRODUCT
+}
+
+"Conditions on an Vector value"
+input Vector_Filter {
+  eq: Vector
+  ne: Vector
+  in: [Vector!]
+  nin: [Vector!]
+  isNull: Boolean
+}
+
+input Vector_ListFilter {
+  "When true, will match if the list includes the supplied vector."
+  includes: Vector
+  excludes: Vector
+  includesAll: [Vector!]
+  excludesAll: [Vector!]
+}
+
+"Update input of an Vector value"
+input Vector_Update {
+  set: Vector @fdc_oneOf(group: "set")
+  set_embed: Vector_Embed @fdc_oneOf(group: "set")
+}
+
+"Update input of a Vector list value"
+input Vector_ListUpdate {
+  set: [Vector]
+  append: [Vector]
+  prepend: [Vector]
+  delete: Int
+  i: Int
+  update: Vector
+}
+
+"""
+Create a vector embedding of text using the given model on Vertex AI.
+
+Example: {text: "Hi there", model: "textembedding-gecko@003"}
+See: https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-text-embeddings
+
+Limitation: In the emulator, if Vertex AI is not configured, a pseudorandom
+vector is generated from text as a fake implementation for testing only.
+"""
+input Vector_Embed @fdc_forbiddenAsVariableType {
+  model: Vector_Embed_Model!
+  text: String!
+}
+
+"""
+A string that specifies a Vertex AI model and version.
+
+It is strongly recommended to specify a stable model version (for example,
+textembedding-gecko@003). The latest version of a model is in Preview and is not
+General Availability (GA). Because the latest version is in Preview, it isn't
+guaranteed to be production ready.
+"""
+scalar Vector_Embed_Model
+  @specifiedBy(url: "https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versioning")
+  @fdc_forbiddenAsVariableType
+  @fdc_forbiddenAsFieldType
+  @fdc_example(value: "textembedding-gecko@003", description: "A stable version of the textembedding-gecko model")
diff --git a/dataconnect/dataconnect/1_movie_insert.gql b/dataconnect/dataconnect/1_movie_insert.gql
new file mode 100644
index 000000000..1a264ebbc
--- /dev/null
+++ b/dataconnect/dataconnect/1_movie_insert.gql
@@ -0,0 +1,241 @@
+mutation {
+  movie1: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440000",
+    title: "Inception",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Finception.jpg?alt=media&token=0a2950ee-0df7-4909-a5fd-e9f44dd803d6",
+    releaseYear: 2010,
+    genre: "sci-fi",
+    rating: 8.8,
+    description: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move.",
+    tags: ["thriller", "action"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move."}
+  })
+  
+  movie2: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440001",
+    title: "The Matrix",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_matrix.jpg?alt=media&token=9d9a952e-6441-420a-8479-6a58d62655f8",
+    releaseYear: 1999,
+    genre: "action",
+    rating: 8.7,
+    description: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny.",
+    tags: ["sci-fi", "adventure"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny."}
+  })
+  
+  movie3: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440002",
+    title: "John Wick 4",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fjohn_wick_4.jpg?alt=media&token=98c60306-fbd9-4718-ac7a-2c6cde8706d8",
+    releaseYear: 2023,
+    genre: "action",
+    rating: 8.1,
+    description: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances.",
+    tags: ["action", "thriller"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances."}
+  })
+
+  movie4: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440003",
+    title: "The Dark Knight",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_dark_knight.jpg?alt=media&token=7ee322e9-3b27-4952-b4a9-e445a15412de",
+    releaseYear: 2008,
+    genre: "action",
+    rating: 9.0,
+    description: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice.",
+    tags: ["action", "drama"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice."}
+  })
+
+  movie5: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440004",
+    title: "Fight Club",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Ffight_club.jpg?alt=media&token=1dcfbea5-feb3-4345-92bc-7551c671cb49",
+    releaseYear: 1999,
+    genre: "drama",
+    rating: 8.8,
+    description: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity.",
+    tags: ["drama", "thriller"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity."}
+  })
+
+  movie6: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440005",
+    title: "Pulp Fiction",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fpulp_fiction.jpg?alt=media&token=d9ccbe88-c19b-4aab-bb89-016a7cbd4051",
+    releaseYear: 1994,
+    genre: "crime",
+    rating: 8.9,
+    description: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references.",
+    tags: ["crime", "drama"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references."}
+  })
+
+  movie7: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440006",
+    title: "The Lord of the Rings: The Fellowship of the Ring",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Flotr_fellowship.jpg?alt=media&token=f98d137b-f37f-43e6-86f2-7f49e946e133",
+    releaseYear: 2001,
+    genre: "fantasy",
+    rating: 8.8,
+    description: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond.",
+    tags: ["fantasy", "adventure"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond."}
+  })
+
+  movie8: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440007",
+    title: "The Shawshank Redemption",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_shawshanks_redemption.jpg?alt=media&token=8fae5b0c-8797-4607-9c2b-3ecc09b48a8e",
+    releaseYear: 1994,
+    genre: "drama",
+    rating: 9.3,
+    description: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman).",
+    tags: ["drama", "crime"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman)."}
+    })
+
+  movie9: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440008",
+    title: "Forrest Gump",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fforrest_gump.jpeg?alt=media&token=decc25fa-d88e-49cc-a2ca-fc9a77e3a651",
+    releaseYear: 1994,
+    genre: "drama",
+    rating: 8.8,
+    description: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright).",
+    tags: ["drama", "romance"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright)."}
+  })
+
+  movie10: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440009",
+    title: "The Godfather",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_godfather.jpg?alt=media&token=52cc0cbd-0fc7-4afa-a44e-f44ab4880079",
+    releaseYear: 1972,
+    genre: "crime",
+    rating: 9.2,
+    description: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal.",
+    tags: ["crime", "drama"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal."}
+  })
+
+  movie11: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440010",
+    title: "The Silence of the Lambs",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_silence_of_the_lambs.jpg?alt=media&token=064778c8-8b0e-4412-8235-511082613118",
+    releaseYear: 1991,
+    genre: "thriller",
+    rating: 8.6,
+    description: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer.",
+    tags: ["thriller", "crime"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer."}
+  })
+
+  movie12: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440011",
+    title: "Saving Private Ryan",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fsaving_private_ryan.jpg?alt=media&token=54b5ade0-e41d-4f53-a39d-56fd5be270f9",
+    releaseYear: 1998,
+    genre: "war",
+    rating: 8.6,
+    description: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war.",
+    tags: ["war", "drama"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war."}
+  })
+ 
+  movie13: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440012",
+    title: "The Avengers",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_avengers.jpg?alt=media&token=54cd8f43-cf29-4e86-9f78-a4c43c9ac79c",
+    releaseYear: 2012,
+    genre: "action",
+    rating: 8.0,
+    description: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast.",
+    tags: ["action", "sci-fi"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast."}
+  })
+
+  movie14: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440013",
+    title: "Gladiator",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fgladiator.jpg?alt=media&token=aa112d9f-de39-4b5e-80c4-621c7af842bd",
+    releaseYear: 2000,
+    genre: "action",
+    rating: 8.5,
+    description: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance.",
+    tags: ["action", "drama"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance."}
+  })
+
+  movie15: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440014",
+    title: "Titanic",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Ftitanic.png?alt=media&token=5f594626-19d8-4043-9d09-81104e128ed2",
+    releaseYear: 1997,
+    genre: "romance",
+    rating: 7.8,
+    description: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals.",
+    tags: ["romance", "drama"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals."}
+  })
+
+  movie16: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440015",
+    title: "Avatar",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Favatar.jpg?alt=media&token=2d858616-4033-408a-aea0-9add07a67c88",
+    releaseYear: 2009,
+    genre: "sci-fi",
+    rating: 7.8,
+    description: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience.",
+    tags: ["sci-fi", "adventure"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience."}
+  })
+
+  movie17: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440016",
+    title: "Jurassic Park",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fjurassic_park.jpg?alt=media&token=040b46b8-c974-4825-85e5-2652bc375ed7",
+    releaseYear: 1993,
+    genre: "adventure",
+    rating: 8.1,
+    description: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures.",
+    tags: ["adventure", "sci-fi"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures."}
+  })
+
+  movie18: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440017",
+    title: "The Lion King",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_lion_king.jpg?alt=media&token=4778e0ac-96e7-44fd-9422-423d5aad353f",
+    releaseYear: 1994,
+    genre: "animation",
+    rating: 8.5,
+    description: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption.",
+    tags: ["animation", "drama"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption."}
+  })
+
+  movie19: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440018",
+    title: "Star Wars: Episode IV - A New Hope",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fstar_wars_4.jpg?alt=media&token=cad4cb98-89ce-4c8a-a735-d7cdaf884b26",
+    releaseYear: 1977,
+    genre: "sci-fi",
+    rating: 8.6,
+    description: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters.",
+    tags: ["sci-fi", "adventure"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters."}
+  })
+
+  movie20: movie_insert(data: {
+    id: "550e8400-e29b-41d4-a716-446655440019",
+    title: "Blade Runner",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fblade_runner.jpg?alt=media&token=4c7e7c9d-c9c7-4cef-9eb7-4302b2610905",
+    releaseYear: 1982,
+    genre: "sci-fi",
+    rating: 8.1,
+    description: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity.",
+    tags: ["sci-fi", "thriller"],
+    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity."}
+  })
+}
diff --git a/dataconnect/dataconnect/2_actor_insert.gql b/dataconnect/dataconnect/2_actor_insert.gql
new file mode 100644
index 000000000..a4a0c1c49
--- /dev/null
+++ b/dataconnect/dataconnect/2_actor_insert.gql
@@ -0,0 +1,141 @@
+mutation {
+  actor1: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174000",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/46/Leonardo_Dicaprio_Cannes_2019.jpg/440px-Leonardo_Dicaprio_Cannes_2019.jpg",
+    name: "Leonardo DiCaprio",
+    biography: "Leonardo DiCaprio is an American actor and producer. He has received numerous awards, including an Academy Award and three Golden Globe Awards. DiCaprio is known for his roles in Titanic, Inception, and The Revenant."
+  })
+  
+  actor2: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174001",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Reuni%C3%A3o_com_o_ator_norte-americano_Keanu_Reeves_%2846806576944%29_%28cropped%29.jpg/440px-Reuni%C3%A3o_com_o_ator_norte-americano_Keanu_Reeves_%2846806576944%29_%28cropped%29.jpg",
+    name: "Keanu Reeves",
+    biography: "Keanu Reeves is a Canadian actor known for his roles in The Matrix and John Wick series. He has gained acclaim for his versatility and has also directed and produced several films."
+  })
+  
+  actor3: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174002",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Matthew_McConaughey_2019_%2848648344772%29.jpg/440px-Matthew_McConaughey_2019_%2848648344772%29.jpg",
+    name: "Matthew McConaughey",
+    biography: "Matthew McConaughey is an American actor and producer. He gained fame with his breakout role in Dazed and Confused and has won an Academy Award for his performance in Dallas Buyers Club."
+  })
+
+  actor4: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174003",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Christian_Bale-7837.jpg/440px-Christian_Bale-7837.jpg",
+    name: "Christian Bale",
+    biography: "Christian Bale is an English actor known for his versatility and physical transformations for roles. He has starred in The Dark Knight Trilogy and won an Academy Award for The Fighter."
+  })
+
+  actor5: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174004",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Brad_Pitt_2019_by_Glenn_Francis.jpg/440px-Brad_Pitt_2019_by_Glenn_Francis.jpg",
+    name: "Brad Pitt",
+    biography: "Brad Pitt is an American actor and producer. He has won two Academy Awards and is known for his roles in Fight Club, Ocean's Eleven, and Once Upon a Time in Hollywood."
+  })
+
+  actor6: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174005",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/SamuelLJackson.jpg/440px-SamuelLJackson.jpg",
+    name: "Samuel L. Jackson",
+    biography: "Samuel L. Jackson is an American actor and producer. He is one of the most widely recognized actors of his generation, known for his roles in Pulp Fiction, the Marvel Cinematic Universe, and Jurassic Park."
+  })
+
+  actor7: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174006",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/6/64/Viggo_Mortensen_B_%282020%29.jpg",
+    name: "Viggo Mortensen",
+    biography: "Viggo Mortensen is an American actor, author, and musician. He is best known for his role as Aragorn in The Lord of the Rings trilogy and has been nominated for three Academy Awards."
+  })
+
+  actor8: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174007",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Morgan_Freeman_at_The_Pentagon_on_2_August_2023_-_230802-D-PM193-3363_%28cropped%29.jpg/440px-Morgan_Freeman_at_The_Pentagon_on_2_August_2023_-_230802-D-PM193-3363_%28cropped%29.jpg",
+    name: "Morgan Freeman",
+    biography: "Morgan Freeman is an American actor, director, and narrator. He is known for his distinctive voice and has won an Academy Award for his role in Million Dollar Baby."
+  })
+
+  actor9: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174008",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Tom_Hanks_TIFF_2019.jpg/440px-Tom_Hanks_TIFF_2019.jpg",
+    name: "Tom Hanks",
+    biography: "Tom Hanks is an American actor and filmmaker. He is known for his roles in Forrest Gump, Saving Private Ryan, and Toy Story, and has won two Academy Awards for Best Actor."
+  })
+
+  actor10: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174009",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Al_Pacino_2016_%2830401544240%29.jpg/440px-Al_Pacino_2016_%2830401544240%29.jpg",
+    name: "Al Pacino",
+    biography: "Al Pacino is an American actor and filmmaker. He has won an Academy Award, two Tony Awards, and two Primetime Emmy Awards. He is known for his roles in The Godfather series, Scarface, and Scent of a Woman."
+  })
+
+  actor11: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174010",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/3/3f/Jodie_Foster_C%C3%A9sars_2011_2_%28cropped%29.jpg",
+    name: "Jodie Foster",
+    biography: "Jodie Foster is an American actress and director. She has won two Academy Awards for Best Actress for her roles in The Accused and The Silence of the Lambs."
+  })
+
+  actor12: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174011",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Tom_Cruise_by_Gage_Skidmore_2.jpg/440px-Tom_Cruise_by_Gage_Skidmore_2.jpg",
+    name: "Tom Cruise",
+    biography: "Tom Cruise is an American actor and producer. He is one of the highest-paid actors in the world and is known for his roles in Top Gun, the Mission: Impossible series, and Jerry Maguire."
+  })
+
+  actor13: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174012",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Robert_Downey_Jr_2014_Comic_Con_%28cropped%29.jpg/440px-Robert_Downey_Jr_2014_Comic_Con_%28cropped%29.jpg",
+    name: "Robert Downey Jr.",
+    biography: "Robert Downey Jr. is an American actor and producer. He is known for his roles in Iron Man, Sherlock Holmes, and Chaplin, and has been a major figure in the Marvel Cinematic Universe."
+  })
+
+  actor14: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174013",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Russell_Crowe_%2833994020424%29.jpg/440px-Russell_Crowe_%2833994020424%29.jpg",
+    name: "Russell Crowe",
+    biography: "Russell Crowe is an Australian actor, film producer, and musician. He gained international fame for his role in Gladiator, for which he won the Academy Award for Best Actor."
+  })
+
+  actor15: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174014",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Kate_Winslet_at_the_2017_Toronto_International_Film_Festival_%28cropped%29.jpg/440px-Kate_Winslet_at_the_2017_Toronto_International_Film_Festival_%28cropped%29.jpg",
+    name: "Kate Winslet",
+    biography: "Kate Winslet is an English actress known for her roles in Titanic, The Reader, and Eternal Sunshine of the Spotless Mind. She has won numerous awards, including an Academy Award and an Emmy."
+  })
+
+  actor16: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174015",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Sigourney_Weaver_by_Gage_Skidmore_4.jpg/862px-Sigourney_Weaver_by_Gage_Skidmore_4.jpg",
+    name: "Sigourney Weaver",
+    biography: "Sigourney Weaver is an American actress best known for her roles in the Alien franchise, Ghostbusters, and Avatar. She has been nominated for three Academy Awards and has won two Golden Globe Awards."
+  })
+
+  actor17: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174016",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Jeff_Goldblum_by_Gage_Skidmore_3.jpg/440px-Jeff_Goldblum_by_Gage_Skidmore_3.jpg",
+    name: "Jeff Goldblum",
+    biography: "Jeff Goldblum is an American actor and musician known for his roles in Jurassic Park, Independence Day, and The Fly. His unique delivery and eccentric characters have made him a cult icon."
+  })
+
+  actor18: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174017",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/James_Earl_Jones_%288516667383%29.jpg/440px-James_Earl_Jones_%288516667383%29.jpg",
+    name: "James Earl Jones",
+    biography: "James Earl Jones is an American actor known for his deep resonant voice, which has been featured in roles such as Darth Vader in Star Wars and Mufasa in The Lion King. He has won multiple awards, including a Tony, Emmy, and Grammy."
+  })
+
+  actor19: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174018",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Harrison_Ford_by_Gage_Skidmore_3.jpg/440px-Harrison_Ford_by_Gage_Skidmore_3.jpg",
+    name: "Harrison Ford",
+    biography: "Harrison Ford is an American actor known for his iconic roles as Han Solo in Star Wars and Indiana Jones in the Indiana Jones series. He has been nominated for an Academy Award and has received numerous other accolades."
+  })
+
+  actor20: actor_insert(data: {
+    id: "123e4567-e89b-12d3-a456-426614174019",
+    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Arnold_Schwarzenegger_by_Gage_Skidmore_4.jpg/440px-Arnold_Schwarzenegger_by_Gage_Skidmore_4.jpg",
+    name: "Arnold Schwarzenegger",
+    biography: "Arnold Schwarzenegger is an Austrian-American actor, businessman, and former politician. He is best known for his roles in The Terminator series and Total Recall, and for serving as the 38th Governor of California."
+  })
+}
diff --git a/dataconnect/dataconnect/3_movie_actor_insert.gql b/dataconnect/dataconnect/3_movie_actor_insert.gql
new file mode 100644
index 000000000..b8a270541
--- /dev/null
+++ b/dataconnect/dataconnect/3_movie_actor_insert.gql
@@ -0,0 +1,283 @@
+mutation {
+  metadata1: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440000",
+    director: "Christopher Nolan"
+  })
+  
+  metadata2: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440001",
+    director: "Lana Wachowski, Lilly Wachowski"
+  })
+  
+  metadata3: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440002",
+    director: "Chad Stahelski"
+  })
+
+  metadata4: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440003",
+    director: "Christopher Nolan"
+  })
+
+  metadata5: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440004",
+    director: "David Fincher"
+  })
+
+  metadata6: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440005",
+    director: "Quentin Tarantino"
+  })
+
+  metadata7: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440006",
+    director: "Peter Jackson"
+  })
+
+  metadata8: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440007",
+    director: "Frank Darabont"
+  })
+
+  metadata9: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440008",
+    director: "Robert Zemeckis"
+  })
+
+  metadata10: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440009",
+    director: "Francis Ford Coppola"
+  })
+
+  metadata11: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440010",
+    director: "Jonathan Demme"
+  })
+
+  metadata12: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440011",
+    director: "Steven Spielberg"
+  })
+
+  metadata13: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440012",
+    director: "Joss Whedon"
+  })
+
+  metadata14: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440013",
+    director: "Ridley Scott"
+  })
+
+  metadata15: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440014",
+    director: "James Cameron"
+  })
+
+  metadata16: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440015",
+    director: "James Cameron"
+  })
+
+  metadata17: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440016",
+    director: "Steven Spielberg"
+  })
+
+  metadata18: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440017",
+    director: "Roger Allers, Rob Minkoff"
+  })
+
+  metadata19: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440018",
+    director: "George Lucas"
+  })
+
+  metadata20: movieMetadata_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440019",
+    director: "Ridley Scott"
+  })
+
+  movieActor1: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440000",
+    actorId: "123e4567-e89b-12d3-a456-426614174000",
+    role: "main"
+  })
+  
+  movieActor2: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440001",
+    actorId: "123e4567-e89b-12d3-a456-426614174001",
+    role: "main"
+  })
+  
+  movieActor3: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440002",
+    actorId: "123e4567-e89b-12d3-a456-426614174001",
+    role: "main"
+  })
+
+  movieActor4: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440003",
+    actorId: "123e4567-e89b-12d3-a456-426614174003",
+    role: "main"
+  })
+
+  movieActor5: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440004",
+    actorId: "123e4567-e89b-12d3-a456-426614174004",
+    role: "main"
+  })
+
+  movieActor6: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440005",
+    actorId: "123e4567-e89b-12d3-a456-426614174005",
+    role: "main"
+  })
+
+  movieActor7: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440006",
+    actorId: "123e4567-e89b-12d3-a456-426614174006",
+    role: "main"
+  })
+
+  movieActor8: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440007",
+    actorId: "123e4567-e89b-12d3-a456-426614174007",
+    role: "main"
+  })
+
+  movieActor9: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440008",
+    actorId: "123e4567-e89b-12d3-a456-426614174008",
+    role: "main"
+  })
+
+  movieActor10: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440009",
+    actorId: "123e4567-e89b-12d3-a456-426614174009",
+    role: "main"
+  })
+
+  movieActor11: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440010",
+    actorId: "123e4567-e89b-12d3-a456-426614174010",
+    role: "main"
+  })
+
+  movieActor12: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440011",
+    actorId: "123e4567-e89b-12d3-a456-426614174011",
+    role: "main"
+  })
+
+  movieActor13: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440012",
+    actorId: "123e4567-e89b-12d3-a456-426614174012",
+    role: "main"
+  })
+
+  movieActor14: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440013",
+    actorId: "123e4567-e89b-12d3-a456-426614174013",
+    role: "main"
+  })
+
+  movieActor15: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440014",
+    actorId: "123e4567-e89b-12d3-a456-426614174014",
+    role: "main"
+  })
+
+  movieActor16: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440015",
+    actorId: "123e4567-e89b-12d3-a456-426614174015",
+    role: "main"
+  })
+
+  movieActor17: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440016",
+    actorId: "123e4567-e89b-12d3-a456-426614174016",
+    role: "main"
+  })
+
+  movieActor18: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440017",
+    actorId: "123e4567-e89b-12d3-a456-426614174017",
+    role: "main"
+  })
+
+  movieActor19: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440018",
+    actorId: "123e4567-e89b-12d3-a456-426614174018",
+    role: "main"
+  })
+
+  movieActor20: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440019",
+    actorId: "123e4567-e89b-12d3-a456-426614174019",
+    role: "main"
+  })
+
+  # Adding supporting actors
+  movieActor21: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440000",
+    actorId: "123e4567-e89b-12d3-a456-426614174001",
+    role: "supporting"
+  })
+  
+  movieActor22: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440001",
+    actorId: "123e4567-e89b-12d3-a456-426614174002",
+    role: "supporting"
+  })
+  
+  movieActor23: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440002",
+    actorId: "123e4567-e89b-12d3-a456-426614174003",
+    role: "supporting"
+  })
+
+  movieActor24: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440003",
+    actorId: "123e4567-e89b-12d3-a456-426614174004",
+    role: "supporting"
+  })
+
+  movieActor25: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440004",
+    actorId: "123e4567-e89b-12d3-a456-426614174005",
+    role: "supporting"
+  })
+
+  movieActor26: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440005",
+    actorId: "123e4567-e89b-12d3-a456-426614174006",
+    role: "supporting"
+  })
+
+  movieActor27: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440006",
+    actorId: "123e4567-e89b-12d3-a456-426614174007",
+    role: "supporting"
+  })
+
+  movieActor28: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440007",
+    actorId: "123e4567-e89b-12d3-a456-426614174008",
+    role: "supporting"
+  })
+
+  movieActor29: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440008",
+    actorId: "123e4567-e89b-12d3-a456-426614174009",
+    role: "supporting"
+  })
+
+  movieActor30: movieActor_insert(data: {
+    movieId: "550e8400-e29b-41d4-a716-446655440009",
+    actorId: "123e4567-e89b-12d3-a456-426614174010",
+    role: "supporting"
+  })
+
+}
diff --git a/dataconnect/dataconnect/4_user_favorites_review_insert.gql b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
new file mode 100644
index 000000000..70bf8fa23
--- /dev/null
+++ b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
@@ -0,0 +1,184 @@
+mutation {
+  user1: user_insert(data: {
+    id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    username: "cynthia_w"
+  })
+  
+  user2: user_insert(data: {
+    id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    username: "momo_h"
+  })
+  
+  user3: user_insert(data: {
+    id: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    username: "siyi_w"
+  })
+
+  review1: review_insert(data: {
+    id: "345e4567-e89b-12d3-a456-426614174000",
+
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    movieId: "550e8400-e29b-41d4-a716-446655440000",
+    rating: 5,
+    reviewText: "An incredible movie with a mind-blowing plot!",
+    reviewDate_date: { today: true }
+  })
+  
+  review2: review_insert(data: {
+    id: "345e4567-e89b-12d3-a456-426614174001",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440001",
+    rating: 5,
+    reviewText: "A revolutionary film that changed cinema forever.",
+    reviewDate_date: { today: true }
+  })
+  
+  review3: review_insert(data: {
+    id: "345e4567-e89b-12d3-a456-426614174002",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440002",
+    rating: 5,
+    reviewText: "A visually stunning and emotionally impactful movie.",
+    reviewDate_date: { today: true }
+  })
+
+  review4: review_insert(data: {
+    id: "345e4567-e89b-12d3-a456-426614174003",
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440003",
+    rating: 4,
+    reviewText: "A fantastic superhero film with great performances.",
+    reviewDate_date: { today: true }
+  })
+
+  review5: review_insert(data: {
+    id: "345e4567-e89b-12d3-a456-426614174004",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440004",
+    rating: 5,
+    reviewText: "An amazing film that keeps you on the edge of your seat.",
+    reviewDate_date: { today: true }
+  })
+
+  review6: review_insert(data: {
+    id: "345e4567-e89b-12d3-a456-426614174005",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440005",
+    rating: 5,
+    reviewText: "An absolute classic with unforgettable dialogue.",
+    reviewDate_date: { today: true }
+  })
+
+  favoriteMovie1: favoriteMovie_insert(data: {
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440000"
+  })
+  
+  favoriteMovie2: favoriteMovie_insert(data: {
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440001"
+  })
+  
+  favoriteMovie3: favoriteMovie_insert(data: {
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440002"
+  })
+
+  favoriteMovie4: favoriteMovie_insert(data: {
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440003"
+  })
+
+  favoriteMovie5: favoriteMovie_insert(data: {
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440004"
+  })
+
+  favoriteMovie6: favoriteMovie_insert(data: {
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440005"
+  })
+
+  favoriteActor1: favoriteActor_insert(data: {
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+
+    actorId: "123e4567-e89b-12d3-a456-426614174000"
+  })
+  
+  favoriteActor2: favoriteActor_insert(data: {
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+
+    actorId: "123e4567-e89b-12d3-a456-426614174001"
+  })
+  
+  favoriteActor3: favoriteActor_insert(data: {
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+
+    actorId: "123e4567-e89b-12d3-a456-426614174002"
+  })
+
+  favoriteActor4: favoriteActor_insert(data: {
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+
+    actorId: "123e4567-e89b-12d3-a456-426614174003"
+  })
+
+  favoriteActor5: favoriteActor_insert(data: {
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+
+    actorId: "123e4567-e89b-12d3-a456-426614174004"
+  })
+
+  favoriteActor6: favoriteActor_insert(data: {
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+
+    actorId: "123e4567-e89b-12d3-a456-426614174005"
+  })
+
+  watchedMovie1: watchedMovie_insert(data: {
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440000"
+  })
+  
+  watchedMovie2: watchedMovie_insert(data: {
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440001"
+  })
+  
+  watchedMovie3: watchedMovie_insert(data: {
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440002"
+  })
+
+  watchedMovie4: watchedMovie_insert(data: {
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440003"
+  })
+
+  watchedMovie5: watchedMovie_insert(data: {
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440004"
+  })
+
+  watchedMovie6: watchedMovie_insert(data: {
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+
+    movieId: "550e8400-e29b-41d4-a716-446655440005"
+  })
+}
diff --git a/dataconnect/dataconnect/connector/connector.yaml b/dataconnect/dataconnect/connector/connector.yaml
new file mode 100644
index 000000000..66d17e5e5
--- /dev/null
+++ b/dataconnect/dataconnect/connector/connector.yaml
@@ -0,0 +1,14 @@
+connectorId: movie-connector
+# Required. Accepted values are either "PUBLIC" or "ADMIN" (only "PUBLIC" for gated private
+# preview). If "ADMIN", the connector in this directory is an AdminConnector and its operations
+# are gated by IAM.
+authMode: PUBLIC
+generate:
+  javascriptSdk:
+    # Create a custom package name for your generated SDK
+    package: "@movie/sdk"
+    # Tells Data Connect where to store the generated SDK code, this should be in the same
+    # directory as your app code
+    outputDir: "../../movie/lib/dataconnect-sdk"
+    # This property tells Data Connect what directory to install the generated SDK to
+    # packageJsonDir: "../../movie/lib/dataconnect-sdk"
diff --git a/dataconnect/dataconnect/connector/mutations.gql b/dataconnect/dataconnect/connector/mutations.gql
new file mode 100644
index 000000000..57a6920ef
--- /dev/null
+++ b/dataconnect/dataconnect/connector/mutations.gql
@@ -0,0 +1,113 @@
+# Create a movie based on user input
+mutation createMovie(
+  $title: String!
+  $releaseYear: Int!
+  $genre: String!
+  $rating: Float
+  $description: String
+  $imageUrl: String!
+  $tags: [String!] = []
+) {
+  movie_insert(
+    data: {
+      title: $title
+      releaseYear: $releaseYear
+      genre: $genre
+      rating: $rating
+      description: $description
+      imageUrl: $imageUrl
+      tags: $tags
+    }
+  )
+}
+
+# Update movie information based on the provided ID
+mutation updateMovie(
+  $id: UUID!
+  $title: String
+  $releaseYear: Int
+  $genre: String
+  $rating: Float
+  $description: String
+  $imageUrl: String
+  $tags: [String!] = []
+) {
+  movie_update(
+    id: $id
+    data: {
+      title: $title
+      releaseYear: $releaseYear
+      genre: $genre
+      rating: $rating
+      description: $description
+      imageUrl: $imageUrl
+      tags: $tags
+    }
+  )
+}
+
+# Delete a movie by its ID
+mutation deleteMovie($id: UUID!) {
+  movie_delete(id: $id)
+}
+
+# Delete movies with a rating lower than the specified minimum rating
+mutation deleteUnpopularMovies($minRating: Float!) {
+  movie_deleteMany(where: { rating: { le: $minRating } })
+}
+
+# Add a movie to the user's watched list
+mutation addWatchedMovie($movieId: UUID!) @auth(level: USER) {
+  watchedMovie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
+}
+
+# Remove a movie from the user's watched list
+mutation deleteWatchedMovie($userId: String!, $movieId: UUID!) @auth(level: USER) {
+  watchedMovie_delete(key: { userId: $userId, movieId: $movieId })
+}
+
+# Add a movie to the user's favorites list
+mutation addFavoritedMovie($movieId: UUID!) @auth(level: USER) {
+  favoriteMovie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
+}
+
+# Remove a movie from the user's favorites list
+mutation deleteFavoritedMovie($userId: String!, $movieId: UUID!) @auth(level: USER) {
+  favoriteMovie_delete(key: { userId: $userId, movieId: $movieId })
+}
+
+# Add an actor to the user's favorites list
+mutation addFavoritedActor($actorId: UUID!) @auth(level: USER) {
+  favoriteActor_upsert(data: { userId_expr: "auth.uid", actorId: $actorId })
+}
+
+# Remove an actor from the user's favorites list
+mutation deleteFavoriteActor($userId: String!, $actorId: UUID!) @auth(level: USER) {
+  favoriteActor_delete(key: { userId: $userId, actorId: $actorId })
+}
+
+# Add a review for a movie
+mutation addReview($movieId: UUID!, $rating: Int!, $reviewText: String!) @auth(level: USER) {
+  review_upsert(
+    data: {
+      userId_expr: "auth.uid"
+      movieId: $movieId
+      rating: $rating
+      reviewText: $reviewText
+      reviewDate_date: { today: true }
+    }
+  )
+}
+
+# Delete a user's review for a movie
+mutation deleteReview($movieId: UUID!, $userId: String!) @auth(level: USER) {
+  review_delete(key: { userId: $userId, movieId: $movieId })
+}
+
+# Upsert (update or insert) a user based on their username
+mutation upsertUser($username: String!) @auth(level: USER) {
+  user_upsert(data: {
+    id_expr: "auth.uid",
+    username: $username
+  })
+}
diff --git a/dataconnect/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql
new file mode 100644
index 000000000..f191debfc
--- /dev/null
+++ b/dataconnect/dataconnect/connector/queries.gql
@@ -0,0 +1,565 @@
+# List subset of fields for movies
+query ListMovies @auth(level: PUBLIC) {
+  movies {
+    id
+    title
+    imageUrl
+    releaseYear
+    genre
+    rating
+    tags
+  }
+}
+
+# List subset of fields for users
+query ListUsers @auth(level: PUBLIC) {
+  users {
+    id
+    username
+    favoriteActors_on_user {
+      actor {
+        id
+        name
+        imageUrl
+      }
+    }
+    favoriteMovies_on_user {
+      movie {
+        id
+        title
+        genre
+        imageUrl
+        tags
+      }
+    }
+    reviews_on_user {
+      id
+      rating
+      reviewText
+      reviewDate
+      movie {
+        id
+        title
+      }
+    }
+    watchedMovies_on_user {
+      movie {
+        id
+        title
+        genre
+        imageUrl
+      }
+    }
+  }
+}
+
+# List movies of a certain genre
+query ListMoviesByGenre($genre: String!) @auth(level: PUBLIC) {
+  mostPopular: movies(
+    where: { genre: { eq: $genre } }
+    orderBy: { rating: DESC }
+  ) {
+    id
+    title
+    imageUrl
+    rating
+    tags
+  }
+  mostRecent: movies(
+    where: { genre: { eq: $genre } }
+    orderBy: { releaseYear: DESC }
+  ) {
+    id
+    title
+    imageUrl
+    rating
+    tags
+  }
+}
+
+# List movies by the order of release
+query ListMoviesByReleaseYear @auth(level: PUBLIC) {
+  movies(orderBy: [{ releaseYear: DESC }]) {
+    id
+    title
+    imageUrl
+  }
+}
+
+# Get movie by id
+query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
+  movie(id: $id) {
+    id
+    title
+    imageUrl
+    releaseYear
+    genre
+    rating
+    description
+    tags
+    metadata: movieMetadatas_on_movie {
+      director
+    }
+    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
+      id
+      name
+      imageUrl
+    }
+    supportingActors: actors_via_MovieActor(
+      where: { role: { eq: "supporting" } }
+    ) {
+      id
+      name
+      imageUrl
+    }
+    sequelTo {
+      id
+      title
+      imageUrl
+    }
+    reviews: reviews_on_movie {
+      id
+      reviewText
+      reviewDate
+      rating
+      user {
+        id
+        username
+      }
+    }
+  }
+}
+
+# Get actor by id
+query GetActorById($id: UUID!) @auth(level: PUBLIC) {
+  actor(id: $id) {
+    id
+    name
+    imageUrl
+    biography
+    mainActors: movies_via_MovieActor(where: { role: { eq: "main" } }) {
+      id
+      title
+      genre
+      tags
+      imageUrl
+    }
+    supportingActors: movies_via_MovieActor(
+      where: { role: { eq: "supporting" } }
+    ) {
+      id
+      title
+      genre
+      tags
+      imageUrl
+    }
+  }
+}
+
+# User movie preferences
+query UserMoviePreferences($username: String!) @auth(level: USER) {
+  users(where: { username: { eq: $username } }) {
+    likedMovies: movies_via_Review(where: { rating: { ge: 4 } }) {
+      title
+      imageUrl
+      genre
+      description
+    }
+    dislikedMovies: movies_via_Review(where: { rating: { le: 2 } }) {
+      title
+      imageUrl
+      genre
+      description
+    }
+  }
+}
+
+# Get movie metadata
+query GetMovieMetadata($id: UUID!) @auth(level: PUBLIC) {
+  movie(id: $id) {
+    movieMetadatas_on_movie {
+      director
+    }
+  }
+}
+
+# Get movie cast and actor roles
+query GetMovieCast($movieId: UUID!, $actorId: UUID!) @auth(level: PUBLIC) {
+  movie(id: $movieId) {
+    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
+      id
+      name
+      imageUrl
+    }
+    supportingActors: actors_via_MovieActor(
+      where: { role: { eq: "supporting" } }
+    ) {
+      id
+      name
+      imageUrl
+    }
+  }
+  actor(id: $actorId) {
+    mainRoles: movies_via_MovieActor(where: { role: { eq: "main" } }) {
+      id
+      title
+      imageUrl
+    }
+    supportingRoles: movies_via_MovieActor(
+      where: { role: { eq: "supporting" } }
+    ) {
+      id
+      title
+      imageUrl
+    }
+  }
+}
+
+# List movies by partial title match
+query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
+  movies(where: { title: { contains: $input } }) {
+    id
+    title
+    genre
+    rating
+    imageUrl
+  }
+}
+
+# Fetch a single movie using key scalars (same as get movie by id)
+query MovieByKey($key: Movie_Key!) @auth(level: PUBLIC) {
+  movie(key: $key) {
+    title
+    imageUrl
+  }
+}
+
+# Fetch movies by title
+query MovieByTitle($title: String!) @auth(level: PUBLIC) {
+  movies(where: { title: { eq: $title } }) {
+    id
+    title
+    imageUrl
+    genre
+    rating
+  }
+}
+
+# Fetch top-rated movies by genre
+query MovieByTopRating($genre: String) @auth(level: PUBLIC) {
+  mostPopular: movies(
+    where: { genre: { eq: $genre } }
+    orderBy: { rating: DESC }
+  ) {
+    id
+    title
+    imageUrl
+    rating
+    tags
+  }
+}
+
+# List movies by tag
+query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
+  movies(where: { tags: { includes: $tag } }) {
+    id
+    title
+    imageUrl
+    genre
+    rating
+  }
+}
+
+# List top 10 movies
+query MoviesTop10 @auth(level: PUBLIC) {
+  movies(orderBy: [{ rating: DESC }], limit: 10) {
+    id
+    title
+    imageUrl
+    rating
+    genre
+    tags
+    metadata: movieMetadatas_on_movie {
+      director
+    }
+    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
+      id
+      name
+      imageUrl
+    }
+    supportingActors: actors_via_MovieActor(where: { role: { eq: "supporting" } }) {
+      id
+      name
+      imageUrl
+    }
+  }
+}
+
+# List movies by release year range
+query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
+  movies(
+    where: { releaseYear: { le: $max, ge: $min } }
+    orderBy: [{ releaseYear: ASC }]
+  ) {
+    id
+    rating
+    title
+    imageUrl
+  }
+}
+
+# List recently released movies
+query MoviesRecentlyReleased @auth(level: PUBLIC) {
+  movies(where: { releaseYear: { ge: 2010 } }) {
+    id
+    title
+    rating
+    imageUrl
+    genre
+    tags
+  }
+}
+
+# List movies with filtering on fields
+query ListMoviesFilter($genre: String, $limit: Int) @auth(level: PUBLIC) {
+  movies(where: { genre: { eq: $genre } }, limit: $limit) {
+    title
+    imageUrl
+  }
+}
+
+# List movies by partial title string match
+query ListMoviesByTitleString(
+  $prefix: String
+  $suffix: String
+  $contained: String
+) @auth(level: PUBLIC) {
+  prefixed: movies(where: { description: { startsWith: $prefix } }) {
+    title
+  }
+  suffixed: movies(where: { description: { endsWith: $suffix } }) {
+    title
+  }
+  contained: movies(where: { description: { contains: $contained } }) {
+    title
+  }
+}
+
+# List movies by rating and genre with OR/AND filters
+query ListMoviesByRatingAndGenre($minRating: Float!, $genre: String)
+@auth(level: PUBLIC) {
+  movies(
+    where: { _or: [{ rating: { ge: $minRating } }, { genre: { eq: $genre } }] }
+  ) {
+    title
+    imageUrl
+  }
+}
+
+# Get favorite movies by user ID
+query GetFavoriteMoviesById($id: String!) @auth(level: USER) {
+  user(id: $id) {
+    favoriteMovies_on_user {
+      movie {
+        id
+        title
+        genre
+        imageUrl
+        releaseYear
+        rating
+        description
+      }
+    }
+  }
+}
+
+# Get favorite actors by user ID
+query GetFavoriteActorsById($id: String!) @auth(level: USER) {
+  user(id: $id) {
+    favoriteActors_on_user {
+      actor {
+        id
+        name
+        imageUrl
+      }
+    }
+  }
+}
+
+# Get watched movies by user ID
+query GetWatchedMoviesByAuthId($id: String!) @auth(level: USER) {
+  user(id: $id) {
+    watchedMovies_on_user {
+      movie {
+        id
+        title
+        genre
+        imageUrl
+        releaseYear
+        rating
+        description
+      }
+    }
+  }
+}
+
+# Get user by ID
+query GetUserById($id: String!) @auth(level: USER) {
+  user(id: $id) {
+    id
+    username
+    reviews: reviews_on_user {
+      id
+      rating
+      reviewDate
+      reviewText
+      movie {
+        id
+        title
+      }
+    }
+    watched: watchedMovies_on_user {
+      movie {
+        id
+        title
+        genre
+        imageUrl
+        releaseYear
+        rating
+        description
+        tags
+        metadata: movieMetadatas_on_movie {
+          director
+        }
+      }
+    }
+    favoriteMovies: favoriteMovies_on_user {
+      movie {
+        id
+        title
+        genre
+        imageUrl
+        releaseYear
+        rating
+        description
+        tags
+        metadata: movieMetadatas_on_movie {
+          director
+        }
+      }
+    }
+    favoriteActors: favoriteActors_on_user {
+      actor {
+        id
+        name
+        imageUrl
+      }
+    }
+  }
+}
+
+# Check if a movie is watched by user
+query GetIfWatched($id: String!, $movieId: UUID!) @auth(level: USER) {
+  watchedMovie(key: { userId: $id, movieId: $movieId }) {
+    movieId
+  }
+}
+
+# Check if a movie is favorited by user
+query GetIfFavoritedMovie($id: String!, $movieId: UUID!) @auth(level: USER) {
+  favoriteMovie(key: { userId: $id, movieId: $movieId }) {
+    movieId
+  }
+}
+
+# Check if an actor is favorited by user
+query GetIfFavoritedActor($id: String!, $actorId: UUID!) @auth(level: USER) {
+  favoriteActor(key: { userId: $id, actorId: $actorId }) {
+    actorId
+  }
+}
+
+# Fuzzy search for movies, actors, and reviews
+query fuzzySearch(
+  $input: String
+  $minYear: Int!
+  $maxYear: Int!
+  $minRating: Float!
+  $maxRating: Float!
+  $genre: String!
+) @auth(level: PUBLIC) {
+  moviesMatchingTitle: movies(
+    where: {
+      _and: [
+        { releaseYear: { ge: $minYear } }
+        { releaseYear: { le: $maxYear } }
+        { rating: { ge: $minRating } }
+        { rating: { le: $maxRating } }
+        { genre: { contains: $genre } }
+        { title: { contains: $input } }
+      ]
+    }
+  ) {
+    id
+    title
+    genre
+    rating
+    imageUrl
+  }
+  moviesMatchingDescription: movies(
+    where: {
+      _and: [
+        { releaseYear: { ge: $minYear } }
+        { releaseYear: { le: $maxYear } }
+        { rating: { ge: $minRating } }
+        { rating: { le: $maxRating } }
+        { genre: { contains: $genre } }
+        { description: { contains: $input } }
+      ]
+    }
+  ) {
+    id
+    title
+    genre
+    rating
+    imageUrl
+  }
+  actorsMatchingName: actors(where: { name: { contains: $input } }) {
+    id
+    name
+    imageUrl
+  }
+  reviewsMatchingText: reviews(where: { reviewText: { contains: $input } }) {
+    id
+    rating
+    reviewText
+    reviewDate
+    movie {
+      id
+      title
+    }
+    user {
+      id
+      username
+    }
+  }
+}
+
+# Search movie descriptions using L2 similarity with Vertex AI
+query searchMovieDescriptionUsingL2Similarity($query: String!)
+@auth(level: PUBLIC) {
+  movies_descriptionEmbedding_similarity(
+    compare_embed: { model: "textembedding-gecko@001", text: $query }
+    method: L2
+    within: 2
+    where: { description: { ne: "" } }
+    limit: 5
+  ) {
+    id
+    title
+    description
+    tags
+    rating
+    imageUrl
+  }
+}
diff --git a/dataconnect/dataconnect/dataconnect.yaml b/dataconnect/dataconnect/dataconnect.yaml
new file mode 100644
index 000000000..9dd8a336b
--- /dev/null
+++ b/dataconnect/dataconnect/dataconnect.yaml
@@ -0,0 +1,10 @@
+specVersion: "v1alpha"
+serviceId: "dataconnect"
+schema:
+  source: "./schema"
+  datasource:
+    postgresql:
+      database: "postgres"
+      cloudSql:
+        instanceId: "your-instanceId"
+connectorDirs: ["./connector"]
diff --git a/dataconnect/dataconnect/schema/schema.gql b/dataconnect/dataconnect/schema/schema.gql
new file mode 100644
index 000000000..01260143a
--- /dev/null
+++ b/dataconnect/dataconnect/schema/schema.gql
@@ -0,0 +1,104 @@
+# Movies
+type Movie
+  @table(name: "Movies", singular: "movie", plural: "movies", key: ["id"]) {
+  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
+  title: String!
+  imageUrl: String! @col(name: "image_url")
+  releaseYear: Int @col(name: "release_year")
+  genre: String
+  rating: Float @col(name: "rating") 
+  description: String @col(name: "description")
+  tags: [String] @col(name: "tags")
+  # Vectors
+  descriptionEmbedding: Vector @col(size:768) # vector
+}
+
+# Movie Metadata
+# Movie - MovieMetadata is a one-to-one relationship
+type MovieMetadata
+  @table(
+    name: "MovieMetadata"
+  ) {
+  # @ref creates a field in the current table (MovieMetadata) that holds the primary key of the referenced type
+  # In this case, @ref(fields: "id") is implied
+  movie: Movie! @ref
+  # movieId: UUID <- this is created by the above @ref
+  director: String @col(name: "director")
+  # TODO: optional other fields
+}
+
+# Actors
+# Suppose an actor can participate in multiple movies and movies can have multiple actors
+# Movie - Actors (or vice versa) is a many to many relationship
+type Actor @table(name: "Actors", singular: "actor", plural: "actors") {
+  id: UUID! @col(name: "actor_id") @default(expr: "uuidV4()")
+  imageUrl: String! @col(name: "image_url")
+  name: String! @col(name: "name", dataType: "varchar(30)")
+  biography: String @col(name: "biography")
+}
+
+# Join table for many-to-many relationship for movies and actors
+# The 'key' param signifies the primary key(s) of this table
+# In this case, the keys are [movieId, actorId], the generated fields of the reference types [movie, actor]
+type MovieActor @table(key: ["movie", "actor"]) {
+  # @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
+  # In this case, @ref(fields: "id") is implied
+  movie: Movie! @ref
+  # movieId: UUID! <- this is created by the above @ref, see: implicit.gql
+
+  actor: Actor! @ref
+  # actorId: UUID! <- this is created by the above @ref, see: implicit.gql
+
+  role: String! @col(name: "role") # "main" or "supporting"
+  # TODO: optional other fields
+}
+
+# Users
+# Suppose a user can leave reviews for movies
+# user:reviews is a one to many relationship, movie:reviews is a one to many relationship, movie:user is a many to many relationship
+type User
+  @table(name: "Users", singular: "user", plural: "users", key: ["id"]) {
+  # id: UUID! @col(name: "user_id") @default(expr: "uuidV4()")
+  id: String! @col(name: "user_auth")
+  username: String! @col(name: "username", dataType: "varchar(50)")
+  # The following are generated from the @ref in the Review table
+  # reviews_on_user 
+  # movies_via_Review
+}
+
+# Join table for many-to-many relationship for users and favorite movies
+type FavoriteMovie
+  @table(name: "FavoriteMovies", key: ["user", "movie"]) {
+  user: User! @ref
+  movie: Movie! @ref
+}
+
+# Join table for many-to-many relationship for users and favorite actors
+type FavoriteActor
+  @table(name: "FavoriteActors", key: ["user", "actor"]) {
+  user: User! @ref
+  actor: Actor! @ref
+}
+
+# Join table for many-to-many relationship for users and watched movies
+type WatchedMovie
+  @table(name: "WatchedMovies", key: ["user", "movie"]) {
+  user: User! @ref
+  movie: Movie! @ref
+}
+
+# Reviews
+type Review @table(name: "Reviews", key: ["movie", "user"]) {
+  id: UUID! @col(name: "review_id") @default(expr: "uuidV4()")
+  user: User! @ref
+  movie: Movie! @ref
+  rating: Int
+  reviewText: String
+  reviewDate: Date! @default(expr: "request.time")
+}
+
+# Self Joins
+extend type Movie {
+    sequelTo: Movie
+}
+
diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json
new file mode 100644
index 000000000..d333fb6ea
--- /dev/null
+++ b/dataconnect/firebase.json
@@ -0,0 +1,32 @@
+{
+  "dataconnect": {
+    "source": "./dataconnect",
+    "location": "us-central1"
+  },
+  "emulators": {
+    "dataconnect": {
+      "port": 9399
+    },
+    "ui": {
+      "enabled": false
+    },
+    "singleProjectMode": true,
+    "auth": {
+      "port": 9099
+    },
+    "hosting": {
+      "port": 5000
+    }
+  },
+  "hosting": {
+    "source": "movie",
+    "ignore": [
+      "firebase.json",
+      "**/.*",
+      "**/node_modules/**"
+    ],
+    "frameworksBackend": {
+      "region": "us-central1"
+    }
+  }
+}
diff --git a/dataconnect/movie/.env.local b/dataconnect/movie/.env.local
new file mode 100644
index 000000000..d080f30d3
--- /dev/null
+++ b/dataconnect/movie/.env.local
@@ -0,0 +1,6 @@
+NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
+NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-auth-domain
+NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
+NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-storage-bucket
+NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id
+NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
\ No newline at end of file
diff --git a/dataconnect/movie/app/actor/[id]/page.tsx b/dataconnect/movie/app/actor/[id]/page.tsx
new file mode 100644
index 000000000..d057ce327
--- /dev/null
+++ b/dataconnect/movie/app/actor/[id]/page.tsx
@@ -0,0 +1,138 @@
+'use client';
+import { useEffect, useState } from 'react';
+import { useParams, useRouter } from 'next/navigation';
+import Link from 'next/link';
+import { MdFavorite, MdFavoriteBorder } from 'react-icons/md';
+import { getActorById, GetActorByIdResponse, GetActorByIdVariables, addFavoritedActor, deleteFavoriteActor, getIfFavoritedActor } from '../../../lib/dataconnect-sdk';
+import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
+
+const Page = () => {
+  const router = useRouter();
+  const { id } = useParams() as { id: string };
+  const [actor, setActor] = useState<GetActorByIdResponse['actor'] | null>(null);
+  const [loading, setLoading] = useState(true);
+  const [authUser, setAuthUser] = useState<User | null>(null);
+  const [isFavorited, setIsFavorited] = useState(false);
+
+  useEffect(() => {
+    const auth = getAuth();
+    const unsubscribe = onAuthStateChanged(auth, (user) => {
+      if (user) {
+        setAuthUser(user);
+        checkIfFavorited(user.uid);
+      }
+    });
+
+    return () => unsubscribe();
+  }, [id]);
+
+  useEffect(() => {
+    if (id) {
+      const fetchActor = async () => {
+        try {
+          const response = await getActorById({ id });
+          setActor(response.data.actor);
+        } catch (error) {
+          console.error('Error fetching actor:', error);
+        } finally {
+          setLoading(false);
+        }
+      };
+
+      fetchActor();
+    }
+  }, [id]);
+
+  const checkIfFavorited = async (userId: string) => {
+    try {
+      const response = await getIfFavoritedActor({ id: userId, actorId: id });
+      setIsFavorited(!!response.data.favoriteActor);
+    } catch (error) {
+      console.error('Error checking if favorited:', error);
+    }
+  };
+
+  const handleFavoriteToggle = async () => {
+    if (!authUser) return;
+    try {
+      if (isFavorited) {
+        await deleteFavoriteActor({ userId: authUser.uid, actorId: id });
+      } else {
+        await addFavoritedActor({ actorId: id });
+      }
+      setIsFavorited(!isFavorited);
+    } catch (error) {
+      console.error('Error updating favorite status:', error);
+    }
+  };
+
+  if (loading) return <p>Loading...</p>;
+  if (!actor) return <p>Actor not found.</p>;
+
+  return (
+    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
+      <div className="flex flex-col md:flex-row mb-8">
+        <img className="w-full md:w-1/3 object-cover rounded-lg shadow-md" src={actor.imageUrl} alt={actor.name} />
+        <div className="md:ml-8 mt-4 md:mt-0 flex-1">
+          <h1 className="text-5xl font-bold mb-2">{actor.name}</h1>
+          <div className="mt-4 flex space-x-4">
+            <button
+              className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
+              aria-label="Favorite"
+              onClick={handleFavoriteToggle}
+            >
+              {isFavorited ? <MdFavorite size={24} /> : <MdFavoriteBorder size={24} />}
+            </button>
+          </div>
+          <p className="text-lg mb-4 p-4 bg-gray-800 rounded-lg">{actor.biography}</p>
+        </div>
+      </div>
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">Main Roles</h2>
+        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
+          {actor.mainActors.map((movie) => (
+            <Link key={movie.id} href={`/movie/${movie.id}`}>
+              <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
+                <img className="w-full h-48 object-cover" src={movie.imageUrl} alt={movie.title} />
+                <div className="p-4">
+                  <h3 className="font-bold text-lg mb-1 text-white">{movie.title}</h3>
+                  <p className="text-sm text-gray-400">{movie.genre}</p>
+                  <div className="flex flex-wrap gap-1 mt-2">
+                    {movie.tags.map((tag, index) => (
+                      <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{tag}</span>
+                    ))}
+                  </div>
+                </div>
+              </div>
+            </Link>
+          ))}
+        </div>
+      </div>
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">Supporting Roles</h2>
+        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
+          {actor.supportingActors.map((movie) => (
+            <Link key={movie.id} href={`/movie/${movie.id}`}>
+              <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
+                <img className="w-full h-48 object-cover" src={movie.imageUrl} alt={movie.title} />
+                <div className="p-4">
+                  <h3 className="font-bold text-lg mb-1 text-white">{movie.title}</h3>
+                  <p className="text-sm text-gray-400">{movie.genre}</p>
+                  <div className="flex flex-wrap gap-1 mt-2">
+                    {movie.tags.map((tag, index) => (
+                      <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{tag}</span>
+                    ))}
+                  </div>
+                </div>
+              </div>
+            </Link>
+          ))}
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default Page;
diff --git a/dataconnect/movie/app/advancedsearch/page.tsx b/dataconnect/movie/app/advancedsearch/page.tsx
new file mode 100644
index 000000000..042010999
--- /dev/null
+++ b/dataconnect/movie/app/advancedsearch/page.tsx
@@ -0,0 +1,219 @@
+'use client';
+import { useState } from 'react';
+import Link from 'next/link';
+import { FaSearch } from 'react-icons/fa';
+import { MdStar } from 'react-icons/md';
+import { fuzzySearch } from '../../lib/dataconnect-sdk';
+
+const genres = ['', 'action', 'crime', 'drama', 'sci-fi', 'thriller', 'adventure'];
+
+const Page = () => {
+  const [searchQuery, setSearchQuery] = useState('');
+  const [releaseYearRange, setReleaseYearRange] = useState({ min: 1900, max: 2030 });
+  const [genre, setGenre] = useState('');
+  const [ratingRange, setRatingRange] = useState({ min: 1, max: 10 });
+  const [results, setResults] = useState({
+    moviesMatchingTitle: [],
+    moviesMatchingDescription: [],
+    actors: [],
+    reviews: [],
+  });
+
+  const handleSearch = async (e: React.FormEvent<HTMLFormElement>) => {
+    e.preventDefault();
+    try {
+      const response = await fuzzySearch({
+        input: searchQuery,
+        minYear: releaseYearRange.min,
+        maxYear: releaseYearRange.max,
+        minRating: ratingRange.min,
+        maxRating: ratingRange.max,
+        genre,
+      });
+      setResults({
+        moviesMatchingTitle: response.data.moviesMatchingTitle,
+        moviesMatchingDescription: response.data.moviesMatchingDescription,
+        actors: response.data.actorsMatchingName,
+        reviews: response.data.reviewsMatchingText,
+      });
+    } catch (error) {
+      console.error('Error fetching search results:', error);
+    }
+  };
+
+  return (
+    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
+      <h1 className="text-4xl font-bold mb-4">Advanced Search</h1>
+      <form onSubmit={handleSearch} className="mb-8">
+        <div className="flex items-center mb-4">
+          <label htmlFor="searchQuery" className="sr-only">Search</label>
+          <input
+            id="searchQuery"
+            type="text"
+            placeholder="Search for movies, actors, or reviews..."
+            className="w-full p-4 rounded bg-gray-800 text-white"
+            value={searchQuery}
+            onChange={(e) => setSearchQuery(e.target.value)}
+          />
+          <button
+            type="submit"
+            className="ml-2 p-4 rounded bg-blue-600 text-white hover:bg-blue-700 transition-colors"
+          >
+            <FaSearch />
+          </button>
+        </div>
+        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-4">
+          <div>
+            <label htmlFor="minYear" className="block mb-2">Release Year From</label>
+            <input
+              id="minYear"
+              type="number"
+              className="w-full p-2 rounded bg-gray-800 text-white"
+              value={releaseYearRange.min}
+              onChange={(e) => setReleaseYearRange({ ...releaseYearRange, min: Number(e.target.value) })}
+              min="1900"
+              max="2030"
+            />
+            <label htmlFor="maxYear" className="block mb-2 mt-2">Release Year To</label>
+            <input
+              id="maxYear"
+              type="number"
+              className="w-full p-2 rounded bg-gray-800 text-white"
+              value={releaseYearRange.max}
+              onChange={(e) => setReleaseYearRange({ ...releaseYearRange, max: Number(e.target.value) })}
+              min="1900"
+              max="2030"
+            />
+          </div>
+          <div>
+            <label htmlFor="genre" className="block mb-2">Genre</label>
+            <select
+              id="genre"
+              className="w-full p-2 rounded bg-gray-800 text-white"
+              value={genre}
+              onChange={(e) => setGenre(e.target.value)}
+            >
+              {genres.map((g) => (
+                <option key={g} value={g}>
+                  {g.charAt(0).toUpperCase() + g.slice(1)}
+                </option>
+              ))}
+            </select>
+          </div>
+          <div>
+            <label htmlFor="minRating" className="block mb-2">Rating From</label>
+            <input
+              id="minRating"
+              type="number"
+              className="w-full p-2 rounded bg-gray-800 text-white"
+              value={ratingRange.min}
+              onChange={(e) => setRatingRange({ ...ratingRange, min: Number(e.target.value) })}
+              min="1"
+              max="10"
+            />
+            <label htmlFor="maxRating" className="block mb-2 mt-2">Rating To</label>
+            <input
+              id="maxRating"
+              type="number"
+              className="w-full p-2 rounded bg-gray-800 text-white"
+              value={ratingRange.max}
+              onChange={(e) => setRatingRange({ ...ratingRange, max: Number(e.target.value) })}
+              min="1"
+              max="10"
+            />
+          </div>
+        </div>
+      </form>
+      <div className="results">
+        <h2 className="text-2xl font-bold mb-4">Results</h2>
+        <div>
+          <h3 className="text-xl font-bold mb-2">Movies Matching Title</h3>
+          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
+            {results.moviesMatchingTitle?.map((movie) => (
+              <Link key={movie.id} href={`/movie/${movie.id}`}>
+                <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
+                  <img className="w-full h-64 object-cover" src={movie.imageUrl} alt={movie.title} />
+                  <div className="p-4">
+                    <h3 className="font-bold text-lg mb-1 text-white">{movie.title}</h3>
+                    <div className="flex items-center text-yellow-500">
+                      <MdStar className="text-yellow-500" size={20} />
+                      <span className="ml-1 text-gray-400">{movie.rating}</span>
+                    </div>
+                    <div className="flex flex-wrap gap-1 mt-2">
+                      {movie?.tags?.map((tag, index) => (
+                        <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{tag}</span>
+                      ))}
+                    </div>
+                  </div>
+                </div>
+              </Link>
+            ))}
+          </div>
+        </div>
+        <div className="mt-8">
+          <h3 className="text-xl font-bold mb-2">Movies Matching Description</h3>
+          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
+            {results.moviesMatchingDescription?.map((movie) => (
+              <Link key={movie.id} href={`/movie/${movie.id}`}>
+                <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
+                  <img className="w-full h-64 object-cover" src={movie.imageUrl} alt={movie.title} />
+                  <div className="p-4">
+                    <h3 className="font-bold text-lg mb-1 text-white">{movie.title}</h3>
+                    <div className="flex items-center text-yellow-500">
+                      <MdStar className="text-yellow-500" size={20} />
+                      <span className="ml-1 text-gray-400">{movie.rating}</span>
+                    </div>
+                    <div className="flex flex-wrap gap-1 mt-2">
+                      {movie?.tags?.map((tag, index) => (
+                        <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{tag}</span>
+                      ))}
+                    </div>
+                  </div>
+                </div>
+              </Link>
+            ))}
+          </div>
+        </div>
+        <div className="mt-8">
+          <h3 className="text-xl font-bold mb-2">Actors</h3>
+          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
+            {results.actors?.map((actor) => (
+              <Link key={actor.id} href={`/actor/${actor.id}`}>
+                <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
+                  <img className="w-full h-64 object-cover" src={actor.imageUrl} alt={actor.name} />
+                  <div className="p-4">
+                    <h3 className="font-bold text-lg mb-1 text-white">{actor.name}</h3>
+                  </div>
+                </div>
+              </Link>
+            ))}
+          </div>
+        </div>
+        <div className="mt-8">
+          <h3 className="text-xl font-bold mb-2">Reviews</h3>
+          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
+            {results?.reviews?.map((review) => (
+              <div
+                key={review.id}
+                className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 p-4"
+              >
+                <p className="font-bold text-white">{review?.user?.username}</p>
+                <p className="text-sm text-gray-400">{review.reviewDate}</p>
+                <p className="mt-2 text-white">{review.reviewText}</p>
+                <div className="flex items-center text-yellow-500 mt-2">
+                  <MdStar className="text-yellow-500" size={20} />
+                  <span className="ml-1 text-gray-400">{review.rating}</span>
+                </div>
+                <Link href={`/movie/${review.movie.id}`} className="mt-2 text-blue-500 hover:text-blue-400 transition-colors">
+                  {review?.movie?.title}
+                </Link>
+              </div>
+            ))}
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default Page;
diff --git a/dataconnect/movie/app/genre/[genre]/page.tsx b/dataconnect/movie/app/genre/[genre]/page.tsx
new file mode 100644
index 000000000..48ab5697e
--- /dev/null
+++ b/dataconnect/movie/app/genre/[genre]/page.tsx
@@ -0,0 +1,70 @@
+'use client';
+import { useEffect, useState } from 'react';
+import { useParams } from 'next/navigation';
+import MovieCard from '../../../components/moviecard';
+import { ListMoviesByGenreResponse, ListMoviesByGenreVariables, listMoviesByGenre } from '../../../lib/dataconnect-sdk';
+
+const Page = () => {
+  const { genre } = useParams() as { genre: string };
+  const [mostPopular, setMostPopular] = useState<ListMoviesByGenreResponse['mostPopular']>([]);
+  const [mostRecent, setMostRecent] = useState<ListMoviesByGenreResponse['mostRecent']>([]);
+  const [loading, setLoading] = useState(true);
+
+  useEffect(() => {
+    const fetchMovies = async () => {
+      try {
+        const response = await listMoviesByGenre({ genre });
+        setMostPopular(response.data.mostPopular);
+        setMostRecent(response.data.mostRecent);
+      } catch (error) {
+        console.error('Error fetching movies:', error);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchMovies();
+  }, [genre]);
+
+  if (loading) return <p>Loading...</p>;
+
+  return (
+    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
+      <h1 className="text-3xl font-bold mb-4 capitalize">{genre} Movies</h1>
+
+      <section className="mb-8">
+        <h2 className="text-2xl font-bold mb-4">Most Popular</h2>
+        <div className="flex overflow-x-auto space-x-4">
+          {mostPopular.map((movie) => (
+            <MovieCard
+              key={movie.id}
+              id={movie.id}
+              title={movie.title}
+              imageUrl={movie.imageUrl}
+              rating={movie.rating}
+              tags={movie.tags}
+            />
+          ))}
+        </div>
+      </section>
+
+      <section>
+        <h2 className="text-2xl font-bold mb-4">Most Recent</h2>
+        <div className="flex overflow-x-auto space-x-4">
+          {mostRecent.map((movie) => (
+            <MovieCard
+              key={movie.id}
+              id={movie.id}
+              title={movie.title}
+              imageUrl={movie.imageUrl}
+              rating={movie.rating}
+              tags={movie.tags}
+            />
+          ))}
+        </div>
+      </section>
+    </div>
+  );
+};
+
+export default Page;
diff --git a/dataconnect/movie/app/layout.tsx b/dataconnect/movie/app/layout.tsx
new file mode 100644
index 000000000..1d3a8e1b2
--- /dev/null
+++ b/dataconnect/movie/app/layout.tsx
@@ -0,0 +1,19 @@
+"use client";
+import Navbar from "../components/navbar";
+import "../styles.css";
+export default function RootLayout({
+  children,
+}: {
+  children: React.ReactNode;
+}) {
+  return (
+    <html lang="en">
+      <body>
+        <Navbar />
+        <div className="bg-gray-800 min-h-screen min-w-screen flex justify-center items-center">
+          {children}
+        </div>
+      </body>
+    </html>
+  );
+}
diff --git a/dataconnect/movie/app/movie/[id]/page.tsx b/dataconnect/movie/app/movie/[id]/page.tsx
new file mode 100644
index 000000000..c15c4e488
--- /dev/null
+++ b/dataconnect/movie/app/movie/[id]/page.tsx
@@ -0,0 +1,280 @@
+'use client';
+import { useEffect, useState } from 'react';
+import { useParams, useRouter } from 'next/navigation';
+import Link from 'next/link';
+import { MdFavorite, MdFavoriteBorder, MdCheck, MdCheckBoxOutlineBlank, MdStar } from 'react-icons/md';
+import {
+  getMovieById,
+  GetMovieByIdResponse,
+  addFavoritedMovie,
+  deleteFavoritedMovie,
+  addWatchedMovie,
+  deleteWatchedMovie,
+  getIfWatched,
+  getIfFavoritedMovie,
+  addReview,
+  deleteReview,
+} from '../../../lib/dataconnect-sdk';
+import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
+
+const Page = () => {
+  const router = useRouter();
+  const { id } = useParams() as { id: string };
+  const [movie, setMovie] = useState<GetMovieByIdResponse['movie'] | null>(null);
+  const [loading, setLoading] = useState(true);
+  const [authUser, setAuthUser] = useState<User | null>(null);
+  const [isFavorited, setIsFavorited] = useState(false);
+  const [isWatched, setIsWatched] = useState(false);
+  const [reviewText, setReviewText] = useState('');
+  const [userReview, setUserReview] = useState<GetMovieByIdResponse['movie']['reviews'][0] | null>(null);
+  const [rating, setRating] = useState(0);
+
+  useEffect(() => {
+    const auth = getAuth();
+    const unsubscribe = onAuthStateChanged(auth, (user) => {
+      if (user) {
+        setAuthUser(user);
+        checkIfFavorited(user.uid);
+        checkIfWatched(user.uid);
+      }
+    });
+
+    return () => unsubscribe();
+  }, [id]);
+
+  useEffect(() => {
+    if (id) {
+      const fetchMovie = async () => {
+        try {
+          const response = await getMovieById({ id });
+          setMovie(response.data.movie);
+          const userReview = response.data.movie.reviews.find(review => review.user.id === authUser?.uid);
+          setUserReview(userReview || null);
+        } catch (error) {
+          console.error('Error fetching movie:', error);
+        } finally {
+          setLoading(false);
+        }
+      };
+
+      fetchMovie();
+    }
+  }, [id, authUser, movie]);
+
+  const checkIfFavorited = async (userId: string) => {
+    try {
+      const response = await getIfFavoritedMovie({ id: userId, movieId: id });
+      setIsFavorited(!!response.data.favoriteMovie);
+    } catch (error) {
+      console.error('Error checking if favorited:', error);
+    }
+  };
+
+  const checkIfWatched = async (userId: string) => {
+    try {
+      const response = await getIfWatched({ id: userId, movieId: id });
+      setIsWatched(!!response.data.watchedMovie);
+    } catch (error) {
+      console.error('Error checking if watched:', error);
+    }
+  };
+
+  const handleFavoriteToggle = async (e: React.MouseEvent) => {
+    e.stopPropagation();
+    e.preventDefault();
+    if (!authUser) return;
+    try {
+      if (isFavorited) {
+        await deleteFavoritedMovie({ userId: authUser.uid, movieId: id });
+      } else {
+        await addFavoritedMovie({ movieId: id });
+      }
+      setIsFavorited(!isFavorited);
+    } catch (error) {
+      console.error('Error updating favorite status:', error);
+    }
+  };
+
+  const handleWatchedToggle = async (e: React.MouseEvent) => {
+    e.stopPropagation();
+    e.preventDefault();
+    if (!authUser) return;
+    try {
+      if (isWatched) {
+        await deleteWatchedMovie({ userId: authUser.uid, movieId: id });
+      } else {
+        await addWatchedMovie({ movieId: id });
+      }
+      setIsWatched(!isWatched);
+    } catch (error) {
+      console.error('Error updating watched status:', error);
+    }
+  };
+
+  const handleReviewSubmit = async (e: React.FormEvent) => {
+    e.preventDefault();
+    if (!authUser) return;
+    try {
+        const response  = await addReview({ movieId: id, rating, reviewText });
+      setReviewText('');
+      setRating(0);
+      const updatedMovie = await getMovieById({ id });
+      setMovie(updatedMovie.data.movie);
+    } catch (error) {
+      console.error('Error adding review:', error);
+    }
+  };
+
+  const handleReviewDelete = async (e: React.MouseEvent) => {
+    e.stopPropagation();
+    e.preventDefault();
+    if (!authUser || !userReview) return;
+    try {
+      await deleteReview({ movieId: id, userId: authUser.uid });
+      setUserReview(null);
+      const updatedMovie = await getMovieById({ id });
+      setMovie(updatedMovie.data.movie);
+    } catch (error) {
+      console.error('Error deleting review:', error);
+    }
+  };
+
+  if (loading) return <p>Loading...</p>;
+  if (!movie) return <p>Movie not found.</p>;
+
+  return (
+    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
+      <div className="flex flex-col md:flex-row mb-8">
+        <img className="w-full md:w-1/3 object-cover rounded-lg shadow-md" src={movie.imageUrl} alt={movie.title} />
+        <div className="md:ml-8 mt-4 md:mt-0 flex-1">
+          <h1 className="text-5xl font-bold mb-2">{movie.title}</h1>
+          <div className="flex items-center text-yellow-500 mb-4">
+            <MdStar className="text-yellow-500" size={24} />
+            <span className="ml-1 text-gray-400 text-lg">{movie.rating}</span>
+          </div>
+          <p className="text-lg mb-4 p-4 bg-gray-800 rounded-lg">{movie.description}</p>
+          <div className="text-sm space-y-2">
+            <p><span className="font-bold">Genre:</span> {movie.genre}</p>
+            <p><span className="font-bold">Release Year:</span> {movie.releaseYear}</p>
+            <p><span className="font-bold">Director:</span> {movie.metadata[0]?.director}</p>
+            <p><span className="font-bold">Tags:</span> {movie.tags.join(', ')}</p>
+          </div>
+          <div className="mt-4 flex space-x-4">
+            <button
+              className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
+              aria-label="Favorite"
+              onClick={handleFavoriteToggle}
+            >
+              {isFavorited ? <MdFavorite size={24} /> : <MdFavoriteBorder size={24} />}
+            </button>
+            <button
+              className="flex items-center justify-center p-1 text-green-700 hover:text-green-800 transition-colors duration-200"
+              aria-label="Watched"
+              onClick={handleWatchedToggle}
+            >
+              {isWatched ? <MdCheck size={24} /> : <MdCheckBoxOutlineBlank size={24} />}
+            </button>
+          </div>
+        </div>
+      </div>
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">Main Actors</h2>
+        <div className="flex overflow-x-auto space-x-4">
+          {movie.mainActors.map((actor) => (
+            <Link key={actor.id} href={`/actor/${actor.id}`} passHref>
+              <div className="flex-shrink-0 bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer w-32">
+                <img className="w-full h-32 object-cover" src={actor.imageUrl} alt={actor.name} />
+                <div className="p-2 text-center">
+                  <h3 className="font-bold text-sm text-white">{actor.name}</h3>
+                </div>
+              </div>
+            </Link>
+          ))}
+        </div>
+      </div>
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">Supporting Actors</h2>
+        <div className="flex overflow-x-auto space-x-4">
+          {movie.supportingActors.map((actor) => (
+            <Link key={actor.id} href={`/actor/${actor.id}`} passHref>
+              <div className="flex-shrink-0 bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer w-32">
+                <img className="w-full h-32 object-cover" src={actor.imageUrl} alt={actor.name} />
+                <div className="p-2 text-center">
+                  <h3 className="font-bold text-sm text-white">{actor.name}</h3>
+                </div>
+              </div>
+            </Link>
+          ))}
+        </div>
+      </div>
+
+      {movie.sequelTo && (
+        <div className="mt-8">
+          <h2 className="text-2xl font-bold mb-2">Sequel</h2>
+          <Link href={`/movie/${movie.sequelTo.id}`} passHref>
+            <div className="flex items-center cursor-pointer hover:bg-gray-800 p-2 rounded-lg transition">
+              <img className="w-20 h-28 object-cover rounded-lg mr-4" src={movie.sequelTo.imageUrl} alt={movie.sequelTo.title} />
+              <span className="text-lg">{movie.sequelTo.title}</span>
+            </div>
+          </Link>
+        </div>
+      )}
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">User Reviews</h2>
+        {!userReview ? (
+          <form onSubmit={handleReviewSubmit} className="mb-4 p-4 bg-gray-800 rounded-lg shadow-md">
+            <h3 className="text-xl font-bold mb-2">Leave a Review</h3>
+            <textarea
+              className="w-full p-2 rounded-lg bg-gray-700 text-white mb-2"
+              value={reviewText}
+              onChange={(e) => setReviewText(e.target.value)}
+              placeholder="Write your review here..."
+            />
+            <div className="flex items-center mb-2">
+              <label className="mr-2">Rating:</label>
+              <input
+                type="number"
+                className="p-1 rounded-lg bg-gray-700 text-white"
+                value={rating}
+                onChange={(e) => setRating(Number(e.target.value))}
+                min="1"
+                max="10"
+              />
+            </div>
+            <button
+              type="submit"
+              className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors duration-200"
+            >
+              Submit Review
+            </button>
+          </form>
+        ) : (<></>)}
+
+        {movie.reviews.map((review) => (
+          <div key={review.id} className="mb-4 p-4 bg-gray-800 rounded-lg shadow-md">
+            <p className="font-bold">{review.user.username}</p>
+            <p className="text-sm">{review.reviewDate}</p>
+            <p className="mt-2">{review.reviewText}</p>
+            <div className="flex items-center text-yellow-500 mt-2">
+              <MdStar className="text-yellow-500" size={20} />
+              <span className="ml-1 text-gray-400">{review.rating}</span>
+            </div>
+            {userReview?.id === review.id && (
+              <button
+                className="mt-2 text-red-500 hover:text-red-600 transition-colors duration-200"
+                onClick={handleReviewDelete}
+              >
+                Delete Review
+              </button>
+            )}
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+};
+
+export default Page;
diff --git a/dataconnect/movie/app/myprofile/page.tsx b/dataconnect/movie/app/myprofile/page.tsx
new file mode 100644
index 000000000..b2b527788
--- /dev/null
+++ b/dataconnect/movie/app/myprofile/page.tsx
@@ -0,0 +1,210 @@
+'use client';
+import { useEffect, useState } from 'react';
+import { useRouter } from 'next/navigation';
+import Link from 'next/link';
+import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
+import {
+  getUserById,
+  GetUserByIdResponse,
+  deleteReview,
+  deleteWatchedMovie,
+  deleteFavoritedMovie,
+  deleteFavoriteActor,
+} from '../../lib/dataconnect-sdk';
+import { MdStar } from 'react-icons/md';
+
+const Page = () => {
+  const router = useRouter();
+  const [authUser, setAuthUser] = useState<User | null>(null);
+  const [user, setUser] = useState<GetUserByIdResponse['user'] | null>(null);
+  const [loading, setLoading] = useState(true);
+
+  useEffect(() => {
+    const auth = getAuth();
+    const unsubscribe = onAuthStateChanged(auth, (user) => {
+      if (user) {
+        setAuthUser(user);
+        fetchUserProfile(user.uid);
+      } else {
+        router.push('/');
+      }
+    });
+
+    return () => unsubscribe();
+  }, [router]);
+
+  const fetchUserProfile = async (userId: string) => {
+    try {
+      const response = await getUserById({ id: userId });
+      setUser(response.data.user);
+    } catch (error) {
+      console.error('Error fetching user:', error);
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleDeleteReview = async (reviewId: string) => {
+    if (!authUser) return;
+    try {
+      await deleteReview({ movieId: reviewId, userId: authUser.uid });
+      fetchUserProfile(authUser.uid);
+    } catch (error) {
+      console.error('Error deleting review:', error);
+    }
+  };
+
+  const handleUnwatchMovie = async (movieId: string) => {
+    if (!authUser) return;
+    try {
+      await deleteWatchedMovie({ userId: authUser.uid, movieId });
+      fetchUserProfile(authUser.uid);
+    } catch (error) {
+      console.error('Error unwatching movie:', error);
+    }
+  };
+
+  const handleUnfavoriteMovie = async (movieId: string) => {
+    if (!authUser) return;
+    try {
+      await deleteFavoritedMovie({ userId: authUser.uid, movieId });
+      fetchUserProfile(authUser.uid);
+    } catch (error) {
+      console.error('Error unfavoriting movie:', error);
+    }
+  };
+
+  const handleUnfavoriteActor = async (actorId: string) => {
+    if (!authUser) return;
+    try {
+      await deleteFavoriteActor({ userId: authUser.uid, actorId });
+      fetchUserProfile(authUser.uid);
+    } catch (error) {
+      console.error('Error unfavoriting actor:', error);
+    }
+  };
+
+  if (loading) return <p>Loading...</p>;
+  if (!user) return <p>User not found.</p>;
+
+  return (
+    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
+      <div className="mb-8">
+        <h1 className="text-5xl font-bold mb-4">Welcome back, {user.username}</h1>
+      </div>
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">Reviews</h2>
+        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
+          {user.reviews.map((review) => (
+            <div key={review.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md p-4 relative max-h-72">
+              <h3 className="font-bold text-lg mb-1 text-white">{review.movie.title}</h3>
+              <div className="flex items-center text-yellow-500 mb-2">
+                <MdStar className="text-yellow-500" size={24} />
+                <span className="ml-1 text-gray-400">{review.rating}</span>
+              </div>
+              <p className="text-sm text-gray-400 mb-2">{review.reviewDate}</p>
+              <p className="text-sm text-gray-300">{review.reviewText}</p>
+              <button
+                onClick={() => handleDeleteReview(review.id)}
+                className="absolute bottom-2 right-2 text-red-500 hover:text-red-600"
+              >
+                Delete Review
+              </button>
+            </div>
+          ))}
+        </div>
+      </div>
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">Watched Movies</h2>
+        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
+          {user.watched.map((watched) => (
+            <div key={watched.movie.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative max-h-80">
+              <Link href={`/movie/${watched.movie.id}`}>
+                <img className="w-full h-64 object-cover" src={watched.movie.imageUrl} alt={watched.movie.title} />
+              </Link>
+              <div className="p-4">
+                <h3 className="font-bold text-lg mb-1 text-white">{watched.movie.title}</h3>
+                <p className="text-sm text-gray-400 capitalize">{watched.movie.genre}</p>
+                <p className="text-sm text-gray-300 overflow-y-scroll max-h-24">{watched.movie.description}</p>
+                <div className="flex items-center text-yellow-500 mt-2">
+                  <MdStar className="text-yellow-500" size={24} />
+                  <span className="ml-1 text-gray-400">{watched.movie.rating}</span>
+                </div>
+                <div className="flex flex-wrap gap-1 mt-2">
+                  {watched.movie.tags?.map((tag, index) => (
+                    <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs capitalize">{tag}</span>
+                  ))}
+                </div>
+              </div>
+              <button
+                onClick={() => handleUnwatchMovie(watched.movie.id)}
+                className="absolute bottom-2 right-2 text-red-500 hover:text-red-600"
+              >
+                Remove Watched
+              </button>
+            </div>
+          ))}
+        </div>
+      </div>
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">Favorite Movies</h2>
+        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
+          {user.favoriteMovies.map((fav) => (
+            <div key={fav.movie.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative max-h-80">
+              <Link href={`/movie/${fav.movie.id}`}>
+                <img className="w-full h-64 object-cover" src={fav.movie.imageUrl} alt={fav.movie.title} />
+              </Link>
+              <div className="p-4">
+                <h3 className="font-bold text-lg mb-1 text-white">{fav.movie.title}</h3>
+                <p className="text-sm text-gray-400 capitalize">{fav.movie.genre}</p>
+                <p className="text-sm text-gray-300 overflow-y-scroll max-h-24">{fav.movie.description}</p>
+                <div className="flex items-center text-yellow-500 mt-2">
+                  <MdStar className="text-yellow-500" size={24} />
+                  <span className="ml-1 text-gray-400">{fav.movie.rating}</span>
+                </div>
+                <div className="flex flex-wrap gap-1 mt-2">
+                  {fav.movie.tags?.map((tag, index) => (
+                    <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs capitalize">{tag}</span>
+                  ))}
+                </div>
+              </div>
+              <button
+                onClick={() => handleUnfavoriteMovie(fav.movie.id)}
+                className="absolute bottom-2 right-2 text-red-500 hover:text-red-600"
+              >
+                Remove Favorite
+              </button>
+            </div>
+          ))}
+        </div>
+      </div>
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">Favorite Actors</h2>
+        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
+          {user.favoriteActors.map((favActor) => (
+            <div key={favActor.actor.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative max-h-80">
+              <Link href={`/actor/${favActor.actor.id}`}>
+                <img className="w-48 h-48 object-cover rounded-full mx-auto mt-4" src={favActor.actor.imageUrl} alt={favActor.actor.name} />
+              </Link>
+              <div className="p-4 text-center">
+                <h3 className="font-bold text-lg mb-1 text-white">{favActor.actor.name}</h3>
+              </div>
+              <button
+                onClick={() => handleUnfavoriteActor(favActor.actor.id)}
+                className="absolute bottom-2 right-2 text-red-500 hover:text-red-600"
+              >
+                Remove Favorite
+              </button>
+            </div>
+          ))}
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default Page;
diff --git a/dataconnect/movie/app/page.tsx b/dataconnect/movie/app/page.tsx
new file mode 100644
index 000000000..3754b9f73
--- /dev/null
+++ b/dataconnect/movie/app/page.tsx
@@ -0,0 +1,41 @@
+"use client";
+import { useEffect, useState } from "react";
+import Carousel from "../components/carousel";
+import {
+  moviesTop10,
+  moviesRecentlyReleased,
+  MoviesRecentlyReleasedResponse,
+  MoviesTop10Response,
+} from "../lib/dataconnect-sdk";
+
+const Page = () => {
+  const [topMovies, setTopMovies] = useState<MoviesTop10Response["movies"]>([]);
+  const [latestMovies, setLatestMovies] = useState<
+    MoviesRecentlyReleasedResponse["movies"]
+  >([]);
+
+  useEffect(() => {
+    const fetchMovies = async () => {
+      try {
+        const topMoviesResponse = await moviesTop10();
+        const latestMoviesResponse = await moviesRecentlyReleased();
+
+        setTopMovies(topMoviesResponse.data.movies);
+        setLatestMovies(latestMoviesResponse.data.movies);
+      } catch (error) {
+        console.error("Error fetching movies:", error);
+      }
+    };
+
+    fetchMovies();
+  }, []);
+
+  return (
+    <div className="container mx-auto p-4 bg-gray-900 text-white shadow-md min-h-screen">
+      <Carousel title="Top 10 Movies" movies={topMovies} />
+      <Carousel title="Latest Movies" movies={latestMovies.slice(0, 10)} />
+    </div>
+  );
+};
+
+export default Page;
diff --git a/dataconnect/movie/app/vectors/page.tsx b/dataconnect/movie/app/vectors/page.tsx
new file mode 100644
index 000000000..b8b06be6e
--- /dev/null
+++ b/dataconnect/movie/app/vectors/page.tsx
@@ -0,0 +1,82 @@
+'use client';
+import { useState } from 'react';
+import { useRouter } from 'next/navigation';
+import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '../../lib/dataconnect-sdk';
+import { FaSpinner } from 'react-icons/fa';
+
+const Page = () => {
+  const [query, setQuery] = useState('');
+  const [loading, setLoading] = useState(false);
+  const [results, setResults] = useState<SearchMovieDescriptionUsingL2similarityResponse['movies_descriptionEmbedding_similarity']>([]);
+
+  const handleSearch = async (e: React.FormEvent<HTMLFormElement>) => {
+    e.preventDefault();
+    setLoading(true);
+    try {
+      const response = await searchMovieDescriptionUsingL2similarity({ query });
+      setResults(response.data.movies_descriptionEmbedding_similarity);
+    } catch (error) {
+      console.error('Error fetching movie descriptions:', error);
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  return (
+    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
+      <h1 className="text-4xl font-bold mb-4">Vector Movie Search</h1>
+      <form onSubmit={handleSearch} className="mb-8">
+        <label htmlFor="query" className="block mb-2 text-xl">Enter your query</label>
+        <div className="flex items-center">
+          <input
+            id="query"
+            type="text"
+            className="w-full p-4 rounded bg-gray-800 text-white"
+            value={query}
+            onChange={(e) => setQuery(e.target.value)}
+            placeholder="Describe the kind of movie you're looking for..."
+          />
+          <button
+            type="submit"
+            className="ml-2 p-4 rounded bg-blue-600 text-white hover:bg-blue-700 transition-colors"
+          >
+            Search
+          </button>
+        </div>
+      </form>
+
+      {loading && (
+        <div className="flex justify-center items-center">
+          <FaSpinner className="animate-spin text-4xl text-blue-600" />
+        </div>
+      )}
+
+      {!loading && results.length > 0 && (
+        <div className="results">
+          <h2 className="text-2xl font-bold mb-4">Results</h2>
+          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
+            {results.map((movie) => (
+              <div key={movie.id} className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
+                <img className="w-full h-64 object-cover" src={movie.imageUrl} alt={movie.title} />
+                <div className="p-4">
+                  <h3 className="font-bold text-lg mb-1 text-white">{movie.title}</h3>
+                  <p className="text-sm text-gray-400">{movie.description}</p>
+                  <div className="flex items-center text-yellow-500 mt-2">
+                    <span className="ml-1 text-gray-400">{movie.rating}</span>
+                  </div>
+                  <div className="flex flex-wrap gap-1 mt-2">
+                    {movie?.tags?.map((tag, index) => (
+                      <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{tag}</span>
+                    ))}
+                  </div>
+                </div>
+              </div>
+            ))}
+          </div>
+        </div>
+      )}
+    </div>
+  );
+};
+
+export default Page;
diff --git a/dataconnect/movie/assets/firebase_logo.svg b/dataconnect/movie/assets/firebase_logo.svg
new file mode 100644
index 000000000..f7515edcb
--- /dev/null
+++ b/dataconnect/movie/assets/firebase_logo.svg
@@ -0,0 +1,6 @@
+<svg width="600" height="600" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M213.918 560.499C237.166 569.856 262.387 575.408 288.87 576.333C324.71 577.585 358.792 570.175 389.261 556.099C352.724 541.744 319.634 520.751 291.392 494.651C273.086 523.961 246.01 547.113 213.918 560.499Z" fill="#FF9100"/>
+<path d="M291.389 494.66C226.923 435.038 187.815 348.743 191.12 254.092C191.228 251.019 191.39 247.947 191.58 244.876C180.034 241.89 167.98 240.068 155.576 239.635C137.821 239.015 120.626 241.217 104.393 245.788C87.1838 275.933 76.7989 310.521 75.5051 347.569C72.1663 443.18 130.027 526.723 213.914 560.508C246.007 547.121 273.082 523.998 291.389 494.66Z" fill="#FFC400"/>
+<path d="M291.39 494.657C306.378 470.671 315.465 442.551 316.523 412.254C319.306 332.559 265.731 264.003 191.581 244.873C191.391 247.944 191.229 251.016 191.121 254.089C187.816 348.74 226.924 435.035 291.39 494.657Z" fill="#FF9100"/>
+<path d="M308.231 20.8584C266 54.6908 232.652 99.302 212.475 150.693C200.924 180.129 193.665 211.748 191.546 244.893C265.696 264.023 319.272 332.579 316.489 412.273C315.431 442.57 306.317 470.663 291.355 494.677C319.595 520.804 352.686 541.77 389.223 556.124C462.56 522.224 514.593 449.278 517.606 362.997C519.558 307.096 498.08 257.273 467.731 215.219C435.68 170.742 308.231 20.8584 308.231 20.8584Z" fill="#DD2C00"/>
+</svg>
diff --git a/dataconnect/movie/components/carousel.tsx b/dataconnect/movie/components/carousel.tsx
new file mode 100644
index 000000000..0813e6abd
--- /dev/null
+++ b/dataconnect/movie/components/carousel.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import MovieCard from './moviecard';
+
+interface CarouselProps {
+  title: string;
+  movies: {
+    id: string;
+    title?: string;
+    imageUrl?: string;
+    rating?: number;
+    genre?: string;
+    tags?: string[];
+  }[];
+}
+
+const Carousel: React.FC<CarouselProps> = ({ title, movies }) => {
+  return (
+    <section className="carousel py-8">
+      <h2 className="text-gray-200 text-2xl font-bold mb-4">{title}</h2>
+      <div className="carousel__container flex overflow-x-auto space-x-4">
+        {movies.map((movie) => (
+          <div className="flex-shrink-0" key={movie.id}>
+            <MovieCard
+              id={movie.id}
+              title={movie.title}
+              imageUrl={movie.imageUrl}
+              rating={movie.rating}
+              genre={movie.genre}
+              tags={movie.tags}
+            />
+          </div>
+        ))}
+      </div>
+    </section>
+  );
+};
+
+export default Carousel;
diff --git a/dataconnect/movie/components/moviecard.tsx b/dataconnect/movie/components/moviecard.tsx
new file mode 100644
index 000000000..2f1d83b26
--- /dev/null
+++ b/dataconnect/movie/components/moviecard.tsx
@@ -0,0 +1,144 @@
+import { useEffect, useState } from 'react';
+import Link from 'next/link';
+import { MdFavorite, MdFavoriteBorder, MdCheck, MdAdd, MdStar } from 'react-icons/md';
+import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
+import { addFavoritedMovie, deleteFavoritedMovie, addWatchedMovie, deleteWatchedMovie, getIfWatched, getIfFavoritedMovie } from '../lib/dataconnect-sdk';
+
+interface MovieCardProps {
+  id: string;
+  title: string;
+  imageUrl?: string;
+  rating?: number;
+  genre?: string;
+  tags?: string[];
+}
+
+const MovieCard: React.FC<MovieCardProps> = ({ id, title, imageUrl, rating, genre, tags }) => {
+  const [user, setUser] = useState<User | null>(null);
+  const [isFavorited, setIsFavorited] = useState(false);
+  const [isWatched, setIsWatched] = useState(false);
+  const auth = getAuth();
+
+  useEffect(() => {
+    const unsubscribe = onAuthStateChanged(auth, (user) => {
+      if (user) {
+        setUser(user);
+        checkIfFavorited(user.uid);
+        checkIfWatched(user.uid);
+      }
+    });
+
+    return () => unsubscribe();
+  }, [auth, id]);
+
+  const checkIfFavorited = async (userId: string) => {
+    try {
+      const response = await getIfFavoritedMovie({ id: userId, movieId: id });
+      setIsFavorited(!!response.data.favoriteMovie);
+    } catch (error) {
+      console.error('Error checking if favorited:', error);
+    }
+  };
+
+  const checkIfWatched = async (userId: string) => {
+    try {
+      const response = await getIfWatched({ id: userId, movieId: id });
+      setIsWatched(!!response.data.watchedMovie);
+    } catch (error) {
+      console.error('Error checking if watched:', error);
+    }
+  };
+
+  const handleFavoriteToggle = async (e: React.MouseEvent) => {
+    e.stopPropagation();
+    e.preventDefault();
+    if (!user) return;
+    try {
+      if (isFavorited) {
+        await deleteFavoritedMovie({ userId: user.uid, movieId: id });
+      } else {
+        await addFavoritedMovie({ movieId: id });
+      }
+      setIsFavorited(!isFavorited);
+    } catch (error) {
+      console.error('Error updating favorite status:', error);
+    }
+  };
+
+  const handleWatchedToggle = async (e: React.MouseEvent) => {
+    e.stopPropagation();
+    e.preventDefault();
+    if (!user) return;
+    try {
+      if (isWatched) {
+        await deleteWatchedMovie({ userId: user.uid, movieId: id });
+      } else {
+        await addWatchedMovie({ movieId: id });
+      }
+      setIsWatched(!isWatched);
+    } catch (error) {
+      console.error('Error updating watched status:', error);
+    }
+  };
+
+  const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
+
+  return (
+    <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-1000 transform hover:scale-105 cursor-pointer w-64">
+      <Link href={`/movie/${id}`} passHref>
+        <div>
+          <img className="w-full h-64 object-cover" src={imageUrl} alt={title} />
+          <div className="p-4">
+            <div className="font-bold text-lg mb-1 text-white whitespace-nowrap overflow-hidden overflow-ellipsis">{title}</div>
+            <div className="flex items-center text-yellow-500">
+              <MdStar className="text-yellow-500" size={20} />
+              <span className="ml-1 text-gray-400">{rating}</span>
+            </div>
+            <div className="mt-2 text-gray-400">
+              {genre && (
+                <Link href={`/genre/${genre.toLowerCase()}`} passHref legacyBehavior>
+                  <a className="block mb-1 hover:underline">{capitalize(genre)}</a>
+                </Link>
+              )}
+              <div className="flex flex-wrap gap-1">
+                {tags?.map((tag, index) => (
+                  <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{capitalize(tag)}</span>
+                ))}
+              </div>
+            </div>
+            {user && (
+              <div className="mt-2 flex space-x-2 items-center">
+                <button
+                  className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
+                  aria-label="Favorite"
+                  onClick={handleFavoriteToggle}
+                >
+                  {isFavorited ? <MdFavorite size={20} /> : <MdFavoriteBorder size={20} />}
+                </button>
+                <button
+                  className="flex items-center justify-center p-1 text-green-700 hover:text-green-800 transition-colors duration-200"
+                  aria-label="Watched"
+                  onClick={handleWatchedToggle}
+                >
+                  {isWatched ? (
+                    <>
+                      <MdCheck size={20} />
+                      <span className="ml-1 text-sm">Watched</span>
+                    </>
+                  ) : (
+                    <>
+                      <MdAdd size={20} />
+                      <span className="ml-1 text-sm">Add to watchlist</span>
+                    </>
+                  )}
+                </button>
+              </div>
+            )}
+          </div>
+        </div>
+      </Link>
+    </div>
+  );
+};
+
+export default MovieCard;
diff --git a/dataconnect/movie/components/navbar.tsx b/dataconnect/movie/components/navbar.tsx
new file mode 100644
index 000000000..fd3b5827e
--- /dev/null
+++ b/dataconnect/movie/components/navbar.tsx
@@ -0,0 +1,97 @@
+import { useEffect, useState } from 'react';
+import { getAuth, signInWithRedirect, GoogleAuthProvider, signOut, User } from 'firebase/auth';
+import { firebaseapp, onAuthStateChanged } from '../lib/firebase';
+import Link from 'next/link';
+import { useRouter } from 'next/navigation';
+import { upsertUser } from '../lib/dataconnect-sdk';
+import { FaSearch } from 'react-icons/fa';
+import Image from 'next/image';
+import firebaseLogo from '../assets/firebase_logo.svg';
+
+const Navbar = () => {
+  const [user, setUser] = useState<User | null>(null);
+  const auth = getAuth(firebaseapp);
+  const router = useRouter();
+
+  useEffect(() => {
+    const unsubscribe = onAuthStateChanged(auth, async (user) => {
+      if (user) {
+        setUser(user);
+        const username = user.email.substring(0, user.email.indexOf("@"));
+        await upsertUser({ username });
+      } else {
+        setUser(null);
+      }
+    });
+    return () => unsubscribe();
+  }, [auth]);
+
+  const handleSignIn = async () => {
+    const provider = new GoogleAuthProvider();
+    await signInWithRedirect(auth, provider);
+  };
+
+  const handleSignOut = async () => {
+    await signOut(auth);
+  };
+
+  return (
+    <nav className="bg-black p-4">
+      <div className="container mx-auto flex justify-between items-center">
+        <div className="flex items-center space-x-4">
+          <Link href="/" className="flex items-center text-white text-lg font-bold">
+            <Image src={firebaseLogo} alt="Firebase Logo" width={30} height={30} className="mr-2" />
+            FriendlyMovies
+          </Link>
+          <div className="relative group">
+            <button className="text-gray-200 hover:text-white">Genres</button>
+            <div className="absolute hidden group-hover:block bg-black text-white mt-1 rounded shadow-lg" style={{ minWidth: '150px' }}>
+              <div className="py-2">
+                <Link href="/genre/action" className="block px-4 py-2 hover:bg-gray-800">
+                  Action
+                </Link>
+                <Link href="/genre/crime" className="block px-4 py-2 hover:bg-gray-800">
+                  Crime
+                </Link>
+                <Link href="/genre/drama" className="block px-4 py-2 hover:bg-gray-800">
+                  Drama
+                </Link>
+                <Link href="/genre/sci-fi" className="block px-4 py-2 hover:bg-gray-800">
+                  Sci-Fi
+                </Link>
+              </div>
+            </div>
+          </div>
+          <Link href="/vectors" className="text-gray-200 hover:text-white">
+            Vector Search
+          </Link>
+        </div>
+        <Link href="/advancedsearch" className="flex items-center text-gray-200 hover:text-white mx-auto">
+          <FaSearch className="mr-2" />
+          Advanced Search
+        </Link>
+        <div className="flex items-center space-x-4">
+          {user && (
+            <Link href="/myprofile" className="text-yellow-500 hover:text-yellow-400">
+              My Profile
+            </Link>
+          )}
+          {user ? (
+            <>
+              <span className="text-gray-200 mr-4">Hello, {user.displayName}</span>
+              <button onClick={handleSignOut} className="text-gray-200 hover:text-white">
+                Sign Out
+              </button>
+            </>
+          ) : (
+            <button onClick={handleSignIn} className="text-gray-200 hover:text-white">
+              Sign In with Google
+            </button>
+          )}
+        </div>
+      </div>
+    </nav>
+  );
+};
+
+export default Navbar;
diff --git a/dataconnect/movie/lib/dataconnect-sdk/esm/index.esm.js b/dataconnect/movie/lib/dataconnect-sdk/esm/index.esm.js
new file mode 100644
index 000000000..c25a275f7
--- /dev/null
+++ b/dataconnect/movie/lib/dataconnect-sdk/esm/index.esm.js
@@ -0,0 +1,318 @@
+import { getDataConnect, queryRef, executeQuery, mutationRef, executeMutation } from 'firebase/data-connect';
+
+export const connectorConfig = {
+  connector: 'movie-connector',
+  service: 'dataconnect',
+  location: 'us-central1'
+};
+
+export function createMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'createMovie', inputVars);
+}
+export function createMovie(dcOrVars, vars) {
+  return executeMutation(createMovieRef(dcOrVars, vars));
+}
+export function updateMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'updateMovie', inputVars);
+}
+export function updateMovie(dcOrVars, vars) {
+  return executeMutation(updateMovieRef(dcOrVars, vars));
+}
+export function deleteMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteMovie', inputVars);
+}
+export function deleteMovie(dcOrVars, vars) {
+  return executeMutation(deleteMovieRef(dcOrVars, vars));
+}
+export function deleteUnpopularMoviesRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteUnpopularMovies', inputVars);
+}
+export function deleteUnpopularMovies(dcOrVars, vars) {
+  return executeMutation(deleteUnpopularMoviesRef(dcOrVars, vars));
+}
+export function addWatchedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'addWatchedMovie', inputVars);
+}
+export function addWatchedMovie(dcOrVars, vars) {
+  return executeMutation(addWatchedMovieRef(dcOrVars, vars));
+}
+export function deleteWatchedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteWatchedMovie', inputVars);
+}
+export function deleteWatchedMovie(dcOrVars, vars) {
+  return executeMutation(deleteWatchedMovieRef(dcOrVars, vars));
+}
+export function addFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'addFavoritedMovie', inputVars);
+}
+export function addFavoritedMovie(dcOrVars, vars) {
+  return executeMutation(addFavoritedMovieRef(dcOrVars, vars));
+}
+export function deleteFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteFavoritedMovie', inputVars);
+}
+export function deleteFavoritedMovie(dcOrVars, vars) {
+  return executeMutation(deleteFavoritedMovieRef(dcOrVars, vars));
+}
+export function addFavoritedActorRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'addFavoritedActor', inputVars);
+}
+export function addFavoritedActor(dcOrVars, vars) {
+  return executeMutation(addFavoritedActorRef(dcOrVars, vars));
+}
+export function deleteFavoriteActorRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteFavoriteActor', inputVars);
+}
+export function deleteFavoriteActor(dcOrVars, vars) {
+  return executeMutation(deleteFavoriteActorRef(dcOrVars, vars));
+}
+export function addReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'addReview', inputVars);
+}
+export function addReview(dcOrVars, vars) {
+  return executeMutation(addReviewRef(dcOrVars, vars));
+}
+export function deleteReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteReview', inputVars);
+}
+export function deleteReview(dcOrVars, vars) {
+  return executeMutation(deleteReviewRef(dcOrVars, vars));
+}
+export function upsertUserRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'upsertUser', inputVars);
+}
+export function upsertUser(dcOrVars, vars) {
+  return executeMutation(upsertUserRef(dcOrVars, vars));
+}
+export function listMoviesRef(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'ListMovies');
+}
+export function listMovies(dc) {
+  return executeQuery(listMoviesRef(dc));
+}
+export function listUsersRef(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'ListUsers');
+}
+export function listUsers(dc) {
+  return executeQuery(listUsersRef(dc));
+}
+export function listMoviesByGenreRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'ListMoviesByGenre', inputVars);
+}
+export function listMoviesByGenre(dcOrVars, vars) {
+  return executeQuery(listMoviesByGenreRef(dcOrVars, vars));
+}
+export function listMoviesByReleaseYearRef(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'ListMoviesByReleaseYear');
+}
+export function listMoviesByReleaseYear(dc) {
+  return executeQuery(listMoviesByReleaseYearRef(dc));
+}
+export function getMovieByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetMovieById', inputVars);
+}
+export function getMovieById(dcOrVars, vars) {
+  return executeQuery(getMovieByIdRef(dcOrVars, vars));
+}
+export function getActorByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetActorById', inputVars);
+}
+export function getActorById(dcOrVars, vars) {
+  return executeQuery(getActorByIdRef(dcOrVars, vars));
+}
+export function userMoviePreferencesRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'UserMoviePreferences', inputVars);
+}
+export function userMoviePreferences(dcOrVars, vars) {
+  return executeQuery(userMoviePreferencesRef(dcOrVars, vars));
+}
+export function getMovieMetadataRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetMovieMetadata', inputVars);
+}
+export function getMovieMetadata(dcOrVars, vars) {
+  return executeQuery(getMovieMetadataRef(dcOrVars, vars));
+}
+export function getMovieCastRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetMovieCast', inputVars);
+}
+export function getMovieCast(dcOrVars, vars) {
+  return executeQuery(getMovieCastRef(dcOrVars, vars));
+}
+export function listMoviesByPartialTitleRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'ListMoviesByPartialTitle', inputVars);
+}
+export function listMoviesByPartialTitle(dcOrVars, vars) {
+  return executeQuery(listMoviesByPartialTitleRef(dcOrVars, vars));
+}
+export function movieByKeyRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'MovieByKey', inputVars);
+}
+export function movieByKey(dcOrVars, vars) {
+  return executeQuery(movieByKeyRef(dcOrVars, vars));
+}
+export function movieByTitleRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'MovieByTitle', inputVars);
+}
+export function movieByTitle(dcOrVars, vars) {
+  return executeQuery(movieByTitleRef(dcOrVars, vars));
+}
+export function movieByTopRatingRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
+  return queryRef(dcInstance, 'MovieByTopRating', inputVars);
+}
+export function movieByTopRating(dcOrVars, vars) {
+  return executeQuery(movieByTopRatingRef(dcOrVars, vars));
+}
+export function listMoviesByTagRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'ListMoviesByTag', inputVars);
+}
+export function listMoviesByTag(dcOrVars, vars) {
+  return executeQuery(listMoviesByTagRef(dcOrVars, vars));
+}
+export function moviesTop10Ref(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'MoviesTop10');
+}
+export function moviesTop10(dc) {
+  return executeQuery(moviesTop10Ref(dc));
+}
+export function moviesByReleaseYearRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
+  return queryRef(dcInstance, 'MoviesByReleaseYear', inputVars);
+}
+export function moviesByReleaseYear(dcOrVars, vars) {
+  return executeQuery(moviesByReleaseYearRef(dcOrVars, vars));
+}
+export function moviesRecentlyReleasedRef(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'MoviesRecentlyReleased');
+}
+export function moviesRecentlyReleased(dc) {
+  return executeQuery(moviesRecentlyReleasedRef(dc));
+}
+export function listMoviesFilterRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
+  return queryRef(dcInstance, 'ListMoviesFilter', inputVars);
+}
+export function listMoviesFilter(dcOrVars, vars) {
+  return executeQuery(listMoviesFilterRef(dcOrVars, vars));
+}
+export function listMoviesByTitleStringRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
+  return queryRef(dcInstance, 'ListMoviesByTitleString', inputVars);
+}
+export function listMoviesByTitleString(dcOrVars, vars) {
+  return executeQuery(listMoviesByTitleStringRef(dcOrVars, vars));
+}
+export function listMoviesByRatingAndGenreRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'ListMoviesByRatingAndGenre', inputVars);
+}
+export function listMoviesByRatingAndGenre(dcOrVars, vars) {
+  return executeQuery(listMoviesByRatingAndGenreRef(dcOrVars, vars));
+}
+export function getFavoriteMoviesByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetFavoriteMoviesById', inputVars);
+}
+export function getFavoriteMoviesById(dcOrVars, vars) {
+  return executeQuery(getFavoriteMoviesByIdRef(dcOrVars, vars));
+}
+export function getFavoriteActorsByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetFavoriteActorsById', inputVars);
+}
+export function getFavoriteActorsById(dcOrVars, vars) {
+  return executeQuery(getFavoriteActorsByIdRef(dcOrVars, vars));
+}
+export function getWatchedMoviesByAuthIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetWatchedMoviesByAuthId', inputVars);
+}
+export function getWatchedMoviesByAuthId(dcOrVars, vars) {
+  return executeQuery(getWatchedMoviesByAuthIdRef(dcOrVars, vars));
+}
+export function getUserByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetUserById', inputVars);
+}
+export function getUserById(dcOrVars, vars) {
+  return executeQuery(getUserByIdRef(dcOrVars, vars));
+}
+export function getIfWatchedRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetIfWatched', inputVars);
+}
+export function getIfWatched(dcOrVars, vars) {
+  return executeQuery(getIfWatchedRef(dcOrVars, vars));
+}
+export function getIfFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetIfFavoritedMovie', inputVars);
+}
+export function getIfFavoritedMovie(dcOrVars, vars) {
+  return executeQuery(getIfFavoritedMovieRef(dcOrVars, vars));
+}
+export function getIfFavoritedActorRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetIfFavoritedActor', inputVars);
+}
+export function getIfFavoritedActor(dcOrVars, vars) {
+  return executeQuery(getIfFavoritedActorRef(dcOrVars, vars));
+}
+export function fuzzySearchRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'fuzzySearch', inputVars);
+}
+export function fuzzySearch(dcOrVars, vars) {
+  return executeQuery(fuzzySearchRef(dcOrVars, vars));
+}
+export function searchMovieDescriptionUsingL2similarityRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'searchMovieDescriptionUsingL2Similarity', inputVars);
+}
+export function searchMovieDescriptionUsingL2similarity(dcOrVars, vars) {
+  return executeQuery(searchMovieDescriptionUsingL2similarityRef(dcOrVars, vars));
+}
+function validateArgs(dcOrVars, vars, validateVars) {
+  let dcInstance;
+  let realVars;
+  // TODO; Check what happens if this is undefined.
+  if(dcOrVars && 'dataConnectOptions' in dcOrVars) {
+      dcInstance = dcOrVars;
+      realVars = vars;
+  } else {
+      dcInstance = getDataConnect(connectorConfig);
+      realVars = dcOrVars;
+  }
+  if(!dcInstance || (!realVars && validateVars)) {
+      throw new Error('You didn\t pass in the vars!');
+  }
+  return { dc: dcInstance, vars: realVars };
+}
\ No newline at end of file
diff --git a/dataconnect/movie/lib/dataconnect-sdk/esm/package.json b/dataconnect/movie/lib/dataconnect-sdk/esm/package.json
new file mode 100644
index 000000000..7c34deb58
--- /dev/null
+++ b/dataconnect/movie/lib/dataconnect-sdk/esm/package.json
@@ -0,0 +1 @@
+{"type":"module"}
\ No newline at end of file
diff --git a/dataconnect/movie/lib/dataconnect-sdk/index.cjs.js b/dataconnect/movie/lib/dataconnect-sdk/index.cjs.js
new file mode 100644
index 000000000..6e6fb47cd
--- /dev/null
+++ b/dataconnect/movie/lib/dataconnect-sdk/index.cjs.js
@@ -0,0 +1,403 @@
+const { getDataConnect, queryRef, executeQuery, mutationRef, executeMutation } = require('firebase/data-connect');
+
+const connectorConfig = {
+  connector: 'movie-connector',
+  service: 'dataconnect',
+  location: 'us-central1'
+};
+exports.connectorConfig = connectorConfig;
+
+function createMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'createMovie', inputVars);
+}
+exports.createMovieRef = createMovieRef;
+exports.createMovie = function createMovie(dcOrVars, vars) {
+  return executeMutation(createMovieRef(dcOrVars, vars));
+};
+
+function updateMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'updateMovie', inputVars);
+}
+exports.updateMovieRef = updateMovieRef;
+exports.updateMovie = function updateMovie(dcOrVars, vars) {
+  return executeMutation(updateMovieRef(dcOrVars, vars));
+};
+
+function deleteMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteMovie', inputVars);
+}
+exports.deleteMovieRef = deleteMovieRef;
+exports.deleteMovie = function deleteMovie(dcOrVars, vars) {
+  return executeMutation(deleteMovieRef(dcOrVars, vars));
+};
+
+function deleteUnpopularMoviesRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteUnpopularMovies', inputVars);
+}
+exports.deleteUnpopularMoviesRef = deleteUnpopularMoviesRef;
+exports.deleteUnpopularMovies = function deleteUnpopularMovies(dcOrVars, vars) {
+  return executeMutation(deleteUnpopularMoviesRef(dcOrVars, vars));
+};
+
+function addWatchedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'addWatchedMovie', inputVars);
+}
+exports.addWatchedMovieRef = addWatchedMovieRef;
+exports.addWatchedMovie = function addWatchedMovie(dcOrVars, vars) {
+  return executeMutation(addWatchedMovieRef(dcOrVars, vars));
+};
+
+function deleteWatchedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteWatchedMovie', inputVars);
+}
+exports.deleteWatchedMovieRef = deleteWatchedMovieRef;
+exports.deleteWatchedMovie = function deleteWatchedMovie(dcOrVars, vars) {
+  return executeMutation(deleteWatchedMovieRef(dcOrVars, vars));
+};
+
+function addFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'addFavoritedMovie', inputVars);
+}
+exports.addFavoritedMovieRef = addFavoritedMovieRef;
+exports.addFavoritedMovie = function addFavoritedMovie(dcOrVars, vars) {
+  return executeMutation(addFavoritedMovieRef(dcOrVars, vars));
+};
+
+function deleteFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteFavoritedMovie', inputVars);
+}
+exports.deleteFavoritedMovieRef = deleteFavoritedMovieRef;
+exports.deleteFavoritedMovie = function deleteFavoritedMovie(dcOrVars, vars) {
+  return executeMutation(deleteFavoritedMovieRef(dcOrVars, vars));
+};
+
+function addFavoritedActorRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'addFavoritedActor', inputVars);
+}
+exports.addFavoritedActorRef = addFavoritedActorRef;
+exports.addFavoritedActor = function addFavoritedActor(dcOrVars, vars) {
+  return executeMutation(addFavoritedActorRef(dcOrVars, vars));
+};
+
+function deleteFavoriteActorRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteFavoriteActor', inputVars);
+}
+exports.deleteFavoriteActorRef = deleteFavoriteActorRef;
+exports.deleteFavoriteActor = function deleteFavoriteActor(dcOrVars, vars) {
+  return executeMutation(deleteFavoriteActorRef(dcOrVars, vars));
+};
+
+function addReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'addReview', inputVars);
+}
+exports.addReviewRef = addReviewRef;
+exports.addReview = function addReview(dcOrVars, vars) {
+  return executeMutation(addReviewRef(dcOrVars, vars));
+};
+
+function deleteReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'deleteReview', inputVars);
+}
+exports.deleteReviewRef = deleteReviewRef;
+exports.deleteReview = function deleteReview(dcOrVars, vars) {
+  return executeMutation(deleteReviewRef(dcOrVars, vars));
+};
+
+function upsertUserRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return mutationRef(dcInstance, 'upsertUser', inputVars);
+}
+exports.upsertUserRef = upsertUserRef;
+exports.upsertUser = function upsertUser(dcOrVars, vars) {
+  return executeMutation(upsertUserRef(dcOrVars, vars));
+};
+
+function listMoviesRef(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'ListMovies');
+}
+exports.listMoviesRef = listMoviesRef;
+exports.listMovies = function listMovies(dc) {
+  return executeQuery(listMoviesRef(dc));
+};
+
+function listUsersRef(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'ListUsers');
+}
+exports.listUsersRef = listUsersRef;
+exports.listUsers = function listUsers(dc) {
+  return executeQuery(listUsersRef(dc));
+};
+
+function listMoviesByGenreRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'ListMoviesByGenre', inputVars);
+}
+exports.listMoviesByGenreRef = listMoviesByGenreRef;
+exports.listMoviesByGenre = function listMoviesByGenre(dcOrVars, vars) {
+  return executeQuery(listMoviesByGenreRef(dcOrVars, vars));
+};
+
+function listMoviesByReleaseYearRef(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'ListMoviesByReleaseYear');
+}
+exports.listMoviesByReleaseYearRef = listMoviesByReleaseYearRef;
+exports.listMoviesByReleaseYear = function listMoviesByReleaseYear(dc) {
+  return executeQuery(listMoviesByReleaseYearRef(dc));
+};
+
+function getMovieByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetMovieById', inputVars);
+}
+exports.getMovieByIdRef = getMovieByIdRef;
+exports.getMovieById = function getMovieById(dcOrVars, vars) {
+  return executeQuery(getMovieByIdRef(dcOrVars, vars));
+};
+
+function getActorByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetActorById', inputVars);
+}
+exports.getActorByIdRef = getActorByIdRef;
+exports.getActorById = function getActorById(dcOrVars, vars) {
+  return executeQuery(getActorByIdRef(dcOrVars, vars));
+};
+
+function userMoviePreferencesRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'UserMoviePreferences', inputVars);
+}
+exports.userMoviePreferencesRef = userMoviePreferencesRef;
+exports.userMoviePreferences = function userMoviePreferences(dcOrVars, vars) {
+  return executeQuery(userMoviePreferencesRef(dcOrVars, vars));
+};
+
+function getMovieMetadataRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetMovieMetadata', inputVars);
+}
+exports.getMovieMetadataRef = getMovieMetadataRef;
+exports.getMovieMetadata = function getMovieMetadata(dcOrVars, vars) {
+  return executeQuery(getMovieMetadataRef(dcOrVars, vars));
+};
+
+function getMovieCastRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetMovieCast', inputVars);
+}
+exports.getMovieCastRef = getMovieCastRef;
+exports.getMovieCast = function getMovieCast(dcOrVars, vars) {
+  return executeQuery(getMovieCastRef(dcOrVars, vars));
+};
+
+function listMoviesByPartialTitleRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'ListMoviesByPartialTitle', inputVars);
+}
+exports.listMoviesByPartialTitleRef = listMoviesByPartialTitleRef;
+exports.listMoviesByPartialTitle = function listMoviesByPartialTitle(dcOrVars, vars) {
+  return executeQuery(listMoviesByPartialTitleRef(dcOrVars, vars));
+};
+
+function movieByKeyRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'MovieByKey', inputVars);
+}
+exports.movieByKeyRef = movieByKeyRef;
+exports.movieByKey = function movieByKey(dcOrVars, vars) {
+  return executeQuery(movieByKeyRef(dcOrVars, vars));
+};
+
+function movieByTitleRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'MovieByTitle', inputVars);
+}
+exports.movieByTitleRef = movieByTitleRef;
+exports.movieByTitle = function movieByTitle(dcOrVars, vars) {
+  return executeQuery(movieByTitleRef(dcOrVars, vars));
+};
+
+function movieByTopRatingRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
+  return queryRef(dcInstance, 'MovieByTopRating', inputVars);
+}
+exports.movieByTopRatingRef = movieByTopRatingRef;
+exports.movieByTopRating = function movieByTopRating(dcOrVars, vars) {
+  return executeQuery(movieByTopRatingRef(dcOrVars, vars));
+};
+
+function listMoviesByTagRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'ListMoviesByTag', inputVars);
+}
+exports.listMoviesByTagRef = listMoviesByTagRef;
+exports.listMoviesByTag = function listMoviesByTag(dcOrVars, vars) {
+  return executeQuery(listMoviesByTagRef(dcOrVars, vars));
+};
+
+function moviesTop10Ref(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'MoviesTop10');
+}
+exports.moviesTop10Ref = moviesTop10Ref;
+exports.moviesTop10 = function moviesTop10(dc) {
+  return executeQuery(moviesTop10Ref(dc));
+};
+
+function moviesByReleaseYearRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
+  return queryRef(dcInstance, 'MoviesByReleaseYear', inputVars);
+}
+exports.moviesByReleaseYearRef = moviesByReleaseYearRef;
+exports.moviesByReleaseYear = function moviesByReleaseYear(dcOrVars, vars) {
+  return executeQuery(moviesByReleaseYearRef(dcOrVars, vars));
+};
+
+function moviesRecentlyReleasedRef(dc) {
+  const { dc: dcInstance} = validateArgs(dc, undefined);
+  return queryRef(dcInstance, 'MoviesRecentlyReleased');
+}
+exports.moviesRecentlyReleasedRef = moviesRecentlyReleasedRef;
+exports.moviesRecentlyReleased = function moviesRecentlyReleased(dc) {
+  return executeQuery(moviesRecentlyReleasedRef(dc));
+};
+
+function listMoviesFilterRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
+  return queryRef(dcInstance, 'ListMoviesFilter', inputVars);
+}
+exports.listMoviesFilterRef = listMoviesFilterRef;
+exports.listMoviesFilter = function listMoviesFilter(dcOrVars, vars) {
+  return executeQuery(listMoviesFilterRef(dcOrVars, vars));
+};
+
+function listMoviesByTitleStringRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
+  return queryRef(dcInstance, 'ListMoviesByTitleString', inputVars);
+}
+exports.listMoviesByTitleStringRef = listMoviesByTitleStringRef;
+exports.listMoviesByTitleString = function listMoviesByTitleString(dcOrVars, vars) {
+  return executeQuery(listMoviesByTitleStringRef(dcOrVars, vars));
+};
+
+function listMoviesByRatingAndGenreRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'ListMoviesByRatingAndGenre', inputVars);
+}
+exports.listMoviesByRatingAndGenreRef = listMoviesByRatingAndGenreRef;
+exports.listMoviesByRatingAndGenre = function listMoviesByRatingAndGenre(dcOrVars, vars) {
+  return executeQuery(listMoviesByRatingAndGenreRef(dcOrVars, vars));
+};
+
+function getFavoriteMoviesByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetFavoriteMoviesById', inputVars);
+}
+exports.getFavoriteMoviesByIdRef = getFavoriteMoviesByIdRef;
+exports.getFavoriteMoviesById = function getFavoriteMoviesById(dcOrVars, vars) {
+  return executeQuery(getFavoriteMoviesByIdRef(dcOrVars, vars));
+};
+
+function getFavoriteActorsByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetFavoriteActorsById', inputVars);
+}
+exports.getFavoriteActorsByIdRef = getFavoriteActorsByIdRef;
+exports.getFavoriteActorsById = function getFavoriteActorsById(dcOrVars, vars) {
+  return executeQuery(getFavoriteActorsByIdRef(dcOrVars, vars));
+};
+
+function getWatchedMoviesByAuthIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetWatchedMoviesByAuthId', inputVars);
+}
+exports.getWatchedMoviesByAuthIdRef = getWatchedMoviesByAuthIdRef;
+exports.getWatchedMoviesByAuthId = function getWatchedMoviesByAuthId(dcOrVars, vars) {
+  return executeQuery(getWatchedMoviesByAuthIdRef(dcOrVars, vars));
+};
+
+function getUserByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetUserById', inputVars);
+}
+exports.getUserByIdRef = getUserByIdRef;
+exports.getUserById = function getUserById(dcOrVars, vars) {
+  return executeQuery(getUserByIdRef(dcOrVars, vars));
+};
+
+function getIfWatchedRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetIfWatched', inputVars);
+}
+exports.getIfWatchedRef = getIfWatchedRef;
+exports.getIfWatched = function getIfWatched(dcOrVars, vars) {
+  return executeQuery(getIfWatchedRef(dcOrVars, vars));
+};
+
+function getIfFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetIfFavoritedMovie', inputVars);
+}
+exports.getIfFavoritedMovieRef = getIfFavoritedMovieRef;
+exports.getIfFavoritedMovie = function getIfFavoritedMovie(dcOrVars, vars) {
+  return executeQuery(getIfFavoritedMovieRef(dcOrVars, vars));
+};
+
+function getIfFavoritedActorRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'GetIfFavoritedActor', inputVars);
+}
+exports.getIfFavoritedActorRef = getIfFavoritedActorRef;
+exports.getIfFavoritedActor = function getIfFavoritedActor(dcOrVars, vars) {
+  return executeQuery(getIfFavoritedActorRef(dcOrVars, vars));
+};
+
+function fuzzySearchRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'fuzzySearch', inputVars);
+}
+exports.fuzzySearchRef = fuzzySearchRef;
+exports.fuzzySearch = function fuzzySearch(dcOrVars, vars) {
+  return executeQuery(fuzzySearchRef(dcOrVars, vars));
+};
+
+function searchMovieDescriptionUsingL2similarityRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
+  return queryRef(dcInstance, 'searchMovieDescriptionUsingL2Similarity', inputVars);
+}
+exports.searchMovieDescriptionUsingL2similarityRef = searchMovieDescriptionUsingL2similarityRef;
+exports.searchMovieDescriptionUsingL2similarity = function searchMovieDescriptionUsingL2similarity(dcOrVars, vars) {
+  return executeQuery(searchMovieDescriptionUsingL2similarityRef(dcOrVars, vars));
+};
+
+function validateArgs(dcOrVars, vars, validateVars) {
+  let dcInstance;
+  let realVars;
+  // TODO; Check what happens if this is undefined.
+  if(dcOrVars && 'dataConnectOptions' in dcOrVars) {
+      dcInstance = dcOrVars;
+      realVars = vars;
+  } else {
+      dcInstance = getDataConnect(connectorConfig);
+      realVars = dcOrVars;
+  }
+  if(!dcInstance || (!realVars && validateVars)) {
+      throw new Error('You didn\t pass in the vars!');
+  }
+  return { dc: dcInstance, vars: realVars };
+}
\ No newline at end of file
diff --git a/dataconnect/movie/lib/dataconnect-sdk/index.d.ts b/dataconnect/movie/lib/dataconnect-sdk/index.d.ts
new file mode 100644
index 000000000..519c7186c
--- /dev/null
+++ b/dataconnect/movie/lib/dataconnect-sdk/index.d.ts
@@ -0,0 +1,1144 @@
+import { ConnectorConfig, DataConnect, QueryRef, QueryPromise, MutationRef, MutationPromise } from 'firebase/data-connect';
+export const connectorConfig: ConnectorConfig;
+
+export type TimestampString = string;
+
+export type UUIDString = string;
+
+export type Int64String = string;
+
+export type DateString = string;
+
+
+export interface Actor_Key {
+  id: UUIDString;
+  __typename?: 'Actor_Key';
+}
+
+export interface AddFavoritedActorResponse {
+  favoriteActor_upsert: FavoriteActor_Key;
+}
+
+export interface AddFavoritedActorVariables {
+  actorId: UUIDString;
+}
+
+export interface AddFavoritedMovieResponse {
+  favoriteMovie_upsert: FavoriteMovie_Key;
+}
+
+export interface AddFavoritedMovieVariables {
+  movieId: UUIDString;
+}
+
+export interface AddReviewResponse {
+  review_upsert: Review_Key;
+}
+
+export interface AddReviewVariables {
+  movieId: UUIDString;
+  rating: number;
+  reviewText: string;
+}
+
+export interface AddWatchedMovieResponse {
+  watchedMovie_upsert: WatchedMovie_Key;
+}
+
+export interface AddWatchedMovieVariables {
+  movieId: UUIDString;
+}
+
+export interface CreateMovieResponse {
+  movie_insert: Movie_Key;
+}
+
+export interface CreateMovieVariables {
+  title: string;
+  releaseYear: number;
+  genre: string;
+  rating?: number | null;
+  description?: string | null;
+  imageUrl: string;
+  tags?: string[] | null;
+}
+
+export interface DeleteFavoriteActorResponse {
+  favoriteActor_delete?: FavoriteActor_Key | null;
+}
+
+export interface DeleteFavoriteActorVariables {
+  userId: string;
+  actorId: UUIDString;
+}
+
+export interface DeleteFavoritedMovieResponse {
+  favoriteMovie_delete?: FavoriteMovie_Key | null;
+}
+
+export interface DeleteFavoritedMovieVariables {
+  userId: string;
+  movieId: UUIDString;
+}
+
+export interface DeleteMovieResponse {
+  movie_delete?: Movie_Key | null;
+}
+
+export interface DeleteMovieVariables {
+  id: UUIDString;
+}
+
+export interface DeleteReviewResponse {
+  review_delete?: Review_Key | null;
+}
+
+export interface DeleteReviewVariables {
+  movieId: UUIDString;
+  userId: string;
+}
+
+export interface DeleteUnpopularMoviesResponse {
+  movie_deleteMany: number;
+}
+
+export interface DeleteUnpopularMoviesVariables {
+  minRating: number;
+}
+
+export interface DeleteWatchedMovieResponse {
+  watchedMovie_delete?: WatchedMovie_Key | null;
+}
+
+export interface DeleteWatchedMovieVariables {
+  userId: string;
+  movieId: UUIDString;
+}
+
+export interface FavoriteActor_Key {
+  userId: string;
+  actorId: UUIDString;
+  __typename?: 'FavoriteActor_Key';
+}
+
+export interface FavoriteMovie_Key {
+  userId: string;
+  movieId: UUIDString;
+  __typename?: 'FavoriteMovie_Key';
+}
+
+export interface FuzzySearchResponse {
+  moviesMatchingTitle: ({
+    id: UUIDString;
+    title: string;
+    genre?: string | null;
+    rating?: number | null;
+    imageUrl: string;
+  } & Movie_Key)[];
+    moviesMatchingDescription: ({
+      id: UUIDString;
+      title: string;
+      genre?: string | null;
+      rating?: number | null;
+      imageUrl: string;
+    } & Movie_Key)[];
+      actorsMatchingName: ({
+        id: UUIDString;
+        name: string;
+        imageUrl: string;
+      } & Actor_Key)[];
+        reviewsMatchingText: ({
+          id: UUIDString;
+          rating?: number | null;
+          reviewText?: string | null;
+          reviewDate: DateString;
+          movie: {
+            id: UUIDString;
+            title: string;
+          } & Movie_Key;
+            user: {
+              id: string;
+              username: string;
+            } & User_Key;
+        })[];
+}
+
+export interface FuzzySearchVariables {
+  input?: string | null;
+  minYear: number;
+  maxYear: number;
+  minRating: number;
+  maxRating: number;
+  genre: string;
+}
+
+export interface GetActorByIdResponse {
+  actor?: {
+    id: UUIDString;
+    name: string;
+    imageUrl: string;
+    biography?: string | null;
+    mainActors: ({
+      id: UUIDString;
+      title: string;
+      genre?: string | null;
+      tags?: string[] | null;
+      imageUrl: string;
+    } & Movie_Key)[];
+      supportingActors: ({
+        id: UUIDString;
+        title: string;
+        genre?: string | null;
+        tags?: string[] | null;
+        imageUrl: string;
+      } & Movie_Key)[];
+  } & Actor_Key;
+}
+
+export interface GetActorByIdVariables {
+  id: UUIDString;
+}
+
+export interface GetFavoriteActorsByIdResponse {
+  user?: {
+    favoriteActors_on_user: ({
+      actor: {
+        id: UUIDString;
+        name: string;
+        imageUrl: string;
+      } & Actor_Key;
+    })[];
+  };
+}
+
+export interface GetFavoriteActorsByIdVariables {
+  id: string;
+}
+
+export interface GetFavoriteMoviesByIdResponse {
+  user?: {
+    favoriteMovies_on_user: ({
+      movie: {
+        id: UUIDString;
+        title: string;
+        genre?: string | null;
+        imageUrl: string;
+        releaseYear?: number | null;
+        rating?: number | null;
+        description?: string | null;
+      } & Movie_Key;
+    })[];
+  };
+}
+
+export interface GetFavoriteMoviesByIdVariables {
+  id: string;
+}
+
+export interface GetIfFavoritedActorResponse {
+  favoriteActor?: {
+    actorId: UUIDString;
+  };
+}
+
+export interface GetIfFavoritedActorVariables {
+  id: string;
+  actorId: UUIDString;
+}
+
+export interface GetIfFavoritedMovieResponse {
+  favoriteMovie?: {
+    movieId: UUIDString;
+  };
+}
+
+export interface GetIfFavoritedMovieVariables {
+  id: string;
+  movieId: UUIDString;
+}
+
+export interface GetIfWatchedResponse {
+  watchedMovie?: {
+    movieId: UUIDString;
+  };
+}
+
+export interface GetIfWatchedVariables {
+  id: string;
+  movieId: UUIDString;
+}
+
+export interface GetMovieByIdResponse {
+  movie?: {
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+    releaseYear?: number | null;
+    genre?: string | null;
+    rating?: number | null;
+    description?: string | null;
+    tags?: string[] | null;
+    metadata: ({
+      director?: string | null;
+    })[];
+      mainActors: ({
+        id: UUIDString;
+        name: string;
+        imageUrl: string;
+      } & Actor_Key)[];
+        supportingActors: ({
+          id: UUIDString;
+          name: string;
+          imageUrl: string;
+        } & Actor_Key)[];
+          sequelTo?: {
+            id: UUIDString;
+            title: string;
+            imageUrl: string;
+          } & Movie_Key;
+            reviews: ({
+              id: UUIDString;
+              reviewText?: string | null;
+              reviewDate: DateString;
+              rating?: number | null;
+              user: {
+                id: string;
+                username: string;
+              } & User_Key;
+            })[];
+  } & Movie_Key;
+}
+
+export interface GetMovieByIdVariables {
+  id: UUIDString;
+}
+
+export interface GetMovieCastResponse {
+  movie?: {
+    mainActors: ({
+      id: UUIDString;
+      name: string;
+      imageUrl: string;
+    } & Actor_Key)[];
+      supportingActors: ({
+        id: UUIDString;
+        name: string;
+        imageUrl: string;
+      } & Actor_Key)[];
+  };
+    actor?: {
+      mainRoles: ({
+        id: UUIDString;
+        title: string;
+        imageUrl: string;
+      } & Movie_Key)[];
+        supportingRoles: ({
+          id: UUIDString;
+          title: string;
+          imageUrl: string;
+        } & Movie_Key)[];
+    };
+}
+
+export interface GetMovieCastVariables {
+  movieId: UUIDString;
+  actorId: UUIDString;
+}
+
+export interface GetMovieMetadataResponse {
+  movie?: {
+    movieMetadatas_on_movie: ({
+      director?: string | null;
+    })[];
+  };
+}
+
+export interface GetMovieMetadataVariables {
+  id: UUIDString;
+}
+
+export interface GetUserByIdResponse {
+  user?: {
+    id: string;
+    username: string;
+    reviews: ({
+      id: UUIDString;
+      rating?: number | null;
+      reviewDate: DateString;
+      reviewText?: string | null;
+      movie: {
+        id: UUIDString;
+        title: string;
+      } & Movie_Key;
+    })[];
+      watched: ({
+        movie: {
+          id: UUIDString;
+          title: string;
+          genre?: string | null;
+          imageUrl: string;
+          releaseYear?: number | null;
+          rating?: number | null;
+          description?: string | null;
+          tags?: string[] | null;
+          metadata: ({
+            director?: string | null;
+          })[];
+        } & Movie_Key;
+      })[];
+        favoriteMovies: ({
+          movie: {
+            id: UUIDString;
+            title: string;
+            genre?: string | null;
+            imageUrl: string;
+            releaseYear?: number | null;
+            rating?: number | null;
+            description?: string | null;
+            tags?: string[] | null;
+            metadata: ({
+              director?: string | null;
+            })[];
+          } & Movie_Key;
+        })[];
+          favoriteActors: ({
+            actor: {
+              id: UUIDString;
+              name: string;
+              imageUrl: string;
+            } & Actor_Key;
+          })[];
+  } & User_Key;
+}
+
+export interface GetUserByIdVariables {
+  id: string;
+}
+
+export interface GetWatchedMoviesByAuthIdResponse {
+  user?: {
+    watchedMovies_on_user: ({
+      movie: {
+        id: UUIDString;
+        title: string;
+        genre?: string | null;
+        imageUrl: string;
+        releaseYear?: number | null;
+        rating?: number | null;
+        description?: string | null;
+      } & Movie_Key;
+    })[];
+  };
+}
+
+export interface GetWatchedMoviesByAuthIdVariables {
+  id: string;
+}
+
+export interface ListMoviesByGenreResponse {
+  mostPopular: ({
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+    rating?: number | null;
+    tags?: string[] | null;
+  } & Movie_Key)[];
+    mostRecent: ({
+      id: UUIDString;
+      title: string;
+      imageUrl: string;
+      rating?: number | null;
+      tags?: string[] | null;
+    } & Movie_Key)[];
+}
+
+export interface ListMoviesByGenreVariables {
+  genre: string;
+}
+
+export interface ListMoviesByPartialTitleResponse {
+  movies: ({
+    id: UUIDString;
+    title: string;
+    genre?: string | null;
+    rating?: number | null;
+    imageUrl: string;
+  } & Movie_Key)[];
+}
+
+export interface ListMoviesByPartialTitleVariables {
+  input: string;
+}
+
+export interface ListMoviesByRatingAndGenreResponse {
+  movies: ({
+    title: string;
+    imageUrl: string;
+  })[];
+}
+
+export interface ListMoviesByRatingAndGenreVariables {
+  minRating: number;
+  genre?: string | null;
+}
+
+export interface ListMoviesByReleaseYearResponse {
+  movies: ({
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+  } & Movie_Key)[];
+}
+
+export interface ListMoviesByTagResponse {
+  movies: ({
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+    genre?: string | null;
+    rating?: number | null;
+  } & Movie_Key)[];
+}
+
+export interface ListMoviesByTagVariables {
+  tag: string;
+}
+
+export interface ListMoviesByTitleStringResponse {
+  prefixed: ({
+    title: string;
+  })[];
+    suffixed: ({
+      title: string;
+    })[];
+      contained: ({
+        title: string;
+      })[];
+}
+
+export interface ListMoviesByTitleStringVariables {
+  prefix?: string | null;
+  suffix?: string | null;
+  contained?: string | null;
+}
+
+export interface ListMoviesFilterResponse {
+  movies: ({
+    title: string;
+    imageUrl: string;
+  })[];
+}
+
+export interface ListMoviesFilterVariables {
+  genre?: string | null;
+  limit?: number | null;
+}
+
+export interface ListMoviesResponse {
+  movies: ({
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+    releaseYear?: number | null;
+    genre?: string | null;
+    rating?: number | null;
+    tags?: string[] | null;
+  } & Movie_Key)[];
+}
+
+export interface ListUsersResponse {
+  users: ({
+    id: string;
+    username: string;
+    favoriteActors_on_user: ({
+      actor: {
+        id: UUIDString;
+        name: string;
+        imageUrl: string;
+      } & Actor_Key;
+    })[];
+      favoriteMovies_on_user: ({
+        movie: {
+          id: UUIDString;
+          title: string;
+          genre?: string | null;
+          imageUrl: string;
+          tags?: string[] | null;
+        } & Movie_Key;
+      })[];
+        reviews_on_user: ({
+          id: UUIDString;
+          rating?: number | null;
+          reviewText?: string | null;
+          reviewDate: DateString;
+          movie: {
+            id: UUIDString;
+            title: string;
+          } & Movie_Key;
+        })[];
+          watchedMovies_on_user: ({
+            movie: {
+              id: UUIDString;
+              title: string;
+              genre?: string | null;
+              imageUrl: string;
+            } & Movie_Key;
+          })[];
+  } & User_Key)[];
+}
+
+export interface MovieActor_Key {
+  movieId: UUIDString;
+  actorId: UUIDString;
+  __typename?: 'MovieActor_Key';
+}
+
+export interface MovieByKeyResponse {
+  movie?: {
+    title: string;
+    imageUrl: string;
+  };
+}
+
+export interface MovieByKeyVariables {
+  key: Movie_Key;
+}
+
+export interface MovieByTitleResponse {
+  movies: ({
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+    genre?: string | null;
+    rating?: number | null;
+  } & Movie_Key)[];
+}
+
+export interface MovieByTitleVariables {
+  title: string;
+}
+
+export interface MovieByTopRatingResponse {
+  mostPopular: ({
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+    rating?: number | null;
+    tags?: string[] | null;
+  } & Movie_Key)[];
+}
+
+export interface MovieByTopRatingVariables {
+  genre?: string | null;
+}
+
+export interface MovieMetadata_Key {
+  id: UUIDString;
+  __typename?: 'MovieMetadata_Key';
+}
+
+export interface Movie_Key {
+  id: UUIDString;
+  __typename?: 'Movie_Key';
+}
+
+export interface MoviesByReleaseYearResponse {
+  movies: ({
+    id: UUIDString;
+    rating?: number | null;
+    title: string;
+    imageUrl: string;
+  } & Movie_Key)[];
+}
+
+export interface MoviesByReleaseYearVariables {
+  min?: number | null;
+  max?: number | null;
+}
+
+export interface MoviesRecentlyReleasedResponse {
+  movies: ({
+    id: UUIDString;
+    title: string;
+    rating?: number | null;
+    imageUrl: string;
+    genre?: string | null;
+    tags?: string[] | null;
+  } & Movie_Key)[];
+}
+
+export interface MoviesTop10Response {
+  movies: ({
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+    rating?: number | null;
+    genre?: string | null;
+    tags?: string[] | null;
+    metadata: ({
+      director?: string | null;
+    })[];
+      mainActors: ({
+        id: UUIDString;
+        name: string;
+        imageUrl: string;
+      } & Actor_Key)[];
+        supportingActors: ({
+          id: UUIDString;
+          name: string;
+          imageUrl: string;
+        } & Actor_Key)[];
+  } & Movie_Key)[];
+}
+
+export interface Review_Key {
+  userId: string;
+  movieId: UUIDString;
+  __typename?: 'Review_Key';
+}
+
+export interface SearchMovieDescriptionUsingL2similarityResponse {
+  movies_descriptionEmbedding_similarity: ({
+    id: UUIDString;
+    title: string;
+    description?: string | null;
+    tags?: string[] | null;
+    rating?: number | null;
+    imageUrl: string;
+  } & Movie_Key)[];
+}
+
+export interface SearchMovieDescriptionUsingL2similarityVariables {
+  query: string;
+}
+
+export interface UpdateMovieResponse {
+  movie_update?: Movie_Key | null;
+}
+
+export interface UpdateMovieVariables {
+  id: UUIDString;
+  title?: string | null;
+  releaseYear?: number | null;
+  genre?: string | null;
+  rating?: number | null;
+  description?: string | null;
+  imageUrl?: string | null;
+  tags?: string[] | null;
+}
+
+export interface UpsertUserResponse {
+  user_upsert: User_Key;
+}
+
+export interface UpsertUserVariables {
+  username: string;
+}
+
+export interface UserMoviePreferencesResponse {
+  users: ({
+    likedMovies: ({
+      title: string;
+      imageUrl: string;
+      genre?: string | null;
+      description?: string | null;
+    })[];
+      dislikedMovies: ({
+        title: string;
+        imageUrl: string;
+        genre?: string | null;
+        description?: string | null;
+      })[];
+  })[];
+}
+
+export interface UserMoviePreferencesVariables {
+  username: string;
+}
+
+export interface User_Key {
+  id: string;
+  __typename?: 'User_Key';
+}
+
+export interface WatchedMovie_Key {
+  userId: string;
+  movieId: UUIDString;
+  __typename?: 'WatchedMovie_Key';
+}
+
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function createMovieRef(vars: CreateMovieVariables): MutationRef<CreateMovieResponse, CreateMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function createMovieRef(dc: DataConnect, vars: CreateMovieVariables): MutationRef<CreateMovieResponse,CreateMovieVariables>;
+
+export function createMovie(vars: CreateMovieVariables): MutationPromise<CreateMovieResponse, CreateMovieVariables>;
+export function createMovie(dc: DataConnect, vars: CreateMovieVariables): MutationPromise<CreateMovieResponse,CreateMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function updateMovieRef(vars: UpdateMovieVariables): MutationRef<UpdateMovieResponse, UpdateMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function updateMovieRef(dc: DataConnect, vars: UpdateMovieVariables): MutationRef<UpdateMovieResponse,UpdateMovieVariables>;
+
+export function updateMovie(vars: UpdateMovieVariables): MutationPromise<UpdateMovieResponse, UpdateMovieVariables>;
+export function updateMovie(dc: DataConnect, vars: UpdateMovieVariables): MutationPromise<UpdateMovieResponse,UpdateMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function deleteMovieRef(vars: DeleteMovieVariables): MutationRef<DeleteMovieResponse, DeleteMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function deleteMovieRef(dc: DataConnect, vars: DeleteMovieVariables): MutationRef<DeleteMovieResponse,DeleteMovieVariables>;
+
+export function deleteMovie(vars: DeleteMovieVariables): MutationPromise<DeleteMovieResponse, DeleteMovieVariables>;
+export function deleteMovie(dc: DataConnect, vars: DeleteMovieVariables): MutationPromise<DeleteMovieResponse,DeleteMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function deleteUnpopularMoviesRef(vars: DeleteUnpopularMoviesVariables): MutationRef<DeleteUnpopularMoviesResponse, DeleteUnpopularMoviesVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function deleteUnpopularMoviesRef(dc: DataConnect, vars: DeleteUnpopularMoviesVariables): MutationRef<DeleteUnpopularMoviesResponse,DeleteUnpopularMoviesVariables>;
+
+export function deleteUnpopularMovies(vars: DeleteUnpopularMoviesVariables): MutationPromise<DeleteUnpopularMoviesResponse, DeleteUnpopularMoviesVariables>;
+export function deleteUnpopularMovies(dc: DataConnect, vars: DeleteUnpopularMoviesVariables): MutationPromise<DeleteUnpopularMoviesResponse,DeleteUnpopularMoviesVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function addWatchedMovieRef(vars: AddWatchedMovieVariables): MutationRef<AddWatchedMovieResponse, AddWatchedMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function addWatchedMovieRef(dc: DataConnect, vars: AddWatchedMovieVariables): MutationRef<AddWatchedMovieResponse,AddWatchedMovieVariables>;
+
+export function addWatchedMovie(vars: AddWatchedMovieVariables): MutationPromise<AddWatchedMovieResponse, AddWatchedMovieVariables>;
+export function addWatchedMovie(dc: DataConnect, vars: AddWatchedMovieVariables): MutationPromise<AddWatchedMovieResponse,AddWatchedMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function deleteWatchedMovieRef(vars: DeleteWatchedMovieVariables): MutationRef<DeleteWatchedMovieResponse, DeleteWatchedMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function deleteWatchedMovieRef(dc: DataConnect, vars: DeleteWatchedMovieVariables): MutationRef<DeleteWatchedMovieResponse,DeleteWatchedMovieVariables>;
+
+export function deleteWatchedMovie(vars: DeleteWatchedMovieVariables): MutationPromise<DeleteWatchedMovieResponse, DeleteWatchedMovieVariables>;
+export function deleteWatchedMovie(dc: DataConnect, vars: DeleteWatchedMovieVariables): MutationPromise<DeleteWatchedMovieResponse,DeleteWatchedMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function addFavoritedMovieRef(vars: AddFavoritedMovieVariables): MutationRef<AddFavoritedMovieResponse, AddFavoritedMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function addFavoritedMovieRef(dc: DataConnect, vars: AddFavoritedMovieVariables): MutationRef<AddFavoritedMovieResponse,AddFavoritedMovieVariables>;
+
+export function addFavoritedMovie(vars: AddFavoritedMovieVariables): MutationPromise<AddFavoritedMovieResponse, AddFavoritedMovieVariables>;
+export function addFavoritedMovie(dc: DataConnect, vars: AddFavoritedMovieVariables): MutationPromise<AddFavoritedMovieResponse,AddFavoritedMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function deleteFavoritedMovieRef(vars: DeleteFavoritedMovieVariables): MutationRef<DeleteFavoritedMovieResponse, DeleteFavoritedMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function deleteFavoritedMovieRef(dc: DataConnect, vars: DeleteFavoritedMovieVariables): MutationRef<DeleteFavoritedMovieResponse,DeleteFavoritedMovieVariables>;
+
+export function deleteFavoritedMovie(vars: DeleteFavoritedMovieVariables): MutationPromise<DeleteFavoritedMovieResponse, DeleteFavoritedMovieVariables>;
+export function deleteFavoritedMovie(dc: DataConnect, vars: DeleteFavoritedMovieVariables): MutationPromise<DeleteFavoritedMovieResponse,DeleteFavoritedMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function addFavoritedActorRef(vars: AddFavoritedActorVariables): MutationRef<AddFavoritedActorResponse, AddFavoritedActorVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function addFavoritedActorRef(dc: DataConnect, vars: AddFavoritedActorVariables): MutationRef<AddFavoritedActorResponse,AddFavoritedActorVariables>;
+
+export function addFavoritedActor(vars: AddFavoritedActorVariables): MutationPromise<AddFavoritedActorResponse, AddFavoritedActorVariables>;
+export function addFavoritedActor(dc: DataConnect, vars: AddFavoritedActorVariables): MutationPromise<AddFavoritedActorResponse,AddFavoritedActorVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function deleteFavoriteActorRef(vars: DeleteFavoriteActorVariables): MutationRef<DeleteFavoriteActorResponse, DeleteFavoriteActorVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function deleteFavoriteActorRef(dc: DataConnect, vars: DeleteFavoriteActorVariables): MutationRef<DeleteFavoriteActorResponse,DeleteFavoriteActorVariables>;
+
+export function deleteFavoriteActor(vars: DeleteFavoriteActorVariables): MutationPromise<DeleteFavoriteActorResponse, DeleteFavoriteActorVariables>;
+export function deleteFavoriteActor(dc: DataConnect, vars: DeleteFavoriteActorVariables): MutationPromise<DeleteFavoriteActorResponse,DeleteFavoriteActorVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function addReviewRef(vars: AddReviewVariables): MutationRef<AddReviewResponse, AddReviewVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function addReviewRef(dc: DataConnect, vars: AddReviewVariables): MutationRef<AddReviewResponse,AddReviewVariables>;
+
+export function addReview(vars: AddReviewVariables): MutationPromise<AddReviewResponse, AddReviewVariables>;
+export function addReview(dc: DataConnect, vars: AddReviewVariables): MutationPromise<AddReviewResponse,AddReviewVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function deleteReviewRef(vars: DeleteReviewVariables): MutationRef<DeleteReviewResponse, DeleteReviewVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function deleteReviewRef(dc: DataConnect, vars: DeleteReviewVariables): MutationRef<DeleteReviewResponse,DeleteReviewVariables>;
+
+export function deleteReview(vars: DeleteReviewVariables): MutationPromise<DeleteReviewResponse, DeleteReviewVariables>;
+export function deleteReview(dc: DataConnect, vars: DeleteReviewVariables): MutationPromise<DeleteReviewResponse,DeleteReviewVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function upsertUserRef(vars: UpsertUserVariables): MutationRef<UpsertUserResponse, UpsertUserVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function upsertUserRef(dc: DataConnect, vars: UpsertUserVariables): MutationRef<UpsertUserResponse,UpsertUserVariables>;
+
+export function upsertUser(vars: UpsertUserVariables): MutationPromise<UpsertUserResponse, UpsertUserVariables>;
+export function upsertUser(dc: DataConnect, vars: UpsertUserVariables): MutationPromise<UpsertUserResponse,UpsertUserVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listMoviesRef(): QueryRef<ListMoviesResponse, undefined>;/* Allow users to pass in custom DataConnect instances */
+export function listMoviesRef(dc: DataConnect): QueryRef<ListMoviesResponse,undefined>;
+
+export function listMovies(): QueryPromise<ListMoviesResponse, undefined>;
+export function listMovies(dc: DataConnect): QueryPromise<ListMoviesResponse,undefined>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listUsersRef(): QueryRef<ListUsersResponse, undefined>;/* Allow users to pass in custom DataConnect instances */
+export function listUsersRef(dc: DataConnect): QueryRef<ListUsersResponse,undefined>;
+
+export function listUsers(): QueryPromise<ListUsersResponse, undefined>;
+export function listUsers(dc: DataConnect): QueryPromise<ListUsersResponse,undefined>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listMoviesByGenreRef(vars: ListMoviesByGenreVariables): QueryRef<ListMoviesByGenreResponse, ListMoviesByGenreVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function listMoviesByGenreRef(dc: DataConnect, vars: ListMoviesByGenreVariables): QueryRef<ListMoviesByGenreResponse,ListMoviesByGenreVariables>;
+
+export function listMoviesByGenre(vars: ListMoviesByGenreVariables): QueryPromise<ListMoviesByGenreResponse, ListMoviesByGenreVariables>;
+export function listMoviesByGenre(dc: DataConnect, vars: ListMoviesByGenreVariables): QueryPromise<ListMoviesByGenreResponse,ListMoviesByGenreVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listMoviesByReleaseYearRef(): QueryRef<ListMoviesByReleaseYearResponse, undefined>;/* Allow users to pass in custom DataConnect instances */
+export function listMoviesByReleaseYearRef(dc: DataConnect): QueryRef<ListMoviesByReleaseYearResponse,undefined>;
+
+export function listMoviesByReleaseYear(): QueryPromise<ListMoviesByReleaseYearResponse, undefined>;
+export function listMoviesByReleaseYear(dc: DataConnect): QueryPromise<ListMoviesByReleaseYearResponse,undefined>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getMovieByIdRef(vars: GetMovieByIdVariables): QueryRef<GetMovieByIdResponse, GetMovieByIdVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getMovieByIdRef(dc: DataConnect, vars: GetMovieByIdVariables): QueryRef<GetMovieByIdResponse,GetMovieByIdVariables>;
+
+export function getMovieById(vars: GetMovieByIdVariables): QueryPromise<GetMovieByIdResponse, GetMovieByIdVariables>;
+export function getMovieById(dc: DataConnect, vars: GetMovieByIdVariables): QueryPromise<GetMovieByIdResponse,GetMovieByIdVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getActorByIdRef(vars: GetActorByIdVariables): QueryRef<GetActorByIdResponse, GetActorByIdVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getActorByIdRef(dc: DataConnect, vars: GetActorByIdVariables): QueryRef<GetActorByIdResponse,GetActorByIdVariables>;
+
+export function getActorById(vars: GetActorByIdVariables): QueryPromise<GetActorByIdResponse, GetActorByIdVariables>;
+export function getActorById(dc: DataConnect, vars: GetActorByIdVariables): QueryPromise<GetActorByIdResponse,GetActorByIdVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function userMoviePreferencesRef(vars: UserMoviePreferencesVariables): QueryRef<UserMoviePreferencesResponse, UserMoviePreferencesVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function userMoviePreferencesRef(dc: DataConnect, vars: UserMoviePreferencesVariables): QueryRef<UserMoviePreferencesResponse,UserMoviePreferencesVariables>;
+
+export function userMoviePreferences(vars: UserMoviePreferencesVariables): QueryPromise<UserMoviePreferencesResponse, UserMoviePreferencesVariables>;
+export function userMoviePreferences(dc: DataConnect, vars: UserMoviePreferencesVariables): QueryPromise<UserMoviePreferencesResponse,UserMoviePreferencesVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getMovieMetadataRef(vars: GetMovieMetadataVariables): QueryRef<GetMovieMetadataResponse, GetMovieMetadataVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getMovieMetadataRef(dc: DataConnect, vars: GetMovieMetadataVariables): QueryRef<GetMovieMetadataResponse,GetMovieMetadataVariables>;
+
+export function getMovieMetadata(vars: GetMovieMetadataVariables): QueryPromise<GetMovieMetadataResponse, GetMovieMetadataVariables>;
+export function getMovieMetadata(dc: DataConnect, vars: GetMovieMetadataVariables): QueryPromise<GetMovieMetadataResponse,GetMovieMetadataVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getMovieCastRef(vars: GetMovieCastVariables): QueryRef<GetMovieCastResponse, GetMovieCastVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getMovieCastRef(dc: DataConnect, vars: GetMovieCastVariables): QueryRef<GetMovieCastResponse,GetMovieCastVariables>;
+
+export function getMovieCast(vars: GetMovieCastVariables): QueryPromise<GetMovieCastResponse, GetMovieCastVariables>;
+export function getMovieCast(dc: DataConnect, vars: GetMovieCastVariables): QueryPromise<GetMovieCastResponse,GetMovieCastVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listMoviesByPartialTitleRef(vars: ListMoviesByPartialTitleVariables): QueryRef<ListMoviesByPartialTitleResponse, ListMoviesByPartialTitleVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function listMoviesByPartialTitleRef(dc: DataConnect, vars: ListMoviesByPartialTitleVariables): QueryRef<ListMoviesByPartialTitleResponse,ListMoviesByPartialTitleVariables>;
+
+export function listMoviesByPartialTitle(vars: ListMoviesByPartialTitleVariables): QueryPromise<ListMoviesByPartialTitleResponse, ListMoviesByPartialTitleVariables>;
+export function listMoviesByPartialTitle(dc: DataConnect, vars: ListMoviesByPartialTitleVariables): QueryPromise<ListMoviesByPartialTitleResponse,ListMoviesByPartialTitleVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function movieByKeyRef(vars: MovieByKeyVariables): QueryRef<MovieByKeyResponse, MovieByKeyVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function movieByKeyRef(dc: DataConnect, vars: MovieByKeyVariables): QueryRef<MovieByKeyResponse,MovieByKeyVariables>;
+
+export function movieByKey(vars: MovieByKeyVariables): QueryPromise<MovieByKeyResponse, MovieByKeyVariables>;
+export function movieByKey(dc: DataConnect, vars: MovieByKeyVariables): QueryPromise<MovieByKeyResponse,MovieByKeyVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function movieByTitleRef(vars: MovieByTitleVariables): QueryRef<MovieByTitleResponse, MovieByTitleVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function movieByTitleRef(dc: DataConnect, vars: MovieByTitleVariables): QueryRef<MovieByTitleResponse,MovieByTitleVariables>;
+
+export function movieByTitle(vars: MovieByTitleVariables): QueryPromise<MovieByTitleResponse, MovieByTitleVariables>;
+export function movieByTitle(dc: DataConnect, vars: MovieByTitleVariables): QueryPromise<MovieByTitleResponse,MovieByTitleVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function movieByTopRatingRef(vars?: MovieByTopRatingVariables): QueryRef<MovieByTopRatingResponse, MovieByTopRatingVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function movieByTopRatingRef(dc: DataConnect, vars?: MovieByTopRatingVariables): QueryRef<MovieByTopRatingResponse,MovieByTopRatingVariables>;
+
+export function movieByTopRating(vars?: MovieByTopRatingVariables): QueryPromise<MovieByTopRatingResponse, MovieByTopRatingVariables>;
+export function movieByTopRating(dc: DataConnect, vars?: MovieByTopRatingVariables): QueryPromise<MovieByTopRatingResponse,MovieByTopRatingVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listMoviesByTagRef(vars: ListMoviesByTagVariables): QueryRef<ListMoviesByTagResponse, ListMoviesByTagVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function listMoviesByTagRef(dc: DataConnect, vars: ListMoviesByTagVariables): QueryRef<ListMoviesByTagResponse,ListMoviesByTagVariables>;
+
+export function listMoviesByTag(vars: ListMoviesByTagVariables): QueryPromise<ListMoviesByTagResponse, ListMoviesByTagVariables>;
+export function listMoviesByTag(dc: DataConnect, vars: ListMoviesByTagVariables): QueryPromise<ListMoviesByTagResponse,ListMoviesByTagVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function moviesTop10Ref(): QueryRef<MoviesTop10Response, undefined>;/* Allow users to pass in custom DataConnect instances */
+export function moviesTop10Ref(dc: DataConnect): QueryRef<MoviesTop10Response,undefined>;
+
+export function moviesTop10(): QueryPromise<MoviesTop10Response, undefined>;
+export function moviesTop10(dc: DataConnect): QueryPromise<MoviesTop10Response,undefined>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function moviesByReleaseYearRef(vars?: MoviesByReleaseYearVariables): QueryRef<MoviesByReleaseYearResponse, MoviesByReleaseYearVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function moviesByReleaseYearRef(dc: DataConnect, vars?: MoviesByReleaseYearVariables): QueryRef<MoviesByReleaseYearResponse,MoviesByReleaseYearVariables>;
+
+export function moviesByReleaseYear(vars?: MoviesByReleaseYearVariables): QueryPromise<MoviesByReleaseYearResponse, MoviesByReleaseYearVariables>;
+export function moviesByReleaseYear(dc: DataConnect, vars?: MoviesByReleaseYearVariables): QueryPromise<MoviesByReleaseYearResponse,MoviesByReleaseYearVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function moviesRecentlyReleasedRef(): QueryRef<MoviesRecentlyReleasedResponse, undefined>;/* Allow users to pass in custom DataConnect instances */
+export function moviesRecentlyReleasedRef(dc: DataConnect): QueryRef<MoviesRecentlyReleasedResponse,undefined>;
+
+export function moviesRecentlyReleased(): QueryPromise<MoviesRecentlyReleasedResponse, undefined>;
+export function moviesRecentlyReleased(dc: DataConnect): QueryPromise<MoviesRecentlyReleasedResponse,undefined>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listMoviesFilterRef(vars?: ListMoviesFilterVariables): QueryRef<ListMoviesFilterResponse, ListMoviesFilterVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function listMoviesFilterRef(dc: DataConnect, vars?: ListMoviesFilterVariables): QueryRef<ListMoviesFilterResponse,ListMoviesFilterVariables>;
+
+export function listMoviesFilter(vars?: ListMoviesFilterVariables): QueryPromise<ListMoviesFilterResponse, ListMoviesFilterVariables>;
+export function listMoviesFilter(dc: DataConnect, vars?: ListMoviesFilterVariables): QueryPromise<ListMoviesFilterResponse,ListMoviesFilterVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listMoviesByTitleStringRef(vars?: ListMoviesByTitleStringVariables): QueryRef<ListMoviesByTitleStringResponse, ListMoviesByTitleStringVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function listMoviesByTitleStringRef(dc: DataConnect, vars?: ListMoviesByTitleStringVariables): QueryRef<ListMoviesByTitleStringResponse,ListMoviesByTitleStringVariables>;
+
+export function listMoviesByTitleString(vars?: ListMoviesByTitleStringVariables): QueryPromise<ListMoviesByTitleStringResponse, ListMoviesByTitleStringVariables>;
+export function listMoviesByTitleString(dc: DataConnect, vars?: ListMoviesByTitleStringVariables): QueryPromise<ListMoviesByTitleStringResponse,ListMoviesByTitleStringVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listMoviesByRatingAndGenreRef(vars: ListMoviesByRatingAndGenreVariables): QueryRef<ListMoviesByRatingAndGenreResponse, ListMoviesByRatingAndGenreVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function listMoviesByRatingAndGenreRef(dc: DataConnect, vars: ListMoviesByRatingAndGenreVariables): QueryRef<ListMoviesByRatingAndGenreResponse,ListMoviesByRatingAndGenreVariables>;
+
+export function listMoviesByRatingAndGenre(vars: ListMoviesByRatingAndGenreVariables): QueryPromise<ListMoviesByRatingAndGenreResponse, ListMoviesByRatingAndGenreVariables>;
+export function listMoviesByRatingAndGenre(dc: DataConnect, vars: ListMoviesByRatingAndGenreVariables): QueryPromise<ListMoviesByRatingAndGenreResponse,ListMoviesByRatingAndGenreVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getFavoriteMoviesByIdRef(vars: GetFavoriteMoviesByIdVariables): QueryRef<GetFavoriteMoviesByIdResponse, GetFavoriteMoviesByIdVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getFavoriteMoviesByIdRef(dc: DataConnect, vars: GetFavoriteMoviesByIdVariables): QueryRef<GetFavoriteMoviesByIdResponse,GetFavoriteMoviesByIdVariables>;
+
+export function getFavoriteMoviesById(vars: GetFavoriteMoviesByIdVariables): QueryPromise<GetFavoriteMoviesByIdResponse, GetFavoriteMoviesByIdVariables>;
+export function getFavoriteMoviesById(dc: DataConnect, vars: GetFavoriteMoviesByIdVariables): QueryPromise<GetFavoriteMoviesByIdResponse,GetFavoriteMoviesByIdVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getFavoriteActorsByIdRef(vars: GetFavoriteActorsByIdVariables): QueryRef<GetFavoriteActorsByIdResponse, GetFavoriteActorsByIdVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getFavoriteActorsByIdRef(dc: DataConnect, vars: GetFavoriteActorsByIdVariables): QueryRef<GetFavoriteActorsByIdResponse,GetFavoriteActorsByIdVariables>;
+
+export function getFavoriteActorsById(vars: GetFavoriteActorsByIdVariables): QueryPromise<GetFavoriteActorsByIdResponse, GetFavoriteActorsByIdVariables>;
+export function getFavoriteActorsById(dc: DataConnect, vars: GetFavoriteActorsByIdVariables): QueryPromise<GetFavoriteActorsByIdResponse,GetFavoriteActorsByIdVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getWatchedMoviesByAuthIdRef(vars: GetWatchedMoviesByAuthIdVariables): QueryRef<GetWatchedMoviesByAuthIdResponse, GetWatchedMoviesByAuthIdVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getWatchedMoviesByAuthIdRef(dc: DataConnect, vars: GetWatchedMoviesByAuthIdVariables): QueryRef<GetWatchedMoviesByAuthIdResponse,GetWatchedMoviesByAuthIdVariables>;
+
+export function getWatchedMoviesByAuthId(vars: GetWatchedMoviesByAuthIdVariables): QueryPromise<GetWatchedMoviesByAuthIdResponse, GetWatchedMoviesByAuthIdVariables>;
+export function getWatchedMoviesByAuthId(dc: DataConnect, vars: GetWatchedMoviesByAuthIdVariables): QueryPromise<GetWatchedMoviesByAuthIdResponse,GetWatchedMoviesByAuthIdVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getUserByIdRef(vars: GetUserByIdVariables): QueryRef<GetUserByIdResponse, GetUserByIdVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getUserByIdRef(dc: DataConnect, vars: GetUserByIdVariables): QueryRef<GetUserByIdResponse,GetUserByIdVariables>;
+
+export function getUserById(vars: GetUserByIdVariables): QueryPromise<GetUserByIdResponse, GetUserByIdVariables>;
+export function getUserById(dc: DataConnect, vars: GetUserByIdVariables): QueryPromise<GetUserByIdResponse,GetUserByIdVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getIfWatchedRef(vars: GetIfWatchedVariables): QueryRef<GetIfWatchedResponse, GetIfWatchedVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getIfWatchedRef(dc: DataConnect, vars: GetIfWatchedVariables): QueryRef<GetIfWatchedResponse,GetIfWatchedVariables>;
+
+export function getIfWatched(vars: GetIfWatchedVariables): QueryPromise<GetIfWatchedResponse, GetIfWatchedVariables>;
+export function getIfWatched(dc: DataConnect, vars: GetIfWatchedVariables): QueryPromise<GetIfWatchedResponse,GetIfWatchedVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getIfFavoritedMovieRef(vars: GetIfFavoritedMovieVariables): QueryRef<GetIfFavoritedMovieResponse, GetIfFavoritedMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getIfFavoritedMovieRef(dc: DataConnect, vars: GetIfFavoritedMovieVariables): QueryRef<GetIfFavoritedMovieResponse,GetIfFavoritedMovieVariables>;
+
+export function getIfFavoritedMovie(vars: GetIfFavoritedMovieVariables): QueryPromise<GetIfFavoritedMovieResponse, GetIfFavoritedMovieVariables>;
+export function getIfFavoritedMovie(dc: DataConnect, vars: GetIfFavoritedMovieVariables): QueryPromise<GetIfFavoritedMovieResponse,GetIfFavoritedMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getIfFavoritedActorRef(vars: GetIfFavoritedActorVariables): QueryRef<GetIfFavoritedActorResponse, GetIfFavoritedActorVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getIfFavoritedActorRef(dc: DataConnect, vars: GetIfFavoritedActorVariables): QueryRef<GetIfFavoritedActorResponse,GetIfFavoritedActorVariables>;
+
+export function getIfFavoritedActor(vars: GetIfFavoritedActorVariables): QueryPromise<GetIfFavoritedActorResponse, GetIfFavoritedActorVariables>;
+export function getIfFavoritedActor(dc: DataConnect, vars: GetIfFavoritedActorVariables): QueryPromise<GetIfFavoritedActorResponse,GetIfFavoritedActorVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function fuzzySearchRef(vars: FuzzySearchVariables): QueryRef<FuzzySearchResponse, FuzzySearchVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function fuzzySearchRef(dc: DataConnect, vars: FuzzySearchVariables): QueryRef<FuzzySearchResponse,FuzzySearchVariables>;
+
+export function fuzzySearch(vars: FuzzySearchVariables): QueryPromise<FuzzySearchResponse, FuzzySearchVariables>;
+export function fuzzySearch(dc: DataConnect, vars: FuzzySearchVariables): QueryPromise<FuzzySearchResponse,FuzzySearchVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function searchMovieDescriptionUsingL2similarityRef(vars: SearchMovieDescriptionUsingL2similarityVariables): QueryRef<SearchMovieDescriptionUsingL2similarityResponse, SearchMovieDescriptionUsingL2similarityVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function searchMovieDescriptionUsingL2similarityRef(dc: DataConnect, vars: SearchMovieDescriptionUsingL2similarityVariables): QueryRef<SearchMovieDescriptionUsingL2similarityResponse,SearchMovieDescriptionUsingL2similarityVariables>;
+
+export function searchMovieDescriptionUsingL2similarity(vars: SearchMovieDescriptionUsingL2similarityVariables): QueryPromise<SearchMovieDescriptionUsingL2similarityResponse, SearchMovieDescriptionUsingL2similarityVariables>;
+export function searchMovieDescriptionUsingL2similarity(dc: DataConnect, vars: SearchMovieDescriptionUsingL2similarityVariables): QueryPromise<SearchMovieDescriptionUsingL2similarityResponse,SearchMovieDescriptionUsingL2similarityVariables>;
+
+
diff --git a/dataconnect/movie/lib/dataconnect-sdk/package.json b/dataconnect/movie/lib/dataconnect-sdk/package.json
new file mode 100644
index 000000000..30759b830
--- /dev/null
+++ b/dataconnect/movie/lib/dataconnect-sdk/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "@movie/sdk",
+  "version": "1.0.0",
+  "author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)",
+  "description": "Generated SDK For movie-connector",
+  "license": "Apache-2.0",
+  "engines": {
+    "node": " >=20.0"
+  },
+  "typings": "index.d.ts",
+  "module": "esm/index.esm.js",
+  "main": "index.cjs.js",
+  "browser": "esm/index.esm.js",
+  "exports": {
+    ".": {
+      "types": "./index.d.ts",
+      "require": "./index.cjs.js",
+      "default": "./esm/index.esm.js"
+    },
+    "./package.json": "./package.json"
+  },
+  "peerDependencies": {
+    "firebase": "dataconnect-preview"
+  }
+}
\ No newline at end of file
diff --git a/dataconnect/movie/lib/firebase.tsx b/dataconnect/movie/lib/firebase.tsx
new file mode 100644
index 000000000..731eb86a7
--- /dev/null
+++ b/dataconnect/movie/lib/firebase.tsx
@@ -0,0 +1,33 @@
+import { initializeApp } from 'firebase/app';
+import { getAuth, GoogleAuthProvider, signInWithPopup, signOut, onAuthStateChanged, connectAuthEmulator } from "firebase/auth";
+import { getDataConnect, connectDataConnectEmulator } from 'firebase/data-connect'
+
+const firebaseConfig = {
+  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
+  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
+  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
+  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
+  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
+  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
+};
+
+const firebaseapp = initializeApp(firebaseConfig);
+const auth = getAuth(firebaseapp);
+// const dataconnect = getDataConnect(firebaseapp, {
+//   connector: 'movie-connector',
+//   service: 'local',
+//   location: 'us-central1'
+// });
+const provider = new GoogleAuthProvider();
+
+if (process.env.NODE_ENV === 'development') {
+  // connectDataConnectEmulator(
+  //   dataconnect, 
+  //   'localhost', 
+  //   9399, 
+  //   false
+  // );
+  // connectAuthEmulator(auth, "http://localhost:9099");
+}
+
+export { firebaseapp, auth, onAuthStateChanged };
diff --git a/dataconnect/movie/next-env.d.ts b/dataconnect/movie/next-env.d.ts
new file mode 100644
index 000000000..4f11a03dc
--- /dev/null
+++ b/dataconnect/movie/next-env.d.ts
@@ -0,0 +1,5 @@
+/// <reference types="next" />
+/// <reference types="next/image-types/global" />
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/dataconnect/movie/package-lock.json b/dataconnect/movie/package-lock.json
new file mode 100644
index 000000000..2cd40f33e
--- /dev/null
+++ b/dataconnect/movie/package-lock.json
@@ -0,0 +1,2653 @@
+{
+  "name": "movie",
+  "version": "0.1.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "version": "0.1.0",
+      "dependencies": {
+        "autoprefixer": "^10.4.19",
+        "firebase": "10.12.0-dataconnect-preview.388b61c7e",
+        "next": "latest",
+        "postcss": "^8.4.38",
+        "react": "^18.3.1",
+        "react-dom": "^18.3.1",
+        "react-icons": "^5.2.1",
+        "tailwindcss": "^3.4.3"
+      },
+      "devDependencies": {
+        "@types/node": "^20.10.8",
+        "@types/react": "^18.2.47",
+        "@types/react-dom": "18.2.18",
+        "typescript": "^5.3.3"
+      }
+    },
+    "node_modules/@alloc/quick-lru": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+      "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@fastify/busboy": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
+      "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@firebase/analytics": {
+      "version": "0.10.3-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.3-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-Zk2hYq6vaEX+cmfrBsybz1yXh9ebmNBLxWLW1YF8PUZtlVTAUQDdcbnEYEdCF+UcMpQjdEGS+sGej6ItGy69NQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/analytics-compat": {
+      "version": "0.2.9-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.9-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-OlLd+nVMNFQuY7LRq5bLnYG2dlZ3/Ma17U14klxE7WGRU5q1dtx/+Tjw53CK2zAciPB31E+xtpHp2vb1O2UIfw==",
+      "dependencies": {
+        "@firebase/analytics": "0.10.3-dataconnect-preview.388b61c7e",
+        "@firebase/analytics-types": "0.8.2-dataconnect-preview.388b61c7e",
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/analytics-types": {
+      "version": "0.8.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-JZ1t1yVI57lWpscEA8vd9uZUa82wOlMsjxysvosCH69wbtY7wAu7lM2puB3RytdjVx3aYYiQURkCOFbsQGE9Ow=="
+    },
+    "node_modules/@firebase/app": {
+      "version": "0.10.3-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.3-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-tm0Ll26kc40pVegaJKzS0x4lkkudylQH9u9E3B3UkDFqPPTlUaSoI54YQENb6JKSCqbNQCAb2Zw2PxMjvPgABw==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/app-check": {
+      "version": "0.8.4-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.4-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-pdQrKwfsViQiZCWGEoFor9YSL9dAI6nxbaZSSp4FCy9GI/iGwzSM5EFTA76pPJTU8FmhrdGG+RmQLc46CPHiIw==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/app-check-compat": {
+      "version": "0.3.11-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.11-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-PdMU60HYFriKMPlof17tvrLoXYMWkdPq4oj6PuuOlEZ4wJh/+3Se7RFhtoGb+54gt2PdVvV+yCUV1rHlg7Snbw==",
+      "dependencies": {
+        "@firebase/app-check": "0.8.4-dataconnect-preview.388b61c7e",
+        "@firebase/app-check-types": "0.5.2-dataconnect-preview.388b61c7e",
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/app-check-interop-types": {
+      "version": "0.3.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-UOefiHjjBpetkD9WMC3dIXISyJxgOQtx5jQ5TPKOZCJvYUpGSA04qIIIFkvxd/eIIMtx9hiPtucyQJtNkbs5TA=="
+    },
+    "node_modules/@firebase/app-check-types": {
+      "version": "0.5.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-/XSOutZYx6DrmIrNP3sFiFcdOqu9Z+3LcR4aI5jrDwR/fh73eph/bBMi9rmw17vkg/BFdUbfOyC0p1mfR1EaXA=="
+    },
+    "node_modules/@firebase/app-compat": {
+      "version": "0.2.33-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.33-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-vjRVOKJWOCssAF6p/uKJhDv+iHDElNVAUk7MUHEl03y73NpoClS+F7t8k0FZ1xi1tauyiX9z2oeliBoeUv65kA==",
+      "dependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/app-types": {
+      "version": "0.9.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-NlvumIXiw89crl4qb0mHt1fTU6AEvzCUZyLnrw/DElp0UNQXPDBhxnwxqFvk9/7QK5aROuznSPAA4D7N2juFPQ=="
+    },
+    "node_modules/@firebase/auth-compat": {
+      "version": "0.5.8-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.8-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-7RgwekPUnFKAmiOlFZThc3xZcruIdR2Qy4p7Yu5znDW1xSk74Re5ijV521i3ArX+m4Sz9othHgiCZmgRV8eY+Q==",
+      "dependencies": {
+        "@firebase/auth": "1.7.3-dataconnect-preview.388b61c7e",
+        "@firebase/auth-types": "0.12.2-dataconnect-preview.388b61c7e",
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/auth-compat/node_modules/@firebase/auth": {
+      "version": "1.7.3-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.3-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-5EkGSQKk8jOml0SS3aZibeTweCrnc2mB5HyHbqOg98zHW9jMKfy9fZ2zL4qG7QOCVRT3SF0pBiDF2L6UETJnoA==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
+        "@react-native-async-storage/async-storage": "^1.18.1"
+      },
+      "peerDependenciesMeta": {
+        "@react-native-async-storage/async-storage": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@firebase/auth-interop-types": {
+      "version": "0.2.3-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-Vao5kFj48qi7K76LEZLwCimtfppdTfCHw54EfLvxOZNCgYpScx1x9oq91xn2vWqNTCP1eGWeMYPACqgLPlM57Q=="
+    },
+    "node_modules/@firebase/auth-types": {
+      "version": "0.12.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-ONN/dDQpnKUvdKiT1aT2AofnLyEyxMHDzAHSL/eJefDlWfNL/UicJXKtHCqFDLC0k9U9apQZdqzoepI+Wicrjw==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/component": {
+      "version": "0.6.7-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.7-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-2AXGmpE1D+4lR9akCw1TE5bwhlNirS26toZDQVlvYGbFypt5SnZzgKus9JLHKyaMMYIcoPrReqFF247DYwaJAg==",
+      "dependencies": {
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/data-connect": {
+      "version": "0.0.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.0.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-pPQElS3ceqxmekGWZOtzrEcuwbZTPV0JvPQPc7yHPWkAqAC6qftd6t3TYEy3GsDvYCaBmKC1KSM/YPPrQvj/Gg==",
+      "dependencies": {
+        "@firebase/auth-interop-types": "0.2.3-dataconnect-preview.388b61c7e",
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/database": {
+      "version": "1.0.5-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.5-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-nQXgc47g3bbB1/KYcrlfwoRzPsdSFiwenQPBRrhi9WAL/VUyNgwCtA2tWqfythvKrfAwoVEzm55aQ0uV/PxrGw==",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.2-dataconnect-preview.388b61c7e",
+        "@firebase/auth-interop-types": "0.2.3-dataconnect-preview.388b61c7e",
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "faye-websocket": "0.11.4",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/database-compat": {
+      "version": "1.0.5-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.5-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-6x4YBdlEcbRjc3VMG6RqmLfYW/wBW21wqaKuec1TKDuQjT7czFeyXtxPCX64qbSDC4yc1v9+ru4m3NnQ8kVTrw==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/database": "1.0.5-dataconnect-preview.388b61c7e",
+        "@firebase/database-types": "1.0.3-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/database-types": {
+      "version": "1.0.3-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.3-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-JrYV6qJa77fu94LJbw4oOE22a3qVJ9Zl8mPNHxG1/yXcqDAj4STnDiccEvnGEKTspgVfksPnqD7IkaroN4bzLg==",
+      "dependencies": {
+        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/firestore": {
+      "version": "4.6.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.6.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-s0ZFLG+XaZUHYeIEBp1SnqyMz33lwOL17QDDlleFnMhRswgqyWwiMZD55juVaVrn3bTnGPpKSZB1t7RurtzgfA==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "@firebase/webchannel-wrapper": "1.0.0-dataconnect-preview.388b61c7e",
+        "@grpc/grpc-js": "~1.9.0",
+        "@grpc/proto-loader": "^0.7.8",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "engines": {
+        "node": ">=10.10.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/firestore-compat": {
+      "version": "0.3.31-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.31-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-Et2OO+JevBmkkfKWVm4uZnHT7OgjfT1EBK31yFbHd8/y8NoD6M6XveM16IoBTGYnhqHVVjJQ3WFI1FfyQKVIgg==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/firestore": "4.6.2-dataconnect-preview.388b61c7e",
+        "@firebase/firestore-types": "3.0.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/firestore-types": {
+      "version": "3.0.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-z+x9vINP8Jcu0ePpWZgj5S2H4glsOsD914P9OaNRUAovacdrr1rmo5tHdNdrbQ2cIma9TPCTfDeXTDm/UhOiAw==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/functions": {
+      "version": "0.11.5-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.5-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-8MsDg9At4oO7AJqtx9iyIuJpTDEmZOTavOMw1bCQQ/wrsITDs0oCaOQmdiGRgbAQ9xJgdbZFqlKJfYRFE8lA2w==",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.2-dataconnect-preview.388b61c7e",
+        "@firebase/auth-interop-types": "0.2.3-dataconnect-preview.388b61c7e",
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/messaging-interop-types": "0.2.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/functions-compat": {
+      "version": "0.3.11-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.11-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-Puty2X6HwdCwTL+jD8EzHLRUoYfcUtkVIwghLrz1ewwe9kYnwYvhbeAGibsXFYhuaxaYOD5OqDFS2lsK3gfFKg==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/functions": "0.11.5-dataconnect-preview.388b61c7e",
+        "@firebase/functions-types": "0.6.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/functions-types": {
+      "version": "0.6.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-poR5xISP3LGau7KvPWVseT97I8XG+y0nkrtkgzzgBytpbe94jLdagFrzG03Nm2YInj841arE1Jdprz24FJ67bQ=="
+    },
+    "node_modules/@firebase/installations": {
+      "version": "0.6.7-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.7-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-vlYBEvQeQjF2Z+hceZJQsvGyjHlEsU7Ibvzyjr2wVvvdxV3nkjPtyr0Ccy5EeegFNoxaKLFyFkol5tP4WfN9mw==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/installations-compat": {
+      "version": "0.2.7-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.7-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-HYwIO1BiSW7yfUxvXWWXIcv3lFPqMa/bPH9aO/0bUfeCVfa5Ww1cIs8QjWQYKNqW96zBxr3RnpiWI12jxSUJyw==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/installations-types": "0.5.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/installations-types": {
+      "version": "0.5.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-JkYzoUi28NbOlw7KzjoUhJueYbD4od+TAw5kiyFoK0DAG7FUkX0uca3MOrWuhNsvM4XKVW/Np4rvA1AKrmzR/g==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/logger": {
+      "version": "0.4.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-nvZLqLFCbXW6r1kzXTeTGmzMCx+1tzq0sL4niwYaws3V/Xl6mDkNcEGMoOX6OuwTq8NlP1sjE9ER4qnbV3Olqw==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/messaging": {
+      "version": "0.12.9-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.9-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-E5dKGhwtwPIeglDUAhJMLTQicV2tQnuU3t7r/Oc51WI05HgzM7WVu78DqPjCIp7GGDHy5R2qU4BiCzYaMSAJRg==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/messaging-interop-types": "0.2.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/messaging-compat": {
+      "version": "0.2.9-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.9-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-taSKYJ3b/8DByQGDYx3NbtgLmo06wKFRM7d8bT1o3N4A0Cd5Y51DKU2uR/Xf/QMNECKsH7Jv18d1VrU3aOOOng==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/messaging": "0.12.9-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/messaging-interop-types": {
+      "version": "0.2.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-NKCrCBovd63kK40vTSfMrThtyzTCfQjj82+4MaX8OMn/gFGm4RCU8UqO4PnxbR/viYAlxXitbeFR/aKeixdDBA=="
+    },
+    "node_modules/@firebase/performance": {
+      "version": "0.6.7-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.7-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-AltYdWIO0Rlz0Nu10IyzlCi2XPztP4kDArsYcPX25fv6DOGSAI7fnLN+9dejDSbrhxttL4FCK9/WqywDdEretg==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/performance-compat": {
+      "version": "0.2.7-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.7-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-6h+T3S0EBSWy+69OUTGeCDqFpOzla1hID5HlKtC5eTNhbWygHuC/s0zrLXInwR6o5xMayxhvf0HNIRoUy6FZkA==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/performance": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/performance-types": "0.2.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/performance-types": {
+      "version": "0.2.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-/rWGG41TwiYkaI3E6pD5vb4uWKoPxuyP259QCHnt2lB4s/gPAtU8VRVoEgx1do4CB+8AvrV5Aec6KL2C2YQlYg=="
+    },
+    "node_modules/@firebase/remote-config": {
+      "version": "0.4.7-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.7-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-PLHu0C/qTf0C2Z2ss65Mt0AkPY5MfwWzV2fHHhsj5AEJHpJsSS9elKAk/6J2W0plJnmlJkcvihsMkMTVl8vzzQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/remote-config-compat": {
+      "version": "0.2.7-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.7-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-Q0dKJyidqdERRlyuomQAhrw0KNu6lNSM/jc29HDjlQJhCFdin3XrcDSYYxBgpkWNKD2nQ/4XNMslkGP7fzu5+Q==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/remote-config": "0.4.7-dataconnect-preview.388b61c7e",
+        "@firebase/remote-config-types": "0.3.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/remote-config-types": {
+      "version": "0.3.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-B8twcsCV1auMHoVg5ICSzCrc8RUz4WVPOaQBiR/veeS0+PmBRiTHoyZzZh33vED1FHPzz3Cf7uwMfhk0gNhuYw=="
+    },
+    "node_modules/@firebase/storage": {
+      "version": "0.12.5-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.5-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-YFDMpLf1piDU28/d8DAWRfCU62UTas9IDsvTnzfc/P3MNJJSnHcUrECe97O09EatfbZW3z5Wh0iM7uZTO0ts3Q==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/storage-compat": {
+      "version": "0.3.8-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.8-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-sQF/Hd/0oWsR3fimD6LXXtvwcwc8dpc6SQfmfR46ISCGKeAml2Wla1w1rWA8TyHce5eYRQAgczxk6f9JdBwcNQ==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/storage": "0.12.5-dataconnect-preview.388b61c7e",
+        "@firebase/storage-types": "0.8.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/storage-types": {
+      "version": "0.8.2-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.2-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-w5Tjd4rBFV6ZZ/fXacl+h9/CKaCWVlTJae96Z0+pcB6BtTQY+B8E1I62O+4UCzs4yauF8PpuWLxkULBO9Zjtkg==",
+      "peerDependencies": {
+        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/util": {
+      "version": "1.9.6-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.6-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-oBd5uhs6sixiauvFo4RJ5+X4diK6AdrEBdOPYdeoV4HhF6aV4tuxcfJrb1O+d+9I2xMjpA5b+ySIxJ32Dknk2w==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@firebase/vertexai-preview": {
+      "version": "0.0.1-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/vertexai-preview/-/vertexai-preview-0.0.1-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-qy0MVJztKV9Fr7BXjOHwyxa/51D4vpj5h2nsEUUjYA+wQQqz2HTejnHNjitswFSnDGWErCwWwIZau1d+NEeK8g==",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.2-dataconnect-preview.388b61c7e",
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
+        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/@firebase/webchannel-wrapper": {
+      "version": "1.0.0-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.0-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-Bfz5tSuiwYE9Y/tPt7haiZEnexNXZX8zQINi0ZlnecepwZcLy03dyF/SKlhAv0mAXzGZBXfn3eqBccgcssCS5Q=="
+    },
+    "node_modules/@grpc/grpc-js": {
+      "version": "1.9.14",
+      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz",
+      "integrity": "sha512-nOpuzZ2G3IuMFN+UPPpKrC6NsLmWsTqSsm66IRfnBt1D4pwTqE27lmbpcPM+l2Ua4gE7PfjRHI6uedAy7hoXUw==",
+      "dependencies": {
+        "@grpc/proto-loader": "^0.7.8",
+        "@types/node": ">=12.12.47"
+      },
+      "engines": {
+        "node": "^8.13.0 || >=10.10.0"
+      }
+    },
+    "node_modules/@grpc/proto-loader": {
+      "version": "0.7.13",
+      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz",
+      "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==",
+      "dependencies": {
+        "lodash.camelcase": "^4.3.0",
+        "long": "^5.0.0",
+        "protobufjs": "^7.2.5",
+        "yargs": "^17.7.2"
+      },
+      "bin": {
+        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@isaacs/cliui": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+      "dependencies": {
+        "string-width": "^5.1.2",
+        "string-width-cjs": "npm:string-width@^4.2.0",
+        "strip-ansi": "^7.0.1",
+        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+        "wrap-ansi": "^8.1.0",
+        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+      "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
+    },
+    "node_modules/@isaacs/cliui/node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+      "dependencies": {
+        "ansi-styles": "^6.1.0",
+        "string-width": "^5.0.1",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+      "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
+      "dependencies": {
+        "@jridgewell/set-array": "^1.2.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.15",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+      "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.25",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@next/env": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz",
+      "integrity": "sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA=="
+    },
+    "node_modules/@next/swc-darwin-arm64": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.3.tgz",
+      "integrity": "sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-darwin-x64": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.3.tgz",
+      "integrity": "sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-arm64-gnu": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.3.tgz",
+      "integrity": "sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-arm64-musl": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.3.tgz",
+      "integrity": "sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-x64-gnu": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz",
+      "integrity": "sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-x64-musl": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz",
+      "integrity": "sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-arm64-msvc": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz",
+      "integrity": "sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-ia32-msvc": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz",
+      "integrity": "sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==",
+      "cpu": [
+        "ia32"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-x64-msvc": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz",
+      "integrity": "sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@pkgjs/parseargs": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+      "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+      "optional": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+    },
+    "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.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"
+      }
+    },
+    "node_modules/@types/node": {
+      "version": "20.10.8",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz",
+      "integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==",
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/@types/prop-types": {
+      "version": "15.7.12",
+      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
+      "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
+      "dev": true
+    },
+    "node_modules/@types/react": {
+      "version": "18.2.47",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.47.tgz",
+      "integrity": "sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/prop-types": "*",
+        "@types/scheduler": "*",
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/@types/react-dom": {
+      "version": "18.2.18",
+      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz",
+      "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==",
+      "dev": true,
+      "dependencies": {
+        "@types/react": "*"
+      }
+    },
+    "node_modules/@types/scheduler": {
+      "version": "0.23.0",
+      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz",
+      "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==",
+      "dev": true
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/any-promise": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/arg": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+      "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
+    },
+    "node_modules/autoprefixer": {
+      "version": "10.4.19",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
+      "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "browserslist": "^4.23.0",
+        "caniuse-lite": "^1.0.30001599",
+        "fraction.js": "^4.3.7",
+        "normalize-range": "^0.1.2",
+        "picocolors": "^1.0.0",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "bin": {
+        "autoprefixer": "bin/autoprefixer"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.23.0",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
+      "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001587",
+        "electron-to-chromium": "^1.4.668",
+        "node-releases": "^2.0.14",
+        "update-browserslist-db": "^1.0.13"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/busboy": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+      "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+      "dependencies": {
+        "streamsearch": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=10.16.0"
+      }
+    },
+    "node_modules/camelcase-css": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001625",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz",
+      "integrity": "sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ]
+    },
+    "node_modules/chokidar": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/chokidar/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==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/client-only": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+      "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
+    },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/commander": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+      "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/csstype": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+      "dev": true
+    },
+    "node_modules/didyoumean": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
+    },
+    "node_modules/dlv": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+      "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
+    },
+    "node_modules/eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.784",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.784.tgz",
+      "integrity": "sha512-9CZwh+sDrhDAeOEFh8s3PqwduzTyYIeYwZolc1b9ENAUt3ePu7R1sJSCWr/820ISssRxCJUyHI9Wb7j+0Uo1AA=="
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+    },
+    "node_modules/escalade": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+      "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+      "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/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==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fastq": {
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+      "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/faye-websocket": {
+      "version": "0.11.4",
+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+      "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+      "dependencies": {
+        "websocket-driver": ">=0.5.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/firebase": {
+      "version": "10.12.0-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.12.0-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-QoqKj8DnHlIHLqSdEu+hwR69n/HWYLIRcOtCNrv1h2BXcl0V91CNtFYqX5LHk4zJ6eZ+hSOfDnxKya6gAEGZ6w==",
+      "dependencies": {
+        "@firebase/analytics": "0.10.3-dataconnect-preview.388b61c7e",
+        "@firebase/analytics-compat": "0.2.9-dataconnect-preview.388b61c7e",
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
+        "@firebase/app-check": "0.8.4-dataconnect-preview.388b61c7e",
+        "@firebase/app-check-compat": "0.3.11-dataconnect-preview.388b61c7e",
+        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e",
+        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
+        "@firebase/auth": "1.7.3-dataconnect-preview.388b61c7e",
+        "@firebase/auth-compat": "0.5.8-dataconnect-preview.388b61c7e",
+        "@firebase/data-connect": "0.0.2-dataconnect-preview.388b61c7e",
+        "@firebase/database": "1.0.5-dataconnect-preview.388b61c7e",
+        "@firebase/database-compat": "1.0.5-dataconnect-preview.388b61c7e",
+        "@firebase/firestore": "4.6.2-dataconnect-preview.388b61c7e",
+        "@firebase/firestore-compat": "0.3.31-dataconnect-preview.388b61c7e",
+        "@firebase/functions": "0.11.5-dataconnect-preview.388b61c7e",
+        "@firebase/functions-compat": "0.3.11-dataconnect-preview.388b61c7e",
+        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/installations-compat": "0.2.7-dataconnect-preview.388b61c7e",
+        "@firebase/messaging": "0.12.9-dataconnect-preview.388b61c7e",
+        "@firebase/messaging-compat": "0.2.9-dataconnect-preview.388b61c7e",
+        "@firebase/performance": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/performance-compat": "0.2.7-dataconnect-preview.388b61c7e",
+        "@firebase/remote-config": "0.4.7-dataconnect-preview.388b61c7e",
+        "@firebase/remote-config-compat": "0.2.7-dataconnect-preview.388b61c7e",
+        "@firebase/storage": "0.12.5-dataconnect-preview.388b61c7e",
+        "@firebase/storage-compat": "0.3.8-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "@firebase/vertexai-preview": "0.0.1-dataconnect-preview.388b61c7e"
+      }
+    },
+    "node_modules/firebase/node_modules/@firebase/auth": {
+      "version": "1.7.3-dataconnect-preview.388b61c7e",
+      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.3-dataconnect-preview.388b61c7e.tgz",
+      "integrity": "sha512-5EkGSQKk8jOml0SS3aZibeTweCrnc2mB5HyHbqOg98zHW9jMKfy9fZ2zL4qG7QOCVRT3SF0pBiDF2L6UETJnoA==",
+      "dependencies": {
+        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
+        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
+        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
+        "tslib": "^2.1.0",
+        "undici": "5.28.4"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
+        "@react-native-async-storage/async-storage": "^1.18.1"
+      },
+      "peerDependenciesMeta": {
+        "@react-native-async-storage/async-storage": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/foreground-child": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
+      "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
+      "dependencies": {
+        "cross-spawn": "^7.0.0",
+        "signal-exit": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/fraction.js": {
+      "version": "4.3.7",
+      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+      "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "type": "patreon",
+        "url": "https://github.com/sponsors/rawify"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/glob": {
+      "version": "10.4.1",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz",
+      "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==",
+      "dependencies": {
+        "foreground-child": "^3.1.0",
+        "jackspeak": "^3.1.2",
+        "minimatch": "^9.0.4",
+        "minipass": "^7.1.2",
+        "path-scurry": "^1.11.1"
+      },
+      "bin": {
+        "glob": "dist/esm/bin.mjs"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+    },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/http-parser-js": {
+      "version": "0.5.8",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+      "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q=="
+    },
+    "node_modules/idb": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
+      "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.13.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
+      "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+      "dependencies": {
+        "hasown": "^2.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+    },
+    "node_modules/jackspeak": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz",
+      "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==",
+      "dependencies": {
+        "@isaacs/cliui": "^8.0.2"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      },
+      "optionalDependencies": {
+        "@pkgjs/parseargs": "^0.11.0"
+      }
+    },
+    "node_modules/jiti": {
+      "version": "1.21.0",
+      "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
+      "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
+      "bin": {
+        "jiti": "bin/jiti.js"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+    },
+    "node_modules/lilconfig": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+      "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+    },
+    "node_modules/lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
+    },
+    "node_modules/long": {
+      "version": "5.2.3",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
+      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
+    },
+    "node_modules/loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "dependencies": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      },
+      "bin": {
+        "loose-envify": "cli.js"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
+      "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
+      "engines": {
+        "node": "14 || >=16.14"
+      }
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
+      "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "9.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+      "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/mz": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+      "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+      "dependencies": {
+        "any-promise": "^1.0.0",
+        "object-assign": "^4.0.1",
+        "thenify-all": "^1.0.0"
+      }
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.7",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+      "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/next": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/next/-/next-14.2.3.tgz",
+      "integrity": "sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A==",
+      "dependencies": {
+        "@next/env": "14.2.3",
+        "@swc/helpers": "0.5.5",
+        "busboy": "1.6.0",
+        "caniuse-lite": "^1.0.30001579",
+        "graceful-fs": "^4.2.11",
+        "postcss": "8.4.31",
+        "styled-jsx": "5.1.1"
+      },
+      "bin": {
+        "next": "dist/bin/next"
+      },
+      "engines": {
+        "node": ">=18.17.0"
+      },
+      "optionalDependencies": {
+        "@next/swc-darwin-arm64": "14.2.3",
+        "@next/swc-darwin-x64": "14.2.3",
+        "@next/swc-linux-arm64-gnu": "14.2.3",
+        "@next/swc-linux-arm64-musl": "14.2.3",
+        "@next/swc-linux-x64-gnu": "14.2.3",
+        "@next/swc-linux-x64-musl": "14.2.3",
+        "@next/swc-win32-arm64-msvc": "14.2.3",
+        "@next/swc-win32-ia32-msvc": "14.2.3",
+        "@next/swc-win32-x64-msvc": "14.2.3"
+      },
+      "peerDependencies": {
+        "@opentelemetry/api": "^1.1.0",
+        "@playwright/test": "^1.41.2",
+        "react": "^18.2.0",
+        "react-dom": "^18.2.0",
+        "sass": "^1.3.0"
+      },
+      "peerDependenciesMeta": {
+        "@opentelemetry/api": {
+          "optional": true
+        },
+        "@playwright/test": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/next/node_modules/postcss": {
+      "version": "8.4.31",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+      "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "nanoid": "^3.3.6",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.0.2"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.14",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
+      "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw=="
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-hash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+      "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+    },
+    "node_modules/path-scurry": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+      "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+      "dependencies": {
+        "lru-cache": "^10.2.0",
+        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+      "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/pirates": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+      "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.4.38",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
+      "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "nanoid": "^3.3.7",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.2.0"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/postcss-import": {
+      "version": "15.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+      "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+      "dependencies": {
+        "postcss-value-parser": "^4.0.0",
+        "read-cache": "^1.0.0",
+        "resolve": "^1.1.7"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.0.0"
+      }
+    },
+    "node_modules/postcss-js": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+      "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+      "dependencies": {
+        "camelcase-css": "^2.0.1"
+      },
+      "engines": {
+        "node": "^12 || ^14 || >= 16"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      },
+      "peerDependencies": {
+        "postcss": "^8.4.21"
+      }
+    },
+    "node_modules/postcss-load-config": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
+      "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "lilconfig": "^3.0.0",
+        "yaml": "^2.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      },
+      "peerDependencies": {
+        "postcss": ">=8.0.9",
+        "ts-node": ">=9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "postcss": {
+          "optional": true
+        },
+        "ts-node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/postcss-load-config/node_modules/lilconfig": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz",
+      "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antonk52"
+      }
+    },
+    "node_modules/postcss-nested": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
+      "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+      "dependencies": {
+        "postcss-selector-parser": "^6.0.11"
+      },
+      "engines": {
+        "node": ">=12.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      },
+      "peerDependencies": {
+        "postcss": "^8.2.14"
+      }
+    },
+    "node_modules/postcss-selector-parser": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz",
+      "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==",
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+    },
+    "node_modules/protobufjs": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.0.tgz",
+      "integrity": "sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/react": {
+      "version": "18.3.1",
+      "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+      "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+      "dependencies": {
+        "loose-envify": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-dom": {
+      "version": "18.3.1",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+      "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+      "dependencies": {
+        "loose-envify": "^1.1.0",
+        "scheduler": "^0.23.2"
+      },
+      "peerDependencies": {
+        "react": "^18.3.1"
+      }
+    },
+    "node_modules/react-icons": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz",
+      "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==",
+      "peerDependencies": {
+        "react": "*"
+      }
+    },
+    "node_modules/read-cache": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+      "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+      "dependencies": {
+        "pify": "^2.3.0"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve": {
+      "version": "1.22.8",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+      "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+      "dependencies": {
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/scheduler": {
+      "version": "0.23.2",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+      "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+      "dependencies": {
+        "loose-envify": "^1.1.0"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+      "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/streamsearch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+      "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs": {
+      "name": "string-width",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi-cjs": {
+      "name": "strip-ansi",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/styled-jsx": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
+      "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
+      "dependencies": {
+        "client-only": "0.0.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "peerDependencies": {
+        "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
+      },
+      "peerDependenciesMeta": {
+        "@babel/core": {
+          "optional": true
+        },
+        "babel-plugin-macros": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/sucrase": {
+      "version": "3.35.0",
+      "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+      "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "commander": "^4.0.0",
+        "glob": "^10.3.10",
+        "lines-and-columns": "^1.1.6",
+        "mz": "^2.7.0",
+        "pirates": "^4.0.1",
+        "ts-interface-checker": "^0.1.9"
+      },
+      "bin": {
+        "sucrase": "bin/sucrase",
+        "sucrase-node": "bin/sucrase-node"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/tailwindcss": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
+      "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
+      "dependencies": {
+        "@alloc/quick-lru": "^5.2.0",
+        "arg": "^5.0.2",
+        "chokidar": "^3.5.3",
+        "didyoumean": "^1.2.2",
+        "dlv": "^1.1.3",
+        "fast-glob": "^3.3.0",
+        "glob-parent": "^6.0.2",
+        "is-glob": "^4.0.3",
+        "jiti": "^1.21.0",
+        "lilconfig": "^2.1.0",
+        "micromatch": "^4.0.5",
+        "normalize-path": "^3.0.0",
+        "object-hash": "^3.0.0",
+        "picocolors": "^1.0.0",
+        "postcss": "^8.4.23",
+        "postcss-import": "^15.1.0",
+        "postcss-js": "^4.0.1",
+        "postcss-load-config": "^4.0.1",
+        "postcss-nested": "^6.0.1",
+        "postcss-selector-parser": "^6.0.11",
+        "resolve": "^1.22.2",
+        "sucrase": "^3.32.0"
+      },
+      "bin": {
+        "tailwind": "lib/cli.js",
+        "tailwindcss": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/thenify": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+      "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+      "dependencies": {
+        "any-promise": "^1.0.0"
+      }
+    },
+    "node_modules/thenify-all": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+      "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+      "dependencies": {
+        "thenify": ">= 3.1.0 < 4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/ts-interface-checker": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+      "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
+    },
+    "node_modules/tslib": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+      "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+    },
+    "node_modules/typescript": {
+      "version": "5.4.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+      "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
+      "dev": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/undici": {
+      "version": "5.28.4",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
+      "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
+      "dependencies": {
+        "@fastify/busboy": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=14.0"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.16",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
+      "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "escalade": "^3.1.2",
+        "picocolors": "^1.0.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+    },
+    "node_modules/websocket-driver": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+      "dependencies": {
+        "http-parser-js": ">=0.5.1",
+        "safe-buffer": ">=5.1.0",
+        "websocket-extensions": ">=0.1.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/websocket-extensions": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs": {
+      "name": "wrap-ansi",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yaml": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
+      "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/yargs": {
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "engines": {
+        "node": ">=12"
+      }
+    }
+  }
+}
diff --git a/dataconnect/movie/package.json b/dataconnect/movie/package.json
new file mode 100644
index 000000000..d809017ea
--- /dev/null
+++ b/dataconnect/movie/package.json
@@ -0,0 +1,26 @@
+{
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "dev": "next dev",
+    "build": "next build",
+    "start": "next start",
+    "lint": "next lint"
+  },
+  "dependencies": {
+    "autoprefixer": "^10.4.19",
+    "firebase": "10.12.0-dataconnect-preview.388b61c7e",
+    "next": "latest",
+    "postcss": "^8.4.38",
+    "react": "^18.3.1",
+    "react-dom": "^18.3.1",
+    "react-icons": "^5.2.1",
+    "tailwindcss": "^3.4.3"
+  },
+  "devDependencies": {
+    "@types/node": "^20.10.8",
+    "@types/react": "^18.2.47",
+    "@types/react-dom": "18.2.18",
+    "typescript": "^5.3.3"
+  }
+}
diff --git a/dataconnect/movie/postcss.config.js b/dataconnect/movie/postcss.config.js
new file mode 100644
index 000000000..33ad091d2
--- /dev/null
+++ b/dataconnect/movie/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+  plugins: {
+    tailwindcss: {},
+    autoprefixer: {},
+  },
+}
diff --git a/dataconnect/movie/styles.css b/dataconnect/movie/styles.css
new file mode 100644
index 000000000..bd6213e1d
--- /dev/null
+++ b/dataconnect/movie/styles.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
\ No newline at end of file
diff --git a/dataconnect/movie/tailwind.config.js b/dataconnect/movie/tailwind.config.js
new file mode 100644
index 000000000..86ae52d0c
--- /dev/null
+++ b/dataconnect/movie/tailwind.config.js
@@ -0,0 +1,13 @@
+module.exports = {
+  content: [
+    './app/**/*.{js,ts,jsx,tsx}',
+    './app/*.{js,ts,jsx,tsx}',
+    './app/***/**/*.{js,ts,jsx,tsx}',
+    './components/**/*.{js,ts,jsx,tsx}',
+  ],
+  darkMode: 'class',
+  theme: {
+    extend: {},
+  },
+  plugins: [],
+};
diff --git a/dataconnect/movie/tsconfig.json b/dataconnect/movie/tsconfig.json
new file mode 100644
index 000000000..b6ba42e2d
--- /dev/null
+++ b/dataconnect/movie/tsconfig.json
@@ -0,0 +1,25 @@
+{
+  "compilerOptions": {
+    "target": "es5",
+    "lib": ["dom", "dom.iterable", "esnext"],
+    "allowJs": true,
+    "skipLibCheck": true,
+    "strict": false,
+    "forceConsistentCasingInFileNames": true,
+    "noEmit": true,
+    "esModuleInterop": true,
+    "module": "esnext",
+    "moduleResolution": "node",
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "jsx": "preserve",
+    "incremental": true,
+    "plugins": [
+      {
+        "name": "next"
+      }
+    ]
+  },
+  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+  "exclude": ["node_modules"]
+}

From ce6954849ff32afbe9b2e165146b9373f1f9fc74 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Fri, 31 May 2024 14:48:11 -0400
Subject: [PATCH 08/82] fix: remove generated files

---
 .gitignore                                    |    2 +
 dataconnect/README.md                         |    6 +-
 .../.dataconnect/schema/main/implicit.gql     |   27 -
 .../.dataconnect/schema/main/input.gql        |  316 -----
 .../.dataconnect/schema/main/mutation.gql     |  218 ----
 .../.dataconnect/schema/main/query.gql        |   79 --
 .../.dataconnect/schema/main/relation.gql     |   94 --
 .../.dataconnect/schema/prelude.gql           |  947 --------------
 .../lib/dataconnect-sdk/esm/index.esm.js      |  318 -----
 .../lib/dataconnect-sdk/esm/package.json      |    1 -
 .../movie/lib/dataconnect-sdk/index.cjs.js    |  403 ------
 .../movie/lib/dataconnect-sdk/index.d.ts      | 1144 -----------------
 .../movie/lib/dataconnect-sdk/package.json    |   25 -
 13 files changed, 6 insertions(+), 3574 deletions(-)
 delete mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql
 delete mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/input.gql
 delete mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql
 delete mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/query.gql
 delete mode 100755 dataconnect/dataconnect/.dataconnect/schema/main/relation.gql
 delete mode 100755 dataconnect/dataconnect/.dataconnect/schema/prelude.gql
 delete mode 100644 dataconnect/movie/lib/dataconnect-sdk/esm/index.esm.js
 delete mode 100644 dataconnect/movie/lib/dataconnect-sdk/esm/package.json
 delete mode 100644 dataconnect/movie/lib/dataconnect-sdk/index.cjs.js
 delete mode 100644 dataconnect/movie/lib/dataconnect-sdk/index.d.ts
 delete mode 100644 dataconnect/movie/lib/dataconnect-sdk/package.json

diff --git a/.gitignore b/.gitignore
index dee8c505e..6a850a095 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@
 dist/
 **/ui-debug.log
 .next
+dataconnect/.dataconnect
+dataconnect/movie/lib/dataconnect-sdk
\ No newline at end of file
diff --git a/dataconnect/README.md b/dataconnect/README.md
index c2b0dca3c..47b45d410 100644
--- a/dataconnect/README.md
+++ b/dataconnect/README.md
@@ -25,8 +25,10 @@ Getting Started
 8. Replace variables in `.env.local` with your project-specific values.
 9. Allow domains for Firebase Auth (e.g., http://localhost or http://127.0.0.1).
 10. Deploy DataConnect with `firebase deploy --only dataconnect` (this unlocks hidden vectors search).
-11. Navigate to the `movie` directory and install dependencies with `npm i` and start the development server with `npm run dev`.
-12. Run the four `_insert.gql` files in the `./dataconnect` directory in order.
+11. Start the DateConnect emulators.
+12. Run `firebase dataconnect:sdk:generate` to generate the SDK
+13. Navigate to the `movie` directory and install dependencies with `npm i` and start the development server with `npm run dev`.
+14. Run the four `_insert.gql` files in the `./dataconnect` directory in order.
 
 <!-- Support
 -------
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql b/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql
deleted file mode 100755
index a3860ad40..000000000
--- a/dataconnect/dataconnect/.dataconnect/schema/main/implicit.gql
+++ /dev/null
@@ -1,27 +0,0 @@
-extend type FavoriteActor {
-  userId: String!
-  actorId: UUID!
-}
-extend type FavoriteMovie {
-  userId: String!
-  movieId: UUID!
-}
-extend type Movie {
-  sequelToId: UUID
-}
-extend type MovieActor {
-  movieId: UUID!
-  actorId: UUID!
-}
-extend type MovieMetadata {
-  id: UUID! @default(expr: "uuidV4()")
-  movieId: UUID!
-}
-extend type Review {
-  movieId: UUID!
-  userId: String!
-}
-extend type WatchedMovie {
-  userId: String!
-  movieId: UUID!
-}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/input.gql b/dataconnect/dataconnect/.dataconnect/schema/main/input.gql
deleted file mode 100755
index b7d1c62ae..000000000
--- a/dataconnect/dataconnect/.dataconnect/schema/main/input.gql
+++ /dev/null
@@ -1,316 +0,0 @@
-scalar Actor_Key
-scalar FavoriteActor_Key
-scalar FavoriteMovie_Key
-scalar Movie_Key
-scalar MovieActor_Key
-scalar MovieMetadata_Key
-scalar Review_Key
-scalar User_Key
-scalar WatchedMovie_Key
-input Actor_Data {
-  id: UUID
-  id_expr: UUID_Expr
-  biography: String
-  biography_expr: String_Expr
-  imageUrl: String
-  imageUrl_expr: String_Expr
-  name: String
-  name_expr: String_Expr
-}
-input Actor_Filter {
-  _and: [Actor_Filter!]
-  _not: Actor_Filter
-  _or: [Actor_Filter!]
-  id: UUID_Filter
-  biography: String_Filter
-  imageUrl: String_Filter
-  name: String_Filter
-  favoriteActors_on_actor: FavoriteActor_ListFilter
-  movieActors_on_actor: MovieActor_ListFilter
-  movies_via_MovieActor: Movie_ListFilter
-  users_via_FavoriteActor: User_ListFilter
-}
-input Actor_ListFilter {
-  count: Int_Filter
-  exist: Actor_Filter
-}
-input Actor_Order {
-  id: OrderDirection
-  biography: OrderDirection
-  imageUrl: OrderDirection
-  name: OrderDirection
-}
-input FavoriteActor_Data {
-  userId: String
-  userId_expr: String_Expr
-  actorId: UUID
-  actorId_expr: UUID_Expr
-  actor: Actor_Key
-  user: User_Key
-}
-input FavoriteActor_Filter {
-  _and: [FavoriteActor_Filter!]
-  _not: FavoriteActor_Filter
-  _or: [FavoriteActor_Filter!]
-  userId: String_Filter
-  actorId: UUID_Filter
-  actor: Actor_Filter
-  user: User_Filter
-}
-input FavoriteActor_ListFilter {
-  count: Int_Filter
-  exist: FavoriteActor_Filter
-}
-input FavoriteActor_Order {
-  userId: OrderDirection
-  actorId: OrderDirection
-  actor: Actor_Order
-  user: User_Order
-}
-input FavoriteMovie_Data {
-  userId: String
-  userId_expr: String_Expr
-  movieId: UUID
-  movieId_expr: UUID_Expr
-  movie: Movie_Key
-  user: User_Key
-}
-input FavoriteMovie_Filter {
-  _and: [FavoriteMovie_Filter!]
-  _not: FavoriteMovie_Filter
-  _or: [FavoriteMovie_Filter!]
-  userId: String_Filter
-  movieId: UUID_Filter
-  movie: Movie_Filter
-  user: User_Filter
-}
-input FavoriteMovie_ListFilter {
-  count: Int_Filter
-  exist: FavoriteMovie_Filter
-}
-input FavoriteMovie_Order {
-  userId: OrderDirection
-  movieId: OrderDirection
-  movie: Movie_Order
-  user: User_Order
-}
-input Movie_Data {
-  id: UUID
-  id_expr: UUID_Expr
-  sequelToId: UUID
-  sequelToId_expr: UUID_Expr
-  sequelTo: Movie_Key
-  description: String
-  description_expr: String_Expr
-  descriptionEmbedding: Vector
-  descriptionEmbedding_embed: Vector_Embed
-  genre: String
-  genre_expr: String_Expr
-  imageUrl: String
-  imageUrl_expr: String_Expr
-  rating: Float
-  releaseYear: Int
-  tags: [String!]
-  title: String
-  title_expr: String_Expr
-}
-input Movie_Filter {
-  _and: [Movie_Filter!]
-  _not: Movie_Filter
-  _or: [Movie_Filter!]
-  id: UUID_Filter
-  sequelToId: UUID_Filter
-  sequelTo: Movie_Filter
-  description: String_Filter
-  descriptionEmbedding: Vector_Filter
-  genre: String_Filter
-  imageUrl: String_Filter
-  rating: Float_Filter
-  releaseYear: Int_Filter
-  tags: String_ListFilter
-  title: String_Filter
-  favoriteMovies_on_movie: FavoriteMovie_ListFilter
-  movies_on_sequelTo: Movie_ListFilter
-  movieActors_on_movie: MovieActor_ListFilter
-  movieMetadatas_on_movie: MovieMetadata_ListFilter
-  reviews_on_movie: Review_ListFilter
-  watchedMovies_on_movie: WatchedMovie_ListFilter
-  actors_via_MovieActor: Actor_ListFilter
-  users_via_FavoriteMovie: User_ListFilter
-  users_via_Review: User_ListFilter
-  users_via_WatchedMovie: User_ListFilter
-}
-input Movie_ListFilter {
-  count: Int_Filter
-  exist: Movie_Filter
-}
-input Movie_Order {
-  id: OrderDirection
-  sequelToId: OrderDirection
-  sequelTo: Movie_Order
-  description: OrderDirection
-  descriptionEmbedding: OrderDirection
-  genre: OrderDirection
-  imageUrl: OrderDirection
-  rating: OrderDirection
-  releaseYear: OrderDirection
-  title: OrderDirection
-}
-input MovieActor_Data {
-  movieId: UUID
-  movieId_expr: UUID_Expr
-  actorId: UUID
-  actorId_expr: UUID_Expr
-  actor: Actor_Key
-  movie: Movie_Key
-  role: String
-  role_expr: String_Expr
-}
-input MovieActor_Filter {
-  _and: [MovieActor_Filter!]
-  _not: MovieActor_Filter
-  _or: [MovieActor_Filter!]
-  movieId: UUID_Filter
-  actorId: UUID_Filter
-  actor: Actor_Filter
-  movie: Movie_Filter
-  role: String_Filter
-}
-input MovieActor_ListFilter {
-  count: Int_Filter
-  exist: MovieActor_Filter
-}
-input MovieActor_Order {
-  movieId: OrderDirection
-  actorId: OrderDirection
-  actor: Actor_Order
-  movie: Movie_Order
-  role: OrderDirection
-}
-input MovieMetadata_Data {
-  id: UUID
-  id_expr: UUID_Expr
-  movieId: UUID
-  movieId_expr: UUID_Expr
-  movie: Movie_Key
-  director: String
-  director_expr: String_Expr
-}
-input MovieMetadata_Filter {
-  _and: [MovieMetadata_Filter!]
-  _not: MovieMetadata_Filter
-  _or: [MovieMetadata_Filter!]
-  id: UUID_Filter
-  movieId: UUID_Filter
-  movie: Movie_Filter
-  director: String_Filter
-}
-input MovieMetadata_ListFilter {
-  count: Int_Filter
-  exist: MovieMetadata_Filter
-}
-input MovieMetadata_Order {
-  id: OrderDirection
-  movieId: OrderDirection
-  movie: Movie_Order
-  director: OrderDirection
-}
-input Review_Data {
-  movieId: UUID
-  movieId_expr: UUID_Expr
-  userId: String
-  userId_expr: String_Expr
-  movie: Movie_Key
-  user: User_Key
-  id: UUID
-  id_expr: UUID_Expr
-  rating: Int
-  reviewDate: Date
-  reviewDate_date: Date_Relative
-  reviewDate_expr: Date_Expr
-  reviewText: String
-  reviewText_expr: String_Expr
-}
-input Review_Filter {
-  _and: [Review_Filter!]
-  _not: Review_Filter
-  _or: [Review_Filter!]
-  movieId: UUID_Filter
-  userId: String_Filter
-  movie: Movie_Filter
-  user: User_Filter
-  id: UUID_Filter
-  rating: Int_Filter
-  reviewDate: Date_Filter
-  reviewText: String_Filter
-}
-input Review_ListFilter {
-  count: Int_Filter
-  exist: Review_Filter
-}
-input Review_Order {
-  movieId: OrderDirection
-  userId: OrderDirection
-  movie: Movie_Order
-  user: User_Order
-  id: OrderDirection
-  rating: OrderDirection
-  reviewDate: OrderDirection
-  reviewText: OrderDirection
-}
-input User_Data {
-  id: String
-  id_expr: String_Expr
-  username: String
-  username_expr: String_Expr
-}
-input User_Filter {
-  _and: [User_Filter!]
-  _not: User_Filter
-  _or: [User_Filter!]
-  id: String_Filter
-  username: String_Filter
-  favoriteActors_on_user: FavoriteActor_ListFilter
-  favoriteMovies_on_user: FavoriteMovie_ListFilter
-  reviews_on_user: Review_ListFilter
-  watchedMovies_on_user: WatchedMovie_ListFilter
-  actors_via_FavoriteActor: Actor_ListFilter
-  movies_via_FavoriteMovie: Movie_ListFilter
-  movies_via_Review: Movie_ListFilter
-  movies_via_WatchedMovie: Movie_ListFilter
-}
-input User_ListFilter {
-  count: Int_Filter
-  exist: User_Filter
-}
-input User_Order {
-  id: OrderDirection
-  username: OrderDirection
-}
-input WatchedMovie_Data {
-  userId: String
-  userId_expr: String_Expr
-  movieId: UUID
-  movieId_expr: UUID_Expr
-  movie: Movie_Key
-  user: User_Key
-}
-input WatchedMovie_Filter {
-  _and: [WatchedMovie_Filter!]
-  _not: WatchedMovie_Filter
-  _or: [WatchedMovie_Filter!]
-  userId: String_Filter
-  movieId: UUID_Filter
-  movie: Movie_Filter
-  user: User_Filter
-}
-input WatchedMovie_ListFilter {
-  count: Int_Filter
-  exist: WatchedMovie_Filter
-}
-input WatchedMovie_Order {
-  userId: OrderDirection
-  movieId: OrderDirection
-  movie: Movie_Order
-  user: User_Order
-}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql
deleted file mode 100755
index 89c6e66db..000000000
--- a/dataconnect/dataconnect/.dataconnect/schema/main/mutation.gql
+++ /dev/null
@@ -1,218 +0,0 @@
-extend type Mutation {
-  """
-  Insert a single Actor into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
-  """
-  actor_insert(data: Actor_Data!): Actor_Key!
-  """
-  Insert a single FavoriteActor into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
-  """
-  favoriteActor_insert(data: FavoriteActor_Data!): FavoriteActor_Key!
-  """
-  Insert a single FavoriteMovie into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
-  """
-  favoriteMovie_insert(data: FavoriteMovie_Data!): FavoriteMovie_Key!
-  """
-  Insert a single Movie into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
-  """
-  movie_insert(data: Movie_Data!): Movie_Key!
-  """
-  Insert a single MovieActor into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
-  """
-  movieActor_insert(data: MovieActor_Data!): MovieActor_Key!
-  """
-  Insert a single MovieMetadata into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
-  """
-  movieMetadata_insert(data: MovieMetadata_Data!): MovieMetadata_Key!
-  """
-  Insert a single Review into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
-  """
-  review_insert(data: Review_Data!): Review_Key!
-  """
-  Insert a single User into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
-  """
-  user_insert(data: User_Data!): User_Key!
-  """
-  Insert a single WatchedMovie into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
-  """
-  watchedMovie_insert(data: WatchedMovie_Data!): WatchedMovie_Key!
-  """
-  Insert or update a single Actor into the table, based on the primary key. Returns the key of the newly inserted Actor.
-  """
-  actor_upsert(data: Actor_Data!): Actor_Key!
-  """
-  Insert or update a single FavoriteActor into the table, based on the primary key. Returns the key of the newly inserted FavoriteActor.
-  """
-  favoriteActor_upsert(data: FavoriteActor_Data!): FavoriteActor_Key!
-  """
-  Insert or update a single FavoriteMovie into the table, based on the primary key. Returns the key of the newly inserted FavoriteMovie.
-  """
-  favoriteMovie_upsert(data: FavoriteMovie_Data!): FavoriteMovie_Key!
-  """
-  Insert or update a single Movie into the table, based on the primary key. Returns the key of the newly inserted Movie.
-  """
-  movie_upsert(data: Movie_Data!): Movie_Key!
-  """
-  Insert or update a single MovieActor into the table, based on the primary key. Returns the key of the newly inserted MovieActor.
-  """
-  movieActor_upsert(data: MovieActor_Data!): MovieActor_Key!
-  """
-  Insert or update a single MovieMetadata into the table, based on the primary key. Returns the key of the newly inserted MovieMetadata.
-  """
-  movieMetadata_upsert(data: MovieMetadata_Data!): MovieMetadata_Key!
-  """
-  Insert or update a single Review into the table, based on the primary key. Returns the key of the newly inserted Review.
-  """
-  review_upsert(data: Review_Data!): Review_Key!
-  """
-  Insert or update a single User into the table, based on the primary key. Returns the key of the newly inserted User.
-  """
-  user_upsert(data: User_Data!): User_Key!
-  """
-  Insert or update a single WatchedMovie into the table, based on the primary key. Returns the key of the newly inserted WatchedMovie.
-  """
-  watchedMovie_upsert(data: WatchedMovie_Data!): WatchedMovie_Key!
-  """
-  Update a single Actor based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
-  """
-  actor_update(id: UUID, key: Actor_Key, data: Actor_Data!): Actor_Key
-  """
-  Update a single FavoriteActor based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
-  """
-  favoriteActor_update(key: FavoriteActor_Key, data: FavoriteActor_Data!): FavoriteActor_Key
-  """
-  Update a single FavoriteMovie based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
-  """
-  favoriteMovie_update(key: FavoriteMovie_Key, data: FavoriteMovie_Data!): FavoriteMovie_Key
-  """
-  Update a single Movie based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
-  """
-  movie_update(id: UUID, key: Movie_Key, data: Movie_Data!): Movie_Key
-  """
-  Update a single MovieActor based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
-  """
-  movieActor_update(key: MovieActor_Key, data: MovieActor_Data!): MovieActor_Key
-  """
-  Update a single MovieMetadata based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
-  """
-  movieMetadata_update(id: UUID, key: MovieMetadata_Key, data: MovieMetadata_Data!): MovieMetadata_Key
-  """
-  Update a single Review based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
-  """
-  review_update(key: Review_Key, data: Review_Data!): Review_Key
-  """
-  Update a single User based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
-  """
-  user_update(id: String, id_expr: String_Expr, key: User_Key, data: User_Data!): User_Key
-  """
-  Update a single WatchedMovie based on `id` or `key`, setting columns specified in `data`. Returns `null` if not found.
-  """
-  watchedMovie_update(key: WatchedMovie_Key, data: WatchedMovie_Data!): WatchedMovie_Key
-  """
-  Update Actor entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
-  """
-  actor_updateMany(where: Actor_Filter, all: Boolean = false, data: Actor_Data!): Int!
-  """
-  Update FavoriteActor entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
-  """
-  favoriteActor_updateMany(where: FavoriteActor_Filter, all: Boolean = false, data: FavoriteActor_Data!): Int!
-  """
-  Update FavoriteMovie entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
-  """
-  favoriteMovie_updateMany(where: FavoriteMovie_Filter, all: Boolean = false, data: FavoriteMovie_Data!): Int!
-  """
-  Update Movie entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
-  """
-  movie_updateMany(where: Movie_Filter, all: Boolean = false, data: Movie_Data!): Int!
-  """
-  Update MovieActor entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
-  """
-  movieActor_updateMany(where: MovieActor_Filter, all: Boolean = false, data: MovieActor_Data!): Int!
-  """
-  Update MovieMetadata entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
-  """
-  movieMetadata_updateMany(where: MovieMetadata_Filter, all: Boolean = false, data: MovieMetadata_Data!): Int!
-  """
-  Update Review entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
-  """
-  review_updateMany(where: Review_Filter, all: Boolean = false, data: Review_Data!): Int!
-  """
-  Update User entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
-  """
-  user_updateMany(where: User_Filter, all: Boolean = false, data: User_Data!): Int!
-  """
-  Update WatchedMovie entries matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
-  """
-  watchedMovie_updateMany(where: WatchedMovie_Filter, all: Boolean = false, data: WatchedMovie_Data!): Int!
-  """
-  Delete a single Actor based on `id` or `key` and return its key (or `null` if not found).
-  """
-  actor_delete(id: UUID, key: Actor_Key): Actor_Key
-  """
-  Delete a single FavoriteActor based on `id` or `key` and return its key (or `null` if not found).
-  """
-  favoriteActor_delete(key: FavoriteActor_Key): FavoriteActor_Key
-  """
-  Delete a single FavoriteMovie based on `id` or `key` and return its key (or `null` if not found).
-  """
-  favoriteMovie_delete(key: FavoriteMovie_Key): FavoriteMovie_Key
-  """
-  Delete a single Movie based on `id` or `key` and return its key (or `null` if not found).
-  """
-  movie_delete(id: UUID, key: Movie_Key): Movie_Key
-  """
-  Delete a single MovieActor based on `id` or `key` and return its key (or `null` if not found).
-  """
-  movieActor_delete(key: MovieActor_Key): MovieActor_Key
-  """
-  Delete a single MovieMetadata based on `id` or `key` and return its key (or `null` if not found).
-  """
-  movieMetadata_delete(id: UUID, key: MovieMetadata_Key): MovieMetadata_Key
-  """
-  Delete a single Review based on `id` or `key` and return its key (or `null` if not found).
-  """
-  review_delete(key: Review_Key): Review_Key
-  """
-  Delete a single User based on `id` or `key` and return its key (or `null` if not found).
-  """
-  user_delete(id: String, id_expr: String_Expr, key: User_Key): User_Key
-  """
-  Delete a single WatchedMovie based on `id` or `key` and return its key (or `null` if not found).
-  """
-  watchedMovie_delete(key: WatchedMovie_Key): WatchedMovie_Key
-  """
-  Delete Actor entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
-  """
-  actor_deleteMany(where: Actor_Filter, all: Boolean = false): Int!
-  """
-  Delete FavoriteActor entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
-  """
-  favoriteActor_deleteMany(where: FavoriteActor_Filter, all: Boolean = false): Int!
-  """
-  Delete FavoriteMovie entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
-  """
-  favoriteMovie_deleteMany(where: FavoriteMovie_Filter, all: Boolean = false): Int!
-  """
-  Delete Movie entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
-  """
-  movie_deleteMany(where: Movie_Filter, all: Boolean = false): Int!
-  """
-  Delete MovieActor entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
-  """
-  movieActor_deleteMany(where: MovieActor_Filter, all: Boolean = false): Int!
-  """
-  Delete MovieMetadata entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
-  """
-  movieMetadata_deleteMany(where: MovieMetadata_Filter, all: Boolean = false): Int!
-  """
-  Delete Review entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
-  """
-  review_deleteMany(where: Review_Filter, all: Boolean = false): Int!
-  """
-  Delete User entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
-  """
-  user_deleteMany(where: User_Filter, all: Boolean = false): Int!
-  """
-  Delete WatchedMovie entries matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
-  """
-  watchedMovie_deleteMany(where: WatchedMovie_Filter, all: Boolean = false): Int!
-}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/query.gql b/dataconnect/dataconnect/.dataconnect/schema/main/query.gql
deleted file mode 100755
index 2784eb715..000000000
--- a/dataconnect/dataconnect/.dataconnect/schema/main/query.gql
+++ /dev/null
@@ -1,79 +0,0 @@
-extend type Query {
-  """
-  Look up a single Actor based on `id` or `key` and return selected fields (or `null` if not found).
-  """
-  actor(id: UUID, key: Actor_Key): Actor
-  """
-  Look up a single FavoriteActor based on `id` or `key` and return selected fields (or `null` if not found).
-  """
-  favoriteActor(key: FavoriteActor_Key): FavoriteActor
-  """
-  Look up a single FavoriteMovie based on `id` or `key` and return selected fields (or `null` if not found).
-  """
-  favoriteMovie(key: FavoriteMovie_Key): FavoriteMovie
-  """
-  Look up a single Movie based on `id` or `key` and return selected fields (or `null` if not found).
-  """
-  movie(id: UUID, key: Movie_Key): Movie
-  """
-  Look up a single MovieActor based on `id` or `key` and return selected fields (or `null` if not found).
-  """
-  movieActor(key: MovieActor_Key): MovieActor
-  """
-  Look up a single MovieMetadata based on `id` or `key` and return selected fields (or `null` if not found).
-  """
-  movieMetadata(id: UUID, key: MovieMetadata_Key): MovieMetadata
-  """
-  Look up a single Review based on `id` or `key` and return selected fields (or `null` if not found).
-  """
-  review(key: Review_Key): Review
-  """
-  Look up a single User based on `id` or `key` and return selected fields (or `null` if not found).
-  """
-  user(id: String, id_expr: String_Expr, key: User_Key): User
-  """
-  Look up a single WatchedMovie based on `id` or `key` and return selected fields (or `null` if not found).
-  """
-  watchedMovie(key: WatchedMovie_Key): WatchedMovie
-  """
-  List Actor entries in the table, optionally filtered by `where` conditions.
-  """
-  actors(where: Actor_Filter, orderBy: [Actor_Order!], limit: Int = 100): [Actor!]!
-  """
-  List FavoriteActor entries in the table, optionally filtered by `where` conditions.
-  """
-  favoriteActors(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [FavoriteActor!]!
-  """
-  List FavoriteMovie entries in the table, optionally filtered by `where` conditions.
-  """
-  favoriteMovies(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [FavoriteMovie!]!
-  """
-  List Movie entries in the table, optionally filtered by `where` conditions.
-  """
-  movies(where: Movie_Filter, orderBy: [Movie_Order!], limit: Int = 100): [Movie!]!
-  """
-  List MovieActor entries in the table, optionally filtered by `where` conditions.
-  """
-  movieActors(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [MovieActor!]!
-  """
-  List MovieMetadata entries in the table, optionally filtered by `where` conditions.
-  """
-  movieMetadatas(where: MovieMetadata_Filter, orderBy: [MovieMetadata_Order!], limit: Int = 100): [MovieMetadata!]!
-  """
-  List Review entries in the table, optionally filtered by `where` conditions.
-  """
-  reviews(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Review!]!
-  """
-  List User entries in the table, optionally filtered by `where` conditions.
-  """
-  users(where: User_Filter, orderBy: [User_Order!], limit: Int = 100): [User!]!
-  """
-  List WatchedMovie entries in the table, optionally filtered by `where` conditions.
-  """
-  watchedMovies(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [WatchedMovie!]!
-  """
-  List Movie entries ordered by vector similarity between the `descriptionEmbedding` field and `compare_embed`.
-  (Alternatively, `compare` can be used if the input is a raw Vector.)
-  """
-  movies_descriptionEmbedding_similarity(compare: Vector, compare_embed: Vector_Embed, method: VectorSimilarityMethod = INNER_PRODUCT, within: Float, where: Movie_Filter, limit: Int = 100): [Movie!]!
-}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql b/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql
deleted file mode 100755
index 7cc34201b..000000000
--- a/dataconnect/dataconnect/.dataconnect/schema/main/relation.gql
+++ /dev/null
@@ -1,94 +0,0 @@
-extend type Actor {
-  """
-  ✨ List FavoriteActor entries in a one-to-many relationship with this object (i.e. where `FavoriteActor.actor` equals this object).
-  """
-  favoriteActors_on_actor(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [FavoriteActor!]!
-  """
-  ✨ List MovieActor entries in a one-to-many relationship with this object (i.e. where `MovieActor.actor` equals this object).
-  """
-  movieActors_on_actor(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [MovieActor!]!
-  """
-  ✨ List related Movie entries using MovieActor as a join table (i.e. where an entry of MovieActor exists whose actor == this and movie == that).
-  """
-  movies_via_MovieActor(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [Movie!]!
-  """
-  ✨ List related User entries using FavoriteActor as a join table (i.e. where an entry of FavoriteActor exists whose actor == this and user == that).
-  """
-  users_via_FavoriteActor(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [User!]!
-}
-extend type Movie {
-  """
-  ✨ List FavoriteMovie entries in a one-to-many relationship with this object (i.e. where `FavoriteMovie.movie` equals this object).
-  """
-  favoriteMovies_on_movie(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [FavoriteMovie!]!
-  """
-  ✨ List Movie entries in a one-to-many relationship with this object (i.e. where `Movie.sequelTo` equals this object).
-  """
-  movies_on_sequelTo(where: Movie_Filter, orderBy: [Movie_Order!], limit: Int = 100): [Movie!]!
-  """
-  ✨ List MovieActor entries in a one-to-many relationship with this object (i.e. where `MovieActor.movie` equals this object).
-  """
-  movieActors_on_movie(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [MovieActor!]!
-  """
-  ✨ List MovieMetadata entries in a one-to-many relationship with this object (i.e. where `MovieMetadata.movie` equals this object).
-  """
-  movieMetadatas_on_movie(where: MovieMetadata_Filter, orderBy: [MovieMetadata_Order!], limit: Int = 100): [MovieMetadata!]!
-  """
-  ✨ List Review entries in a one-to-many relationship with this object (i.e. where `Review.movie` equals this object).
-  """
-  reviews_on_movie(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Review!]!
-  """
-  ✨ List WatchedMovie entries in a one-to-many relationship with this object (i.e. where `WatchedMovie.movie` equals this object).
-  """
-  watchedMovies_on_movie(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [WatchedMovie!]!
-  """
-  ✨ List related Actor entries using MovieActor as a join table (i.e. where an entry of MovieActor exists whose movie == this and actor == that).
-  """
-  actors_via_MovieActor(where: MovieActor_Filter, orderBy: [MovieActor_Order!], limit: Int = 100): [Actor!]!
-  """
-  ✨ List related User entries using FavoriteMovie as a join table (i.e. where an entry of FavoriteMovie exists whose movie == this and user == that).
-  """
-  users_via_FavoriteMovie(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [User!]!
-  """
-  ✨ List related User entries using Review as a join table (i.e. where an entry of Review exists whose movie == this and user == that).
-  """
-  users_via_Review(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [User!]!
-  """
-  ✨ List related User entries using WatchedMovie as a join table (i.e. where an entry of WatchedMovie exists whose movie == this and user == that).
-  """
-  users_via_WatchedMovie(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [User!]!
-}
-extend type User {
-  """
-  ✨ List FavoriteActor entries in a one-to-many relationship with this object (i.e. where `FavoriteActor.user` equals this object).
-  """
-  favoriteActors_on_user(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [FavoriteActor!]!
-  """
-  ✨ List FavoriteMovie entries in a one-to-many relationship with this object (i.e. where `FavoriteMovie.user` equals this object).
-  """
-  favoriteMovies_on_user(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [FavoriteMovie!]!
-  """
-  ✨ List Review entries in a one-to-many relationship with this object (i.e. where `Review.user` equals this object).
-  """
-  reviews_on_user(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Review!]!
-  """
-  ✨ List WatchedMovie entries in a one-to-many relationship with this object (i.e. where `WatchedMovie.user` equals this object).
-  """
-  watchedMovies_on_user(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [WatchedMovie!]!
-  """
-  ✨ List related Actor entries using FavoriteActor as a join table (i.e. where an entry of FavoriteActor exists whose user == this and actor == that).
-  """
-  actors_via_FavoriteActor(where: FavoriteActor_Filter, orderBy: [FavoriteActor_Order!], limit: Int = 100): [Actor!]!
-  """
-  ✨ List related Movie entries using FavoriteMovie as a join table (i.e. where an entry of FavoriteMovie exists whose user == this and movie == that).
-  """
-  movies_via_FavoriteMovie(where: FavoriteMovie_Filter, orderBy: [FavoriteMovie_Order!], limit: Int = 100): [Movie!]!
-  """
-  ✨ List related Movie entries using Review as a join table (i.e. where an entry of Review exists whose user == this and movie == that).
-  """
-  movies_via_Review(where: Review_Filter, orderBy: [Review_Order!], limit: Int = 100): [Movie!]!
-  """
-  ✨ List related Movie entries using WatchedMovie as a join table (i.e. where an entry of WatchedMovie exists whose user == this and movie == that).
-  """
-  movies_via_WatchedMovie(where: WatchedMovie_Filter, orderBy: [WatchedMovie_Order!], limit: Int = 100): [Movie!]!
-}
diff --git a/dataconnect/dataconnect/.dataconnect/schema/prelude.gql b/dataconnect/dataconnect/.dataconnect/schema/prelude.gql
deleted file mode 100755
index 3782971fe..000000000
--- a/dataconnect/dataconnect/.dataconnect/schema/prelude.gql
+++ /dev/null
@@ -1,947 +0,0 @@
-"AccessLevel specifies coarse access policies for common situations."
-enum AccessLevel {
-  """
-  This operation can be executed by anyone with or without authentication.
-  Equivalent to @auth(expr: "true")
-  """
-  PUBLIC
-
-  """
-  This operation can only be executed with a valid Firebase Auth ID token.
-  Note: it allows anonymous auth and unverified accounts, so may be subjected to abuses.
-  It’s equivalent to @auth(expr: "auth.uid != nil")
-  """
-  USER_ANON
-
-  """
-  This operation can only be executed by a non-anonymous Firebase Auth account.
-  It’s equivalent to @auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")"
-  """
-  USER
-
-  """
-  This operation can only be executed by a verified Firebase Auth account.
-  It’s equivalent to @auth(expr: "auth.uid != nil && auth.token.email_verified")"
-  """
-  USER_EMAIL_VERIFIED
-
-  """
-  This operation can not be executed with no IAM credentials.
-  It’s equivalent to @auth(expr: "false")
-  """
-  NO_ACCESS
-}
-
-"""
-Defines the auth policy for a query or mutation. This directive must be added to
-any operation you wish to be accessible from a client application. If left
-unspecified, defaults to `@auth(level: NO_ACCESS)`.
-"""
-directive @auth(
-  "The minimal level of access required to perform this operation."
-  level: AccessLevel @fdc_oneOf(required: true)
-  """
-  A CEL expression that allows access to this operation if the expression
-  evaluates to `true`.
-  """
-  expr: Boolean_Expr @fdc_oneOf(required: true)
-) on QUERY | MUTATION
-"Conditions on a string value"
-input String_Filter {
-  isNull: Boolean
-  eq: String @fdc_oneOf(group: "eq")
-  eq_expr: String_Expr @fdc_oneOf(group: "eq")
-  ne: String @fdc_oneOf(group: "ne")
-  ne_expr: String_Expr @fdc_oneOf(group: "ne")
-  in: [String!]
-  nin: [String!]
-  gt: String
-  ge: String
-  lt: String
-  le: String
-  contains: String
-  startsWith: String
-  endsWith: String
-  pattern: String_Pattern
-}
-
-"""
-The pattern match condition on a string. Specify either like or regex.
-https://www.postgresql.org/docs/current/functions-matching.html
-"""
-input String_Pattern {
-  "the LIKE expression to use"
-  like: String
-  "the POSIX regular expression"
-  regex: String
-  "when true, it's case-insensitive. In Postgres: ILIKE, ~*"
-  ignoreCase: Boolean
-  "when true, invert the condition. In Postgres: NOT LIKE, !~"
-  invert: Boolean
-}
-
-"Conditions on a string list"
-input String_ListFilter {
-  includes: String
-  excludes: String
-  includesAll: [String!]
-  excludesAll: [String!]
-}
-
-"Conditions on a UUID value"
-input UUID_Filter {
-  isNull: Boolean
-  eq: UUID
-  ne: UUID
-  in: [UUID!]
-  nin: [UUID!]
-}
-
-"Conditions on a UUID list"
-input UUID_ListFilter {
-  includes: UUID
-  excludes: UUID
-  includesAll: [UUID!]
-  excludesAll: [UUID!]
-}
-
-"Conditions on an Int value"
-input Int_Filter {
-  isNull: Boolean
-  eq: Int
-  ne: Int
-  in: [Int!]
-  nin: [Int!]
-  gt: Int
-  ge: Int
-  lt: Int
-  le: Int
-}
-
-"Conditions on an Int list"
-input Int_ListFilter {
-  includes: Int
-  excludes: Int
-  includesAll: [Int!]
-  excludesAll: [Int!]
-}
-
-"Conditions on an Int64 value"
-input Int64_Filter {
-  isNull: Boolean
-  eq: Int64
-  ne: Int64
-  in: [Int64!]
-  nin: [Int64!]
-  gt: Int64
-  ge: Int64
-  lt: Int64
-  le: Int64
-}
-
-"Conditions on an Int64 list"
-input Int64_ListFilter {
-  includes: Int64
-  excludes: Int64
-  includesAll: [Int64!]
-  excludesAll: [Int64!]
-}
-
-"Conditions on a Float value"
-input Float_Filter {
-  isNull: Boolean
-  eq: Float
-  ne: Float
-  in: [Float!]
-  nin: [Float!]
-  gt: Float
-  ge: Float
-  lt: Float
-  le: Float
-}
-
-"Conditions on a Float list"
-input Float_ListFilter {
-  includes: Float
-  excludes: Float
-  includesAll: [Float!]
-  excludesAll: [Float!]
-}
-
-"Conditions on a Boolean value"
-input Boolean_Filter {
-  isNull: Boolean
-  eq: Boolean
-  ne: Boolean
-  in: [Boolean!]
-  nin: [Boolean!]
-}
-
-"Conditions on a Boolean list"
-input Boolean_ListFilter {
-  includes: Boolean
-  excludes: Boolean
-  includesAll: [Boolean!]
-  excludesAll: [Boolean!]
-}
-
-"Conditions on an Any value"
-input Any_Filter {
-  isNull: Boolean
-  eq: Any
-  ne: Any
-  in: [Any!]
-  nin: [Any!]
-}
-
-"Conditions on a Any list"
-input Any_ListFilter {
-  includes: Any
-  excludes: Any
-  includesAll: [Any!]
-  excludesAll: [Any!]
-}
-type Query {
-  _service: _Service!
-}
-
-type Mutation {
-  # This is just a dummy field so that Mutation is always non-empty.
-  _firebase: Void @fdc_deprecated(reason: "dummy field -- does nothing useful")
-}
-
-type _Service {
-  sdl: String!
-}
-
-"(Internal) Added to things that may be removed from FDC and will soon be no longer usable in schema or operations."
-directive @fdc_deprecated(reason: String = "No longer supported") on
-  | SCHEMA
-  | SCALAR
-  | OBJECT
-  | FIELD_DEFINITION
-  | ARGUMENT_DEFINITION
-  | INTERFACE
-  | UNION
-  | ENUM
-  | ENUM_VALUE
-  | INPUT_OBJECT
-  | INPUT_FIELD_DEFINITION
-
-"(Internal) Added to scalars representing quoted CEL expressions."
-directive @fdc_celExpression(
-  "The expected CEL type that the expression should evaluate to."
-  returnType: String
-) on SCALAR
-
-"(Internal) Added to scalars representing quoted SQL expressions."
-directive @fdc_sqlExpression(
-  "The expected SQL type that the expression should evaluate to."
-  dataType: String
-) on SCALAR
-
-"(Internal) Added to types that may not be used as variables."
-directive @fdc_forbiddenAsVariableType on SCALAR | OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT
-
-"(Internal) Added to types that may not be used as fields in schema."
-directive @fdc_forbiddenAsFieldType on SCALAR | OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT
-
-"Provides a frequently used example for this type / field / argument."
-directive @fdc_example(
-  "A GraphQL literal value (verbatim) whose type matches the target."
-  value: Any
-  "A human-readable text description of what `value` means in this context."
-  description: String
-) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | INPUT_OBJECT | INPUT_FIELD_DEFINITION
-
-"(Internal) Marks this field / argument as conflicting with others in the same group."
-directive @fdc_oneOf(
-  "The group name where fields / arguments conflict with each other."
-  group: String! = ""
-  "If true, exactly one field / argument in the group must be specified."
-  required: Boolean! = false
-) repeatable on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
-"""
-UUID is a string with hex digits representing an RFC4122 value.
-
-Outputs will always be 32 lower-case hex digits with no delimiters or curly
-braces. Inputs in the following formats are also accepted (case insensitive):
-
-    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-    urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-    {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
-"""
-scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
-scalar Int64
-
-scalar Any
-scalar Void
-"""
-The `True` scalar type only accepts the boolean `true`.
-
-An optional field / argument typed `True` may either be set to `true` or omitted
-(not provided at all). `false` or `null` is not accepted.
-"""
-scalar True
-  @fdc_forbiddenAsFieldType
-  @fdc_forbiddenAsVariableType
-  @fdc_example(value: true, description: "The only allowed value.")
-"Define the intervals used in timestamps and dates (subset)"
-enum TimestampInterval @fdc_deprecated {
-  second
-  minute
-  hour
-  day
-  week
-  month
-  year
-}
-"""
-A Common Expression Language (CEL) expression that returns a boolean at runtime.
-
-The expression can reference the `auth` variable, which is null if Firebase Auth
-is not used. Otherwise, it contains the following fields:
-
-    - `auth.uid`: The current user ID.
-    - `auth.token`: A map of all token fields (i.e. "claims").
-"""
-scalar Boolean_Expr
-  @specifiedBy(url: "https://github.com/google/cel-spec")
-  @fdc_celExpression(returnType: "bool")
-  @fdc_forbiddenAsVariableType
-  @fdc_forbiddenAsFieldType
-  @fdc_example(value: "auth != null", description: "Allow only if a Firebase Auth user is present.")
-
-"""
-A Common Expression Language (CEL) expression that returns a string at runtime.
-
-Limitation: Right now, only a few expressions are supported. Those are listed
-using the @fdc_example directive on this scalar.
-"""
-scalar String_Expr
-  @specifiedBy(url: "https://github.com/google/cel-spec")
-  @fdc_celExpression(returnType: "string")
-  @fdc_forbiddenAsVariableType
-  @fdc_forbiddenAsFieldType
-  @fdc_example(value: "auth.uid", description: "The ID of the currently logged in user in Firebase Auth. (Errors if not logged in.)")
-  @fdc_example(value: "uuidV4()", description: "Generates a new random UUID (version 4) string, formatted as 32 lower-case hex digits without delimiters.")
-
-"""
-A Common Expression Language (CEL) expression that returns a UUID string at runtime.
-
-Limitation: Right now, only a few expressions are supported. Those are listed
-using the @fdc_example directive on this scalar.
-"""
-scalar UUID_Expr
-  @specifiedBy(url: "https://github.com/google/cel-spec")
-  @fdc_celExpression(returnType: "string")
-  @fdc_forbiddenAsVariableType
-  @fdc_forbiddenAsFieldType
-  @fdc_example(value: "uuidV4()", description: "Generates a new random UUID (version 4) every time.")
-
-"""
-A Common Expression Language (CEL) expression whose return type is unspecified.
-
-Limitation: Only a limited set of expressions are supported for now for each
-type. For type XXX, see the @fdc_example directives on XXX_Expr for a full list.
-"""
-scalar Any_Expr
-  @specifiedBy(url: "https://github.com/google/cel-spec")
-  @fdc_celExpression
-  @fdc_forbiddenAsVariableType
-  @fdc_forbiddenAsFieldType
-  @fdc_example(value: "auth.uid", description: "The ID of the currently logged in user in Firebase Auth. (Errors if not logged in.)")
-  @fdc_example(value: "uuidV4()", description: "Generates a new random UUID version 4 (formatted as 32 lower-case hex digits without delimiters if result type is String).")
-  @fdc_example(value: "request.time", description: "The timestamp when the request is received (with microseconds precision).")
-
-"""
-A PostgreSQL value expression whose return type is unspecified.
-"""
-scalar Any_SQL
-  @specifiedBy(url: "https://www.postgresql.org/docs/current/sql-expressions.html")
-  @fdc_sqlExpression
-  @fdc_forbiddenAsVariableType
-  @fdc_forbiddenAsFieldType
-"""
-Defines a relational database table.
-
-Given `type TableName @table`,
-
- - `TableName` is the GQL type name.
- - `tableName` is the singular name. Override with `@table(singular)`.
- - `tableNames` is the plural name. Override with `@table(plural)`.
- - `table_name` is the SQL table id. Override with `@table(name)`.
-
-Only a table type can be configured further with:
-
- - Customized data types. See `@col`.
- - Index. See `@index`
- - Unique constraint. See `@unqiue`
- - Relation. See `@ref`
- - Embedded Json. See `@embed`
-
-A scalar field map to a SQL database column.
-An object field (like `type TableName @table { field: AnotherType }`) are either
-
- - a relation reference field if `AnotherType` is annotated with `@table`.
- - an embedded json field if `field` is annotated with `@embed`.
-
-"""
-directive @table(
-  "Override the SQL database table name. Defaults to <table_name>."
-  name: String
-  "Override the singular name. Default is the camel case of the type name."
-  singular: String
-  "Override the plural name. Default is generated based on English patterns."
-  plural: String
-  "The primary key of the table. Defaults to a single field `id: UUID!`. Generate if missing."
-  key: [String!]
-) on OBJECT
-
-"""
-Defines a relational database view.
-
-Given `type ViewName @view`,
- - `ViewName` is the GQL type name.
- - `viewName` is the singular name. Override with `@view(singular)`.
- - `viewNames` is the plural name. Override with `@view(plural)`.
- - `view_name` is the SQL view id. Override with `@view(name)`.
-    When `@view(sql)` is defined, it uses the given raw SQL as the view instead.
-
-A view type can be used just as a table type with queries.
-A view type may have a nullable `@ref` field to another table, but cannot be
-referenced in a `@ref`.
-
-WARNING: Firebase Data Connect does not validate the SQL of the view or
-evaluate whether it matches the defined fields.
-
-If the SQL view is invalid or undefined, related requests may fail.
-If the SQL view return incompatible types. Firebase Data Connect will surface
-an error in the response.
-"""
-directive @view(
-  """
-  The SQL view name. If no `name` or `sql` are provided, defaults to
-  snake_case of the singular type name.
-  """
-  name: String @fdc_oneOf
-  """
-  SQL SELECT statement to use as the basis for this type. Note that all SQL
-  identifiers should be snake_case and all GraphQL identifiers should be
-  camelCase.
-  """
-  sql: String @fdc_oneOf
-  "Override the singular name. Default is the camel case of the type name."
-  singular: String
-  "Override the plural name. Default is generated based on English patterns."
-  plural: String
-) on OBJECT
-
-"""
-Specify additional column options.
-
-Given `type TableName @table { fieldName: Int } `
-
- - `field_name` is the SQL column name. Override with `@col(name)`.
-
-"""
-directive @col(
-  "The SQL database column name. Defaults to <field_name>."
-  name: String
-  """
-  Override SQL columns data type.
-  Each GraphQL type could map to many SQL data types.
-  Refer to Postgres supported data types and mappings to GQL.
-  """
-  dataType: String
-  """
-  Defines a fixed column size for certain scalar types.
-
-  - For Vector, size is required. It establishes the length of the vector.
-  - For String, size converts `text` type to `varchar(size)`.
-  """
-  size: Int
-) on FIELD_DEFINITION
-
-
-"""
-Define a reference field to another table.
-
-Given `type TableName @table { refField: AnotherTableName }`, it defines a foreign-key constraint
-
- - with id `table_name_ref_field_fkey` (override with `@ref(constraintName)`)
- - from `table_name.ref_field` (override with `@ref(fields)`)
- - to `another_table_name.id` (override with `@ref(references)`)
-
-Does not support `[AnotherTableName]` because array fields cannot have foreign-key constraints.
-Nullability determines whether the reference is required.
-
- - `refField: AnotherTableName`: optional reference, SET_NULL on delete.
- - `refField: AnotherTableName!`: required reference, CASCADE on delete.
-
-Consider all types of SQL relations:
-
- - many-to-one relations involve a reference field on the many-side.
-    - many-to-maybe-one if `refField: AnotherTableName`.
-    - many-to-exactly-one if `refField: AnotherTableName!`.
- - one-to-one relations involve a unique reference field on one side.
-    - maybe-one-to-maybe-one if `refField: AnotherTableName @unique`.
-    - maybe-one-to-exact-one if `refField: AnotherTableName! @unique`.
-    - exact-one-to-exact-one shall be represented as a single table instead.
- - many-to-many relations involve a join table.
-    - Its primary keys must be two non-null reference fields to tables bridged together to guarantee at most one relation per pair.
-
-type TableNameToAnotherTableName @table(key: ["refField", "anotherRefField"]) {
-  refField: TableName!
-  anotherRefField: AnotherTableName!
-}
-
-"""
-directive @ref(
-  "The SQL database foreign key constraint name. Default to <table_name>_<field_name>_fkey."
-  constraintName: String
-  """
-  Foreign key fields. Default to <tableName><PrimaryIdName>.
-  """
-  fields: [String!]
-  "The fields that the foreign key references in the other table. Default to the primary key."
-  references: [String!]
-) on FIELD_DEFINITION
-
-"Define the direction of an orderby query"
-enum OrderDirection {
-  ASC
-  DESC
-}
-
-enum ColDefault @fdc_deprecated {
-  """
-  Generates a random UUID (v4) as the default column value.
-  Compatible with String or UUID typed fields.
-  """
-  UUID
-  """
-  Generates an auto-incrementing sequence as the default column value.
-  Compatible with Int and Int64 typed fields.
-  """
-  SEQUENCE
-  """
-  Populates the default column value with the current date or timestamp.
-  Compatible with Date and Timestamp typed fields.
-  """
-  NOW
-}
-
-"""
-Specify the default column value.
-
-The supported arguments vary based on the field type.
-"""
-directive @default(
-  "A constant value. Validated against the field GraphQL type at compile-time."
-  value: Any @fdc_oneOf(required: true)
-  "(Deprecated) Built-in common ways to generate initial value."
-  generate: ColDefault @fdc_oneOf(required: true) @deprecated
-  "A CEL expression, whose return value must match the field data type."
-  expr: Any_Expr @fdc_oneOf(required: true)
-  """
-  A raw SQL expression, whose SQL data type must match the underlying column.
-
-  The value is any variable-free expression (in particular, cross-references to
-  other columns in the current table are not allowed). Subqueries are not allowed either.
-  https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-DEFAULT
-  """
-  sql: Any_SQL @fdc_oneOf(required: true)
-) on FIELD_DEFINITION
-"""
-Date is a string in the YYYY-MM-DD format representing a local-only date.
-
-See the description for Timestamp for range and limitations.
-
-As a FDC-specific extension, inputs that includes time portions (as specified by
-the Timestamp scalar) are accepted but only the date portion is used. In other
-words, only the part before "T" is used and the rest discarded. This effectively
-truncates it to the local date in the specified time-zone.
-
-Outputs will always be in the canonical YYYY-MM-DD format.
-"""
-scalar Date @specifiedBy(url: "https://scalars.graphql.org/andimarek/local-date.html")
-
-"""
-Timestamp is a RFC 3339 string that represents an exact point in time.
-
-The serialization format follows https://scalars.graphql.org/andimarek/date-time
-except the "Non-optional exact milliseconds" Section. As a FDC-specific
-extension, inputs and outputs may contain 0, 3, 6, or 9 fractional digits.
-
-Specifically, output precision varies by server-side factors such as data source
-support and clients must not rely on an exact number of digits. Clients may
-truncate extra digits as fit, with the caveat that there may be information loss
-if the truncated value is subsequently sent back to the server.
-
-FDC only supports year 1583 to 9999 (inclusive) and uses the ISO-8601 calendar
-system for all date-time calculations. Notably, the expanded year representation
-(+/-YYYYY) is rejected and Year 1582 and before may either be rejected or cause
-undefined behavior.
-"""
-scalar Timestamp @specifiedBy(url: "https://scalars.graphql.org/andimarek/date-time")
-
-"""
-A Common Expression Language (CEL) expression that returns a Timestamp at runtime.
-
-Limitation: Right now, only a few expressions are supported. Those are listed
-using the @fdc_example directive on this scalar.
-"""
-scalar Timestamp_Expr
-  @specifiedBy(url: "https://github.com/google/cel-spec")
-  @fdc_celExpression(returnType: "google.protobuf.Timestamp")
-  @fdc_forbiddenAsVariableType
-  @fdc_forbiddenAsFieldType
-  @fdc_example(value: "request.time", description: "The timestamp when the request is received (with microseconds precision).")
-
-"""
-A Common Expression Language (CEL) expression that returns a Timestamp at runtime,
-which is then truncated to UTC date only. The time-of-day parts are discarded.
-
-Limitation: Right now, only a few expressions are supported. Those are listed
-using the @fdc_example directive on this scalar.
-"""
-scalar Date_Expr
-  @specifiedBy(url: "https://github.com/google/cel-spec")
-  @fdc_celExpression(returnType: "google.protobuf.Timestamp")
-  @fdc_forbiddenAsVariableType
-  @fdc_forbiddenAsFieldType
-  @fdc_example(value: "request.time", description: "The UTC date on which the request is received.")
-
-"Conditions on a Date value"
-input Date_Filter {
-  isNull: Boolean
-  eq: Date @fdc_oneOf(group: "eq")
-  eq_expr: Date_Expr @fdc_oneOf(group: "eq")
-  eq_date: Date_Relative @fdc_oneOf(group: "eq")
-  ne: Date @fdc_oneOf(group: "ne")
-  ne_expr: Date_Expr @fdc_oneOf(group: "ne")
-  ne_date: Date_Relative @fdc_oneOf(group: "ne")
-  in: [Date!]
-  nin: [Date!]
-  gt: Date @fdc_oneOf(group: "gt")
-  gt_expr: Date_Expr @fdc_oneOf(group: "gt")
-  gt_date: Date_Relative @fdc_oneOf(group: "gt")
-  ge: Date @fdc_oneOf(group: "ge")
-  ge_expr: Date_Expr @fdc_oneOf(group: "ge")
-  ge_date: Date_Relative @fdc_oneOf(group: "ge")
-  lt: Date @fdc_oneOf(group: "lt")
-  lt_expr: Date_Expr @fdc_oneOf(group: "lt")
-  lt_date: Date_Relative @fdc_oneOf(group: "lt")
-  le: Date @fdc_oneOf(group: "le")
-  le_expr: Date_Expr @fdc_oneOf(group: "le")
-  le_date: Date_Relative @fdc_oneOf(group: "le")
-}
-
-"Conditions on a Date list"
-input Date_ListFilter {
-  includes: Date @fdc_oneOf(group: "includes")
-  includes_expr: Date_Expr @fdc_oneOf(group: "includes")
-  includes_date: Date_Relative @fdc_oneOf(group: "includes")
-  excludes: Date @fdc_oneOf(group: "excludes")
-  excludes_expr: Date_Expr @fdc_oneOf(group: "excludes")
-  excludes_date: Date_Relative @fdc_oneOf(group: "excludes")
-  includesAll: [Date!]
-  excludesAll: [Date!]
-}
-
-"Conditions on an Timestamp value"
-input Timestamp_Filter {
-  isNull: Boolean
-  eq: Timestamp @fdc_oneOf(group: "eq")
-  eq_expr: Timestamp_Expr @fdc_oneOf(group: "eq")
-  eq_time: Timestamp_Relative @fdc_oneOf(group: "eq")
-  ne: Timestamp @fdc_oneOf(group: "ne")
-  ne_expr: Timestamp_Expr @fdc_oneOf(group: "ne")
-  ne_time: Timestamp_Relative @fdc_oneOf(group: "ne")
-  in: [Timestamp!]
-  nin: [Timestamp!]
-  gt: Timestamp @fdc_oneOf(group: "gt")
-  gt_expr: Timestamp_Expr @fdc_oneOf(group: "gt")
-  gt_time: Timestamp_Relative @fdc_oneOf(group: "gt")
-  ge: Timestamp @fdc_oneOf(group: "ge")
-  ge_expr: Timestamp_Expr @fdc_oneOf(group: "ge")
-  ge_time: Timestamp_Relative @fdc_oneOf(group: "ge")
-  lt: Timestamp @fdc_oneOf(group: "lt")
-  lt_expr: Timestamp_Expr @fdc_oneOf(group: "lt")
-  lt_time: Timestamp_Relative @fdc_oneOf(group: "lt")
-  le: Timestamp @fdc_oneOf(group: "le")
-  le_expr: Timestamp_Expr @fdc_oneOf(group: "le")
-  le_time: Timestamp_Relative @fdc_oneOf(group: "le")
-}
-
-"Conditions on a Timestamp list"
-input Timestamp_ListFilter {
-  includes: Timestamp @fdc_oneOf(group: "includes")
-  includes_expr: Timestamp_Expr @fdc_oneOf(group: "includes")
-  includes_time: Timestamp_Relative @fdc_oneOf(group: "includes")
-  excludes: Timestamp @fdc_oneOf(group: "excludes")
-  excludes_expr: Timestamp_Expr @fdc_oneOf(group: "excludes")
-  excludes_time: Timestamp_Relative @fdc_oneOf(group: "excludes")
-  includesAll: [Timestamp!]
-  excludesAll: [Timestamp!]
-}
-
-"Update input of a Date value"
-input Date_Update {
-  set: Date @fdc_oneOf(group: "set")
-  set_expr: Date_Expr @fdc_oneOf(group: "set")
-  set_date: Date_Relative @fdc_oneOf(group: "set")
-}
-
-"Update input of a Date list value"
-input Date_ListUpdate {
-  set: [Date!]
-  append: [Date!]
-  prepend: [Date!]
-  delete: Int
-  i: Int
-  update: Date
-}
-
-"Update input of a Timestamp value"
-input Timestamp_Update {
-  set: Timestamp @fdc_oneOf(group: "set")
-  set_expr: Timestamp_Expr @fdc_oneOf(group: "set")
-  set_time: Timestamp_Relative @fdc_oneOf(group: "set")
-}
-
-"Update input of a Timestamp list value"
-input Timestamp_ListUpdate {
-  set: [Timestamp!]
-  append: [Timestamp!]
-  prepend: [Timestamp!]
-  delete: Int
-  i: Int
-  update: Timestamp
-}
-
-"A runtime-calculated Timestamp value relative to `now` or `at`."
-input Timestamp_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
-  now: True @fdc_oneOf(group: "from", required: true)
-  at: Timestamp @fdc_oneOf(group: "from", required: true)
-
-  add: Timestamp_Duration
-  sub: Timestamp_Duration
-
-  truncateTo: Timestamp_Interval
-}
-
-input Timestamp_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
-  milliseconds: Int! = 0
-  seconds: Int! = 0
-  minutes: Int! = 0
-  hours: Int! = 0
-  days: Int! = 0
-  weeks: Int! = 0
-  months: Int! = 0
-  years: Int! = 0
-}
-
-enum Timestamp_Interval @fdc_forbiddenAsFieldType {
-  SECOND
-  MINUTE
-  HOUR
-  DAY
-  WEEK
-  MONTH
-  YEAR
-}
-
-"A runtime-calculated Date value relative to `today` or `on`."
-input Date_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
-  today: True @fdc_oneOf(group: "from", required: true)
-  on: Date @fdc_oneOf(group: "from", required: true)
-
-  add: Date_Duration
-  sub: Date_Duration
-
-  truncateTo: Date_Interval
-}
-
-input Date_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
-  days: Int! = 0
-  weeks: Int! = 0
-  months: Int! = 0
-  years: Int! = 0
-}
-
-enum Date_Interval @fdc_forbiddenAsFieldType {
-  WEEK
-  MONTH
-  YEAR
-}
-"Update input of a String value"
-input String_Update {
-  set: String @fdc_oneOf(group: "set")
-  set_expr: String_Expr @fdc_oneOf(group: "set")
-}
-
-"Update input of a String list value"
-input String_ListUpdate {
-  set: [String!]
-  append: [String!]
-  prepend: [String!]
-}
-
-"Update input of a UUID value"
-input UUID_Update {
-  set: UUID @fdc_oneOf(group: "set")
-  set_expr: UUID_Expr @fdc_oneOf(group: "set")
-}
-
-"Update input of an ID list value"
-input UUID_ListUpdate {
-  set: [UUID!]
-  append: [UUID!]
-  prepend: [UUID!]
-}
-
-"Update input of an Int value"
-input Int_Update {
-  set: Int
-  inc: Int
-  dec: Int
-}
-
-"Update input of an Int list value"
-input Int_ListUpdate {
-  set: [Int!]
-  append: [Int!]
-  prepend: [Int!]
-}
-
-"Update input of an Int64 value"
-input Int64_Update {
-  set: Int64
-  inc: Int64
-  dec: Int64
-}
-
-"Update input of an Int64 list value"
-input Int64_ListUpdate {
-  set: [Int64!]
-  append: [Int64!]
-  prepend: [Int64!]
-}
-
-"Update input of a Float value"
-input Float_Update {
-  set: Float
-  inc: Float
-  dec: Float
-}
-
-"Update input of a Float list value"
-input Float_ListUpdate {
-  set: [Float!]
-  append: [Float!]
-  prepend: [Float!]
-}
-
-"Update input of a Boolean value"
-input Boolean_Update {
-  set: Boolean
-}
-
-"Update input of a Boolean list value"
-input Boolean_ListUpdate {
-  set: [Boolean!]
-  append: [Boolean!]
-  prepend: [Boolean!]
-}
-
-"Update input of an Any value"
-input Any_Update {
-  set: Any
-}
-
-"Update input of an Any list value"
-input Any_ListUpdate {
-  set: [Any!]
-  append: [Any!]
-  prepend: [Any!]
-}
-"""
-Vector is an array of single-precision floating-point numbers, serialized
-as a JSON array. All elements must be finite (no NaN, Infinity or -Infinity).
-
-Example: [1.1, 2, 3.3]
-"""
-scalar Vector
-
-"""
-Defines what siliarlity function to use for fetching vectors.
-Details here: https://github.com/pgvector/pgvector?tab=readme-ov-file#vector-functions
-"""
-enum VectorSimilarityMethod {
-  L2
-  COSINE
-  INNER_PRODUCT
-}
-
-"Conditions on an Vector value"
-input Vector_Filter {
-  eq: Vector
-  ne: Vector
-  in: [Vector!]
-  nin: [Vector!]
-  isNull: Boolean
-}
-
-input Vector_ListFilter {
-  "When true, will match if the list includes the supplied vector."
-  includes: Vector
-  excludes: Vector
-  includesAll: [Vector!]
-  excludesAll: [Vector!]
-}
-
-"Update input of an Vector value"
-input Vector_Update {
-  set: Vector @fdc_oneOf(group: "set")
-  set_embed: Vector_Embed @fdc_oneOf(group: "set")
-}
-
-"Update input of a Vector list value"
-input Vector_ListUpdate {
-  set: [Vector]
-  append: [Vector]
-  prepend: [Vector]
-  delete: Int
-  i: Int
-  update: Vector
-}
-
-"""
-Create a vector embedding of text using the given model on Vertex AI.
-
-Example: {text: "Hi there", model: "textembedding-gecko@003"}
-See: https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-text-embeddings
-
-Limitation: In the emulator, if Vertex AI is not configured, a pseudorandom
-vector is generated from text as a fake implementation for testing only.
-"""
-input Vector_Embed @fdc_forbiddenAsVariableType {
-  model: Vector_Embed_Model!
-  text: String!
-}
-
-"""
-A string that specifies a Vertex AI model and version.
-
-It is strongly recommended to specify a stable model version (for example,
-textembedding-gecko@003). The latest version of a model is in Preview and is not
-General Availability (GA). Because the latest version is in Preview, it isn't
-guaranteed to be production ready.
-"""
-scalar Vector_Embed_Model
-  @specifiedBy(url: "https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versioning")
-  @fdc_forbiddenAsVariableType
-  @fdc_forbiddenAsFieldType
-  @fdc_example(value: "textembedding-gecko@003", description: "A stable version of the textembedding-gecko model")
diff --git a/dataconnect/movie/lib/dataconnect-sdk/esm/index.esm.js b/dataconnect/movie/lib/dataconnect-sdk/esm/index.esm.js
deleted file mode 100644
index c25a275f7..000000000
--- a/dataconnect/movie/lib/dataconnect-sdk/esm/index.esm.js
+++ /dev/null
@@ -1,318 +0,0 @@
-import { getDataConnect, queryRef, executeQuery, mutationRef, executeMutation } from 'firebase/data-connect';
-
-export const connectorConfig = {
-  connector: 'movie-connector',
-  service: 'dataconnect',
-  location: 'us-central1'
-};
-
-export function createMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'createMovie', inputVars);
-}
-export function createMovie(dcOrVars, vars) {
-  return executeMutation(createMovieRef(dcOrVars, vars));
-}
-export function updateMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'updateMovie', inputVars);
-}
-export function updateMovie(dcOrVars, vars) {
-  return executeMutation(updateMovieRef(dcOrVars, vars));
-}
-export function deleteMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteMovie', inputVars);
-}
-export function deleteMovie(dcOrVars, vars) {
-  return executeMutation(deleteMovieRef(dcOrVars, vars));
-}
-export function deleteUnpopularMoviesRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteUnpopularMovies', inputVars);
-}
-export function deleteUnpopularMovies(dcOrVars, vars) {
-  return executeMutation(deleteUnpopularMoviesRef(dcOrVars, vars));
-}
-export function addWatchedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'addWatchedMovie', inputVars);
-}
-export function addWatchedMovie(dcOrVars, vars) {
-  return executeMutation(addWatchedMovieRef(dcOrVars, vars));
-}
-export function deleteWatchedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteWatchedMovie', inputVars);
-}
-export function deleteWatchedMovie(dcOrVars, vars) {
-  return executeMutation(deleteWatchedMovieRef(dcOrVars, vars));
-}
-export function addFavoritedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'addFavoritedMovie', inputVars);
-}
-export function addFavoritedMovie(dcOrVars, vars) {
-  return executeMutation(addFavoritedMovieRef(dcOrVars, vars));
-}
-export function deleteFavoritedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteFavoritedMovie', inputVars);
-}
-export function deleteFavoritedMovie(dcOrVars, vars) {
-  return executeMutation(deleteFavoritedMovieRef(dcOrVars, vars));
-}
-export function addFavoritedActorRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'addFavoritedActor', inputVars);
-}
-export function addFavoritedActor(dcOrVars, vars) {
-  return executeMutation(addFavoritedActorRef(dcOrVars, vars));
-}
-export function deleteFavoriteActorRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteFavoriteActor', inputVars);
-}
-export function deleteFavoriteActor(dcOrVars, vars) {
-  return executeMutation(deleteFavoriteActorRef(dcOrVars, vars));
-}
-export function addReviewRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'addReview', inputVars);
-}
-export function addReview(dcOrVars, vars) {
-  return executeMutation(addReviewRef(dcOrVars, vars));
-}
-export function deleteReviewRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteReview', inputVars);
-}
-export function deleteReview(dcOrVars, vars) {
-  return executeMutation(deleteReviewRef(dcOrVars, vars));
-}
-export function upsertUserRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'upsertUser', inputVars);
-}
-export function upsertUser(dcOrVars, vars) {
-  return executeMutation(upsertUserRef(dcOrVars, vars));
-}
-export function listMoviesRef(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'ListMovies');
-}
-export function listMovies(dc) {
-  return executeQuery(listMoviesRef(dc));
-}
-export function listUsersRef(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'ListUsers');
-}
-export function listUsers(dc) {
-  return executeQuery(listUsersRef(dc));
-}
-export function listMoviesByGenreRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'ListMoviesByGenre', inputVars);
-}
-export function listMoviesByGenre(dcOrVars, vars) {
-  return executeQuery(listMoviesByGenreRef(dcOrVars, vars));
-}
-export function listMoviesByReleaseYearRef(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'ListMoviesByReleaseYear');
-}
-export function listMoviesByReleaseYear(dc) {
-  return executeQuery(listMoviesByReleaseYearRef(dc));
-}
-export function getMovieByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetMovieById', inputVars);
-}
-export function getMovieById(dcOrVars, vars) {
-  return executeQuery(getMovieByIdRef(dcOrVars, vars));
-}
-export function getActorByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetActorById', inputVars);
-}
-export function getActorById(dcOrVars, vars) {
-  return executeQuery(getActorByIdRef(dcOrVars, vars));
-}
-export function userMoviePreferencesRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'UserMoviePreferences', inputVars);
-}
-export function userMoviePreferences(dcOrVars, vars) {
-  return executeQuery(userMoviePreferencesRef(dcOrVars, vars));
-}
-export function getMovieMetadataRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetMovieMetadata', inputVars);
-}
-export function getMovieMetadata(dcOrVars, vars) {
-  return executeQuery(getMovieMetadataRef(dcOrVars, vars));
-}
-export function getMovieCastRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetMovieCast', inputVars);
-}
-export function getMovieCast(dcOrVars, vars) {
-  return executeQuery(getMovieCastRef(dcOrVars, vars));
-}
-export function listMoviesByPartialTitleRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'ListMoviesByPartialTitle', inputVars);
-}
-export function listMoviesByPartialTitle(dcOrVars, vars) {
-  return executeQuery(listMoviesByPartialTitleRef(dcOrVars, vars));
-}
-export function movieByKeyRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'MovieByKey', inputVars);
-}
-export function movieByKey(dcOrVars, vars) {
-  return executeQuery(movieByKeyRef(dcOrVars, vars));
-}
-export function movieByTitleRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'MovieByTitle', inputVars);
-}
-export function movieByTitle(dcOrVars, vars) {
-  return executeQuery(movieByTitleRef(dcOrVars, vars));
-}
-export function movieByTopRatingRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
-  return queryRef(dcInstance, 'MovieByTopRating', inputVars);
-}
-export function movieByTopRating(dcOrVars, vars) {
-  return executeQuery(movieByTopRatingRef(dcOrVars, vars));
-}
-export function listMoviesByTagRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'ListMoviesByTag', inputVars);
-}
-export function listMoviesByTag(dcOrVars, vars) {
-  return executeQuery(listMoviesByTagRef(dcOrVars, vars));
-}
-export function moviesTop10Ref(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'MoviesTop10');
-}
-export function moviesTop10(dc) {
-  return executeQuery(moviesTop10Ref(dc));
-}
-export function moviesByReleaseYearRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
-  return queryRef(dcInstance, 'MoviesByReleaseYear', inputVars);
-}
-export function moviesByReleaseYear(dcOrVars, vars) {
-  return executeQuery(moviesByReleaseYearRef(dcOrVars, vars));
-}
-export function moviesRecentlyReleasedRef(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'MoviesRecentlyReleased');
-}
-export function moviesRecentlyReleased(dc) {
-  return executeQuery(moviesRecentlyReleasedRef(dc));
-}
-export function listMoviesFilterRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
-  return queryRef(dcInstance, 'ListMoviesFilter', inputVars);
-}
-export function listMoviesFilter(dcOrVars, vars) {
-  return executeQuery(listMoviesFilterRef(dcOrVars, vars));
-}
-export function listMoviesByTitleStringRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
-  return queryRef(dcInstance, 'ListMoviesByTitleString', inputVars);
-}
-export function listMoviesByTitleString(dcOrVars, vars) {
-  return executeQuery(listMoviesByTitleStringRef(dcOrVars, vars));
-}
-export function listMoviesByRatingAndGenreRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'ListMoviesByRatingAndGenre', inputVars);
-}
-export function listMoviesByRatingAndGenre(dcOrVars, vars) {
-  return executeQuery(listMoviesByRatingAndGenreRef(dcOrVars, vars));
-}
-export function getFavoriteMoviesByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetFavoriteMoviesById', inputVars);
-}
-export function getFavoriteMoviesById(dcOrVars, vars) {
-  return executeQuery(getFavoriteMoviesByIdRef(dcOrVars, vars));
-}
-export function getFavoriteActorsByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetFavoriteActorsById', inputVars);
-}
-export function getFavoriteActorsById(dcOrVars, vars) {
-  return executeQuery(getFavoriteActorsByIdRef(dcOrVars, vars));
-}
-export function getWatchedMoviesByAuthIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetWatchedMoviesByAuthId', inputVars);
-}
-export function getWatchedMoviesByAuthId(dcOrVars, vars) {
-  return executeQuery(getWatchedMoviesByAuthIdRef(dcOrVars, vars));
-}
-export function getUserByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetUserById', inputVars);
-}
-export function getUserById(dcOrVars, vars) {
-  return executeQuery(getUserByIdRef(dcOrVars, vars));
-}
-export function getIfWatchedRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetIfWatched', inputVars);
-}
-export function getIfWatched(dcOrVars, vars) {
-  return executeQuery(getIfWatchedRef(dcOrVars, vars));
-}
-export function getIfFavoritedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetIfFavoritedMovie', inputVars);
-}
-export function getIfFavoritedMovie(dcOrVars, vars) {
-  return executeQuery(getIfFavoritedMovieRef(dcOrVars, vars));
-}
-export function getIfFavoritedActorRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetIfFavoritedActor', inputVars);
-}
-export function getIfFavoritedActor(dcOrVars, vars) {
-  return executeQuery(getIfFavoritedActorRef(dcOrVars, vars));
-}
-export function fuzzySearchRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'fuzzySearch', inputVars);
-}
-export function fuzzySearch(dcOrVars, vars) {
-  return executeQuery(fuzzySearchRef(dcOrVars, vars));
-}
-export function searchMovieDescriptionUsingL2similarityRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'searchMovieDescriptionUsingL2Similarity', inputVars);
-}
-export function searchMovieDescriptionUsingL2similarity(dcOrVars, vars) {
-  return executeQuery(searchMovieDescriptionUsingL2similarityRef(dcOrVars, vars));
-}
-function validateArgs(dcOrVars, vars, validateVars) {
-  let dcInstance;
-  let realVars;
-  // TODO; Check what happens if this is undefined.
-  if(dcOrVars && 'dataConnectOptions' in dcOrVars) {
-      dcInstance = dcOrVars;
-      realVars = vars;
-  } else {
-      dcInstance = getDataConnect(connectorConfig);
-      realVars = dcOrVars;
-  }
-  if(!dcInstance || (!realVars && validateVars)) {
-      throw new Error('You didn\t pass in the vars!');
-  }
-  return { dc: dcInstance, vars: realVars };
-}
\ No newline at end of file
diff --git a/dataconnect/movie/lib/dataconnect-sdk/esm/package.json b/dataconnect/movie/lib/dataconnect-sdk/esm/package.json
deleted file mode 100644
index 7c34deb58..000000000
--- a/dataconnect/movie/lib/dataconnect-sdk/esm/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{"type":"module"}
\ No newline at end of file
diff --git a/dataconnect/movie/lib/dataconnect-sdk/index.cjs.js b/dataconnect/movie/lib/dataconnect-sdk/index.cjs.js
deleted file mode 100644
index 6e6fb47cd..000000000
--- a/dataconnect/movie/lib/dataconnect-sdk/index.cjs.js
+++ /dev/null
@@ -1,403 +0,0 @@
-const { getDataConnect, queryRef, executeQuery, mutationRef, executeMutation } = require('firebase/data-connect');
-
-const connectorConfig = {
-  connector: 'movie-connector',
-  service: 'dataconnect',
-  location: 'us-central1'
-};
-exports.connectorConfig = connectorConfig;
-
-function createMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'createMovie', inputVars);
-}
-exports.createMovieRef = createMovieRef;
-exports.createMovie = function createMovie(dcOrVars, vars) {
-  return executeMutation(createMovieRef(dcOrVars, vars));
-};
-
-function updateMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'updateMovie', inputVars);
-}
-exports.updateMovieRef = updateMovieRef;
-exports.updateMovie = function updateMovie(dcOrVars, vars) {
-  return executeMutation(updateMovieRef(dcOrVars, vars));
-};
-
-function deleteMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteMovie', inputVars);
-}
-exports.deleteMovieRef = deleteMovieRef;
-exports.deleteMovie = function deleteMovie(dcOrVars, vars) {
-  return executeMutation(deleteMovieRef(dcOrVars, vars));
-};
-
-function deleteUnpopularMoviesRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteUnpopularMovies', inputVars);
-}
-exports.deleteUnpopularMoviesRef = deleteUnpopularMoviesRef;
-exports.deleteUnpopularMovies = function deleteUnpopularMovies(dcOrVars, vars) {
-  return executeMutation(deleteUnpopularMoviesRef(dcOrVars, vars));
-};
-
-function addWatchedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'addWatchedMovie', inputVars);
-}
-exports.addWatchedMovieRef = addWatchedMovieRef;
-exports.addWatchedMovie = function addWatchedMovie(dcOrVars, vars) {
-  return executeMutation(addWatchedMovieRef(dcOrVars, vars));
-};
-
-function deleteWatchedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteWatchedMovie', inputVars);
-}
-exports.deleteWatchedMovieRef = deleteWatchedMovieRef;
-exports.deleteWatchedMovie = function deleteWatchedMovie(dcOrVars, vars) {
-  return executeMutation(deleteWatchedMovieRef(dcOrVars, vars));
-};
-
-function addFavoritedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'addFavoritedMovie', inputVars);
-}
-exports.addFavoritedMovieRef = addFavoritedMovieRef;
-exports.addFavoritedMovie = function addFavoritedMovie(dcOrVars, vars) {
-  return executeMutation(addFavoritedMovieRef(dcOrVars, vars));
-};
-
-function deleteFavoritedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteFavoritedMovie', inputVars);
-}
-exports.deleteFavoritedMovieRef = deleteFavoritedMovieRef;
-exports.deleteFavoritedMovie = function deleteFavoritedMovie(dcOrVars, vars) {
-  return executeMutation(deleteFavoritedMovieRef(dcOrVars, vars));
-};
-
-function addFavoritedActorRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'addFavoritedActor', inputVars);
-}
-exports.addFavoritedActorRef = addFavoritedActorRef;
-exports.addFavoritedActor = function addFavoritedActor(dcOrVars, vars) {
-  return executeMutation(addFavoritedActorRef(dcOrVars, vars));
-};
-
-function deleteFavoriteActorRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteFavoriteActor', inputVars);
-}
-exports.deleteFavoriteActorRef = deleteFavoriteActorRef;
-exports.deleteFavoriteActor = function deleteFavoriteActor(dcOrVars, vars) {
-  return executeMutation(deleteFavoriteActorRef(dcOrVars, vars));
-};
-
-function addReviewRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'addReview', inputVars);
-}
-exports.addReviewRef = addReviewRef;
-exports.addReview = function addReview(dcOrVars, vars) {
-  return executeMutation(addReviewRef(dcOrVars, vars));
-};
-
-function deleteReviewRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'deleteReview', inputVars);
-}
-exports.deleteReviewRef = deleteReviewRef;
-exports.deleteReview = function deleteReview(dcOrVars, vars) {
-  return executeMutation(deleteReviewRef(dcOrVars, vars));
-};
-
-function upsertUserRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return mutationRef(dcInstance, 'upsertUser', inputVars);
-}
-exports.upsertUserRef = upsertUserRef;
-exports.upsertUser = function upsertUser(dcOrVars, vars) {
-  return executeMutation(upsertUserRef(dcOrVars, vars));
-};
-
-function listMoviesRef(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'ListMovies');
-}
-exports.listMoviesRef = listMoviesRef;
-exports.listMovies = function listMovies(dc) {
-  return executeQuery(listMoviesRef(dc));
-};
-
-function listUsersRef(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'ListUsers');
-}
-exports.listUsersRef = listUsersRef;
-exports.listUsers = function listUsers(dc) {
-  return executeQuery(listUsersRef(dc));
-};
-
-function listMoviesByGenreRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'ListMoviesByGenre', inputVars);
-}
-exports.listMoviesByGenreRef = listMoviesByGenreRef;
-exports.listMoviesByGenre = function listMoviesByGenre(dcOrVars, vars) {
-  return executeQuery(listMoviesByGenreRef(dcOrVars, vars));
-};
-
-function listMoviesByReleaseYearRef(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'ListMoviesByReleaseYear');
-}
-exports.listMoviesByReleaseYearRef = listMoviesByReleaseYearRef;
-exports.listMoviesByReleaseYear = function listMoviesByReleaseYear(dc) {
-  return executeQuery(listMoviesByReleaseYearRef(dc));
-};
-
-function getMovieByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetMovieById', inputVars);
-}
-exports.getMovieByIdRef = getMovieByIdRef;
-exports.getMovieById = function getMovieById(dcOrVars, vars) {
-  return executeQuery(getMovieByIdRef(dcOrVars, vars));
-};
-
-function getActorByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetActorById', inputVars);
-}
-exports.getActorByIdRef = getActorByIdRef;
-exports.getActorById = function getActorById(dcOrVars, vars) {
-  return executeQuery(getActorByIdRef(dcOrVars, vars));
-};
-
-function userMoviePreferencesRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'UserMoviePreferences', inputVars);
-}
-exports.userMoviePreferencesRef = userMoviePreferencesRef;
-exports.userMoviePreferences = function userMoviePreferences(dcOrVars, vars) {
-  return executeQuery(userMoviePreferencesRef(dcOrVars, vars));
-};
-
-function getMovieMetadataRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetMovieMetadata', inputVars);
-}
-exports.getMovieMetadataRef = getMovieMetadataRef;
-exports.getMovieMetadata = function getMovieMetadata(dcOrVars, vars) {
-  return executeQuery(getMovieMetadataRef(dcOrVars, vars));
-};
-
-function getMovieCastRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetMovieCast', inputVars);
-}
-exports.getMovieCastRef = getMovieCastRef;
-exports.getMovieCast = function getMovieCast(dcOrVars, vars) {
-  return executeQuery(getMovieCastRef(dcOrVars, vars));
-};
-
-function listMoviesByPartialTitleRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'ListMoviesByPartialTitle', inputVars);
-}
-exports.listMoviesByPartialTitleRef = listMoviesByPartialTitleRef;
-exports.listMoviesByPartialTitle = function listMoviesByPartialTitle(dcOrVars, vars) {
-  return executeQuery(listMoviesByPartialTitleRef(dcOrVars, vars));
-};
-
-function movieByKeyRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'MovieByKey', inputVars);
-}
-exports.movieByKeyRef = movieByKeyRef;
-exports.movieByKey = function movieByKey(dcOrVars, vars) {
-  return executeQuery(movieByKeyRef(dcOrVars, vars));
-};
-
-function movieByTitleRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'MovieByTitle', inputVars);
-}
-exports.movieByTitleRef = movieByTitleRef;
-exports.movieByTitle = function movieByTitle(dcOrVars, vars) {
-  return executeQuery(movieByTitleRef(dcOrVars, vars));
-};
-
-function movieByTopRatingRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
-  return queryRef(dcInstance, 'MovieByTopRating', inputVars);
-}
-exports.movieByTopRatingRef = movieByTopRatingRef;
-exports.movieByTopRating = function movieByTopRating(dcOrVars, vars) {
-  return executeQuery(movieByTopRatingRef(dcOrVars, vars));
-};
-
-function listMoviesByTagRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'ListMoviesByTag', inputVars);
-}
-exports.listMoviesByTagRef = listMoviesByTagRef;
-exports.listMoviesByTag = function listMoviesByTag(dcOrVars, vars) {
-  return executeQuery(listMoviesByTagRef(dcOrVars, vars));
-};
-
-function moviesTop10Ref(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'MoviesTop10');
-}
-exports.moviesTop10Ref = moviesTop10Ref;
-exports.moviesTop10 = function moviesTop10(dc) {
-  return executeQuery(moviesTop10Ref(dc));
-};
-
-function moviesByReleaseYearRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
-  return queryRef(dcInstance, 'MoviesByReleaseYear', inputVars);
-}
-exports.moviesByReleaseYearRef = moviesByReleaseYearRef;
-exports.moviesByReleaseYear = function moviesByReleaseYear(dcOrVars, vars) {
-  return executeQuery(moviesByReleaseYearRef(dcOrVars, vars));
-};
-
-function moviesRecentlyReleasedRef(dc) {
-  const { dc: dcInstance} = validateArgs(dc, undefined);
-  return queryRef(dcInstance, 'MoviesRecentlyReleased');
-}
-exports.moviesRecentlyReleasedRef = moviesRecentlyReleasedRef;
-exports.moviesRecentlyReleased = function moviesRecentlyReleased(dc) {
-  return executeQuery(moviesRecentlyReleasedRef(dc));
-};
-
-function listMoviesFilterRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
-  return queryRef(dcInstance, 'ListMoviesFilter', inputVars);
-}
-exports.listMoviesFilterRef = listMoviesFilterRef;
-exports.listMoviesFilter = function listMoviesFilter(dcOrVars, vars) {
-  return executeQuery(listMoviesFilterRef(dcOrVars, vars));
-};
-
-function listMoviesByTitleStringRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars);
-  return queryRef(dcInstance, 'ListMoviesByTitleString', inputVars);
-}
-exports.listMoviesByTitleStringRef = listMoviesByTitleStringRef;
-exports.listMoviesByTitleString = function listMoviesByTitleString(dcOrVars, vars) {
-  return executeQuery(listMoviesByTitleStringRef(dcOrVars, vars));
-};
-
-function listMoviesByRatingAndGenreRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'ListMoviesByRatingAndGenre', inputVars);
-}
-exports.listMoviesByRatingAndGenreRef = listMoviesByRatingAndGenreRef;
-exports.listMoviesByRatingAndGenre = function listMoviesByRatingAndGenre(dcOrVars, vars) {
-  return executeQuery(listMoviesByRatingAndGenreRef(dcOrVars, vars));
-};
-
-function getFavoriteMoviesByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetFavoriteMoviesById', inputVars);
-}
-exports.getFavoriteMoviesByIdRef = getFavoriteMoviesByIdRef;
-exports.getFavoriteMoviesById = function getFavoriteMoviesById(dcOrVars, vars) {
-  return executeQuery(getFavoriteMoviesByIdRef(dcOrVars, vars));
-};
-
-function getFavoriteActorsByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetFavoriteActorsById', inputVars);
-}
-exports.getFavoriteActorsByIdRef = getFavoriteActorsByIdRef;
-exports.getFavoriteActorsById = function getFavoriteActorsById(dcOrVars, vars) {
-  return executeQuery(getFavoriteActorsByIdRef(dcOrVars, vars));
-};
-
-function getWatchedMoviesByAuthIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetWatchedMoviesByAuthId', inputVars);
-}
-exports.getWatchedMoviesByAuthIdRef = getWatchedMoviesByAuthIdRef;
-exports.getWatchedMoviesByAuthId = function getWatchedMoviesByAuthId(dcOrVars, vars) {
-  return executeQuery(getWatchedMoviesByAuthIdRef(dcOrVars, vars));
-};
-
-function getUserByIdRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetUserById', inputVars);
-}
-exports.getUserByIdRef = getUserByIdRef;
-exports.getUserById = function getUserById(dcOrVars, vars) {
-  return executeQuery(getUserByIdRef(dcOrVars, vars));
-};
-
-function getIfWatchedRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetIfWatched', inputVars);
-}
-exports.getIfWatchedRef = getIfWatchedRef;
-exports.getIfWatched = function getIfWatched(dcOrVars, vars) {
-  return executeQuery(getIfWatchedRef(dcOrVars, vars));
-};
-
-function getIfFavoritedMovieRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetIfFavoritedMovie', inputVars);
-}
-exports.getIfFavoritedMovieRef = getIfFavoritedMovieRef;
-exports.getIfFavoritedMovie = function getIfFavoritedMovie(dcOrVars, vars) {
-  return executeQuery(getIfFavoritedMovieRef(dcOrVars, vars));
-};
-
-function getIfFavoritedActorRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'GetIfFavoritedActor', inputVars);
-}
-exports.getIfFavoritedActorRef = getIfFavoritedActorRef;
-exports.getIfFavoritedActor = function getIfFavoritedActor(dcOrVars, vars) {
-  return executeQuery(getIfFavoritedActorRef(dcOrVars, vars));
-};
-
-function fuzzySearchRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'fuzzySearch', inputVars);
-}
-exports.fuzzySearchRef = fuzzySearchRef;
-exports.fuzzySearch = function fuzzySearch(dcOrVars, vars) {
-  return executeQuery(fuzzySearchRef(dcOrVars, vars));
-};
-
-function searchMovieDescriptionUsingL2similarityRef(dcOrVars, vars) {
-  const { dc: dcInstance, vars: inputVars} = validateArgs(dcOrVars, vars, true);
-  return queryRef(dcInstance, 'searchMovieDescriptionUsingL2Similarity', inputVars);
-}
-exports.searchMovieDescriptionUsingL2similarityRef = searchMovieDescriptionUsingL2similarityRef;
-exports.searchMovieDescriptionUsingL2similarity = function searchMovieDescriptionUsingL2similarity(dcOrVars, vars) {
-  return executeQuery(searchMovieDescriptionUsingL2similarityRef(dcOrVars, vars));
-};
-
-function validateArgs(dcOrVars, vars, validateVars) {
-  let dcInstance;
-  let realVars;
-  // TODO; Check what happens if this is undefined.
-  if(dcOrVars && 'dataConnectOptions' in dcOrVars) {
-      dcInstance = dcOrVars;
-      realVars = vars;
-  } else {
-      dcInstance = getDataConnect(connectorConfig);
-      realVars = dcOrVars;
-  }
-  if(!dcInstance || (!realVars && validateVars)) {
-      throw new Error('You didn\t pass in the vars!');
-  }
-  return { dc: dcInstance, vars: realVars };
-}
\ No newline at end of file
diff --git a/dataconnect/movie/lib/dataconnect-sdk/index.d.ts b/dataconnect/movie/lib/dataconnect-sdk/index.d.ts
deleted file mode 100644
index 519c7186c..000000000
--- a/dataconnect/movie/lib/dataconnect-sdk/index.d.ts
+++ /dev/null
@@ -1,1144 +0,0 @@
-import { ConnectorConfig, DataConnect, QueryRef, QueryPromise, MutationRef, MutationPromise } from 'firebase/data-connect';
-export const connectorConfig: ConnectorConfig;
-
-export type TimestampString = string;
-
-export type UUIDString = string;
-
-export type Int64String = string;
-
-export type DateString = string;
-
-
-export interface Actor_Key {
-  id: UUIDString;
-  __typename?: 'Actor_Key';
-}
-
-export interface AddFavoritedActorResponse {
-  favoriteActor_upsert: FavoriteActor_Key;
-}
-
-export interface AddFavoritedActorVariables {
-  actorId: UUIDString;
-}
-
-export interface AddFavoritedMovieResponse {
-  favoriteMovie_upsert: FavoriteMovie_Key;
-}
-
-export interface AddFavoritedMovieVariables {
-  movieId: UUIDString;
-}
-
-export interface AddReviewResponse {
-  review_upsert: Review_Key;
-}
-
-export interface AddReviewVariables {
-  movieId: UUIDString;
-  rating: number;
-  reviewText: string;
-}
-
-export interface AddWatchedMovieResponse {
-  watchedMovie_upsert: WatchedMovie_Key;
-}
-
-export interface AddWatchedMovieVariables {
-  movieId: UUIDString;
-}
-
-export interface CreateMovieResponse {
-  movie_insert: Movie_Key;
-}
-
-export interface CreateMovieVariables {
-  title: string;
-  releaseYear: number;
-  genre: string;
-  rating?: number | null;
-  description?: string | null;
-  imageUrl: string;
-  tags?: string[] | null;
-}
-
-export interface DeleteFavoriteActorResponse {
-  favoriteActor_delete?: FavoriteActor_Key | null;
-}
-
-export interface DeleteFavoriteActorVariables {
-  userId: string;
-  actorId: UUIDString;
-}
-
-export interface DeleteFavoritedMovieResponse {
-  favoriteMovie_delete?: FavoriteMovie_Key | null;
-}
-
-export interface DeleteFavoritedMovieVariables {
-  userId: string;
-  movieId: UUIDString;
-}
-
-export interface DeleteMovieResponse {
-  movie_delete?: Movie_Key | null;
-}
-
-export interface DeleteMovieVariables {
-  id: UUIDString;
-}
-
-export interface DeleteReviewResponse {
-  review_delete?: Review_Key | null;
-}
-
-export interface DeleteReviewVariables {
-  movieId: UUIDString;
-  userId: string;
-}
-
-export interface DeleteUnpopularMoviesResponse {
-  movie_deleteMany: number;
-}
-
-export interface DeleteUnpopularMoviesVariables {
-  minRating: number;
-}
-
-export interface DeleteWatchedMovieResponse {
-  watchedMovie_delete?: WatchedMovie_Key | null;
-}
-
-export interface DeleteWatchedMovieVariables {
-  userId: string;
-  movieId: UUIDString;
-}
-
-export interface FavoriteActor_Key {
-  userId: string;
-  actorId: UUIDString;
-  __typename?: 'FavoriteActor_Key';
-}
-
-export interface FavoriteMovie_Key {
-  userId: string;
-  movieId: UUIDString;
-  __typename?: 'FavoriteMovie_Key';
-}
-
-export interface FuzzySearchResponse {
-  moviesMatchingTitle: ({
-    id: UUIDString;
-    title: string;
-    genre?: string | null;
-    rating?: number | null;
-    imageUrl: string;
-  } & Movie_Key)[];
-    moviesMatchingDescription: ({
-      id: UUIDString;
-      title: string;
-      genre?: string | null;
-      rating?: number | null;
-      imageUrl: string;
-    } & Movie_Key)[];
-      actorsMatchingName: ({
-        id: UUIDString;
-        name: string;
-        imageUrl: string;
-      } & Actor_Key)[];
-        reviewsMatchingText: ({
-          id: UUIDString;
-          rating?: number | null;
-          reviewText?: string | null;
-          reviewDate: DateString;
-          movie: {
-            id: UUIDString;
-            title: string;
-          } & Movie_Key;
-            user: {
-              id: string;
-              username: string;
-            } & User_Key;
-        })[];
-}
-
-export interface FuzzySearchVariables {
-  input?: string | null;
-  minYear: number;
-  maxYear: number;
-  minRating: number;
-  maxRating: number;
-  genre: string;
-}
-
-export interface GetActorByIdResponse {
-  actor?: {
-    id: UUIDString;
-    name: string;
-    imageUrl: string;
-    biography?: string | null;
-    mainActors: ({
-      id: UUIDString;
-      title: string;
-      genre?: string | null;
-      tags?: string[] | null;
-      imageUrl: string;
-    } & Movie_Key)[];
-      supportingActors: ({
-        id: UUIDString;
-        title: string;
-        genre?: string | null;
-        tags?: string[] | null;
-        imageUrl: string;
-      } & Movie_Key)[];
-  } & Actor_Key;
-}
-
-export interface GetActorByIdVariables {
-  id: UUIDString;
-}
-
-export interface GetFavoriteActorsByIdResponse {
-  user?: {
-    favoriteActors_on_user: ({
-      actor: {
-        id: UUIDString;
-        name: string;
-        imageUrl: string;
-      } & Actor_Key;
-    })[];
-  };
-}
-
-export interface GetFavoriteActorsByIdVariables {
-  id: string;
-}
-
-export interface GetFavoriteMoviesByIdResponse {
-  user?: {
-    favoriteMovies_on_user: ({
-      movie: {
-        id: UUIDString;
-        title: string;
-        genre?: string | null;
-        imageUrl: string;
-        releaseYear?: number | null;
-        rating?: number | null;
-        description?: string | null;
-      } & Movie_Key;
-    })[];
-  };
-}
-
-export interface GetFavoriteMoviesByIdVariables {
-  id: string;
-}
-
-export interface GetIfFavoritedActorResponse {
-  favoriteActor?: {
-    actorId: UUIDString;
-  };
-}
-
-export interface GetIfFavoritedActorVariables {
-  id: string;
-  actorId: UUIDString;
-}
-
-export interface GetIfFavoritedMovieResponse {
-  favoriteMovie?: {
-    movieId: UUIDString;
-  };
-}
-
-export interface GetIfFavoritedMovieVariables {
-  id: string;
-  movieId: UUIDString;
-}
-
-export interface GetIfWatchedResponse {
-  watchedMovie?: {
-    movieId: UUIDString;
-  };
-}
-
-export interface GetIfWatchedVariables {
-  id: string;
-  movieId: UUIDString;
-}
-
-export interface GetMovieByIdResponse {
-  movie?: {
-    id: UUIDString;
-    title: string;
-    imageUrl: string;
-    releaseYear?: number | null;
-    genre?: string | null;
-    rating?: number | null;
-    description?: string | null;
-    tags?: string[] | null;
-    metadata: ({
-      director?: string | null;
-    })[];
-      mainActors: ({
-        id: UUIDString;
-        name: string;
-        imageUrl: string;
-      } & Actor_Key)[];
-        supportingActors: ({
-          id: UUIDString;
-          name: string;
-          imageUrl: string;
-        } & Actor_Key)[];
-          sequelTo?: {
-            id: UUIDString;
-            title: string;
-            imageUrl: string;
-          } & Movie_Key;
-            reviews: ({
-              id: UUIDString;
-              reviewText?: string | null;
-              reviewDate: DateString;
-              rating?: number | null;
-              user: {
-                id: string;
-                username: string;
-              } & User_Key;
-            })[];
-  } & Movie_Key;
-}
-
-export interface GetMovieByIdVariables {
-  id: UUIDString;
-}
-
-export interface GetMovieCastResponse {
-  movie?: {
-    mainActors: ({
-      id: UUIDString;
-      name: string;
-      imageUrl: string;
-    } & Actor_Key)[];
-      supportingActors: ({
-        id: UUIDString;
-        name: string;
-        imageUrl: string;
-      } & Actor_Key)[];
-  };
-    actor?: {
-      mainRoles: ({
-        id: UUIDString;
-        title: string;
-        imageUrl: string;
-      } & Movie_Key)[];
-        supportingRoles: ({
-          id: UUIDString;
-          title: string;
-          imageUrl: string;
-        } & Movie_Key)[];
-    };
-}
-
-export interface GetMovieCastVariables {
-  movieId: UUIDString;
-  actorId: UUIDString;
-}
-
-export interface GetMovieMetadataResponse {
-  movie?: {
-    movieMetadatas_on_movie: ({
-      director?: string | null;
-    })[];
-  };
-}
-
-export interface GetMovieMetadataVariables {
-  id: UUIDString;
-}
-
-export interface GetUserByIdResponse {
-  user?: {
-    id: string;
-    username: string;
-    reviews: ({
-      id: UUIDString;
-      rating?: number | null;
-      reviewDate: DateString;
-      reviewText?: string | null;
-      movie: {
-        id: UUIDString;
-        title: string;
-      } & Movie_Key;
-    })[];
-      watched: ({
-        movie: {
-          id: UUIDString;
-          title: string;
-          genre?: string | null;
-          imageUrl: string;
-          releaseYear?: number | null;
-          rating?: number | null;
-          description?: string | null;
-          tags?: string[] | null;
-          metadata: ({
-            director?: string | null;
-          })[];
-        } & Movie_Key;
-      })[];
-        favoriteMovies: ({
-          movie: {
-            id: UUIDString;
-            title: string;
-            genre?: string | null;
-            imageUrl: string;
-            releaseYear?: number | null;
-            rating?: number | null;
-            description?: string | null;
-            tags?: string[] | null;
-            metadata: ({
-              director?: string | null;
-            })[];
-          } & Movie_Key;
-        })[];
-          favoriteActors: ({
-            actor: {
-              id: UUIDString;
-              name: string;
-              imageUrl: string;
-            } & Actor_Key;
-          })[];
-  } & User_Key;
-}
-
-export interface GetUserByIdVariables {
-  id: string;
-}
-
-export interface GetWatchedMoviesByAuthIdResponse {
-  user?: {
-    watchedMovies_on_user: ({
-      movie: {
-        id: UUIDString;
-        title: string;
-        genre?: string | null;
-        imageUrl: string;
-        releaseYear?: number | null;
-        rating?: number | null;
-        description?: string | null;
-      } & Movie_Key;
-    })[];
-  };
-}
-
-export interface GetWatchedMoviesByAuthIdVariables {
-  id: string;
-}
-
-export interface ListMoviesByGenreResponse {
-  mostPopular: ({
-    id: UUIDString;
-    title: string;
-    imageUrl: string;
-    rating?: number | null;
-    tags?: string[] | null;
-  } & Movie_Key)[];
-    mostRecent: ({
-      id: UUIDString;
-      title: string;
-      imageUrl: string;
-      rating?: number | null;
-      tags?: string[] | null;
-    } & Movie_Key)[];
-}
-
-export interface ListMoviesByGenreVariables {
-  genre: string;
-}
-
-export interface ListMoviesByPartialTitleResponse {
-  movies: ({
-    id: UUIDString;
-    title: string;
-    genre?: string | null;
-    rating?: number | null;
-    imageUrl: string;
-  } & Movie_Key)[];
-}
-
-export interface ListMoviesByPartialTitleVariables {
-  input: string;
-}
-
-export interface ListMoviesByRatingAndGenreResponse {
-  movies: ({
-    title: string;
-    imageUrl: string;
-  })[];
-}
-
-export interface ListMoviesByRatingAndGenreVariables {
-  minRating: number;
-  genre?: string | null;
-}
-
-export interface ListMoviesByReleaseYearResponse {
-  movies: ({
-    id: UUIDString;
-    title: string;
-    imageUrl: string;
-  } & Movie_Key)[];
-}
-
-export interface ListMoviesByTagResponse {
-  movies: ({
-    id: UUIDString;
-    title: string;
-    imageUrl: string;
-    genre?: string | null;
-    rating?: number | null;
-  } & Movie_Key)[];
-}
-
-export interface ListMoviesByTagVariables {
-  tag: string;
-}
-
-export interface ListMoviesByTitleStringResponse {
-  prefixed: ({
-    title: string;
-  })[];
-    suffixed: ({
-      title: string;
-    })[];
-      contained: ({
-        title: string;
-      })[];
-}
-
-export interface ListMoviesByTitleStringVariables {
-  prefix?: string | null;
-  suffix?: string | null;
-  contained?: string | null;
-}
-
-export interface ListMoviesFilterResponse {
-  movies: ({
-    title: string;
-    imageUrl: string;
-  })[];
-}
-
-export interface ListMoviesFilterVariables {
-  genre?: string | null;
-  limit?: number | null;
-}
-
-export interface ListMoviesResponse {
-  movies: ({
-    id: UUIDString;
-    title: string;
-    imageUrl: string;
-    releaseYear?: number | null;
-    genre?: string | null;
-    rating?: number | null;
-    tags?: string[] | null;
-  } & Movie_Key)[];
-}
-
-export interface ListUsersResponse {
-  users: ({
-    id: string;
-    username: string;
-    favoriteActors_on_user: ({
-      actor: {
-        id: UUIDString;
-        name: string;
-        imageUrl: string;
-      } & Actor_Key;
-    })[];
-      favoriteMovies_on_user: ({
-        movie: {
-          id: UUIDString;
-          title: string;
-          genre?: string | null;
-          imageUrl: string;
-          tags?: string[] | null;
-        } & Movie_Key;
-      })[];
-        reviews_on_user: ({
-          id: UUIDString;
-          rating?: number | null;
-          reviewText?: string | null;
-          reviewDate: DateString;
-          movie: {
-            id: UUIDString;
-            title: string;
-          } & Movie_Key;
-        })[];
-          watchedMovies_on_user: ({
-            movie: {
-              id: UUIDString;
-              title: string;
-              genre?: string | null;
-              imageUrl: string;
-            } & Movie_Key;
-          })[];
-  } & User_Key)[];
-}
-
-export interface MovieActor_Key {
-  movieId: UUIDString;
-  actorId: UUIDString;
-  __typename?: 'MovieActor_Key';
-}
-
-export interface MovieByKeyResponse {
-  movie?: {
-    title: string;
-    imageUrl: string;
-  };
-}
-
-export interface MovieByKeyVariables {
-  key: Movie_Key;
-}
-
-export interface MovieByTitleResponse {
-  movies: ({
-    id: UUIDString;
-    title: string;
-    imageUrl: string;
-    genre?: string | null;
-    rating?: number | null;
-  } & Movie_Key)[];
-}
-
-export interface MovieByTitleVariables {
-  title: string;
-}
-
-export interface MovieByTopRatingResponse {
-  mostPopular: ({
-    id: UUIDString;
-    title: string;
-    imageUrl: string;
-    rating?: number | null;
-    tags?: string[] | null;
-  } & Movie_Key)[];
-}
-
-export interface MovieByTopRatingVariables {
-  genre?: string | null;
-}
-
-export interface MovieMetadata_Key {
-  id: UUIDString;
-  __typename?: 'MovieMetadata_Key';
-}
-
-export interface Movie_Key {
-  id: UUIDString;
-  __typename?: 'Movie_Key';
-}
-
-export interface MoviesByReleaseYearResponse {
-  movies: ({
-    id: UUIDString;
-    rating?: number | null;
-    title: string;
-    imageUrl: string;
-  } & Movie_Key)[];
-}
-
-export interface MoviesByReleaseYearVariables {
-  min?: number | null;
-  max?: number | null;
-}
-
-export interface MoviesRecentlyReleasedResponse {
-  movies: ({
-    id: UUIDString;
-    title: string;
-    rating?: number | null;
-    imageUrl: string;
-    genre?: string | null;
-    tags?: string[] | null;
-  } & Movie_Key)[];
-}
-
-export interface MoviesTop10Response {
-  movies: ({
-    id: UUIDString;
-    title: string;
-    imageUrl: string;
-    rating?: number | null;
-    genre?: string | null;
-    tags?: string[] | null;
-    metadata: ({
-      director?: string | null;
-    })[];
-      mainActors: ({
-        id: UUIDString;
-        name: string;
-        imageUrl: string;
-      } & Actor_Key)[];
-        supportingActors: ({
-          id: UUIDString;
-          name: string;
-          imageUrl: string;
-        } & Actor_Key)[];
-  } & Movie_Key)[];
-}
-
-export interface Review_Key {
-  userId: string;
-  movieId: UUIDString;
-  __typename?: 'Review_Key';
-}
-
-export interface SearchMovieDescriptionUsingL2similarityResponse {
-  movies_descriptionEmbedding_similarity: ({
-    id: UUIDString;
-    title: string;
-    description?: string | null;
-    tags?: string[] | null;
-    rating?: number | null;
-    imageUrl: string;
-  } & Movie_Key)[];
-}
-
-export interface SearchMovieDescriptionUsingL2similarityVariables {
-  query: string;
-}
-
-export interface UpdateMovieResponse {
-  movie_update?: Movie_Key | null;
-}
-
-export interface UpdateMovieVariables {
-  id: UUIDString;
-  title?: string | null;
-  releaseYear?: number | null;
-  genre?: string | null;
-  rating?: number | null;
-  description?: string | null;
-  imageUrl?: string | null;
-  tags?: string[] | null;
-}
-
-export interface UpsertUserResponse {
-  user_upsert: User_Key;
-}
-
-export interface UpsertUserVariables {
-  username: string;
-}
-
-export interface UserMoviePreferencesResponse {
-  users: ({
-    likedMovies: ({
-      title: string;
-      imageUrl: string;
-      genre?: string | null;
-      description?: string | null;
-    })[];
-      dislikedMovies: ({
-        title: string;
-        imageUrl: string;
-        genre?: string | null;
-        description?: string | null;
-      })[];
-  })[];
-}
-
-export interface UserMoviePreferencesVariables {
-  username: string;
-}
-
-export interface User_Key {
-  id: string;
-  __typename?: 'User_Key';
-}
-
-export interface WatchedMovie_Key {
-  userId: string;
-  movieId: UUIDString;
-  __typename?: 'WatchedMovie_Key';
-}
-
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function createMovieRef(vars: CreateMovieVariables): MutationRef<CreateMovieResponse, CreateMovieVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function createMovieRef(dc: DataConnect, vars: CreateMovieVariables): MutationRef<CreateMovieResponse,CreateMovieVariables>;
-
-export function createMovie(vars: CreateMovieVariables): MutationPromise<CreateMovieResponse, CreateMovieVariables>;
-export function createMovie(dc: DataConnect, vars: CreateMovieVariables): MutationPromise<CreateMovieResponse,CreateMovieVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function updateMovieRef(vars: UpdateMovieVariables): MutationRef<UpdateMovieResponse, UpdateMovieVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function updateMovieRef(dc: DataConnect, vars: UpdateMovieVariables): MutationRef<UpdateMovieResponse,UpdateMovieVariables>;
-
-export function updateMovie(vars: UpdateMovieVariables): MutationPromise<UpdateMovieResponse, UpdateMovieVariables>;
-export function updateMovie(dc: DataConnect, vars: UpdateMovieVariables): MutationPromise<UpdateMovieResponse,UpdateMovieVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function deleteMovieRef(vars: DeleteMovieVariables): MutationRef<DeleteMovieResponse, DeleteMovieVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function deleteMovieRef(dc: DataConnect, vars: DeleteMovieVariables): MutationRef<DeleteMovieResponse,DeleteMovieVariables>;
-
-export function deleteMovie(vars: DeleteMovieVariables): MutationPromise<DeleteMovieResponse, DeleteMovieVariables>;
-export function deleteMovie(dc: DataConnect, vars: DeleteMovieVariables): MutationPromise<DeleteMovieResponse,DeleteMovieVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function deleteUnpopularMoviesRef(vars: DeleteUnpopularMoviesVariables): MutationRef<DeleteUnpopularMoviesResponse, DeleteUnpopularMoviesVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function deleteUnpopularMoviesRef(dc: DataConnect, vars: DeleteUnpopularMoviesVariables): MutationRef<DeleteUnpopularMoviesResponse,DeleteUnpopularMoviesVariables>;
-
-export function deleteUnpopularMovies(vars: DeleteUnpopularMoviesVariables): MutationPromise<DeleteUnpopularMoviesResponse, DeleteUnpopularMoviesVariables>;
-export function deleteUnpopularMovies(dc: DataConnect, vars: DeleteUnpopularMoviesVariables): MutationPromise<DeleteUnpopularMoviesResponse,DeleteUnpopularMoviesVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function addWatchedMovieRef(vars: AddWatchedMovieVariables): MutationRef<AddWatchedMovieResponse, AddWatchedMovieVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function addWatchedMovieRef(dc: DataConnect, vars: AddWatchedMovieVariables): MutationRef<AddWatchedMovieResponse,AddWatchedMovieVariables>;
-
-export function addWatchedMovie(vars: AddWatchedMovieVariables): MutationPromise<AddWatchedMovieResponse, AddWatchedMovieVariables>;
-export function addWatchedMovie(dc: DataConnect, vars: AddWatchedMovieVariables): MutationPromise<AddWatchedMovieResponse,AddWatchedMovieVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function deleteWatchedMovieRef(vars: DeleteWatchedMovieVariables): MutationRef<DeleteWatchedMovieResponse, DeleteWatchedMovieVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function deleteWatchedMovieRef(dc: DataConnect, vars: DeleteWatchedMovieVariables): MutationRef<DeleteWatchedMovieResponse,DeleteWatchedMovieVariables>;
-
-export function deleteWatchedMovie(vars: DeleteWatchedMovieVariables): MutationPromise<DeleteWatchedMovieResponse, DeleteWatchedMovieVariables>;
-export function deleteWatchedMovie(dc: DataConnect, vars: DeleteWatchedMovieVariables): MutationPromise<DeleteWatchedMovieResponse,DeleteWatchedMovieVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function addFavoritedMovieRef(vars: AddFavoritedMovieVariables): MutationRef<AddFavoritedMovieResponse, AddFavoritedMovieVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function addFavoritedMovieRef(dc: DataConnect, vars: AddFavoritedMovieVariables): MutationRef<AddFavoritedMovieResponse,AddFavoritedMovieVariables>;
-
-export function addFavoritedMovie(vars: AddFavoritedMovieVariables): MutationPromise<AddFavoritedMovieResponse, AddFavoritedMovieVariables>;
-export function addFavoritedMovie(dc: DataConnect, vars: AddFavoritedMovieVariables): MutationPromise<AddFavoritedMovieResponse,AddFavoritedMovieVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function deleteFavoritedMovieRef(vars: DeleteFavoritedMovieVariables): MutationRef<DeleteFavoritedMovieResponse, DeleteFavoritedMovieVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function deleteFavoritedMovieRef(dc: DataConnect, vars: DeleteFavoritedMovieVariables): MutationRef<DeleteFavoritedMovieResponse,DeleteFavoritedMovieVariables>;
-
-export function deleteFavoritedMovie(vars: DeleteFavoritedMovieVariables): MutationPromise<DeleteFavoritedMovieResponse, DeleteFavoritedMovieVariables>;
-export function deleteFavoritedMovie(dc: DataConnect, vars: DeleteFavoritedMovieVariables): MutationPromise<DeleteFavoritedMovieResponse,DeleteFavoritedMovieVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function addFavoritedActorRef(vars: AddFavoritedActorVariables): MutationRef<AddFavoritedActorResponse, AddFavoritedActorVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function addFavoritedActorRef(dc: DataConnect, vars: AddFavoritedActorVariables): MutationRef<AddFavoritedActorResponse,AddFavoritedActorVariables>;
-
-export function addFavoritedActor(vars: AddFavoritedActorVariables): MutationPromise<AddFavoritedActorResponse, AddFavoritedActorVariables>;
-export function addFavoritedActor(dc: DataConnect, vars: AddFavoritedActorVariables): MutationPromise<AddFavoritedActorResponse,AddFavoritedActorVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function deleteFavoriteActorRef(vars: DeleteFavoriteActorVariables): MutationRef<DeleteFavoriteActorResponse, DeleteFavoriteActorVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function deleteFavoriteActorRef(dc: DataConnect, vars: DeleteFavoriteActorVariables): MutationRef<DeleteFavoriteActorResponse,DeleteFavoriteActorVariables>;
-
-export function deleteFavoriteActor(vars: DeleteFavoriteActorVariables): MutationPromise<DeleteFavoriteActorResponse, DeleteFavoriteActorVariables>;
-export function deleteFavoriteActor(dc: DataConnect, vars: DeleteFavoriteActorVariables): MutationPromise<DeleteFavoriteActorResponse,DeleteFavoriteActorVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function addReviewRef(vars: AddReviewVariables): MutationRef<AddReviewResponse, AddReviewVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function addReviewRef(dc: DataConnect, vars: AddReviewVariables): MutationRef<AddReviewResponse,AddReviewVariables>;
-
-export function addReview(vars: AddReviewVariables): MutationPromise<AddReviewResponse, AddReviewVariables>;
-export function addReview(dc: DataConnect, vars: AddReviewVariables): MutationPromise<AddReviewResponse,AddReviewVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function deleteReviewRef(vars: DeleteReviewVariables): MutationRef<DeleteReviewResponse, DeleteReviewVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function deleteReviewRef(dc: DataConnect, vars: DeleteReviewVariables): MutationRef<DeleteReviewResponse,DeleteReviewVariables>;
-
-export function deleteReview(vars: DeleteReviewVariables): MutationPromise<DeleteReviewResponse, DeleteReviewVariables>;
-export function deleteReview(dc: DataConnect, vars: DeleteReviewVariables): MutationPromise<DeleteReviewResponse,DeleteReviewVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function upsertUserRef(vars: UpsertUserVariables): MutationRef<UpsertUserResponse, UpsertUserVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function upsertUserRef(dc: DataConnect, vars: UpsertUserVariables): MutationRef<UpsertUserResponse,UpsertUserVariables>;
-
-export function upsertUser(vars: UpsertUserVariables): MutationPromise<UpsertUserResponse, UpsertUserVariables>;
-export function upsertUser(dc: DataConnect, vars: UpsertUserVariables): MutationPromise<UpsertUserResponse,UpsertUserVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function listMoviesRef(): QueryRef<ListMoviesResponse, undefined>;/* Allow users to pass in custom DataConnect instances */
-export function listMoviesRef(dc: DataConnect): QueryRef<ListMoviesResponse,undefined>;
-
-export function listMovies(): QueryPromise<ListMoviesResponse, undefined>;
-export function listMovies(dc: DataConnect): QueryPromise<ListMoviesResponse,undefined>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function listUsersRef(): QueryRef<ListUsersResponse, undefined>;/* Allow users to pass in custom DataConnect instances */
-export function listUsersRef(dc: DataConnect): QueryRef<ListUsersResponse,undefined>;
-
-export function listUsers(): QueryPromise<ListUsersResponse, undefined>;
-export function listUsers(dc: DataConnect): QueryPromise<ListUsersResponse,undefined>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function listMoviesByGenreRef(vars: ListMoviesByGenreVariables): QueryRef<ListMoviesByGenreResponse, ListMoviesByGenreVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function listMoviesByGenreRef(dc: DataConnect, vars: ListMoviesByGenreVariables): QueryRef<ListMoviesByGenreResponse,ListMoviesByGenreVariables>;
-
-export function listMoviesByGenre(vars: ListMoviesByGenreVariables): QueryPromise<ListMoviesByGenreResponse, ListMoviesByGenreVariables>;
-export function listMoviesByGenre(dc: DataConnect, vars: ListMoviesByGenreVariables): QueryPromise<ListMoviesByGenreResponse,ListMoviesByGenreVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function listMoviesByReleaseYearRef(): QueryRef<ListMoviesByReleaseYearResponse, undefined>;/* Allow users to pass in custom DataConnect instances */
-export function listMoviesByReleaseYearRef(dc: DataConnect): QueryRef<ListMoviesByReleaseYearResponse,undefined>;
-
-export function listMoviesByReleaseYear(): QueryPromise<ListMoviesByReleaseYearResponse, undefined>;
-export function listMoviesByReleaseYear(dc: DataConnect): QueryPromise<ListMoviesByReleaseYearResponse,undefined>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getMovieByIdRef(vars: GetMovieByIdVariables): QueryRef<GetMovieByIdResponse, GetMovieByIdVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getMovieByIdRef(dc: DataConnect, vars: GetMovieByIdVariables): QueryRef<GetMovieByIdResponse,GetMovieByIdVariables>;
-
-export function getMovieById(vars: GetMovieByIdVariables): QueryPromise<GetMovieByIdResponse, GetMovieByIdVariables>;
-export function getMovieById(dc: DataConnect, vars: GetMovieByIdVariables): QueryPromise<GetMovieByIdResponse,GetMovieByIdVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getActorByIdRef(vars: GetActorByIdVariables): QueryRef<GetActorByIdResponse, GetActorByIdVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getActorByIdRef(dc: DataConnect, vars: GetActorByIdVariables): QueryRef<GetActorByIdResponse,GetActorByIdVariables>;
-
-export function getActorById(vars: GetActorByIdVariables): QueryPromise<GetActorByIdResponse, GetActorByIdVariables>;
-export function getActorById(dc: DataConnect, vars: GetActorByIdVariables): QueryPromise<GetActorByIdResponse,GetActorByIdVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function userMoviePreferencesRef(vars: UserMoviePreferencesVariables): QueryRef<UserMoviePreferencesResponse, UserMoviePreferencesVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function userMoviePreferencesRef(dc: DataConnect, vars: UserMoviePreferencesVariables): QueryRef<UserMoviePreferencesResponse,UserMoviePreferencesVariables>;
-
-export function userMoviePreferences(vars: UserMoviePreferencesVariables): QueryPromise<UserMoviePreferencesResponse, UserMoviePreferencesVariables>;
-export function userMoviePreferences(dc: DataConnect, vars: UserMoviePreferencesVariables): QueryPromise<UserMoviePreferencesResponse,UserMoviePreferencesVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getMovieMetadataRef(vars: GetMovieMetadataVariables): QueryRef<GetMovieMetadataResponse, GetMovieMetadataVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getMovieMetadataRef(dc: DataConnect, vars: GetMovieMetadataVariables): QueryRef<GetMovieMetadataResponse,GetMovieMetadataVariables>;
-
-export function getMovieMetadata(vars: GetMovieMetadataVariables): QueryPromise<GetMovieMetadataResponse, GetMovieMetadataVariables>;
-export function getMovieMetadata(dc: DataConnect, vars: GetMovieMetadataVariables): QueryPromise<GetMovieMetadataResponse,GetMovieMetadataVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getMovieCastRef(vars: GetMovieCastVariables): QueryRef<GetMovieCastResponse, GetMovieCastVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getMovieCastRef(dc: DataConnect, vars: GetMovieCastVariables): QueryRef<GetMovieCastResponse,GetMovieCastVariables>;
-
-export function getMovieCast(vars: GetMovieCastVariables): QueryPromise<GetMovieCastResponse, GetMovieCastVariables>;
-export function getMovieCast(dc: DataConnect, vars: GetMovieCastVariables): QueryPromise<GetMovieCastResponse,GetMovieCastVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function listMoviesByPartialTitleRef(vars: ListMoviesByPartialTitleVariables): QueryRef<ListMoviesByPartialTitleResponse, ListMoviesByPartialTitleVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function listMoviesByPartialTitleRef(dc: DataConnect, vars: ListMoviesByPartialTitleVariables): QueryRef<ListMoviesByPartialTitleResponse,ListMoviesByPartialTitleVariables>;
-
-export function listMoviesByPartialTitle(vars: ListMoviesByPartialTitleVariables): QueryPromise<ListMoviesByPartialTitleResponse, ListMoviesByPartialTitleVariables>;
-export function listMoviesByPartialTitle(dc: DataConnect, vars: ListMoviesByPartialTitleVariables): QueryPromise<ListMoviesByPartialTitleResponse,ListMoviesByPartialTitleVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function movieByKeyRef(vars: MovieByKeyVariables): QueryRef<MovieByKeyResponse, MovieByKeyVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function movieByKeyRef(dc: DataConnect, vars: MovieByKeyVariables): QueryRef<MovieByKeyResponse,MovieByKeyVariables>;
-
-export function movieByKey(vars: MovieByKeyVariables): QueryPromise<MovieByKeyResponse, MovieByKeyVariables>;
-export function movieByKey(dc: DataConnect, vars: MovieByKeyVariables): QueryPromise<MovieByKeyResponse,MovieByKeyVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function movieByTitleRef(vars: MovieByTitleVariables): QueryRef<MovieByTitleResponse, MovieByTitleVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function movieByTitleRef(dc: DataConnect, vars: MovieByTitleVariables): QueryRef<MovieByTitleResponse,MovieByTitleVariables>;
-
-export function movieByTitle(vars: MovieByTitleVariables): QueryPromise<MovieByTitleResponse, MovieByTitleVariables>;
-export function movieByTitle(dc: DataConnect, vars: MovieByTitleVariables): QueryPromise<MovieByTitleResponse,MovieByTitleVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function movieByTopRatingRef(vars?: MovieByTopRatingVariables): QueryRef<MovieByTopRatingResponse, MovieByTopRatingVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function movieByTopRatingRef(dc: DataConnect, vars?: MovieByTopRatingVariables): QueryRef<MovieByTopRatingResponse,MovieByTopRatingVariables>;
-
-export function movieByTopRating(vars?: MovieByTopRatingVariables): QueryPromise<MovieByTopRatingResponse, MovieByTopRatingVariables>;
-export function movieByTopRating(dc: DataConnect, vars?: MovieByTopRatingVariables): QueryPromise<MovieByTopRatingResponse,MovieByTopRatingVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function listMoviesByTagRef(vars: ListMoviesByTagVariables): QueryRef<ListMoviesByTagResponse, ListMoviesByTagVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function listMoviesByTagRef(dc: DataConnect, vars: ListMoviesByTagVariables): QueryRef<ListMoviesByTagResponse,ListMoviesByTagVariables>;
-
-export function listMoviesByTag(vars: ListMoviesByTagVariables): QueryPromise<ListMoviesByTagResponse, ListMoviesByTagVariables>;
-export function listMoviesByTag(dc: DataConnect, vars: ListMoviesByTagVariables): QueryPromise<ListMoviesByTagResponse,ListMoviesByTagVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function moviesTop10Ref(): QueryRef<MoviesTop10Response, undefined>;/* Allow users to pass in custom DataConnect instances */
-export function moviesTop10Ref(dc: DataConnect): QueryRef<MoviesTop10Response,undefined>;
-
-export function moviesTop10(): QueryPromise<MoviesTop10Response, undefined>;
-export function moviesTop10(dc: DataConnect): QueryPromise<MoviesTop10Response,undefined>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function moviesByReleaseYearRef(vars?: MoviesByReleaseYearVariables): QueryRef<MoviesByReleaseYearResponse, MoviesByReleaseYearVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function moviesByReleaseYearRef(dc: DataConnect, vars?: MoviesByReleaseYearVariables): QueryRef<MoviesByReleaseYearResponse,MoviesByReleaseYearVariables>;
-
-export function moviesByReleaseYear(vars?: MoviesByReleaseYearVariables): QueryPromise<MoviesByReleaseYearResponse, MoviesByReleaseYearVariables>;
-export function moviesByReleaseYear(dc: DataConnect, vars?: MoviesByReleaseYearVariables): QueryPromise<MoviesByReleaseYearResponse,MoviesByReleaseYearVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function moviesRecentlyReleasedRef(): QueryRef<MoviesRecentlyReleasedResponse, undefined>;/* Allow users to pass in custom DataConnect instances */
-export function moviesRecentlyReleasedRef(dc: DataConnect): QueryRef<MoviesRecentlyReleasedResponse,undefined>;
-
-export function moviesRecentlyReleased(): QueryPromise<MoviesRecentlyReleasedResponse, undefined>;
-export function moviesRecentlyReleased(dc: DataConnect): QueryPromise<MoviesRecentlyReleasedResponse,undefined>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function listMoviesFilterRef(vars?: ListMoviesFilterVariables): QueryRef<ListMoviesFilterResponse, ListMoviesFilterVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function listMoviesFilterRef(dc: DataConnect, vars?: ListMoviesFilterVariables): QueryRef<ListMoviesFilterResponse,ListMoviesFilterVariables>;
-
-export function listMoviesFilter(vars?: ListMoviesFilterVariables): QueryPromise<ListMoviesFilterResponse, ListMoviesFilterVariables>;
-export function listMoviesFilter(dc: DataConnect, vars?: ListMoviesFilterVariables): QueryPromise<ListMoviesFilterResponse,ListMoviesFilterVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function listMoviesByTitleStringRef(vars?: ListMoviesByTitleStringVariables): QueryRef<ListMoviesByTitleStringResponse, ListMoviesByTitleStringVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function listMoviesByTitleStringRef(dc: DataConnect, vars?: ListMoviesByTitleStringVariables): QueryRef<ListMoviesByTitleStringResponse,ListMoviesByTitleStringVariables>;
-
-export function listMoviesByTitleString(vars?: ListMoviesByTitleStringVariables): QueryPromise<ListMoviesByTitleStringResponse, ListMoviesByTitleStringVariables>;
-export function listMoviesByTitleString(dc: DataConnect, vars?: ListMoviesByTitleStringVariables): QueryPromise<ListMoviesByTitleStringResponse,ListMoviesByTitleStringVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function listMoviesByRatingAndGenreRef(vars: ListMoviesByRatingAndGenreVariables): QueryRef<ListMoviesByRatingAndGenreResponse, ListMoviesByRatingAndGenreVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function listMoviesByRatingAndGenreRef(dc: DataConnect, vars: ListMoviesByRatingAndGenreVariables): QueryRef<ListMoviesByRatingAndGenreResponse,ListMoviesByRatingAndGenreVariables>;
-
-export function listMoviesByRatingAndGenre(vars: ListMoviesByRatingAndGenreVariables): QueryPromise<ListMoviesByRatingAndGenreResponse, ListMoviesByRatingAndGenreVariables>;
-export function listMoviesByRatingAndGenre(dc: DataConnect, vars: ListMoviesByRatingAndGenreVariables): QueryPromise<ListMoviesByRatingAndGenreResponse,ListMoviesByRatingAndGenreVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getFavoriteMoviesByIdRef(vars: GetFavoriteMoviesByIdVariables): QueryRef<GetFavoriteMoviesByIdResponse, GetFavoriteMoviesByIdVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getFavoriteMoviesByIdRef(dc: DataConnect, vars: GetFavoriteMoviesByIdVariables): QueryRef<GetFavoriteMoviesByIdResponse,GetFavoriteMoviesByIdVariables>;
-
-export function getFavoriteMoviesById(vars: GetFavoriteMoviesByIdVariables): QueryPromise<GetFavoriteMoviesByIdResponse, GetFavoriteMoviesByIdVariables>;
-export function getFavoriteMoviesById(dc: DataConnect, vars: GetFavoriteMoviesByIdVariables): QueryPromise<GetFavoriteMoviesByIdResponse,GetFavoriteMoviesByIdVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getFavoriteActorsByIdRef(vars: GetFavoriteActorsByIdVariables): QueryRef<GetFavoriteActorsByIdResponse, GetFavoriteActorsByIdVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getFavoriteActorsByIdRef(dc: DataConnect, vars: GetFavoriteActorsByIdVariables): QueryRef<GetFavoriteActorsByIdResponse,GetFavoriteActorsByIdVariables>;
-
-export function getFavoriteActorsById(vars: GetFavoriteActorsByIdVariables): QueryPromise<GetFavoriteActorsByIdResponse, GetFavoriteActorsByIdVariables>;
-export function getFavoriteActorsById(dc: DataConnect, vars: GetFavoriteActorsByIdVariables): QueryPromise<GetFavoriteActorsByIdResponse,GetFavoriteActorsByIdVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getWatchedMoviesByAuthIdRef(vars: GetWatchedMoviesByAuthIdVariables): QueryRef<GetWatchedMoviesByAuthIdResponse, GetWatchedMoviesByAuthIdVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getWatchedMoviesByAuthIdRef(dc: DataConnect, vars: GetWatchedMoviesByAuthIdVariables): QueryRef<GetWatchedMoviesByAuthIdResponse,GetWatchedMoviesByAuthIdVariables>;
-
-export function getWatchedMoviesByAuthId(vars: GetWatchedMoviesByAuthIdVariables): QueryPromise<GetWatchedMoviesByAuthIdResponse, GetWatchedMoviesByAuthIdVariables>;
-export function getWatchedMoviesByAuthId(dc: DataConnect, vars: GetWatchedMoviesByAuthIdVariables): QueryPromise<GetWatchedMoviesByAuthIdResponse,GetWatchedMoviesByAuthIdVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getUserByIdRef(vars: GetUserByIdVariables): QueryRef<GetUserByIdResponse, GetUserByIdVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getUserByIdRef(dc: DataConnect, vars: GetUserByIdVariables): QueryRef<GetUserByIdResponse,GetUserByIdVariables>;
-
-export function getUserById(vars: GetUserByIdVariables): QueryPromise<GetUserByIdResponse, GetUserByIdVariables>;
-export function getUserById(dc: DataConnect, vars: GetUserByIdVariables): QueryPromise<GetUserByIdResponse,GetUserByIdVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getIfWatchedRef(vars: GetIfWatchedVariables): QueryRef<GetIfWatchedResponse, GetIfWatchedVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getIfWatchedRef(dc: DataConnect, vars: GetIfWatchedVariables): QueryRef<GetIfWatchedResponse,GetIfWatchedVariables>;
-
-export function getIfWatched(vars: GetIfWatchedVariables): QueryPromise<GetIfWatchedResponse, GetIfWatchedVariables>;
-export function getIfWatched(dc: DataConnect, vars: GetIfWatchedVariables): QueryPromise<GetIfWatchedResponse,GetIfWatchedVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getIfFavoritedMovieRef(vars: GetIfFavoritedMovieVariables): QueryRef<GetIfFavoritedMovieResponse, GetIfFavoritedMovieVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getIfFavoritedMovieRef(dc: DataConnect, vars: GetIfFavoritedMovieVariables): QueryRef<GetIfFavoritedMovieResponse,GetIfFavoritedMovieVariables>;
-
-export function getIfFavoritedMovie(vars: GetIfFavoritedMovieVariables): QueryPromise<GetIfFavoritedMovieResponse, GetIfFavoritedMovieVariables>;
-export function getIfFavoritedMovie(dc: DataConnect, vars: GetIfFavoritedMovieVariables): QueryPromise<GetIfFavoritedMovieResponse,GetIfFavoritedMovieVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function getIfFavoritedActorRef(vars: GetIfFavoritedActorVariables): QueryRef<GetIfFavoritedActorResponse, GetIfFavoritedActorVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function getIfFavoritedActorRef(dc: DataConnect, vars: GetIfFavoritedActorVariables): QueryRef<GetIfFavoritedActorResponse,GetIfFavoritedActorVariables>;
-
-export function getIfFavoritedActor(vars: GetIfFavoritedActorVariables): QueryPromise<GetIfFavoritedActorResponse, GetIfFavoritedActorVariables>;
-export function getIfFavoritedActor(dc: DataConnect, vars: GetIfFavoritedActorVariables): QueryPromise<GetIfFavoritedActorResponse,GetIfFavoritedActorVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function fuzzySearchRef(vars: FuzzySearchVariables): QueryRef<FuzzySearchResponse, FuzzySearchVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function fuzzySearchRef(dc: DataConnect, vars: FuzzySearchVariables): QueryRef<FuzzySearchResponse,FuzzySearchVariables>;
-
-export function fuzzySearch(vars: FuzzySearchVariables): QueryPromise<FuzzySearchResponse, FuzzySearchVariables>;
-export function fuzzySearch(dc: DataConnect, vars: FuzzySearchVariables): QueryPromise<FuzzySearchResponse,FuzzySearchVariables>;
-
-
-/* Allow users to create refs without passing in DataConnect */
-export function searchMovieDescriptionUsingL2similarityRef(vars: SearchMovieDescriptionUsingL2similarityVariables): QueryRef<SearchMovieDescriptionUsingL2similarityResponse, SearchMovieDescriptionUsingL2similarityVariables>;
-/* Allow users to pass in custom DataConnect instances */
-export function searchMovieDescriptionUsingL2similarityRef(dc: DataConnect, vars: SearchMovieDescriptionUsingL2similarityVariables): QueryRef<SearchMovieDescriptionUsingL2similarityResponse,SearchMovieDescriptionUsingL2similarityVariables>;
-
-export function searchMovieDescriptionUsingL2similarity(vars: SearchMovieDescriptionUsingL2similarityVariables): QueryPromise<SearchMovieDescriptionUsingL2similarityResponse, SearchMovieDescriptionUsingL2similarityVariables>;
-export function searchMovieDescriptionUsingL2similarity(dc: DataConnect, vars: SearchMovieDescriptionUsingL2similarityVariables): QueryPromise<SearchMovieDescriptionUsingL2similarityResponse,SearchMovieDescriptionUsingL2similarityVariables>;
-
-
diff --git a/dataconnect/movie/lib/dataconnect-sdk/package.json b/dataconnect/movie/lib/dataconnect-sdk/package.json
deleted file mode 100644
index 30759b830..000000000
--- a/dataconnect/movie/lib/dataconnect-sdk/package.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-  "name": "@movie/sdk",
-  "version": "1.0.0",
-  "author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)",
-  "description": "Generated SDK For movie-connector",
-  "license": "Apache-2.0",
-  "engines": {
-    "node": " >=20.0"
-  },
-  "typings": "index.d.ts",
-  "module": "esm/index.esm.js",
-  "main": "index.cjs.js",
-  "browser": "esm/index.esm.js",
-  "exports": {
-    ".": {
-      "types": "./index.d.ts",
-      "require": "./index.cjs.js",
-      "default": "./esm/index.esm.js"
-    },
-    "./package.json": "./package.json"
-  },
-  "peerDependencies": {
-    "firebase": "dataconnect-preview"
-  }
-}
\ No newline at end of file

From 6d3b882bb632afea63105ca985f3e005e7051eab Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Fri, 31 May 2024 14:55:42 -0400
Subject: [PATCH 09/82] fix: readme

---
 .gitignore             |  2 --
 dataconnect/.gitignore | 69 ++++++++++++++++++++++++++++++++++++++++++
 dataconnect/README.md  |  2 +-
 3 files changed, 70 insertions(+), 3 deletions(-)
 create mode 100644 dataconnect/.gitignore

diff --git a/.gitignore b/.gitignore
index 6a850a095..dee8c505e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,5 +8,3 @@
 dist/
 **/ui-debug.log
 .next
-dataconnect/.dataconnect
-dataconnect/movie/lib/dataconnect-sdk
\ No newline at end of file
diff --git a/dataconnect/.gitignore b/dataconnect/.gitignore
new file mode 100644
index 000000000..0663a14c0
--- /dev/null
+++ b/dataconnect/.gitignore
@@ -0,0 +1,69 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+firebase-debug.log*
+firebase-debug.*.log*
+
+# Firebase cache
+.firebase/
+
+# Firebase config
+
+# Uncomment this if you'd like others to create their own Firebase project.
+# For a team working on the same Firebase project(s), it is recommended to leave
+# it commented so all members can deploy to the same project(s) in .firebaserc.
+# .firebaserc
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.next
+.dataconnect
+movie/lib/dataconnect-sdk
\ No newline at end of file
diff --git a/dataconnect/README.md b/dataconnect/README.md
index 47b45d410..708390df9 100644
--- a/dataconnect/README.md
+++ b/dataconnect/README.md
@@ -21,7 +21,7 @@ Getting Started
 4. Clone this repository to your local machine.
 5. Update `firebase-tools` with `npm install -g firebase-tools`.
 6. Enable the DataConnect CLI with `firebase experiments:enable dataconnect`.
-7. Initialize your Firebase project in the `dataconnect` folder with `firebase init` and select DataConnect.
+7. Initialize your Firebase project in the `dataconnect` folder with `firebase init` and select DataConnect. Do not overwrite the dataconnect files when prompted.
 8. Replace variables in `.env.local` with your project-specific values.
 9. Allow domains for Firebase Auth (e.g., http://localhost or http://127.0.0.1).
 10. Deploy DataConnect with `firebase deploy --only dataconnect` (this unlocks hidden vectors search).

From 119634904b2a381deb14fbbf41b282fc12d5fbac Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 3 Jun 2024 12:33:25 -0400
Subject: [PATCH 10/82] fix: vector search

---
 dataconnect/dataconnect/1_movie_insert.gql    | 40 +++++++++----------
 dataconnect/dataconnect/2_actor_insert.gql    | 40 +++++++++----------
 dataconnect/dataconnect/connector/queries.gql |  9 +++++
 3 files changed, 49 insertions(+), 40 deletions(-)

diff --git a/dataconnect/dataconnect/1_movie_insert.gql b/dataconnect/dataconnect/1_movie_insert.gql
index 1a264ebbc..4078c2066 100644
--- a/dataconnect/dataconnect/1_movie_insert.gql
+++ b/dataconnect/dataconnect/1_movie_insert.gql
@@ -2,7 +2,7 @@ mutation {
   movie1: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440000",
     title: "Inception",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Finception.jpg?alt=media&token=0a2950ee-0df7-4909-a5fd-e9f44dd803d6",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Finception.jpg?alt=media&token=07b09781-b302-4623-a5c3-1956d0143168",
     releaseYear: 2010,
     genre: "sci-fi",
     rating: 8.8,
@@ -14,7 +14,7 @@ mutation {
   movie2: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440001",
     title: "The Matrix",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_matrix.jpg?alt=media&token=9d9a952e-6441-420a-8479-6a58d62655f8",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_matrix.jpg?alt=media&token=4975645d-fef8-409e-84a5-bcc1046e2059",
     releaseYear: 1999,
     genre: "action",
     rating: 8.7,
@@ -26,7 +26,7 @@ mutation {
   movie3: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440002",
     title: "John Wick 4",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fjohn_wick_4.jpg?alt=media&token=98c60306-fbd9-4718-ac7a-2c6cde8706d8",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fjohn_wick_4.jpg?alt=media&token=463ed467-9daa-4281-965d-44e7cc4172d5",
     releaseYear: 2023,
     genre: "action",
     rating: 8.1,
@@ -38,7 +38,7 @@ mutation {
   movie4: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440003",
     title: "The Dark Knight",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_dark_knight.jpg?alt=media&token=7ee322e9-3b27-4952-b4a9-e445a15412de",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_dark_knight.jpg?alt=media&token=a9803c59-40d5-4758-a6f4-9a7c274a1218",
     releaseYear: 2008,
     genre: "action",
     rating: 9.0,
@@ -50,7 +50,7 @@ mutation {
   movie5: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440004",
     title: "Fight Club",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Ffight_club.jpg?alt=media&token=1dcfbea5-feb3-4345-92bc-7551c671cb49",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Ffight_club.jpg?alt=media&token=a4bc1933-2607-42cd-a860-e44c4587fd9c",
     releaseYear: 1999,
     genre: "drama",
     rating: 8.8,
@@ -62,7 +62,7 @@ mutation {
   movie6: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440005",
     title: "Pulp Fiction",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fpulp_fiction.jpg?alt=media&token=d9ccbe88-c19b-4aab-bb89-016a7cbd4051",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fpulp_fiction.jpg?alt=media&token=0df86e18-5cb1-45b3-a6d9-3f41563c3465",
     releaseYear: 1994,
     genre: "crime",
     rating: 8.9,
@@ -74,7 +74,7 @@ mutation {
   movie7: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440006",
     title: "The Lord of the Rings: The Fellowship of the Ring",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Flotr_fellowship.jpg?alt=media&token=f98d137b-f37f-43e6-86f2-7f49e946e133",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Flotr_fellowship.jpg?alt=media&token=92641d2d-6c52-4172-bd66-95fb86b4b96b",
     releaseYear: 2001,
     genre: "fantasy",
     rating: 8.8,
@@ -86,7 +86,7 @@ mutation {
   movie8: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440007",
     title: "The Shawshank Redemption",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_shawshanks_redemption.jpg?alt=media&token=8fae5b0c-8797-4607-9c2b-3ecc09b48a8e",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_shawshanks_redemption.jpg?alt=media&token=f67b5ab2-a435-48b2-8251-5bf866b183e9",
     releaseYear: 1994,
     genre: "drama",
     rating: 9.3,
@@ -98,7 +98,7 @@ mutation {
   movie9: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440008",
     title: "Forrest Gump",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fforrest_gump.jpeg?alt=media&token=decc25fa-d88e-49cc-a2ca-fc9a77e3a651",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fforrest_gump.jpeg?alt=media&token=f21e88ce-6fab-4218-aa55-94738acc9b8f",
     releaseYear: 1994,
     genre: "drama",
     rating: 8.8,
@@ -110,7 +110,7 @@ mutation {
   movie10: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440009",
     title: "The Godfather",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_godfather.jpg?alt=media&token=52cc0cbd-0fc7-4afa-a44e-f44ab4880079",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_godfather.jpg?alt=media&token=5297fd94-ae87-4995-9de5-3755232bad52",
     releaseYear: 1972,
     genre: "crime",
     rating: 9.2,
@@ -122,7 +122,7 @@ mutation {
   movie11: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440010",
     title: "The Silence of the Lambs",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_silence_of_the_lambs.jpg?alt=media&token=064778c8-8b0e-4412-8235-511082613118",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_silence_of_the_lambs.jpg?alt=media&token=7ca6abeb-b15c-4f5e-9280-5a590e89fe54",
     releaseYear: 1991,
     genre: "thriller",
     rating: 8.6,
@@ -134,7 +134,7 @@ mutation {
   movie12: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440011",
     title: "Saving Private Ryan",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fsaving_private_ryan.jpg?alt=media&token=54b5ade0-e41d-4f53-a39d-56fd5be270f9",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fsaving_private_ryan.jpg?alt=media&token=58ed877e-7ae0-4e30-9aee-d45c2deb7a00",
     releaseYear: 1998,
     genre: "war",
     rating: 8.6,
@@ -146,7 +146,7 @@ mutation {
   movie13: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440012",
     title: "The Avengers",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_avengers.jpg?alt=media&token=54cd8f43-cf29-4e86-9f78-a4c43c9ac79c",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_avengers.jpg?alt=media&token=3d68ccad-2fa1-48da-a83e-7941e246c9f9",
     releaseYear: 2012,
     genre: "action",
     rating: 8.0,
@@ -158,7 +158,7 @@ mutation {
   movie14: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440013",
     title: "Gladiator",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fgladiator.jpg?alt=media&token=aa112d9f-de39-4b5e-80c4-621c7af842bd",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fgladiator.jpg?alt=media&token=61d75825-b79f-4add-afdb-7da5eed53407",
     releaseYear: 2000,
     genre: "action",
     rating: 8.5,
@@ -170,7 +170,7 @@ mutation {
   movie15: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440014",
     title: "Titanic",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Ftitanic.png?alt=media&token=5f594626-19d8-4043-9d09-81104e128ed2",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Ftitanic.png?alt=media&token=dd03dc83-486e-4b03-9b03-2f9ed83fd9d0",
     releaseYear: 1997,
     genre: "romance",
     rating: 7.8,
@@ -182,7 +182,7 @@ mutation {
   movie16: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440015",
     title: "Avatar",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Favatar.jpg?alt=media&token=2d858616-4033-408a-aea0-9add07a67c88",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Favatar.jpg?alt=media&token=1c75b09d-7c7a-44bf-b7ad-e7da4d0b7193",
     releaseYear: 2009,
     genre: "sci-fi",
     rating: 7.8,
@@ -194,7 +194,7 @@ mutation {
   movie17: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440016",
     title: "Jurassic Park",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fjurassic_park.jpg?alt=media&token=040b46b8-c974-4825-85e5-2652bc375ed7",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fjurassic_park.jpg?alt=media&token=1731ce71-3384-4435-8a5b-821d4fd286d3",
     releaseYear: 1993,
     genre: "adventure",
     rating: 8.1,
@@ -206,7 +206,7 @@ mutation {
   movie18: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440017",
     title: "The Lion King",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fthe_lion_king.jpg?alt=media&token=4778e0ac-96e7-44fd-9422-423d5aad353f",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_lion_king.jpg?alt=media&token=3e4e4265-6ae7-47d6-a5ba-584de126ef00",
     releaseYear: 1994,
     genre: "animation",
     rating: 8.5,
@@ -218,7 +218,7 @@ mutation {
   movie19: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440018",
     title: "Star Wars: Episode IV - A New Hope",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fstar_wars_4.jpg?alt=media&token=cad4cb98-89ce-4c8a-a735-d7cdaf884b26",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fstar_wars_4.jpg?alt=media&token=b4ea7e0c-707f-43dd-8633-9d962e77b5a4",
     releaseYear: 1977,
     genre: "sci-fi",
     rating: 8.6,
@@ -230,7 +230,7 @@ mutation {
   movie20: movie_insert(data: {
     id: "550e8400-e29b-41d4-a716-446655440019",
     title: "Blade Runner",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/matcha-yuzu.appspot.com/o/fdc-quickstart%2Fblade_runner.jpg?alt=media&token=4c7e7c9d-c9c7-4cef-9eb7-4302b2610905",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fblade_runner.jpg?alt=media&token=d8e94bdd-1477-49f3-b244-dd7a9c059fc1",
     releaseYear: 1982,
     genre: "sci-fi",
     rating: 8.1,
diff --git a/dataconnect/dataconnect/2_actor_insert.gql b/dataconnect/dataconnect/2_actor_insert.gql
index a4a0c1c49..971cb1007 100644
--- a/dataconnect/dataconnect/2_actor_insert.gql
+++ b/dataconnect/dataconnect/2_actor_insert.gql
@@ -1,140 +1,140 @@
 mutation {
   actor1: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174000",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/46/Leonardo_Dicaprio_Cannes_2019.jpg/440px-Leonardo_Dicaprio_Cannes_2019.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdicaprio.jpeg?alt=media&token=452e030a-efa5-4ef4-bb81-502b23241316",
     name: "Leonardo DiCaprio",
     biography: "Leonardo DiCaprio is an American actor and producer. He has received numerous awards, including an Academy Award and three Golden Globe Awards. DiCaprio is known for his roles in Titanic, Inception, and The Revenant."
   })
   
   actor2: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174001",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Reuni%C3%A3o_com_o_ator_norte-americano_Keanu_Reeves_%2846806576944%29_%28cropped%29.jpg/440px-Reuni%C3%A3o_com_o_ator_norte-americano_Keanu_Reeves_%2846806576944%29_%28cropped%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fkeanu.jpg?alt=media&token=6056520c-ef3e-4823-aad0-108aab163115",
     name: "Keanu Reeves",
     biography: "Keanu Reeves is a Canadian actor known for his roles in The Matrix and John Wick series. He has gained acclaim for his versatility and has also directed and produced several films."
   })
   
   actor3: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174002",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Matthew_McConaughey_2019_%2848648344772%29.jpg/440px-Matthew_McConaughey_2019_%2848648344772%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fmcconaoghey.jpg?alt=media&token=d340ca18-ef51-44ac-a160-08e45b242cd7",
     name: "Matthew McConaughey",
     biography: "Matthew McConaughey is an American actor and producer. He gained fame with his breakout role in Dazed and Confused and has won an Academy Award for his performance in Dallas Buyers Club."
   })
 
   actor4: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174003",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Christian_Bale-7837.jpg/440px-Christian_Bale-7837.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fbale.jpg?alt=media&token=666f1690-a550-458f-a1cf-9505b7d1af7d",
     name: "Christian Bale",
     biography: "Christian Bale is an English actor known for his versatility and physical transformations for roles. He has starred in The Dark Knight Trilogy and won an Academy Award for The Fighter."
   })
 
   actor5: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174004",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Brad_Pitt_2019_by_Glenn_Francis.jpg/440px-Brad_Pitt_2019_by_Glenn_Francis.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fpitt.jpeg?alt=media&token=3a5283d4-f85c-4ba7-be72-51bc87ca4133",
     name: "Brad Pitt",
     biography: "Brad Pitt is an American actor and producer. He has won two Academy Awards and is known for his roles in Fight Club, Ocean's Eleven, and Once Upon a Time in Hollywood."
   })
 
   actor6: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174005",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/SamuelLJackson.jpg/440px-SamuelLJackson.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fjackson.jpg?alt=media&token=07be0601-19fe-4b5d-b111-84fa71f32139",
     name: "Samuel L. Jackson",
     biography: "Samuel L. Jackson is an American actor and producer. He is one of the most widely recognized actors of his generation, known for his roles in Pulp Fiction, the Marvel Cinematic Universe, and Jurassic Park."
   })
 
   actor7: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174006",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/6/64/Viggo_Mortensen_B_%282020%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fmortensen.jpeg?alt=media&token=e3d1ec99-b8e7-42e9-9d1c-03f56f61ecf7",
     name: "Viggo Mortensen",
     biography: "Viggo Mortensen is an American actor, author, and musician. He is best known for his role as Aragorn in The Lord of the Rings trilogy and has been nominated for three Academy Awards."
   })
 
   actor8: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174007",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Morgan_Freeman_at_The_Pentagon_on_2_August_2023_-_230802-D-PM193-3363_%28cropped%29.jpg/440px-Morgan_Freeman_at_The_Pentagon_on_2_August_2023_-_230802-D-PM193-3363_%28cropped%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Ffreeman.jpg?alt=media&token=94bc6227-119e-4ab0-b350-55fac7aeb062",
     name: "Morgan Freeman",
     biography: "Morgan Freeman is an American actor, director, and narrator. He is known for his distinctive voice and has won an Academy Award for his role in Million Dollar Baby."
   })
 
   actor9: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174008",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Tom_Hanks_TIFF_2019.jpg/440px-Tom_Hanks_TIFF_2019.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fhanks.jpeg?alt=media&token=d92979ce-da62-4b28-afbe-b8740bbb9d32",
     name: "Tom Hanks",
     biography: "Tom Hanks is an American actor and filmmaker. He is known for his roles in Forrest Gump, Saving Private Ryan, and Toy Story, and has won two Academy Awards for Best Actor."
   })
 
   actor10: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174009",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Al_Pacino_2016_%2830401544240%29.jpg/440px-Al_Pacino_2016_%2830401544240%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fpacino.jpg?alt=media&token=9c0c54b1-6913-48b5-8e5e-d6551dd2f182",
     name: "Al Pacino",
     biography: "Al Pacino is an American actor and filmmaker. He has won an Academy Award, two Tony Awards, and two Primetime Emmy Awards. He is known for his roles in The Godfather series, Scarface, and Scent of a Woman."
   })
 
   actor11: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174010",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/3/3f/Jodie_Foster_C%C3%A9sars_2011_2_%28cropped%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Ffoster.jpg?alt=media&token=b429734c-0f2d-4840-b75b-6857eac7bb4f",
     name: "Jodie Foster",
     biography: "Jodie Foster is an American actress and director. She has won two Academy Awards for Best Actress for her roles in The Accused and The Silence of the Lambs."
   })
 
   actor12: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174011",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Tom_Cruise_by_Gage_Skidmore_2.jpg/440px-Tom_Cruise_by_Gage_Skidmore_2.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fcruise.jpg?alt=media&token=d34b0326-a8d1-4f01-86e5-f3f094594e5a",
     name: "Tom Cruise",
     biography: "Tom Cruise is an American actor and producer. He is one of the highest-paid actors in the world and is known for his roles in Top Gun, the Mission: Impossible series, and Jerry Maguire."
   })
 
   actor13: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174012",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Robert_Downey_Jr_2014_Comic_Con_%28cropped%29.jpg/440px-Robert_Downey_Jr_2014_Comic_Con_%28cropped%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdowney.jpg?alt=media&token=dd291c96-6ef0-42fc-841c-902c80748b37",
     name: "Robert Downey Jr.",
     biography: "Robert Downey Jr. is an American actor and producer. He is known for his roles in Iron Man, Sherlock Holmes, and Chaplin, and has been a major figure in the Marvel Cinematic Universe."
   })
 
   actor14: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174013",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Russell_Crowe_%2833994020424%29.jpg/440px-Russell_Crowe_%2833994020424%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fcrowe.jpg?alt=media&token=46d413d5-ace8-404e-b018-8d7e6fe0d362",
     name: "Russell Crowe",
     biography: "Russell Crowe is an Australian actor, film producer, and musician. He gained international fame for his role in Gladiator, for which he won the Academy Award for Best Actor."
   })
 
   actor15: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174014",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Kate_Winslet_at_the_2017_Toronto_International_Film_Festival_%28cropped%29.jpg/440px-Kate_Winslet_at_the_2017_Toronto_International_Film_Festival_%28cropped%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fwinslet.jpg?alt=media&token=b675585e-356e-4361-a041-5ac1a6ee5922",
     name: "Kate Winslet",
     biography: "Kate Winslet is an English actress known for her roles in Titanic, The Reader, and Eternal Sunshine of the Spotless Mind. She has won numerous awards, including an Academy Award and an Emmy."
   })
 
   actor16: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174015",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Sigourney_Weaver_by_Gage_Skidmore_4.jpg/862px-Sigourney_Weaver_by_Gage_Skidmore_4.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fweaver.jpeg?alt=media&token=263b5c3d-e0ee-43c3-854d-9b236c6df391",
     name: "Sigourney Weaver",
     biography: "Sigourney Weaver is an American actress best known for her roles in the Alien franchise, Ghostbusters, and Avatar. She has been nominated for three Academy Awards and has won two Golden Globe Awards."
   })
 
   actor17: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174016",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Jeff_Goldblum_by_Gage_Skidmore_3.jpg/440px-Jeff_Goldblum_by_Gage_Skidmore_3.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fgoldblume.jpeg?alt=media&token=18277dd1-166c-4934-a02e-19ef141c86e2",
     name: "Jeff Goldblum",
     biography: "Jeff Goldblum is an American actor and musician known for his roles in Jurassic Park, Independence Day, and The Fly. His unique delivery and eccentric characters have made him a cult icon."
   })
 
   actor18: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174017",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/James_Earl_Jones_%288516667383%29.jpg/440px-James_Earl_Jones_%288516667383%29.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fjones.jpg?alt=media&token=f7ac9bc4-6e26-4b25-9a73-7a90f699424e",
     name: "James Earl Jones",
     biography: "James Earl Jones is an American actor known for his deep resonant voice, which has been featured in roles such as Darth Vader in Star Wars and Mufasa in The Lion King. He has won multiple awards, including a Tony, Emmy, and Grammy."
   })
 
   actor19: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174018",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Harrison_Ford_by_Gage_Skidmore_3.jpg/440px-Harrison_Ford_by_Gage_Skidmore_3.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fford.jpg?alt=media&token=928434c0-d492-4c8e-bdf0-0db585008d87",
     name: "Harrison Ford",
     biography: "Harrison Ford is an American actor known for his iconic roles as Han Solo in Star Wars and Indiana Jones in the Indiana Jones series. He has been nominated for an Academy Award and has received numerous other accolades."
   })
 
   actor20: actor_insert(data: {
     id: "123e4567-e89b-12d3-a456-426614174019",
-    imageUrl: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Arnold_Schwarzenegger_by_Gage_Skidmore_4.jpg/440px-Arnold_Schwarzenegger_by_Gage_Skidmore_4.jpg",
+    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fschwarzenegger.jpeg?alt=media&token=c46fb249-41ef-4084-b4ad-9517bee6ab46",
     name: "Arnold Schwarzenegger",
     biography: "Arnold Schwarzenegger is an Austrian-American actor, businessman, and former politician. He is best known for his roles in The Terminator series and Total Recall, and for serving as the 38th Governor of California."
   })
diff --git a/dataconnect/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql
index f191debfc..6a4887023 100644
--- a/dataconnect/dataconnect/connector/queries.gql
+++ b/dataconnect/dataconnect/connector/queries.gql
@@ -8,9 +8,18 @@ query ListMovies @auth(level: PUBLIC) {
     genre
     rating
     tags
+    description
   }
 }
 
+query searchMovieDescriptionUsingL2Similarity1($compare: Vector!, $within: Float, $excludesContent: String, $limit: Int) @auth(level: PUBLIC) {
+    movies_descriptionEmbedding_similarity(compare: $compare, method: L2, within: $within, where: {description: {ne: $excludesContent}}, limit: $limit) {
+      id
+      title
+	description
+    }
+  }
+
 # List subset of fields for users
 query ListUsers @auth(level: PUBLIC) {
   users {

From bf92f748f4f2740b433363dbac9b9b5b0d57f52b Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 3 Jun 2024 12:37:09 -0400
Subject: [PATCH 11/82] fix: vector query description

---
 dataconnect/dataconnect/connector/queries.gql | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/dataconnect/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql
index 6a4887023..6a4437a2d 100644
--- a/dataconnect/dataconnect/connector/queries.gql
+++ b/dataconnect/dataconnect/connector/queries.gql
@@ -12,13 +12,6 @@ query ListMovies @auth(level: PUBLIC) {
   }
 }
 
-query searchMovieDescriptionUsingL2Similarity1($compare: Vector!, $within: Float, $excludesContent: String, $limit: Int) @auth(level: PUBLIC) {
-    movies_descriptionEmbedding_similarity(compare: $compare, method: L2, within: $within, where: {description: {ne: $excludesContent}}, limit: $limit) {
-      id
-      title
-	description
-    }
-  }
 
 # List subset of fields for users
 query ListUsers @auth(level: PUBLIC) {
@@ -572,3 +565,12 @@ query searchMovieDescriptionUsingL2Similarity($query: String!)
     imageUrl
   }
 }
+
+# Search movie descriptions using L2 similarity with Vertex AI, with custom embeddings
+query searchMovieDescriptionUsingL2Similarity1($compare: Vector!, $within: Float, $excludesContent: String, $limit: Int) @auth(level: PUBLIC) {
+    movies_descriptionEmbedding_similarity(compare: $compare, method: L2, within: $within, where: {description: {ne: $excludesContent}}, limit: $limit) {
+      id
+      title
+	description
+    }
+  }

From 0cc97fb61f09fd1d8faecf4ac3688d8d4961192c Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 3 Jun 2024 12:39:05 -0400
Subject: [PATCH 12/82] fix: gitignore

---
 dataconnect/.gitignore              |    3 +-
 dataconnect/movie/package-lock.json | 2653 ---------------------------
 2 files changed, 2 insertions(+), 2654 deletions(-)
 delete mode 100644 dataconnect/movie/package-lock.json

diff --git a/dataconnect/.gitignore b/dataconnect/.gitignore
index 0663a14c0..a431356d1 100644
--- a/dataconnect/.gitignore
+++ b/dataconnect/.gitignore
@@ -66,4 +66,5 @@ node_modules/
 .env
 .next
 .dataconnect
-movie/lib/dataconnect-sdk
\ No newline at end of file
+movie/lib/dataconnect-sdk
+movie/package-lock.json
diff --git a/dataconnect/movie/package-lock.json b/dataconnect/movie/package-lock.json
deleted file mode 100644
index 2cd40f33e..000000000
--- a/dataconnect/movie/package-lock.json
+++ /dev/null
@@ -1,2653 +0,0 @@
-{
-  "name": "movie",
-  "version": "0.1.0",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "version": "0.1.0",
-      "dependencies": {
-        "autoprefixer": "^10.4.19",
-        "firebase": "10.12.0-dataconnect-preview.388b61c7e",
-        "next": "latest",
-        "postcss": "^8.4.38",
-        "react": "^18.3.1",
-        "react-dom": "^18.3.1",
-        "react-icons": "^5.2.1",
-        "tailwindcss": "^3.4.3"
-      },
-      "devDependencies": {
-        "@types/node": "^20.10.8",
-        "@types/react": "^18.2.47",
-        "@types/react-dom": "18.2.18",
-        "typescript": "^5.3.3"
-      }
-    },
-    "node_modules/@alloc/quick-lru": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
-      "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/@fastify/busboy": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
-      "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
-      "engines": {
-        "node": ">=14"
-      }
-    },
-    "node_modules/@firebase/analytics": {
-      "version": "0.10.3-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.3-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-Zk2hYq6vaEX+cmfrBsybz1yXh9ebmNBLxWLW1YF8PUZtlVTAUQDdcbnEYEdCF+UcMpQjdEGS+sGej6ItGy69NQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/analytics-compat": {
-      "version": "0.2.9-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.9-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-OlLd+nVMNFQuY7LRq5bLnYG2dlZ3/Ma17U14klxE7WGRU5q1dtx/+Tjw53CK2zAciPB31E+xtpHp2vb1O2UIfw==",
-      "dependencies": {
-        "@firebase/analytics": "0.10.3-dataconnect-preview.388b61c7e",
-        "@firebase/analytics-types": "0.8.2-dataconnect-preview.388b61c7e",
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/analytics-types": {
-      "version": "0.8.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-JZ1t1yVI57lWpscEA8vd9uZUa82wOlMsjxysvosCH69wbtY7wAu7lM2puB3RytdjVx3aYYiQURkCOFbsQGE9Ow=="
-    },
-    "node_modules/@firebase/app": {
-      "version": "0.10.3-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.3-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-tm0Ll26kc40pVegaJKzS0x4lkkudylQH9u9E3B3UkDFqPPTlUaSoI54YQENb6JKSCqbNQCAb2Zw2PxMjvPgABw==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "idb": "7.1.1",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/app-check": {
-      "version": "0.8.4-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.4-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-pdQrKwfsViQiZCWGEoFor9YSL9dAI6nxbaZSSp4FCy9GI/iGwzSM5EFTA76pPJTU8FmhrdGG+RmQLc46CPHiIw==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/app-check-compat": {
-      "version": "0.3.11-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.11-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-PdMU60HYFriKMPlof17tvrLoXYMWkdPq4oj6PuuOlEZ4wJh/+3Se7RFhtoGb+54gt2PdVvV+yCUV1rHlg7Snbw==",
-      "dependencies": {
-        "@firebase/app-check": "0.8.4-dataconnect-preview.388b61c7e",
-        "@firebase/app-check-types": "0.5.2-dataconnect-preview.388b61c7e",
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/app-check-interop-types": {
-      "version": "0.3.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-UOefiHjjBpetkD9WMC3dIXISyJxgOQtx5jQ5TPKOZCJvYUpGSA04qIIIFkvxd/eIIMtx9hiPtucyQJtNkbs5TA=="
-    },
-    "node_modules/@firebase/app-check-types": {
-      "version": "0.5.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-/XSOutZYx6DrmIrNP3sFiFcdOqu9Z+3LcR4aI5jrDwR/fh73eph/bBMi9rmw17vkg/BFdUbfOyC0p1mfR1EaXA=="
-    },
-    "node_modules/@firebase/app-compat": {
-      "version": "0.2.33-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.33-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-vjRVOKJWOCssAF6p/uKJhDv+iHDElNVAUk7MUHEl03y73NpoClS+F7t8k0FZ1xi1tauyiX9z2oeliBoeUv65kA==",
-      "dependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/app-types": {
-      "version": "0.9.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-NlvumIXiw89crl4qb0mHt1fTU6AEvzCUZyLnrw/DElp0UNQXPDBhxnwxqFvk9/7QK5aROuznSPAA4D7N2juFPQ=="
-    },
-    "node_modules/@firebase/auth-compat": {
-      "version": "0.5.8-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.8-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-7RgwekPUnFKAmiOlFZThc3xZcruIdR2Qy4p7Yu5znDW1xSk74Re5ijV521i3ArX+m4Sz9othHgiCZmgRV8eY+Q==",
-      "dependencies": {
-        "@firebase/auth": "1.7.3-dataconnect-preview.388b61c7e",
-        "@firebase/auth-types": "0.12.2-dataconnect-preview.388b61c7e",
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/auth-compat/node_modules/@firebase/auth": {
-      "version": "1.7.3-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.3-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-5EkGSQKk8jOml0SS3aZibeTweCrnc2mB5HyHbqOg98zHW9jMKfy9fZ2zL4qG7QOCVRT3SF0pBiDF2L6UETJnoA==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
-        "@react-native-async-storage/async-storage": "^1.18.1"
-      },
-      "peerDependenciesMeta": {
-        "@react-native-async-storage/async-storage": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@firebase/auth-interop-types": {
-      "version": "0.2.3-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-Vao5kFj48qi7K76LEZLwCimtfppdTfCHw54EfLvxOZNCgYpScx1x9oq91xn2vWqNTCP1eGWeMYPACqgLPlM57Q=="
-    },
-    "node_modules/@firebase/auth-types": {
-      "version": "0.12.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-ONN/dDQpnKUvdKiT1aT2AofnLyEyxMHDzAHSL/eJefDlWfNL/UicJXKtHCqFDLC0k9U9apQZdqzoepI+Wicrjw==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/component": {
-      "version": "0.6.7-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.7-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-2AXGmpE1D+4lR9akCw1TE5bwhlNirS26toZDQVlvYGbFypt5SnZzgKus9JLHKyaMMYIcoPrReqFF247DYwaJAg==",
-      "dependencies": {
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/data-connect": {
-      "version": "0.0.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.0.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-pPQElS3ceqxmekGWZOtzrEcuwbZTPV0JvPQPc7yHPWkAqAC6qftd6t3TYEy3GsDvYCaBmKC1KSM/YPPrQvj/Gg==",
-      "dependencies": {
-        "@firebase/auth-interop-types": "0.2.3-dataconnect-preview.388b61c7e",
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/database": {
-      "version": "1.0.5-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.5-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-nQXgc47g3bbB1/KYcrlfwoRzPsdSFiwenQPBRrhi9WAL/VUyNgwCtA2tWqfythvKrfAwoVEzm55aQ0uV/PxrGw==",
-      "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.2-dataconnect-preview.388b61c7e",
-        "@firebase/auth-interop-types": "0.2.3-dataconnect-preview.388b61c7e",
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "faye-websocket": "0.11.4",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/database-compat": {
-      "version": "1.0.5-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.5-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-6x4YBdlEcbRjc3VMG6RqmLfYW/wBW21wqaKuec1TKDuQjT7czFeyXtxPCX64qbSDC4yc1v9+ru4m3NnQ8kVTrw==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/database": "1.0.5-dataconnect-preview.388b61c7e",
-        "@firebase/database-types": "1.0.3-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/database-types": {
-      "version": "1.0.3-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.3-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-JrYV6qJa77fu94LJbw4oOE22a3qVJ9Zl8mPNHxG1/yXcqDAj4STnDiccEvnGEKTspgVfksPnqD7IkaroN4bzLg==",
-      "dependencies": {
-        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/firestore": {
-      "version": "4.6.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.6.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-s0ZFLG+XaZUHYeIEBp1SnqyMz33lwOL17QDDlleFnMhRswgqyWwiMZD55juVaVrn3bTnGPpKSZB1t7RurtzgfA==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "@firebase/webchannel-wrapper": "1.0.0-dataconnect-preview.388b61c7e",
-        "@grpc/grpc-js": "~1.9.0",
-        "@grpc/proto-loader": "^0.7.8",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
-      },
-      "engines": {
-        "node": ">=10.10.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/firestore-compat": {
-      "version": "0.3.31-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.31-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-Et2OO+JevBmkkfKWVm4uZnHT7OgjfT1EBK31yFbHd8/y8NoD6M6XveM16IoBTGYnhqHVVjJQ3WFI1FfyQKVIgg==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/firestore": "4.6.2-dataconnect-preview.388b61c7e",
-        "@firebase/firestore-types": "3.0.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/firestore-types": {
-      "version": "3.0.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-z+x9vINP8Jcu0ePpWZgj5S2H4glsOsD914P9OaNRUAovacdrr1rmo5tHdNdrbQ2cIma9TPCTfDeXTDm/UhOiAw==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/functions": {
-      "version": "0.11.5-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.5-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-8MsDg9At4oO7AJqtx9iyIuJpTDEmZOTavOMw1bCQQ/wrsITDs0oCaOQmdiGRgbAQ9xJgdbZFqlKJfYRFE8lA2w==",
-      "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.2-dataconnect-preview.388b61c7e",
-        "@firebase/auth-interop-types": "0.2.3-dataconnect-preview.388b61c7e",
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/messaging-interop-types": "0.2.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/functions-compat": {
-      "version": "0.3.11-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.11-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-Puty2X6HwdCwTL+jD8EzHLRUoYfcUtkVIwghLrz1ewwe9kYnwYvhbeAGibsXFYhuaxaYOD5OqDFS2lsK3gfFKg==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/functions": "0.11.5-dataconnect-preview.388b61c7e",
-        "@firebase/functions-types": "0.6.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/functions-types": {
-      "version": "0.6.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-poR5xISP3LGau7KvPWVseT97I8XG+y0nkrtkgzzgBytpbe94jLdagFrzG03Nm2YInj841arE1Jdprz24FJ67bQ=="
-    },
-    "node_modules/@firebase/installations": {
-      "version": "0.6.7-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.7-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-vlYBEvQeQjF2Z+hceZJQsvGyjHlEsU7Ibvzyjr2wVvvdxV3nkjPtyr0Ccy5EeegFNoxaKLFyFkol5tP4WfN9mw==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "idb": "7.1.1",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/installations-compat": {
-      "version": "0.2.7-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.7-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-HYwIO1BiSW7yfUxvXWWXIcv3lFPqMa/bPH9aO/0bUfeCVfa5Ww1cIs8QjWQYKNqW96zBxr3RnpiWI12jxSUJyw==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/installations-types": "0.5.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/installations-types": {
-      "version": "0.5.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-JkYzoUi28NbOlw7KzjoUhJueYbD4od+TAw5kiyFoK0DAG7FUkX0uca3MOrWuhNsvM4XKVW/Np4rvA1AKrmzR/g==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/logger": {
-      "version": "0.4.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-nvZLqLFCbXW6r1kzXTeTGmzMCx+1tzq0sL4niwYaws3V/Xl6mDkNcEGMoOX6OuwTq8NlP1sjE9ER4qnbV3Olqw==",
-      "dependencies": {
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/messaging": {
-      "version": "0.12.9-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.9-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-E5dKGhwtwPIeglDUAhJMLTQicV2tQnuU3t7r/Oc51WI05HgzM7WVu78DqPjCIp7GGDHy5R2qU4BiCzYaMSAJRg==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/messaging-interop-types": "0.2.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "idb": "7.1.1",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/messaging-compat": {
-      "version": "0.2.9-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.9-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-taSKYJ3b/8DByQGDYx3NbtgLmo06wKFRM7d8bT1o3N4A0Cd5Y51DKU2uR/Xf/QMNECKsH7Jv18d1VrU3aOOOng==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/messaging": "0.12.9-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/messaging-interop-types": {
-      "version": "0.2.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-NKCrCBovd63kK40vTSfMrThtyzTCfQjj82+4MaX8OMn/gFGm4RCU8UqO4PnxbR/viYAlxXitbeFR/aKeixdDBA=="
-    },
-    "node_modules/@firebase/performance": {
-      "version": "0.6.7-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.7-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-AltYdWIO0Rlz0Nu10IyzlCi2XPztP4kDArsYcPX25fv6DOGSAI7fnLN+9dejDSbrhxttL4FCK9/WqywDdEretg==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/performance-compat": {
-      "version": "0.2.7-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.7-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-6h+T3S0EBSWy+69OUTGeCDqFpOzla1hID5HlKtC5eTNhbWygHuC/s0zrLXInwR6o5xMayxhvf0HNIRoUy6FZkA==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/performance": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/performance-types": "0.2.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/performance-types": {
-      "version": "0.2.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-/rWGG41TwiYkaI3E6pD5vb4uWKoPxuyP259QCHnt2lB4s/gPAtU8VRVoEgx1do4CB+8AvrV5Aec6KL2C2YQlYg=="
-    },
-    "node_modules/@firebase/remote-config": {
-      "version": "0.4.7-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.7-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-PLHu0C/qTf0C2Z2ss65Mt0AkPY5MfwWzV2fHHhsj5AEJHpJsSS9elKAk/6J2W0plJnmlJkcvihsMkMTVl8vzzQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/remote-config-compat": {
-      "version": "0.2.7-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.7-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-Q0dKJyidqdERRlyuomQAhrw0KNu6lNSM/jc29HDjlQJhCFdin3XrcDSYYxBgpkWNKD2nQ/4XNMslkGP7fzu5+Q==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/remote-config": "0.4.7-dataconnect-preview.388b61c7e",
-        "@firebase/remote-config-types": "0.3.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/remote-config-types": {
-      "version": "0.3.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-B8twcsCV1auMHoVg5ICSzCrc8RUz4WVPOaQBiR/veeS0+PmBRiTHoyZzZh33vED1FHPzz3Cf7uwMfhk0gNhuYw=="
-    },
-    "node_modules/@firebase/storage": {
-      "version": "0.12.5-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.5-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-YFDMpLf1piDU28/d8DAWRfCU62UTas9IDsvTnzfc/P3MNJJSnHcUrECe97O09EatfbZW3z5Wh0iM7uZTO0ts3Q==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/storage-compat": {
-      "version": "0.3.8-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.8-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-sQF/Hd/0oWsR3fimD6LXXtvwcwc8dpc6SQfmfR46ISCGKeAml2Wla1w1rWA8TyHce5eYRQAgczxk6f9JdBwcNQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/storage": "0.12.5-dataconnect-preview.388b61c7e",
-        "@firebase/storage-types": "0.8.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/storage-types": {
-      "version": "0.8.2-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.2-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-w5Tjd4rBFV6ZZ/fXacl+h9/CKaCWVlTJae96Z0+pcB6BtTQY+B8E1I62O+4UCzs4yauF8PpuWLxkULBO9Zjtkg==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/util": {
-      "version": "1.9.6-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.6-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-oBd5uhs6sixiauvFo4RJ5+X4diK6AdrEBdOPYdeoV4HhF6aV4tuxcfJrb1O+d+9I2xMjpA5b+ySIxJ32Dknk2w==",
-      "dependencies": {
-        "tslib": "^2.1.0"
-      }
-    },
-    "node_modules/@firebase/vertexai-preview": {
-      "version": "0.0.1-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/vertexai-preview/-/vertexai-preview-0.0.1-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-qy0MVJztKV9Fr7BXjOHwyxa/51D4vpj5h2nsEUUjYA+wQQqz2HTejnHNjitswFSnDGWErCwWwIZau1d+NEeK8g==",
-      "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.2-dataconnect-preview.388b61c7e",
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
-        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/@firebase/webchannel-wrapper": {
-      "version": "1.0.0-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.0-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-Bfz5tSuiwYE9Y/tPt7haiZEnexNXZX8zQINi0ZlnecepwZcLy03dyF/SKlhAv0mAXzGZBXfn3eqBccgcssCS5Q=="
-    },
-    "node_modules/@grpc/grpc-js": {
-      "version": "1.9.14",
-      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz",
-      "integrity": "sha512-nOpuzZ2G3IuMFN+UPPpKrC6NsLmWsTqSsm66IRfnBt1D4pwTqE27lmbpcPM+l2Ua4gE7PfjRHI6uedAy7hoXUw==",
-      "dependencies": {
-        "@grpc/proto-loader": "^0.7.8",
-        "@types/node": ">=12.12.47"
-      },
-      "engines": {
-        "node": "^8.13.0 || >=10.10.0"
-      }
-    },
-    "node_modules/@grpc/proto-loader": {
-      "version": "0.7.13",
-      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz",
-      "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==",
-      "dependencies": {
-        "lodash.camelcase": "^4.3.0",
-        "long": "^5.0.0",
-        "protobufjs": "^7.2.5",
-        "yargs": "^17.7.2"
-      },
-      "bin": {
-        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/@isaacs/cliui": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
-      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
-      "dependencies": {
-        "string-width": "^5.1.2",
-        "string-width-cjs": "npm:string-width@^4.2.0",
-        "strip-ansi": "^7.0.1",
-        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
-        "wrap-ansi": "^8.1.0",
-        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
-      },
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
-      }
-    },
-    "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
-      "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-      }
-    },
-    "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
-      "version": "9.2.2",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
-      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
-    },
-    "node_modules/@isaacs/cliui/node_modules/string-width": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
-      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
-      "dependencies": {
-        "eastasianwidth": "^0.2.0",
-        "emoji-regex": "^9.2.2",
-        "strip-ansi": "^7.0.1"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
-      "dependencies": {
-        "ansi-regex": "^6.0.1"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
-      }
-    },
-    "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
-      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
-      "dependencies": {
-        "ansi-styles": "^6.1.0",
-        "string-width": "^5.0.1",
-        "strip-ansi": "^7.0.1"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-      }
-    },
-    "node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
-      "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
-      "dependencies": {
-        "@jridgewell/set-array": "^1.2.1",
-        "@jridgewell/sourcemap-codec": "^1.4.10",
-        "@jridgewell/trace-mapping": "^0.3.24"
-      },
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
-      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@jridgewell/set-array": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
-      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.4.15",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
-      "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
-    },
-    "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.25",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
-      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
-      "dependencies": {
-        "@jridgewell/resolve-uri": "^3.1.0",
-        "@jridgewell/sourcemap-codec": "^1.4.14"
-      }
-    },
-    "node_modules/@next/env": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz",
-      "integrity": "sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA=="
-    },
-    "node_modules/@next/swc-darwin-arm64": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.3.tgz",
-      "integrity": "sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-darwin-x64": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.3.tgz",
-      "integrity": "sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-arm64-gnu": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.3.tgz",
-      "integrity": "sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-arm64-musl": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.3.tgz",
-      "integrity": "sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-x64-gnu": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz",
-      "integrity": "sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-x64-musl": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz",
-      "integrity": "sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-win32-arm64-msvc": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz",
-      "integrity": "sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-win32-ia32-msvc": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz",
-      "integrity": "sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==",
-      "cpu": [
-        "ia32"
-      ],
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-win32-x64-msvc": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz",
-      "integrity": "sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@nodelib/fs.scandir": {
-      "version": "2.1.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
-      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
-      "dependencies": {
-        "@nodelib/fs.stat": "2.0.5",
-        "run-parallel": "^1.1.9"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/@nodelib/fs.stat": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
-      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/@nodelib/fs.walk": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
-      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
-      "dependencies": {
-        "@nodelib/fs.scandir": "2.1.5",
-        "fastq": "^1.6.0"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/@pkgjs/parseargs": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
-      "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
-      "optional": true,
-      "engines": {
-        "node": ">=14"
-      }
-    },
-    "node_modules/@protobufjs/aspromise": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
-      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
-    },
-    "node_modules/@protobufjs/base64": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
-      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
-    },
-    "node_modules/@protobufjs/codegen": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
-      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
-    },
-    "node_modules/@protobufjs/eventemitter": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
-      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
-    },
-    "node_modules/@protobufjs/fetch": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
-      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
-      "dependencies": {
-        "@protobufjs/aspromise": "^1.1.1",
-        "@protobufjs/inquire": "^1.1.0"
-      }
-    },
-    "node_modules/@protobufjs/float": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
-      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
-    },
-    "node_modules/@protobufjs/inquire": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
-      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
-    },
-    "node_modules/@protobufjs/path": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
-      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
-    },
-    "node_modules/@protobufjs/pool": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
-      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
-    },
-    "node_modules/@protobufjs/utf8": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
-      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
-    },
-    "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.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"
-      }
-    },
-    "node_modules/@types/node": {
-      "version": "20.10.8",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz",
-      "integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==",
-      "dependencies": {
-        "undici-types": "~5.26.4"
-      }
-    },
-    "node_modules/@types/prop-types": {
-      "version": "15.7.12",
-      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
-      "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
-      "dev": true
-    },
-    "node_modules/@types/react": {
-      "version": "18.2.47",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.47.tgz",
-      "integrity": "sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==",
-      "dev": true,
-      "dependencies": {
-        "@types/prop-types": "*",
-        "@types/scheduler": "*",
-        "csstype": "^3.0.2"
-      }
-    },
-    "node_modules/@types/react-dom": {
-      "version": "18.2.18",
-      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz",
-      "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==",
-      "dev": true,
-      "dependencies": {
-        "@types/react": "*"
-      }
-    },
-    "node_modules/@types/scheduler": {
-      "version": "0.23.0",
-      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz",
-      "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==",
-      "dev": true
-    },
-    "node_modules/ansi-regex": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/ansi-styles": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-      "dependencies": {
-        "color-convert": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-      }
-    },
-    "node_modules/any-promise": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
-      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
-    },
-    "node_modules/anymatch": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
-      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
-      "dependencies": {
-        "normalize-path": "^3.0.0",
-        "picomatch": "^2.0.4"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/arg": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
-      "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
-    },
-    "node_modules/autoprefixer": {
-      "version": "10.4.19",
-      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
-      "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/autoprefixer"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "dependencies": {
-        "browserslist": "^4.23.0",
-        "caniuse-lite": "^1.0.30001599",
-        "fraction.js": "^4.3.7",
-        "normalize-range": "^0.1.2",
-        "picocolors": "^1.0.0",
-        "postcss-value-parser": "^4.2.0"
-      },
-      "bin": {
-        "autoprefixer": "bin/autoprefixer"
-      },
-      "engines": {
-        "node": "^10 || ^12 || >=14"
-      },
-      "peerDependencies": {
-        "postcss": "^8.1.0"
-      }
-    },
-    "node_modules/balanced-match": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
-    },
-    "node_modules/binary-extensions": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
-      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/brace-expansion": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
-      "dependencies": {
-        "balanced-match": "^1.0.0"
-      }
-    },
-    "node_modules/braces": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
-      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
-      "dependencies": {
-        "fill-range": "^7.1.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/browserslist": {
-      "version": "4.23.0",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
-      "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/browserslist"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/browserslist"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "dependencies": {
-        "caniuse-lite": "^1.0.30001587",
-        "electron-to-chromium": "^1.4.668",
-        "node-releases": "^2.0.14",
-        "update-browserslist-db": "^1.0.13"
-      },
-      "bin": {
-        "browserslist": "cli.js"
-      },
-      "engines": {
-        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
-      }
-    },
-    "node_modules/busboy": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
-      "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
-      "dependencies": {
-        "streamsearch": "^1.1.0"
-      },
-      "engines": {
-        "node": ">=10.16.0"
-      }
-    },
-    "node_modules/camelcase-css": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
-      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/caniuse-lite": {
-      "version": "1.0.30001625",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz",
-      "integrity": "sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/browserslist"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ]
-    },
-    "node_modules/chokidar": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
-      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
-      "dependencies": {
-        "anymatch": "~3.1.2",
-        "braces": "~3.0.2",
-        "glob-parent": "~5.1.2",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.6.0"
-      },
-      "engines": {
-        "node": ">= 8.10.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      }
-    },
-    "node_modules/chokidar/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==",
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/client-only": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
-      "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
-    },
-    "node_modules/cliui": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
-      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
-      "dependencies": {
-        "string-width": "^4.2.0",
-        "strip-ansi": "^6.0.1",
-        "wrap-ansi": "^7.0.0"
-      },
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/color-convert": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "dependencies": {
-        "color-name": "~1.1.4"
-      },
-      "engines": {
-        "node": ">=7.0.0"
-      }
-    },
-    "node_modules/color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
-    },
-    "node_modules/commander": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
-      "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/cross-spawn": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
-      "dependencies": {
-        "path-key": "^3.1.0",
-        "shebang-command": "^2.0.0",
-        "which": "^2.0.1"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/cssesc": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
-      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
-      "bin": {
-        "cssesc": "bin/cssesc"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/csstype": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
-      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
-      "dev": true
-    },
-    "node_modules/didyoumean": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
-      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
-    },
-    "node_modules/dlv": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
-      "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
-    },
-    "node_modules/eastasianwidth": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
-      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
-    },
-    "node_modules/electron-to-chromium": {
-      "version": "1.4.784",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.784.tgz",
-      "integrity": "sha512-9CZwh+sDrhDAeOEFh8s3PqwduzTyYIeYwZolc1b9ENAUt3ePu7R1sJSCWr/820ISssRxCJUyHI9Wb7j+0Uo1AA=="
-    },
-    "node_modules/emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
-    },
-    "node_modules/escalade": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
-      "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/fast-glob": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
-      "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
-      "dependencies": {
-        "@nodelib/fs.stat": "^2.0.2",
-        "@nodelib/fs.walk": "^1.2.3",
-        "glob-parent": "^5.1.2",
-        "merge2": "^1.3.0",
-        "micromatch": "^4.0.4"
-      },
-      "engines": {
-        "node": ">=8.6.0"
-      }
-    },
-    "node_modules/fast-glob/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==",
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/fastq": {
-      "version": "1.17.1",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
-      "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
-      "dependencies": {
-        "reusify": "^1.0.4"
-      }
-    },
-    "node_modules/faye-websocket": {
-      "version": "0.11.4",
-      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
-      "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
-      "dependencies": {
-        "websocket-driver": ">=0.5.1"
-      },
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/fill-range": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
-      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
-      "dependencies": {
-        "to-regex-range": "^5.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/firebase": {
-      "version": "10.12.0-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.12.0-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-QoqKj8DnHlIHLqSdEu+hwR69n/HWYLIRcOtCNrv1h2BXcl0V91CNtFYqX5LHk4zJ6eZ+hSOfDnxKya6gAEGZ6w==",
-      "dependencies": {
-        "@firebase/analytics": "0.10.3-dataconnect-preview.388b61c7e",
-        "@firebase/analytics-compat": "0.2.9-dataconnect-preview.388b61c7e",
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
-        "@firebase/app-check": "0.8.4-dataconnect-preview.388b61c7e",
-        "@firebase/app-check-compat": "0.3.11-dataconnect-preview.388b61c7e",
-        "@firebase/app-compat": "0.2.33-dataconnect-preview.388b61c7e",
-        "@firebase/app-types": "0.9.2-dataconnect-preview.388b61c7e",
-        "@firebase/auth": "1.7.3-dataconnect-preview.388b61c7e",
-        "@firebase/auth-compat": "0.5.8-dataconnect-preview.388b61c7e",
-        "@firebase/data-connect": "0.0.2-dataconnect-preview.388b61c7e",
-        "@firebase/database": "1.0.5-dataconnect-preview.388b61c7e",
-        "@firebase/database-compat": "1.0.5-dataconnect-preview.388b61c7e",
-        "@firebase/firestore": "4.6.2-dataconnect-preview.388b61c7e",
-        "@firebase/firestore-compat": "0.3.31-dataconnect-preview.388b61c7e",
-        "@firebase/functions": "0.11.5-dataconnect-preview.388b61c7e",
-        "@firebase/functions-compat": "0.3.11-dataconnect-preview.388b61c7e",
-        "@firebase/installations": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/installations-compat": "0.2.7-dataconnect-preview.388b61c7e",
-        "@firebase/messaging": "0.12.9-dataconnect-preview.388b61c7e",
-        "@firebase/messaging-compat": "0.2.9-dataconnect-preview.388b61c7e",
-        "@firebase/performance": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/performance-compat": "0.2.7-dataconnect-preview.388b61c7e",
-        "@firebase/remote-config": "0.4.7-dataconnect-preview.388b61c7e",
-        "@firebase/remote-config-compat": "0.2.7-dataconnect-preview.388b61c7e",
-        "@firebase/storage": "0.12.5-dataconnect-preview.388b61c7e",
-        "@firebase/storage-compat": "0.3.8-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "@firebase/vertexai-preview": "0.0.1-dataconnect-preview.388b61c7e"
-      }
-    },
-    "node_modules/firebase/node_modules/@firebase/auth": {
-      "version": "1.7.3-dataconnect-preview.388b61c7e",
-      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.3-dataconnect-preview.388b61c7e.tgz",
-      "integrity": "sha512-5EkGSQKk8jOml0SS3aZibeTweCrnc2mB5HyHbqOg98zHW9jMKfy9fZ2zL4qG7QOCVRT3SF0pBiDF2L6UETJnoA==",
-      "dependencies": {
-        "@firebase/component": "0.6.7-dataconnect-preview.388b61c7e",
-        "@firebase/logger": "0.4.2-dataconnect-preview.388b61c7e",
-        "@firebase/util": "1.9.6-dataconnect-preview.388b61c7e",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.10.3-dataconnect-preview.388b61c7e",
-        "@react-native-async-storage/async-storage": "^1.18.1"
-      },
-      "peerDependenciesMeta": {
-        "@react-native-async-storage/async-storage": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/foreground-child": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
-      "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
-      "dependencies": {
-        "cross-spawn": "^7.0.0",
-        "signal-exit": "^4.0.1"
-      },
-      "engines": {
-        "node": ">=14"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/fraction.js": {
-      "version": "4.3.7",
-      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
-      "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
-      "engines": {
-        "node": "*"
-      },
-      "funding": {
-        "type": "patreon",
-        "url": "https://github.com/sponsors/rawify"
-      }
-    },
-    "node_modules/fsevents": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
-      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
-      "hasInstallScript": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-      }
-    },
-    "node_modules/function-bind": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
-      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/get-caller-file": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-      "engines": {
-        "node": "6.* || 8.* || >= 10.*"
-      }
-    },
-    "node_modules/glob": {
-      "version": "10.4.1",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz",
-      "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==",
-      "dependencies": {
-        "foreground-child": "^3.1.0",
-        "jackspeak": "^3.1.2",
-        "minimatch": "^9.0.4",
-        "minipass": "^7.1.2",
-        "path-scurry": "^1.11.1"
-      },
-      "bin": {
-        "glob": "dist/esm/bin.mjs"
-      },
-      "engines": {
-        "node": ">=16 || 14 >=14.18"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/glob-parent": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
-      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
-      "dependencies": {
-        "is-glob": "^4.0.3"
-      },
-      "engines": {
-        "node": ">=10.13.0"
-      }
-    },
-    "node_modules/graceful-fs": {
-      "version": "4.2.11",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
-      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
-    },
-    "node_modules/hasown": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
-      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
-      "dependencies": {
-        "function-bind": "^1.1.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/http-parser-js": {
-      "version": "0.5.8",
-      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
-      "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q=="
-    },
-    "node_modules/idb": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
-      "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="
-    },
-    "node_modules/is-binary-path": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-      "dependencies": {
-        "binary-extensions": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/is-core-module": {
-      "version": "2.13.1",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
-      "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
-      "dependencies": {
-        "hasown": "^2.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-extglob": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/is-fullwidth-code-point": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/is-glob": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
-      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-      "dependencies": {
-        "is-extglob": "^2.1.1"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/is-number": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-      "engines": {
-        "node": ">=0.12.0"
-      }
-    },
-    "node_modules/isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
-    },
-    "node_modules/jackspeak": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz",
-      "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==",
-      "dependencies": {
-        "@isaacs/cliui": "^8.0.2"
-      },
-      "engines": {
-        "node": ">=14"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      },
-      "optionalDependencies": {
-        "@pkgjs/parseargs": "^0.11.0"
-      }
-    },
-    "node_modules/jiti": {
-      "version": "1.21.0",
-      "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
-      "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
-      "bin": {
-        "jiti": "bin/jiti.js"
-      }
-    },
-    "node_modules/js-tokens": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
-    },
-    "node_modules/lilconfig": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
-      "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/lines-and-columns": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
-      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
-    },
-    "node_modules/lodash.camelcase": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
-      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
-    },
-    "node_modules/long": {
-      "version": "5.2.3",
-      "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
-      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
-    },
-    "node_modules/loose-envify": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
-      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
-      "dependencies": {
-        "js-tokens": "^3.0.0 || ^4.0.0"
-      },
-      "bin": {
-        "loose-envify": "cli.js"
-      }
-    },
-    "node_modules/lru-cache": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
-      "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
-      "engines": {
-        "node": "14 || >=16.14"
-      }
-    },
-    "node_modules/merge2": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
-      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/micromatch": {
-      "version": "4.0.7",
-      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
-      "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
-      "dependencies": {
-        "braces": "^3.0.3",
-        "picomatch": "^2.3.1"
-      },
-      "engines": {
-        "node": ">=8.6"
-      }
-    },
-    "node_modules/minimatch": {
-      "version": "9.0.4",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
-      "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
-      "dependencies": {
-        "brace-expansion": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=16 || 14 >=14.17"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/minipass": {
-      "version": "7.1.2",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
-      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
-      "engines": {
-        "node": ">=16 || 14 >=14.17"
-      }
-    },
-    "node_modules/mz": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
-      "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
-      "dependencies": {
-        "any-promise": "^1.0.0",
-        "object-assign": "^4.0.1",
-        "thenify-all": "^1.0.0"
-      }
-    },
-    "node_modules/nanoid": {
-      "version": "3.3.7",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
-      "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "bin": {
-        "nanoid": "bin/nanoid.cjs"
-      },
-      "engines": {
-        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
-      }
-    },
-    "node_modules/next": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/next/-/next-14.2.3.tgz",
-      "integrity": "sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A==",
-      "dependencies": {
-        "@next/env": "14.2.3",
-        "@swc/helpers": "0.5.5",
-        "busboy": "1.6.0",
-        "caniuse-lite": "^1.0.30001579",
-        "graceful-fs": "^4.2.11",
-        "postcss": "8.4.31",
-        "styled-jsx": "5.1.1"
-      },
-      "bin": {
-        "next": "dist/bin/next"
-      },
-      "engines": {
-        "node": ">=18.17.0"
-      },
-      "optionalDependencies": {
-        "@next/swc-darwin-arm64": "14.2.3",
-        "@next/swc-darwin-x64": "14.2.3",
-        "@next/swc-linux-arm64-gnu": "14.2.3",
-        "@next/swc-linux-arm64-musl": "14.2.3",
-        "@next/swc-linux-x64-gnu": "14.2.3",
-        "@next/swc-linux-x64-musl": "14.2.3",
-        "@next/swc-win32-arm64-msvc": "14.2.3",
-        "@next/swc-win32-ia32-msvc": "14.2.3",
-        "@next/swc-win32-x64-msvc": "14.2.3"
-      },
-      "peerDependencies": {
-        "@opentelemetry/api": "^1.1.0",
-        "@playwright/test": "^1.41.2",
-        "react": "^18.2.0",
-        "react-dom": "^18.2.0",
-        "sass": "^1.3.0"
-      },
-      "peerDependenciesMeta": {
-        "@opentelemetry/api": {
-          "optional": true
-        },
-        "@playwright/test": {
-          "optional": true
-        },
-        "sass": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/next/node_modules/postcss": {
-      "version": "8.4.31",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
-      "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/postcss"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "dependencies": {
-        "nanoid": "^3.3.6",
-        "picocolors": "^1.0.0",
-        "source-map-js": "^1.0.2"
-      },
-      "engines": {
-        "node": "^10 || ^12 || >=14"
-      }
-    },
-    "node_modules/node-releases": {
-      "version": "2.0.14",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
-      "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw=="
-    },
-    "node_modules/normalize-path": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/normalize-range": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
-      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/object-hash": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
-      "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/path-key": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/path-parse": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
-    },
-    "node_modules/path-scurry": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
-      "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
-      "dependencies": {
-        "lru-cache": "^10.2.0",
-        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
-      },
-      "engines": {
-        "node": ">=16 || 14 >=14.18"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/picocolors": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
-      "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
-    },
-    "node_modules/picomatch": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-      "engines": {
-        "node": ">=8.6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/jonschlinkert"
-      }
-    },
-    "node_modules/pify": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-      "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/pirates": {
-      "version": "4.0.6",
-      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
-      "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/postcss": {
-      "version": "8.4.38",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
-      "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/postcss"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "dependencies": {
-        "nanoid": "^3.3.7",
-        "picocolors": "^1.0.0",
-        "source-map-js": "^1.2.0"
-      },
-      "engines": {
-        "node": "^10 || ^12 || >=14"
-      }
-    },
-    "node_modules/postcss-import": {
-      "version": "15.1.0",
-      "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
-      "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
-      "dependencies": {
-        "postcss-value-parser": "^4.0.0",
-        "read-cache": "^1.0.0",
-        "resolve": "^1.1.7"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      },
-      "peerDependencies": {
-        "postcss": "^8.0.0"
-      }
-    },
-    "node_modules/postcss-js": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
-      "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
-      "dependencies": {
-        "camelcase-css": "^2.0.1"
-      },
-      "engines": {
-        "node": "^12 || ^14 || >= 16"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/postcss/"
-      },
-      "peerDependencies": {
-        "postcss": "^8.4.21"
-      }
-    },
-    "node_modules/postcss-load-config": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
-      "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "dependencies": {
-        "lilconfig": "^3.0.0",
-        "yaml": "^2.3.4"
-      },
-      "engines": {
-        "node": ">= 14"
-      },
-      "peerDependencies": {
-        "postcss": ">=8.0.9",
-        "ts-node": ">=9.0.0"
-      },
-      "peerDependenciesMeta": {
-        "postcss": {
-          "optional": true
-        },
-        "ts-node": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/postcss-load-config/node_modules/lilconfig": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz",
-      "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==",
-      "engines": {
-        "node": ">=14"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/antonk52"
-      }
-    },
-    "node_modules/postcss-nested": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
-      "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
-      "dependencies": {
-        "postcss-selector-parser": "^6.0.11"
-      },
-      "engines": {
-        "node": ">=12.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/postcss/"
-      },
-      "peerDependencies": {
-        "postcss": "^8.2.14"
-      }
-    },
-    "node_modules/postcss-selector-parser": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz",
-      "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==",
-      "dependencies": {
-        "cssesc": "^3.0.0",
-        "util-deprecate": "^1.0.2"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/postcss-value-parser": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
-      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
-    },
-    "node_modules/protobufjs": {
-      "version": "7.3.0",
-      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.0.tgz",
-      "integrity": "sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g==",
-      "hasInstallScript": true,
-      "dependencies": {
-        "@protobufjs/aspromise": "^1.1.2",
-        "@protobufjs/base64": "^1.1.2",
-        "@protobufjs/codegen": "^2.0.4",
-        "@protobufjs/eventemitter": "^1.1.0",
-        "@protobufjs/fetch": "^1.1.0",
-        "@protobufjs/float": "^1.0.2",
-        "@protobufjs/inquire": "^1.1.0",
-        "@protobufjs/path": "^1.1.2",
-        "@protobufjs/pool": "^1.1.0",
-        "@protobufjs/utf8": "^1.1.0",
-        "@types/node": ">=13.7.0",
-        "long": "^5.0.0"
-      },
-      "engines": {
-        "node": ">=12.0.0"
-      }
-    },
-    "node_modules/queue-microtask": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
-      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ]
-    },
-    "node_modules/react": {
-      "version": "18.3.1",
-      "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
-      "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
-      "dependencies": {
-        "loose-envify": "^1.1.0"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/react-dom": {
-      "version": "18.3.1",
-      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
-      "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
-      "dependencies": {
-        "loose-envify": "^1.1.0",
-        "scheduler": "^0.23.2"
-      },
-      "peerDependencies": {
-        "react": "^18.3.1"
-      }
-    },
-    "node_modules/react-icons": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz",
-      "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==",
-      "peerDependencies": {
-        "react": "*"
-      }
-    },
-    "node_modules/read-cache": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
-      "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
-      "dependencies": {
-        "pify": "^2.3.0"
-      }
-    },
-    "node_modules/readdirp": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-      "dependencies": {
-        "picomatch": "^2.2.1"
-      },
-      "engines": {
-        "node": ">=8.10.0"
-      }
-    },
-    "node_modules/require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/resolve": {
-      "version": "1.22.8",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
-      "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
-      "dependencies": {
-        "is-core-module": "^2.13.0",
-        "path-parse": "^1.0.7",
-        "supports-preserve-symlinks-flag": "^1.0.0"
-      },
-      "bin": {
-        "resolve": "bin/resolve"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/reusify": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
-      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
-      "engines": {
-        "iojs": ">=1.0.0",
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/run-parallel": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
-      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "dependencies": {
-        "queue-microtask": "^1.2.2"
-      }
-    },
-    "node_modules/safe-buffer": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ]
-    },
-    "node_modules/scheduler": {
-      "version": "0.23.2",
-      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
-      "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
-      "dependencies": {
-        "loose-envify": "^1.1.0"
-      }
-    },
-    "node_modules/shebang-command": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-      "dependencies": {
-        "shebang-regex": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/shebang-regex": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/signal-exit": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
-      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
-      "engines": {
-        "node": ">=14"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/source-map-js": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
-      "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/streamsearch": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
-      "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
-      "engines": {
-        "node": ">=10.0.0"
-      }
-    },
-    "node_modules/string-width": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "dependencies": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/string-width-cjs": {
-      "name": "string-width",
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "dependencies": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/strip-ansi": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-      "dependencies": {
-        "ansi-regex": "^5.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/strip-ansi-cjs": {
-      "name": "strip-ansi",
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-      "dependencies": {
-        "ansi-regex": "^5.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/styled-jsx": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
-      "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
-      "dependencies": {
-        "client-only": "0.0.1"
-      },
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "peerDependencies": {
-        "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
-      },
-      "peerDependenciesMeta": {
-        "@babel/core": {
-          "optional": true
-        },
-        "babel-plugin-macros": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/sucrase": {
-      "version": "3.35.0",
-      "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
-      "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
-      "dependencies": {
-        "@jridgewell/gen-mapping": "^0.3.2",
-        "commander": "^4.0.0",
-        "glob": "^10.3.10",
-        "lines-and-columns": "^1.1.6",
-        "mz": "^2.7.0",
-        "pirates": "^4.0.1",
-        "ts-interface-checker": "^0.1.9"
-      },
-      "bin": {
-        "sucrase": "bin/sucrase",
-        "sucrase-node": "bin/sucrase-node"
-      },
-      "engines": {
-        "node": ">=16 || 14 >=14.17"
-      }
-    },
-    "node_modules/supports-preserve-symlinks-flag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
-      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/tailwindcss": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
-      "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
-      "dependencies": {
-        "@alloc/quick-lru": "^5.2.0",
-        "arg": "^5.0.2",
-        "chokidar": "^3.5.3",
-        "didyoumean": "^1.2.2",
-        "dlv": "^1.1.3",
-        "fast-glob": "^3.3.0",
-        "glob-parent": "^6.0.2",
-        "is-glob": "^4.0.3",
-        "jiti": "^1.21.0",
-        "lilconfig": "^2.1.0",
-        "micromatch": "^4.0.5",
-        "normalize-path": "^3.0.0",
-        "object-hash": "^3.0.0",
-        "picocolors": "^1.0.0",
-        "postcss": "^8.4.23",
-        "postcss-import": "^15.1.0",
-        "postcss-js": "^4.0.1",
-        "postcss-load-config": "^4.0.1",
-        "postcss-nested": "^6.0.1",
-        "postcss-selector-parser": "^6.0.11",
-        "resolve": "^1.22.2",
-        "sucrase": "^3.32.0"
-      },
-      "bin": {
-        "tailwind": "lib/cli.js",
-        "tailwindcss": "lib/cli.js"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/thenify": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
-      "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
-      "dependencies": {
-        "any-promise": "^1.0.0"
-      }
-    },
-    "node_modules/thenify-all": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
-      "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
-      "dependencies": {
-        "thenify": ">= 3.1.0 < 4"
-      },
-      "engines": {
-        "node": ">=0.8"
-      }
-    },
-    "node_modules/to-regex-range": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-      "dependencies": {
-        "is-number": "^7.0.0"
-      },
-      "engines": {
-        "node": ">=8.0"
-      }
-    },
-    "node_modules/ts-interface-checker": {
-      "version": "0.1.13",
-      "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
-      "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
-    },
-    "node_modules/tslib": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
-      "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
-    },
-    "node_modules/typescript": {
-      "version": "5.4.5",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
-      "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
-      "dev": true,
-      "bin": {
-        "tsc": "bin/tsc",
-        "tsserver": "bin/tsserver"
-      },
-      "engines": {
-        "node": ">=14.17"
-      }
-    },
-    "node_modules/undici": {
-      "version": "5.28.4",
-      "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
-      "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
-      "dependencies": {
-        "@fastify/busboy": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=14.0"
-      }
-    },
-    "node_modules/undici-types": {
-      "version": "5.26.5",
-      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
-      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
-    },
-    "node_modules/update-browserslist-db": {
-      "version": "1.0.16",
-      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
-      "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/browserslist"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/browserslist"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "dependencies": {
-        "escalade": "^3.1.2",
-        "picocolors": "^1.0.1"
-      },
-      "bin": {
-        "update-browserslist-db": "cli.js"
-      },
-      "peerDependencies": {
-        "browserslist": ">= 4.21.0"
-      }
-    },
-    "node_modules/util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
-    },
-    "node_modules/websocket-driver": {
-      "version": "0.7.4",
-      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
-      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
-      "dependencies": {
-        "http-parser-js": ">=0.5.1",
-        "safe-buffer": ">=5.1.0",
-        "websocket-extensions": ">=0.1.1"
-      },
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/websocket-extensions": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
-      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/which": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-      "dependencies": {
-        "isexe": "^2.0.0"
-      },
-      "bin": {
-        "node-which": "bin/node-which"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/wrap-ansi": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-      "dependencies": {
-        "ansi-styles": "^4.0.0",
-        "string-width": "^4.1.0",
-        "strip-ansi": "^6.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-      }
-    },
-    "node_modules/wrap-ansi-cjs": {
-      "name": "wrap-ansi",
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-      "dependencies": {
-        "ansi-styles": "^4.0.0",
-        "string-width": "^4.1.0",
-        "strip-ansi": "^6.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-      }
-    },
-    "node_modules/y18n": {
-      "version": "5.0.8",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
-      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/yaml": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
-      "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
-      "bin": {
-        "yaml": "bin.mjs"
-      },
-      "engines": {
-        "node": ">= 14"
-      }
-    },
-    "node_modules/yargs": {
-      "version": "17.7.2",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
-      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
-      "dependencies": {
-        "cliui": "^8.0.1",
-        "escalade": "^3.1.1",
-        "get-caller-file": "^2.0.5",
-        "require-directory": "^2.1.1",
-        "string-width": "^4.2.3",
-        "y18n": "^5.0.5",
-        "yargs-parser": "^21.1.1"
-      },
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/yargs-parser": {
-      "version": "21.1.1",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-      "engines": {
-        "node": ">=12"
-      }
-    }
-  }
-}

From d3ffc0fc55e2a3ec6ebc049c0eb3fca3df6686f5 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 3 Jun 2024 12:41:22 -0400
Subject: [PATCH 13/82] fix: lint

---
 dataconnect/movie/.env.local        | 2 +-
 dataconnect/movie/postcss.config.js | 2 +-
 dataconnect/movie/styles.css        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/dataconnect/movie/.env.local b/dataconnect/movie/.env.local
index d080f30d3..77171b344 100644
--- a/dataconnect/movie/.env.local
+++ b/dataconnect/movie/.env.local
@@ -3,4 +3,4 @@ NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-auth-domain
 NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
 NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-storage-bucket
 NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id
-NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
\ No newline at end of file
+NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
diff --git a/dataconnect/movie/postcss.config.js b/dataconnect/movie/postcss.config.js
index 33ad091d2..12a703d90 100644
--- a/dataconnect/movie/postcss.config.js
+++ b/dataconnect/movie/postcss.config.js
@@ -3,4 +3,4 @@ module.exports = {
     tailwindcss: {},
     autoprefixer: {},
   },
-}
+};
diff --git a/dataconnect/movie/styles.css b/dataconnect/movie/styles.css
index bd6213e1d..b5c61c956 100644
--- a/dataconnect/movie/styles.css
+++ b/dataconnect/movie/styles.css
@@ -1,3 +1,3 @@
 @tailwind base;
 @tailwind components;
-@tailwind utilities;
\ No newline at end of file
+@tailwind utilities;

From e840d97105992f4d7fce81ad3ee53150e45e78d3 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 3 Jun 2024 13:30:34 -0400
Subject: [PATCH 14/82] fix: update embedding version

---
 dataconnect/dataconnect/1_movie_insert.gql    | 40 +++++++-------
 .../4_user_favorites_review_insert.gql        | 54 +++++++++----------
 dataconnect/dataconnect/connector/queries.gql |  2 +-
 3 files changed, 48 insertions(+), 48 deletions(-)

diff --git a/dataconnect/dataconnect/1_movie_insert.gql b/dataconnect/dataconnect/1_movie_insert.gql
index 4078c2066..5f312db4e 100644
--- a/dataconnect/dataconnect/1_movie_insert.gql
+++ b/dataconnect/dataconnect/1_movie_insert.gql
@@ -8,7 +8,7 @@ mutation {
     rating: 8.8,
     description: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move.",
     tags: ["thriller", "action"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move."}
   })
   
   movie2: movie_insert(data: {
@@ -20,7 +20,7 @@ mutation {
     rating: 8.7,
     description: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny.",
     tags: ["sci-fi", "adventure"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny."}
   })
   
   movie3: movie_insert(data: {
@@ -32,7 +32,7 @@ mutation {
     rating: 8.1,
     description: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances.",
     tags: ["action", "thriller"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances."}
   })
 
   movie4: movie_insert(data: {
@@ -44,7 +44,7 @@ mutation {
     rating: 9.0,
     description: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice.",
     tags: ["action", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice."}
   })
 
   movie5: movie_insert(data: {
@@ -56,7 +56,7 @@ mutation {
     rating: 8.8,
     description: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity.",
     tags: ["drama", "thriller"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity."}
   })
 
   movie6: movie_insert(data: {
@@ -68,7 +68,7 @@ mutation {
     rating: 8.9,
     description: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references.",
     tags: ["crime", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references."}
   })
 
   movie7: movie_insert(data: {
@@ -80,7 +80,7 @@ mutation {
     rating: 8.8,
     description: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond.",
     tags: ["fantasy", "adventure"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond."}
   })
 
   movie8: movie_insert(data: {
@@ -92,7 +92,7 @@ mutation {
     rating: 9.3,
     description: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman).",
     tags: ["drama", "crime"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman)."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman)."}
     })
 
   movie9: movie_insert(data: {
@@ -104,7 +104,7 @@ mutation {
     rating: 8.8,
     description: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright).",
     tags: ["drama", "romance"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright)."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright)."}
   })
 
   movie10: movie_insert(data: {
@@ -116,7 +116,7 @@ mutation {
     rating: 9.2,
     description: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal.",
     tags: ["crime", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal."}
   })
 
   movie11: movie_insert(data: {
@@ -128,7 +128,7 @@ mutation {
     rating: 8.6,
     description: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer.",
     tags: ["thriller", "crime"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer."}
   })
 
   movie12: movie_insert(data: {
@@ -140,7 +140,7 @@ mutation {
     rating: 8.6,
     description: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war.",
     tags: ["war", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war."}
   })
  
   movie13: movie_insert(data: {
@@ -152,7 +152,7 @@ mutation {
     rating: 8.0,
     description: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast.",
     tags: ["action", "sci-fi"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast."}
   })
 
   movie14: movie_insert(data: {
@@ -164,7 +164,7 @@ mutation {
     rating: 8.5,
     description: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance.",
     tags: ["action", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance."}
   })
 
   movie15: movie_insert(data: {
@@ -176,7 +176,7 @@ mutation {
     rating: 7.8,
     description: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals.",
     tags: ["romance", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals."}
   })
 
   movie16: movie_insert(data: {
@@ -188,7 +188,7 @@ mutation {
     rating: 7.8,
     description: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience.",
     tags: ["sci-fi", "adventure"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience."}
   })
 
   movie17: movie_insert(data: {
@@ -200,7 +200,7 @@ mutation {
     rating: 8.1,
     description: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures.",
     tags: ["adventure", "sci-fi"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures."}
   })
 
   movie18: movie_insert(data: {
@@ -212,7 +212,7 @@ mutation {
     rating: 8.5,
     description: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption.",
     tags: ["animation", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption."}
   })
 
   movie19: movie_insert(data: {
@@ -224,7 +224,7 @@ mutation {
     rating: 8.6,
     description: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters.",
     tags: ["sci-fi", "adventure"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters."}
   })
 
   movie20: movie_insert(data: {
@@ -236,6 +236,6 @@ mutation {
     rating: 8.1,
     description: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity.",
     tags: ["sci-fi", "thriller"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@001", text: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity."}
+    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity."}
   })
 }
diff --git a/dataconnect/dataconnect/4_user_favorites_review_insert.gql b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
index 70bf8fa23..157091e4f 100644
--- a/dataconnect/dataconnect/4_user_favorites_review_insert.gql
+++ b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
@@ -1,23 +1,23 @@
 mutation {
   user1: user_insert(data: {
-    id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    id: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
     username: "cynthia_w"
   })
   
   user2: user_insert(data: {
-    id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    id: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
     username: "momo_h"
   })
   
   user3: user_insert(data: {
-    id: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    id: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
     username: "siyi_w"
   })
 
   review1: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174000",
 
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
     movieId: "550e8400-e29b-41d4-a716-446655440000",
     rating: 5,
     reviewText: "An incredible movie with a mind-blowing plot!",
@@ -26,7 +26,7 @@ mutation {
   
   review2: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174001",
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440001",
     rating: 5,
@@ -36,7 +36,7 @@ mutation {
   
   review3: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174002",
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440002",
     rating: 5,
@@ -46,7 +46,7 @@ mutation {
 
   review4: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174003",
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440003",
     rating: 4,
@@ -56,7 +56,7 @@ mutation {
 
   review5: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174004",
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440004",
     rating: 5,
@@ -66,7 +66,7 @@ mutation {
 
   review6: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174005",
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440005",
     rating: 5,
@@ -75,109 +75,109 @@ mutation {
   })
 
   favoriteMovie1: favoriteMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440000"
   })
   
   favoriteMovie2: favoriteMovie_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440001"
   })
   
   favoriteMovie3: favoriteMovie_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440002"
   })
 
   favoriteMovie4: favoriteMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440003"
   })
 
   favoriteMovie5: favoriteMovie_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440004"
   })
 
   favoriteMovie6: favoriteMovie_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440005"
   })
 
   favoriteActor1: favoriteActor_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
 
     actorId: "123e4567-e89b-12d3-a456-426614174000"
   })
   
   favoriteActor2: favoriteActor_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
 
     actorId: "123e4567-e89b-12d3-a456-426614174001"
   })
   
   favoriteActor3: favoriteActor_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
 
     actorId: "123e4567-e89b-12d3-a456-426614174002"
   })
 
   favoriteActor4: favoriteActor_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
 
     actorId: "123e4567-e89b-12d3-a456-426614174003"
   })
 
   favoriteActor5: favoriteActor_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
 
     actorId: "123e4567-e89b-12d3-a456-426614174004"
   })
 
   favoriteActor6: favoriteActor_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
 
     actorId: "123e4567-e89b-12d3-a456-426614174005"
   })
 
   watchedMovie1: watchedMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440000"
   })
   
   watchedMovie2: watchedMovie_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440001"
   })
   
   watchedMovie3: watchedMovie_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440002"
   })
 
   watchedMovie4: watchedMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440003"
   })
 
   watchedMovie5: watchedMovie_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440004"
   })
 
   watchedMovie6: watchedMovie_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440005"
   })
diff --git a/dataconnect/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql
index 6a4437a2d..fcb481d19 100644
--- a/dataconnect/dataconnect/connector/queries.gql
+++ b/dataconnect/dataconnect/connector/queries.gql
@@ -551,7 +551,7 @@ query fuzzySearch(
 query searchMovieDescriptionUsingL2Similarity($query: String!)
 @auth(level: PUBLIC) {
   movies_descriptionEmbedding_similarity(
-    compare_embed: { model: "textembedding-gecko@001", text: $query }
+    compare_embed: { model: "textembedding-gecko@003", text: $query }
     method: L2
     within: 2
     where: { description: { ne: "" } }

From b396a6f7b908603985682a217ab45f5a2f2469f7 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 3 Jun 2024 13:36:17 -0400
Subject: [PATCH 15/82] fix: username

---
 dataconnect/dataconnect/4_user_favorites_review_insert.gql | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/dataconnect/dataconnect/4_user_favorites_review_insert.gql b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
index 157091e4f..a2b0703c5 100644
--- a/dataconnect/dataconnect/4_user_favorites_review_insert.gql
+++ b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
@@ -1,17 +1,17 @@
 mutation {
   user1: user_insert(data: {
     id: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
-    username: "cynthia_w"
+    username: "c_w"
   })
   
   user2: user_insert(data: {
     id: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
-    username: "momo_h"
+    username: "a_w"
   })
   
   user3: user_insert(data: {
     id: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
-    username: "siyi_w"
+    username: "r_f"
   })
 
   review1: review_insert(data: {

From b06625646a7bfc9beb58d9b950ac83efd77279e3 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Tue, 25 Jun 2024 20:39:19 -0400
Subject: [PATCH 16/82] feat: update versions

---
 dataconnect/dataconnect/connector/queries.gql |  6 +-
 dataconnect/movie/app/actor/[id]/page.tsx     |  2 +-
 dataconnect/movie/app/advancedsearch/page.tsx |  2 +-
 dataconnect/movie/app/genre/[genre]/page.tsx  |  4 +-
 dataconnect/movie/app/layout.tsx              |  2 +-
 dataconnect/movie/app/movie/[id]/page.tsx     | 63 ++++++++++++++++---
 dataconnect/movie/app/myprofile/page.tsx      |  2 +-
 dataconnect/movie/app/page.tsx                |  4 +-
 dataconnect/movie/app/vectors/page.tsx        |  2 +-
 dataconnect/movie/components/moviecard.tsx    |  2 +-
 dataconnect/movie/components/navbar.tsx       |  6 +-
 dataconnect/movie/tsconfig.json               |  6 ++
 12 files changed, 75 insertions(+), 26 deletions(-)

diff --git a/dataconnect/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql
index fcb481d19..158874ef9 100644
--- a/dataconnect/dataconnect/connector/queries.gql
+++ b/dataconnect/dataconnect/connector/queries.gql
@@ -18,14 +18,14 @@ query ListUsers @auth(level: PUBLIC) {
   users {
     id
     username
-    favoriteActors_on_user {
+    favoriteActors: favoriteActors_on_user {
       actor {
         id
         name
         imageUrl
       }
     }
-    favoriteMovies_on_user {
+    favoriteMovies: favoriteMovies_on_user {
       movie {
         id
         title
@@ -571,6 +571,6 @@ query searchMovieDescriptionUsingL2Similarity1($compare: Vector!, $within: Float
     movies_descriptionEmbedding_similarity(compare: $compare, method: L2, within: $within, where: {description: {ne: $excludesContent}}, limit: $limit) {
       id
       title
-	description
+      description
     }
   }
diff --git a/dataconnect/movie/app/actor/[id]/page.tsx b/dataconnect/movie/app/actor/[id]/page.tsx
index d057ce327..c2e09099b 100644
--- a/dataconnect/movie/app/actor/[id]/page.tsx
+++ b/dataconnect/movie/app/actor/[id]/page.tsx
@@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
 import { useParams, useRouter } from 'next/navigation';
 import Link from 'next/link';
 import { MdFavorite, MdFavoriteBorder } from 'react-icons/md';
-import { getActorById, GetActorByIdResponse, GetActorByIdVariables, addFavoritedActor, deleteFavoriteActor, getIfFavoritedActor } from '../../../lib/dataconnect-sdk';
+import { getActorById, GetActorByIdResponse, GetActorByIdVariables, addFavoritedActor, deleteFavoriteActor, getIfFavoritedActor } from '@/lib/dataconnect-sdk';
 import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
 
 const Page = () => {
diff --git a/dataconnect/movie/app/advancedsearch/page.tsx b/dataconnect/movie/app/advancedsearch/page.tsx
index 042010999..06e52d634 100644
--- a/dataconnect/movie/app/advancedsearch/page.tsx
+++ b/dataconnect/movie/app/advancedsearch/page.tsx
@@ -3,7 +3,7 @@ import { useState } from 'react';
 import Link from 'next/link';
 import { FaSearch } from 'react-icons/fa';
 import { MdStar } from 'react-icons/md';
-import { fuzzySearch } from '../../lib/dataconnect-sdk';
+import { fuzzySearch } from '@/lib/dataconnect-sdk';
 
 const genres = ['', 'action', 'crime', 'drama', 'sci-fi', 'thriller', 'adventure'];
 
diff --git a/dataconnect/movie/app/genre/[genre]/page.tsx b/dataconnect/movie/app/genre/[genre]/page.tsx
index 48ab5697e..bc38cf7ce 100644
--- a/dataconnect/movie/app/genre/[genre]/page.tsx
+++ b/dataconnect/movie/app/genre/[genre]/page.tsx
@@ -1,8 +1,8 @@
 'use client';
 import { useEffect, useState } from 'react';
 import { useParams } from 'next/navigation';
-import MovieCard from '../../../components/moviecard';
-import { ListMoviesByGenreResponse, ListMoviesByGenreVariables, listMoviesByGenre } from '../../../lib/dataconnect-sdk';
+import MovieCard from '@/components/moviecard';
+import { ListMoviesByGenreResponse, ListMoviesByGenreVariables, listMoviesByGenre } from '@/lib/dataconnect-sdk';
 
 const Page = () => {
   const { genre } = useParams() as { genre: string };
diff --git a/dataconnect/movie/app/layout.tsx b/dataconnect/movie/app/layout.tsx
index 1d3a8e1b2..c7e9c7a62 100644
--- a/dataconnect/movie/app/layout.tsx
+++ b/dataconnect/movie/app/layout.tsx
@@ -1,5 +1,5 @@
 "use client";
-import Navbar from "../components/navbar";
+import Navbar from "@/components/navbar";
 import "../styles.css";
 export default function RootLayout({
   children,
diff --git a/dataconnect/movie/app/movie/[id]/page.tsx b/dataconnect/movie/app/movie/[id]/page.tsx
index c15c4e488..6e63d7309 100644
--- a/dataconnect/movie/app/movie/[id]/page.tsx
+++ b/dataconnect/movie/app/movie/[id]/page.tsx
@@ -2,7 +2,7 @@
 import { useEffect, useState } from 'react';
 import { useParams, useRouter } from 'next/navigation';
 import Link from 'next/link';
-import { MdFavorite, MdFavoriteBorder, MdCheck, MdCheckBoxOutlineBlank, MdStar } from 'react-icons/md';
+import { MdFavorite, MdFavoriteBorder, MdCheck, MdAdd, MdStar } from 'react-icons/md';
 import {
   getMovieById,
   GetMovieByIdResponse,
@@ -14,7 +14,9 @@ import {
   getIfFavoritedMovie,
   addReview,
   deleteReview,
-} from '../../../lib/dataconnect-sdk';
+  searchMovieDescriptionUsingL2similarity,
+  SearchMovieDescriptionUsingL2similarityResponse,
+} from '@/lib/dataconnect-sdk';
 import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
 
 const Page = () => {
@@ -28,6 +30,7 @@ const Page = () => {
   const [reviewText, setReviewText] = useState('');
   const [userReview, setUserReview] = useState<GetMovieByIdResponse['movie']['reviews'][0] | null>(null);
   const [rating, setRating] = useState(0);
+  const [similarMovies, setSimilarMovies] = useState<SearchMovieDescriptionUsingL2similarityResponse['movies_descriptionEmbedding_similarity']>([]);
 
   useEffect(() => {
     const auth = getAuth();
@@ -50,6 +53,7 @@ const Page = () => {
           setMovie(response.data.movie);
           const userReview = response.data.movie.reviews.find(review => review.user.id === authUser?.uid);
           setUserReview(userReview || null);
+          await fetchSimilarMovies(response.data.movie.description);
         } catch (error) {
           console.error('Error fetching movie:', error);
         } finally {
@@ -59,7 +63,16 @@ const Page = () => {
 
       fetchMovie();
     }
-  }, [id, authUser, movie]);
+  }, [id, authUser]);
+
+  const fetchSimilarMovies = async (description: string) => {
+    try {
+      const response = await searchMovieDescriptionUsingL2similarity({ query: description });
+      setSimilarMovies(response?.data?.movies_descriptionEmbedding_similarity);
+    } catch (error) {
+      console.error('Error fetching similar movies:', error);
+    }
+  };
 
   const checkIfFavorited = async (userId: string) => {
     try {
@@ -167,13 +180,6 @@ const Page = () => {
             >
               {isFavorited ? <MdFavorite size={24} /> : <MdFavoriteBorder size={24} />}
             </button>
-            <button
-              className="flex items-center justify-center p-1 text-green-700 hover:text-green-800 transition-colors duration-200"
-              aria-label="Watched"
-              onClick={handleWatchedToggle}
-            >
-              {isWatched ? <MdCheck size={24} /> : <MdCheckBoxOutlineBlank size={24} />}
-            </button>
           </div>
         </div>
       </div>
@@ -273,6 +279,43 @@ const Page = () => {
           </div>
         ))}
       </div>
+
+      <div className="mt-8">
+        <h2 className="text-2xl font-bold mb-2">Similar Movies</h2>
+        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
+          {similarMovies.map((similarMovie) => (
+            <div key={similarMovie.id} className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative">
+              <Link href={`/movie/${similarMovie.id}`}>
+                <img className="w-full h-64 object-cover" src={similarMovie.imageUrl} alt={similarMovie.title} />
+              </Link>
+              <div className="p-4">
+                <h3 className="font-bold text-lg mb-1 text-white">{similarMovie.title}</h3>
+                <p className="text-sm text-gray-300 overflow-y-scroll max-h-12">{similarMovie.description}</p>
+                <div className="flex items-center text-yellow-500 mt-2">
+                  <MdStar className="text-yellow-500" size={20} />
+                  <span className="ml-1 text-gray-400">{similarMovie.rating}</span>
+                </div>
+                <div className="flex flex-wrap gap-1 mt-2">
+                  {similarMovie.tags?.map((tag, index) => (
+                    <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs capitalize">{tag}</span>
+                  ))}
+                </div>
+                {authUser && (
+                  <div className="mt-2 flex space-x-2 items-center">
+                    <button
+                      className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
+                      aria-label="Favorite"
+                      onClick={handleFavoriteToggle}
+                    >
+                      {isFavorited ? <MdFavorite size={20} /> : <MdFavoriteBorder size={20} />}
+                    </button>
+                  </div>
+                )}
+              </div>
+            </div>
+          ))}
+        </div>
+      </div>
     </div>
   );
 };
diff --git a/dataconnect/movie/app/myprofile/page.tsx b/dataconnect/movie/app/myprofile/page.tsx
index b2b527788..0b7dba866 100644
--- a/dataconnect/movie/app/myprofile/page.tsx
+++ b/dataconnect/movie/app/myprofile/page.tsx
@@ -10,7 +10,7 @@ import {
   deleteWatchedMovie,
   deleteFavoritedMovie,
   deleteFavoriteActor,
-} from '../../lib/dataconnect-sdk';
+} from '@/lib/dataconnect-sdk';
 import { MdStar } from 'react-icons/md';
 
 const Page = () => {
diff --git a/dataconnect/movie/app/page.tsx b/dataconnect/movie/app/page.tsx
index 3754b9f73..b7831fe90 100644
--- a/dataconnect/movie/app/page.tsx
+++ b/dataconnect/movie/app/page.tsx
@@ -1,12 +1,12 @@
 "use client";
 import { useEffect, useState } from "react";
-import Carousel from "../components/carousel";
+import Carousel from "@/components/carousel";
 import {
   moviesTop10,
   moviesRecentlyReleased,
   MoviesRecentlyReleasedResponse,
   MoviesTop10Response,
-} from "../lib/dataconnect-sdk";
+} from "@/lib/dataconnect-sdk";
 
 const Page = () => {
   const [topMovies, setTopMovies] = useState<MoviesTop10Response["movies"]>([]);
diff --git a/dataconnect/movie/app/vectors/page.tsx b/dataconnect/movie/app/vectors/page.tsx
index b8b06be6e..9fb411e73 100644
--- a/dataconnect/movie/app/vectors/page.tsx
+++ b/dataconnect/movie/app/vectors/page.tsx
@@ -1,7 +1,7 @@
 'use client';
 import { useState } from 'react';
 import { useRouter } from 'next/navigation';
-import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '../../lib/dataconnect-sdk';
+import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '@/lib/dataconnect-sdk';
 import { FaSpinner } from 'react-icons/fa';
 
 const Page = () => {
diff --git a/dataconnect/movie/components/moviecard.tsx b/dataconnect/movie/components/moviecard.tsx
index 2f1d83b26..fd0dbfa5c 100644
--- a/dataconnect/movie/components/moviecard.tsx
+++ b/dataconnect/movie/components/moviecard.tsx
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
 import Link from 'next/link';
 import { MdFavorite, MdFavoriteBorder, MdCheck, MdAdd, MdStar } from 'react-icons/md';
 import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
-import { addFavoritedMovie, deleteFavoritedMovie, addWatchedMovie, deleteWatchedMovie, getIfWatched, getIfFavoritedMovie } from '../lib/dataconnect-sdk';
+import { addFavoritedMovie, deleteFavoritedMovie, addWatchedMovie, deleteWatchedMovie, getIfWatched, getIfFavoritedMovie } from '@/lib/dataconnect-sdk';
 
 interface MovieCardProps {
   id: string;
diff --git a/dataconnect/movie/components/navbar.tsx b/dataconnect/movie/components/navbar.tsx
index fd3b5827e..6379de0c0 100644
--- a/dataconnect/movie/components/navbar.tsx
+++ b/dataconnect/movie/components/navbar.tsx
@@ -1,12 +1,12 @@
 import { useEffect, useState } from 'react';
 import { getAuth, signInWithRedirect, GoogleAuthProvider, signOut, User } from 'firebase/auth';
-import { firebaseapp, onAuthStateChanged } from '../lib/firebase';
+import { firebaseapp, onAuthStateChanged } from '@/lib/firebase';
 import Link from 'next/link';
 import { useRouter } from 'next/navigation';
-import { upsertUser } from '../lib/dataconnect-sdk';
+import { upsertUser } from '@/lib/dataconnect-sdk';
 import { FaSearch } from 'react-icons/fa';
 import Image from 'next/image';
-import firebaseLogo from '../assets/firebase_logo.svg';
+import firebaseLogo from '@/assets/firebase_logo.svg';
 
 const Navbar = () => {
   const [user, setUser] = useState<User | null>(null);
diff --git a/dataconnect/movie/tsconfig.json b/dataconnect/movie/tsconfig.json
index b6ba42e2d..065550b56 100644
--- a/dataconnect/movie/tsconfig.json
+++ b/dataconnect/movie/tsconfig.json
@@ -1,5 +1,11 @@
 {
   "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "@/lib/*": ["lib/*"],
+      "@/components/*": ["components/*"],
+      "@/assets/*": ["assets/*"],
+    },
     "target": "es5",
     "lib": ["dom", "dom.iterable", "esnext"],
     "allowJs": true,

From 0823b91d6729c413dec6b575ff9f33c446d981bd Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Tue, 25 Jun 2024 20:39:52 -0400
Subject: [PATCH 17/82] fix: signinwithredirect

---
 .../4_user_favorites_review_insert.gql        | 60 ++++++++--------
 dataconnect/dataconnect/schema/schema.gql     | 69 +++++++++----------
 dataconnect/movie/components/navbar.tsx       |  4 +-
 3 files changed, 65 insertions(+), 68 deletions(-)

diff --git a/dataconnect/dataconnect/4_user_favorites_review_insert.gql b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
index a2b0703c5..70bf8fa23 100644
--- a/dataconnect/dataconnect/4_user_favorites_review_insert.gql
+++ b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
@@ -1,23 +1,23 @@
 mutation {
   user1: user_insert(data: {
-    id: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
-    username: "c_w"
+    id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+    username: "cynthia_w"
   })
   
   user2: user_insert(data: {
-    id: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
-    username: "a_w"
+    id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+    username: "momo_h"
   })
   
   user3: user_insert(data: {
-    id: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
-    username: "r_f"
+    id: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+    username: "siyi_w"
   })
 
   review1: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174000",
 
-    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
     movieId: "550e8400-e29b-41d4-a716-446655440000",
     rating: 5,
     reviewText: "An incredible movie with a mind-blowing plot!",
@@ -26,7 +26,7 @@ mutation {
   
   review2: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174001",
-    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440001",
     rating: 5,
@@ -36,7 +36,7 @@ mutation {
   
   review3: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174002",
-    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440002",
     rating: 5,
@@ -46,7 +46,7 @@ mutation {
 
   review4: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174003",
-    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440003",
     rating: 4,
@@ -56,7 +56,7 @@ mutation {
 
   review5: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174004",
-    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440004",
     rating: 5,
@@ -66,7 +66,7 @@ mutation {
 
   review6: review_insert(data: {
     id: "345e4567-e89b-12d3-a456-426614174005",
-    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440005",
     rating: 5,
@@ -75,109 +75,109 @@ mutation {
   })
 
   favoriteMovie1: favoriteMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440000"
   })
   
   favoriteMovie2: favoriteMovie_insert(data: {
-    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440001"
   })
   
   favoriteMovie3: favoriteMovie_insert(data: {
-    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440002"
   })
 
   favoriteMovie4: favoriteMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440003"
   })
 
   favoriteMovie5: favoriteMovie_insert(data: {
-    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440004"
   })
 
   favoriteMovie6: favoriteMovie_insert(data: {
-    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440005"
   })
 
   favoriteActor1: favoriteActor_insert(data: {
-    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
 
     actorId: "123e4567-e89b-12d3-a456-426614174000"
   })
   
   favoriteActor2: favoriteActor_insert(data: {
-    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
 
     actorId: "123e4567-e89b-12d3-a456-426614174001"
   })
   
   favoriteActor3: favoriteActor_insert(data: {
-    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
 
     actorId: "123e4567-e89b-12d3-a456-426614174002"
   })
 
   favoriteActor4: favoriteActor_insert(data: {
-    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
 
     actorId: "123e4567-e89b-12d3-a456-426614174003"
   })
 
   favoriteActor5: favoriteActor_insert(data: {
-    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
 
     actorId: "123e4567-e89b-12d3-a456-426614174004"
   })
 
   favoriteActor6: favoriteActor_insert(data: {
-    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
 
     actorId: "123e4567-e89b-12d3-a456-426614174005"
   })
 
   watchedMovie1: watchedMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440000"
   })
   
   watchedMovie2: watchedMovie_insert(data: {
-    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440001"
   })
   
   watchedMovie3: watchedMovie_insert(data: {
-    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440002"
   })
 
   watchedMovie4: watchedMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69e53cW0Q8R1T2",
+    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440003"
   })
 
   watchedMovie5: watchedMovie_insert(data: {
-    userId: "fep4fXpGWsaRpiphq9CIrBIXQ0S2",
+    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
 
     movieId: "550e8400-e29b-41d4-a716-446655440004"
   })
 
   watchedMovie6: watchedMovie_insert(data: {
-    userId: "TBedjwCX1Jf955Uuoxk6k74sY0l1",
+    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
 
     movieId: "550e8400-e29b-41d4-a716-446655440005"
   })
diff --git a/dataconnect/dataconnect/schema/schema.gql b/dataconnect/dataconnect/schema/schema.gql
index 01260143a..4cda98395 100644
--- a/dataconnect/dataconnect/schema/schema.gql
+++ b/dataconnect/dataconnect/schema/schema.gql
@@ -1,40 +1,43 @@
 # Movies
 type Movie
+  # The below parameter values are generated by default with @table, and can be edited manually.
   @table(name: "Movies", singular: "movie", plural: "movies", key: ["id"]) {
-  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
+  # implicitly calls @col to generates a column name. ex: @col(name: "movie_id")
+  # for UUID fields, @default(expr: "uuidV4()") is implicitly called
+  id: UUID!
   title: String!
-  imageUrl: String! @col(name: "image_url")
-  releaseYear: Int @col(name: "release_year")
+  imageUrl: String!
+  releaseYear: Int
   genre: String
-  rating: Float @col(name: "rating") 
-  description: String @col(name: "description")
-  tags: [String] @col(name: "tags")
+  rating: Float
+  description: String
+  tags: [String]
   # Vectors
   descriptionEmbedding: Vector @col(size:768) # vector
+  # Self Joins
+  sequelTo: Movie
 }
 
 # Movie Metadata
 # Movie - MovieMetadata is a one-to-one relationship
 type MovieMetadata
-  @table(
-    name: "MovieMetadata"
-  ) {
+  @table {
   # @ref creates a field in the current table (MovieMetadata) that holds the primary key of the referenced type
   # In this case, @ref(fields: "id") is implied
   movie: Movie! @ref
   # movieId: UUID <- this is created by the above @ref
-  director: String @col(name: "director")
+  director: String
   # TODO: optional other fields
 }
 
 # Actors
 # Suppose an actor can participate in multiple movies and movies can have multiple actors
 # Movie - Actors (or vice versa) is a many to many relationship
-type Actor @table(name: "Actors", singular: "actor", plural: "actors") {
-  id: UUID! @col(name: "actor_id") @default(expr: "uuidV4()")
-  imageUrl: String! @col(name: "image_url")
+type Actor @table {
+  id: UUID!
+  imageUrl: String! 
   name: String! @col(name: "name", dataType: "varchar(30)")
-  biography: String @col(name: "biography")
+  biography: String
 }
 
 # Join table for many-to-many relationship for movies and actors
@@ -43,13 +46,13 @@ type Actor @table(name: "Actors", singular: "actor", plural: "actors") {
 type MovieActor @table(key: ["movie", "actor"]) {
   # @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
   # In this case, @ref(fields: "id") is implied
-  movie: Movie! @ref
-  # movieId: UUID! <- this is created by the above @ref, see: implicit.gql
+  movie: Movie!
+  # movieId: UUID! <- this is created by the implied @ref, see: implicit.gql
 
-  actor: Actor! @ref
-  # actorId: UUID! <- this is created by the above @ref, see: implicit.gql
+  actor: Actor!
+  # actorId: UUID! <- this is created by the implied  @ref, see: implicit.gql
 
-  role: String! @col(name: "role") # "main" or "supporting"
+  role: String! # "main" or "supporting"
   # TODO: optional other fields
 }
 
@@ -57,8 +60,7 @@ type MovieActor @table(key: ["movie", "actor"]) {
 # Suppose a user can leave reviews for movies
 # user:reviews is a one to many relationship, movie:reviews is a one to many relationship, movie:user is a many to many relationship
 type User
-  @table(name: "Users", singular: "user", plural: "users", key: ["id"]) {
-  # id: UUID! @col(name: "user_id") @default(expr: "uuidV4()")
+  @table {
   id: String! @col(name: "user_auth")
   username: String! @col(name: "username", dataType: "varchar(50)")
   # The following are generated from the @ref in the Review table
@@ -69,36 +71,31 @@ type User
 # Join table for many-to-many relationship for users and favorite movies
 type FavoriteMovie
   @table(name: "FavoriteMovies", key: ["user", "movie"]) {
-  user: User! @ref
-  movie: Movie! @ref
+  # @ref is implicit
+  user: User!
+  movie: Movie!
 }
 
 # Join table for many-to-many relationship for users and favorite actors
 type FavoriteActor
   @table(name: "FavoriteActors", key: ["user", "actor"]) {
-  user: User! @ref
-  actor: Actor! @ref
+  user: User!
+  actor: Actor!
 }
 
 # Join table for many-to-many relationship for users and watched movies
 type WatchedMovie
   @table(name: "WatchedMovies", key: ["user", "movie"]) {
-  user: User! @ref
-  movie: Movie! @ref
+  user: User!
+  movie: Movie!
 }
 
 # Reviews
 type Review @table(name: "Reviews", key: ["movie", "user"]) {
-  id: UUID! @col(name: "review_id") @default(expr: "uuidV4()")
-  user: User! @ref
-  movie: Movie! @ref
+  id: UUID! @default(expr: "uuidV4()")
+  user: User!
+  movie: Movie!
   rating: Int
   reviewText: String
   reviewDate: Date! @default(expr: "request.time")
 }
-
-# Self Joins
-extend type Movie {
-    sequelTo: Movie
-}
-
diff --git a/dataconnect/movie/components/navbar.tsx b/dataconnect/movie/components/navbar.tsx
index 6379de0c0..875c0065a 100644
--- a/dataconnect/movie/components/navbar.tsx
+++ b/dataconnect/movie/components/navbar.tsx
@@ -1,5 +1,5 @@
 import { useEffect, useState } from 'react';
-import { getAuth, signInWithRedirect, GoogleAuthProvider, signOut, User } from 'firebase/auth';
+import { getAuth, signInWithPopup, GoogleAuthProvider, signOut, User } from 'firebase/auth';
 import { firebaseapp, onAuthStateChanged } from '@/lib/firebase';
 import Link from 'next/link';
 import { useRouter } from 'next/navigation';
@@ -28,7 +28,7 @@ const Navbar = () => {
 
   const handleSignIn = async () => {
     const provider = new GoogleAuthProvider();
-    await signInWithRedirect(auth, provider);
+    await signInWithPopup(auth, provider);
   };
 
   const handleSignOut = async () => {

From 25931e6624b04ca6c1545b21f063d9d95f4280bb Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Thu, 25 Jul 2024 02:20:53 -0400
Subject: [PATCH 18/82] feat: update to v13.14.0

---
 dataconnect/README.md                         |  41 --
 dataconnect/dataconnect/1_movie_insert.gql    | 441 ++++++--------
 dataconnect/dataconnect/2_actor_insert.gql    | 241 ++++----
 .../dataconnect/3_movie_actor_insert.gql      | 517 +++++++---------
 .../4_user_favorites_review_insert.gql        | 301 ++++-----
 .../dataconnect/5_optional_vector_embed.gql   | 141 +++++
 dataconnect/dataconnect/connector/queries.gql | 576 ------------------
 dataconnect/dataconnect/dataconnect.yaml      |   9 +-
 .../connector.yaml                            |   2 +-
 .../mutations.gql                             |  54 +-
 .../dataconnect/movie-connector/queries.gql   | 383 ++++++++++++
 dataconnect/dataconnect/schema/schema.gql     |  66 +-
 dataconnect/firebase.json                     |   3 +-
 dataconnect/movie/app/actor/[id]/page.tsx     |   7 +-
 dataconnect/movie/app/advancedsearch/page.tsx |   4 +-
 dataconnect/movie/app/movie/[id]/page.tsx     |  50 +-
 dataconnect/movie/app/myprofile/page.tsx      |  68 +--
 dataconnect/movie/app/page.tsx                |  16 +-
 dataconnect/movie/app/vectors/page.tsx        |   1 -
 dataconnect/movie/components/moviecard.tsx    |  58 +-
 dataconnect/movie/lib/firebase.tsx            |  24 +-
 21 files changed, 1290 insertions(+), 1713 deletions(-)
 delete mode 100644 dataconnect/README.md
 create mode 100644 dataconnect/dataconnect/5_optional_vector_embed.gql
 delete mode 100644 dataconnect/dataconnect/connector/queries.gql
 rename dataconnect/dataconnect/{connector => movie-connector}/connector.yaml (91%)
 rename dataconnect/dataconnect/{connector => movie-connector}/mutations.gql (57%)
 create mode 100644 dataconnect/dataconnect/movie-connector/queries.gql

diff --git a/dataconnect/README.md b/dataconnect/README.md
deleted file mode 100644
index 708390df9..000000000
--- a/dataconnect/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-Firebase DataConnect Quickstart
-=======================================
-
-Introduction
-------------
-
-This is a sample app for the preview version of the Firebase DataConnect.
-This will not work if you don't have access to the preview.
-
-<!-- Introduction
-------------
-
-[Read more about Firebase DataConnect ](https://firebase.google.com/docs/dataconnect/) -->
-
-Getting Started
----------------
-
-1. Sign up for early access [here](https://firebase.google.com/products/data-connect) and receive an invitation.
-2. Upgrade your Firebase project billing to the Blaze plan, you will not be charged for the duration of gated preview.
-3. Initialize DataConnect in the [Firebase Console](https://console.firebase.google.com/u/0/).
-4. Clone this repository to your local machine.
-5. Update `firebase-tools` with `npm install -g firebase-tools`.
-6. Enable the DataConnect CLI with `firebase experiments:enable dataconnect`.
-7. Initialize your Firebase project in the `dataconnect` folder with `firebase init` and select DataConnect. Do not overwrite the dataconnect files when prompted.
-8. Replace variables in `.env.local` with your project-specific values.
-9. Allow domains for Firebase Auth (e.g., http://localhost or http://127.0.0.1).
-10. Deploy DataConnect with `firebase deploy --only dataconnect` (this unlocks hidden vectors search).
-11. Start the DateConnect emulators.
-12. Run `firebase dataconnect:sdk:generate` to generate the SDK
-13. Navigate to the `movie` directory and install dependencies with `npm i` and start the development server with `npm run dev`.
-14. Run the four `_insert.gql` files in the `./dataconnect` directory in order.
-
-<!-- Support
--------
-
-- [Firebase Support](https://firebase.google.com/support/) -->
-
-License
--------
-
-© Google, 2024. Licensed under an [Apache-2](../LICENSE) license.
diff --git a/dataconnect/dataconnect/1_movie_insert.gql b/dataconnect/dataconnect/1_movie_insert.gql
index 5f312db4e..b8a9f8cef 100644
--- a/dataconnect/dataconnect/1_movie_insert.gql
+++ b/dataconnect/dataconnect/1_movie_insert.gql
@@ -1,241 +1,204 @@
 mutation {
-  movie1: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440000",
-    title: "Inception",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Finception.jpg?alt=media&token=07b09781-b302-4623-a5c3-1956d0143168",
-    releaseYear: 2010,
-    genre: "sci-fi",
-    rating: 8.8,
-    description: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move.",
-    tags: ["thriller", "action"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move."}
-  })
-  
-  movie2: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440001",
-    title: "The Matrix",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_matrix.jpg?alt=media&token=4975645d-fef8-409e-84a5-bcc1046e2059",
-    releaseYear: 1999,
-    genre: "action",
-    rating: 8.7,
-    description: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny.",
-    tags: ["sci-fi", "adventure"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny."}
-  })
-  
-  movie3: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440002",
-    title: "John Wick 4",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fjohn_wick_4.jpg?alt=media&token=463ed467-9daa-4281-965d-44e7cc4172d5",
-    releaseYear: 2023,
-    genre: "action",
-    rating: 8.1,
-    description: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances.",
-    tags: ["action", "thriller"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances."}
-  })
-
-  movie4: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440003",
-    title: "The Dark Knight",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_dark_knight.jpg?alt=media&token=a9803c59-40d5-4758-a6f4-9a7c274a1218",
-    releaseYear: 2008,
-    genre: "action",
-    rating: 9.0,
-    description: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice.",
-    tags: ["action", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice."}
-  })
-
-  movie5: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440004",
-    title: "Fight Club",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Ffight_club.jpg?alt=media&token=a4bc1933-2607-42cd-a860-e44c4587fd9c",
-    releaseYear: 1999,
-    genre: "drama",
-    rating: 8.8,
-    description: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity.",
-    tags: ["drama", "thriller"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity."}
-  })
-
-  movie6: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440005",
-    title: "Pulp Fiction",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fpulp_fiction.jpg?alt=media&token=0df86e18-5cb1-45b3-a6d9-3f41563c3465",
-    releaseYear: 1994,
-    genre: "crime",
-    rating: 8.9,
-    description: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references.",
-    tags: ["crime", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references."}
-  })
-
-  movie7: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440006",
-    title: "The Lord of the Rings: The Fellowship of the Ring",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Flotr_fellowship.jpg?alt=media&token=92641d2d-6c52-4172-bd66-95fb86b4b96b",
-    releaseYear: 2001,
-    genre: "fantasy",
-    rating: 8.8,
-    description: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond.",
-    tags: ["fantasy", "adventure"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond."}
-  })
-
-  movie8: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440007",
-    title: "The Shawshank Redemption",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_shawshanks_redemption.jpg?alt=media&token=f67b5ab2-a435-48b2-8251-5bf866b183e9",
-    releaseYear: 1994,
-    genre: "drama",
-    rating: 9.3,
-    description: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman).",
-    tags: ["drama", "crime"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman)."}
-    })
-
-  movie9: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440008",
-    title: "Forrest Gump",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fforrest_gump.jpeg?alt=media&token=f21e88ce-6fab-4218-aa55-94738acc9b8f",
-    releaseYear: 1994,
-    genre: "drama",
-    rating: 8.8,
-    description: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright).",
-    tags: ["drama", "romance"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright)."}
-  })
-
-  movie10: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440009",
-    title: "The Godfather",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_godfather.jpg?alt=media&token=5297fd94-ae87-4995-9de5-3755232bad52",
-    releaseYear: 1972,
-    genre: "crime",
-    rating: 9.2,
-    description: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal.",
-    tags: ["crime", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal."}
-  })
-
-  movie11: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440010",
-    title: "The Silence of the Lambs",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_silence_of_the_lambs.jpg?alt=media&token=7ca6abeb-b15c-4f5e-9280-5a590e89fe54",
-    releaseYear: 1991,
-    genre: "thriller",
-    rating: 8.6,
-    description: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer.",
-    tags: ["thriller", "crime"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer."}
-  })
-
-  movie12: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440011",
-    title: "Saving Private Ryan",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fsaving_private_ryan.jpg?alt=media&token=58ed877e-7ae0-4e30-9aee-d45c2deb7a00",
-    releaseYear: 1998,
-    genre: "war",
-    rating: 8.6,
-    description: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war.",
-    tags: ["war", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war."}
-  })
- 
-  movie13: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440012",
-    title: "The Avengers",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_avengers.jpg?alt=media&token=3d68ccad-2fa1-48da-a83e-7941e246c9f9",
-    releaseYear: 2012,
-    genre: "action",
-    rating: 8.0,
-    description: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast.",
-    tags: ["action", "sci-fi"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast."}
-  })
-
-  movie14: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440013",
-    title: "Gladiator",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fgladiator.jpg?alt=media&token=61d75825-b79f-4add-afdb-7da5eed53407",
-    releaseYear: 2000,
-    genre: "action",
-    rating: 8.5,
-    description: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance.",
-    tags: ["action", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance."}
-  })
-
-  movie15: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440014",
-    title: "Titanic",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Ftitanic.png?alt=media&token=dd03dc83-486e-4b03-9b03-2f9ed83fd9d0",
-    releaseYear: 1997,
-    genre: "romance",
-    rating: 7.8,
-    description: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals.",
-    tags: ["romance", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals."}
-  })
-
-  movie16: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440015",
-    title: "Avatar",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Favatar.jpg?alt=media&token=1c75b09d-7c7a-44bf-b7ad-e7da4d0b7193",
-    releaseYear: 2009,
-    genre: "sci-fi",
-    rating: 7.8,
-    description: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience.",
-    tags: ["sci-fi", "adventure"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience."}
-  })
-
-  movie17: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440016",
-    title: "Jurassic Park",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fjurassic_park.jpg?alt=media&token=1731ce71-3384-4435-8a5b-821d4fd286d3",
-    releaseYear: 1993,
-    genre: "adventure",
-    rating: 8.1,
-    description: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures.",
-    tags: ["adventure", "sci-fi"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures."}
-  })
-
-  movie18: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440017",
-    title: "The Lion King",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_lion_king.jpg?alt=media&token=3e4e4265-6ae7-47d6-a5ba-584de126ef00",
-    releaseYear: 1994,
-    genre: "animation",
-    rating: 8.5,
-    description: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption.",
-    tags: ["animation", "drama"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption."}
-  })
-
-  movie19: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440018",
-    title: "Star Wars: Episode IV - A New Hope",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fstar_wars_4.jpg?alt=media&token=b4ea7e0c-707f-43dd-8633-9d962e77b5a4",
-    releaseYear: 1977,
-    genre: "sci-fi",
-    rating: 8.6,
-    description: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters.",
-    tags: ["sci-fi", "adventure"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters."}
-  })
-
-  movie20: movie_insert(data: {
-    id: "550e8400-e29b-41d4-a716-446655440019",
-    title: "Blade Runner",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fblade_runner.jpg?alt=media&token=d8e94bdd-1477-49f3-b244-dd7a9c059fc1",
-    releaseYear: 1982,
-    genre: "sci-fi",
-    rating: 8.1,
-    description: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity.",
-    tags: ["sci-fi", "thriller"],
-    descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity."}
-  })
+  movie_insertMany(data: [
+    {
+      id: "550e8400-e29b-41d4-a716-446655440000",
+      title: "Inception",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Finception.jpg?alt=media&token=07b09781-b302-4623-a5c3-1956d0143168",
+      releaseYear: 2010,
+      genre: "sci-fi",
+      rating: 8.8,
+      description: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move.",
+      tags: ["thriller", "action"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440001",
+      title: "The Matrix",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_matrix.jpg?alt=media&token=4975645d-fef8-409e-84a5-bcc1046e2059",
+      releaseYear: 1999,
+      genre: "action",
+      rating: 8.7,
+      description: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny.",
+      tags: ["sci-fi", "adventure"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440002",
+      title: "John Wick 4",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fjohn_wick_4.jpg?alt=media&token=463ed467-9daa-4281-965d-44e7cc4172d5",
+      releaseYear: 2023,
+      genre: "action",
+      rating: 8.1,
+      description: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances.",
+      tags: ["action", "thriller"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440003",
+      title: "The Dark Knight",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_dark_knight.jpg?alt=media&token=a9803c59-40d5-4758-a6f4-9a7c274a1218",
+      releaseYear: 2008,
+      genre: "action",
+      rating: 9.0,
+      description: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice.",
+      tags: ["action", "drama"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440004",
+      title: "Fight Club",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Ffight_club.jpg?alt=media&token=a4bc1933-2607-42cd-a860-e44c4587fd9c",
+      releaseYear: 1999,
+      genre: "drama",
+      rating: 8.8,
+      description: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity.",
+      tags: ["drama", "thriller"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440005",
+      title: "Pulp Fiction",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fpulp_fiction.jpg?alt=media&token=0df86e18-5cb1-45b3-a6d9-3f41563c3465",
+      releaseYear: 1994,
+      genre: "crime",
+      rating: 8.9,
+      description: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references.",
+      tags: ["crime", "drama"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440006",
+      title: "The Lord of the Rings: The Fellowship of the Ring",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Flotr_fellowship.jpg?alt=media&token=92641d2d-6c52-4172-bd66-95fb86b4b96b",
+      releaseYear: 2001,
+      genre: "fantasy",
+      rating: 8.8,
+      description: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond.",
+      tags: ["fantasy", "adventure"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440007",
+      title: "The Shawshank Redemption",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_shawshanks_redemption.jpg?alt=media&token=f67b5ab2-a435-48b2-8251-5bf866b183e9",
+      releaseYear: 1994,
+      genre: "drama",
+      rating: 9.3,
+      description: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman).",
+      tags: ["drama", "crime"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440008",
+      title: "Forrest Gump",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fforrest_gump.jpeg?alt=media&token=f21e88ce-6fab-4218-aa55-94738acc9b8f",
+      releaseYear: 1994,
+      genre: "drama",
+      rating: 8.8,
+      description: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright).",
+      tags: ["drama", "romance"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440009",
+      title: "The Godfather",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_godfather.jpg?alt=media&token=5297fd94-ae87-4995-9de5-3755232bad52",
+      releaseYear: 1972,
+      genre: "crime",
+      rating: 9.2,
+      description: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal.",
+      tags: ["crime", "drama"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440010",
+      title: "The Silence of the Lambs",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_silence_of_the_lambs.jpg?alt=media&token=7ca6abeb-b15c-4f5e-9280-5a590e89fe54",
+      releaseYear: 1991,
+      genre: "thriller",
+      rating: 8.6,
+      description: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer.",
+      tags: ["thriller", "crime"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440011",
+      title: "Saving Private Ryan",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fsaving_private_ryan.jpg?alt=media&token=58ed877e-7ae0-4e30-9aee-d45c2deb7a00",
+      releaseYear: 1998,
+      genre: "war",
+      rating: 8.6,
+      description: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war.",
+      tags: ["war", "drama"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440012",
+      title: "The Avengers",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_avengers.jpg?alt=media&token=3d68ccad-2fa1-48da-a83e-7941e246c9f9",
+      releaseYear: 2012,
+      genre: "action",
+      rating: 8.0,
+      description: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast.",
+      tags: ["action", "sci-fi"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440013",
+      title: "Gladiator",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fgladiator.jpg?alt=media&token=61d75825-b79f-4add-afdb-7da5eed53407",
+      releaseYear: 2000,
+      genre: "action",
+      rating: 8.5,
+      description: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance.",
+      tags: ["action", "drama"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440014",
+      title: "Titanic",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Ftitanic.png?alt=media&token=dd03dc83-486e-4b03-9b03-2f9ed83fd9d0",
+      releaseYear: 1997,
+      genre: "romance",
+      rating: 7.8,
+      description: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals.",
+      tags: ["romance", "drama"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440015",
+      title: "Avatar",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Favatar.jpg?alt=media&token=1c75b09d-7c7a-44bf-b7ad-e7da4d0b7193",
+      releaseYear: 2009,
+      genre: "sci-fi",
+      rating: 7.8,
+      description: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience.",
+      tags: ["sci-fi", "adventure"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440016",
+      title: "Jurassic Park",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fjurassic_park.jpg?alt=media&token=1731ce71-3384-4435-8a5b-821d4fd286d3",
+      releaseYear: 1993,
+      genre: "adventure",
+      rating: 8.1,
+      description: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures.",
+      tags: ["adventure", "sci-fi"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440017",
+      title: "The Lion King",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_lion_king.jpg?alt=media&token=3e4e4265-6ae7-47d6-a5ba-584de126ef00",
+      releaseYear: 1994,
+      genre: "animation",
+      rating: 8.5,
+      description: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption.",
+      tags: ["animation", "drama"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440018",
+      title: "Star Wars: Episode IV - A New Hope",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fstar_wars_4.jpg?alt=media&token=b4ea7e0c-707f-43dd-8633-9d962e77b5a4",
+      releaseYear: 1977,
+      genre: "sci-fi",
+      rating: 8.6,
+      description: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters.",
+      tags: ["sci-fi", "adventure"]
+    },
+    {
+      id: "550e8400-e29b-41d4-a716-446655440019",
+      title: "Blade Runner",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fblade_runner.jpg?alt=media&token=d8e94bdd-1477-49f3-b244-dd7a9c059fc1",
+      releaseYear: 1982,
+      genre: "sci-fi",
+      rating: 8.1,
+      description: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity.",
+      tags: ["sci-fi", "thriller"]
+    }
+  ])
 }
diff --git a/dataconnect/dataconnect/2_actor_insert.gql b/dataconnect/dataconnect/2_actor_insert.gql
index 971cb1007..6922dcf15 100644
--- a/dataconnect/dataconnect/2_actor_insert.gql
+++ b/dataconnect/dataconnect/2_actor_insert.gql
@@ -1,141 +1,104 @@
 mutation {
-  actor1: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174000",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdicaprio.jpeg?alt=media&token=452e030a-efa5-4ef4-bb81-502b23241316",
-    name: "Leonardo DiCaprio",
-    biography: "Leonardo DiCaprio is an American actor and producer. He has received numerous awards, including an Academy Award and three Golden Globe Awards. DiCaprio is known for his roles in Titanic, Inception, and The Revenant."
-  })
-  
-  actor2: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174001",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fkeanu.jpg?alt=media&token=6056520c-ef3e-4823-aad0-108aab163115",
-    name: "Keanu Reeves",
-    biography: "Keanu Reeves is a Canadian actor known for his roles in The Matrix and John Wick series. He has gained acclaim for his versatility and has also directed and produced several films."
-  })
-  
-  actor3: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174002",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fmcconaoghey.jpg?alt=media&token=d340ca18-ef51-44ac-a160-08e45b242cd7",
-    name: "Matthew McConaughey",
-    biography: "Matthew McConaughey is an American actor and producer. He gained fame with his breakout role in Dazed and Confused and has won an Academy Award for his performance in Dallas Buyers Club."
-  })
-
-  actor4: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174003",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fbale.jpg?alt=media&token=666f1690-a550-458f-a1cf-9505b7d1af7d",
-    name: "Christian Bale",
-    biography: "Christian Bale is an English actor known for his versatility and physical transformations for roles. He has starred in The Dark Knight Trilogy and won an Academy Award for The Fighter."
-  })
-
-  actor5: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174004",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fpitt.jpeg?alt=media&token=3a5283d4-f85c-4ba7-be72-51bc87ca4133",
-    name: "Brad Pitt",
-    biography: "Brad Pitt is an American actor and producer. He has won two Academy Awards and is known for his roles in Fight Club, Ocean's Eleven, and Once Upon a Time in Hollywood."
-  })
-
-  actor6: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174005",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fjackson.jpg?alt=media&token=07be0601-19fe-4b5d-b111-84fa71f32139",
-    name: "Samuel L. Jackson",
-    biography: "Samuel L. Jackson is an American actor and producer. He is one of the most widely recognized actors of his generation, known for his roles in Pulp Fiction, the Marvel Cinematic Universe, and Jurassic Park."
-  })
-
-  actor7: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174006",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fmortensen.jpeg?alt=media&token=e3d1ec99-b8e7-42e9-9d1c-03f56f61ecf7",
-    name: "Viggo Mortensen",
-    biography: "Viggo Mortensen is an American actor, author, and musician. He is best known for his role as Aragorn in The Lord of the Rings trilogy and has been nominated for three Academy Awards."
-  })
-
-  actor8: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174007",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Ffreeman.jpg?alt=media&token=94bc6227-119e-4ab0-b350-55fac7aeb062",
-    name: "Morgan Freeman",
-    biography: "Morgan Freeman is an American actor, director, and narrator. He is known for his distinctive voice and has won an Academy Award for his role in Million Dollar Baby."
-  })
-
-  actor9: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174008",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fhanks.jpeg?alt=media&token=d92979ce-da62-4b28-afbe-b8740bbb9d32",
-    name: "Tom Hanks",
-    biography: "Tom Hanks is an American actor and filmmaker. He is known for his roles in Forrest Gump, Saving Private Ryan, and Toy Story, and has won two Academy Awards for Best Actor."
-  })
-
-  actor10: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174009",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fpacino.jpg?alt=media&token=9c0c54b1-6913-48b5-8e5e-d6551dd2f182",
-    name: "Al Pacino",
-    biography: "Al Pacino is an American actor and filmmaker. He has won an Academy Award, two Tony Awards, and two Primetime Emmy Awards. He is known for his roles in The Godfather series, Scarface, and Scent of a Woman."
-  })
-
-  actor11: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174010",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Ffoster.jpg?alt=media&token=b429734c-0f2d-4840-b75b-6857eac7bb4f",
-    name: "Jodie Foster",
-    biography: "Jodie Foster is an American actress and director. She has won two Academy Awards for Best Actress for her roles in The Accused and The Silence of the Lambs."
-  })
-
-  actor12: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174011",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fcruise.jpg?alt=media&token=d34b0326-a8d1-4f01-86e5-f3f094594e5a",
-    name: "Tom Cruise",
-    biography: "Tom Cruise is an American actor and producer. He is one of the highest-paid actors in the world and is known for his roles in Top Gun, the Mission: Impossible series, and Jerry Maguire."
-  })
-
-  actor13: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174012",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdowney.jpg?alt=media&token=dd291c96-6ef0-42fc-841c-902c80748b37",
-    name: "Robert Downey Jr.",
-    biography: "Robert Downey Jr. is an American actor and producer. He is known for his roles in Iron Man, Sherlock Holmes, and Chaplin, and has been a major figure in the Marvel Cinematic Universe."
-  })
-
-  actor14: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174013",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fcrowe.jpg?alt=media&token=46d413d5-ace8-404e-b018-8d7e6fe0d362",
-    name: "Russell Crowe",
-    biography: "Russell Crowe is an Australian actor, film producer, and musician. He gained international fame for his role in Gladiator, for which he won the Academy Award for Best Actor."
-  })
-
-  actor15: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174014",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fwinslet.jpg?alt=media&token=b675585e-356e-4361-a041-5ac1a6ee5922",
-    name: "Kate Winslet",
-    biography: "Kate Winslet is an English actress known for her roles in Titanic, The Reader, and Eternal Sunshine of the Spotless Mind. She has won numerous awards, including an Academy Award and an Emmy."
-  })
-
-  actor16: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174015",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fweaver.jpeg?alt=media&token=263b5c3d-e0ee-43c3-854d-9b236c6df391",
-    name: "Sigourney Weaver",
-    biography: "Sigourney Weaver is an American actress best known for her roles in the Alien franchise, Ghostbusters, and Avatar. She has been nominated for three Academy Awards and has won two Golden Globe Awards."
-  })
-
-  actor17: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174016",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fgoldblume.jpeg?alt=media&token=18277dd1-166c-4934-a02e-19ef141c86e2",
-    name: "Jeff Goldblum",
-    biography: "Jeff Goldblum is an American actor and musician known for his roles in Jurassic Park, Independence Day, and The Fly. His unique delivery and eccentric characters have made him a cult icon."
-  })
-
-  actor18: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174017",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fjones.jpg?alt=media&token=f7ac9bc4-6e26-4b25-9a73-7a90f699424e",
-    name: "James Earl Jones",
-    biography: "James Earl Jones is an American actor known for his deep resonant voice, which has been featured in roles such as Darth Vader in Star Wars and Mufasa in The Lion King. He has won multiple awards, including a Tony, Emmy, and Grammy."
-  })
-
-  actor19: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174018",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fford.jpg?alt=media&token=928434c0-d492-4c8e-bdf0-0db585008d87",
-    name: "Harrison Ford",
-    biography: "Harrison Ford is an American actor known for his iconic roles as Han Solo in Star Wars and Indiana Jones in the Indiana Jones series. He has been nominated for an Academy Award and has received numerous other accolades."
-  })
-
-  actor20: actor_insert(data: {
-    id: "123e4567-e89b-12d3-a456-426614174019",
-    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fschwarzenegger.jpeg?alt=media&token=c46fb249-41ef-4084-b4ad-9517bee6ab46",
-    name: "Arnold Schwarzenegger",
-    biography: "Arnold Schwarzenegger is an Austrian-American actor, businessman, and former politician. He is best known for his roles in The Terminator series and Total Recall, and for serving as the 38th Governor of California."
-  })
+  actor_insertMany(data: [
+    {
+      id: "123e4567-e89b-12d3-a456-426614174000",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdicaprio.jpeg?alt=media&token=452e030a-efa5-4ef4-bb81-502b23241316",
+      name: "Leonardo DiCaprio"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174001",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fkeanu.jpg?alt=media&token=6056520c-ef3e-4823-aad0-108aab163115",
+      name: "Keanu Reeves"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174002",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fmcconaoghey.jpg?alt=media&token=d340ca18-ef51-44ac-a160-08e45b242cd7",
+      name: "Matthew McConaughey"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174003",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fbale.jpg?alt=media&token=666f1690-a550-458f-a1cf-9505b7d1af7d",
+      name: "Christian Bale"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174004",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fpitt.jpeg?alt=media&token=3a5283d4-f85c-4ba7-be72-51bc87ca4133",
+      name: "Brad Pitt"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174005",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fjackson.jpg?alt=media&token=07be0601-19fe-4b5d-b111-84fa71f32139",
+      name: "Samuel L. Jackson"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174006",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fmortensen.jpeg?alt=media&token=e3d1ec99-b8e7-42e9-9d1c-03f56f61ecf7",
+      name: "Viggo Mortensen"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174007",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Ffreeman.jpg?alt=media&token=94bc6227-119e-4ab0-b350-55fac7aeb062",
+      name: "Morgan Freeman"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174008",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fhanks.jpeg?alt=media&token=d92979ce-da62-4b28-afbe-b8740bbb9d32",
+      name: "Tom Hanks"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174009",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fpacino.jpg?alt=media&token=9c0c54b1-6913-48b5-8e5e-d6551dd2f182",
+      name: "Al Pacino"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174010",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Ffoster.jpg?alt=media&token=b429734c-0f2d-4840-b75b-6857eac7bb4f",
+      name: "Jodie Foster"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174011",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fcruise.jpg?alt=media&token=d34b0326-a8d1-4f01-86e5-f3f094594e5a",
+      name: "Tom Cruise"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174012",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdowney.jpg?alt=media&token=dd291c96-6ef0-42fc-841c-902c80748b37",
+      name: "Robert Downey Jr."
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174013",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fcrowe.jpg?alt=media&token=46d413d5-ace8-404e-b018-8d7e6fe0d362",
+      name: "Russell Crowe"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174014",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fwinslet.jpg?alt=media&token=b675585e-356e-4361-a041-5ac1a6ee5922",
+      name: "Kate Winslet"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174015",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fweaver.jpeg?alt=media&token=263b5c3d-e0ee-43c3-854d-9b236c6df391",
+      name: "Sigourney Weaver"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174016",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fgoldblume.jpeg?alt=media&token=18277dd1-166c-4934-a02e-19ef141c86e2",
+      name: "Jeff Goldblum"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174017",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fjones.jpg?alt=media&token=f7ac9bc4-6e26-4b25-9a73-7a90f699424e",
+      name: "James Earl Jones"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174018",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fford.jpg?alt=media&token=928434c0-d492-4c8e-bdf0-0db585008d87",
+      name: "Harrison Ford"
+    },
+    {
+      id: "123e4567-e89b-12d3-a456-426614174019",
+      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fschwarzenegger.jpeg?alt=media&token=c46fb249-41ef-4084-b4ad-9517bee6ab46",
+      name: "Arnold Schwarzenegger"
+    }
+  ])
 }
diff --git a/dataconnect/dataconnect/3_movie_actor_insert.gql b/dataconnect/dataconnect/3_movie_actor_insert.gql
index b8a270541..c2256acc8 100644
--- a/dataconnect/dataconnect/3_movie_actor_insert.gql
+++ b/dataconnect/dataconnect/3_movie_actor_insert.gql
@@ -1,283 +1,238 @@
 mutation {
-  metadata1: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440000",
-    director: "Christopher Nolan"
-  })
-  
-  metadata2: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440001",
-    director: "Lana Wachowski, Lilly Wachowski"
-  })
-  
-  metadata3: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440002",
-    director: "Chad Stahelski"
-  })
-
-  metadata4: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440003",
-    director: "Christopher Nolan"
-  })
-
-  metadata5: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440004",
-    director: "David Fincher"
-  })
-
-  metadata6: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440005",
-    director: "Quentin Tarantino"
-  })
-
-  metadata7: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440006",
-    director: "Peter Jackson"
-  })
-
-  metadata8: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440007",
-    director: "Frank Darabont"
-  })
-
-  metadata9: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440008",
-    director: "Robert Zemeckis"
-  })
-
-  metadata10: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440009",
-    director: "Francis Ford Coppola"
-  })
-
-  metadata11: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440010",
-    director: "Jonathan Demme"
-  })
-
-  metadata12: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440011",
-    director: "Steven Spielberg"
-  })
-
-  metadata13: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440012",
-    director: "Joss Whedon"
-  })
-
-  metadata14: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440013",
-    director: "Ridley Scott"
-  })
-
-  metadata15: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440014",
-    director: "James Cameron"
-  })
-
-  metadata16: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440015",
-    director: "James Cameron"
-  })
-
-  metadata17: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440016",
-    director: "Steven Spielberg"
-  })
-
-  metadata18: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440017",
-    director: "Roger Allers, Rob Minkoff"
-  })
-
-  metadata19: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440018",
-    director: "George Lucas"
-  })
-
-  metadata20: movieMetadata_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440019",
-    director: "Ridley Scott"
-  })
-
-  movieActor1: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440000",
-    actorId: "123e4567-e89b-12d3-a456-426614174000",
-    role: "main"
-  })
-  
-  movieActor2: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440001",
-    actorId: "123e4567-e89b-12d3-a456-426614174001",
-    role: "main"
-  })
-  
-  movieActor3: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440002",
-    actorId: "123e4567-e89b-12d3-a456-426614174001",
-    role: "main"
-  })
-
-  movieActor4: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440003",
-    actorId: "123e4567-e89b-12d3-a456-426614174003",
-    role: "main"
-  })
-
-  movieActor5: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440004",
-    actorId: "123e4567-e89b-12d3-a456-426614174004",
-    role: "main"
-  })
-
-  movieActor6: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440005",
-    actorId: "123e4567-e89b-12d3-a456-426614174005",
-    role: "main"
-  })
-
-  movieActor7: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440006",
-    actorId: "123e4567-e89b-12d3-a456-426614174006",
-    role: "main"
-  })
-
-  movieActor8: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440007",
-    actorId: "123e4567-e89b-12d3-a456-426614174007",
-    role: "main"
-  })
-
-  movieActor9: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440008",
-    actorId: "123e4567-e89b-12d3-a456-426614174008",
-    role: "main"
-  })
-
-  movieActor10: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440009",
-    actorId: "123e4567-e89b-12d3-a456-426614174009",
-    role: "main"
-  })
-
-  movieActor11: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440010",
-    actorId: "123e4567-e89b-12d3-a456-426614174010",
-    role: "main"
-  })
-
-  movieActor12: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440011",
-    actorId: "123e4567-e89b-12d3-a456-426614174011",
-    role: "main"
-  })
-
-  movieActor13: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440012",
-    actorId: "123e4567-e89b-12d3-a456-426614174012",
-    role: "main"
-  })
-
-  movieActor14: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440013",
-    actorId: "123e4567-e89b-12d3-a456-426614174013",
-    role: "main"
-  })
-
-  movieActor15: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440014",
-    actorId: "123e4567-e89b-12d3-a456-426614174014",
-    role: "main"
-  })
-
-  movieActor16: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440015",
-    actorId: "123e4567-e89b-12d3-a456-426614174015",
-    role: "main"
-  })
-
-  movieActor17: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440016",
-    actorId: "123e4567-e89b-12d3-a456-426614174016",
-    role: "main"
-  })
-
-  movieActor18: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440017",
-    actorId: "123e4567-e89b-12d3-a456-426614174017",
-    role: "main"
-  })
-
-  movieActor19: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440018",
-    actorId: "123e4567-e89b-12d3-a456-426614174018",
-    role: "main"
-  })
-
-  movieActor20: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440019",
-    actorId: "123e4567-e89b-12d3-a456-426614174019",
-    role: "main"
-  })
-
-  # Adding supporting actors
-  movieActor21: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440000",
-    actorId: "123e4567-e89b-12d3-a456-426614174001",
-    role: "supporting"
-  })
-  
-  movieActor22: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440001",
-    actorId: "123e4567-e89b-12d3-a456-426614174002",
-    role: "supporting"
-  })
-  
-  movieActor23: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440002",
-    actorId: "123e4567-e89b-12d3-a456-426614174003",
-    role: "supporting"
-  })
-
-  movieActor24: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440003",
-    actorId: "123e4567-e89b-12d3-a456-426614174004",
-    role: "supporting"
-  })
-
-  movieActor25: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440004",
-    actorId: "123e4567-e89b-12d3-a456-426614174005",
-    role: "supporting"
-  })
-
-  movieActor26: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440005",
-    actorId: "123e4567-e89b-12d3-a456-426614174006",
-    role: "supporting"
-  })
-
-  movieActor27: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440006",
-    actorId: "123e4567-e89b-12d3-a456-426614174007",
-    role: "supporting"
-  })
-
-  movieActor28: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440007",
-    actorId: "123e4567-e89b-12d3-a456-426614174008",
-    role: "supporting"
-  })
-
-  movieActor29: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440008",
-    actorId: "123e4567-e89b-12d3-a456-426614174009",
-    role: "supporting"
-  })
-
-  movieActor30: movieActor_insert(data: {
-    movieId: "550e8400-e29b-41d4-a716-446655440009",
-    actorId: "123e4567-e89b-12d3-a456-426614174010",
-    role: "supporting"
-  })
-
+  movieMetadata_insertMany(data: [
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440000",
+      director: "Christopher Nolan"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440001",
+      director: "Lana Wachowski, Lilly Wachowski"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440002",
+      director: "Chad Stahelski"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440003",
+      director: "Christopher Nolan"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440004",
+      director: "David Fincher"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440005",
+      director: "Quentin Tarantino"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440006",
+      director: "Peter Jackson"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440007",
+      director: "Frank Darabont"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440008",
+      director: "Robert Zemeckis"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440009",
+      director: "Francis Ford Coppola"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440010",
+      director: "Jonathan Demme"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440011",
+      director: "Steven Spielberg"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440012",
+      director: "Joss Whedon"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440013",
+      director: "Ridley Scott"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440014",
+      director: "James Cameron"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440015",
+      director: "James Cameron"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440016",
+      director: "Steven Spielberg"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440017",
+      director: "Roger Allers, Rob Minkoff"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440018",
+      director: "George Lucas"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440019",
+      director: "Ridley Scott"
+    }
+  ])
+
+  movieActor_insertMany(data: [
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440000",
+      actorId: "123e4567-e89b-12d3-a456-426614174000",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440001",
+      actorId: "123e4567-e89b-12d3-a456-426614174001",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440002",
+      actorId: "123e4567-e89b-12d3-a456-426614174001",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440003",
+      actorId: "123e4567-e89b-12d3-a456-426614174003",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440004",
+      actorId: "123e4567-e89b-12d3-a456-426614174004",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440005",
+      actorId: "123e4567-e89b-12d3-a456-426614174005",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440006",
+      actorId: "123e4567-e89b-12d3-a456-426614174006",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440007",
+      actorId: "123e4567-e89b-12d3-a456-426614174007",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440008",
+      actorId: "123e4567-e89b-12d3-a456-426614174008",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440009",
+      actorId: "123e4567-e89b-12d3-a456-426614174009",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440010",
+      actorId: "123e4567-e89b-12d3-a456-426614174010",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440011",
+      actorId: "123e4567-e89b-12d3-a456-426614174011",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440012",
+      actorId: "123e4567-e89b-12d3-a456-426614174012",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440013",
+      actorId: "123e4567-e89b-12d3-a456-426614174013",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440014",
+      actorId: "123e4567-e89b-12d3-a456-426614174014",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440015",
+      actorId: "123e4567-e89b-12d3-a456-426614174015",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440016",
+      actorId: "123e4567-e89b-12d3-a456-426614174016",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440017",
+      actorId: "123e4567-e89b-12d3-a456-426614174017",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440018",
+      actorId: "123e4567-e89b-12d3-a456-426614174018",
+      role: "main"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440019",
+      actorId: "123e4567-e89b-12d3-a456-426614174019",
+      role: "main"
+    },
+    # Supporting actors
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440000",
+      actorId: "123e4567-e89b-12d3-a456-426614174001",
+      role: "supporting"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440001",
+      actorId: "123e4567-e89b-12d3-a456-426614174002",
+      role: "supporting"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440002",
+      actorId: "123e4567-e89b-12d3-a456-426614174003",
+      role: "supporting"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440003",
+      actorId: "123e4567-e89b-12d3-a456-426614174004",
+      role: "supporting"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440004",
+      actorId: "123e4567-e89b-12d3-a456-426614174005",
+      role: "supporting"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440005",
+      actorId: "123e4567-e89b-12d3-a456-426614174006",
+      role: "supporting"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440006",
+      actorId: "123e4567-e89b-12d3-a456-426614174007",
+      role: "supporting"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440007",
+      actorId: "123e4567-e89b-12d3-a456-426614174008",
+      role: "supporting"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440008",
+      actorId: "123e4567-e89b-12d3-a456-426614174009",
+      role: "supporting"
+    },
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440009",
+      actorId: "123e4567-e89b-12d3-a456-426614174010",
+      role: "supporting"
+    }
+  ])
 }
diff --git a/dataconnect/dataconnect/4_user_favorites_review_insert.gql b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
index 70bf8fa23..27a9a64a8 100644
--- a/dataconnect/dataconnect/4_user_favorites_review_insert.gql
+++ b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
@@ -1,184 +1,121 @@
 mutation {
-  user1: user_insert(data: {
-    id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-    username: "cynthia_w"
-  })
-  
-  user2: user_insert(data: {
-    id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-    username: "momo_h"
-  })
-  
-  user3: user_insert(data: {
-    id: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-    username: "siyi_w"
-  })
-
-  review1: review_insert(data: {
-    id: "345e4567-e89b-12d3-a456-426614174000",
-
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-    movieId: "550e8400-e29b-41d4-a716-446655440000",
-    rating: 5,
-    reviewText: "An incredible movie with a mind-blowing plot!",
-    reviewDate_date: { today: true }
-  })
-  
-  review2: review_insert(data: {
-    id: "345e4567-e89b-12d3-a456-426614174001",
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440001",
-    rating: 5,
-    reviewText: "A revolutionary film that changed cinema forever.",
-    reviewDate_date: { today: true }
-  })
-  
-  review3: review_insert(data: {
-    id: "345e4567-e89b-12d3-a456-426614174002",
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440002",
-    rating: 5,
-    reviewText: "A visually stunning and emotionally impactful movie.",
-    reviewDate_date: { today: true }
-  })
-
-  review4: review_insert(data: {
-    id: "345e4567-e89b-12d3-a456-426614174003",
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440003",
-    rating: 4,
-    reviewText: "A fantastic superhero film with great performances.",
-    reviewDate_date: { today: true }
-  })
-
-  review5: review_insert(data: {
-    id: "345e4567-e89b-12d3-a456-426614174004",
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440004",
-    rating: 5,
-    reviewText: "An amazing film that keeps you on the edge of your seat.",
-    reviewDate_date: { today: true }
-  })
-
-  review6: review_insert(data: {
-    id: "345e4567-e89b-12d3-a456-426614174005",
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440005",
-    rating: 5,
-    reviewText: "An absolute classic with unforgettable dialogue.",
-    reviewDate_date: { today: true }
-  })
-
-  favoriteMovie1: favoriteMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440000"
-  })
-  
-  favoriteMovie2: favoriteMovie_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440001"
-  })
-  
-  favoriteMovie3: favoriteMovie_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440002"
-  })
-
-  favoriteMovie4: favoriteMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440003"
-  })
-
-  favoriteMovie5: favoriteMovie_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440004"
-  })
-
-  favoriteMovie6: favoriteMovie_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440005"
-  })
-
-  favoriteActor1: favoriteActor_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-
-    actorId: "123e4567-e89b-12d3-a456-426614174000"
-  })
-  
-  favoriteActor2: favoriteActor_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-
-    actorId: "123e4567-e89b-12d3-a456-426614174001"
-  })
-  
-  favoriteActor3: favoriteActor_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-
-    actorId: "123e4567-e89b-12d3-a456-426614174002"
-  })
-
-  favoriteActor4: favoriteActor_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-
-    actorId: "123e4567-e89b-12d3-a456-426614174003"
-  })
-
-  favoriteActor5: favoriteActor_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-
-    actorId: "123e4567-e89b-12d3-a456-426614174004"
-  })
-
-  favoriteActor6: favoriteActor_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-
-    actorId: "123e4567-e89b-12d3-a456-426614174005"
-  })
-
-  watchedMovie1: watchedMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440000"
-  })
-  
-  watchedMovie2: watchedMovie_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440001"
-  })
-  
-  watchedMovie3: watchedMovie_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440002"
-  })
-
-  watchedMovie4: watchedMovie_insert(data: {
-    userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440003"
-  })
-
-  watchedMovie5: watchedMovie_insert(data: {
-    userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440004"
-  })
-
-  watchedMovie6: watchedMovie_insert(data: {
-    userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-
-    movieId: "550e8400-e29b-41d4-a716-446655440005"
-  })
+  user_insertMany(data: [
+    {
+      id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+      username: "cynthia_w"
+    },
+    {
+      id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+      username: "hercule_p"
+    },
+    {
+      id: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+      username: "jane_d"
+    }
+  ])
+
+  review_insertMany(data: [
+    {
+      id: "345e4567-e89b-12d3-a456-426614174000",
+      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+      movieId: "550e8400-e29b-41d4-a716-446655440000",
+      rating: 5,
+      reviewText: "An incredible movie with a mind-blowing plot!",
+      reviewDate_date: { today: true }
+    },
+    {
+      id: "345e4567-e89b-12d3-a456-426614174001",
+      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+      movieId: "550e8400-e29b-41d4-a716-446655440001",
+      rating: 5,
+      reviewText: "A revolutionary film that changed cinema forever.",
+      reviewDate_date: { today: true }
+    },
+    {
+      id: "345e4567-e89b-12d3-a456-426614174002",
+      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+      movieId: "550e8400-e29b-41d4-a716-446655440002",
+      rating: 5,
+      reviewText: "A visually stunning and emotionally impactful movie.",
+      reviewDate_date: { today: true }
+    },
+    {
+      id: "345e4567-e89b-12d3-a456-426614174003",
+      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+      movieId: "550e8400-e29b-41d4-a716-446655440003",
+      rating: 4,
+      reviewText: "A fantastic superhero film with great performances.",
+      reviewDate_date: { today: true }
+    },
+    {
+      id: "345e4567-e89b-12d3-a456-426614174004",
+      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+      movieId: "550e8400-e29b-41d4-a716-446655440004",
+      rating: 5,
+      reviewText: "An amazing film that keeps you on the edge of your seat.",
+      reviewDate_date: { today: true }
+    },
+    {
+      id: "345e4567-e89b-12d3-a456-426614174005",
+      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+      movieId: "550e8400-e29b-41d4-a716-446655440005",
+      rating: 5,
+      reviewText: "An absolute classic with unforgettable dialogue.",
+      reviewDate_date: { today: true }
+    }
+  ])
+
+  favorite_movie_insertMany(data: [
+    {
+      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+      movieId: "550e8400-e29b-41d4-a716-446655440000"
+    },
+    {
+      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+      movieId: "550e8400-e29b-41d4-a716-446655440001"
+    },
+    {
+      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+      movieId: "550e8400-e29b-41d4-a716-446655440002"
+    },
+    {
+      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+      movieId: "550e8400-e29b-41d4-a716-446655440003"
+    },
+    {
+      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+      movieId: "550e8400-e29b-41d4-a716-446655440004"
+    },
+    {
+      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+      movieId: "550e8400-e29b-41d4-a716-446655440005"
+    }
+  ])
+
+  favorite_actor_insertMany(data: [
+    {
+      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+      actorId: "123e4567-e89b-12d3-a456-426614174000"
+    },
+    {
+      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+      actorId: "123e4567-e89b-12d3-a456-426614174001"
+    },
+    {
+      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+      actorId: "123e4567-e89b-12d3-a456-426614174002"
+    },
+    {
+      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
+      actorId: "123e4567-e89b-12d3-a456-426614174003"
+    },
+    {
+      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
+      actorId: "123e4567-e89b-12d3-a456-426614174004"
+    },
+    {
+      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
+      actorId: "123e4567-e89b-12d3-a456-426614174005"
+    }
+  ])
 }
diff --git a/dataconnect/dataconnect/5_optional_vector_embed.gql b/dataconnect/dataconnect/5_optional_vector_embed.gql
new file mode 100644
index 000000000..76b11da60
--- /dev/null
+++ b/dataconnect/dataconnect/5_optional_vector_embed.gql
@@ -0,0 +1,141 @@
+mutation updateMovieEmbeddings {
+  movie1: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440000"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move."}
+    }
+  )
+  
+  movie2: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440001"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny."}
+    }
+  )
+  
+  movie3: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440002"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances."}
+    }
+  )
+
+  movie4: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440003"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice."}
+    }
+  )
+
+  movie5: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440004"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity."}
+    }
+  )
+
+  movie6: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440005"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references."}
+    }
+  )
+
+  movie7: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440006"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond."}
+    }
+  )
+
+  movie8: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440007"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman)."}
+    }
+  )
+
+  movie9: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440008"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright)."}
+    }
+  )
+
+  movie10: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440009"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal."}
+    }
+  )
+
+  movie11: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440010"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer."}
+    }
+  )
+
+  movie12: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440011"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war."}
+    }
+  )
+ 
+  movie13: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440012"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast."}
+    }
+  )
+
+  movie14: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440013"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance."}
+    }
+  )
+
+  movie15: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440014"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals."}
+    }
+  )
+
+  movie16: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440015"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience."}
+    }
+  )
+
+  movie17: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440016"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures."}
+    }
+  )
+
+  movie18: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440017"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption."}
+    }
+  )
+
+  movie19: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440018"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters."}
+    }
+  )
+
+  movie20: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440019"
+    data: {
+      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity."}
+    }
+  )
+}
diff --git a/dataconnect/dataconnect/connector/queries.gql b/dataconnect/dataconnect/connector/queries.gql
deleted file mode 100644
index 158874ef9..000000000
--- a/dataconnect/dataconnect/connector/queries.gql
+++ /dev/null
@@ -1,576 +0,0 @@
-# List subset of fields for movies
-query ListMovies @auth(level: PUBLIC) {
-  movies {
-    id
-    title
-    imageUrl
-    releaseYear
-    genre
-    rating
-    tags
-    description
-  }
-}
-
-
-# List subset of fields for users
-query ListUsers @auth(level: PUBLIC) {
-  users {
-    id
-    username
-    favoriteActors: favoriteActors_on_user {
-      actor {
-        id
-        name
-        imageUrl
-      }
-    }
-    favoriteMovies: favoriteMovies_on_user {
-      movie {
-        id
-        title
-        genre
-        imageUrl
-        tags
-      }
-    }
-    reviews_on_user {
-      id
-      rating
-      reviewText
-      reviewDate
-      movie {
-        id
-        title
-      }
-    }
-    watchedMovies_on_user {
-      movie {
-        id
-        title
-        genre
-        imageUrl
-      }
-    }
-  }
-}
-
-# List movies of a certain genre
-query ListMoviesByGenre($genre: String!) @auth(level: PUBLIC) {
-  mostPopular: movies(
-    where: { genre: { eq: $genre } }
-    orderBy: { rating: DESC }
-  ) {
-    id
-    title
-    imageUrl
-    rating
-    tags
-  }
-  mostRecent: movies(
-    where: { genre: { eq: $genre } }
-    orderBy: { releaseYear: DESC }
-  ) {
-    id
-    title
-    imageUrl
-    rating
-    tags
-  }
-}
-
-# List movies by the order of release
-query ListMoviesByReleaseYear @auth(level: PUBLIC) {
-  movies(orderBy: [{ releaseYear: DESC }]) {
-    id
-    title
-    imageUrl
-  }
-}
-
-# Get movie by id
-query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
-  movie(id: $id) {
-    id
-    title
-    imageUrl
-    releaseYear
-    genre
-    rating
-    description
-    tags
-    metadata: movieMetadatas_on_movie {
-      director
-    }
-    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
-      id
-      name
-      imageUrl
-    }
-    supportingActors: actors_via_MovieActor(
-      where: { role: { eq: "supporting" } }
-    ) {
-      id
-      name
-      imageUrl
-    }
-    sequelTo {
-      id
-      title
-      imageUrl
-    }
-    reviews: reviews_on_movie {
-      id
-      reviewText
-      reviewDate
-      rating
-      user {
-        id
-        username
-      }
-    }
-  }
-}
-
-# Get actor by id
-query GetActorById($id: UUID!) @auth(level: PUBLIC) {
-  actor(id: $id) {
-    id
-    name
-    imageUrl
-    biography
-    mainActors: movies_via_MovieActor(where: { role: { eq: "main" } }) {
-      id
-      title
-      genre
-      tags
-      imageUrl
-    }
-    supportingActors: movies_via_MovieActor(
-      where: { role: { eq: "supporting" } }
-    ) {
-      id
-      title
-      genre
-      tags
-      imageUrl
-    }
-  }
-}
-
-# User movie preferences
-query UserMoviePreferences($username: String!) @auth(level: USER) {
-  users(where: { username: { eq: $username } }) {
-    likedMovies: movies_via_Review(where: { rating: { ge: 4 } }) {
-      title
-      imageUrl
-      genre
-      description
-    }
-    dislikedMovies: movies_via_Review(where: { rating: { le: 2 } }) {
-      title
-      imageUrl
-      genre
-      description
-    }
-  }
-}
-
-# Get movie metadata
-query GetMovieMetadata($id: UUID!) @auth(level: PUBLIC) {
-  movie(id: $id) {
-    movieMetadatas_on_movie {
-      director
-    }
-  }
-}
-
-# Get movie cast and actor roles
-query GetMovieCast($movieId: UUID!, $actorId: UUID!) @auth(level: PUBLIC) {
-  movie(id: $movieId) {
-    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
-      id
-      name
-      imageUrl
-    }
-    supportingActors: actors_via_MovieActor(
-      where: { role: { eq: "supporting" } }
-    ) {
-      id
-      name
-      imageUrl
-    }
-  }
-  actor(id: $actorId) {
-    mainRoles: movies_via_MovieActor(where: { role: { eq: "main" } }) {
-      id
-      title
-      imageUrl
-    }
-    supportingRoles: movies_via_MovieActor(
-      where: { role: { eq: "supporting" } }
-    ) {
-      id
-      title
-      imageUrl
-    }
-  }
-}
-
-# List movies by partial title match
-query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
-  movies(where: { title: { contains: $input } }) {
-    id
-    title
-    genre
-    rating
-    imageUrl
-  }
-}
-
-# Fetch a single movie using key scalars (same as get movie by id)
-query MovieByKey($key: Movie_Key!) @auth(level: PUBLIC) {
-  movie(key: $key) {
-    title
-    imageUrl
-  }
-}
-
-# Fetch movies by title
-query MovieByTitle($title: String!) @auth(level: PUBLIC) {
-  movies(where: { title: { eq: $title } }) {
-    id
-    title
-    imageUrl
-    genre
-    rating
-  }
-}
-
-# Fetch top-rated movies by genre
-query MovieByTopRating($genre: String) @auth(level: PUBLIC) {
-  mostPopular: movies(
-    where: { genre: { eq: $genre } }
-    orderBy: { rating: DESC }
-  ) {
-    id
-    title
-    imageUrl
-    rating
-    tags
-  }
-}
-
-# List movies by tag
-query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
-  movies(where: { tags: { includes: $tag } }) {
-    id
-    title
-    imageUrl
-    genre
-    rating
-  }
-}
-
-# List top 10 movies
-query MoviesTop10 @auth(level: PUBLIC) {
-  movies(orderBy: [{ rating: DESC }], limit: 10) {
-    id
-    title
-    imageUrl
-    rating
-    genre
-    tags
-    metadata: movieMetadatas_on_movie {
-      director
-    }
-    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
-      id
-      name
-      imageUrl
-    }
-    supportingActors: actors_via_MovieActor(where: { role: { eq: "supporting" } }) {
-      id
-      name
-      imageUrl
-    }
-  }
-}
-
-# List movies by release year range
-query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
-  movies(
-    where: { releaseYear: { le: $max, ge: $min } }
-    orderBy: [{ releaseYear: ASC }]
-  ) {
-    id
-    rating
-    title
-    imageUrl
-  }
-}
-
-# List recently released movies
-query MoviesRecentlyReleased @auth(level: PUBLIC) {
-  movies(where: { releaseYear: { ge: 2010 } }) {
-    id
-    title
-    rating
-    imageUrl
-    genre
-    tags
-  }
-}
-
-# List movies with filtering on fields
-query ListMoviesFilter($genre: String, $limit: Int) @auth(level: PUBLIC) {
-  movies(where: { genre: { eq: $genre } }, limit: $limit) {
-    title
-    imageUrl
-  }
-}
-
-# List movies by partial title string match
-query ListMoviesByTitleString(
-  $prefix: String
-  $suffix: String
-  $contained: String
-) @auth(level: PUBLIC) {
-  prefixed: movies(where: { description: { startsWith: $prefix } }) {
-    title
-  }
-  suffixed: movies(where: { description: { endsWith: $suffix } }) {
-    title
-  }
-  contained: movies(where: { description: { contains: $contained } }) {
-    title
-  }
-}
-
-# List movies by rating and genre with OR/AND filters
-query ListMoviesByRatingAndGenre($minRating: Float!, $genre: String)
-@auth(level: PUBLIC) {
-  movies(
-    where: { _or: [{ rating: { ge: $minRating } }, { genre: { eq: $genre } }] }
-  ) {
-    title
-    imageUrl
-  }
-}
-
-# Get favorite movies by user ID
-query GetFavoriteMoviesById($id: String!) @auth(level: USER) {
-  user(id: $id) {
-    favoriteMovies_on_user {
-      movie {
-        id
-        title
-        genre
-        imageUrl
-        releaseYear
-        rating
-        description
-      }
-    }
-  }
-}
-
-# Get favorite actors by user ID
-query GetFavoriteActorsById($id: String!) @auth(level: USER) {
-  user(id: $id) {
-    favoriteActors_on_user {
-      actor {
-        id
-        name
-        imageUrl
-      }
-    }
-  }
-}
-
-# Get watched movies by user ID
-query GetWatchedMoviesByAuthId($id: String!) @auth(level: USER) {
-  user(id: $id) {
-    watchedMovies_on_user {
-      movie {
-        id
-        title
-        genre
-        imageUrl
-        releaseYear
-        rating
-        description
-      }
-    }
-  }
-}
-
-# Get user by ID
-query GetUserById($id: String!) @auth(level: USER) {
-  user(id: $id) {
-    id
-    username
-    reviews: reviews_on_user {
-      id
-      rating
-      reviewDate
-      reviewText
-      movie {
-        id
-        title
-      }
-    }
-    watched: watchedMovies_on_user {
-      movie {
-        id
-        title
-        genre
-        imageUrl
-        releaseYear
-        rating
-        description
-        tags
-        metadata: movieMetadatas_on_movie {
-          director
-        }
-      }
-    }
-    favoriteMovies: favoriteMovies_on_user {
-      movie {
-        id
-        title
-        genre
-        imageUrl
-        releaseYear
-        rating
-        description
-        tags
-        metadata: movieMetadatas_on_movie {
-          director
-        }
-      }
-    }
-    favoriteActors: favoriteActors_on_user {
-      actor {
-        id
-        name
-        imageUrl
-      }
-    }
-  }
-}
-
-# Check if a movie is watched by user
-query GetIfWatched($id: String!, $movieId: UUID!) @auth(level: USER) {
-  watchedMovie(key: { userId: $id, movieId: $movieId }) {
-    movieId
-  }
-}
-
-# Check if a movie is favorited by user
-query GetIfFavoritedMovie($id: String!, $movieId: UUID!) @auth(level: USER) {
-  favoriteMovie(key: { userId: $id, movieId: $movieId }) {
-    movieId
-  }
-}
-
-# Check if an actor is favorited by user
-query GetIfFavoritedActor($id: String!, $actorId: UUID!) @auth(level: USER) {
-  favoriteActor(key: { userId: $id, actorId: $actorId }) {
-    actorId
-  }
-}
-
-# Fuzzy search for movies, actors, and reviews
-query fuzzySearch(
-  $input: String
-  $minYear: Int!
-  $maxYear: Int!
-  $minRating: Float!
-  $maxRating: Float!
-  $genre: String!
-) @auth(level: PUBLIC) {
-  moviesMatchingTitle: movies(
-    where: {
-      _and: [
-        { releaseYear: { ge: $minYear } }
-        { releaseYear: { le: $maxYear } }
-        { rating: { ge: $minRating } }
-        { rating: { le: $maxRating } }
-        { genre: { contains: $genre } }
-        { title: { contains: $input } }
-      ]
-    }
-  ) {
-    id
-    title
-    genre
-    rating
-    imageUrl
-  }
-  moviesMatchingDescription: movies(
-    where: {
-      _and: [
-        { releaseYear: { ge: $minYear } }
-        { releaseYear: { le: $maxYear } }
-        { rating: { ge: $minRating } }
-        { rating: { le: $maxRating } }
-        { genre: { contains: $genre } }
-        { description: { contains: $input } }
-      ]
-    }
-  ) {
-    id
-    title
-    genre
-    rating
-    imageUrl
-  }
-  actorsMatchingName: actors(where: { name: { contains: $input } }) {
-    id
-    name
-    imageUrl
-  }
-  reviewsMatchingText: reviews(where: { reviewText: { contains: $input } }) {
-    id
-    rating
-    reviewText
-    reviewDate
-    movie {
-      id
-      title
-    }
-    user {
-      id
-      username
-    }
-  }
-}
-
-# Search movie descriptions using L2 similarity with Vertex AI
-query searchMovieDescriptionUsingL2Similarity($query: String!)
-@auth(level: PUBLIC) {
-  movies_descriptionEmbedding_similarity(
-    compare_embed: { model: "textembedding-gecko@003", text: $query }
-    method: L2
-    within: 2
-    where: { description: { ne: "" } }
-    limit: 5
-  ) {
-    id
-    title
-    description
-    tags
-    rating
-    imageUrl
-  }
-}
-
-# Search movie descriptions using L2 similarity with Vertex AI, with custom embeddings
-query searchMovieDescriptionUsingL2Similarity1($compare: Vector!, $within: Float, $excludesContent: String, $limit: Int) @auth(level: PUBLIC) {
-    movies_descriptionEmbedding_similarity(compare: $compare, method: L2, within: $within, where: {description: {ne: $excludesContent}}, limit: $limit) {
-      id
-      title
-      description
-    }
-  }
diff --git a/dataconnect/dataconnect/dataconnect.yaml b/dataconnect/dataconnect/dataconnect.yaml
index 9dd8a336b..0b82e9d62 100644
--- a/dataconnect/dataconnect/dataconnect.yaml
+++ b/dataconnect/dataconnect/dataconnect.yaml
@@ -1,10 +1,11 @@
 specVersion: "v1alpha"
-serviceId: "dataconnect"
+serviceId: "your-dataconnect-service-id"
+location: "us-central1"
 schema:
   source: "./schema"
   datasource:
     postgresql:
-      database: "postgres"
+      database: "your-dataconnect-database"
       cloudSql:
-        instanceId: "your-instanceId"
-connectorDirs: ["./connector"]
+        instanceId: "your-dataconnect-id"
+connectorDirs: ["./movie-connector"]
diff --git a/dataconnect/dataconnect/connector/connector.yaml b/dataconnect/dataconnect/movie-connector/connector.yaml
similarity index 91%
rename from dataconnect/dataconnect/connector/connector.yaml
rename to dataconnect/dataconnect/movie-connector/connector.yaml
index 66d17e5e5..716396953 100644
--- a/dataconnect/dataconnect/connector/connector.yaml
+++ b/dataconnect/dataconnect/movie-connector/connector.yaml
@@ -11,4 +11,4 @@ generate:
     # directory as your app code
     outputDir: "../../movie/lib/dataconnect-sdk"
     # This property tells Data Connect what directory to install the generated SDK to
-    # packageJsonDir: "../../movie/lib/dataconnect-sdk"
+    packageJsonDir: "../../movie/lib/dataconnect-sdk"
diff --git a/dataconnect/dataconnect/connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
similarity index 57%
rename from dataconnect/dataconnect/connector/mutations.gql
rename to dataconnect/dataconnect/movie-connector/mutations.gql
index 57a6920ef..11e4aa759 100644
--- a/dataconnect/dataconnect/connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -7,7 +7,7 @@ mutation createMovie(
   $description: String
   $imageUrl: String!
   $tags: [String!] = []
-) {
+) @auth(level: USER_EMAIL_VERIFIED) {
   movie_insert(
     data: {
       title: $title
@@ -31,7 +31,7 @@ mutation updateMovie(
   $description: String
   $imageUrl: String
   $tags: [String!] = []
-) {
+) @auth(level: USER_EMAIL_VERIFIED) {
   movie_update(
     id: $id
     data: {
@@ -47,47 +47,41 @@ mutation updateMovie(
 }
 
 # Delete a movie by its ID
-mutation deleteMovie($id: UUID!) {
+mutation deleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
   movie_delete(id: $id)
 }
 
 # Delete movies with a rating lower than the specified minimum rating
-mutation deleteUnpopularMovies($minRating: Float!) {
+mutation deleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
   movie_deleteMany(where: { rating: { le: $minRating } })
 }
 
-# Add a movie to the user's watched list
-mutation addWatchedMovie($movieId: UUID!) @auth(level: USER) {
-  watchedMovie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
-}
-
-# Remove a movie from the user's watched list
-mutation deleteWatchedMovie($userId: String!, $movieId: UUID!) @auth(level: USER) {
-  watchedMovie_delete(key: { userId: $userId, movieId: $movieId })
-}
-
 # Add a movie to the user's favorites list
 mutation addFavoritedMovie($movieId: UUID!) @auth(level: USER) {
-  favoriteMovie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
+  favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
 }
 
 # Remove a movie from the user's favorites list
-mutation deleteFavoritedMovie($userId: String!, $movieId: UUID!) @auth(level: USER) {
-  favoriteMovie_delete(key: { userId: $userId, movieId: $movieId })
+mutation deleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
+  favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
 }
 
 # Add an actor to the user's favorites list
 mutation addFavoritedActor($actorId: UUID!) @auth(level: USER) {
-  favoriteActor_upsert(data: { userId_expr: "auth.uid", actorId: $actorId })
+  favorite_actor_upsert(data: { userId_expr: "auth.uid", actorId: $actorId })
 }
 
 # Remove an actor from the user's favorites list
-mutation deleteFavoriteActor($userId: String!, $actorId: UUID!) @auth(level: USER) {
-  favoriteActor_delete(key: { userId: $userId, actorId: $actorId })
+mutation deleteFavoriteActor($actorId: UUID!) @auth(level: USER) {
+  favorite_actor_delete(key: { userId_expr: "auth.uid", actorId: $actorId })
 }
 
 # Add a review for a movie
-mutation addReview($movieId: UUID!, $rating: Int!, $reviewText: String!) @auth(level: USER) {
+mutation addReview(
+  $movieId: UUID!
+  $rating: Int!
+  $reviewText: String!
+) @auth(level: USER) {
   review_upsert(
     data: {
       userId_expr: "auth.uid"
@@ -100,14 +94,18 @@ mutation addReview($movieId: UUID!, $rating: Int!, $reviewText: String!) @auth(l
 }
 
 # Delete a user's review for a movie
-mutation deleteReview($movieId: UUID!, $userId: String!) @auth(level: USER) {
-  review_delete(key: { userId: $userId, movieId: $movieId })
+mutation deleteReview(
+  $movieId: UUID!
+) @auth(level: USER) {
+  review_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
 }
 
 # Upsert (update or insert) a user based on their username
-mutation upsertUser($username: String!) @auth(level: USER) {
-  user_upsert(data: {
-    id_expr: "auth.uid",
-    username: $username
-  })
+mutation upsertUser($username: String!) @auth(level: PUBLIC) {
+  user_upsert(
+    data: {
+      id_expr: "auth.uid"
+      username: $username
+    }
+  )
 }
diff --git a/dataconnect/dataconnect/movie-connector/queries.gql b/dataconnect/dataconnect/movie-connector/queries.gql
new file mode 100644
index 000000000..4ea8ce9ab
--- /dev/null
+++ b/dataconnect/dataconnect/movie-connector/queries.gql
@@ -0,0 +1,383 @@
+# List subset of fields for movies
+query ListMovies($orderByRating: OrderDirection, $orderByReleaseYear: OrderDirection, $limit: Int) @auth(level: PUBLIC) {
+  movies (
+    orderBy: [
+      { rating: $orderByRating },
+      { releaseYear: $orderByReleaseYear }]
+    limit: $limit
+  ) {
+    id
+    title
+    imageUrl
+    releaseYear
+    genre
+    rating
+    tags
+    description
+  }
+}
+
+# List movies of a certain genre
+query ListMoviesByGenre($genre: String!) @auth(level: PUBLIC) {
+  mostPopular: movies(
+    where: { genre: { eq: $genre } }
+    orderBy: { rating: DESC }
+    limit: 10
+  ) {
+    id
+    title
+    imageUrl
+    rating
+    tags
+  }
+  mostRecent: movies(
+    where: { genre: { eq: $genre } }
+    orderBy: { releaseYear: DESC }
+  ) {
+    id
+    title
+    imageUrl
+    rating
+    tags
+  }
+}
+
+# Get movie by id
+query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
+  movie(id: $id) {
+    id
+    title
+    imageUrl
+    releaseYear
+    genre
+    rating
+    description
+    tags
+    metadata: movieMetadatas_on_movie {
+      director
+    }
+    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
+      id
+      name
+      imageUrl
+    }
+    supportingActors: actors_via_MovieActor(
+      where: { role: { eq: "supporting" } }
+    ) {
+      id
+      name
+      imageUrl
+    }
+    reviews: reviews_on_movie {
+      id
+      reviewText
+      reviewDate
+      rating
+      user {
+        id
+        username
+      }
+    }
+  }
+}
+
+# Get actor by id
+query GetActorById($id: UUID!) @auth(level: PUBLIC) {
+  actor(id: $id) {
+    id
+    name
+    imageUrl
+    mainActors: movies_via_MovieActor(where: { role: { eq: "main" } }) {
+      id
+      title
+      genre
+      tags
+      imageUrl
+    }
+    supportingActors: movies_via_MovieActor(
+      where: { role: { eq: "supporting" } }
+    ) {
+      id
+      title
+      genre
+      tags
+      imageUrl
+    }
+  }
+}
+
+# List movies by partial title match
+query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
+  movies(where: { title: { contains: $input } }) {
+    id
+    title
+    genre
+    rating
+    imageUrl
+  }
+}
+
+# List movies by tag
+query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
+  movies(where: { tags: { includes: $tag } }) {
+    id
+    title
+    imageUrl
+    genre
+    rating
+  }
+}
+
+# List movies by release year range
+query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
+  movies(
+    where: { releaseYear: { le: $max, ge: $min } }
+    orderBy: { releaseYear: ASC }
+  ) {
+    id
+    rating
+    title
+    imageUrl
+  }
+}
+
+# List movies by rating and genre with OR filters
+query SearchMovieOr(
+  $minRating: Float
+  $maxRating: Float
+  $genre: String
+  $tag: String
+  $input: String
+) @auth(level: PUBLIC) {
+  movies(
+    where: {
+      _or: [
+        { rating: { ge: $minRating } }
+        { rating: { le: $maxRating } }
+        { genre: { eq: $genre } }
+        { tags: { includes: $tag } }
+        { title: { contains: $input } }
+      ]
+    }
+  ) {
+    id
+    rating
+    title
+    imageUrl
+  }
+}
+
+# List movies by rating and genre with AND filters
+query SearchMovieAnd(
+  $minRating: Float
+  $maxRating: Float
+  $genre: String
+  $tag: String
+  $input: String
+) @auth(level: PUBLIC) {
+  movies(
+    where: {
+      _and: [
+        { rating: { ge: $minRating } }
+        { rating: { le: $maxRating } }
+        { genre: { eq: $genre } }
+        { tags: { includes: $tag } }
+        { title: { contains: $input } }
+      ]
+    }
+  ) {
+    id
+    rating
+    title
+    imageUrl
+  }
+}
+
+# Get favorite movies by user ID
+query GetUserFavoriteMovies @auth(level: USER) {
+  user(key: {id_expr: "auth.uid"}) {
+    favorite_movies_on_user {
+      movie {
+        id
+        title
+        genre
+        imageUrl
+        releaseYear
+        rating
+        description
+      }
+    }
+  }
+}
+
+# Get favorite actors by user ID
+query GetFavoriteActors @auth(level: USER) {
+  user(key: {id_expr: "auth.uid"}) {
+    favorite_actors_on_user {
+      actor {
+        id
+        name
+        imageUrl
+      }
+    }
+  }
+}
+
+# Get user by ID
+query GetCurrentUser @auth(level: USER) {
+  user(key: {id_expr: "auth.uid"}) {
+    id
+    username
+    reviews: reviews_on_user {
+      id
+      rating
+      reviewDate
+      reviewText
+      movie {
+        id
+        title
+      }
+    }
+    favoriteMovies: favorite_movies_on_user {
+      movie {
+        id
+        title
+        genre
+        imageUrl
+        releaseYear
+        rating
+        description
+        tags
+        metadata: movieMetadatas_on_movie {
+          director
+        }
+      }
+    }
+    favoriteActors: favorite_actors_on_user {
+      actor {
+        id
+        name
+        imageUrl
+      }
+    }
+  }
+}
+
+# Check if a movie is favorited by user
+query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
+  favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
+    movieId
+  }
+}
+
+# Check if an actor is favorited by user
+query GetIfFavoritedActor($actorId: UUID!) @auth(level: USER) {
+  favorite_actor(key: { userId_expr: "auth.uid", actorId: $actorId }) {
+    actorId
+  }
+}
+
+# Search for movies, actors, and reviews
+query searchAll(
+  $input: String
+  $minYear: Int!
+  $maxYear: Int!
+  $minRating: Float!
+  $maxRating: Float!
+  $genre: String!
+) @auth(level: PUBLIC) {
+  moviesMatchingTitle: movies(
+    where: {
+      _and: [
+        { releaseYear: { ge: $minYear } }
+        { releaseYear: { le: $maxYear } }
+        { rating: { ge: $minRating } }
+        { rating: { le: $maxRating } }
+        { genre: { contains: $genre } }
+        { title: { contains: $input } }
+      ]
+    }
+  ) {
+    id
+    title
+    genre
+    rating
+    imageUrl
+  }
+  moviesMatchingDescription: movies(
+    where: {
+      _and: [
+        { releaseYear: { ge: $minYear } }
+        { releaseYear: { le: $maxYear } }
+        { rating: { ge: $minRating } }
+        { rating: { le: $maxRating } }
+        { genre: { contains: $genre } }
+        { description: { contains: $input } }
+      ]
+    }
+  ) {
+    id
+    title
+    genre
+    rating
+    imageUrl
+  }
+  actorsMatchingName: actors(where: { name: { contains: $input } }) {
+    id
+    name
+    imageUrl
+  }
+  reviewsMatchingText: reviews(where: { reviewText: { contains: $input } }) {
+    id
+    rating
+    reviewText
+    reviewDate
+    movie {
+      id
+      title
+    }
+    user {
+      id
+      username
+    }
+  }
+}
+
+# Search movie descriptions using L2 similarity with Vertex AI
+query searchMovieDescriptionUsingL2Similarity($query: String!)
+@auth(level: PUBLIC) {
+  movies_descriptionEmbedding_similarity(
+    compare_embed: { model: "textembedding-gecko@003", text: $query }
+    method: L2
+    within: 2
+    where: { description: { ne: "" } }
+    limit: 5
+  ) {
+    id
+    title
+    description
+    tags
+    rating
+    imageUrl
+  }
+}
+
+# Search movie descriptions using L2 similarity with Vertex AI, with custom embeddings
+query searchMovieDescriptionUsingL2Similarity1(
+  $compare: Vector!
+  $within: Float
+  $excludesContent: String
+  $limit: Int
+) @auth(level: PUBLIC) {
+  movies_descriptionEmbedding_similarity(
+    compare: $compare
+    method: L2
+    within: $within
+    where: { description: { ne: $excludesContent } }
+    limit: $limit
+  ) {
+    id
+    title
+    description
+  }
+}
diff --git a/dataconnect/dataconnect/schema/schema.gql b/dataconnect/dataconnect/schema/schema.gql
index 4cda98395..6c151e78b 100644
--- a/dataconnect/dataconnect/schema/schema.gql
+++ b/dataconnect/dataconnect/schema/schema.gql
@@ -1,7 +1,7 @@
 # Movies
 type Movie
   # The below parameter values are generated by default with @table, and can be edited manually.
-  @table(name: "Movies", singular: "movie", plural: "movies", key: ["id"]) {
+  @table {
   # implicitly calls @col to generates a column name. ex: @col(name: "movie_id")
   # for UUID fields, @default(expr: "uuidV4()") is implicitly called
   id: UUID!
@@ -12,10 +12,8 @@ type Movie
   rating: Float
   description: String
   tags: [String]
-  # Vectors
-  descriptionEmbedding: Vector @col(size:768) # vector
-  # Self Joins
-  sequelTo: Movie
+  # Vectors -- uncomment the line below to enable vector search
+  descriptionEmbedding: Vector @col(size:768)
 }
 
 # Movie Metadata
@@ -27,7 +25,6 @@ type MovieMetadata
   movie: Movie! @ref
   # movieId: UUID <- this is created by the above @ref
   director: String
-  # TODO: optional other fields
 }
 
 # Actors
@@ -37,7 +34,28 @@ type Actor @table {
   id: UUID!
   imageUrl: String! 
   name: String! @col(name: "name", dataType: "varchar(30)")
-  biography: String
+}
+
+# Users
+# Suppose a user can leave reviews for movies
+# user-reviews is a one to many relationship, movie-reviews is a one to many relationship, movie:user is a many to many relationship
+type User
+  @table {
+  id: String! @col(name: "user_auth")
+  username: String! @col(name: "username", dataType: "varchar(50)")
+  # The following are generated from the @ref in the Review table
+  # reviews_on_user 
+  # movies_via_Review
+}
+
+# Reviews
+type Review @table(name: "Reviews", key: ["movie", "user"]) {
+  id: UUID! @default(expr: "uuidV4()")
+  user: User!
+  movie: Movie!
+  rating: Int
+  reviewText: String
+  reviewDate: Date! @default(expr: "request.time")
 }
 
 # Join table for many-to-many relationship for movies and actors
@@ -53,24 +71,11 @@ type MovieActor @table(key: ["movie", "actor"]) {
   # actorId: UUID! <- this is created by the implied  @ref, see: implicit.gql
 
   role: String! # "main" or "supporting"
-  # TODO: optional other fields
-}
-
-# Users
-# Suppose a user can leave reviews for movies
-# user:reviews is a one to many relationship, movie:reviews is a one to many relationship, movie:user is a many to many relationship
-type User
-  @table {
-  id: String! @col(name: "user_auth")
-  username: String! @col(name: "username", dataType: "varchar(50)")
-  # The following are generated from the @ref in the Review table
-  # reviews_on_user 
-  # movies_via_Review
 }
 
 # Join table for many-to-many relationship for users and favorite movies
 type FavoriteMovie
-  @table(name: "FavoriteMovies", key: ["user", "movie"]) {
+  @table(name: "FavoriteMovies", singular: "favorite_movie", plural: "favorite_movies", key: ["user", "movie"]) {
   # @ref is implicit
   user: User!
   movie: Movie!
@@ -78,24 +83,7 @@ type FavoriteMovie
 
 # Join table for many-to-many relationship for users and favorite actors
 type FavoriteActor
-  @table(name: "FavoriteActors", key: ["user", "actor"]) {
+  @table(name: "FavoriteActors", singular: "favorite_actor", plural: "favorite_actors", key: ["user", "actor"]) {
   user: User!
   actor: Actor!
 }
-
-# Join table for many-to-many relationship for users and watched movies
-type WatchedMovie
-  @table(name: "WatchedMovies", key: ["user", "movie"]) {
-  user: User!
-  movie: Movie!
-}
-
-# Reviews
-type Review @table(name: "Reviews", key: ["movie", "user"]) {
-  id: UUID! @default(expr: "uuidV4()")
-  user: User!
-  movie: Movie!
-  rating: Int
-  reviewText: String
-  reviewDate: Date! @default(expr: "request.time")
-}
diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json
index d333fb6ea..a472ebc75 100644
--- a/dataconnect/firebase.json
+++ b/dataconnect/firebase.json
@@ -1,7 +1,6 @@
 {
   "dataconnect": {
-    "source": "./dataconnect",
-    "location": "us-central1"
+    "source": "./dataconnect"
   },
   "emulators": {
     "dataconnect": {
diff --git a/dataconnect/movie/app/actor/[id]/page.tsx b/dataconnect/movie/app/actor/[id]/page.tsx
index c2e09099b..5497a69eb 100644
--- a/dataconnect/movie/app/actor/[id]/page.tsx
+++ b/dataconnect/movie/app/actor/[id]/page.tsx
@@ -45,8 +45,8 @@ const Page = () => {
 
   const checkIfFavorited = async (userId: string) => {
     try {
-      const response = await getIfFavoritedActor({ id: userId, actorId: id });
-      setIsFavorited(!!response.data.favoriteActor);
+      const response = await getIfFavoritedActor({ actorId: id });
+      setIsFavorited(!!response.data.favorite_actor);
     } catch (error) {
       console.error('Error checking if favorited:', error);
     }
@@ -56,7 +56,7 @@ const Page = () => {
     if (!authUser) return;
     try {
       if (isFavorited) {
-        await deleteFavoriteActor({ userId: authUser.uid, actorId: id });
+        await deleteFavoriteActor({ actorId: id });
       } else {
         await addFavoritedActor({ actorId: id });
       }
@@ -84,7 +84,6 @@ const Page = () => {
               {isFavorited ? <MdFavorite size={24} /> : <MdFavoriteBorder size={24} />}
             </button>
           </div>
-          <p className="text-lg mb-4 p-4 bg-gray-800 rounded-lg">{actor.biography}</p>
         </div>
       </div>
 
diff --git a/dataconnect/movie/app/advancedsearch/page.tsx b/dataconnect/movie/app/advancedsearch/page.tsx
index 06e52d634..3ab0b4e0a 100644
--- a/dataconnect/movie/app/advancedsearch/page.tsx
+++ b/dataconnect/movie/app/advancedsearch/page.tsx
@@ -3,7 +3,7 @@ import { useState } from 'react';
 import Link from 'next/link';
 import { FaSearch } from 'react-icons/fa';
 import { MdStar } from 'react-icons/md';
-import { fuzzySearch } from '@/lib/dataconnect-sdk';
+import { searchAll } from '@/lib/dataconnect-sdk';
 
 const genres = ['', 'action', 'crime', 'drama', 'sci-fi', 'thriller', 'adventure'];
 
@@ -22,7 +22,7 @@ const Page = () => {
   const handleSearch = async (e: React.FormEvent<HTMLFormElement>) => {
     e.preventDefault();
     try {
-      const response = await fuzzySearch({
+      const response = await searchAll({
         input: searchQuery,
         minYear: releaseYearRange.min,
         maxYear: releaseYearRange.max,
diff --git a/dataconnect/movie/app/movie/[id]/page.tsx b/dataconnect/movie/app/movie/[id]/page.tsx
index 6e63d7309..51153c7b7 100644
--- a/dataconnect/movie/app/movie/[id]/page.tsx
+++ b/dataconnect/movie/app/movie/[id]/page.tsx
@@ -8,9 +8,6 @@ import {
   GetMovieByIdResponse,
   addFavoritedMovie,
   deleteFavoritedMovie,
-  addWatchedMovie,
-  deleteWatchedMovie,
-  getIfWatched,
   getIfFavoritedMovie,
   addReview,
   deleteReview,
@@ -26,7 +23,6 @@ const Page = () => {
   const [loading, setLoading] = useState(true);
   const [authUser, setAuthUser] = useState<User | null>(null);
   const [isFavorited, setIsFavorited] = useState(false);
-  const [isWatched, setIsWatched] = useState(false);
   const [reviewText, setReviewText] = useState('');
   const [userReview, setUserReview] = useState<GetMovieByIdResponse['movie']['reviews'][0] | null>(null);
   const [rating, setRating] = useState(0);
@@ -38,7 +34,6 @@ const Page = () => {
       if (user) {
         setAuthUser(user);
         checkIfFavorited(user.uid);
-        checkIfWatched(user.uid);
       }
     });
 
@@ -76,29 +71,20 @@ const Page = () => {
 
   const checkIfFavorited = async (userId: string) => {
     try {
-      const response = await getIfFavoritedMovie({ id: userId, movieId: id });
-      setIsFavorited(!!response.data.favoriteMovie);
+      const response = await getIfFavoritedMovie({ movieId: id });
+      setIsFavorited(!!response.data.favorite_movie);
     } catch (error) {
       console.error('Error checking if favorited:', error);
     }
   };
 
-  const checkIfWatched = async (userId: string) => {
-    try {
-      const response = await getIfWatched({ id: userId, movieId: id });
-      setIsWatched(!!response.data.watchedMovie);
-    } catch (error) {
-      console.error('Error checking if watched:', error);
-    }
-  };
-
   const handleFavoriteToggle = async (e: React.MouseEvent) => {
     e.stopPropagation();
     e.preventDefault();
     if (!authUser) return;
     try {
       if (isFavorited) {
-        await deleteFavoritedMovie({ userId: authUser.uid, movieId: id });
+        await deleteFavoritedMovie({ movieId: id });
       } else {
         await addFavoritedMovie({ movieId: id });
       }
@@ -108,22 +94,6 @@ const Page = () => {
     }
   };
 
-  const handleWatchedToggle = async (e: React.MouseEvent) => {
-    e.stopPropagation();
-    e.preventDefault();
-    if (!authUser) return;
-    try {
-      if (isWatched) {
-        await deleteWatchedMovie({ userId: authUser.uid, movieId: id });
-      } else {
-        await addWatchedMovie({ movieId: id });
-      }
-      setIsWatched(!isWatched);
-    } catch (error) {
-      console.error('Error updating watched status:', error);
-    }
-  };
-
   const handleReviewSubmit = async (e: React.FormEvent) => {
     e.preventDefault();
     if (!authUser) return;
@@ -143,7 +113,7 @@ const Page = () => {
     e.preventDefault();
     if (!authUser || !userReview) return;
     try {
-      await deleteReview({ movieId: id, userId: authUser.uid });
+      await deleteReview({ movieId: id });
       setUserReview(null);
       const updatedMovie = await getMovieById({ id });
       setMovie(updatedMovie.data.movie);
@@ -216,18 +186,6 @@ const Page = () => {
         </div>
       </div>
 
-      {movie.sequelTo && (
-        <div className="mt-8">
-          <h2 className="text-2xl font-bold mb-2">Sequel</h2>
-          <Link href={`/movie/${movie.sequelTo.id}`} passHref>
-            <div className="flex items-center cursor-pointer hover:bg-gray-800 p-2 rounded-lg transition">
-              <img className="w-20 h-28 object-cover rounded-lg mr-4" src={movie.sequelTo.imageUrl} alt={movie.sequelTo.title} />
-              <span className="text-lg">{movie.sequelTo.title}</span>
-            </div>
-          </Link>
-        </div>
-      )}
-
       <div className="mt-8">
         <h2 className="text-2xl font-bold mb-2">User Reviews</h2>
         {!userReview ? (
diff --git a/dataconnect/movie/app/myprofile/page.tsx b/dataconnect/movie/app/myprofile/page.tsx
index 0b7dba866..2e662dfcf 100644
--- a/dataconnect/movie/app/myprofile/page.tsx
+++ b/dataconnect/movie/app/myprofile/page.tsx
@@ -4,10 +4,9 @@ import { useRouter } from 'next/navigation';
 import Link from 'next/link';
 import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
 import {
-  getUserById,
-  GetUserByIdResponse,
+  getCurrentUser,
+  GetCurrentUserResponse,
   deleteReview,
-  deleteWatchedMovie,
   deleteFavoritedMovie,
   deleteFavoriteActor,
 } from '@/lib/dataconnect-sdk';
@@ -16,7 +15,7 @@ import { MdStar } from 'react-icons/md';
 const Page = () => {
   const router = useRouter();
   const [authUser, setAuthUser] = useState<User | null>(null);
-  const [user, setUser] = useState<GetUserByIdResponse['user'] | null>(null);
+  const [user, setUser] = useState<GetCurrentUserResponse['user'] | null>(null);
   const [loading, setLoading] = useState(true);
 
   useEffect(() => {
@@ -24,7 +23,7 @@ const Page = () => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
       if (user) {
         setAuthUser(user);
-        fetchUserProfile(user.uid);
+        fetchUserProfile();
       } else {
         router.push('/');
       }
@@ -33,9 +32,9 @@ const Page = () => {
     return () => unsubscribe();
   }, [router]);
 
-  const fetchUserProfile = async (userId: string) => {
+  const fetchUserProfile = async () => {
     try {
-      const response = await getUserById({ id: userId });
+      const response = await getCurrentUser();
       setUser(response.data.user);
     } catch (error) {
       console.error('Error fetching user:', error);
@@ -47,28 +46,18 @@ const Page = () => {
   const handleDeleteReview = async (reviewId: string) => {
     if (!authUser) return;
     try {
-      await deleteReview({ movieId: reviewId, userId: authUser.uid });
-      fetchUserProfile(authUser.uid);
+      await deleteReview({ movieId: reviewId });
+      fetchUserProfile();
     } catch (error) {
       console.error('Error deleting review:', error);
     }
   };
 
-  const handleUnwatchMovie = async (movieId: string) => {
-    if (!authUser) return;
-    try {
-      await deleteWatchedMovie({ userId: authUser.uid, movieId });
-      fetchUserProfile(authUser.uid);
-    } catch (error) {
-      console.error('Error unwatching movie:', error);
-    }
-  };
-
   const handleUnfavoriteMovie = async (movieId: string) => {
     if (!authUser) return;
     try {
-      await deleteFavoritedMovie({ userId: authUser.uid, movieId });
-      fetchUserProfile(authUser.uid);
+      await deleteFavoritedMovie({ movieId });
+      fetchUserProfile();
     } catch (error) {
       console.error('Error unfavoriting movie:', error);
     }
@@ -77,8 +66,8 @@ const Page = () => {
   const handleUnfavoriteActor = async (actorId: string) => {
     if (!authUser) return;
     try {
-      await deleteFavoriteActor({ userId: authUser.uid, actorId });
-      fetchUserProfile(authUser.uid);
+      await deleteFavoriteActor({ actorId });
+      fetchUserProfile();
     } catch (error) {
       console.error('Error unfavoriting actor:', error);
     }
@@ -116,39 +105,6 @@ const Page = () => {
         </div>
       </div>
 
-      <div className="mt-8">
-        <h2 className="text-2xl font-bold mb-2">Watched Movies</h2>
-        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
-          {user.watched.map((watched) => (
-            <div key={watched.movie.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative max-h-80">
-              <Link href={`/movie/${watched.movie.id}`}>
-                <img className="w-full h-64 object-cover" src={watched.movie.imageUrl} alt={watched.movie.title} />
-              </Link>
-              <div className="p-4">
-                <h3 className="font-bold text-lg mb-1 text-white">{watched.movie.title}</h3>
-                <p className="text-sm text-gray-400 capitalize">{watched.movie.genre}</p>
-                <p className="text-sm text-gray-300 overflow-y-scroll max-h-24">{watched.movie.description}</p>
-                <div className="flex items-center text-yellow-500 mt-2">
-                  <MdStar className="text-yellow-500" size={24} />
-                  <span className="ml-1 text-gray-400">{watched.movie.rating}</span>
-                </div>
-                <div className="flex flex-wrap gap-1 mt-2">
-                  {watched.movie.tags?.map((tag, index) => (
-                    <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs capitalize">{tag}</span>
-                  ))}
-                </div>
-              </div>
-              <button
-                onClick={() => handleUnwatchMovie(watched.movie.id)}
-                className="absolute bottom-2 right-2 text-red-500 hover:text-red-600"
-              >
-                Remove Watched
-              </button>
-            </div>
-          ))}
-        </div>
-      </div>
-
       <div className="mt-8">
         <h2 className="text-2xl font-bold mb-2">Favorite Movies</h2>
         <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
diff --git a/dataconnect/movie/app/page.tsx b/dataconnect/movie/app/page.tsx
index b7831fe90..f0aec106e 100644
--- a/dataconnect/movie/app/page.tsx
+++ b/dataconnect/movie/app/page.tsx
@@ -2,23 +2,21 @@
 import { useEffect, useState } from "react";
 import Carousel from "@/components/carousel";
 import {
-  moviesTop10,
-  moviesRecentlyReleased,
-  MoviesRecentlyReleasedResponse,
-  MoviesTop10Response,
+  listMovies,
+  ListMoviesResponse,
 } from "@/lib/dataconnect-sdk";
 
 const Page = () => {
-  const [topMovies, setTopMovies] = useState<MoviesTop10Response["movies"]>([]);
+  const [topMovies, setTopMovies] = useState<ListMoviesResponse["movies"]>([]);
   const [latestMovies, setLatestMovies] = useState<
-    MoviesRecentlyReleasedResponse["movies"]
+  ListMoviesResponse["movies"]
   >([]);
 
   useEffect(() => {
     const fetchMovies = async () => {
       try {
-        const topMoviesResponse = await moviesTop10();
-        const latestMoviesResponse = await moviesRecentlyReleased();
+        const topMoviesResponse = await listMovies({orderByRating :"DESC", limit: 10});
+        const latestMoviesResponse = await listMovies({orderByReleaseYear :"DESC", limit: 10});
 
         setTopMovies(topMoviesResponse.data.movies);
         setLatestMovies(latestMoviesResponse.data.movies);
@@ -33,7 +31,7 @@ const Page = () => {
   return (
     <div className="container mx-auto p-4 bg-gray-900 text-white shadow-md min-h-screen">
       <Carousel title="Top 10 Movies" movies={topMovies} />
-      <Carousel title="Latest Movies" movies={latestMovies.slice(0, 10)} />
+      <Carousel title="Latest Movies" movies={latestMovies} />
     </div>
   );
 };
diff --git a/dataconnect/movie/app/vectors/page.tsx b/dataconnect/movie/app/vectors/page.tsx
index 9fb411e73..65e1fb9a8 100644
--- a/dataconnect/movie/app/vectors/page.tsx
+++ b/dataconnect/movie/app/vectors/page.tsx
@@ -1,6 +1,5 @@
 'use client';
 import { useState } from 'react';
-import { useRouter } from 'next/navigation';
 import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '@/lib/dataconnect-sdk';
 import { FaSpinner } from 'react-icons/fa';
 
diff --git a/dataconnect/movie/components/moviecard.tsx b/dataconnect/movie/components/moviecard.tsx
index fd0dbfa5c..c9bda5144 100644
--- a/dataconnect/movie/components/moviecard.tsx
+++ b/dataconnect/movie/components/moviecard.tsx
@@ -1,8 +1,8 @@
 import { useEffect, useState } from 'react';
 import Link from 'next/link';
-import { MdFavorite, MdFavoriteBorder, MdCheck, MdAdd, MdStar } from 'react-icons/md';
+import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
 import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
-import { addFavoritedMovie, deleteFavoritedMovie, addWatchedMovie, deleteWatchedMovie, getIfWatched, getIfFavoritedMovie } from '@/lib/dataconnect-sdk';
+import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from '@/lib/dataconnect-sdk';
 
 interface MovieCardProps {
   id: string;
@@ -16,46 +16,35 @@ interface MovieCardProps {
 const MovieCard: React.FC<MovieCardProps> = ({ id, title, imageUrl, rating, genre, tags }) => {
   const [user, setUser] = useState<User | null>(null);
   const [isFavorited, setIsFavorited] = useState(false);
-  const [isWatched, setIsWatched] = useState(false);
   const auth = getAuth();
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
       if (user) {
         setUser(user);
-        checkIfFavorited(user.uid);
-        checkIfWatched(user.uid);
+        checkIfFavorited();
       }
     });
 
     return () => unsubscribe();
   }, [auth, id]);
 
-  const checkIfFavorited = async (userId: string) => {
+  const checkIfFavorited = async () => {
     try {
-      const response = await getIfFavoritedMovie({ id: userId, movieId: id });
-      setIsFavorited(!!response.data.favoriteMovie);
+      const response = await getIfFavoritedMovie({ movieId: id });
+      setIsFavorited(!!response.data.favorite_movie);
     } catch (error) {
       console.error('Error checking if favorited:', error);
     }
   };
 
-  const checkIfWatched = async (userId: string) => {
-    try {
-      const response = await getIfWatched({ id: userId, movieId: id });
-      setIsWatched(!!response.data.watchedMovie);
-    } catch (error) {
-      console.error('Error checking if watched:', error);
-    }
-  };
-
   const handleFavoriteToggle = async (e: React.MouseEvent) => {
     e.stopPropagation();
     e.preventDefault();
     if (!user) return;
     try {
       if (isFavorited) {
-        await deleteFavoritedMovie({ userId: user.uid, movieId: id });
+        await deleteFavoritedMovie({ movieId: id });
       } else {
         await addFavoritedMovie({ movieId: id });
       }
@@ -65,22 +54,6 @@ const MovieCard: React.FC<MovieCardProps> = ({ id, title, imageUrl, rating, genr
     }
   };
 
-  const handleWatchedToggle = async (e: React.MouseEvent) => {
-    e.stopPropagation();
-    e.preventDefault();
-    if (!user) return;
-    try {
-      if (isWatched) {
-        await deleteWatchedMovie({ userId: user.uid, movieId: id });
-      } else {
-        await addWatchedMovie({ movieId: id });
-      }
-      setIsWatched(!isWatched);
-    } catch (error) {
-      console.error('Error updating watched status:', error);
-    }
-  };
-
   const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
 
   return (
@@ -115,23 +88,6 @@ const MovieCard: React.FC<MovieCardProps> = ({ id, title, imageUrl, rating, genr
                 >
                   {isFavorited ? <MdFavorite size={20} /> : <MdFavoriteBorder size={20} />}
                 </button>
-                <button
-                  className="flex items-center justify-center p-1 text-green-700 hover:text-green-800 transition-colors duration-200"
-                  aria-label="Watched"
-                  onClick={handleWatchedToggle}
-                >
-                  {isWatched ? (
-                    <>
-                      <MdCheck size={20} />
-                      <span className="ml-1 text-sm">Watched</span>
-                    </>
-                  ) : (
-                    <>
-                      <MdAdd size={20} />
-                      <span className="ml-1 text-sm">Add to watchlist</span>
-                    </>
-                  )}
-                </button>
               </div>
             )}
           </div>
diff --git a/dataconnect/movie/lib/firebase.tsx b/dataconnect/movie/lib/firebase.tsx
index 731eb86a7..be5b7d9bf 100644
--- a/dataconnect/movie/lib/firebase.tsx
+++ b/dataconnect/movie/lib/firebase.tsx
@@ -13,21 +13,21 @@ const firebaseConfig = {
 
 const firebaseapp = initializeApp(firebaseConfig);
 const auth = getAuth(firebaseapp);
-// const dataconnect = getDataConnect(firebaseapp, {
-//   connector: 'movie-connector',
-//   service: 'local',
-//   location: 'us-central1'
-// });
+const dataconnect = getDataConnect(firebaseapp, {
+  connector: 'movie-connector',
+  service: 'local',
+  location: 'us-central1'
+});
 const provider = new GoogleAuthProvider();
 
 if (process.env.NODE_ENV === 'development') {
-  // connectDataConnectEmulator(
-  //   dataconnect, 
-  //   'localhost', 
-  //   9399, 
-  //   false
-  // );
-  // connectAuthEmulator(auth, "http://localhost:9099");
+  connectDataConnectEmulator(
+    dataconnect, 
+    '127.0.0.1', 
+    9399, 
+    false
+  );
+  connectAuthEmulator(auth, "http://127.0.0.1:9099");
 }
 
 export { firebaseapp, auth, onAuthStateChanged };

From 4692aa5be4bce5aa4899561e7310b938a7b370f7 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Thu, 25 Jul 2024 10:34:47 -0400
Subject: [PATCH 19/82] fix: auth

---
 dataconnect/.gitignore                        |  5 +--
 .../movie-connector/connector.yaml            |  4 +-
 dataconnect/firebase.json                     |  2 +-
 dataconnect/movie/.env.local                  |  6 ---
 dataconnect/movie/app/layout.tsx              | 19 --------
 dataconnect/movie/lib/firebase.tsx            | 33 --------------
 .../{movie => src}/app/actor/[id]/page.tsx    | 16 +++----
 .../app/advancedsearch/page.tsx               |  0
 .../{movie => src}/app/genre/[genre]/page.tsx |  2 +-
 dataconnect/src/app/layout.tsx                | 23 ++++++++++
 .../{movie => src}/app/movie/[id]/page.tsx    | 13 +++---
 .../{movie => src}/app/myprofile/page.tsx     |  9 ++--
 dataconnect/{movie => src}/app/page.tsx       |  0
 .../{movie => src}/app/vectors/page.tsx       |  0
 .../{movie => src}/assets/firebase_logo.svg   |  0
 .../{movie => src}/components/carousel.tsx    |  0
 .../{movie => src}/components/moviecard.tsx   |  9 ++--
 .../{movie => src}/components/navbar.tsx      | 10 ++---
 dataconnect/src/lib/firebase.tsx              | 43 +++++++++++++++++++
 dataconnect/{movie => src}/next-env.d.ts      |  0
 dataconnect/{movie => src}/package.json       |  3 +-
 dataconnect/{movie => src}/postcss.config.js  |  0
 dataconnect/{movie => src}/styles.css         |  0
 dataconnect/{movie => src}/tailwind.config.js |  0
 dataconnect/{movie => src}/tsconfig.json      |  0
 25 files changed, 103 insertions(+), 94 deletions(-)
 delete mode 100644 dataconnect/movie/.env.local
 delete mode 100644 dataconnect/movie/app/layout.tsx
 delete mode 100644 dataconnect/movie/lib/firebase.tsx
 rename dataconnect/{movie => src}/app/actor/[id]/page.tsx (90%)
 rename dataconnect/{movie => src}/app/advancedsearch/page.tsx (100%)
 rename dataconnect/{movie => src}/app/genre/[genre]/page.tsx (94%)
 create mode 100644 dataconnect/src/app/layout.tsx
 rename dataconnect/{movie => src}/app/movie/[id]/page.tsx (97%)
 rename dataconnect/{movie => src}/app/myprofile/page.tsx (96%)
 rename dataconnect/{movie => src}/app/page.tsx (100%)
 rename dataconnect/{movie => src}/app/vectors/page.tsx (100%)
 rename dataconnect/{movie => src}/assets/firebase_logo.svg (100%)
 rename dataconnect/{movie => src}/components/carousel.tsx (100%)
 rename dataconnect/{movie => src}/components/moviecard.tsx (92%)
 rename dataconnect/{movie => src}/components/navbar.tsx (91%)
 create mode 100644 dataconnect/src/lib/firebase.tsx
 rename dataconnect/{movie => src}/next-env.d.ts (100%)
 rename dataconnect/{movie => src}/package.json (84%)
 rename dataconnect/{movie => src}/postcss.config.js (100%)
 rename dataconnect/{movie => src}/styles.css (100%)
 rename dataconnect/{movie => src}/tailwind.config.js (100%)
 rename dataconnect/{movie => src}/tsconfig.json (100%)

diff --git a/dataconnect/.gitignore b/dataconnect/.gitignore
index a431356d1..43adbed10 100644
--- a/dataconnect/.gitignore
+++ b/dataconnect/.gitignore
@@ -63,8 +63,7 @@ node_modules/
 .yarn-integrity
 
 # dotenv environment variables file
-.env
 .next
 .dataconnect
-movie/lib/dataconnect-sdk
-movie/package-lock.json
+src/lib/dataconnect-sdk
+src/package-lock.json
diff --git a/dataconnect/dataconnect/movie-connector/connector.yaml b/dataconnect/dataconnect/movie-connector/connector.yaml
index 716396953..ced088385 100644
--- a/dataconnect/dataconnect/movie-connector/connector.yaml
+++ b/dataconnect/dataconnect/movie-connector/connector.yaml
@@ -9,6 +9,6 @@ generate:
     package: "@movie/sdk"
     # Tells Data Connect where to store the generated SDK code, this should be in the same
     # directory as your app code
-    outputDir: "../../movie/lib/dataconnect-sdk"
+    outputDir: "../../src/lib/dataconnect-sdk"
     # This property tells Data Connect what directory to install the generated SDK to
-    packageJsonDir: "../../movie/lib/dataconnect-sdk"
+    packageJsonDir: "../../src/lib/dataconnect-sdk"
diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json
index a472ebc75..dd78268e0 100644
--- a/dataconnect/firebase.json
+++ b/dataconnect/firebase.json
@@ -18,7 +18,7 @@
     }
   },
   "hosting": {
-    "source": "movie",
+    "source": "src",
     "ignore": [
       "firebase.json",
       "**/.*",
diff --git a/dataconnect/movie/.env.local b/dataconnect/movie/.env.local
deleted file mode 100644
index 77171b344..000000000
--- a/dataconnect/movie/.env.local
+++ /dev/null
@@ -1,6 +0,0 @@
-NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
-NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-auth-domain
-NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
-NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-storage-bucket
-NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id
-NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
diff --git a/dataconnect/movie/app/layout.tsx b/dataconnect/movie/app/layout.tsx
deleted file mode 100644
index c7e9c7a62..000000000
--- a/dataconnect/movie/app/layout.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-"use client";
-import Navbar from "@/components/navbar";
-import "../styles.css";
-export default function RootLayout({
-  children,
-}: {
-  children: React.ReactNode;
-}) {
-  return (
-    <html lang="en">
-      <body>
-        <Navbar />
-        <div className="bg-gray-800 min-h-screen min-w-screen flex justify-center items-center">
-          {children}
-        </div>
-      </body>
-    </html>
-  );
-}
diff --git a/dataconnect/movie/lib/firebase.tsx b/dataconnect/movie/lib/firebase.tsx
deleted file mode 100644
index be5b7d9bf..000000000
--- a/dataconnect/movie/lib/firebase.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { initializeApp } from 'firebase/app';
-import { getAuth, GoogleAuthProvider, signInWithPopup, signOut, onAuthStateChanged, connectAuthEmulator } from "firebase/auth";
-import { getDataConnect, connectDataConnectEmulator } from 'firebase/data-connect'
-
-const firebaseConfig = {
-  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
-  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
-  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
-  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
-  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
-  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
-};
-
-const firebaseapp = initializeApp(firebaseConfig);
-const auth = getAuth(firebaseapp);
-const dataconnect = getDataConnect(firebaseapp, {
-  connector: 'movie-connector',
-  service: 'local',
-  location: 'us-central1'
-});
-const provider = new GoogleAuthProvider();
-
-if (process.env.NODE_ENV === 'development') {
-  connectDataConnectEmulator(
-    dataconnect, 
-    '127.0.0.1', 
-    9399, 
-    false
-  );
-  connectAuthEmulator(auth, "http://127.0.0.1:9099");
-}
-
-export { firebaseapp, auth, onAuthStateChanged };
diff --git a/dataconnect/movie/app/actor/[id]/page.tsx b/dataconnect/src/app/actor/[id]/page.tsx
similarity index 90%
rename from dataconnect/movie/app/actor/[id]/page.tsx
rename to dataconnect/src/app/actor/[id]/page.tsx
index 5497a69eb..c04c5fc5c 100644
--- a/dataconnect/movie/app/actor/[id]/page.tsx
+++ b/dataconnect/src/app/actor/[id]/page.tsx
@@ -1,25 +1,25 @@
 'use client';
-import { useEffect, useState } from 'react';
-import { useParams, useRouter } from 'next/navigation';
+import { useContext, useEffect, useState } from 'react';
+import { useParams } from 'next/navigation';
 import Link from 'next/link';
 import { MdFavorite, MdFavoriteBorder } from 'react-icons/md';
-import { getActorById, GetActorByIdResponse, GetActorByIdVariables, addFavoritedActor, deleteFavoriteActor, getIfFavoritedActor } from '@/lib/dataconnect-sdk';
-import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
+import { getActorById, GetActorByIdResponse, addFavoritedActor, deleteFavoriteActor, getIfFavoritedActor } from '@/lib/dataconnect-sdk';
+import { onAuthStateChanged, User } from 'firebase/auth';
+import { AuthContext } from '@/lib/firebase';
 
 const Page = () => {
-  const router = useRouter();
   const { id } = useParams() as { id: string };
   const [actor, setActor] = useState<GetActorByIdResponse['actor'] | null>(null);
   const [loading, setLoading] = useState(true);
   const [authUser, setAuthUser] = useState<User | null>(null);
   const [isFavorited, setIsFavorited] = useState(false);
+  let auth  = useContext(AuthContext);
 
   useEffect(() => {
-    const auth = getAuth();
     const unsubscribe = onAuthStateChanged(auth, (user) => {
       if (user) {
         setAuthUser(user);
-        checkIfFavorited(user.uid);
+        checkIfFavorited();
       }
     });
 
@@ -43,7 +43,7 @@ const Page = () => {
     }
   }, [id]);
 
-  const checkIfFavorited = async (userId: string) => {
+  const checkIfFavorited = async () => {
     try {
       const response = await getIfFavoritedActor({ actorId: id });
       setIsFavorited(!!response.data.favorite_actor);
diff --git a/dataconnect/movie/app/advancedsearch/page.tsx b/dataconnect/src/app/advancedsearch/page.tsx
similarity index 100%
rename from dataconnect/movie/app/advancedsearch/page.tsx
rename to dataconnect/src/app/advancedsearch/page.tsx
diff --git a/dataconnect/movie/app/genre/[genre]/page.tsx b/dataconnect/src/app/genre/[genre]/page.tsx
similarity index 94%
rename from dataconnect/movie/app/genre/[genre]/page.tsx
rename to dataconnect/src/app/genre/[genre]/page.tsx
index bc38cf7ce..c0cc6ca1b 100644
--- a/dataconnect/movie/app/genre/[genre]/page.tsx
+++ b/dataconnect/src/app/genre/[genre]/page.tsx
@@ -2,7 +2,7 @@
 import { useEffect, useState } from 'react';
 import { useParams } from 'next/navigation';
 import MovieCard from '@/components/moviecard';
-import { ListMoviesByGenreResponse, ListMoviesByGenreVariables, listMoviesByGenre } from '@/lib/dataconnect-sdk';
+import { ListMoviesByGenreResponse, listMoviesByGenre } from '@/lib/dataconnect-sdk';
 
 const Page = () => {
   const { genre } = useParams() as { genre: string };
diff --git a/dataconnect/src/app/layout.tsx b/dataconnect/src/app/layout.tsx
new file mode 100644
index 000000000..4062127c2
--- /dev/null
+++ b/dataconnect/src/app/layout.tsx
@@ -0,0 +1,23 @@
+"use client";
+import { AuthProvider } from '@/lib/firebase';
+import Navbar from "@/components/navbar";
+
+import "../styles.css";
+export default function RootLayout({
+  children,
+}: {
+  children: React.ReactNode;
+}) {
+  return (
+    <html lang="en">
+      <body>
+        <AuthProvider>
+          <Navbar />
+          <div className="bg-gray-800 min-h-screen min-w-screen flex justify-center items-center">
+            {children}
+          </div>
+        </AuthProvider>
+      </body>
+    </html>
+  );
+}
diff --git a/dataconnect/movie/app/movie/[id]/page.tsx b/dataconnect/src/app/movie/[id]/page.tsx
similarity index 97%
rename from dataconnect/movie/app/movie/[id]/page.tsx
rename to dataconnect/src/app/movie/[id]/page.tsx
index 51153c7b7..910a78387 100644
--- a/dataconnect/movie/app/movie/[id]/page.tsx
+++ b/dataconnect/src/app/movie/[id]/page.tsx
@@ -1,8 +1,8 @@
 'use client';
-import { useEffect, useState } from 'react';
+import { useContext, useEffect, useState } from 'react';
 import { useParams, useRouter } from 'next/navigation';
 import Link from 'next/link';
-import { MdFavorite, MdFavoriteBorder, MdCheck, MdAdd, MdStar } from 'react-icons/md';
+import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
 import {
   getMovieById,
   GetMovieByIdResponse,
@@ -14,7 +14,8 @@ import {
   searchMovieDescriptionUsingL2similarity,
   SearchMovieDescriptionUsingL2similarityResponse,
 } from '@/lib/dataconnect-sdk';
-import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
+import { onAuthStateChanged, User } from 'firebase/auth';
+import { AuthContext } from '@/lib/firebase';
 
 const Page = () => {
   const router = useRouter();
@@ -27,13 +28,13 @@ const Page = () => {
   const [userReview, setUserReview] = useState<GetMovieByIdResponse['movie']['reviews'][0] | null>(null);
   const [rating, setRating] = useState(0);
   const [similarMovies, setSimilarMovies] = useState<SearchMovieDescriptionUsingL2similarityResponse['movies_descriptionEmbedding_similarity']>([]);
+  let auth  = useContext(AuthContext);
 
   useEffect(() => {
-    const auth = getAuth();
     const unsubscribe = onAuthStateChanged(auth, (user) => {
       if (user) {
         setAuthUser(user);
-        checkIfFavorited(user.uid);
+        checkIfFavorited();
       }
     });
 
@@ -69,7 +70,7 @@ const Page = () => {
     }
   };
 
-  const checkIfFavorited = async (userId: string) => {
+  const checkIfFavorited = async () => {
     try {
       const response = await getIfFavoritedMovie({ movieId: id });
       setIsFavorited(!!response.data.favorite_movie);
diff --git a/dataconnect/movie/app/myprofile/page.tsx b/dataconnect/src/app/myprofile/page.tsx
similarity index 96%
rename from dataconnect/movie/app/myprofile/page.tsx
rename to dataconnect/src/app/myprofile/page.tsx
index 2e662dfcf..47847163c 100644
--- a/dataconnect/movie/app/myprofile/page.tsx
+++ b/dataconnect/src/app/myprofile/page.tsx
@@ -1,8 +1,8 @@
 'use client';
-import { useEffect, useState } from 'react';
+import { useContext, useEffect, useState } from 'react';
 import { useRouter } from 'next/navigation';
 import Link from 'next/link';
-import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
+import { onAuthStateChanged, User } from 'firebase/auth';
 import {
   getCurrentUser,
   GetCurrentUserResponse,
@@ -11,15 +11,16 @@ import {
   deleteFavoriteActor,
 } from '@/lib/dataconnect-sdk';
 import { MdStar } from 'react-icons/md';
+import { AuthContext } from '@/lib/firebase';
 
 const Page = () => {
   const router = useRouter();
   const [authUser, setAuthUser] = useState<User | null>(null);
   const [user, setUser] = useState<GetCurrentUserResponse['user'] | null>(null);
   const [loading, setLoading] = useState(true);
-
+  let auth  = useContext(AuthContext);
+  
   useEffect(() => {
-    const auth = getAuth();
     const unsubscribe = onAuthStateChanged(auth, (user) => {
       if (user) {
         setAuthUser(user);
diff --git a/dataconnect/movie/app/page.tsx b/dataconnect/src/app/page.tsx
similarity index 100%
rename from dataconnect/movie/app/page.tsx
rename to dataconnect/src/app/page.tsx
diff --git a/dataconnect/movie/app/vectors/page.tsx b/dataconnect/src/app/vectors/page.tsx
similarity index 100%
rename from dataconnect/movie/app/vectors/page.tsx
rename to dataconnect/src/app/vectors/page.tsx
diff --git a/dataconnect/movie/assets/firebase_logo.svg b/dataconnect/src/assets/firebase_logo.svg
similarity index 100%
rename from dataconnect/movie/assets/firebase_logo.svg
rename to dataconnect/src/assets/firebase_logo.svg
diff --git a/dataconnect/movie/components/carousel.tsx b/dataconnect/src/components/carousel.tsx
similarity index 100%
rename from dataconnect/movie/components/carousel.tsx
rename to dataconnect/src/components/carousel.tsx
diff --git a/dataconnect/movie/components/moviecard.tsx b/dataconnect/src/components/moviecard.tsx
similarity index 92%
rename from dataconnect/movie/components/moviecard.tsx
rename to dataconnect/src/components/moviecard.tsx
index c9bda5144..bf357074c 100644
--- a/dataconnect/movie/components/moviecard.tsx
+++ b/dataconnect/src/components/moviecard.tsx
@@ -1,8 +1,9 @@
-import { useEffect, useState } from 'react';
+import { useContext, useEffect, useState } from 'react';
 import Link from 'next/link';
 import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
-import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
+import { onAuthStateChanged, User } from 'firebase/auth';
 import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from '@/lib/dataconnect-sdk';
+import { AuthContext } from '@/lib/firebase';
 
 interface MovieCardProps {
   id: string;
@@ -16,7 +17,7 @@ interface MovieCardProps {
 const MovieCard: React.FC<MovieCardProps> = ({ id, title, imageUrl, rating, genre, tags }) => {
   const [user, setUser] = useState<User | null>(null);
   const [isFavorited, setIsFavorited] = useState(false);
-  const auth = getAuth();
+  let auth  = useContext(AuthContext);
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
@@ -70,7 +71,7 @@ const MovieCard: React.FC<MovieCardProps> = ({ id, title, imageUrl, rating, genr
             <div className="mt-2 text-gray-400">
               {genre && (
                 <Link href={`/genre/${genre.toLowerCase()}`} passHref legacyBehavior>
-                  <a className="block mb-1 hover:underline">{capitalize(genre)}</a>
+                  <p className="block mb-1 hover:underline">{capitalize(genre)}</p>
                 </Link>
               )}
               <div className="flex flex-wrap gap-1">
diff --git a/dataconnect/movie/components/navbar.tsx b/dataconnect/src/components/navbar.tsx
similarity index 91%
rename from dataconnect/movie/components/navbar.tsx
rename to dataconnect/src/components/navbar.tsx
index 875c0065a..ea1d20a18 100644
--- a/dataconnect/movie/components/navbar.tsx
+++ b/dataconnect/src/components/navbar.tsx
@@ -1,8 +1,7 @@
-import { useEffect, useState } from 'react';
-import { getAuth, signInWithPopup, GoogleAuthProvider, signOut, User } from 'firebase/auth';
-import { firebaseapp, onAuthStateChanged } from '@/lib/firebase';
+import { useEffect, useState, useContext } from 'react';
+import { onAuthStateChanged, signInWithPopup, GoogleAuthProvider, signOut, User } from 'firebase/auth';
+import { AuthContext } from '@/lib/firebase';
 import Link from 'next/link';
-import { useRouter } from 'next/navigation';
 import { upsertUser } from '@/lib/dataconnect-sdk';
 import { FaSearch } from 'react-icons/fa';
 import Image from 'next/image';
@@ -10,8 +9,7 @@ import firebaseLogo from '@/assets/firebase_logo.svg';
 
 const Navbar = () => {
   const [user, setUser] = useState<User | null>(null);
-  const auth = getAuth(firebaseapp);
-  const router = useRouter();
+  let auth  = useContext(AuthContext);
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, async (user) => {
diff --git a/dataconnect/src/lib/firebase.tsx b/dataconnect/src/lib/firebase.tsx
new file mode 100644
index 000000000..4bf5fedcc
--- /dev/null
+++ b/dataconnect/src/lib/firebase.tsx
@@ -0,0 +1,43 @@
+import { initializeApp, getApps } from 'firebase/app';
+import { getAuth } from "firebase/auth";
+import { createContext } from 'react';
+
+const firebaseConfig = {
+  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
+  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
+  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
+  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
+  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
+  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
+};
+
+const firebaseapp =
+  getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
+
+const auth = getAuth(firebaseapp);
+
+if (process.env.NODE_ENV === 'development') {
+//   connectDataConnectEmulator(
+//     dataconnect, 
+//     '127.0.0.1', 
+//     9399, 
+//     false
+//   );
+//   // connectAuthEmulator(auth, "http://127.0.0.1:9099");
+}
+const AuthContext = createContext(auth);
+function AuthProvider({
+  children,
+}: {
+  children: React.ReactNode;
+}) {
+  const auth = getAuth(firebaseapp);
+
+  return (
+    <AuthContext.Provider value={ auth }>
+      {children}
+    </AuthContext.Provider>
+  );
+}
+
+export { firebaseapp, AuthContext, AuthProvider };
diff --git a/dataconnect/movie/next-env.d.ts b/dataconnect/src/next-env.d.ts
similarity index 100%
rename from dataconnect/movie/next-env.d.ts
rename to dataconnect/src/next-env.d.ts
diff --git a/dataconnect/movie/package.json b/dataconnect/src/package.json
similarity index 84%
rename from dataconnect/movie/package.json
rename to dataconnect/src/package.json
index d809017ea..02fe621ac 100644
--- a/dataconnect/movie/package.json
+++ b/dataconnect/src/package.json
@@ -9,7 +9,8 @@
   },
   "dependencies": {
     "autoprefixer": "^10.4.19",
-    "firebase": "10.12.0-dataconnect-preview.388b61c7e",
+    "firebase": "^10.12.0-dataconnect-preview.388b61c7e",
+    "firebase-functions": "^5.0.1",
     "next": "latest",
     "postcss": "^8.4.38",
     "react": "^18.3.1",
diff --git a/dataconnect/movie/postcss.config.js b/dataconnect/src/postcss.config.js
similarity index 100%
rename from dataconnect/movie/postcss.config.js
rename to dataconnect/src/postcss.config.js
diff --git a/dataconnect/movie/styles.css b/dataconnect/src/styles.css
similarity index 100%
rename from dataconnect/movie/styles.css
rename to dataconnect/src/styles.css
diff --git a/dataconnect/movie/tailwind.config.js b/dataconnect/src/tailwind.config.js
similarity index 100%
rename from dataconnect/movie/tailwind.config.js
rename to dataconnect/src/tailwind.config.js
diff --git a/dataconnect/movie/tsconfig.json b/dataconnect/src/tsconfig.json
similarity index 100%
rename from dataconnect/movie/tsconfig.json
rename to dataconnect/src/tsconfig.json

From e2b06c30f3342a4457ba7508f9dc6a8ceca3bd73 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Thu, 25 Jul 2024 16:31:57 -0400
Subject: [PATCH 20/82] update: convert from next to vite

---
 dataconnect/.gitignore                        |   4 +-
 dataconnect/app/.env                          |   6 +
 dataconnect/app/.eslintrc.cjs                 |  18 +++
 dataconnect/app/.gitignore                    |  24 ++++
 dataconnect/app/index.html                    |  13 +++
 dataconnect/app/package.json                  |  35 ++++++
 dataconnect/{src => app}/postcss.config.js    |   4 +-
 dataconnect/app/src/App.css                   |  42 +++++++
 dataconnect/app/src/App.tsx                   |  32 ++++++
 .../{ => app}/src/assets/firebase_logo.svg    |   0
 .../{ => app}/src/components/carousel.tsx     |  10 +-
 dataconnect/app/src/components/moviecard.tsx  | 107 ++++++++++++++++++
 .../{ => app}/src/components/navbar.tsx       |  29 +++--
 .../{src/styles.css => app/src/index.css}     |   0
 dataconnect/app/src/layout/RootLayout.tsx     |  14 +++
 dataconnect/app/src/lib/firebase.tsx          |  28 +++++
 dataconnect/app/src/main.tsx                  |  10 ++
 .../[id]/page.tsx => app/src/pages/Actor.tsx} |  59 ++++++----
 .../src/pages/AdvancedSearch.tsx}             |  17 ++-
 .../page.tsx => app/src/pages/Genre.tsx}      |  11 +-
 .../app/page.tsx => app/src/pages/Home.tsx}   |  22 ++--
 .../[id]/page.tsx => app/src/pages/Movie.tsx} |  32 +++---
 .../page.tsx => app/src/pages/MyProfile.tsx}  |  24 ++--
 dataconnect/app/src/pages/NotFound.tsx        |  29 +++++
 .../src/pages/VectorSearch.tsx}               |   7 +-
 dataconnect/app/src/vite-env.d.ts             |   1 +
 dataconnect/app/tailwind.config.js            |  15 +++
 dataconnect/{src => app}/tsconfig.json        |   8 +-
 dataconnect/app/tsconfig.node.json            |  10 ++
 dataconnect/app/vite.config.ts                |  13 +++
 dataconnect/dataconnect/dataconnect.yaml      |   6 +-
 .../movie-connector/connector.yaml            |  10 +-
 dataconnect/firebase.json                     |  24 ++--
 dataconnect/src/app/layout.tsx                |  23 ----
 dataconnect/src/components/moviecard.tsx      | 101 -----------------
 dataconnect/src/lib/firebase.tsx              |  43 -------
 dataconnect/src/next-env.d.ts                 |   5 -
 dataconnect/src/package.json                  |  27 -----
 dataconnect/src/tailwind.config.js            |  13 ---
 39 files changed, 526 insertions(+), 350 deletions(-)
 create mode 100644 dataconnect/app/.env
 create mode 100644 dataconnect/app/.eslintrc.cjs
 create mode 100644 dataconnect/app/.gitignore
 create mode 100644 dataconnect/app/index.html
 create mode 100644 dataconnect/app/package.json
 rename dataconnect/{src => app}/postcss.config.js (73%)
 create mode 100644 dataconnect/app/src/App.css
 create mode 100644 dataconnect/app/src/App.tsx
 rename dataconnect/{ => app}/src/assets/firebase_logo.svg (100%)
 rename dataconnect/{ => app}/src/components/carousel.tsx (82%)
 create mode 100644 dataconnect/app/src/components/moviecard.tsx
 rename dataconnect/{ => app}/src/components/navbar.tsx (69%)
 rename dataconnect/{src/styles.css => app/src/index.css} (100%)
 create mode 100644 dataconnect/app/src/layout/RootLayout.tsx
 create mode 100644 dataconnect/app/src/lib/firebase.tsx
 create mode 100644 dataconnect/app/src/main.tsx
 rename dataconnect/{src/app/actor/[id]/page.tsx => app/src/pages/Actor.tsx} (76%)
 rename dataconnect/{src/app/advancedsearch/page.tsx => app/src/pages/AdvancedSearch.tsx} (95%)
 rename dataconnect/{src/app/genre/[genre]/page.tsx => app/src/pages/Genre.tsx} (90%)
 rename dataconnect/{src/app/page.tsx => app/src/pages/Home.tsx} (55%)
 rename dataconnect/{src/app/movie/[id]/page.tsx => app/src/pages/Movie.tsx} (94%)
 rename dataconnect/{src/app/myprofile/page.tsx => app/src/pages/MyProfile.tsx} (93%)
 create mode 100644 dataconnect/app/src/pages/NotFound.tsx
 rename dataconnect/{src/app/vectors/page.tsx => app/src/pages/VectorSearch.tsx} (96%)
 create mode 100644 dataconnect/app/src/vite-env.d.ts
 create mode 100644 dataconnect/app/tailwind.config.js
 rename dataconnect/{src => app}/tsconfig.json (78%)
 create mode 100644 dataconnect/app/tsconfig.node.json
 create mode 100644 dataconnect/app/vite.config.ts
 delete mode 100644 dataconnect/src/app/layout.tsx
 delete mode 100644 dataconnect/src/components/moviecard.tsx
 delete mode 100644 dataconnect/src/lib/firebase.tsx
 delete mode 100644 dataconnect/src/next-env.d.ts
 delete mode 100644 dataconnect/src/package.json
 delete mode 100644 dataconnect/src/tailwind.config.js

diff --git a/dataconnect/.gitignore b/dataconnect/.gitignore
index 43adbed10..5f24225c0 100644
--- a/dataconnect/.gitignore
+++ b/dataconnect/.gitignore
@@ -46,6 +46,8 @@ build/Release
 
 # Dependency directories
 node_modules/
+app/src/lib/dataconnect-sdk/
+app/package-lock.json
 
 # Optional npm cache directory
 .npm
@@ -65,5 +67,3 @@ node_modules/
 # dotenv environment variables file
 .next
 .dataconnect
-src/lib/dataconnect-sdk
-src/package-lock.json
diff --git a/dataconnect/app/.env b/dataconnect/app/.env
new file mode 100644
index 000000000..ae2d76e12
--- /dev/null
+++ b/dataconnect/app/.env
@@ -0,0 +1,6 @@
+VITE_FIREBASE_API_KEY=your-api-key
+VITE_FIREBASE_AUTH_DOMAIN=your-auth-domain
+VITE_FIREBASE_PROJECT_ID=your-project-id
+VITE_FIREBASE_STORAGE_BUCKET=your-storage-bucket
+VITE_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id
+VITE_FIREBASE_APP_ID=your-app-id
\ No newline at end of file
diff --git a/dataconnect/app/.eslintrc.cjs b/dataconnect/app/.eslintrc.cjs
new file mode 100644
index 000000000..d6c953795
--- /dev/null
+++ b/dataconnect/app/.eslintrc.cjs
@@ -0,0 +1,18 @@
+module.exports = {
+  root: true,
+  env: { browser: true, es2020: true },
+  extends: [
+    'eslint:recommended',
+    'plugin:@typescript-eslint/recommended',
+    'plugin:react-hooks/recommended',
+  ],
+  ignorePatterns: ['dist', '.eslintrc.cjs'],
+  parser: '@typescript-eslint/parser',
+  plugins: ['react-refresh'],
+  rules: {
+    'react-refresh/only-export-components': [
+      'warn',
+      { allowConstantExport: true },
+    ],
+  },
+}
diff --git a/dataconnect/app/.gitignore b/dataconnect/app/.gitignore
new file mode 100644
index 000000000..a547bf36d
--- /dev/null
+++ b/dataconnect/app/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/dataconnect/app/index.html b/dataconnect/app/index.html
new file mode 100644
index 000000000..7152fe9d8
--- /dev/null
+++ b/dataconnect/app/index.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" type="image/svg+xml" href="/app/src/assets/firebase_logo.svg" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>FriendlyMovies</title>
+  </head>
+  <body>
+    <div id="root"></div>
+    <script type="module" src="/src/main.tsx"></script>
+  </body>
+</html>
diff --git a/dataconnect/app/package.json b/dataconnect/app/package.json
new file mode 100644
index 000000000..0798e9c64
--- /dev/null
+++ b/dataconnect/app/package.json
@@ -0,0 +1,35 @@
+{
+  "name": "app",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "tsc && vite build",
+    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "dotenv": "^16.4.5",
+    "firebase": "^10.12.0-dataconnect-preview.388b61c7e",
+    "react": "^18.3.1",
+    "react-dom": "^18.3.1",
+    "react-icons": "^5.2.1",
+    "react-router-dom": "^6.25.1"
+  },
+  "devDependencies": {
+    "@types/react": "^18.2.43",
+    "@types/react-dom": "^18.2.17",
+    "@typescript-eslint/eslint-plugin": "^6.14.0",
+    "@typescript-eslint/parser": "^6.14.0",
+    "@vitejs/plugin-react": "^4.2.1",
+    "autoprefixer": "^10.4.19",
+    "eslint": "^8.55.0",
+    "eslint-plugin-react-hooks": "^4.6.0",
+    "eslint-plugin-react-refresh": "^0.4.5",
+    "postcss": "^8.4.40",
+    "tailwindcss": "^3.4.7",
+    "typescript": "^5.2.2",
+    "vite": "^5.0.8"
+  }
+}
diff --git a/dataconnect/src/postcss.config.js b/dataconnect/app/postcss.config.js
similarity index 73%
rename from dataconnect/src/postcss.config.js
rename to dataconnect/app/postcss.config.js
index 12a703d90..2e7af2b7f 100644
--- a/dataconnect/src/postcss.config.js
+++ b/dataconnect/app/postcss.config.js
@@ -1,6 +1,6 @@
-module.exports = {
+export default {
   plugins: {
     tailwindcss: {},
     autoprefixer: {},
   },
-};
+}
diff --git a/dataconnect/app/src/App.css b/dataconnect/app/src/App.css
new file mode 100644
index 000000000..b9d355df2
--- /dev/null
+++ b/dataconnect/app/src/App.css
@@ -0,0 +1,42 @@
+#root {
+  max-width: 1280px;
+  margin: 0 auto;
+  padding: 2rem;
+  text-align: center;
+}
+
+.logo {
+  height: 6em;
+  padding: 1.5em;
+  will-change: filter;
+  transition: filter 300ms;
+}
+.logo:hover {
+  filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+  filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  a:nth-of-type(2) .logo {
+    animation: logo-spin infinite 20s linear;
+  }
+}
+
+.card {
+  padding: 2em;
+}
+
+.read-the-docs {
+  color: #888;
+}
diff --git a/dataconnect/app/src/App.tsx b/dataconnect/app/src/App.tsx
new file mode 100644
index 000000000..b1e3ed5ef
--- /dev/null
+++ b/dataconnect/app/src/App.tsx
@@ -0,0 +1,32 @@
+import React from "react";
+import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
+import Home from "./pages/Home";
+import ActorPage from "./pages/Actor";
+import MoviePage from "./pages/Movie";
+import GenrePage from "./pages/Genre";
+import MyProfilePage from "./pages/MyProfile";
+import VectorSearchPage from "./pages/VectorSearch";
+import AdvancedSearchPage from "./pages/AdvancedSearch";
+import NotFound from "./pages/NotFound";
+import RootLayout from "./layout/RootLayout";
+
+const App: React.FC = () => {
+  return (
+    <Router>
+      <RootLayout>
+        <Routes>
+          <Route path="/" element={<Home />} />
+          <Route path="/actor/:id" element={<ActorPage />} />
+          <Route path="/movie/:id" element={<MoviePage />} />
+          <Route path="/genre/:genre" element={<GenrePage />} />
+          <Route path="/myprofile" element={<MyProfilePage />} />
+          <Route path="/vectorsearch" element={<VectorSearchPage />} />
+          <Route path="/advancedsearch" element={<AdvancedSearchPage />} />
+          <Route path="*" element={<NotFound />} />
+        </Routes>
+      </RootLayout>
+    </Router>
+  );
+};
+
+export default App;
diff --git a/dataconnect/src/assets/firebase_logo.svg b/dataconnect/app/src/assets/firebase_logo.svg
similarity index 100%
rename from dataconnect/src/assets/firebase_logo.svg
rename to dataconnect/app/src/assets/firebase_logo.svg
diff --git a/dataconnect/src/components/carousel.tsx b/dataconnect/app/src/components/carousel.tsx
similarity index 82%
rename from dataconnect/src/components/carousel.tsx
rename to dataconnect/app/src/components/carousel.tsx
index 0813e6abd..a859799d0 100644
--- a/dataconnect/src/components/carousel.tsx
+++ b/dataconnect/app/src/components/carousel.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import MovieCard from './moviecard';
+import MovieCard from '@/components/moviecard';
 
 interface CarouselProps {
   title: string;
@@ -7,9 +7,9 @@ interface CarouselProps {
     id: string;
     title?: string;
     imageUrl?: string;
-    rating?: number;
-    genre?: string;
-    tags?: string[];
+    rating?: number | null;
+    genre?: string | null;
+    tags?: string[] | null;
   }[];
 }
 
@@ -22,7 +22,7 @@ const Carousel: React.FC<CarouselProps> = ({ title, movies }) => {
           <div className="flex-shrink-0" key={movie.id}>
             <MovieCard
               id={movie.id}
-              title={movie.title}
+              title={movie.title || 'TBA'}
               imageUrl={movie.imageUrl}
               rating={movie.rating}
               genre={movie.genre}
diff --git a/dataconnect/app/src/components/moviecard.tsx b/dataconnect/app/src/components/moviecard.tsx
new file mode 100644
index 000000000..c5c71d41f
--- /dev/null
+++ b/dataconnect/app/src/components/moviecard.tsx
@@ -0,0 +1,107 @@
+import React, { useContext, useEffect, useState } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
+import { onAuthStateChanged, User } from 'firebase/auth';
+import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from '@/lib/dataconnect-sdk';
+import { AuthContext } from '@/lib/firebase';
+
+interface MovieCardProps {
+  id: string;
+  title: string;
+  imageUrl?: string;
+  rating?: number | null;
+  genre?: string | null;
+  tags?: string[] | null;
+}
+
+const MovieCard: React.FC<MovieCardProps> = ({ id, title, imageUrl, rating, genre, tags }) => {
+  const [user, setUser] = useState<User | null>(null);
+  const [isFavorited, setIsFavorited] = useState(false);
+  const auth = useContext(AuthContext);
+  const navigate = useNavigate();
+
+  useEffect(() => {
+    const unsubscribe = onAuthStateChanged(auth, (user) => {
+      if (user) {
+        setUser(user);
+        checkIfFavorited();
+      }
+    });
+
+    return () => unsubscribe();
+  }, [auth, id]);
+
+  const checkIfFavorited = async () => {
+    try {
+      const response = await getIfFavoritedMovie({ movieId: id });
+      setIsFavorited(!!response.data.favorite_movie);
+    } catch (error) {
+      console.error('Error checking if favorited:', error);
+    }
+  };
+
+  const handleFavoriteToggle = async (e: React.MouseEvent) => {
+    e.stopPropagation();
+    e.preventDefault();
+    if (!user) return;
+    try {
+      if (isFavorited) {
+        await deleteFavoritedMovie({ movieId: id });
+      } else {
+        await addFavoritedMovie({ movieId: id });
+      }
+      setIsFavorited(!isFavorited);
+    } catch (error) {
+      console.error('Error updating favorite status:', error);
+    }
+  };
+
+  const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
+
+  const handleCardClick = () => {
+    navigate(`/movie/${id}`);
+  };
+
+  return (
+    <div
+      className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-1000 transform hover:scale-105 cursor-pointer w-64"
+      onClick={handleCardClick}
+    >
+      <div>
+        <img className="w-full h-64 object-cover" src={imageUrl} alt={title} />
+        <div className="p-4">
+          <div className="font-bold text-lg mb-1 text-white whitespace-nowrap overflow-hidden overflow-ellipsis">{title}</div>
+          <div className="flex items-center text-yellow-500">
+            <MdStar className="text-yellow-500" size={20} />
+            <span className="ml-1 text-gray-400">{rating ?? 'N/A'}</span>
+          </div>
+          <div className="mt-2 text-gray-400">
+            {genre && (
+              <Link to={`/genre/${genre.toLowerCase()}`} className="block mb-1 hover:underline">
+                {capitalize(genre)}
+              </Link>
+            )}
+            <div className="flex flex-wrap gap-1">
+              {tags?.map((tag, index) => (
+                <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{capitalize(tag)}</span>
+              ))}
+            </div>
+          </div>
+          {user && (
+            <div className="mt-2 flex space-x-2 items-center">
+              <button
+                className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
+                aria-label="Favorite"
+                onClick={handleFavoriteToggle}
+              >
+                {isFavorited ? <MdFavorite size={20} /> : <MdFavoriteBorder size={20} />}
+              </button>
+            </div>
+          )}
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default MovieCard;
diff --git a/dataconnect/src/components/navbar.tsx b/dataconnect/app/src/components/navbar.tsx
similarity index 69%
rename from dataconnect/src/components/navbar.tsx
rename to dataconnect/app/src/components/navbar.tsx
index ea1d20a18..2afabe834 100644
--- a/dataconnect/src/components/navbar.tsx
+++ b/dataconnect/app/src/components/navbar.tsx
@@ -1,21 +1,20 @@
-import { useEffect, useState, useContext } from 'react';
+import React, { useEffect, useState, useContext } from 'react';
 import { onAuthStateChanged, signInWithPopup, GoogleAuthProvider, signOut, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
-import Link from 'next/link';
+import { Link } from 'react-router-dom';
 import { upsertUser } from '@/lib/dataconnect-sdk';
 import { FaSearch } from 'react-icons/fa';
-import Image from 'next/image';
 import firebaseLogo from '@/assets/firebase_logo.svg';
 
-const Navbar = () => {
+const Navbar: React.FC = () => {
   const [user, setUser] = useState<User | null>(null);
-  let auth  = useContext(AuthContext);
+  const auth = useContext(AuthContext);
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, async (user) => {
       if (user) {
         setUser(user);
-        const username = user.email.substring(0, user.email.indexOf("@"));
+        const username = user.email?.substring(0, user.email?.indexOf("@")) || 'anon';
         await upsertUser({ username });
       } else {
         setUser(null);
@@ -37,40 +36,40 @@ const Navbar = () => {
     <nav className="bg-black p-4">
       <div className="container mx-auto flex justify-between items-center">
         <div className="flex items-center space-x-4">
-          <Link href="/" className="flex items-center text-white text-lg font-bold">
-            <Image src={firebaseLogo} alt="Firebase Logo" width={30} height={30} className="mr-2" />
+          <Link to="/" className="flex items-center text-white text-lg font-bold">
+            <img src={firebaseLogo} alt="Firebase Logo" width={30} height={30} className="mr-2" />
             FriendlyMovies
           </Link>
           <div className="relative group">
             <button className="text-gray-200 hover:text-white">Genres</button>
             <div className="absolute hidden group-hover:block bg-black text-white mt-1 rounded shadow-lg" style={{ minWidth: '150px' }}>
               <div className="py-2">
-                <Link href="/genre/action" className="block px-4 py-2 hover:bg-gray-800">
+                <Link to="/genre/action" className="block px-4 py-2 hover:bg-gray-800">
                   Action
                 </Link>
-                <Link href="/genre/crime" className="block px-4 py-2 hover:bg-gray-800">
+                <Link to="/genre/crime" className="block px-4 py-2 hover:bg-gray-800">
                   Crime
                 </Link>
-                <Link href="/genre/drama" className="block px-4 py-2 hover:bg-gray-800">
+                <Link to="/genre/drama" className="block px-4 py-2 hover:bg-gray-800">
                   Drama
                 </Link>
-                <Link href="/genre/sci-fi" className="block px-4 py-2 hover:bg-gray-800">
+                <Link to="/genre/sci-fi" className="block px-4 py-2 hover:bg-gray-800">
                   Sci-Fi
                 </Link>
               </div>
             </div>
           </div>
-          <Link href="/vectors" className="text-gray-200 hover:text-white">
+          <Link to="/vectors" className="text-gray-200 hover:text-white">
             Vector Search
           </Link>
         </div>
-        <Link href="/advancedsearch" className="flex items-center text-gray-200 hover:text-white mx-auto">
+        <Link to="/advancedsearch" className="flex items-center text-gray-200 hover:text-white mx-auto">
           <FaSearch className="mr-2" />
           Advanced Search
         </Link>
         <div className="flex items-center space-x-4">
           {user && (
-            <Link href="/myprofile" className="text-yellow-500 hover:text-yellow-400">
+            <Link to="/myprofile" className="text-yellow-500 hover:text-yellow-400">
               My Profile
             </Link>
           )}
diff --git a/dataconnect/src/styles.css b/dataconnect/app/src/index.css
similarity index 100%
rename from dataconnect/src/styles.css
rename to dataconnect/app/src/index.css
diff --git a/dataconnect/app/src/layout/RootLayout.tsx b/dataconnect/app/src/layout/RootLayout.tsx
new file mode 100644
index 000000000..78e2d2045
--- /dev/null
+++ b/dataconnect/app/src/layout/RootLayout.tsx
@@ -0,0 +1,14 @@
+import { AuthProvider } from '@/lib/firebase';
+import Navbar from '@/components/navbar';
+import '@/index.css';
+
+export default function RootLayout({ children }: { children: React.ReactNode }) {
+  return (
+    <AuthProvider>
+      <Navbar />
+      <div className="bg-gray-800 min-h-screen min-w-screen flex justify-center items-center">
+        {children}
+      </div>
+    </AuthProvider>
+  );
+}
diff --git a/dataconnect/app/src/lib/firebase.tsx b/dataconnect/app/src/lib/firebase.tsx
new file mode 100644
index 000000000..6c925c064
--- /dev/null
+++ b/dataconnect/app/src/lib/firebase.tsx
@@ -0,0 +1,28 @@
+import { initializeApp, getApps } from 'firebase/app';
+import { getAuth } from 'firebase/auth';
+import { createContext } from 'react';
+
+const firebaseConfig = {
+  apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
+  authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
+  projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
+  storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
+  messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
+  appId: import.meta.env.VITE_FIREBASE_APP_ID,
+};
+
+const firebaseApp = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
+
+const auth = getAuth(firebaseApp);
+
+const AuthContext = createContext(auth);
+
+function AuthProvider({ children }: { children: React.ReactNode }) {
+  return (
+    <AuthContext.Provider value={auth}>
+      {children}
+    </AuthContext.Provider>
+  );
+}
+
+export { AuthContext, AuthProvider };
diff --git a/dataconnect/app/src/main.tsx b/dataconnect/app/src/main.tsx
new file mode 100644
index 000000000..964aeb4c7
--- /dev/null
+++ b/dataconnect/app/src/main.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App'
+import './index.css'
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+  <React.StrictMode>
+    <App />
+  </React.StrictMode>,
+)
diff --git a/dataconnect/src/app/actor/[id]/page.tsx b/dataconnect/app/src/pages/Actor.tsx
similarity index 76%
rename from dataconnect/src/app/actor/[id]/page.tsx
rename to dataconnect/app/src/pages/Actor.tsx
index c04c5fc5c..8a807eb2f 100644
--- a/dataconnect/src/app/actor/[id]/page.tsx
+++ b/dataconnect/app/src/pages/Actor.tsx
@@ -1,19 +1,26 @@
-'use client';
-import { useContext, useEffect, useState } from 'react';
-import { useParams } from 'next/navigation';
-import Link from 'next/link';
+import React, { useContext, useEffect, useState } from 'react';
+import { useParams, Link, useNavigate } from 'react-router-dom';
 import { MdFavorite, MdFavoriteBorder } from 'react-icons/md';
-import { getActorById, GetActorByIdResponse, addFavoritedActor, deleteFavoriteActor, getIfFavoritedActor } from '@/lib/dataconnect-sdk';
+import {
+  getActorById,
+  GetActorByIdResponse,
+  addFavoritedActor,
+  deleteFavoriteActor,
+  getIfFavoritedActor
+} from '@/lib/dataconnect-sdk';
 import { onAuthStateChanged, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
+import NotFound from './NotFound';
 
-const Page = () => {
-  const { id } = useParams() as { id: string };
+const ActorPage: React.FC = () => {
+  const { id } = useParams<{ id: string }>();
+  const actorId = id || '';
   const [actor, setActor] = useState<GetActorByIdResponse['actor'] | null>(null);
   const [loading, setLoading] = useState(true);
   const [authUser, setAuthUser] = useState<User | null>(null);
   const [isFavorited, setIsFavorited] = useState(false);
-  let auth  = useContext(AuthContext);
+  const auth = useContext(AuthContext);
+  const navigate = useNavigate();
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
@@ -24,16 +31,21 @@ const Page = () => {
     });
 
     return () => unsubscribe();
-  }, [id]);
+  }, [auth, actorId]);
 
   useEffect(() => {
-    if (id) {
+    if (actorId) {
       const fetchActor = async () => {
         try {
-          const response = await getActorById({ id });
-          setActor(response.data.actor);
+          const response = await getActorById({ id: actorId });
+          if (response.data.actor) {
+            setActor(response.data.actor);
+          } else {
+            navigate('/not-found');
+          }
         } catch (error) {
           console.error('Error fetching actor:', error);
+          navigate('/not-found');
         } finally {
           setLoading(false);
         }
@@ -41,11 +53,11 @@ const Page = () => {
 
       fetchActor();
     }
-  }, [id]);
+  }, [actorId, navigate]);
 
   const checkIfFavorited = async () => {
     try {
-      const response = await getIfFavoritedActor({ actorId: id });
+      const response = await getIfFavoritedActor({ actorId });
       setIsFavorited(!!response.data.favorite_actor);
     } catch (error) {
       console.error('Error checking if favorited:', error);
@@ -56,9 +68,9 @@ const Page = () => {
     if (!authUser) return;
     try {
       if (isFavorited) {
-        await deleteFavoriteActor({ actorId: id });
+        await deleteFavoriteActor({ actorId });
       } else {
-        await addFavoritedActor({ actorId: id });
+        await addFavoritedActor({ actorId });
       }
       setIsFavorited(!isFavorited);
     } catch (error) {
@@ -67,9 +79,8 @@ const Page = () => {
   };
 
   if (loading) return <p>Loading...</p>;
-  if (!actor) return <p>Actor not found.</p>;
 
-  return (
+  return actor ? (
     <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
       <div className="flex flex-col md:flex-row mb-8">
         <img className="w-full md:w-1/3 object-cover rounded-lg shadow-md" src={actor.imageUrl} alt={actor.name} />
@@ -91,14 +102,14 @@ const Page = () => {
         <h2 className="text-2xl font-bold mb-2">Main Roles</h2>
         <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
           {actor.mainActors.map((movie) => (
-            <Link key={movie.id} href={`/movie/${movie.id}`}>
+            <Link key={movie.id} to={`/movie/${movie.id}`}>
               <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
                 <img className="w-full h-48 object-cover" src={movie.imageUrl} alt={movie.title} />
                 <div className="p-4">
                   <h3 className="font-bold text-lg mb-1 text-white">{movie.title}</h3>
                   <p className="text-sm text-gray-400">{movie.genre}</p>
                   <div className="flex flex-wrap gap-1 mt-2">
-                    {movie.tags.map((tag, index) => (
+                    {movie.tags?.map((tag, index) => (
                       <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{tag}</span>
                     ))}
                   </div>
@@ -113,14 +124,14 @@ const Page = () => {
         <h2 className="text-2xl font-bold mb-2">Supporting Roles</h2>
         <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
           {actor.supportingActors.map((movie) => (
-            <Link key={movie.id} href={`/movie/${movie.id}`}>
+            <Link key={movie.id} to={`/movie/${movie.id}`}>
               <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
                 <img className="w-full h-48 object-cover" src={movie.imageUrl} alt={movie.title} />
                 <div className="p-4">
                   <h3 className="font-bold text-lg mb-1 text-white">{movie.title}</h3>
                   <p className="text-sm text-gray-400">{movie.genre}</p>
                   <div className="flex flex-wrap gap-1 mt-2">
-                    {movie.tags.map((tag, index) => (
+                    {movie.tags?.map((tag, index) => (
                       <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{tag}</span>
                     ))}
                   </div>
@@ -131,7 +142,9 @@ const Page = () => {
         </div>
       </div>
     </div>
+  ) : (
+    <NotFound />
   );
 };
 
-export default Page;
+export default ActorPage;
diff --git a/dataconnect/src/app/advancedsearch/page.tsx b/dataconnect/app/src/pages/AdvancedSearch.tsx
similarity index 95%
rename from dataconnect/src/app/advancedsearch/page.tsx
rename to dataconnect/app/src/pages/AdvancedSearch.tsx
index 3ab0b4e0a..8eefcf454 100644
--- a/dataconnect/src/app/advancedsearch/page.tsx
+++ b/dataconnect/app/src/pages/AdvancedSearch.tsx
@@ -1,13 +1,12 @@
-'use client';
-import { useState } from 'react';
-import Link from 'next/link';
+import React, { useState } from 'react';
+import { Link } from 'react-router-dom';
 import { FaSearch } from 'react-icons/fa';
 import { MdStar } from 'react-icons/md';
 import { searchAll } from '@/lib/dataconnect-sdk';
 
 const genres = ['', 'action', 'crime', 'drama', 'sci-fi', 'thriller', 'adventure'];
 
-const Page = () => {
+const AdvancedSearchPage: React.FC = () => {
   const [searchQuery, setSearchQuery] = useState('');
   const [releaseYearRange, setReleaseYearRange] = useState({ min: 1900, max: 2030 });
   const [genre, setGenre] = useState('');
@@ -130,7 +129,7 @@ const Page = () => {
           <h3 className="text-xl font-bold mb-2">Movies Matching Title</h3>
           <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
             {results.moviesMatchingTitle?.map((movie) => (
-              <Link key={movie.id} href={`/movie/${movie.id}`}>
+              <Link key={movie.id} to={`/movie/${movie.id}`}>
                 <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
                   <img className="w-full h-64 object-cover" src={movie.imageUrl} alt={movie.title} />
                   <div className="p-4">
@@ -154,7 +153,7 @@ const Page = () => {
           <h3 className="text-xl font-bold mb-2">Movies Matching Description</h3>
           <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
             {results.moviesMatchingDescription?.map((movie) => (
-              <Link key={movie.id} href={`/movie/${movie.id}`}>
+              <Link key={movie.id} to={`/movie/${movie.id}`}>
                 <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
                   <img className="w-full h-64 object-cover" src={movie.imageUrl} alt={movie.title} />
                   <div className="p-4">
@@ -178,7 +177,7 @@ const Page = () => {
           <h3 className="text-xl font-bold mb-2">Actors</h3>
           <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
             {results.actors?.map((actor) => (
-              <Link key={actor.id} href={`/actor/${actor.id}`}>
+              <Link key={actor.id} to={`/actor/${actor.id}`}>
                 <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer">
                   <img className="w-full h-64 object-cover" src={actor.imageUrl} alt={actor.name} />
                   <div className="p-4">
@@ -204,7 +203,7 @@ const Page = () => {
                   <MdStar className="text-yellow-500" size={20} />
                   <span className="ml-1 text-gray-400">{review.rating}</span>
                 </div>
-                <Link href={`/movie/${review.movie.id}`} className="mt-2 text-blue-500 hover:text-blue-400 transition-colors">
+                <Link to={`/movie/${review.movie.id}`} className="mt-2 text-blue-500 hover:text-blue-400 transition-colors">
                   {review?.movie?.title}
                 </Link>
               </div>
@@ -216,4 +215,4 @@ const Page = () => {
   );
 };
 
-export default Page;
+export default AdvancedSearchPage;
diff --git a/dataconnect/src/app/genre/[genre]/page.tsx b/dataconnect/app/src/pages/Genre.tsx
similarity index 90%
rename from dataconnect/src/app/genre/[genre]/page.tsx
rename to dataconnect/app/src/pages/Genre.tsx
index c0cc6ca1b..edbfb92e8 100644
--- a/dataconnect/src/app/genre/[genre]/page.tsx
+++ b/dataconnect/app/src/pages/Genre.tsx
@@ -1,11 +1,10 @@
-'use client';
-import { useEffect, useState } from 'react';
-import { useParams } from 'next/navigation';
+import React, { useEffect, useState } from 'react';
+import { useParams } from 'react-router-dom';
 import MovieCard from '@/components/moviecard';
 import { ListMoviesByGenreResponse, listMoviesByGenre } from '@/lib/dataconnect-sdk';
 
-const Page = () => {
-  const { genre } = useParams() as { genre: string };
+const GenrePage: React.FC = () => {
+  const { genre } = useParams<{ genre: string }>();
   const [mostPopular, setMostPopular] = useState<ListMoviesByGenreResponse['mostPopular']>([]);
   const [mostRecent, setMostRecent] = useState<ListMoviesByGenreResponse['mostRecent']>([]);
   const [loading, setLoading] = useState(true);
@@ -67,4 +66,4 @@ const Page = () => {
   );
 };
 
-export default Page;
+export default GenrePage;
diff --git a/dataconnect/src/app/page.tsx b/dataconnect/app/src/pages/Home.tsx
similarity index 55%
rename from dataconnect/src/app/page.tsx
rename to dataconnect/app/src/pages/Home.tsx
index f0aec106e..993bf074c 100644
--- a/dataconnect/src/app/page.tsx
+++ b/dataconnect/app/src/pages/Home.tsx
@@ -1,22 +1,16 @@
-"use client";
-import { useEffect, useState } from "react";
-import Carousel from "@/components/carousel";
-import {
-  listMovies,
-  ListMoviesResponse,
-} from "@/lib/dataconnect-sdk";
+import React, { useEffect, useState } from 'react';
+import Carousel from '@/components/carousel';
+import { listMovies, ListMoviesResponse } from '@/lib/dataconnect-sdk';
 
-const Page = () => {
+const HomePage: React.FC = () => {
   const [topMovies, setTopMovies] = useState<ListMoviesResponse["movies"]>([]);
-  const [latestMovies, setLatestMovies] = useState<
-  ListMoviesResponse["movies"]
-  >([]);
+  const [latestMovies, setLatestMovies] = useState<ListMoviesResponse["movies"]>([]);
 
   useEffect(() => {
     const fetchMovies = async () => {
       try {
-        const topMoviesResponse = await listMovies({orderByRating :"DESC", limit: 10});
-        const latestMoviesResponse = await listMovies({orderByReleaseYear :"DESC", limit: 10});
+        const topMoviesResponse = await listMovies({ orderByRating: "DESC", limit: 10 });
+        const latestMoviesResponse = await listMovies({ orderByReleaseYear: "DESC", limit: 10 });
 
         setTopMovies(topMoviesResponse.data.movies);
         setLatestMovies(latestMoviesResponse.data.movies);
@@ -36,4 +30,4 @@ const Page = () => {
   );
 };
 
-export default Page;
+export default HomePage;
diff --git a/dataconnect/src/app/movie/[id]/page.tsx b/dataconnect/app/src/pages/Movie.tsx
similarity index 94%
rename from dataconnect/src/app/movie/[id]/page.tsx
rename to dataconnect/app/src/pages/Movie.tsx
index 910a78387..b3153bed5 100644
--- a/dataconnect/src/app/movie/[id]/page.tsx
+++ b/dataconnect/app/src/pages/Movie.tsx
@@ -1,7 +1,6 @@
 'use client';
 import { useContext, useEffect, useState } from 'react';
-import { useParams, useRouter } from 'next/navigation';
-import Link from 'next/link';
+import { useParams, Link } from 'react-router-dom';
 import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
 import {
   getMovieById,
@@ -16,9 +15,9 @@ import {
 } from '@/lib/dataconnect-sdk';
 import { onAuthStateChanged, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
+import NotFound from './NotFound';
 
-const Page = () => {
-  const router = useRouter();
+const MoviePage = () => {
   const { id } = useParams() as { id: string };
   const [movie, setMovie] = useState<GetMovieByIdResponse['movie'] | null>(null);
   const [loading, setLoading] = useState(true);
@@ -28,7 +27,7 @@ const Page = () => {
   const [userReview, setUserReview] = useState<GetMovieByIdResponse['movie']['reviews'][0] | null>(null);
   const [rating, setRating] = useState(0);
   const [similarMovies, setSimilarMovies] = useState<SearchMovieDescriptionUsingL2similarityResponse['movies_descriptionEmbedding_similarity']>([]);
-  let auth  = useContext(AuthContext);
+  const auth = useContext(AuthContext);
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
@@ -99,7 +98,7 @@ const Page = () => {
     e.preventDefault();
     if (!authUser) return;
     try {
-        const response  = await addReview({ movieId: id, rating, reviewText });
+        await addReview({ movieId: id, rating, reviewText });
       setReviewText('');
       setRating(0);
       const updatedMovie = await getMovieById({ id });
@@ -122,12 +121,10 @@ const Page = () => {
       console.error('Error deleting review:', error);
     }
   };
-
   if (loading) return <p>Loading...</p>;
-  if (!movie) return <p>Movie not found.</p>;
-
+  if (!movie) return <NotFound />;
   return (
-    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
+  <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
       <div className="flex flex-col md:flex-row mb-8">
         <img className="w-full md:w-1/3 object-cover rounded-lg shadow-md" src={movie.imageUrl} alt={movie.title} />
         <div className="md:ml-8 mt-4 md:mt-0 flex-1">
@@ -141,7 +138,7 @@ const Page = () => {
             <p><span className="font-bold">Genre:</span> {movie.genre}</p>
             <p><span className="font-bold">Release Year:</span> {movie.releaseYear}</p>
             <p><span className="font-bold">Director:</span> {movie.metadata[0]?.director}</p>
-            <p><span className="font-bold">Tags:</span> {movie.tags.join(', ')}</p>
+            <p><span className="font-bold">Tags:</span> {movie.tags?.join(', ')}</p>
           </div>
           <div className="mt-4 flex space-x-4">
             <button
@@ -159,7 +156,7 @@ const Page = () => {
         <h2 className="text-2xl font-bold mb-2">Main Actors</h2>
         <div className="flex overflow-x-auto space-x-4">
           {movie.mainActors.map((actor) => (
-            <Link key={actor.id} href={`/actor/${actor.id}`} passHref>
+            <Link key={actor.id} to={`/actor/${actor.id}`}>
               <div className="flex-shrink-0 bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer w-32">
                 <img className="w-full h-32 object-cover" src={actor.imageUrl} alt={actor.name} />
                 <div className="p-2 text-center">
@@ -175,7 +172,7 @@ const Page = () => {
         <h2 className="text-2xl font-bold mb-2">Supporting Actors</h2>
         <div className="flex overflow-x-auto space-x-4">
           {movie.supportingActors.map((actor) => (
-            <Link key={actor.id} href={`/actor/${actor.id}`} passHref>
+            <Link key={actor.id} to={`/actor/${actor.id}`}>
               <div className="flex-shrink-0 bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer w-32">
                 <img className="w-full h-32 object-cover" src={actor.imageUrl} alt={actor.name} />
                 <div className="p-2 text-center">
@@ -216,7 +213,7 @@ const Page = () => {
               Submit Review
             </button>
           </form>
-        ) : (<></>)}
+        ) : null}
 
         {movie.reviews.map((review) => (
           <div key={review.id} className="mb-4 p-4 bg-gray-800 rounded-lg shadow-md">
@@ -244,7 +241,7 @@ const Page = () => {
         <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
           {similarMovies.map((similarMovie) => (
             <div key={similarMovie.id} className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative">
-              <Link href={`/movie/${similarMovie.id}`}>
+              <Link to={`/movie/${similarMovie.id}`}>
                 <img className="w-full h-64 object-cover" src={similarMovie.imageUrl} alt={similarMovie.title} />
               </Link>
               <div className="p-4">
@@ -275,8 +272,7 @@ const Page = () => {
           ))}
         </div>
       </div>
-    </div>
-  );
+    </div>);
 };
 
-export default Page;
+export default MoviePage;
diff --git a/dataconnect/src/app/myprofile/page.tsx b/dataconnect/app/src/pages/MyProfile.tsx
similarity index 93%
rename from dataconnect/src/app/myprofile/page.tsx
rename to dataconnect/app/src/pages/MyProfile.tsx
index 47847163c..a1d69cf1f 100644
--- a/dataconnect/src/app/myprofile/page.tsx
+++ b/dataconnect/app/src/pages/MyProfile.tsx
@@ -1,7 +1,5 @@
-'use client';
-import { useContext, useEffect, useState } from 'react';
-import { useRouter } from 'next/navigation';
-import Link from 'next/link';
+import React, { useContext, useEffect, useState } from 'react';
+import { useNavigate, Link } from 'react-router-dom';
 import { onAuthStateChanged, User } from 'firebase/auth';
 import {
   getCurrentUser,
@@ -13,25 +11,25 @@ import {
 import { MdStar } from 'react-icons/md';
 import { AuthContext } from '@/lib/firebase';
 
-const Page = () => {
-  const router = useRouter();
+const MyProfilePage: React.FC = () => {
+  const navigate = useNavigate();
   const [authUser, setAuthUser] = useState<User | null>(null);
   const [user, setUser] = useState<GetCurrentUserResponse['user'] | null>(null);
   const [loading, setLoading] = useState(true);
-  let auth  = useContext(AuthContext);
-  
+  const auth = useContext(AuthContext);
+
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
       if (user) {
         setAuthUser(user);
         fetchUserProfile();
       } else {
-        router.push('/');
+        navigate('/');
       }
     });
 
     return () => unsubscribe();
-  }, [router]);
+  }, [navigate, auth]);
 
   const fetchUserProfile = async () => {
     try {
@@ -111,7 +109,7 @@ const Page = () => {
         <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
           {user.favoriteMovies.map((fav) => (
             <div key={fav.movie.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative max-h-80">
-              <Link href={`/movie/${fav.movie.id}`}>
+              <Link to={`/movie/${fav.movie.id}`}>
                 <img className="w-full h-64 object-cover" src={fav.movie.imageUrl} alt={fav.movie.title} />
               </Link>
               <div className="p-4">
@@ -144,7 +142,7 @@ const Page = () => {
         <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
           {user.favoriteActors.map((favActor) => (
             <div key={favActor.actor.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative max-h-80">
-              <Link href={`/actor/${favActor.actor.id}`}>
+              <Link to={`/actor/${favActor.actor.id}`}>
                 <img className="w-48 h-48 object-cover rounded-full mx-auto mt-4" src={favActor.actor.imageUrl} alt={favActor.actor.name} />
               </Link>
               <div className="p-4 text-center">
@@ -164,4 +162,4 @@ const Page = () => {
   );
 };
 
-export default Page;
+export default MyProfilePage;
diff --git a/dataconnect/app/src/pages/NotFound.tsx b/dataconnect/app/src/pages/NotFound.tsx
new file mode 100644
index 000000000..a518c3952
--- /dev/null
+++ b/dataconnect/app/src/pages/NotFound.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+
+const NotFound: React.FC = () => {
+  const navigate = useNavigate();
+
+  return (
+    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white text-center">
+      <h1 className="text-4xl font-bold mb-4">404 - Page Not Found</h1>
+      <p className="mb-8">The page you are looking for does not exist.</p>
+      <div className="flex justify-center space-x-4">
+        <button
+          onClick={() => navigate(-1)}
+          className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
+        >
+          Go Back
+        </button>
+        <button
+          onClick={() => navigate('/')}
+          className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
+        >
+          Home Page
+        </button>
+      </div>
+    </div>
+  );
+};
+
+export default NotFound;
diff --git a/dataconnect/src/app/vectors/page.tsx b/dataconnect/app/src/pages/VectorSearch.tsx
similarity index 96%
rename from dataconnect/src/app/vectors/page.tsx
rename to dataconnect/app/src/pages/VectorSearch.tsx
index 65e1fb9a8..e60e05777 100644
--- a/dataconnect/src/app/vectors/page.tsx
+++ b/dataconnect/app/src/pages/VectorSearch.tsx
@@ -1,9 +1,8 @@
-'use client';
-import { useState } from 'react';
+import React, { useState } from 'react';
 import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '@/lib/dataconnect-sdk';
 import { FaSpinner } from 'react-icons/fa';
 
-const Page = () => {
+const VectorSearchPage: React.FC = () => {
   const [query, setQuery] = useState('');
   const [loading, setLoading] = useState(false);
   const [results, setResults] = useState<SearchMovieDescriptionUsingL2similarityResponse['movies_descriptionEmbedding_similarity']>([]);
@@ -78,4 +77,4 @@ const Page = () => {
   );
 };
 
-export default Page;
+export default VectorSearchPage;
diff --git a/dataconnect/app/src/vite-env.d.ts b/dataconnect/app/src/vite-env.d.ts
new file mode 100644
index 000000000..11f02fe2a
--- /dev/null
+++ b/dataconnect/app/src/vite-env.d.ts
@@ -0,0 +1 @@
+/// <reference types="vite/client" />
diff --git a/dataconnect/app/tailwind.config.js b/dataconnect/app/tailwind.config.js
new file mode 100644
index 000000000..129cf61a5
--- /dev/null
+++ b/dataconnect/app/tailwind.config.js
@@ -0,0 +1,15 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+  content: [
+    './src/**/*.{js,ts,jsx,tsx}',
+    './src/*.{js,ts,jsx,tsx}',
+    './src/***/**/*.{js,ts,jsx,tsx}',
+    './components/**/*.{js,ts,jsx,tsx}',
+  ],
+  darkMode: 'class',
+  theme: {
+    extend: {},
+  },
+  plugins: [],
+}
+
diff --git a/dataconnect/src/tsconfig.json b/dataconnect/app/tsconfig.json
similarity index 78%
rename from dataconnect/src/tsconfig.json
rename to dataconnect/app/tsconfig.json
index 065550b56..7c235bb4e 100644
--- a/dataconnect/src/tsconfig.json
+++ b/dataconnect/app/tsconfig.json
@@ -2,11 +2,13 @@
   "compilerOptions": {
     "baseUrl": ".",
     "paths": {
-      "@/lib/*": ["lib/*"],
-      "@/components/*": ["components/*"],
+      "@/lib/*": ["src/lib/*"],
+      "@/components/*": ["src/components/*"],
       "@/assets/*": ["assets/*"],
+      "@/pages/*": ["src/pages/*"],
+      "@/layout/*": ["src/layout/*"],
     },
-    "target": "es5",
+    "target": "es2020",
     "lib": ["dom", "dom.iterable", "esnext"],
     "allowJs": true,
     "skipLibCheck": true,
diff --git a/dataconnect/app/tsconfig.node.json b/dataconnect/app/tsconfig.node.json
new file mode 100644
index 000000000..42872c59f
--- /dev/null
+++ b/dataconnect/app/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "composite": true,
+    "skipLibCheck": true,
+    "module": "ESNext",
+    "moduleResolution": "bundler",
+    "allowSyntheticDefaultImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/dataconnect/app/vite.config.ts b/dataconnect/app/vite.config.ts
new file mode 100644
index 000000000..17fa26f37
--- /dev/null
+++ b/dataconnect/app/vite.config.ts
@@ -0,0 +1,13 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import path from 'path';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [react()],
+  resolve: {
+    alias: {
+      '@': path.resolve(__dirname, 'src'),
+    },
+  },
+})
diff --git a/dataconnect/dataconnect/dataconnect.yaml b/dataconnect/dataconnect/dataconnect.yaml
index 0b82e9d62..15a5f9974 100644
--- a/dataconnect/dataconnect/dataconnect.yaml
+++ b/dataconnect/dataconnect/dataconnect.yaml
@@ -1,11 +1,11 @@
 specVersion: "v1alpha"
-serviceId: "your-dataconnect-service-id"
+serviceId: "fdc-quickstart-web"
 location: "us-central1"
 schema:
   source: "./schema"
   datasource:
     postgresql:
-      database: "your-dataconnect-database"
+      database: "fdc-quickstart-web"
       cloudSql:
-        instanceId: "your-dataconnect-id"
+        instanceId: "fdc-quickstart-web"
 connectorDirs: ["./movie-connector"]
diff --git a/dataconnect/dataconnect/movie-connector/connector.yaml b/dataconnect/dataconnect/movie-connector/connector.yaml
index ced088385..3247d642f 100644
--- a/dataconnect/dataconnect/movie-connector/connector.yaml
+++ b/dataconnect/dataconnect/movie-connector/connector.yaml
@@ -1,14 +1,6 @@
 connectorId: movie-connector
-# Required. Accepted values are either "PUBLIC" or "ADMIN" (only "PUBLIC" for gated private
-# preview). If "ADMIN", the connector in this directory is an AdminConnector and its operations
-# are gated by IAM.
 authMode: PUBLIC
 generate:
   javascriptSdk:
-    # Create a custom package name for your generated SDK
     package: "@movie/sdk"
-    # Tells Data Connect where to store the generated SDK code, this should be in the same
-    # directory as your app code
-    outputDir: "../../src/lib/dataconnect-sdk"
-    # This property tells Data Connect what directory to install the generated SDK to
-    packageJsonDir: "../../src/lib/dataconnect-sdk"
+    outputDir: ../../app/lib/dataconnect-sdk
diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json
index dd78268e0..c46f2c51d 100644
--- a/dataconnect/firebase.json
+++ b/dataconnect/firebase.json
@@ -1,24 +1,24 @@
 {
-  "dataconnect": {
-    "source": "./dataconnect"
-  },
   "emulators": {
-    "dataconnect": {
-      "port": 9399
-    },
-    "ui": {
-      "enabled": false
-    },
-    "singleProjectMode": true,
     "auth": {
       "port": 9099
     },
     "hosting": {
       "port": 5000
-    }
+    },
+    "dataconnect": {
+      "port": 9399
+    },
+    "ui": {
+      "enabled": true
+    },
+    "singleProjectMode": true
+  },
+  "dataconnect": {
+    "source": "./dataconnect"
   },
   "hosting": {
-    "source": "src",
+    "source": "app",
     "ignore": [
       "firebase.json",
       "**/.*",
diff --git a/dataconnect/src/app/layout.tsx b/dataconnect/src/app/layout.tsx
deleted file mode 100644
index 4062127c2..000000000
--- a/dataconnect/src/app/layout.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-"use client";
-import { AuthProvider } from '@/lib/firebase';
-import Navbar from "@/components/navbar";
-
-import "../styles.css";
-export default function RootLayout({
-  children,
-}: {
-  children: React.ReactNode;
-}) {
-  return (
-    <html lang="en">
-      <body>
-        <AuthProvider>
-          <Navbar />
-          <div className="bg-gray-800 min-h-screen min-w-screen flex justify-center items-center">
-            {children}
-          </div>
-        </AuthProvider>
-      </body>
-    </html>
-  );
-}
diff --git a/dataconnect/src/components/moviecard.tsx b/dataconnect/src/components/moviecard.tsx
deleted file mode 100644
index bf357074c..000000000
--- a/dataconnect/src/components/moviecard.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import { useContext, useEffect, useState } from 'react';
-import Link from 'next/link';
-import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
-import { onAuthStateChanged, User } from 'firebase/auth';
-import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from '@/lib/dataconnect-sdk';
-import { AuthContext } from '@/lib/firebase';
-
-interface MovieCardProps {
-  id: string;
-  title: string;
-  imageUrl?: string;
-  rating?: number;
-  genre?: string;
-  tags?: string[];
-}
-
-const MovieCard: React.FC<MovieCardProps> = ({ id, title, imageUrl, rating, genre, tags }) => {
-  const [user, setUser] = useState<User | null>(null);
-  const [isFavorited, setIsFavorited] = useState(false);
-  let auth  = useContext(AuthContext);
-
-  useEffect(() => {
-    const unsubscribe = onAuthStateChanged(auth, (user) => {
-      if (user) {
-        setUser(user);
-        checkIfFavorited();
-      }
-    });
-
-    return () => unsubscribe();
-  }, [auth, id]);
-
-  const checkIfFavorited = async () => {
-    try {
-      const response = await getIfFavoritedMovie({ movieId: id });
-      setIsFavorited(!!response.data.favorite_movie);
-    } catch (error) {
-      console.error('Error checking if favorited:', error);
-    }
-  };
-
-  const handleFavoriteToggle = async (e: React.MouseEvent) => {
-    e.stopPropagation();
-    e.preventDefault();
-    if (!user) return;
-    try {
-      if (isFavorited) {
-        await deleteFavoritedMovie({ movieId: id });
-      } else {
-        await addFavoritedMovie({ movieId: id });
-      }
-      setIsFavorited(!isFavorited);
-    } catch (error) {
-      console.error('Error updating favorite status:', error);
-    }
-  };
-
-  const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
-
-  return (
-    <div className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-1000 transform hover:scale-105 cursor-pointer w-64">
-      <Link href={`/movie/${id}`} passHref>
-        <div>
-          <img className="w-full h-64 object-cover" src={imageUrl} alt={title} />
-          <div className="p-4">
-            <div className="font-bold text-lg mb-1 text-white whitespace-nowrap overflow-hidden overflow-ellipsis">{title}</div>
-            <div className="flex items-center text-yellow-500">
-              <MdStar className="text-yellow-500" size={20} />
-              <span className="ml-1 text-gray-400">{rating}</span>
-            </div>
-            <div className="mt-2 text-gray-400">
-              {genre && (
-                <Link href={`/genre/${genre.toLowerCase()}`} passHref legacyBehavior>
-                  <p className="block mb-1 hover:underline">{capitalize(genre)}</p>
-                </Link>
-              )}
-              <div className="flex flex-wrap gap-1">
-                {tags?.map((tag, index) => (
-                  <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{capitalize(tag)}</span>
-                ))}
-              </div>
-            </div>
-            {user && (
-              <div className="mt-2 flex space-x-2 items-center">
-                <button
-                  className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
-                  aria-label="Favorite"
-                  onClick={handleFavoriteToggle}
-                >
-                  {isFavorited ? <MdFavorite size={20} /> : <MdFavoriteBorder size={20} />}
-                </button>
-              </div>
-            )}
-          </div>
-        </div>
-      </Link>
-    </div>
-  );
-};
-
-export default MovieCard;
diff --git a/dataconnect/src/lib/firebase.tsx b/dataconnect/src/lib/firebase.tsx
deleted file mode 100644
index 4bf5fedcc..000000000
--- a/dataconnect/src/lib/firebase.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import { initializeApp, getApps } from 'firebase/app';
-import { getAuth } from "firebase/auth";
-import { createContext } from 'react';
-
-const firebaseConfig = {
-  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
-  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
-  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
-  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
-  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
-  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
-};
-
-const firebaseapp =
-  getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
-
-const auth = getAuth(firebaseapp);
-
-if (process.env.NODE_ENV === 'development') {
-//   connectDataConnectEmulator(
-//     dataconnect, 
-//     '127.0.0.1', 
-//     9399, 
-//     false
-//   );
-//   // connectAuthEmulator(auth, "http://127.0.0.1:9099");
-}
-const AuthContext = createContext(auth);
-function AuthProvider({
-  children,
-}: {
-  children: React.ReactNode;
-}) {
-  const auth = getAuth(firebaseapp);
-
-  return (
-    <AuthContext.Provider value={ auth }>
-      {children}
-    </AuthContext.Provider>
-  );
-}
-
-export { firebaseapp, AuthContext, AuthProvider };
diff --git a/dataconnect/src/next-env.d.ts b/dataconnect/src/next-env.d.ts
deleted file mode 100644
index 4f11a03dc..000000000
--- a/dataconnect/src/next-env.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-/// <reference types="next" />
-/// <reference types="next/image-types/global" />
-
-// NOTE: This file should not be edited
-// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/dataconnect/src/package.json b/dataconnect/src/package.json
deleted file mode 100644
index 02fe621ac..000000000
--- a/dataconnect/src/package.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
-  "version": "0.1.0",
-  "private": true,
-  "scripts": {
-    "dev": "next dev",
-    "build": "next build",
-    "start": "next start",
-    "lint": "next lint"
-  },
-  "dependencies": {
-    "autoprefixer": "^10.4.19",
-    "firebase": "^10.12.0-dataconnect-preview.388b61c7e",
-    "firebase-functions": "^5.0.1",
-    "next": "latest",
-    "postcss": "^8.4.38",
-    "react": "^18.3.1",
-    "react-dom": "^18.3.1",
-    "react-icons": "^5.2.1",
-    "tailwindcss": "^3.4.3"
-  },
-  "devDependencies": {
-    "@types/node": "^20.10.8",
-    "@types/react": "^18.2.47",
-    "@types/react-dom": "18.2.18",
-    "typescript": "^5.3.3"
-  }
-}
diff --git a/dataconnect/src/tailwind.config.js b/dataconnect/src/tailwind.config.js
deleted file mode 100644
index 86ae52d0c..000000000
--- a/dataconnect/src/tailwind.config.js
+++ /dev/null
@@ -1,13 +0,0 @@
-module.exports = {
-  content: [
-    './app/**/*.{js,ts,jsx,tsx}',
-    './app/*.{js,ts,jsx,tsx}',
-    './app/***/**/*.{js,ts,jsx,tsx}',
-    './components/**/*.{js,ts,jsx,tsx}',
-  ],
-  darkMode: 'class',
-  theme: {
-    extend: {},
-  },
-  plugins: [],
-};

From ed62e3596791a4fe8c771eccded46e9b2e1b4bbf Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Thu, 25 Jul 2024 16:32:46 -0400
Subject: [PATCH 21/82] fix: env

---
 dataconnect/app/.env | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dataconnect/app/.env b/dataconnect/app/.env
index ae2d76e12..3ccd40ee1 100644
--- a/dataconnect/app/.env
+++ b/dataconnect/app/.env
@@ -3,4 +3,4 @@ VITE_FIREBASE_AUTH_DOMAIN=your-auth-domain
 VITE_FIREBASE_PROJECT_ID=your-project-id
 VITE_FIREBASE_STORAGE_BUCKET=your-storage-bucket
 VITE_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id
-VITE_FIREBASE_APP_ID=your-app-id
\ No newline at end of file
+VITE_FIREBASE_APP_ID=your-app-id

From 747f4586c2c3a14ac3ca9c2f6a5977f008105169 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Thu, 25 Jul 2024 16:34:30 -0400
Subject: [PATCH 22/82] fix: routing

---
 dataconnect/app/src/components/navbar.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dataconnect/app/src/components/navbar.tsx b/dataconnect/app/src/components/navbar.tsx
index 2afabe834..873a73894 100644
--- a/dataconnect/app/src/components/navbar.tsx
+++ b/dataconnect/app/src/components/navbar.tsx
@@ -59,7 +59,7 @@ const Navbar: React.FC = () => {
               </div>
             </div>
           </div>
-          <Link to="/vectors" className="text-gray-200 hover:text-white">
+          <Link to="/vectorsearch" className="text-gray-200 hover:text-white">
             Vector Search
           </Link>
         </div>

From 0039fc62fe50596dd8cdc11589615cd401f63585 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Thu, 25 Jul 2024 16:46:55 -0400
Subject: [PATCH 23/82] fix: dev env

---
 dataconnect/app/src/lib/firebase.tsx | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/dataconnect/app/src/lib/firebase.tsx b/dataconnect/app/src/lib/firebase.tsx
index 6c925c064..749efd1ba 100644
--- a/dataconnect/app/src/lib/firebase.tsx
+++ b/dataconnect/app/src/lib/firebase.tsx
@@ -15,6 +15,16 @@ const firebaseApp = getApps().length === 0 ? initializeApp(firebaseConfig) : get
 
 const auth = getAuth(firebaseApp);
 
+if (process.env.NODE_ENV === 'development') {
+  // connectDataConnectEmulator(
+  //   dataconnect, 
+  //   'localhost', 
+  //   9399, 
+  //   false
+  // );
+  // connectAuthEmulator(auth, "http://localhost:9099");
+}
+
 const AuthContext = createContext(auth);
 
 function AuthProvider({ children }: { children: React.ReactNode }) {

From dae81844e634c15818a562a8d42e1f1b57e46158 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Thu, 25 Jul 2024 19:17:26 -0400
Subject: [PATCH 24/82] fix: auth params

---
 dataconnect/dataconnect/movie-connector/mutations.gql | 2 +-
 dataconnect/dataconnect/movie-connector/queries.gql   | 4 ++--
 dataconnect/dataconnect/schema/schema.gql             | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/dataconnect/dataconnect/movie-connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
index 11e4aa759..9d4d25458 100644
--- a/dataconnect/dataconnect/movie-connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -101,7 +101,7 @@ mutation deleteReview(
 }
 
 # Upsert (update or insert) a user based on their username
-mutation upsertUser($username: String!) @auth(level: PUBLIC) {
+mutation upsertUser($username: String!) @auth(level: USER) {
   user_upsert(
     data: {
       id_expr: "auth.uid"
diff --git a/dataconnect/dataconnect/movie-connector/queries.gql b/dataconnect/dataconnect/movie-connector/queries.gql
index 4ea8ce9ab..5a75ea6ec 100644
--- a/dataconnect/dataconnect/movie-connector/queries.gql
+++ b/dataconnect/dataconnect/movie-connector/queries.gql
@@ -195,7 +195,7 @@ query SearchMovieAnd(
 
 # Get favorite movies by user ID
 query GetUserFavoriteMovies @auth(level: USER) {
-  user(key: {id_expr: "auth.uid"}) {
+  user(id_expr: "auth.uid") {
     favorite_movies_on_user {
       movie {
         id
@@ -350,7 +350,7 @@ query searchMovieDescriptionUsingL2Similarity($query: String!)
     compare_embed: { model: "textembedding-gecko@003", text: $query }
     method: L2
     within: 2
-    where: { description: { ne: "" } }
+    where: { isNull: false }
     limit: 5
   ) {
     id
diff --git a/dataconnect/dataconnect/schema/schema.gql b/dataconnect/dataconnect/schema/schema.gql
index 6c151e78b..f25a8a19d 100644
--- a/dataconnect/dataconnect/schema/schema.gql
+++ b/dataconnect/dataconnect/schema/schema.gql
@@ -21,7 +21,7 @@ type Movie
 type MovieMetadata
   @table {
   # @ref creates a field in the current table (MovieMetadata) that holds the primary key of the referenced type
-  # In this case, @ref(fields: "id") is implied
+  # In this case, @ref(fields: "movieId", references: "id") is implied
   movie: Movie! @ref
   # movieId: UUID <- this is created by the above @ref
   director: String

From b4dff9e87a3bc85b0a10cd67857c38c45a0ab1b7 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 13:38:14 -0400
Subject: [PATCH 25/82] fix: remove react.fc

---
 dataconnect/app/src/App.tsx                  |  2 +-
 dataconnect/app/src/components/carousel.tsx  |  7 ++++++-
 dataconnect/app/src/components/moviecard.tsx | 11 ++++++++++-
 dataconnect/app/src/components/navbar.tsx    |  2 +-
 dataconnect/app/src/pages/Actor.tsx          |  2 +-
 dataconnect/app/src/pages/AdvancedSearch.tsx |  2 +-
 dataconnect/app/src/pages/Genre.tsx          |  2 +-
 dataconnect/app/src/pages/Home.tsx           |  2 +-
 dataconnect/app/src/pages/MyProfile.tsx      |  2 +-
 dataconnect/app/src/pages/NotFound.tsx       |  2 +-
 dataconnect/app/src/pages/VectorSearch.tsx   |  2 +-
 11 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/dataconnect/app/src/App.tsx b/dataconnect/app/src/App.tsx
index b1e3ed5ef..c9dd1f0d6 100644
--- a/dataconnect/app/src/App.tsx
+++ b/dataconnect/app/src/App.tsx
@@ -10,7 +10,7 @@ import AdvancedSearchPage from "./pages/AdvancedSearch";
 import NotFound from "./pages/NotFound";
 import RootLayout from "./layout/RootLayout";
 
-const App: React.FC = () => {
+const App = () => {
   return (
     <Router>
       <RootLayout>
diff --git a/dataconnect/app/src/components/carousel.tsx b/dataconnect/app/src/components/carousel.tsx
index a859799d0..928454362 100644
--- a/dataconnect/app/src/components/carousel.tsx
+++ b/dataconnect/app/src/components/carousel.tsx
@@ -13,7 +13,12 @@ interface CarouselProps {
   }[];
 }
 
-const Carousel: React.FC<CarouselProps> = ({ title, movies }) => {
+const Carousel = (
+  {
+    title,
+    movies
+  }: CarouselProps
+) => {
   return (
     <section className="carousel py-8">
       <h2 className="text-gray-200 text-2xl font-bold mb-4">{title}</h2>
diff --git a/dataconnect/app/src/components/moviecard.tsx b/dataconnect/app/src/components/moviecard.tsx
index c5c71d41f..875531861 100644
--- a/dataconnect/app/src/components/moviecard.tsx
+++ b/dataconnect/app/src/components/moviecard.tsx
@@ -14,7 +14,16 @@ interface MovieCardProps {
   tags?: string[] | null;
 }
 
-const MovieCard: React.FC<MovieCardProps> = ({ id, title, imageUrl, rating, genre, tags }) => {
+const MovieCard = (
+  {
+    id,
+    title,
+    imageUrl,
+    rating,
+    genre,
+    tags
+  }: MovieCardProps
+) => {
   const [user, setUser] = useState<User | null>(null);
   const [isFavorited, setIsFavorited] = useState(false);
   const auth = useContext(AuthContext);
diff --git a/dataconnect/app/src/components/navbar.tsx b/dataconnect/app/src/components/navbar.tsx
index 873a73894..0eff71154 100644
--- a/dataconnect/app/src/components/navbar.tsx
+++ b/dataconnect/app/src/components/navbar.tsx
@@ -6,7 +6,7 @@ import { upsertUser } from '@/lib/dataconnect-sdk';
 import { FaSearch } from 'react-icons/fa';
 import firebaseLogo from '@/assets/firebase_logo.svg';
 
-const Navbar: React.FC = () => {
+const Navbar = () => {
   const [user, setUser] = useState<User | null>(null);
   const auth = useContext(AuthContext);
 
diff --git a/dataconnect/app/src/pages/Actor.tsx b/dataconnect/app/src/pages/Actor.tsx
index 8a807eb2f..d1e065353 100644
--- a/dataconnect/app/src/pages/Actor.tsx
+++ b/dataconnect/app/src/pages/Actor.tsx
@@ -12,7 +12,7 @@ import { onAuthStateChanged, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
 import NotFound from './NotFound';
 
-const ActorPage: React.FC = () => {
+const ActorPage = () => {
   const { id } = useParams<{ id: string }>();
   const actorId = id || '';
   const [actor, setActor] = useState<GetActorByIdResponse['actor'] | null>(null);
diff --git a/dataconnect/app/src/pages/AdvancedSearch.tsx b/dataconnect/app/src/pages/AdvancedSearch.tsx
index 8eefcf454..dcd5ee922 100644
--- a/dataconnect/app/src/pages/AdvancedSearch.tsx
+++ b/dataconnect/app/src/pages/AdvancedSearch.tsx
@@ -6,7 +6,7 @@ import { searchAll } from '@/lib/dataconnect-sdk';
 
 const genres = ['', 'action', 'crime', 'drama', 'sci-fi', 'thriller', 'adventure'];
 
-const AdvancedSearchPage: React.FC = () => {
+const AdvancedSearchPage = () => {
   const [searchQuery, setSearchQuery] = useState('');
   const [releaseYearRange, setReleaseYearRange] = useState({ min: 1900, max: 2030 });
   const [genre, setGenre] = useState('');
diff --git a/dataconnect/app/src/pages/Genre.tsx b/dataconnect/app/src/pages/Genre.tsx
index edbfb92e8..45b02cd0c 100644
--- a/dataconnect/app/src/pages/Genre.tsx
+++ b/dataconnect/app/src/pages/Genre.tsx
@@ -3,7 +3,7 @@ import { useParams } from 'react-router-dom';
 import MovieCard from '@/components/moviecard';
 import { ListMoviesByGenreResponse, listMoviesByGenre } from '@/lib/dataconnect-sdk';
 
-const GenrePage: React.FC = () => {
+const GenrePage = () => {
   const { genre } = useParams<{ genre: string }>();
   const [mostPopular, setMostPopular] = useState<ListMoviesByGenreResponse['mostPopular']>([]);
   const [mostRecent, setMostRecent] = useState<ListMoviesByGenreResponse['mostRecent']>([]);
diff --git a/dataconnect/app/src/pages/Home.tsx b/dataconnect/app/src/pages/Home.tsx
index 993bf074c..abbcd4220 100644
--- a/dataconnect/app/src/pages/Home.tsx
+++ b/dataconnect/app/src/pages/Home.tsx
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
 import Carousel from '@/components/carousel';
 import { listMovies, ListMoviesResponse } from '@/lib/dataconnect-sdk';
 
-const HomePage: React.FC = () => {
+const HomePage = () => {
   const [topMovies, setTopMovies] = useState<ListMoviesResponse["movies"]>([]);
   const [latestMovies, setLatestMovies] = useState<ListMoviesResponse["movies"]>([]);
 
diff --git a/dataconnect/app/src/pages/MyProfile.tsx b/dataconnect/app/src/pages/MyProfile.tsx
index a1d69cf1f..8568e64f0 100644
--- a/dataconnect/app/src/pages/MyProfile.tsx
+++ b/dataconnect/app/src/pages/MyProfile.tsx
@@ -11,7 +11,7 @@ import {
 import { MdStar } from 'react-icons/md';
 import { AuthContext } from '@/lib/firebase';
 
-const MyProfilePage: React.FC = () => {
+const MyProfilePage = () => {
   const navigate = useNavigate();
   const [authUser, setAuthUser] = useState<User | null>(null);
   const [user, setUser] = useState<GetCurrentUserResponse['user'] | null>(null);
diff --git a/dataconnect/app/src/pages/NotFound.tsx b/dataconnect/app/src/pages/NotFound.tsx
index a518c3952..22d9c6040 100644
--- a/dataconnect/app/src/pages/NotFound.tsx
+++ b/dataconnect/app/src/pages/NotFound.tsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import { useNavigate } from 'react-router-dom';
 
-const NotFound: React.FC = () => {
+const NotFound = () => {
   const navigate = useNavigate();
 
   return (
diff --git a/dataconnect/app/src/pages/VectorSearch.tsx b/dataconnect/app/src/pages/VectorSearch.tsx
index e60e05777..1e164f519 100644
--- a/dataconnect/app/src/pages/VectorSearch.tsx
+++ b/dataconnect/app/src/pages/VectorSearch.tsx
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
 import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '@/lib/dataconnect-sdk';
 import { FaSpinner } from 'react-icons/fa';
 
-const VectorSearchPage: React.FC = () => {
+const VectorSearchPage = () => {
   const [query, setQuery] = useState('');
   const [loading, setLoading] = useState(false);
   const [results, setResults] = useState<SearchMovieDescriptionUsingL2similarityResponse['movies_descriptionEmbedding_similarity']>([]);

From 5a76298c7b19bf2c6ab10ceab0fdb5499820f526 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 14:09:28 -0400
Subject: [PATCH 26/82] fix: const to functions

---
 dataconnect/app/src/App.tsx                  |  6 ++--
 dataconnect/app/src/components/carousel.tsx  | 11 ++----
 dataconnect/app/src/components/moviecard.tsx | 38 ++++++++++----------
 dataconnect/app/src/components/navbar.tsx    | 14 ++++----
 dataconnect/app/src/pages/Actor.tsx          | 14 ++++----
 dataconnect/app/src/pages/AdvancedSearch.tsx | 10 +++---
 dataconnect/app/src/pages/Genre.tsx          | 10 +++---
 dataconnect/app/src/pages/Home.tsx           | 10 +++---
 dataconnect/app/src/pages/Movie.tsx          | 36 +++++++++----------
 dataconnect/app/src/pages/MyProfile.tsx      | 22 ++++++------
 dataconnect/app/src/pages/NotFound.tsx       |  6 ++--
 dataconnect/app/src/pages/VectorSearch.tsx   | 10 +++---
 12 files changed, 80 insertions(+), 107 deletions(-)

diff --git a/dataconnect/app/src/App.tsx b/dataconnect/app/src/App.tsx
index c9dd1f0d6..ab89c0a6b 100644
--- a/dataconnect/app/src/App.tsx
+++ b/dataconnect/app/src/App.tsx
@@ -10,7 +10,7 @@ import AdvancedSearchPage from "./pages/AdvancedSearch";
 import NotFound from "./pages/NotFound";
 import RootLayout from "./layout/RootLayout";
 
-const App = () => {
+export default function App() {
   return (
     <Router>
       <RootLayout>
@@ -27,6 +27,4 @@ const App = () => {
       </RootLayout>
     </Router>
   );
-};
-
-export default App;
+}
diff --git a/dataconnect/app/src/components/carousel.tsx b/dataconnect/app/src/components/carousel.tsx
index 928454362..9849a95bc 100644
--- a/dataconnect/app/src/components/carousel.tsx
+++ b/dataconnect/app/src/components/carousel.tsx
@@ -13,12 +13,7 @@ interface CarouselProps {
   }[];
 }
 
-const Carousel = (
-  {
-    title,
-    movies
-  }: CarouselProps
-) => {
+export default function Carousel({ title, movies }: CarouselProps) {
   return (
     <section className="carousel py-8">
       <h2 className="text-gray-200 text-2xl font-bold mb-4">{title}</h2>
@@ -38,6 +33,4 @@ const Carousel = (
       </div>
     </section>
   );
-};
-
-export default Carousel;
+}
diff --git a/dataconnect/app/src/components/moviecard.tsx b/dataconnect/app/src/components/moviecard.tsx
index 875531861..85079e564 100644
--- a/dataconnect/app/src/components/moviecard.tsx
+++ b/dataconnect/app/src/components/moviecard.tsx
@@ -14,16 +14,14 @@ interface MovieCardProps {
   tags?: string[] | null;
 }
 
-const MovieCard = (
-  {
-    id,
-    title,
-    imageUrl,
-    rating,
-    genre,
-    tags
-  }: MovieCardProps
-) => {
+export default function MovieCard({
+  id,
+  title,
+  imageUrl,
+  rating,
+  genre,
+  tags
+}: MovieCardProps) {
   const [user, setUser] = useState<User | null>(null);
   const [isFavorited, setIsFavorited] = useState(false);
   const auth = useContext(AuthContext);
@@ -40,16 +38,16 @@ const MovieCard = (
     return () => unsubscribe();
   }, [auth, id]);
 
-  const checkIfFavorited = async () => {
+  async function checkIfFavorited() {
     try {
       const response = await getIfFavoritedMovie({ movieId: id });
       setIsFavorited(!!response.data.favorite_movie);
     } catch (error) {
       console.error('Error checking if favorited:', error);
     }
-  };
+  }
 
-  const handleFavoriteToggle = async (e: React.MouseEvent) => {
+  async function handleFavoriteToggle(e: React.MouseEvent) {
     e.stopPropagation();
     e.preventDefault();
     if (!user) return;
@@ -63,13 +61,15 @@ const MovieCard = (
     } catch (error) {
       console.error('Error updating favorite status:', error);
     }
-  };
+  }
 
-  const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
+  function capitalize(str: string) {
+    return str.charAt(0).toUpperCase() + str.slice(1);
+  }
 
-  const handleCardClick = () => {
+  function handleCardClick() {
     navigate(`/movie/${id}`);
-  };
+  }
 
   return (
     <div
@@ -111,6 +111,4 @@ const MovieCard = (
       </div>
     </div>
   );
-};
-
-export default MovieCard;
+}
diff --git a/dataconnect/app/src/components/navbar.tsx b/dataconnect/app/src/components/navbar.tsx
index 0eff71154..90880ad02 100644
--- a/dataconnect/app/src/components/navbar.tsx
+++ b/dataconnect/app/src/components/navbar.tsx
@@ -6,7 +6,7 @@ import { upsertUser } from '@/lib/dataconnect-sdk';
 import { FaSearch } from 'react-icons/fa';
 import firebaseLogo from '@/assets/firebase_logo.svg';
 
-const Navbar = () => {
+export default function Navbar() {
   const [user, setUser] = useState<User | null>(null);
   const auth = useContext(AuthContext);
 
@@ -23,14 +23,14 @@ const Navbar = () => {
     return () => unsubscribe();
   }, [auth]);
 
-  const handleSignIn = async () => {
+  async function handleSignIn() {
     const provider = new GoogleAuthProvider();
     await signInWithPopup(auth, provider);
-  };
+  }
 
-  const handleSignOut = async () => {
+  async function handleSignOut() {
     await signOut(auth);
-  };
+  }
 
   return (
     <nav className="bg-black p-4">
@@ -89,6 +89,4 @@ const Navbar = () => {
       </div>
     </nav>
   );
-};
-
-export default Navbar;
+}
diff --git a/dataconnect/app/src/pages/Actor.tsx b/dataconnect/app/src/pages/Actor.tsx
index d1e065353..055e87dbb 100644
--- a/dataconnect/app/src/pages/Actor.tsx
+++ b/dataconnect/app/src/pages/Actor.tsx
@@ -12,7 +12,7 @@ import { onAuthStateChanged, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
 import NotFound from './NotFound';
 
-const ActorPage = () => {
+export default function ActorPage() {
   const { id } = useParams<{ id: string }>();
   const actorId = id || '';
   const [actor, setActor] = useState<GetActorByIdResponse['actor'] | null>(null);
@@ -55,16 +55,16 @@ const ActorPage = () => {
     }
   }, [actorId, navigate]);
 
-  const checkIfFavorited = async () => {
+  async function checkIfFavorited() {
     try {
       const response = await getIfFavoritedActor({ actorId });
       setIsFavorited(!!response.data.favorite_actor);
     } catch (error) {
       console.error('Error checking if favorited:', error);
     }
-  };
+  }
 
-  const handleFavoriteToggle = async () => {
+  async function handleFavoriteToggle() {
     if (!authUser) return;
     try {
       if (isFavorited) {
@@ -76,7 +76,7 @@ const ActorPage = () => {
     } catch (error) {
       console.error('Error updating favorite status:', error);
     }
-  };
+  }
 
   if (loading) return <p>Loading...</p>;
 
@@ -145,6 +145,4 @@ const ActorPage = () => {
   ) : (
     <NotFound />
   );
-};
-
-export default ActorPage;
+}
diff --git a/dataconnect/app/src/pages/AdvancedSearch.tsx b/dataconnect/app/src/pages/AdvancedSearch.tsx
index dcd5ee922..489366f8d 100644
--- a/dataconnect/app/src/pages/AdvancedSearch.tsx
+++ b/dataconnect/app/src/pages/AdvancedSearch.tsx
@@ -6,7 +6,7 @@ import { searchAll } from '@/lib/dataconnect-sdk';
 
 const genres = ['', 'action', 'crime', 'drama', 'sci-fi', 'thriller', 'adventure'];
 
-const AdvancedSearchPage = () => {
+export default function AdvancedSearchPage() {
   const [searchQuery, setSearchQuery] = useState('');
   const [releaseYearRange, setReleaseYearRange] = useState({ min: 1900, max: 2030 });
   const [genre, setGenre] = useState('');
@@ -18,7 +18,7 @@ const AdvancedSearchPage = () => {
     reviews: [],
   });
 
-  const handleSearch = async (e: React.FormEvent<HTMLFormElement>) => {
+  async function handleSearch(e: React.FormEvent<HTMLFormElement>) {
     e.preventDefault();
     try {
       const response = await searchAll({
@@ -38,7 +38,7 @@ const AdvancedSearchPage = () => {
     } catch (error) {
       console.error('Error fetching search results:', error);
     }
-  };
+  }
 
   return (
     <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
@@ -213,6 +213,4 @@ const AdvancedSearchPage = () => {
       </div>
     </div>
   );
-};
-
-export default AdvancedSearchPage;
+}
diff --git a/dataconnect/app/src/pages/Genre.tsx b/dataconnect/app/src/pages/Genre.tsx
index 45b02cd0c..9a8bee9a5 100644
--- a/dataconnect/app/src/pages/Genre.tsx
+++ b/dataconnect/app/src/pages/Genre.tsx
@@ -3,14 +3,14 @@ import { useParams } from 'react-router-dom';
 import MovieCard from '@/components/moviecard';
 import { ListMoviesByGenreResponse, listMoviesByGenre } from '@/lib/dataconnect-sdk';
 
-const GenrePage = () => {
+export default function GenrePage() {
   const { genre } = useParams<{ genre: string }>();
   const [mostPopular, setMostPopular] = useState<ListMoviesByGenreResponse['mostPopular']>([]);
   const [mostRecent, setMostRecent] = useState<ListMoviesByGenreResponse['mostRecent']>([]);
   const [loading, setLoading] = useState(true);
 
   useEffect(() => {
-    const fetchMovies = async () => {
+    async function fetchMovies() {
       try {
         const response = await listMoviesByGenre({ genre });
         setMostPopular(response.data.mostPopular);
@@ -20,7 +20,7 @@ const GenrePage = () => {
       } finally {
         setLoading(false);
       }
-    };
+    }
 
     fetchMovies();
   }, [genre]);
@@ -64,6 +64,4 @@ const GenrePage = () => {
       </section>
     </div>
   );
-};
-
-export default GenrePage;
+}
diff --git a/dataconnect/app/src/pages/Home.tsx b/dataconnect/app/src/pages/Home.tsx
index abbcd4220..ff1fd9dab 100644
--- a/dataconnect/app/src/pages/Home.tsx
+++ b/dataconnect/app/src/pages/Home.tsx
@@ -2,12 +2,12 @@ import React, { useEffect, useState } from 'react';
 import Carousel from '@/components/carousel';
 import { listMovies, ListMoviesResponse } from '@/lib/dataconnect-sdk';
 
-const HomePage = () => {
+export default function HomePage() {
   const [topMovies, setTopMovies] = useState<ListMoviesResponse["movies"]>([]);
   const [latestMovies, setLatestMovies] = useState<ListMoviesResponse["movies"]>([]);
 
   useEffect(() => {
-    const fetchMovies = async () => {
+    async function fetchMovies() {
       try {
         const topMoviesResponse = await listMovies({ orderByRating: "DESC", limit: 10 });
         const latestMoviesResponse = await listMovies({ orderByReleaseYear: "DESC", limit: 10 });
@@ -17,7 +17,7 @@ const HomePage = () => {
       } catch (error) {
         console.error("Error fetching movies:", error);
       }
-    };
+    }
 
     fetchMovies();
   }, []);
@@ -28,6 +28,4 @@ const HomePage = () => {
       <Carousel title="Latest Movies" movies={latestMovies} />
     </div>
   );
-};
-
-export default HomePage;
+}
diff --git a/dataconnect/app/src/pages/Movie.tsx b/dataconnect/app/src/pages/Movie.tsx
index b3153bed5..921c9b81c 100644
--- a/dataconnect/app/src/pages/Movie.tsx
+++ b/dataconnect/app/src/pages/Movie.tsx
@@ -1,4 +1,3 @@
-'use client';
 import { useContext, useEffect, useState } from 'react';
 import { useParams, Link } from 'react-router-dom';
 import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
@@ -17,7 +16,7 @@ import { onAuthStateChanged, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
 import NotFound from './NotFound';
 
-const MoviePage = () => {
+export default function MoviePage() {
   const { id } = useParams() as { id: string };
   const [movie, setMovie] = useState<GetMovieByIdResponse['movie'] | null>(null);
   const [loading, setLoading] = useState(true);
@@ -60,25 +59,25 @@ const MoviePage = () => {
     }
   }, [id, authUser]);
 
-  const fetchSimilarMovies = async (description: string) => {
+  async function fetchSimilarMovies(description: string) {
     try {
       const response = await searchMovieDescriptionUsingL2similarity({ query: description });
       setSimilarMovies(response?.data?.movies_descriptionEmbedding_similarity);
     } catch (error) {
       console.error('Error fetching similar movies:', error);
     }
-  };
+  }
 
-  const checkIfFavorited = async () => {
+  async function checkIfFavorited() {
     try {
       const response = await getIfFavoritedMovie({ movieId: id });
       setIsFavorited(!!response.data.favorite_movie);
     } catch (error) {
       console.error('Error checking if favorited:', error);
     }
-  };
+  }
 
-  const handleFavoriteToggle = async (e: React.MouseEvent) => {
+  async function handleFavoriteToggle(e: React.MouseEvent) {
     e.stopPropagation();
     e.preventDefault();
     if (!authUser) return;
@@ -92,13 +91,13 @@ const MoviePage = () => {
     } catch (error) {
       console.error('Error updating favorite status:', error);
     }
-  };
+  }
 
-  const handleReviewSubmit = async (e: React.FormEvent) => {
+  async function handleReviewSubmit(e: React.FormEvent) {
     e.preventDefault();
     if (!authUser) return;
     try {
-        await addReview({ movieId: id, rating, reviewText });
+      await addReview({ movieId: id, rating, reviewText });
       setReviewText('');
       setRating(0);
       const updatedMovie = await getMovieById({ id });
@@ -106,9 +105,9 @@ const MoviePage = () => {
     } catch (error) {
       console.error('Error adding review:', error);
     }
-  };
+  }
 
-  const handleReviewDelete = async (e: React.MouseEvent) => {
+  async function handleReviewDelete(e: React.MouseEvent) {
     e.stopPropagation();
     e.preventDefault();
     if (!authUser || !userReview) return;
@@ -120,11 +119,13 @@ const MoviePage = () => {
     } catch (error) {
       console.error('Error deleting review:', error);
     }
-  };
+  }
+
   if (loading) return <p>Loading...</p>;
   if (!movie) return <NotFound />;
+
   return (
-  <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
+    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
       <div className="flex flex-col md:flex-row mb-8">
         <img className="w-full md:w-1/3 object-cover rounded-lg shadow-md" src={movie.imageUrl} alt={movie.title} />
         <div className="md:ml-8 mt-4 md:mt-0 flex-1">
@@ -272,7 +273,6 @@ const MoviePage = () => {
           ))}
         </div>
       </div>
-    </div>);
-};
-
-export default MoviePage;
+    </div>
+  );
+}
diff --git a/dataconnect/app/src/pages/MyProfile.tsx b/dataconnect/app/src/pages/MyProfile.tsx
index 8568e64f0..d498a0023 100644
--- a/dataconnect/app/src/pages/MyProfile.tsx
+++ b/dataconnect/app/src/pages/MyProfile.tsx
@@ -11,7 +11,7 @@ import {
 import { MdStar } from 'react-icons/md';
 import { AuthContext } from '@/lib/firebase';
 
-const MyProfilePage = () => {
+export default function MyProfilePage() {
   const navigate = useNavigate();
   const [authUser, setAuthUser] = useState<User | null>(null);
   const [user, setUser] = useState<GetCurrentUserResponse['user'] | null>(null);
@@ -31,7 +31,7 @@ const MyProfilePage = () => {
     return () => unsubscribe();
   }, [navigate, auth]);
 
-  const fetchUserProfile = async () => {
+  async function fetchUserProfile() {
     try {
       const response = await getCurrentUser();
       setUser(response.data.user);
@@ -40,9 +40,9 @@ const MyProfilePage = () => {
     } finally {
       setLoading(false);
     }
-  };
+  }
 
-  const handleDeleteReview = async (reviewId: string) => {
+  async function handleDeleteReview(reviewId: string) {
     if (!authUser) return;
     try {
       await deleteReview({ movieId: reviewId });
@@ -50,9 +50,9 @@ const MyProfilePage = () => {
     } catch (error) {
       console.error('Error deleting review:', error);
     }
-  };
+  }
 
-  const handleUnfavoriteMovie = async (movieId: string) => {
+  async function handleUnfavoriteMovie(movieId: string) {
     if (!authUser) return;
     try {
       await deleteFavoritedMovie({ movieId });
@@ -60,9 +60,9 @@ const MyProfilePage = () => {
     } catch (error) {
       console.error('Error unfavoriting movie:', error);
     }
-  };
+  }
 
-  const handleUnfavoriteActor = async (actorId: string) => {
+  async function handleUnfavoriteActor(actorId: string) {
     if (!authUser) return;
     try {
       await deleteFavoriteActor({ actorId });
@@ -70,7 +70,7 @@ const MyProfilePage = () => {
     } catch (error) {
       console.error('Error unfavoriting actor:', error);
     }
-  };
+  }
 
   if (loading) return <p>Loading...</p>;
   if (!user) return <p>User not found.</p>;
@@ -160,6 +160,4 @@ const MyProfilePage = () => {
       </div>
     </div>
   );
-};
-
-export default MyProfilePage;
+}
diff --git a/dataconnect/app/src/pages/NotFound.tsx b/dataconnect/app/src/pages/NotFound.tsx
index 22d9c6040..eb642a752 100644
--- a/dataconnect/app/src/pages/NotFound.tsx
+++ b/dataconnect/app/src/pages/NotFound.tsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import { useNavigate } from 'react-router-dom';
 
-const NotFound = () => {
+export default function NotFound() {
   const navigate = useNavigate();
 
   return (
@@ -24,6 +24,4 @@ const NotFound = () => {
       </div>
     </div>
   );
-};
-
-export default NotFound;
+}
diff --git a/dataconnect/app/src/pages/VectorSearch.tsx b/dataconnect/app/src/pages/VectorSearch.tsx
index 1e164f519..fdafbce13 100644
--- a/dataconnect/app/src/pages/VectorSearch.tsx
+++ b/dataconnect/app/src/pages/VectorSearch.tsx
@@ -2,12 +2,12 @@ import React, { useState } from 'react';
 import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '@/lib/dataconnect-sdk';
 import { FaSpinner } from 'react-icons/fa';
 
-const VectorSearchPage = () => {
+export default function VectorSearchPage() {
   const [query, setQuery] = useState('');
   const [loading, setLoading] = useState(false);
   const [results, setResults] = useState<SearchMovieDescriptionUsingL2similarityResponse['movies_descriptionEmbedding_similarity']>([]);
 
-  const handleSearch = async (e: React.FormEvent<HTMLFormElement>) => {
+  async function handleSearch(e: React.FormEvent<HTMLFormElement>) {
     e.preventDefault();
     setLoading(true);
     try {
@@ -18,7 +18,7 @@ const VectorSearchPage = () => {
     } finally {
       setLoading(false);
     }
-  };
+  }
 
   return (
     <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
@@ -75,6 +75,4 @@ const VectorSearchPage = () => {
       )}
     </div>
   );
-};
-
-export default VectorSearchPage;
+}

From 825f2e84eb5291e73802fe1b3618fd92256b39f2 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 14:14:06 -0400
Subject: [PATCH 27/82] fix: eslint

---
 dataconnect/app/.eslintrc.cjs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/dataconnect/app/.eslintrc.cjs b/dataconnect/app/.eslintrc.cjs
index d6c953795..74395f2c6 100644
--- a/dataconnect/app/.eslintrc.cjs
+++ b/dataconnect/app/.eslintrc.cjs
@@ -14,5 +14,6 @@ module.exports = {
       'warn',
       { allowConstantExport: true },
     ],
+    "react-hooks/exhaustive-deps": "warn"
   },
 }

From c470c4c13f9b260eaabd6287c0b0e4ff6172ba94 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 14:23:01 -0400
Subject: [PATCH 28/82] fix: eslint

---
 dataconnect/app/src/components/moviecard.tsx | 16 ++++++++--------
 dataconnect/app/src/pages/Actor.tsx          | 17 ++++++++---------
 dataconnect/app/src/pages/Movie.tsx          | 19 +++++++++----------
 3 files changed, 25 insertions(+), 27 deletions(-)

diff --git a/dataconnect/app/src/components/moviecard.tsx b/dataconnect/app/src/components/moviecard.tsx
index 85079e564..7122d61a4 100644
--- a/dataconnect/app/src/components/moviecard.tsx
+++ b/dataconnect/app/src/components/moviecard.tsx
@@ -29,6 +29,14 @@ export default function MovieCard({
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
+      async function checkIfFavorited() {
+        try {
+          const response = await getIfFavoritedMovie({ movieId: id });
+          setIsFavorited(!!response.data.favorite_movie);
+        } catch (error) {
+          console.error('Error checking if favorited:', error);
+        }
+      }
       if (user) {
         setUser(user);
         checkIfFavorited();
@@ -38,14 +46,6 @@ export default function MovieCard({
     return () => unsubscribe();
   }, [auth, id]);
 
-  async function checkIfFavorited() {
-    try {
-      const response = await getIfFavoritedMovie({ movieId: id });
-      setIsFavorited(!!response.data.favorite_movie);
-    } catch (error) {
-      console.error('Error checking if favorited:', error);
-    }
-  }
 
   async function handleFavoriteToggle(e: React.MouseEvent) {
     e.stopPropagation();
diff --git a/dataconnect/app/src/pages/Actor.tsx b/dataconnect/app/src/pages/Actor.tsx
index 055e87dbb..9c488cda9 100644
--- a/dataconnect/app/src/pages/Actor.tsx
+++ b/dataconnect/app/src/pages/Actor.tsx
@@ -24,6 +24,14 @@ export default function ActorPage() {
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
+      async function checkIfFavorited() {
+        try {
+          const response = await getIfFavoritedActor({ actorId });
+          setIsFavorited(!!response.data.favorite_actor);
+        } catch (error) {
+          console.error('Error checking if favorited:', error);
+        }
+      }
       if (user) {
         setAuthUser(user);
         checkIfFavorited();
@@ -55,15 +63,6 @@ export default function ActorPage() {
     }
   }, [actorId, navigate]);
 
-  async function checkIfFavorited() {
-    try {
-      const response = await getIfFavoritedActor({ actorId });
-      setIsFavorited(!!response.data.favorite_actor);
-    } catch (error) {
-      console.error('Error checking if favorited:', error);
-    }
-  }
-
   async function handleFavoriteToggle() {
     if (!authUser) return;
     try {
diff --git a/dataconnect/app/src/pages/Movie.tsx b/dataconnect/app/src/pages/Movie.tsx
index 921c9b81c..f9e942d03 100644
--- a/dataconnect/app/src/pages/Movie.tsx
+++ b/dataconnect/app/src/pages/Movie.tsx
@@ -30,6 +30,14 @@ export default function MoviePage() {
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
+      async function checkIfFavorited() {
+        try {
+          const response = await getIfFavoritedMovie({ movieId: id });
+          setIsFavorited(!!response.data.favorite_movie);
+        } catch (error) {
+          console.error('Error checking if favorited:', error);
+        }
+      }
       if (user) {
         setAuthUser(user);
         checkIfFavorited();
@@ -37,7 +45,7 @@ export default function MoviePage() {
     });
 
     return () => unsubscribe();
-  }, [id]);
+  }, [id, auth]);
 
   useEffect(() => {
     if (id) {
@@ -68,15 +76,6 @@ export default function MoviePage() {
     }
   }
 
-  async function checkIfFavorited() {
-    try {
-      const response = await getIfFavoritedMovie({ movieId: id });
-      setIsFavorited(!!response.data.favorite_movie);
-    } catch (error) {
-      console.error('Error checking if favorited:', error);
-    }
-  }
-
   async function handleFavoriteToggle(e: React.MouseEvent) {
     e.stopPropagation();
     e.preventDefault();

From 99724712021551de86bfe1d3debad42f77c5a870 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 14:47:52 -0400
Subject: [PATCH 29/82] fix: naming conventions

---
 dataconnect/app/src/pages/Movie.tsx           | 17 +++---
 .../dataconnect/movie-connector/mutations.gql | 22 +++----
 .../dataconnect/movie-connector/queries.gql   | 57 +++++++------------
 3 files changed, 38 insertions(+), 58 deletions(-)

diff --git a/dataconnect/app/src/pages/Movie.tsx b/dataconnect/app/src/pages/Movie.tsx
index f9e942d03..b6f33b1ef 100644
--- a/dataconnect/app/src/pages/Movie.tsx
+++ b/dataconnect/app/src/pages/Movie.tsx
@@ -48,6 +48,14 @@ export default function MoviePage() {
   }, [id, auth]);
 
   useEffect(() => {
+    async function fetchSimilarMovies(description: string) {
+      try {
+        const response = await searchMovieDescriptionUsingL2similarity({ query: description });
+        setSimilarMovies(response?.data?.movies_descriptionEmbedding_similarity);
+      } catch (error) {
+        console.error('Error fetching similar movies:', error);
+      }
+    }
     if (id) {
       const fetchMovie = async () => {
         try {
@@ -67,15 +75,6 @@ export default function MoviePage() {
     }
   }, [id, authUser]);
 
-  async function fetchSimilarMovies(description: string) {
-    try {
-      const response = await searchMovieDescriptionUsingL2similarity({ query: description });
-      setSimilarMovies(response?.data?.movies_descriptionEmbedding_similarity);
-    } catch (error) {
-      console.error('Error fetching similar movies:', error);
-    }
-  }
-
   async function handleFavoriteToggle(e: React.MouseEvent) {
     e.stopPropagation();
     e.preventDefault();
diff --git a/dataconnect/dataconnect/movie-connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
index 9d4d25458..b5bd79345 100644
--- a/dataconnect/dataconnect/movie-connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -1,5 +1,5 @@
 # Create a movie based on user input
-mutation createMovie(
+mutation CreateMovie(
   $title: String!
   $releaseYear: Int!
   $genre: String!
@@ -22,7 +22,7 @@ mutation createMovie(
 }
 
 # Update movie information based on the provided ID
-mutation updateMovie(
+mutation UpdateMovie(
   $id: UUID!
   $title: String
   $releaseYear: Int
@@ -47,37 +47,37 @@ mutation updateMovie(
 }
 
 # Delete a movie by its ID
-mutation deleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
+mutation DeleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
   movie_delete(id: $id)
 }
 
 # Delete movies with a rating lower than the specified minimum rating
-mutation deleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
+mutation DeleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
   movie_deleteMany(where: { rating: { le: $minRating } })
 }
 
 # Add a movie to the user's favorites list
-mutation addFavoritedMovie($movieId: UUID!) @auth(level: USER) {
+mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
   favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
 }
 
 # Remove a movie from the user's favorites list
-mutation deleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
+mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
   favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
 }
 
 # Add an actor to the user's favorites list
-mutation addFavoritedActor($actorId: UUID!) @auth(level: USER) {
+mutation AddFavoritedActor($actorId: UUID!) @auth(level: USER) {
   favorite_actor_upsert(data: { userId_expr: "auth.uid", actorId: $actorId })
 }
 
 # Remove an actor from the user's favorites list
-mutation deleteFavoriteActor($actorId: UUID!) @auth(level: USER) {
+mutation DeleteFavoritedActor($actorId: UUID!) @auth(level: USER) {
   favorite_actor_delete(key: { userId_expr: "auth.uid", actorId: $actorId })
 }
 
 # Add a review for a movie
-mutation addReview(
+mutation AddReview(
   $movieId: UUID!
   $rating: Int!
   $reviewText: String!
@@ -94,14 +94,14 @@ mutation addReview(
 }
 
 # Delete a user's review for a movie
-mutation deleteReview(
+mutation DeleteReview(
   $movieId: UUID!
 ) @auth(level: USER) {
   review_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
 }
 
 # Upsert (update or insert) a user based on their username
-mutation upsertUser($username: String!) @auth(level: USER) {
+mutation UpsertUser($username: String!) @auth(level: USER) {
   user_upsert(
     data: {
       id_expr: "auth.uid"
diff --git a/dataconnect/dataconnect/movie-connector/queries.gql b/dataconnect/dataconnect/movie-connector/queries.gql
index 5a75ea6ec..789785713 100644
--- a/dataconnect/dataconnect/movie-connector/queries.gql
+++ b/dataconnect/dataconnect/movie-connector/queries.gql
@@ -278,7 +278,7 @@ query GetIfFavoritedActor($actorId: UUID!) @auth(level: USER) {
 }
 
 # Search for movies, actors, and reviews
-query searchAll(
+query SearchAll(
   $input: String
   $minYear: Int!
   $maxYear: Int!
@@ -343,41 +343,22 @@ query searchAll(
   }
 }
 
-# Search movie descriptions using L2 similarity with Vertex AI
-query searchMovieDescriptionUsingL2Similarity($query: String!)
-@auth(level: PUBLIC) {
-  movies_descriptionEmbedding_similarity(
-    compare_embed: { model: "textembedding-gecko@003", text: $query }
-    method: L2
-    within: 2
-    where: { isNull: false }
-    limit: 5
-  ) {
-    id
-    title
-    description
-    tags
-    rating
-    imageUrl
-  }
-}
+# # Search movie descriptions using L2 similarity with Vertex AI
+# query SearchMovieDescriptionUsingL2Similarity($query: String!)
+# @auth(level: PUBLIC) {
+#   movies_descriptionEmbedding_similarity(
+#     compare_embed: { model: "textembedding-gecko@003", text: $query }
+#     method: L2
+#     within: 2
+#     where: { isNull: false }
+#     limit: 5
+#   ) {
+#     id
+#     title
+#     description
+#     tags
+#     rating
+#     imageUrl
+#   }
+# }
 
-# Search movie descriptions using L2 similarity with Vertex AI, with custom embeddings
-query searchMovieDescriptionUsingL2Similarity1(
-  $compare: Vector!
-  $within: Float
-  $excludesContent: String
-  $limit: Int
-) @auth(level: PUBLIC) {
-  movies_descriptionEmbedding_similarity(
-    compare: $compare
-    method: L2
-    within: $within
-    where: { description: { ne: $excludesContent } }
-    limit: $limit
-  ) {
-    id
-    title
-    description
-  }
-}

From a02ad8c7c6c6ae1783e5d6d9bf8e8817e221cb4c Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 14:51:29 -0400
Subject: [PATCH 30/82] fix: spelling

---
 dataconnect/app/src/pages/Actor.tsx           |  4 +--
 dataconnect/app/src/pages/MyProfile.tsx       |  4 +--
 .../dataconnect/movie-connector/queries.gql   | 36 +++++++++----------
 3 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/dataconnect/app/src/pages/Actor.tsx b/dataconnect/app/src/pages/Actor.tsx
index 9c488cda9..f57f4df00 100644
--- a/dataconnect/app/src/pages/Actor.tsx
+++ b/dataconnect/app/src/pages/Actor.tsx
@@ -5,7 +5,7 @@ import {
   getActorById,
   GetActorByIdResponse,
   addFavoritedActor,
-  deleteFavoriteActor,
+  deleteFavoritedActor,
   getIfFavoritedActor
 } from '@/lib/dataconnect-sdk';
 import { onAuthStateChanged, User } from 'firebase/auth';
@@ -67,7 +67,7 @@ export default function ActorPage() {
     if (!authUser) return;
     try {
       if (isFavorited) {
-        await deleteFavoriteActor({ actorId });
+        await deleteFavoritedActor({ actorId });
       } else {
         await addFavoritedActor({ actorId });
       }
diff --git a/dataconnect/app/src/pages/MyProfile.tsx b/dataconnect/app/src/pages/MyProfile.tsx
index d498a0023..b7bea0928 100644
--- a/dataconnect/app/src/pages/MyProfile.tsx
+++ b/dataconnect/app/src/pages/MyProfile.tsx
@@ -6,7 +6,7 @@ import {
   GetCurrentUserResponse,
   deleteReview,
   deleteFavoritedMovie,
-  deleteFavoriteActor,
+  deleteFavoritedActor,
 } from '@/lib/dataconnect-sdk';
 import { MdStar } from 'react-icons/md';
 import { AuthContext } from '@/lib/firebase';
@@ -65,7 +65,7 @@ export default function MyProfilePage() {
   async function handleUnfavoriteActor(actorId: string) {
     if (!authUser) return;
     try {
-      await deleteFavoriteActor({ actorId });
+      await deleteFavoritedActor({ actorId });
       fetchUserProfile();
     } catch (error) {
       console.error('Error unfavoriting actor:', error);
diff --git a/dataconnect/dataconnect/movie-connector/queries.gql b/dataconnect/dataconnect/movie-connector/queries.gql
index 789785713..f984dfb4d 100644
--- a/dataconnect/dataconnect/movie-connector/queries.gql
+++ b/dataconnect/dataconnect/movie-connector/queries.gql
@@ -343,22 +343,22 @@ query SearchAll(
   }
 }
 
-# # Search movie descriptions using L2 similarity with Vertex AI
-# query SearchMovieDescriptionUsingL2Similarity($query: String!)
-# @auth(level: PUBLIC) {
-#   movies_descriptionEmbedding_similarity(
-#     compare_embed: { model: "textembedding-gecko@003", text: $query }
-#     method: L2
-#     within: 2
-#     where: { isNull: false }
-#     limit: 5
-#   ) {
-#     id
-#     title
-#     description
-#     tags
-#     rating
-#     imageUrl
-#   }
-# }
+# Search movie descriptions using L2 similarity with Vertex AI
+query SearchMovieDescriptionUsingL2Similarity($query: String!)
+@auth(level: PUBLIC) {
+  movies_descriptionEmbedding_similarity(
+    compare_embed: { model: "textembedding-gecko@003", text: $query }
+    method: L2
+    within: 2
+    where: { isNull: false }
+    limit: 5
+  ) {
+    id
+    title
+    description
+    tags
+    rating
+    imageUrl
+  }
+}
 

From cc8a0a34822a887251aaeb8b8f3809a6380a2c68 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 14:51:48 -0400
Subject: [PATCH 31/82] fix: spelling

---
 dataconnect/dataconnect/movie-connector/connector.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dataconnect/dataconnect/movie-connector/connector.yaml b/dataconnect/dataconnect/movie-connector/connector.yaml
index 3247d642f..a1c9fedca 100644
--- a/dataconnect/dataconnect/movie-connector/connector.yaml
+++ b/dataconnect/dataconnect/movie-connector/connector.yaml
@@ -3,4 +3,4 @@ authMode: PUBLIC
 generate:
   javascriptSdk:
     package: "@movie/sdk"
-    outputDir: ../../app/lib/dataconnect-sdk
+    outputDir: ../../app/src/lib/dataconnect-sdk

From 69ec7cc5b90cbe42e3ad61bf62f916f827fe9a8d Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 17:11:57 -0400
Subject: [PATCH 32/82] fix: packageJsonDir

---
 dataconnect/app/package.json                           | 1 +
 dataconnect/app/src/components/moviecard.tsx           | 2 +-
 dataconnect/app/src/components/navbar.tsx              | 2 +-
 dataconnect/app/src/pages/Actor.tsx                    | 2 +-
 dataconnect/app/src/pages/AdvancedSearch.tsx           | 2 +-
 dataconnect/app/src/pages/Genre.tsx                    | 2 +-
 dataconnect/app/src/pages/Home.tsx                     | 2 +-
 dataconnect/app/src/pages/Movie.tsx                    | 2 +-
 dataconnect/app/src/pages/MyProfile.tsx                | 2 +-
 dataconnect/app/src/pages/VectorSearch.tsx             | 2 +-
 dataconnect/dataconnect/movie-connector/connector.yaml | 3 ++-
 dataconnect/dataconnect/movie-connector/queries.gql    | 1 -
 12 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/dataconnect/app/package.json b/dataconnect/app/package.json
index 0798e9c64..4dc225ae5 100644
--- a/dataconnect/app/package.json
+++ b/dataconnect/app/package.json
@@ -10,6 +10,7 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@movie/dataconnect": "file:src/lib/dataconnect-sdk",
     "dotenv": "^16.4.5",
     "firebase": "^10.12.0-dataconnect-preview.388b61c7e",
     "react": "^18.3.1",
diff --git a/dataconnect/app/src/components/moviecard.tsx b/dataconnect/app/src/components/moviecard.tsx
index 7122d61a4..7af10a7f0 100644
--- a/dataconnect/app/src/components/moviecard.tsx
+++ b/dataconnect/app/src/components/moviecard.tsx
@@ -2,7 +2,7 @@ import React, { useContext, useEffect, useState } from 'react';
 import { Link, useNavigate } from 'react-router-dom';
 import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
 import { onAuthStateChanged, User } from 'firebase/auth';
-import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from '@/lib/dataconnect-sdk';
+import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from '@movie/dataconnect';
 import { AuthContext } from '@/lib/firebase';
 
 interface MovieCardProps {
diff --git a/dataconnect/app/src/components/navbar.tsx b/dataconnect/app/src/components/navbar.tsx
index 90880ad02..2a98fcb72 100644
--- a/dataconnect/app/src/components/navbar.tsx
+++ b/dataconnect/app/src/components/navbar.tsx
@@ -2,7 +2,7 @@ import React, { useEffect, useState, useContext } from 'react';
 import { onAuthStateChanged, signInWithPopup, GoogleAuthProvider, signOut, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
 import { Link } from 'react-router-dom';
-import { upsertUser } from '@/lib/dataconnect-sdk';
+import { upsertUser } from '@movie/dataconnect';
 import { FaSearch } from 'react-icons/fa';
 import firebaseLogo from '@/assets/firebase_logo.svg';
 
diff --git a/dataconnect/app/src/pages/Actor.tsx b/dataconnect/app/src/pages/Actor.tsx
index f57f4df00..d74247fc2 100644
--- a/dataconnect/app/src/pages/Actor.tsx
+++ b/dataconnect/app/src/pages/Actor.tsx
@@ -7,7 +7,7 @@ import {
   addFavoritedActor,
   deleteFavoritedActor,
   getIfFavoritedActor
-} from '@/lib/dataconnect-sdk';
+} from '@movie/dataconnect';
 import { onAuthStateChanged, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
 import NotFound from './NotFound';
diff --git a/dataconnect/app/src/pages/AdvancedSearch.tsx b/dataconnect/app/src/pages/AdvancedSearch.tsx
index 489366f8d..102664935 100644
--- a/dataconnect/app/src/pages/AdvancedSearch.tsx
+++ b/dataconnect/app/src/pages/AdvancedSearch.tsx
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
 import { Link } from 'react-router-dom';
 import { FaSearch } from 'react-icons/fa';
 import { MdStar } from 'react-icons/md';
-import { searchAll } from '@/lib/dataconnect-sdk';
+import { searchAll } from '@movie/dataconnect';
 
 const genres = ['', 'action', 'crime', 'drama', 'sci-fi', 'thriller', 'adventure'];
 
diff --git a/dataconnect/app/src/pages/Genre.tsx b/dataconnect/app/src/pages/Genre.tsx
index 9a8bee9a5..4c0b067c9 100644
--- a/dataconnect/app/src/pages/Genre.tsx
+++ b/dataconnect/app/src/pages/Genre.tsx
@@ -1,7 +1,7 @@
 import React, { useEffect, useState } from 'react';
 import { useParams } from 'react-router-dom';
 import MovieCard from '@/components/moviecard';
-import { ListMoviesByGenreResponse, listMoviesByGenre } from '@/lib/dataconnect-sdk';
+import { ListMoviesByGenreResponse, listMoviesByGenre } from '@movie/dataconnect';
 
 export default function GenrePage() {
   const { genre } = useParams<{ genre: string }>();
diff --git a/dataconnect/app/src/pages/Home.tsx b/dataconnect/app/src/pages/Home.tsx
index ff1fd9dab..302da28c7 100644
--- a/dataconnect/app/src/pages/Home.tsx
+++ b/dataconnect/app/src/pages/Home.tsx
@@ -1,6 +1,6 @@
 import React, { useEffect, useState } from 'react';
 import Carousel from '@/components/carousel';
-import { listMovies, ListMoviesResponse } from '@/lib/dataconnect-sdk';
+import { listMovies, ListMoviesResponse } from '@movie/dataconnect';
 
 export default function HomePage() {
   const [topMovies, setTopMovies] = useState<ListMoviesResponse["movies"]>([]);
diff --git a/dataconnect/app/src/pages/Movie.tsx b/dataconnect/app/src/pages/Movie.tsx
index b6f33b1ef..2684cb002 100644
--- a/dataconnect/app/src/pages/Movie.tsx
+++ b/dataconnect/app/src/pages/Movie.tsx
@@ -11,7 +11,7 @@ import {
   deleteReview,
   searchMovieDescriptionUsingL2similarity,
   SearchMovieDescriptionUsingL2similarityResponse,
-} from '@/lib/dataconnect-sdk';
+} from '@movie/dataconnect';
 import { onAuthStateChanged, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
 import NotFound from './NotFound';
diff --git a/dataconnect/app/src/pages/MyProfile.tsx b/dataconnect/app/src/pages/MyProfile.tsx
index b7bea0928..6bfd06427 100644
--- a/dataconnect/app/src/pages/MyProfile.tsx
+++ b/dataconnect/app/src/pages/MyProfile.tsx
@@ -7,7 +7,7 @@ import {
   deleteReview,
   deleteFavoritedMovie,
   deleteFavoritedActor,
-} from '@/lib/dataconnect-sdk';
+} from '@movie/dataconnect';
 import { MdStar } from 'react-icons/md';
 import { AuthContext } from '@/lib/firebase';
 
diff --git a/dataconnect/app/src/pages/VectorSearch.tsx b/dataconnect/app/src/pages/VectorSearch.tsx
index fdafbce13..fa99f1aee 100644
--- a/dataconnect/app/src/pages/VectorSearch.tsx
+++ b/dataconnect/app/src/pages/VectorSearch.tsx
@@ -1,5 +1,5 @@
 import React, { useState } from 'react';
-import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '@/lib/dataconnect-sdk';
+import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '@movie/dataconnect';
 import { FaSpinner } from 'react-icons/fa';
 
 export default function VectorSearchPage() {
diff --git a/dataconnect/dataconnect/movie-connector/connector.yaml b/dataconnect/dataconnect/movie-connector/connector.yaml
index a1c9fedca..6ce8e9673 100644
--- a/dataconnect/dataconnect/movie-connector/connector.yaml
+++ b/dataconnect/dataconnect/movie-connector/connector.yaml
@@ -2,5 +2,6 @@ connectorId: movie-connector
 authMode: PUBLIC
 generate:
   javascriptSdk:
-    package: "@movie/sdk"
+    package: "@movie/dataconnect"
     outputDir: ../../app/src/lib/dataconnect-sdk
+    packageJsonDir: "../../app"
diff --git a/dataconnect/dataconnect/movie-connector/queries.gql b/dataconnect/dataconnect/movie-connector/queries.gql
index f984dfb4d..06d55ee0a 100644
--- a/dataconnect/dataconnect/movie-connector/queries.gql
+++ b/dataconnect/dataconnect/movie-connector/queries.gql
@@ -350,7 +350,6 @@ query SearchMovieDescriptionUsingL2Similarity($query: String!)
     compare_embed: { model: "textembedding-gecko@003", text: $query }
     method: L2
     within: 2
-    where: { isNull: false }
     limit: 5
   ) {
     id

From 37c22eaebb90967e97d0d7d6851eebd99710ffcd Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 17:42:42 -0400
Subject: [PATCH 33/82] fix: mark queries/mutations that are not called

---
 dataconnect/dataconnect/movie-connector/mutations.gql | 3 +++
 dataconnect/dataconnect/movie-connector/queries.gql   | 7 +++++++
 2 files changed, 10 insertions(+)

diff --git a/dataconnect/dataconnect/movie-connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
index b5bd79345..623dccb3b 100644
--- a/dataconnect/dataconnect/movie-connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -22,6 +22,7 @@ mutation CreateMovie(
 }
 
 # Update movie information based on the provided ID
+# For example purposes only, not called in quickstart
 mutation UpdateMovie(
   $id: UUID!
   $title: String
@@ -47,11 +48,13 @@ mutation UpdateMovie(
 }
 
 # Delete a movie by its ID
+# For example purposes only, not called in quickstart
 mutation DeleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
   movie_delete(id: $id)
 }
 
 # Delete movies with a rating lower than the specified minimum rating
+# For example purposes only, not called in quickstart
 mutation DeleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
   movie_deleteMany(where: { rating: { le: $minRating } })
 }
diff --git a/dataconnect/dataconnect/movie-connector/queries.gql b/dataconnect/dataconnect/movie-connector/queries.gql
index 06d55ee0a..191c05f3b 100644
--- a/dataconnect/dataconnect/movie-connector/queries.gql
+++ b/dataconnect/dataconnect/movie-connector/queries.gql
@@ -107,6 +107,7 @@ query GetActorById($id: UUID!) @auth(level: PUBLIC) {
 }
 
 # List movies by partial title match
+# For example purposes only, not called in quickstart
 query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
   movies(where: { title: { contains: $input } }) {
     id
@@ -118,6 +119,7 @@ query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
 }
 
 # List movies by tag
+# For example purposes only, not called in quickstart
 query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
   movies(where: { tags: { includes: $tag } }) {
     id
@@ -129,6 +131,7 @@ query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
 }
 
 # List movies by release year range
+# For example purposes only, not called in quickstart
 query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
   movies(
     where: { releaseYear: { le: $max, ge: $min } }
@@ -142,6 +145,7 @@ query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
 }
 
 # List movies by rating and genre with OR filters
+# For example purposes only, not called in quickstart
 query SearchMovieOr(
   $minRating: Float
   $maxRating: Float
@@ -168,6 +172,7 @@ query SearchMovieOr(
 }
 
 # List movies by rating and genre with AND filters
+# For example purposes only, not called in quickstart
 query SearchMovieAnd(
   $minRating: Float
   $maxRating: Float
@@ -194,6 +199,7 @@ query SearchMovieAnd(
 }
 
 # Get favorite movies by user ID
+# For example purposes only, not called in quickstart
 query GetUserFavoriteMovies @auth(level: USER) {
   user(id_expr: "auth.uid") {
     favorite_movies_on_user {
@@ -211,6 +217,7 @@ query GetUserFavoriteMovies @auth(level: USER) {
 }
 
 # Get favorite actors by user ID
+# For example purposes only, not called in quickstart
 query GetFavoriteActors @auth(level: USER) {
   user(key: {id_expr: "auth.uid"}) {
     favorite_actors_on_user {

From 8ddc524ff637765fd4de64f3e8aa175c7fbffaeb Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 17:53:22 -0400
Subject: [PATCH 34/82] fix: notes

---
 .../dataconnect/movie-connector/mutations.gql |  76 +++---
 .../dataconnect/movie-connector/queries.gql   | 242 +++++++++---------
 2 files changed, 156 insertions(+), 162 deletions(-)

diff --git a/dataconnect/dataconnect/movie-connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
index 623dccb3b..fdac88bc7 100644
--- a/dataconnect/dataconnect/movie-connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -21,44 +21,6 @@ mutation CreateMovie(
   )
 }
 
-# Update movie information based on the provided ID
-# For example purposes only, not called in quickstart
-mutation UpdateMovie(
-  $id: UUID!
-  $title: String
-  $releaseYear: Int
-  $genre: String
-  $rating: Float
-  $description: String
-  $imageUrl: String
-  $tags: [String!] = []
-) @auth(level: USER_EMAIL_VERIFIED) {
-  movie_update(
-    id: $id
-    data: {
-      title: $title
-      releaseYear: $releaseYear
-      genre: $genre
-      rating: $rating
-      description: $description
-      imageUrl: $imageUrl
-      tags: $tags
-    }
-  )
-}
-
-# Delete a movie by its ID
-# For example purposes only, not called in quickstart
-mutation DeleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
-  movie_delete(id: $id)
-}
-
-# Delete movies with a rating lower than the specified minimum rating
-# For example purposes only, not called in quickstart
-mutation DeleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
-  movie_deleteMany(where: { rating: { le: $minRating } })
-}
-
 # Add a movie to the user's favorites list
 mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
   favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
@@ -112,3 +74,41 @@ mutation UpsertUser($username: String!) @auth(level: USER) {
     }
   )
 }
+
+# The mutations below are unused by the application, but are useful examples for more complex cases
+
+# Update movie information based on the provided ID
+mutation UpdateMovie(
+  $id: UUID!
+  $title: String
+  $releaseYear: Int
+  $genre: String
+  $rating: Float
+  $description: String
+  $imageUrl: String
+  $tags: [String!] = []
+) @auth(level: USER_EMAIL_VERIFIED) {
+  movie_update(
+    id: $id
+    data: {
+      title: $title
+      releaseYear: $releaseYear
+      genre: $genre
+      rating: $rating
+      description: $description
+      imageUrl: $imageUrl
+      tags: $tags
+    }
+  )
+}
+
+# Delete a movie by its ID
+mutation DeleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
+  movie_delete(id: $id)
+}
+
+# Delete movies with a rating lower than the specified minimum rating
+mutation DeleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
+  movie_deleteMany(where: { rating: { le: $minRating } })
+}
+# End of example mutations
\ No newline at end of file
diff --git a/dataconnect/dataconnect/movie-connector/queries.gql b/dataconnect/dataconnect/movie-connector/queries.gql
index 191c05f3b..27728103a 100644
--- a/dataconnect/dataconnect/movie-connector/queries.gql
+++ b/dataconnect/dataconnect/movie-connector/queries.gql
@@ -106,130 +106,6 @@ query GetActorById($id: UUID!) @auth(level: PUBLIC) {
   }
 }
 
-# List movies by partial title match
-# For example purposes only, not called in quickstart
-query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
-  movies(where: { title: { contains: $input } }) {
-    id
-    title
-    genre
-    rating
-    imageUrl
-  }
-}
-
-# List movies by tag
-# For example purposes only, not called in quickstart
-query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
-  movies(where: { tags: { includes: $tag } }) {
-    id
-    title
-    imageUrl
-    genre
-    rating
-  }
-}
-
-# List movies by release year range
-# For example purposes only, not called in quickstart
-query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
-  movies(
-    where: { releaseYear: { le: $max, ge: $min } }
-    orderBy: { releaseYear: ASC }
-  ) {
-    id
-    rating
-    title
-    imageUrl
-  }
-}
-
-# List movies by rating and genre with OR filters
-# For example purposes only, not called in quickstart
-query SearchMovieOr(
-  $minRating: Float
-  $maxRating: Float
-  $genre: String
-  $tag: String
-  $input: String
-) @auth(level: PUBLIC) {
-  movies(
-    where: {
-      _or: [
-        { rating: { ge: $minRating } }
-        { rating: { le: $maxRating } }
-        { genre: { eq: $genre } }
-        { tags: { includes: $tag } }
-        { title: { contains: $input } }
-      ]
-    }
-  ) {
-    id
-    rating
-    title
-    imageUrl
-  }
-}
-
-# List movies by rating and genre with AND filters
-# For example purposes only, not called in quickstart
-query SearchMovieAnd(
-  $minRating: Float
-  $maxRating: Float
-  $genre: String
-  $tag: String
-  $input: String
-) @auth(level: PUBLIC) {
-  movies(
-    where: {
-      _and: [
-        { rating: { ge: $minRating } }
-        { rating: { le: $maxRating } }
-        { genre: { eq: $genre } }
-        { tags: { includes: $tag } }
-        { title: { contains: $input } }
-      ]
-    }
-  ) {
-    id
-    rating
-    title
-    imageUrl
-  }
-}
-
-# Get favorite movies by user ID
-# For example purposes only, not called in quickstart
-query GetUserFavoriteMovies @auth(level: USER) {
-  user(id_expr: "auth.uid") {
-    favorite_movies_on_user {
-      movie {
-        id
-        title
-        genre
-        imageUrl
-        releaseYear
-        rating
-        description
-      }
-    }
-  }
-}
-
-# Get favorite actors by user ID
-# For example purposes only, not called in quickstart
-query GetFavoriteActors @auth(level: USER) {
-  user(key: {id_expr: "auth.uid"}) {
-    favorite_actors_on_user {
-      actor {
-        id
-        name
-        imageUrl
-      }
-    }
-  }
-}
-
 # Get user by ID
 query GetCurrentUser @auth(level: USER) {
   user(key: {id_expr: "auth.uid"}) {
@@ -367,4 +243,122 @@ query SearchMovieDescriptionUsingL2Similarity($query: String!)
     imageUrl
   }
 }
+# The queries below are unused by the application, but are useful examples for more complex cases
 
+# List movies by partial title match
+query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
+  movies(where: { title: { contains: $input } }) {
+    id
+    title
+    genre
+    rating
+    imageUrl
+  }
+}
+
+# List movies by tag
+query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
+  movies(where: { tags: { includes: $tag } }) {
+    id
+    title
+    imageUrl
+    genre
+    rating
+  }
+}
+
+# List movies by release year range
+query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
+  movies(
+    where: { releaseYear: { le: $max, ge: $min } }
+    orderBy: { releaseYear: ASC }
+  ) {
+    id
+    rating
+    title
+    imageUrl
+  }
+}
+
+# List movies by rating and genre with OR filters
+query SearchMovieOr(
+  $minRating: Float
+  $maxRating: Float
+  $genre: String
+  $tag: String
+  $input: String
+) @auth(level: PUBLIC) {
+  movies(
+    where: {
+      _or: [
+        { rating: { ge: $minRating } }
+        { rating: { le: $maxRating } }
+        { genre: { eq: $genre } }
+        { tags: { includes: $tag } }
+        { title: { contains: $input } }
+      ]
+    }
+  ) {
+    id
+    rating
+    title
+    imageUrl
+  }
+}
+
+# List movies by rating and genre with AND filters
+query SearchMovieAnd(
+  $minRating: Float
+  $maxRating: Float
+  $genre: String
+  $tag: String
+  $input: String
+) @auth(level: PUBLIC) {
+  movies(
+    where: {
+      _and: [
+        { rating: { ge: $minRating } }
+        { rating: { le: $maxRating } }
+        { genre: { eq: $genre } }
+        { tags: { includes: $tag } }
+        { title: { contains: $input } }
+      ]
+    }
+  ) {
+    id
+    rating
+    title
+    imageUrl
+  }
+}
+
+# Get favorite actors by user ID
+query GetFavoriteActors @auth(level: USER) {
+  user(key: {id_expr: "auth.uid"}) {
+    favorite_actors_on_user {
+      actor {
+        id
+        name
+        imageUrl
+      }
+    }
+  }
+}
+
+# Get favorite movies by user ID
+query GetUserFavoriteMovies @auth(level: USER) {
+  user(id_expr: "auth.uid") {
+    favorite_movies_on_user {
+      movie {
+        id
+        title
+        genre
+        imageUrl
+        releaseYear
+        rating
+        description
+      }
+    }
+  }
+}
+# end of example queries

From 06abb1b6603edddcd2fe97b062e975a76bb11375 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 18:34:29 -0400
Subject: [PATCH 35/82] feat: update eslint

---
 dataconnect/app/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dataconnect/app/package.json b/dataconnect/app/package.json
index 4dc225ae5..0b8f4eff4 100644
--- a/dataconnect/app/package.json
+++ b/dataconnect/app/package.json
@@ -21,7 +21,7 @@
   "devDependencies": {
     "@types/react": "^18.2.43",
     "@types/react-dom": "^18.2.17",
-    "@typescript-eslint/eslint-plugin": "^6.14.0",
+    "@typescript-eslint/eslint-plugin": "^7.18.0",
     "@typescript-eslint/parser": "^6.14.0",
     "@vitejs/plugin-react": "^4.2.1",
     "autoprefixer": "^10.4.19",

From 53ecad13ee57cc4775c587735ec13fc0a1b04625 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 18:36:55 -0400
Subject: [PATCH 36/82] update eslint versions

---
 package-lock.json | 333 +++++++++++++++++++++++++++++++++++++++++-----
 package.json      |   1 +
 2 files changed, 301 insertions(+), 33 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 6779c7f13..b403d9f80 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
       "version": "1.0.0",
       "license": "Apache-2.0",
       "devDependencies": {
+        "@typescript-eslint/eslint-plugin": "^7.18.0",
         "eslint": "^8.39.0",
         "eslint-plugin-promise": "^6.1.1",
         "lerna": "^6.6.1"
@@ -230,10 +231,11 @@
       }
     },
     "node_modules/@eslint/eslintrc": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz",
-      "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==",
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+      "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
       "dev": true,
+      "license": "MIT",
       "dependencies": {
         "ajv": "^6.12.4",
         "debug": "^4.3.2",
@@ -253,10 +255,11 @@
       }
     },
     "node_modules/@eslint/js": {
-      "version": "8.53.0",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz",
-      "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==",
+      "version": "8.57.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
+      "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
       "dev": true,
+      "license": "MIT",
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
@@ -268,13 +271,15 @@
       "dev": true
     },
     "node_modules/@humanwhocodes/config-array": {
-      "version": "0.11.13",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
-      "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
+      "version": "0.11.14",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
+      "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+      "deprecated": "Use @eslint/config-array instead",
       "dev": true,
+      "license": "Apache-2.0",
       "dependencies": {
-        "@humanwhocodes/object-schema": "^2.0.1",
-        "debug": "^4.1.1",
+        "@humanwhocodes/object-schema": "^2.0.2",
+        "debug": "^4.3.1",
         "minimatch": "^3.0.5"
       },
       "engines": {
@@ -295,10 +300,12 @@
       }
     },
     "node_modules/@humanwhocodes/object-schema": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
-      "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
-      "dev": true
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+      "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+      "deprecated": "Use @eslint/object-schema instead",
+      "dev": true,
+      "license": "BSD-3-Clause"
     },
     "node_modules/@hutson/parse-repository-url": {
       "version": "3.0.2",
@@ -1962,6 +1969,239 @@
       "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
       "dev": true
     },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz",
+      "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.10.0",
+        "@typescript-eslint/scope-manager": "7.18.0",
+        "@typescript-eslint/type-utils": "7.18.0",
+        "@typescript-eslint/utils": "7.18.0",
+        "@typescript-eslint/visitor-keys": "7.18.0",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.3.1",
+        "natural-compare": "^1.4.0",
+        "ts-api-utils": "^1.3.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "@typescript-eslint/parser": "^7.0.0",
+        "eslint": "^8.56.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz",
+      "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "7.18.0",
+        "@typescript-eslint/types": "7.18.0",
+        "@typescript-eslint/typescript-estree": "7.18.0",
+        "@typescript-eslint/visitor-keys": "7.18.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.56.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz",
+      "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "7.18.0",
+        "@typescript-eslint/visitor-keys": "7.18.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz",
+      "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/typescript-estree": "7.18.0",
+        "@typescript-eslint/utils": "7.18.0",
+        "debug": "^4.3.4",
+        "ts-api-utils": "^1.3.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.56.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
+      "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree": {
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz",
+      "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "@typescript-eslint/types": "7.18.0",
+        "@typescript-eslint/visitor-keys": "7.18.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "minimatch": "^9.0.4",
+        "semver": "^7.6.0",
+        "ts-api-utils": "^1.3.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+      "version": "7.6.3",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+      "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz",
+      "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.4.0",
+        "@typescript-eslint/scope-manager": "7.18.0",
+        "@typescript-eslint/types": "7.18.0",
+        "@typescript-eslint/typescript-estree": "7.18.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.56.0"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz",
+      "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "7.18.0",
+        "eslint-visitor-keys": "^3.4.3"
+      },
+      "engines": {
+        "node": "^18.18.0 || >=20.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
     "node_modules/@ungap/structured-clone": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
@@ -2043,10 +2283,11 @@
       }
     },
     "node_modules/acorn": {
-      "version": "8.11.2",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
-      "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
+      "version": "8.12.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+      "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
       "dev": true,
+      "license": "MIT",
       "bin": {
         "acorn": "bin/acorn"
       },
@@ -2059,6 +2300,7 @@
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
       "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
       "dev": true,
+      "license": "MIT",
       "peerDependencies": {
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
@@ -2111,6 +2353,7 @@
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
       "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
       "dev": true,
+      "license": "MIT",
       "dependencies": {
         "fast-deep-equal": "^3.1.1",
         "fast-json-stable-stringify": "^2.0.0",
@@ -3351,16 +3594,17 @@
       }
     },
     "node_modules/eslint": {
-      "version": "8.53.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz",
-      "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==",
+      "version": "8.57.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
+      "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
       "dev": true,
+      "license": "MIT",
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
         "@eslint-community/regexpp": "^4.6.1",
-        "@eslint/eslintrc": "^2.1.3",
-        "@eslint/js": "8.53.0",
-        "@humanwhocodes/config-array": "^0.11.13",
+        "@eslint/eslintrc": "^2.1.4",
+        "@eslint/js": "8.57.0",
+        "@humanwhocodes/config-array": "^0.11.14",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
         "@ungap/structured-clone": "^1.2.0",
@@ -3450,6 +3694,7 @@
       "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
       "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
       "dev": true,
+      "license": "BSD-2-Clause",
       "dependencies": {
         "acorn": "^8.9.0",
         "acorn-jsx": "^5.3.2",
@@ -3600,7 +3845,8 @@
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
       "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-      "dev": true
+      "dev": true,
+      "license": "MIT"
     },
     "node_modules/fast-glob": {
       "version": "3.3.2",
@@ -3634,7 +3880,8 @@
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
       "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
-      "dev": true
+      "dev": true,
+      "license": "MIT"
     },
     "node_modules/fast-levenshtein": {
       "version": "2.0.6",
@@ -4180,10 +4427,11 @@
       }
     },
     "node_modules/globals": {
-      "version": "13.23.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
-      "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
+      "version": "13.24.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
       "dev": true,
+      "license": "MIT",
       "dependencies": {
         "type-fest": "^0.20.2"
       },
@@ -4379,10 +4627,11 @@
       ]
     },
     "node_modules/ignore": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
-      "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+      "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
       "dev": true,
+      "license": "MIT",
       "engines": {
         "node": ">= 4"
       }
@@ -4885,7 +5134,8 @@
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
       "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-      "dev": true
+      "dev": true,
+      "license": "MIT"
     },
     "node_modules/json-stable-stringify-without-jsonify": {
       "version": "1.0.1",
@@ -7705,6 +7955,7 @@
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
       "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
       "dev": true,
+      "license": "MIT",
       "engines": {
         "node": ">=6"
       }
@@ -8700,6 +8951,7 @@
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
       "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
       "dev": true,
+      "license": "MIT",
       "engines": {
         "node": ">=8"
       },
@@ -8932,6 +9184,19 @@
         "node": ">=8"
       }
     },
+    "node_modules/ts-api-utils": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
+      "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=16"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.2.0"
+      }
+    },
     "node_modules/tsconfig-paths": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
@@ -9074,6 +9339,7 @@
       "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
       "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
       "dev": true,
+      "license": "(MIT OR CC0-1.0)",
       "engines": {
         "node": ">=10"
       },
@@ -9179,6 +9445,7 @@
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
       "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
       "dev": true,
+      "license": "BSD-2-Clause",
       "dependencies": {
         "punycode": "^2.1.0"
       }
diff --git a/package.json b/package.json
index 78ea42bb9..652e7b335 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
   },
   "homepage": "https://github.com/firebase/quickstart-js#readme",
   "devDependencies": {
+    "@typescript-eslint/eslint-plugin": "^7.18.0",
     "eslint": "^8.39.0",
     "eslint-plugin-promise": "^6.1.1",
     "lerna": "^6.6.1"

From 066753f09544d55f5aa34ae38a44ac10e5b49523 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 18:41:06 -0400
Subject: [PATCH 37/82] fix: eslint

---
 dataconnect/app/.eslintrc.cjs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dataconnect/app/.eslintrc.cjs b/dataconnect/app/.eslintrc.cjs
index 74395f2c6..d25ee83a6 100644
--- a/dataconnect/app/.eslintrc.cjs
+++ b/dataconnect/app/.eslintrc.cjs
@@ -4,7 +4,6 @@ module.exports = {
   extends: [
     'eslint:recommended',
     'plugin:@typescript-eslint/recommended',
-    'plugin:react-hooks/recommended',
   ],
   ignorePatterns: ['dist', '.eslintrc.cjs'],
   parser: '@typescript-eslint/parser',
@@ -14,6 +13,7 @@ module.exports = {
       'warn',
       { allowConstantExport: true },
     ],
+    "react-hooks/rules-of-hooks": "error",
     "react-hooks/exhaustive-deps": "warn"
   },
 }

From b15d8f4d611da95439eba7a0a8971aad8e09e167 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 18:42:32 -0400
Subject: [PATCH 38/82] fix: plugins

---
 dataconnect/app/.eslintrc.cjs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/dataconnect/app/.eslintrc.cjs b/dataconnect/app/.eslintrc.cjs
index d25ee83a6..0dd6761f5 100644
--- a/dataconnect/app/.eslintrc.cjs
+++ b/dataconnect/app/.eslintrc.cjs
@@ -7,7 +7,6 @@ module.exports = {
   ],
   ignorePatterns: ['dist', '.eslintrc.cjs'],
   parser: '@typescript-eslint/parser',
-  plugins: ['react-refresh'],
   rules: {
     'react-refresh/only-export-components': [
       'warn',

From 3a75679a684c76cb030768159add73c0db7f6b92 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 19:39:37 -0400
Subject: [PATCH 39/82] feat: update eslint

---
 dataconnect/app/.eslintrc.cjs | 3 ++-
 dataconnect/app/package.json  | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/dataconnect/app/.eslintrc.cjs b/dataconnect/app/.eslintrc.cjs
index 0dd6761f5..74395f2c6 100644
--- a/dataconnect/app/.eslintrc.cjs
+++ b/dataconnect/app/.eslintrc.cjs
@@ -4,15 +4,16 @@ module.exports = {
   extends: [
     'eslint:recommended',
     'plugin:@typescript-eslint/recommended',
+    'plugin:react-hooks/recommended',
   ],
   ignorePatterns: ['dist', '.eslintrc.cjs'],
   parser: '@typescript-eslint/parser',
+  plugins: ['react-refresh'],
   rules: {
     'react-refresh/only-export-components': [
       'warn',
       { allowConstantExport: true },
     ],
-    "react-hooks/rules-of-hooks": "error",
     "react-hooks/exhaustive-deps": "warn"
   },
 }
diff --git a/dataconnect/app/package.json b/dataconnect/app/package.json
index 0b8f4eff4..9c44d3ed8 100644
--- a/dataconnect/app/package.json
+++ b/dataconnect/app/package.json
@@ -22,7 +22,7 @@
     "@types/react": "^18.2.43",
     "@types/react-dom": "^18.2.17",
     "@typescript-eslint/eslint-plugin": "^7.18.0",
-    "@typescript-eslint/parser": "^6.14.0",
+    "@typescript-eslint/parser": "^7.18.0",
     "@vitejs/plugin-react": "^4.2.1",
     "autoprefixer": "^10.4.19",
     "eslint": "^8.55.0",

From 66e098e5b5b3e6bdb7037c08e49af54b0b06dfd1 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 19:41:46 -0400
Subject: [PATCH 40/82] fix: react-hooks

---
 dataconnect/app/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dataconnect/app/package.json b/dataconnect/app/package.json
index 9c44d3ed8..41ac9cff2 100644
--- a/dataconnect/app/package.json
+++ b/dataconnect/app/package.json
@@ -26,7 +26,7 @@
     "@vitejs/plugin-react": "^4.2.1",
     "autoprefixer": "^10.4.19",
     "eslint": "^8.55.0",
-    "eslint-plugin-react-hooks": "^4.6.0",
+    "eslint-plugin-react-hooks": "^4.6.2",
     "eslint-plugin-react-refresh": "^0.4.5",
     "postcss": "^8.4.40",
     "tailwindcss": "^3.4.7",

From fbcd1df4334534f45b3472a78ea926953f74e573 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 19:45:45 -0400
Subject: [PATCH 41/82] fix: update versions

---
 package-lock.json | 14 ++++++++++++++
 package.json      |  1 +
 2 files changed, 15 insertions(+)

diff --git a/package-lock.json b/package-lock.json
index b403d9f80..3e24cb785 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
         "@typescript-eslint/eslint-plugin": "^7.18.0",
         "eslint": "^8.39.0",
         "eslint-plugin-promise": "^6.1.1",
+        "eslint-plugin-react-hooks": "^4.6.2",
         "lerna": "^6.6.1"
       },
       "engines": {
@@ -3661,6 +3662,19 @@
         "eslint": "^7.0.0 || ^8.0.0"
       }
     },
+    "node_modules/eslint-plugin-react-hooks": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz",
+      "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
+      }
+    },
     "node_modules/eslint-scope": {
       "version": "7.2.2",
       "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
diff --git a/package.json b/package.json
index 652e7b335..830a93e10 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
     "@typescript-eslint/eslint-plugin": "^7.18.0",
     "eslint": "^8.39.0",
     "eslint-plugin-promise": "^6.1.1",
+    "eslint-plugin-react-hooks": "^4.6.2",
     "lerna": "^6.6.1"
   },
   "scripts": {

From dcfd1e88bb6b8158498cec8b76e63ca8abb030c1 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 29 Jul 2024 19:47:37 -0400
Subject: [PATCH 42/82] fix: plugin refresh

---
 package-lock.json | 11 +++++++++++
 package.json      |  1 +
 2 files changed, 12 insertions(+)

diff --git a/package-lock.json b/package-lock.json
index 3e24cb785..4b1efc839 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
         "eslint": "^8.39.0",
         "eslint-plugin-promise": "^6.1.1",
         "eslint-plugin-react-hooks": "^4.6.2",
+        "eslint-plugin-react-refresh": "^0.4.9",
         "lerna": "^6.6.1"
       },
       "engines": {
@@ -3675,6 +3676,16 @@
         "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
       }
     },
+    "node_modules/eslint-plugin-react-refresh": {
+      "version": "0.4.9",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.9.tgz",
+      "integrity": "sha512-QK49YrBAo5CLNLseZ7sZgvgTy21E6NEw22eZqc4teZfH8pxV3yXc9XXOYfUI6JNpw7mfHNkAeWtBxrTyykB6HA==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "eslint": ">=7"
+      }
+    },
     "node_modules/eslint-scope": {
       "version": "7.2.2",
       "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
diff --git a/package.json b/package.json
index 830a93e10..c46c994eb 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
     "eslint": "^8.39.0",
     "eslint-plugin-promise": "^6.1.1",
     "eslint-plugin-react-hooks": "^4.6.2",
+    "eslint-plugin-react-refresh": "^0.4.9",
     "lerna": "^6.6.1"
   },
   "scripts": {

From fc277c313c6261311a0690b738c3cea8389c236c Mon Sep 17 00:00:00 2001
From: Alejandro Marco Alejandre <alejandromarco@google.com>
Date: Fri, 2 Aug 2024 23:56:57 +0800
Subject: [PATCH 43/82] Wrap emulator exec script in double quotes

---
 firestore/package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/firestore/package.json b/firestore/package.json
index 358723701..04af77485 100644
--- a/firestore/package.json
+++ b/firestore/package.json
@@ -3,8 +3,8 @@
   "version": "0.0.0",
   "scripts": {
     "ng": "ng",
-    "start": "npm run pre-build && firebase --project demo-friendly-eats emulators:exec --import ./app-data-seed --ui 'ng serve'",
-    "emulators": "npm run pre-build && firebase --project demo-friendly-eats emulators:exec --import ./app-data-seed --ui 'ng serve -c local'",
+    "start": "npm run pre-build && firebase --project demo-friendly-eats emulators:exec --import ./app-data-seed --ui \"ng serve\"",
+    "emulators": "npm run pre-build && firebase --project demo-friendly-eats emulators:exec --import ./app-data-seed --ui \"ng serve -c local\"",
     "production": "npm run pre-build && firebase deploy --only firestore && npm run check-config",
     "check-config":"grep -q \"projectId\" \"src/environments/environment.prod.ts\" && ng serve -c production || echo \"No project id in configuration file!\"",
     "pre-build": "(cd functions && npm run build)",

From 0a8a6806a677ea9068ce09458d41a32fe2872143 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Mon, 9 Sep 2024 13:38:25 -0400
Subject: [PATCH 44/82] fix: dataconnect @auth

---
 .../dataconnect/movie-connector/mutations.gql | 25 +++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/dataconnect/dataconnect/movie-connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
index fdac88bc7..b9f562c74 100644
--- a/dataconnect/dataconnect/movie-connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -7,7 +7,8 @@ mutation CreateMovie(
   $description: String
   $imageUrl: String!
   $tags: [String!] = []
-) @auth(level: USER_EMAIL_VERIFIED) {
+) @auth(expr: "auth.token.isAdmin == true") {
+  builders($tenantId: String!) {
   movie_insert(
     data: {
       title: $title
@@ -47,7 +48,27 @@ mutation AddReview(
   $rating: Int!
   $reviewText: String!
 ) @auth(level: USER) {
-  review_upsert(
+  review_update(
+    data: {
+      userId_expr: "auth.uid"
+      movieId: $movieId
+      rating: $rating
+      reviewText: $reviewText
+      reviewDate_date: { today: true }
+    }
+  )
+}
+
+# Update a user's review for a movie
+mutation UpdateReview(
+  $id: UUID!
+  $movieId: UUID!
+  $rating: Int!
+  $reviewText: String!
+  $userId: String!
+) @auth(expr: "auth.uid != null && auth.uid == userId") {
+  review_update(
+    id: $id,
     data: {
       userId_expr: "auth.uid"
       movieId: $movieId

From 739dc3b54e2672c52057e110c2274cc26deeaf5d Mon Sep 17 00:00:00 2001
From: Cynthia Wang <44329917+HYACCCINT@users.noreply.github.com>
Date: Thu, 12 Sep 2024 10:31:17 -0400
Subject: [PATCH 45/82] feat: add fdc readme (#811)

* feat: add fdc readme

* fix: running app

* update: readme

* Update README.md

* fix: comments
---
 dataconnect/README.md | 68 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 dataconnect/README.md

diff --git a/dataconnect/README.md b/dataconnect/README.md
new file mode 100644
index 000000000..bbb1aac51
--- /dev/null
+++ b/dataconnect/README.md
@@ -0,0 +1,68 @@
+Firebase DataConnect Quickstart
+=======================================
+
+Introduction
+------------
+
+This is a sample app for the preview version of the Firebase DataConnect.
+This service is currently in Private Preview at no cost for a limited time. Sign up for the program at [Firebase Data Connect](https://firebase.google.com/products/data-connect).
+This quickstart will not work if you don't have access to the preview.
+
+<!-- Introduction
+------------
+
+[Read more about Firebase DataConnect ](https://firebase.google.com/docs/dataconnect/) -->
+
+#  Getting Started with Firebase Data Connect
+---------------
+Follow these steps to get up and running with Firebase Data Connect. For more detailed instructions, check out the [official documentation](https://firebase.google.com/docs/data-connect/quickstart).
+
+### 1. Create a New Data Connect Service and Cloud SQL Instance
+
+1. Open [Firebase Data Connect](https://console.firebase.google.com/u/0/project/_/dataconnect) in your project in Firebase Console and select Get Started.
+2. Create a new Data Connect service and a Cloud SQL instance. Ensure the Blaze plan is active. Pricing details can be found at [Firebase Pricing](https://firebase.google.com/pricing).
+3. Select your server region, if you wish to use vector search, make sure to select `us-central1` region.
+4. Allow some time for the Cloud SQL instance to be provisioned. After it's provisioned, the instance can be managed in the [Cloud Console](https://pantheon.corp.google.com/sql).
+
+### 2. Set Up Firebase CLI
+
+Ensure the Firebase CLI is installed and up to date:
+
+```bash
+npm install -g firebase-tools
+```
+
+### 3. Cloning the repository
+This repository contains the quickstart to get started with the functionalities of Data Connect.
+
+1. Clone this repository to your local machine.
+2. cd to the `dataconnect` folder, and initialize your Firebase project with `firebase init dataconnect`. Overwrite only dataconnect.yaml when prompted, do not overwrite any other dataconnect files.
+(Optional): If you intend on using other Firebase features, run `firebase init` instead, and select both DataConnect options as well as any feature you intend to use.
+3. Replace variables in `.env` with your project-specific values.
+4. Allow domains for Firebase Auth in your [project console](https://console.firebase.google.com/project/_/authentication/settings) (e.g. http://127.0.0.1).
+
+### 4. Running queries and mutations in VS Code
+The VSCode Firebase Extension allows you to generate Firebase Data Connect SDK code, run queries/mutations, and deploy Firebase Data Connect with a click. Alternatively, see below for CLI commands.
+
+1. Install [VS Code](https://code.visualstudio.com/).
+2. Download the [Firebase extension](https://firebasestorage.googleapis.com/v0/b/firemat-preview-drop/o/vsix%2Ffirebase-vscode-latest.vsix?alt=media) and [install](https://code.visualstudio.com/docs/editor/extension-marketplace#_install-an-extension) it.
+3. Open this quickstart in VS code, and in the left pane of the Firebase extension, and log in with your Firebase account.
+(Optional): If your Firebase project was not initialized in the last section, you can click `Run firebase init` and select `Data Connect` to initialize.
+4. Click on deploy to deploy your schema to your cloud SQL instance. Or run `firebase deploy --only dataconnect` (this will also activate vectors search if it's enabled in the schema).
+5. Running the VSCode extension should automatically start the DataConnect emulators. If you see an emulators error, try running `firebase emulators:start dataconnect` manually.
+
+Now you should be able to deploy your schema, run mutations/queries, generate SDK code, and view your application locally.
+
+### 5. Populating the database
+1. Run `1_movie_insert.gql`, `2_actor_insert.gql`, `3_movie_actor_insert.gql`, and `4_user_favorites_review_insert.gql` files in the `./dataconnect` directory in order using the VS code extension, 
+
+### 6. Running the app
+
+1. `cd` into the src folder, and run `npm run dev` to start the localhost web app.
+(Optional): To use the Firebase Auth emulator, run `firebase emulators:start` and uncomment the `connectAuthEmulator` function in `app/src/lib/firebase.ts`.
+
+License
+-------
+
+© Google, 2024. Licensed under an [Apache-2](../../LICENSE) license.
+

From 337a708b0a0538f77d85e4441aa36446e32ef26c Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Thu, 12 Sep 2024 14:03:54 -0400
Subject: [PATCH 46/82] fix: dataconnect mutation

---
 dataconnect/dataconnect/movie-connector/mutations.gql | 1 -
 1 file changed, 1 deletion(-)

diff --git a/dataconnect/dataconnect/movie-connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
index b9f562c74..4dc4fff18 100644
--- a/dataconnect/dataconnect/movie-connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -8,7 +8,6 @@ mutation CreateMovie(
   $imageUrl: String!
   $tags: [String!] = []
 ) @auth(expr: "auth.token.isAdmin == true") {
-  builders($tenantId: String!) {
   movie_insert(
     data: {
       title: $title

From b0871ba52afce265fb50e9acb2ee5c6094a06f03 Mon Sep 17 00:00:00 2001
From: Yuchen Shi <yuchenshi@google.com>
Date: Tue, 17 Sep 2024 23:06:23 -0700
Subject: [PATCH 47/82] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?=
 =?UTF-8?q?initial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.6-beta.1
---
 dataconnect/dataconnect/movie-connector/mutations.gql | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/dataconnect/dataconnect/movie-connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
index b9f562c74..7a00b7c5b 100644
--- a/dataconnect/dataconnect/movie-connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -8,7 +8,6 @@ mutation CreateMovie(
   $imageUrl: String!
   $tags: [String!] = []
 ) @auth(expr: "auth.token.isAdmin == true") {
-  builders($tenantId: String!) {
   movie_insert(
     data: {
       title: $title
@@ -48,7 +47,7 @@ mutation AddReview(
   $rating: Int!
   $reviewText: String!
 ) @auth(level: USER) {
-  review_update(
+  review_insert(
     data: {
       userId_expr: "auth.uid"
       movieId: $movieId
@@ -61,14 +60,12 @@ mutation AddReview(
 
 # Update a user's review for a movie
 mutation UpdateReview(
-  $id: UUID!
   $movieId: UUID!
   $rating: Int!
   $reviewText: String!
-  $userId: String!
-) @auth(expr: "auth.uid != null && auth.uid == userId") {
+) @auth(level: USER) {
   review_update(
-    id: $id,
+    key: {movieId: $movieId, userId_expr: "auth.uid"},
     data: {
       userId_expr: "auth.uid"
       movieId: $movieId
@@ -132,4 +129,4 @@ mutation DeleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
 mutation DeleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
   movie_deleteMany(where: { rating: { le: $minRating } })
 }
-# End of example mutations
\ No newline at end of file
+# End of example mutations

From fdba3e016a9ffe9457490484ea2d58e8ba7fa4d5 Mon Sep 17 00:00:00 2001
From: Yuchen Shi <yuchenshi@google.com>
Date: Mon, 23 Sep 2024 13:20:05 -0700
Subject: [PATCH 48/82] Update mutations.gql

---
 dataconnect/dataconnect/movie-connector/mutations.gql | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dataconnect/dataconnect/movie-connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
index 7a00b7c5b..c236bfb2d 100644
--- a/dataconnect/dataconnect/movie-connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -47,7 +47,7 @@ mutation AddReview(
   $rating: Int!
   $reviewText: String!
 ) @auth(level: USER) {
-  review_insert(
+  review_upsert(
     data: {
       userId_expr: "auth.uid"
       movieId: $movieId
@@ -59,6 +59,7 @@ mutation AddReview(
 }
 
 # Update a user's review for a movie
+# (This is just an example on how to do updates with compound keys; it's not used in the app.)
 mutation UpdateReview(
   $movieId: UUID!
   $rating: Int!

From 1644538dfb0235af7652603f3dbfc7c9d2fdc671 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Tue, 1 Oct 2024 10:05:42 -0400
Subject: [PATCH 49/82] feat: update version to public preview

---
 dataconnect/app/.env                          |   6 -
 dataconnect/app/.gitignore                    |  24 -
 dataconnect/app/index.html                    |   1 +
 dataconnect/app/package.json                  |   2 +-
 dataconnect/app/src/App.tsx                   |   2 -
 dataconnect/app/src/components/carousel.tsx   |   2 +-
 dataconnect/app/src/components/moviecard.tsx  |  95 ++-
 dataconnect/app/src/components/navbar.tsx     |  38 +-
 dataconnect/app/src/lib/MovieService.tsx      | 231 ++++++
 dataconnect/app/src/lib/firebase.tsx          |  44 +-
 dataconnect/app/src/pages/Actor.tsx           |  69 +-
 dataconnect/app/src/pages/AdvancedSearch.tsx  |  38 +-
 dataconnect/app/src/pages/Genre.tsx           |  67 --
 dataconnect/app/src/pages/Home.tsx            |  18 +-
 dataconnect/app/src/pages/Movie.tsx           | 245 ++++---
 dataconnect/app/src/pages/MyProfile.tsx       | 137 ++--
 dataconnect/app/src/pages/VectorSearch.tsx    |  13 +-
 dataconnect/app/tailwind.config.js            |   6 +-
 dataconnect/dataconnect/.DS_Store             | Bin 0 -> 6148 bytes
 dataconnect/dataconnect/1_movie_insert.gql    | 204 ------
 dataconnect/dataconnect/2_actor_insert.gql    | 104 ---
 .../dataconnect/3_movie_actor_insert.gql      | 238 ------
 .../4_user_favorites_review_insert.gql        | 121 ---
 .../dataconnect/5_optional_vector_embed.gql   | 141 ----
 .../dataconnect/movie-connector/mutations.gql | 136 ++--
 .../dataconnect/movie-connector/queries.gql   | 311 ++++----
 dataconnect/dataconnect/moviedata_insert.gql  | 687 ++++++++++++++++++
 .../dataconnect/optional_vector_embed.gql     | 201 +++++
 dataconnect/dataconnect/package.json          |   5 +
 dataconnect/dataconnect/schema/schema.gql     |  23 +-
 dataconnect/firebase.json                     |   9 +-
 31 files changed, 1635 insertions(+), 1583 deletions(-)
 delete mode 100644 dataconnect/app/.env
 delete mode 100644 dataconnect/app/.gitignore
 create mode 100644 dataconnect/app/src/lib/MovieService.tsx
 delete mode 100644 dataconnect/app/src/pages/Genre.tsx
 create mode 100644 dataconnect/dataconnect/.DS_Store
 delete mode 100644 dataconnect/dataconnect/1_movie_insert.gql
 delete mode 100644 dataconnect/dataconnect/2_actor_insert.gql
 delete mode 100644 dataconnect/dataconnect/3_movie_actor_insert.gql
 delete mode 100644 dataconnect/dataconnect/4_user_favorites_review_insert.gql
 delete mode 100644 dataconnect/dataconnect/5_optional_vector_embed.gql
 create mode 100644 dataconnect/dataconnect/moviedata_insert.gql
 create mode 100644 dataconnect/dataconnect/optional_vector_embed.gql
 create mode 100644 dataconnect/dataconnect/package.json

diff --git a/dataconnect/app/.env b/dataconnect/app/.env
deleted file mode 100644
index 3ccd40ee1..000000000
--- a/dataconnect/app/.env
+++ /dev/null
@@ -1,6 +0,0 @@
-VITE_FIREBASE_API_KEY=your-api-key
-VITE_FIREBASE_AUTH_DOMAIN=your-auth-domain
-VITE_FIREBASE_PROJECT_ID=your-project-id
-VITE_FIREBASE_STORAGE_BUCKET=your-storage-bucket
-VITE_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id
-VITE_FIREBASE_APP_ID=your-app-id
diff --git a/dataconnect/app/.gitignore b/dataconnect/app/.gitignore
deleted file mode 100644
index a547bf36d..000000000
--- a/dataconnect/app/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
diff --git a/dataconnect/app/index.html b/dataconnect/app/index.html
index 7152fe9d8..08f2bdaf3 100644
--- a/dataconnect/app/index.html
+++ b/dataconnect/app/index.html
@@ -3,6 +3,7 @@
   <head>
     <meta charset="UTF-8" />
     <link rel="icon" type="image/svg+xml" href="/app/src/assets/firebase_logo.svg" />
+    <link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;700&display=swap" rel="stylesheet">
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>FriendlyMovies</title>
   </head>
diff --git a/dataconnect/app/package.json b/dataconnect/app/package.json
index 41ac9cff2..00e022c24 100644
--- a/dataconnect/app/package.json
+++ b/dataconnect/app/package.json
@@ -12,7 +12,7 @@
   "dependencies": {
     "@movie/dataconnect": "file:src/lib/dataconnect-sdk",
     "dotenv": "^16.4.5",
-    "firebase": "^10.12.0-dataconnect-preview.388b61c7e",
+    "firebase": "^10.12.4-dataconnect-preview.d986d4bf2",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "react-icons": "^5.2.1",
diff --git a/dataconnect/app/src/App.tsx b/dataconnect/app/src/App.tsx
index ab89c0a6b..28a894a5e 100644
--- a/dataconnect/app/src/App.tsx
+++ b/dataconnect/app/src/App.tsx
@@ -3,7 +3,6 @@ import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
 import Home from "./pages/Home";
 import ActorPage from "./pages/Actor";
 import MoviePage from "./pages/Movie";
-import GenrePage from "./pages/Genre";
 import MyProfilePage from "./pages/MyProfile";
 import VectorSearchPage from "./pages/VectorSearch";
 import AdvancedSearchPage from "./pages/AdvancedSearch";
@@ -18,7 +17,6 @@ export default function App() {
           <Route path="/" element={<Home />} />
           <Route path="/actor/:id" element={<ActorPage />} />
           <Route path="/movie/:id" element={<MoviePage />} />
-          <Route path="/genre/:genre" element={<GenrePage />} />
           <Route path="/myprofile" element={<MyProfilePage />} />
           <Route path="/vectorsearch" element={<VectorSearchPage />} />
           <Route path="/advancedsearch" element={<AdvancedSearchPage />} />
diff --git a/dataconnect/app/src/components/carousel.tsx b/dataconnect/app/src/components/carousel.tsx
index 9849a95bc..625724604 100644
--- a/dataconnect/app/src/components/carousel.tsx
+++ b/dataconnect/app/src/components/carousel.tsx
@@ -17,7 +17,7 @@ export default function Carousel({ title, movies }: CarouselProps) {
   return (
     <section className="carousel py-8">
       <h2 className="text-gray-200 text-2xl font-bold mb-4">{title}</h2>
-      <div className="carousel__container flex overflow-x-auto space-x-4">
+      <div className="carousel__container flex overflow-x-auto space-x-4 overflow-y-clip">
         {movies.map((movie) => (
           <div className="flex-shrink-0" key={movie.id}>
             <MovieCard
diff --git a/dataconnect/app/src/components/moviecard.tsx b/dataconnect/app/src/components/moviecard.tsx
index 7af10a7f0..a985eb6ee 100644
--- a/dataconnect/app/src/components/moviecard.tsx
+++ b/dataconnect/app/src/components/moviecard.tsx
@@ -1,9 +1,13 @@
-import React, { useContext, useEffect, useState } from 'react';
-import { Link, useNavigate } from 'react-router-dom';
-import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
-import { onAuthStateChanged, User } from 'firebase/auth';
-import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from '@movie/dataconnect';
-import { AuthContext } from '@/lib/firebase';
+import React, { useContext, useEffect, useState } from "react";
+import { Link, useNavigate } from "react-router-dom";
+import { MdFavorite, MdFavoriteBorder, MdStar } from "react-icons/md";
+import { onAuthStateChanged, User } from "firebase/auth";
+import { AuthContext } from "@/lib/firebase";
+import {
+  handleAddFavoritedMovie,
+  handleDeleteFavoritedMovie,
+  handleGetIfFavoritedMovie,
+} from "@/lib/MovieService";
 
 interface MovieCardProps {
   id: string;
@@ -20,7 +24,7 @@ export default function MovieCard({
   imageUrl,
   rating,
   genre,
-  tags
+  tags,
 }: MovieCardProps) {
   const [user, setUser] = useState<User | null>(null);
   const [isFavorited, setIsFavorited] = useState(false);
@@ -28,38 +32,40 @@ export default function MovieCard({
   const navigate = useNavigate();
 
   useEffect(() => {
-    const unsubscribe = onAuthStateChanged(auth, (user) => {
-      async function checkIfFavorited() {
-        try {
-          const response = await getIfFavoritedMovie({ movieId: id });
-          setIsFavorited(!!response.data.favorite_movie);
-        } catch (error) {
-          console.error('Error checking if favorited:', error);
-        }
+    async function checkIfFavorited() {
+      try {
+        const isFav = await handleGetIfFavoritedMovie(id);
+        setIsFavorited(isFav);
+      } catch (error) {
+        console.error("Error checking if movie is favorited:", error);
       }
+    }
+    const unsubscribe = onAuthStateChanged(auth, (user) => {
       if (user) {
         setUser(user);
         checkIfFavorited();
+      } else {
+        setIsFavorited(false);
       }
     });
 
     return () => unsubscribe();
   }, [auth, id]);
 
-
   async function handleFavoriteToggle(e: React.MouseEvent) {
     e.stopPropagation();
     e.preventDefault();
     if (!user) return;
     try {
-      if (isFavorited) {
-        await deleteFavoritedMovie({ movieId: id });
+      const isFav = await handleGetIfFavoritedMovie(id);
+      if (isFav) {
+        await handleDeleteFavoritedMovie(id);
       } else {
-        await addFavoritedMovie({ movieId: id });
+        await handleAddFavoritedMovie(id);
       }
-      setIsFavorited(!isFavorited);
+      setIsFavorited(!isFav);
     } catch (error) {
-      console.error('Error updating favorite status:', error);
+      console.error("Error updating favorite status:", error);
     }
   }
 
@@ -73,40 +79,55 @@ export default function MovieCard({
 
   return (
     <div
-      className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-1000 transform hover:scale-105 cursor-pointer w-64"
+      className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-1000 transform hover:scale-105 cursor-pointer w-64 h-[440px]"
       onClick={handleCardClick}
     >
       <div>
         <img className="w-full h-64 object-cover" src={imageUrl} alt={title} />
         <div className="p-4">
-          <div className="font-bold text-lg mb-1 text-white whitespace-nowrap overflow-hidden overflow-ellipsis">{title}</div>
+          <div className="font-bold text-lg mb-1 text-white whitespace-nowrap overflow-hidden overflow-ellipsis">
+            {title}
+          </div>
+          <div className="flex flex-row gap-6 justify-between w-full">
+
+          <div className="flex space-x-2 items-center">
+            <button
+              className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
+              aria-label="Favorite"
+              onClick={handleFavoriteToggle}
+            >
+              {isFavorited ? (
+                <MdFavorite size={20} />
+              ) : (
+                <MdFavoriteBorder size={20} />
+              )}
+            </button>
+          </div>
           <div className="flex items-center text-yellow-500">
             <MdStar className="text-yellow-500" size={20} />
-            <span className="ml-1 text-gray-400">{rating ?? 'N/A'}</span>
+            <span className="ml-1 text-gray-400">{rating ?? "N/A"}</span>
+          </div>
           </div>
           <div className="mt-2 text-gray-400">
             {genre && (
-              <Link to={`/genre/${genre.toLowerCase()}`} className="block mb-1 hover:underline">
+              <Link
+                to={`/genre/${genre.toLowerCase()}`}
+                className="block mb-1 hover:underline"
+              >
                 {capitalize(genre)}
               </Link>
             )}
             <div className="flex flex-wrap gap-1">
               {tags?.map((tag, index) => (
-                <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs">{capitalize(tag)}</span>
+                <span
+                  key={index}
+                  className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs"
+                >
+                  {capitalize(tag)}
+                </span>
               ))}
             </div>
           </div>
-          {user && (
-            <div className="mt-2 flex space-x-2 items-center">
-              <button
-                className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
-                aria-label="Favorite"
-                onClick={handleFavoriteToggle}
-              >
-                {isFavorited ? <MdFavorite size={20} /> : <MdFavoriteBorder size={20} />}
-              </button>
-            </div>
-          )}
         </div>
       </div>
     </div>
diff --git a/dataconnect/app/src/components/navbar.tsx b/dataconnect/app/src/components/navbar.tsx
index 2a98fcb72..bf73ad6f4 100644
--- a/dataconnect/app/src/components/navbar.tsx
+++ b/dataconnect/app/src/components/navbar.tsx
@@ -1,8 +1,8 @@
 import React, { useEffect, useState, useContext } from 'react';
-import { onAuthStateChanged, signInWithPopup, GoogleAuthProvider, signOut, User } from 'firebase/auth';
+import { signInWithPopup, GoogleAuthProvider, signOut, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
 import { Link } from 'react-router-dom';
-import { upsertUser } from '@movie/dataconnect';
+import { handleAuthStateChange } from '@/lib/MovieService';
 import { FaSearch } from 'react-icons/fa';
 import firebaseLogo from '@/assets/firebase_logo.svg';
 
@@ -10,16 +10,9 @@ export default function Navbar() {
   const [user, setUser] = useState<User | null>(null);
   const auth = useContext(AuthContext);
 
+
   useEffect(() => {
-    const unsubscribe = onAuthStateChanged(auth, async (user) => {
-      if (user) {
-        setUser(user);
-        const username = user.email?.substring(0, user.email?.indexOf("@")) || 'anon';
-        await upsertUser({ username });
-      } else {
-        setUser(null);
-      }
-    });
+    const unsubscribe = handleAuthStateChange(auth, setUser);
     return () => unsubscribe();
   }, [auth]);
 
@@ -36,29 +29,10 @@ export default function Navbar() {
     <nav className="bg-black p-4">
       <div className="container mx-auto flex justify-between items-center">
         <div className="flex items-center space-x-4">
-          <Link to="/" className="flex items-center text-white text-lg font-bold">
+          <Link to="/" className="flex items-center">
             <img src={firebaseLogo} alt="Firebase Logo" width={30} height={30} className="mr-2" />
-            FriendlyMovies
+            <span className=" text-white text-lg font-bold hidden md:block">FriendlyMovies</span>
           </Link>
-          <div className="relative group">
-            <button className="text-gray-200 hover:text-white">Genres</button>
-            <div className="absolute hidden group-hover:block bg-black text-white mt-1 rounded shadow-lg" style={{ minWidth: '150px' }}>
-              <div className="py-2">
-                <Link to="/genre/action" className="block px-4 py-2 hover:bg-gray-800">
-                  Action
-                </Link>
-                <Link to="/genre/crime" className="block px-4 py-2 hover:bg-gray-800">
-                  Crime
-                </Link>
-                <Link to="/genre/drama" className="block px-4 py-2 hover:bg-gray-800">
-                  Drama
-                </Link>
-                <Link to="/genre/sci-fi" className="block px-4 py-2 hover:bg-gray-800">
-                  Sci-Fi
-                </Link>
-              </div>
-            </div>
-          </div>
           <Link to="/vectorsearch" className="text-gray-200 hover:text-white">
             Vector Search
           </Link>
diff --git a/dataconnect/app/src/lib/MovieService.tsx b/dataconnect/app/src/lib/MovieService.tsx
new file mode 100644
index 000000000..97e9a200b
--- /dev/null
+++ b/dataconnect/app/src/lib/MovieService.tsx
@@ -0,0 +1,231 @@
+import { listMovies, ListMoviesData, OrderDirection } from "@movie/dataconnect";
+import { getMovieById, GetMovieByIdData } from "@movie/dataconnect";
+import { GetActorByIdData, getActorById } from "@movie/dataconnect";
+
+import { upsertUser } from "@movie/dataconnect";
+import { getCurrentUser, GetCurrentUserData } from "@movie/dataconnect";
+
+import { addFavoritedMovie, deleteFavoritedMovie } from "@movie/dataconnect";
+import { addReview, deleteReview } from "@movie/dataconnect";
+import { getIfFavoritedMovie } from "@movie/dataconnect";
+
+import { searchAll, SearchAllData } from "@movie/dataconnect";
+
+import {
+  searchMovieDescriptionUsingL2similarity,
+  SearchMovieDescriptionUsingL2similarityData,
+} from "@movie/dataconnect";
+
+import { onAuthStateChanged, User } from "firebase/auth";
+
+// Fetch top-rated movies
+export const handleGetTopMovies = async (
+  limit: number
+): Promise<ListMoviesData["movies"] | null> => {
+  try {
+    const response = await listMovies({
+      orderByRating: OrderDirection.DESC,
+      limit,
+    });
+    return response.data.movies;
+  } catch (error) {
+    console.error("Error fetching top movies:", error);
+    return null;
+  }
+};
+
+// Fetch latest movies
+export const handleGetLatestMovies = async (
+  limit: number
+): Promise<ListMoviesData["movies"] | null> => {
+  try {
+    const response = await listMovies({
+      orderByReleaseYear: OrderDirection.DESC,
+      limit,
+    });
+    return response.data.movies;
+  } catch (error) {
+    console.error("Error fetching latest movies:", error);
+    return null;
+  }
+};
+
+// Fetch movie details by ID
+export const handleGetMovieById = async (
+  movieId: string
+): Promise<GetMovieByIdData["movie"] | null> => {
+  try {
+    const response = await getMovieById({ id: movieId });
+    if (response.data.movie) {
+      return response.data.movie;
+    }
+    return null;
+  } catch (error) {
+    console.error("Error fetching movie:", error);
+    return null;
+  }
+};
+
+// Calling generated SDK for GetActorById
+export const handleGetActorById = async (
+  actorId: string
+): Promise<GetActorByIdData["actor"] | null> => {
+  try {
+    const response = await getActorById({ id: actorId });
+    if (response.data.actor) {
+      return response.data.actor;
+    }
+    return null;
+  } catch (error) {
+    console.error("Error fetching actor:", error);
+    return null;
+  }
+};
+
+// Handle user authentication state changes and upsert user
+export const handleAuthStateChange = (
+  auth: any,
+  setUser: (user: User | null) => void
+) => {
+  return onAuthStateChanged(auth, async (user) => {
+    if (user) {
+      setUser(user);
+      const username = user.email?.split("@")[0] || "anon";
+      await upsertUser({ username });
+    } else {
+      setUser(null);
+    }
+  });
+};
+
+// Fetch current user profile
+export const handleGetCurrentUser = async (): Promise<
+  GetCurrentUserData["user"] | null
+> => {
+  try {
+    const response = await getCurrentUser();
+    return response.data.user;
+  } catch (error) {
+    console.error("Error fetching user profile:", error);
+    return null;
+  }
+};
+
+// Add a movie to user's favorites
+export const handleAddFavoritedMovie = async (
+  movieId: string
+): Promise<void> => {
+  try {
+    await addFavoritedMovie({ movieId });
+  } catch (error) {
+    console.error("Error adding movie to favorites:", error);
+    throw error;
+  }
+};
+
+// Remove a movie from user's favorites
+export const handleDeleteFavoritedMovie = async (
+  movieId: string
+): Promise<void> => {
+  try {
+    await deleteFavoritedMovie({ movieId });
+  } catch (error) {
+    console.error("Error removing movie from favorites:", error);
+    throw error;
+  }
+};
+
+// Add a review to a movie
+export const handleAddReview = async (
+  movieId: string,
+  rating: number,
+  reviewText: string
+): Promise<void> => {
+  try {
+    await addReview({ movieId, rating, reviewText });
+  } catch (error) {
+    console.error("Error adding review:", error);
+    throw error;
+  }
+};
+
+// Delete a review from a movie
+export const handleDeleteReview = async (movieId: string): Promise<void> => {
+  try {
+    await deleteReview({ movieId });
+  } catch (error) {
+    console.error("Error deleting review:", error);
+    throw error;
+  }
+};
+
+// Check if the movie is favorited by the user
+export const handleGetIfFavoritedMovie = async (
+  movieId: string
+): Promise<boolean> => {
+  try {
+    const response = await getIfFavoritedMovie({ movieId });
+    return !!response.data.favorite_movie;
+  } catch (error) {
+    console.error("Error checking if movie is favorited:", error);
+    return false;
+  }
+};
+
+// Function to perform the search using the query and filters
+export const handleSearchAll = async (
+  searchQuery: string,
+  minYear: number,
+  maxYear: number,
+  minRating: number,
+  maxRating: number,
+  genre: string
+): Promise<SearchAllData | null> => {
+  try {
+    const response = await searchAll({
+      input: searchQuery,
+      minYear,
+      maxYear,
+      minRating,
+      maxRating,
+      genre,
+    });
+
+    return response.data;
+  } catch (error) {
+    console.error("Error performing search:", error);
+    return null;
+  }
+};
+
+// Perform vector-based search for movies based on description
+export const searchMoviesByDescription = async (
+  query: string
+): Promise<
+  | SearchMovieDescriptionUsingL2similarityData["movies_descriptionEmbedding_similarity"]
+  | null
+> => {
+  try {
+    const response = await searchMovieDescriptionUsingL2similarity({ query });
+    return response.data.movies_descriptionEmbedding_similarity;
+  } catch (error) {
+    console.error("Error fetching movie descriptions:", error);
+    return null;
+  }
+};
+
+export const fetchSimilarMovies = async (
+  description: string
+): Promise<
+  | SearchMovieDescriptionUsingL2similarityData["movies_descriptionEmbedding_similarity"]
+  | null
+> => {
+  try {
+    const response = await searchMovieDescriptionUsingL2similarity({
+      query: description,
+    });
+    return response?.data?.movies_descriptionEmbedding_similarity;
+  } catch (error) {
+    console.error("Error fetching similar movies:", error);
+  }
+};
diff --git a/dataconnect/app/src/lib/firebase.tsx b/dataconnect/app/src/lib/firebase.tsx
index 749efd1ba..cfd3bce13 100644
--- a/dataconnect/app/src/lib/firebase.tsx
+++ b/dataconnect/app/src/lib/firebase.tsx
@@ -1,38 +1,36 @@
-import { initializeApp, getApps } from 'firebase/app';
-import { getAuth } from 'firebase/auth';
-import { createContext } from 'react';
+import { initializeApp, getApps } from "firebase/app";
+import { connectAuthEmulator, getAuth } from "firebase/auth";
+import {
+  connectDataConnectEmulator,
+  getDataConnect,
+} from "firebase/data-connect";
+import { connectorConfig } from '@movie/dataconnect';
+import { createContext } from "react";
 
 const firebaseConfig = {
-  apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
-  authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
-  projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
-  storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
-  messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
-  appId: import.meta.env.VITE_FIREBASE_APP_ID,
+  apiKey: "API_KEY",
+  authDomain: "PROJECT_ID.firebaseapp.com",
+  projectId: "PROJECT_ID",
+  storageBucket: "PROJECT_ID.appspot.com",
+  messagingSenderId: "SENDER_ID",
+  appId: "APP_ID"
 };
 
-const firebaseApp = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
+const firebaseApp =
+  getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
 
 const auth = getAuth(firebaseApp);
+const dataconnect = getDataConnect(firebaseApp, connectorConfig);
 
-if (process.env.NODE_ENV === 'development') {
-  // connectDataConnectEmulator(
-  //   dataconnect, 
-  //   'localhost', 
-  //   9399, 
-  //   false
-  // );
-  // connectAuthEmulator(auth, "http://localhost:9099");
+if (process.env.NODE_ENV === "development") {
+  connectDataConnectEmulator(dataconnect, "127.0.0.1", 9399, false);
+  connectAuthEmulator(auth, "http://localhost:9099");
 }
 
 const AuthContext = createContext(auth);
 
 function AuthProvider({ children }: { children: React.ReactNode }) {
-  return (
-    <AuthContext.Provider value={auth}>
-      {children}
-    </AuthContext.Provider>
-  );
+  return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>;
 }
 
 export { AuthContext, AuthProvider };
diff --git a/dataconnect/app/src/pages/Actor.tsx b/dataconnect/app/src/pages/Actor.tsx
index d74247fc2..2d035acbf 100644
--- a/dataconnect/app/src/pages/Actor.tsx
+++ b/dataconnect/app/src/pages/Actor.tsx
@@ -1,40 +1,24 @@
 import React, { useContext, useEffect, useState } from 'react';
 import { useParams, Link, useNavigate } from 'react-router-dom';
-import { MdFavorite, MdFavoriteBorder } from 'react-icons/md';
-import {
-  getActorById,
-  GetActorByIdResponse,
-  addFavoritedActor,
-  deleteFavoritedActor,
-  getIfFavoritedActor
-} from '@movie/dataconnect';
 import { onAuthStateChanged, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
 import NotFound from './NotFound';
+import { handleGetActorById } from '@/lib/MovieService';
 
 export default function ActorPage() {
+  const navigate = useNavigate();
+  const auth = useContext(AuthContext);
+  const [loading, setLoading] = useState(true);
   const { id } = useParams<{ id: string }>();
   const actorId = id || '';
-  const [actor, setActor] = useState<GetActorByIdResponse['actor'] | null>(null);
-  const [loading, setLoading] = useState(true);
-  const [authUser, setAuthUser] = useState<User | null>(null);
-  const [isFavorited, setIsFavorited] = useState(false);
-  const auth = useContext(AuthContext);
-  const navigate = useNavigate();
+  const [, setAuthUser] = useState<User | null>(null);
+
+  const [actor, setActor] = useState(null);
 
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
-      async function checkIfFavorited() {
-        try {
-          const response = await getIfFavoritedActor({ actorId });
-          setIsFavorited(!!response.data.favorite_actor);
-        } catch (error) {
-          console.error('Error checking if favorited:', error);
-        }
-      }
       if (user) {
         setAuthUser(user);
-        checkIfFavorited();
       }
     });
 
@@ -44,39 +28,19 @@ export default function ActorPage() {
   useEffect(() => {
     if (actorId) {
       const fetchActor = async () => {
-        try {
-          const response = await getActorById({ id: actorId });
-          if (response.data.actor) {
-            setActor(response.data.actor);
-          } else {
-            navigate('/not-found');
-          }
-        } catch (error) {
-          console.error('Error fetching actor:', error);
+        const actorData = await handleGetActorById(actorId);
+        if (actorData) {
+          setActor(actorData);
+        } else {
           navigate('/not-found');
-        } finally {
-          setLoading(false);
         }
+        setLoading(false);
       };
 
       fetchActor();
     }
   }, [actorId, navigate]);
 
-  async function handleFavoriteToggle() {
-    if (!authUser) return;
-    try {
-      if (isFavorited) {
-        await deleteFavoritedActor({ actorId });
-      } else {
-        await addFavoritedActor({ actorId });
-      }
-      setIsFavorited(!isFavorited);
-    } catch (error) {
-      console.error('Error updating favorite status:', error);
-    }
-  }
-
   if (loading) return <p>Loading...</p>;
 
   return actor ? (
@@ -85,15 +49,6 @@ export default function ActorPage() {
         <img className="w-full md:w-1/3 object-cover rounded-lg shadow-md" src={actor.imageUrl} alt={actor.name} />
         <div className="md:ml-8 mt-4 md:mt-0 flex-1">
           <h1 className="text-5xl font-bold mb-2">{actor.name}</h1>
-          <div className="mt-4 flex space-x-4">
-            <button
-              className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
-              aria-label="Favorite"
-              onClick={handleFavoriteToggle}
-            >
-              {isFavorited ? <MdFavorite size={24} /> : <MdFavoriteBorder size={24} />}
-            </button>
-          </div>
         </div>
       </div>
 
diff --git a/dataconnect/app/src/pages/AdvancedSearch.tsx b/dataconnect/app/src/pages/AdvancedSearch.tsx
index 102664935..938230f9f 100644
--- a/dataconnect/app/src/pages/AdvancedSearch.tsx
+++ b/dataconnect/app/src/pages/AdvancedSearch.tsx
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
 import { Link } from 'react-router-dom';
 import { FaSearch } from 'react-icons/fa';
 import { MdStar } from 'react-icons/md';
-import { searchAll } from '@movie/dataconnect';
+import { handleSearchAll } from '@/lib/MovieService';
 
 const genres = ['', 'action', 'crime', 'drama', 'sci-fi', 'thriller', 'adventure'];
 
@@ -18,27 +18,23 @@ export default function AdvancedSearchPage() {
     reviews: [],
   });
 
-  async function handleSearch(e: React.FormEvent<HTMLFormElement>) {
+  const handleSearch = async (e: React.FormEvent<HTMLFormElement>) => {
     e.preventDefault();
-    try {
-      const response = await searchAll({
-        input: searchQuery,
-        minYear: releaseYearRange.min,
-        maxYear: releaseYearRange.max,
-        minRating: ratingRange.min,
-        maxRating: ratingRange.max,
-        genre,
-      });
-      setResults({
-        moviesMatchingTitle: response.data.moviesMatchingTitle,
-        moviesMatchingDescription: response.data.moviesMatchingDescription,
-        actors: response.data.actorsMatchingName,
-        reviews: response.data.reviewsMatchingText,
-      });
-    } catch (error) {
-      console.error('Error fetching search results:', error);
-    }
-  }
+    const searchResults = await handleSearchAll(
+      searchQuery,
+      releaseYearRange.min,
+      releaseYearRange.max,
+      ratingRange.min,
+      ratingRange.max,
+      genre
+    );
+    setResults({
+      moviesMatchingTitle: searchResults?.moviesMatchingTitle,
+      moviesMatchingDescription: searchResults?.moviesMatchingDescription,
+      actors: searchResults?.actorsMatchingName,
+      reviews: searchResults?.reviewsMatchingText,
+    });
+  };
 
   return (
     <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
diff --git a/dataconnect/app/src/pages/Genre.tsx b/dataconnect/app/src/pages/Genre.tsx
deleted file mode 100644
index 4c0b067c9..000000000
--- a/dataconnect/app/src/pages/Genre.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useParams } from 'react-router-dom';
-import MovieCard from '@/components/moviecard';
-import { ListMoviesByGenreResponse, listMoviesByGenre } from '@movie/dataconnect';
-
-export default function GenrePage() {
-  const { genre } = useParams<{ genre: string }>();
-  const [mostPopular, setMostPopular] = useState<ListMoviesByGenreResponse['mostPopular']>([]);
-  const [mostRecent, setMostRecent] = useState<ListMoviesByGenreResponse['mostRecent']>([]);
-  const [loading, setLoading] = useState(true);
-
-  useEffect(() => {
-    async function fetchMovies() {
-      try {
-        const response = await listMoviesByGenre({ genre });
-        setMostPopular(response.data.mostPopular);
-        setMostRecent(response.data.mostRecent);
-      } catch (error) {
-        console.error('Error fetching movies:', error);
-      } finally {
-        setLoading(false);
-      }
-    }
-
-    fetchMovies();
-  }, [genre]);
-
-  if (loading) return <p>Loading...</p>;
-
-  return (
-    <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
-      <h1 className="text-3xl font-bold mb-4 capitalize">{genre} Movies</h1>
-
-      <section className="mb-8">
-        <h2 className="text-2xl font-bold mb-4">Most Popular</h2>
-        <div className="flex overflow-x-auto space-x-4">
-          {mostPopular.map((movie) => (
-            <MovieCard
-              key={movie.id}
-              id={movie.id}
-              title={movie.title}
-              imageUrl={movie.imageUrl}
-              rating={movie.rating}
-              tags={movie.tags}
-            />
-          ))}
-        </div>
-      </section>
-
-      <section>
-        <h2 className="text-2xl font-bold mb-4">Most Recent</h2>
-        <div className="flex overflow-x-auto space-x-4">
-          {mostRecent.map((movie) => (
-            <MovieCard
-              key={movie.id}
-              id={movie.id}
-              title={movie.title}
-              imageUrl={movie.imageUrl}
-              rating={movie.rating}
-              tags={movie.tags}
-            />
-          ))}
-        </div>
-      </section>
-    </div>
-  );
-}
diff --git a/dataconnect/app/src/pages/Home.tsx b/dataconnect/app/src/pages/Home.tsx
index 302da28c7..dbc1f2873 100644
--- a/dataconnect/app/src/pages/Home.tsx
+++ b/dataconnect/app/src/pages/Home.tsx
@@ -1,22 +1,18 @@
 import React, { useEffect, useState } from 'react';
 import Carousel from '@/components/carousel';
-import { listMovies, ListMoviesResponse } from '@movie/dataconnect';
+import { handleGetTopMovies, handleGetLatestMovies } from '@/lib/MovieService';
 
 export default function HomePage() {
-  const [topMovies, setTopMovies] = useState<ListMoviesResponse["movies"]>([]);
-  const [latestMovies, setLatestMovies] = useState<ListMoviesResponse["movies"]>([]);
+  const [topMovies, setTopMovies] = useState([]);
+  const [latestMovies, setLatestMovies] = useState([]);
 
   useEffect(() => {
     async function fetchMovies() {
-      try {
-        const topMoviesResponse = await listMovies({ orderByRating: "DESC", limit: 10 });
-        const latestMoviesResponse = await listMovies({ orderByReleaseYear: "DESC", limit: 10 });
+      const topMoviesData = await handleGetTopMovies(10);
+      const latestMoviesData = await handleGetLatestMovies(10);
 
-        setTopMovies(topMoviesResponse.data.movies);
-        setLatestMovies(latestMoviesResponse.data.movies);
-      } catch (error) {
-        console.error("Error fetching movies:", error);
-      }
+      if (topMoviesData) setTopMovies(topMoviesData);
+      if (latestMoviesData) setLatestMovies(latestMoviesData);
     }
 
     fetchMovies();
diff --git a/dataconnect/app/src/pages/Movie.tsx b/dataconnect/app/src/pages/Movie.tsx
index 2684cb002..fd78bb256 100644
--- a/dataconnect/app/src/pages/Movie.tsx
+++ b/dataconnect/app/src/pages/Movie.tsx
@@ -1,123 +1,120 @@
-import { useContext, useEffect, useState } from 'react';
-import { useParams, Link } from 'react-router-dom';
-import { MdFavorite, MdFavoriteBorder, MdStar } from 'react-icons/md';
+import { useContext, useEffect, useState } from "react";
+import { useParams, Link } from "react-router-dom";
+import { MdFavorite, MdFavoriteBorder, MdStar } from "react-icons/md";
+import { onAuthStateChanged, User } from "firebase/auth";
+import { AuthContext } from "@/lib/firebase";
+import NotFound from "./NotFound";
 import {
-  getMovieById,
-  GetMovieByIdResponse,
-  addFavoritedMovie,
-  deleteFavoritedMovie,
-  getIfFavoritedMovie,
-  addReview,
-  deleteReview,
-  searchMovieDescriptionUsingL2similarity,
-  SearchMovieDescriptionUsingL2similarityResponse,
-} from '@movie/dataconnect';
-import { onAuthStateChanged, User } from 'firebase/auth';
-import { AuthContext } from '@/lib/firebase';
-import NotFound from './NotFound';
+  handleGetMovieById,
+  handleGetIfFavoritedMovie,
+  handleAddFavoritedMovie,
+  handleDeleteFavoritedMovie,
+  handleAddReview,
+  handleDeleteReview,
+  fetchSimilarMovies,
+} from "@/lib/MovieService";
+import MovieCard from "@/components/moviecard";
 
 export default function MoviePage() {
   const { id } = useParams() as { id: string };
-  const [movie, setMovie] = useState<GetMovieByIdResponse['movie'] | null>(null);
+  const auth = useContext(AuthContext);
+
   const [loading, setLoading] = useState(true);
   const [authUser, setAuthUser] = useState<User | null>(null);
   const [isFavorited, setIsFavorited] = useState(false);
-  const [reviewText, setReviewText] = useState('');
-  const [userReview, setUserReview] = useState<GetMovieByIdResponse['movie']['reviews'][0] | null>(null);
-  const [rating, setRating] = useState(0);
-  const [similarMovies, setSimilarMovies] = useState<SearchMovieDescriptionUsingL2similarityResponse['movies_descriptionEmbedding_similarity']>([]);
-  const auth = useContext(AuthContext);
+  const [reviewText, setReviewText] = useState("");
+  const [rating, setRating] = useState(1);
 
+  const [movie, setMovie] = useState(null);
+  const [userReview, setUserReview] = useState(null);
+  const [similarMovies, setSimilarMovies] = useState([]);
+
+  // Fetch the movie details and check if it's favorited when the user is authenticated
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
-      async function checkIfFavorited() {
-        try {
-          const response = await getIfFavoritedMovie({ movieId: id });
-          setIsFavorited(!!response.data.favorite_movie);
-        } catch (error) {
-          console.error('Error checking if favorited:', error);
-        }
-      }
       if (user) {
         setAuthUser(user);
-        checkIfFavorited();
+        handleGetIfFavoritedMovie(id).then(setIsFavorited);
       }
     });
 
     return () => unsubscribe();
   }, [id, auth]);
 
+  // Fetch movie details and the user's review
   useEffect(() => {
-    async function fetchSimilarMovies(description: string) {
-      try {
-        const response = await searchMovieDescriptionUsingL2similarity({ query: description });
-        setSimilarMovies(response?.data?.movies_descriptionEmbedding_similarity);
-      } catch (error) {
-        console.error('Error fetching similar movies:', error);
-      }
-    }
     if (id) {
-      const fetchMovie = async () => {
-        try {
-          const response = await getMovieById({ id });
-          setMovie(response.data.movie);
-          const userReview = response.data.movie.reviews.find(review => review.user.id === authUser?.uid);
+      handleGetMovieById(id).then((movieData) => {
+        setMovie(movieData);
+        if (movieData?.reviews) {
+          const userReview = movieData.reviews.find(
+            (review) => review.user.id === authUser?.uid
+          );
+          fetchSimilarMovies(movieData.description).then((similarMovies) => {
+            const similarResults = similarMovies?.filter(
+              (movie) => movie.id !== movieData.id
+            );
+            setSimilarMovies(
+              similarResults && similarResults.length > 1 ? similarResults : []
+            );
+            setMovie(movieData);
+          });
           setUserReview(userReview || null);
-          await fetchSimilarMovies(response.data.movie.description);
-        } catch (error) {
-          console.error('Error fetching movie:', error);
-        } finally {
-          setLoading(false);
         }
-      };
-
-      fetchMovie();
+        setLoading(false);
+      });
     }
   }, [id, authUser]);
 
-  async function handleFavoriteToggle(e: React.MouseEvent) {
+  // Toggle favorite status for the movie
+  const handleFavoriteToggle = async (e: React.MouseEvent) => {
     e.stopPropagation();
     e.preventDefault();
     if (!authUser) return;
+
     try {
       if (isFavorited) {
-        await deleteFavoritedMovie({ movieId: id });
+        await handleDeleteFavoritedMovie(id);
       } else {
-        await addFavoritedMovie({ movieId: id });
+        await handleAddFavoritedMovie(id);
       }
       setIsFavorited(!isFavorited);
     } catch (error) {
-      console.error('Error updating favorite status:', error);
+      console.error("Error updating favorite status:", error);
     }
-  }
+  };
 
-  async function handleReviewSubmit(e: React.FormEvent) {
+  // Submit a new review
+  const handleReviewSubmit = async (e: React.FormEvent) => {
     e.preventDefault();
     if (!authUser) return;
+
     try {
-      await addReview({ movieId: id, rating, reviewText });
-      setReviewText('');
+      await handleAddReview(id, rating, reviewText);
+      setReviewText("");
       setRating(0);
-      const updatedMovie = await getMovieById({ id });
-      setMovie(updatedMovie.data.movie);
+      const updatedMovie = await handleGetMovieById(id);
+      setMovie(updatedMovie);
     } catch (error) {
-      console.error('Error adding review:', error);
+      console.error("Error submitting review:", error);
     }
-  }
+  };
 
-  async function handleReviewDelete(e: React.MouseEvent) {
+  // Delete the user's review
+  const handleReviewDelete = async (e: React.MouseEvent) => {
     e.stopPropagation();
     e.preventDefault();
     if (!authUser || !userReview) return;
+
     try {
-      await deleteReview({ movieId: id });
+      await handleDeleteReview(id);
       setUserReview(null);
-      const updatedMovie = await getMovieById({ id });
-      setMovie(updatedMovie.data.movie);
+      const updatedMovie = await handleGetMovieById(id);
+      setMovie(updatedMovie);
     } catch (error) {
-      console.error('Error deleting review:', error);
+      console.error("Error deleting review:", error);
     }
-  }
+  };
 
   if (loading) return <p>Loading...</p>;
   if (!movie) return <NotFound />;
@@ -125,19 +122,35 @@ export default function MoviePage() {
   return (
     <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
       <div className="flex flex-col md:flex-row mb-8">
-        <img className="w-full md:w-1/3 object-cover rounded-lg shadow-md" src={movie.imageUrl} alt={movie.title} />
+        <img
+          className="w-full md:w-1/3 object-cover rounded-lg shadow-md"
+          src={movie.imageUrl}
+          alt={movie.title}
+        />
         <div className="md:ml-8 mt-4 md:mt-0 flex-1">
           <h1 className="text-5xl font-bold mb-2">{movie.title}</h1>
           <div className="flex items-center text-yellow-500 mb-4">
             <MdStar className="text-yellow-500" size={24} />
             <span className="ml-1 text-gray-400 text-lg">{movie.rating}</span>
           </div>
-          <p className="text-lg mb-4 p-4 bg-gray-800 rounded-lg">{movie.description}</p>
+          <p className="text-lg mb-4 p-4 bg-gray-800 rounded-lg">
+            {movie.description}
+          </p>
           <div className="text-sm space-y-2">
-            <p><span className="font-bold">Genre:</span> {movie.genre}</p>
-            <p><span className="font-bold">Release Year:</span> {movie.releaseYear}</p>
-            <p><span className="font-bold">Director:</span> {movie.metadata[0]?.director}</p>
-            <p><span className="font-bold">Tags:</span> {movie.tags?.join(', ')}</p>
+            <p>
+              <span className="font-bold">Genre:</span> {movie.genre}
+            </p>
+            <p>
+              <span className="font-bold">Release Year:</span>{" "}
+              {movie.releaseYear}
+            </p>
+            <p>
+              <span className="font-bold">Director:</span>{" "}
+              {movie.metadata[0]?.director}
+            </p>
+            <p>
+              <span className="font-bold">Tags:</span> {movie.tags?.join(", ")}
+            </p>
           </div>
           <div className="mt-4 flex space-x-4">
             <button
@@ -145,7 +158,11 @@ export default function MoviePage() {
               aria-label="Favorite"
               onClick={handleFavoriteToggle}
             >
-              {isFavorited ? <MdFavorite size={24} /> : <MdFavoriteBorder size={24} />}
+              {isFavorited ? (
+                <MdFavorite size={24} />
+              ) : (
+                <MdFavoriteBorder size={24} />
+              )}
             </button>
           </div>
         </div>
@@ -157,7 +174,11 @@ export default function MoviePage() {
           {movie.mainActors.map((actor) => (
             <Link key={actor.id} to={`/actor/${actor.id}`}>
               <div className="flex-shrink-0 bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer w-32">
-                <img className="w-full h-32 object-cover" src={actor.imageUrl} alt={actor.name} />
+                <img
+                  className="w-full h-32 object-cover"
+                  src={actor.imageUrl}
+                  alt={actor.name}
+                />
                 <div className="p-2 text-center">
                   <h3 className="font-bold text-sm text-white">{actor.name}</h3>
                 </div>
@@ -173,7 +194,11 @@ export default function MoviePage() {
           {movie.supportingActors.map((actor) => (
             <Link key={actor.id} to={`/actor/${actor.id}`}>
               <div className="flex-shrink-0 bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer w-32">
-                <img className="w-full h-32 object-cover" src={actor.imageUrl} alt={actor.name} />
+                <img
+                  className="w-full h-32 object-cover"
+                  src={actor.imageUrl}
+                  alt={actor.name}
+                />
                 <div className="p-2 text-center">
                   <h3 className="font-bold text-sm text-white">{actor.name}</h3>
                 </div>
@@ -186,7 +211,10 @@ export default function MoviePage() {
       <div className="mt-8">
         <h2 className="text-2xl font-bold mb-2">User Reviews</h2>
         {!userReview ? (
-          <form onSubmit={handleReviewSubmit} className="mb-4 p-4 bg-gray-800 rounded-lg shadow-md">
+          <form
+            onSubmit={handleReviewSubmit}
+            className="mb-4 p-4 bg-gray-800 rounded-lg shadow-md"
+          >
             <h3 className="text-xl font-bold mb-2">Leave a Review</h3>
             <textarea
               className="w-full p-2 rounded-lg bg-gray-700 text-white mb-2"
@@ -215,7 +243,10 @@ export default function MoviePage() {
         ) : null}
 
         {movie.reviews.map((review) => (
-          <div key={review.id} className="mb-4 p-4 bg-gray-800 rounded-lg shadow-md">
+          <div
+            key={review.id}
+            className="mb-4 p-4 bg-gray-800 rounded-lg shadow-md"
+          >
             <p className="font-bold">{review.user.username}</p>
             <p className="text-sm">{review.reviewDate}</p>
             <p className="mt-2">{review.reviewText}</p>
@@ -233,43 +264,23 @@ export default function MoviePage() {
             )}
           </div>
         ))}
-      </div>
-
-      <div className="mt-8">
-        <h2 className="text-2xl font-bold mb-2">Similar Movies</h2>
-        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
-          {similarMovies.map((similarMovie) => (
-            <div key={similarMovie.id} className="bg-gray-800 rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative">
-              <Link to={`/movie/${similarMovie.id}`}>
-                <img className="w-full h-64 object-cover" src={similarMovie.imageUrl} alt={similarMovie.title} />
-              </Link>
-              <div className="p-4">
-                <h3 className="font-bold text-lg mb-1 text-white">{similarMovie.title}</h3>
-                <p className="text-sm text-gray-300 overflow-y-scroll max-h-12">{similarMovie.description}</p>
-                <div className="flex items-center text-yellow-500 mt-2">
-                  <MdStar className="text-yellow-500" size={20} />
-                  <span className="ml-1 text-gray-400">{similarMovie.rating}</span>
-                </div>
-                <div className="flex flex-wrap gap-1 mt-2">
-                  {similarMovie.tags?.map((tag, index) => (
-                    <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs capitalize">{tag}</span>
-                  ))}
-                </div>
-                {authUser && (
-                  <div className="mt-2 flex space-x-2 items-center">
-                    <button
-                      className="flex items-center justify-center p-1 text-red-500 hover:text-red-600 transition-colors duration-200"
-                      aria-label="Favorite"
-                      onClick={handleFavoriteToggle}
-                    >
-                      {isFavorited ? <MdFavorite size={20} /> : <MdFavoriteBorder size={20} />}
-                    </button>
-                  </div>
-                )}
-              </div>
+        {similarMovies && similarMovies.length > 1 ? (
+          <div className="my-10">
+            <h2 className="text-2xl font-bold mb-2">Similar Movies</h2>
+            <div className="grid grid-cols-4 gap-2">
+              {similarMovies.map((similarMovie) => (
+                <MovieCard
+                  id={similarMovie.id}
+                  title={similarMovie.title || "TBA"}
+                  imageUrl={similarMovie.imageUrl}
+                  rating={similarMovie.rating}
+                  genre={similarMovie.genre}
+                  tags={similarMovie.tags}
+                />
+              ))}
             </div>
-          ))}
-        </div>
+          </div>
+        ) : null}
       </div>
     </div>
   );
diff --git a/dataconnect/app/src/pages/MyProfile.tsx b/dataconnect/app/src/pages/MyProfile.tsx
index 6bfd06427..9607af626 100644
--- a/dataconnect/app/src/pages/MyProfile.tsx
+++ b/dataconnect/app/src/pages/MyProfile.tsx
@@ -1,74 +1,50 @@
-import React, { useContext, useEffect, useState } from 'react';
-import { useNavigate, Link } from 'react-router-dom';
-import { onAuthStateChanged, User } from 'firebase/auth';
-import {
-  getCurrentUser,
-  GetCurrentUserResponse,
-  deleteReview,
-  deleteFavoritedMovie,
-  deleteFavoritedActor,
-} from '@movie/dataconnect';
-import { MdStar } from 'react-icons/md';
-import { AuthContext } from '@/lib/firebase';
+import React, { useContext, useEffect, useState } from "react";
+import { useNavigate } from "react-router-dom";
+import { onAuthStateChanged, User } from "firebase/auth";
+import { handleGetCurrentUser, handleDeleteReview } from "@/lib/MovieService";
+import { MdStar } from "react-icons/md";
+import { AuthContext } from "@/lib/firebase";
+import MovieCard from "@/components/moviecard";
 
 export default function MyProfilePage() {
   const navigate = useNavigate();
   const [authUser, setAuthUser] = useState<User | null>(null);
-  const [user, setUser] = useState<GetCurrentUserResponse['user'] | null>(null);
   const [loading, setLoading] = useState(true);
   const auth = useContext(AuthContext);
 
+  const [user, setUser] = useState(null);
+
   useEffect(() => {
     const unsubscribe = onAuthStateChanged(auth, (user) => {
       if (user) {
         setAuthUser(user);
-        fetchUserProfile();
+        loadUserProfile();
       } else {
-        navigate('/');
+        navigate("/");
       }
     });
 
     return () => unsubscribe();
   }, [navigate, auth]);
 
-  async function fetchUserProfile() {
+  async function loadUserProfile() {
     try {
-      const response = await getCurrentUser();
-      setUser(response.data.user);
+      const userProfile = await handleGetCurrentUser();
+      setUser(userProfile);
     } catch (error) {
-      console.error('Error fetching user:', error);
+      console.error("Error loading user profile:", error);
     } finally {
       setLoading(false);
     }
   }
 
-  async function handleDeleteReview(reviewId: string) {
-    if (!authUser) return;
-    try {
-      await deleteReview({ movieId: reviewId });
-      fetchUserProfile();
-    } catch (error) {
-      console.error('Error deleting review:', error);
-    }
-  }
-
-  async function handleUnfavoriteMovie(movieId: string) {
-    if (!authUser) return;
-    try {
-      await deleteFavoritedMovie({ movieId });
-      fetchUserProfile();
-    } catch (error) {
-      console.error('Error unfavoriting movie:', error);
-    }
-  }
-
-  async function handleUnfavoriteActor(actorId: string) {
+  async function deleteReview(reviewMovieId: string) {
     if (!authUser) return;
     try {
-      await deleteFavoritedActor({ actorId });
-      fetchUserProfile();
+      await handleDeleteReview(reviewMovieId);
+      loadUserProfile();
     } catch (error) {
-      console.error('Error unfavoriting actor:', error);
+      console.error("Error deleting review:", error);
     }
   }
 
@@ -78,15 +54,22 @@ export default function MyProfilePage() {
   return (
     <div className="container mx-auto p-4 bg-gray-900 min-h-screen text-white">
       <div className="mb-8">
-        <h1 className="text-5xl font-bold mb-4">Welcome back, {user.username}</h1>
+        <h1 className="text-5xl font-bold mb-4">
+          Welcome back, {user.username}
+        </h1>
       </div>
 
       <div className="mt-8">
         <h2 className="text-2xl font-bold mb-2">Reviews</h2>
         <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
           {user.reviews.map((review) => (
-            <div key={review.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md p-4 relative max-h-72">
-              <h3 className="font-bold text-lg mb-1 text-white">{review.movie.title}</h3>
+            <div
+              key={review.id}
+              className="bg-gray-800 rounded-lg overflow-scroll shadow-md p-4 relative max-h-72"
+            >
+              <h3 className="font-bold text-lg mb-1 text-white">
+                {review.movie.title}
+              </h3>
               <div className="flex items-center text-yellow-500 mb-2">
                 <MdStar className="text-yellow-500" size={24} />
                 <span className="ml-1 text-gray-400">{review.rating}</span>
@@ -94,7 +77,7 @@ export default function MyProfilePage() {
               <p className="text-sm text-gray-400 mb-2">{review.reviewDate}</p>
               <p className="text-sm text-gray-300">{review.reviewText}</p>
               <button
-                onClick={() => handleDeleteReview(review.id)}
+                onClick={() => deleteReview(review.movie.id)}
                 className="absolute bottom-2 right-2 text-red-500 hover:text-red-600"
               >
                 Delete Review
@@ -105,55 +88,19 @@ export default function MyProfilePage() {
       </div>
 
       <div className="mt-8">
-        <h2 className="text-2xl font-bold mb-2">Favorite Movies</h2>
-        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
+        <h2 className="text-2xl font-bold mb-4">Favorite Movies</h2>
+        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">
           {user.favoriteMovies.map((fav) => (
-            <div key={fav.movie.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative max-h-80">
-              <Link to={`/movie/${fav.movie.id}`}>
-                <img className="w-full h-64 object-cover" src={fav.movie.imageUrl} alt={fav.movie.title} />
-              </Link>
-              <div className="p-4">
-                <h3 className="font-bold text-lg mb-1 text-white">{fav.movie.title}</h3>
-                <p className="text-sm text-gray-400 capitalize">{fav.movie.genre}</p>
-                <p className="text-sm text-gray-300 overflow-y-scroll max-h-24">{fav.movie.description}</p>
-                <div className="flex items-center text-yellow-500 mt-2">
-                  <MdStar className="text-yellow-500" size={24} />
-                  <span className="ml-1 text-gray-400">{fav.movie.rating}</span>
-                </div>
-                <div className="flex flex-wrap gap-1 mt-2">
-                  {fav.movie.tags?.map((tag, index) => (
-                    <span key={index} className="bg-gray-700 text-white px-2 py-1 rounded-full text-xs capitalize">{tag}</span>
-                  ))}
-                </div>
-              </div>
-              <button
-                onClick={() => handleUnfavoriteMovie(fav.movie.id)}
-                className="absolute bottom-2 right-2 text-red-500 hover:text-red-600"
-              >
-                Remove Favorite
-              </button>
-            </div>
-          ))}
-        </div>
-      </div>
-
-      <div className="mt-8">
-        <h2 className="text-2xl font-bold mb-2">Favorite Actors</h2>
-        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
-          {user.favoriteActors.map((favActor) => (
-            <div key={favActor.actor.id} className="bg-gray-800 rounded-lg overflow-scroll shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer relative max-h-80">
-              <Link to={`/actor/${favActor.actor.id}`}>
-                <img className="w-48 h-48 object-cover rounded-full mx-auto mt-4" src={favActor.actor.imageUrl} alt={favActor.actor.name} />
-              </Link>
-              <div className="p-4 text-center">
-                <h3 className="font-bold text-lg mb-1 text-white">{favActor.actor.name}</h3>
-              </div>
-              <button
-                onClick={() => handleUnfavoriteActor(favActor.actor.id)}
-                className="absolute bottom-2 right-2 text-red-500 hover:text-red-600"
-              >
-                Remove Favorite
-              </button>
+            <div className="m-4">
+              <MovieCard
+                key={fav.movie.id}
+                id={fav.movie.id}
+                title={fav.movie.title || "TBA"}
+                imageUrl={fav.movie.imageUrl}
+                rating={fav.movie.rating}
+                genre={fav.movie.genre}
+                tags={fav.movie.tags}
+              />
             </div>
           ))}
         </div>
diff --git a/dataconnect/app/src/pages/VectorSearch.tsx b/dataconnect/app/src/pages/VectorSearch.tsx
index fa99f1aee..bd202ea99 100644
--- a/dataconnect/app/src/pages/VectorSearch.tsx
+++ b/dataconnect/app/src/pages/VectorSearch.tsx
@@ -1,18 +1,21 @@
 import React, { useState } from 'react';
-import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityResponse } from '@movie/dataconnect';
+import { searchMoviesByDescription } from '@/lib/MovieService';
 import { FaSpinner } from 'react-icons/fa';
 
 export default function VectorSearchPage() {
   const [query, setQuery] = useState('');
   const [loading, setLoading] = useState(false);
-  const [results, setResults] = useState<SearchMovieDescriptionUsingL2similarityResponse['movies_descriptionEmbedding_similarity']>([]);
+
+  const [results, setResults] = useState([]);
 
   async function handleSearch(e: React.FormEvent<HTMLFormElement>) {
     e.preventDefault();
     setLoading(true);
     try {
-      const response = await searchMovieDescriptionUsingL2similarity({ query });
-      setResults(response.data.movies_descriptionEmbedding_similarity);
+      const searchResults = await searchMoviesByDescription(query);
+      if (searchResults) {
+        setResults(searchResults);
+      }
     } catch (error) {
       console.error('Error fetching movie descriptions:', error);
     } finally {
@@ -36,7 +39,7 @@ export default function VectorSearchPage() {
           />
           <button
             type="submit"
-            className="ml-2 p-4 rounded bg-blue-600 text-white hover:bg-blue-700 transition-colors"
+            className="ml-2 p-4 rounded bg-slate-600 text-white hover:bg-slate-700 transition-colors"
           >
             Search
           </button>
diff --git a/dataconnect/app/tailwind.config.js b/dataconnect/app/tailwind.config.js
index 129cf61a5..e98279b9a 100644
--- a/dataconnect/app/tailwind.config.js
+++ b/dataconnect/app/tailwind.config.js
@@ -8,7 +8,11 @@ export default {
   ],
   darkMode: 'class',
   theme: {
-    extend: {},
+    extend: {
+      fontFamily: {
+        sans: ['"Google Sans"', 'sans-serif'],
+      },
+    },
   },
   plugins: [],
 }
diff --git a/dataconnect/dataconnect/.DS_Store b/dataconnect/dataconnect/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..76a420f7adc7356ab1806f02dbde16a116421d11
GIT binary patch
diff --git a/dataconnect/dataconnect/1_movie_insert.gql b/dataconnect/dataconnect/1_movie_insert.gql
deleted file mode 100644
index b8a9f8cef..000000000
--- a/dataconnect/dataconnect/1_movie_insert.gql
+++ /dev/null
@@ -1,204 +0,0 @@
-mutation {
-  movie_insertMany(data: [
-    {
-      id: "550e8400-e29b-41d4-a716-446655440000",
-      title: "Inception",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Finception.jpg?alt=media&token=07b09781-b302-4623-a5c3-1956d0143168",
-      releaseYear: 2010,
-      genre: "sci-fi",
-      rating: 8.8,
-      description: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move.",
-      tags: ["thriller", "action"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440001",
-      title: "The Matrix",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_matrix.jpg?alt=media&token=4975645d-fef8-409e-84a5-bcc1046e2059",
-      releaseYear: 1999,
-      genre: "action",
-      rating: 8.7,
-      description: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny.",
-      tags: ["sci-fi", "adventure"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440002",
-      title: "John Wick 4",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fjohn_wick_4.jpg?alt=media&token=463ed467-9daa-4281-965d-44e7cc4172d5",
-      releaseYear: 2023,
-      genre: "action",
-      rating: 8.1,
-      description: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances.",
-      tags: ["action", "thriller"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440003",
-      title: "The Dark Knight",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_dark_knight.jpg?alt=media&token=a9803c59-40d5-4758-a6f4-9a7c274a1218",
-      releaseYear: 2008,
-      genre: "action",
-      rating: 9.0,
-      description: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice.",
-      tags: ["action", "drama"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440004",
-      title: "Fight Club",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Ffight_club.jpg?alt=media&token=a4bc1933-2607-42cd-a860-e44c4587fd9c",
-      releaseYear: 1999,
-      genre: "drama",
-      rating: 8.8,
-      description: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity.",
-      tags: ["drama", "thriller"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440005",
-      title: "Pulp Fiction",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fpulp_fiction.jpg?alt=media&token=0df86e18-5cb1-45b3-a6d9-3f41563c3465",
-      releaseYear: 1994,
-      genre: "crime",
-      rating: 8.9,
-      description: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references.",
-      tags: ["crime", "drama"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440006",
-      title: "The Lord of the Rings: The Fellowship of the Ring",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Flotr_fellowship.jpg?alt=media&token=92641d2d-6c52-4172-bd66-95fb86b4b96b",
-      releaseYear: 2001,
-      genre: "fantasy",
-      rating: 8.8,
-      description: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond.",
-      tags: ["fantasy", "adventure"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440007",
-      title: "The Shawshank Redemption",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_shawshanks_redemption.jpg?alt=media&token=f67b5ab2-a435-48b2-8251-5bf866b183e9",
-      releaseYear: 1994,
-      genre: "drama",
-      rating: 9.3,
-      description: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman).",
-      tags: ["drama", "crime"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440008",
-      title: "Forrest Gump",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fforrest_gump.jpeg?alt=media&token=f21e88ce-6fab-4218-aa55-94738acc9b8f",
-      releaseYear: 1994,
-      genre: "drama",
-      rating: 8.8,
-      description: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright).",
-      tags: ["drama", "romance"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440009",
-      title: "The Godfather",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_godfather.jpg?alt=media&token=5297fd94-ae87-4995-9de5-3755232bad52",
-      releaseYear: 1972,
-      genre: "crime",
-      rating: 9.2,
-      description: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal.",
-      tags: ["crime", "drama"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440010",
-      title: "The Silence of the Lambs",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_silence_of_the_lambs.jpg?alt=media&token=7ca6abeb-b15c-4f5e-9280-5a590e89fe54",
-      releaseYear: 1991,
-      genre: "thriller",
-      rating: 8.6,
-      description: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer.",
-      tags: ["thriller", "crime"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440011",
-      title: "Saving Private Ryan",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fsaving_private_ryan.jpg?alt=media&token=58ed877e-7ae0-4e30-9aee-d45c2deb7a00",
-      releaseYear: 1998,
-      genre: "war",
-      rating: 8.6,
-      description: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war.",
-      tags: ["war", "drama"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440012",
-      title: "The Avengers",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_avengers.jpg?alt=media&token=3d68ccad-2fa1-48da-a83e-7941e246c9f9",
-      releaseYear: 2012,
-      genre: "action",
-      rating: 8.0,
-      description: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast.",
-      tags: ["action", "sci-fi"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440013",
-      title: "Gladiator",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fgladiator.jpg?alt=media&token=61d75825-b79f-4add-afdb-7da5eed53407",
-      releaseYear: 2000,
-      genre: "action",
-      rating: 8.5,
-      description: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance.",
-      tags: ["action", "drama"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440014",
-      title: "Titanic",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Ftitanic.png?alt=media&token=dd03dc83-486e-4b03-9b03-2f9ed83fd9d0",
-      releaseYear: 1997,
-      genre: "romance",
-      rating: 7.8,
-      description: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals.",
-      tags: ["romance", "drama"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440015",
-      title: "Avatar",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Favatar.jpg?alt=media&token=1c75b09d-7c7a-44bf-b7ad-e7da4d0b7193",
-      releaseYear: 2009,
-      genre: "sci-fi",
-      rating: 7.8,
-      description: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience.",
-      tags: ["sci-fi", "adventure"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440016",
-      title: "Jurassic Park",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fjurassic_park.jpg?alt=media&token=1731ce71-3384-4435-8a5b-821d4fd286d3",
-      releaseYear: 1993,
-      genre: "adventure",
-      rating: 8.1,
-      description: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures.",
-      tags: ["adventure", "sci-fi"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440017",
-      title: "The Lion King",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_lion_king.jpg?alt=media&token=3e4e4265-6ae7-47d6-a5ba-584de126ef00",
-      releaseYear: 1994,
-      genre: "animation",
-      rating: 8.5,
-      description: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption.",
-      tags: ["animation", "drama"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440018",
-      title: "Star Wars: Episode IV - A New Hope",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fstar_wars_4.jpg?alt=media&token=b4ea7e0c-707f-43dd-8633-9d962e77b5a4",
-      releaseYear: 1977,
-      genre: "sci-fi",
-      rating: 8.6,
-      description: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters.",
-      tags: ["sci-fi", "adventure"]
-    },
-    {
-      id: "550e8400-e29b-41d4-a716-446655440019",
-      title: "Blade Runner",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fblade_runner.jpg?alt=media&token=d8e94bdd-1477-49f3-b244-dd7a9c059fc1",
-      releaseYear: 1982,
-      genre: "sci-fi",
-      rating: 8.1,
-      description: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity.",
-      tags: ["sci-fi", "thriller"]
-    }
-  ])
-}
diff --git a/dataconnect/dataconnect/2_actor_insert.gql b/dataconnect/dataconnect/2_actor_insert.gql
deleted file mode 100644
index 6922dcf15..000000000
--- a/dataconnect/dataconnect/2_actor_insert.gql
+++ /dev/null
@@ -1,104 +0,0 @@
-mutation {
-  actor_insertMany(data: [
-    {
-      id: "123e4567-e89b-12d3-a456-426614174000",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdicaprio.jpeg?alt=media&token=452e030a-efa5-4ef4-bb81-502b23241316",
-      name: "Leonardo DiCaprio"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174001",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fkeanu.jpg?alt=media&token=6056520c-ef3e-4823-aad0-108aab163115",
-      name: "Keanu Reeves"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174002",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fmcconaoghey.jpg?alt=media&token=d340ca18-ef51-44ac-a160-08e45b242cd7",
-      name: "Matthew McConaughey"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174003",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fbale.jpg?alt=media&token=666f1690-a550-458f-a1cf-9505b7d1af7d",
-      name: "Christian Bale"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174004",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fpitt.jpeg?alt=media&token=3a5283d4-f85c-4ba7-be72-51bc87ca4133",
-      name: "Brad Pitt"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174005",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fjackson.jpg?alt=media&token=07be0601-19fe-4b5d-b111-84fa71f32139",
-      name: "Samuel L. Jackson"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174006",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fmortensen.jpeg?alt=media&token=e3d1ec99-b8e7-42e9-9d1c-03f56f61ecf7",
-      name: "Viggo Mortensen"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174007",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Ffreeman.jpg?alt=media&token=94bc6227-119e-4ab0-b350-55fac7aeb062",
-      name: "Morgan Freeman"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174008",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fhanks.jpeg?alt=media&token=d92979ce-da62-4b28-afbe-b8740bbb9d32",
-      name: "Tom Hanks"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174009",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fpacino.jpg?alt=media&token=9c0c54b1-6913-48b5-8e5e-d6551dd2f182",
-      name: "Al Pacino"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174010",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Ffoster.jpg?alt=media&token=b429734c-0f2d-4840-b75b-6857eac7bb4f",
-      name: "Jodie Foster"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174011",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fcruise.jpg?alt=media&token=d34b0326-a8d1-4f01-86e5-f3f094594e5a",
-      name: "Tom Cruise"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174012",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdowney.jpg?alt=media&token=dd291c96-6ef0-42fc-841c-902c80748b37",
-      name: "Robert Downey Jr."
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174013",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fcrowe.jpg?alt=media&token=46d413d5-ace8-404e-b018-8d7e6fe0d362",
-      name: "Russell Crowe"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174014",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fwinslet.jpg?alt=media&token=b675585e-356e-4361-a041-5ac1a6ee5922",
-      name: "Kate Winslet"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174015",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fweaver.jpeg?alt=media&token=263b5c3d-e0ee-43c3-854d-9b236c6df391",
-      name: "Sigourney Weaver"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174016",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fgoldblume.jpeg?alt=media&token=18277dd1-166c-4934-a02e-19ef141c86e2",
-      name: "Jeff Goldblum"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174017",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fjones.jpg?alt=media&token=f7ac9bc4-6e26-4b25-9a73-7a90f699424e",
-      name: "James Earl Jones"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174018",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fford.jpg?alt=media&token=928434c0-d492-4c8e-bdf0-0db585008d87",
-      name: "Harrison Ford"
-    },
-    {
-      id: "123e4567-e89b-12d3-a456-426614174019",
-      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fschwarzenegger.jpeg?alt=media&token=c46fb249-41ef-4084-b4ad-9517bee6ab46",
-      name: "Arnold Schwarzenegger"
-    }
-  ])
-}
diff --git a/dataconnect/dataconnect/3_movie_actor_insert.gql b/dataconnect/dataconnect/3_movie_actor_insert.gql
deleted file mode 100644
index c2256acc8..000000000
--- a/dataconnect/dataconnect/3_movie_actor_insert.gql
+++ /dev/null
@@ -1,238 +0,0 @@
-mutation {
-  movieMetadata_insertMany(data: [
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440000",
-      director: "Christopher Nolan"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440001",
-      director: "Lana Wachowski, Lilly Wachowski"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440002",
-      director: "Chad Stahelski"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440003",
-      director: "Christopher Nolan"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440004",
-      director: "David Fincher"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440005",
-      director: "Quentin Tarantino"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440006",
-      director: "Peter Jackson"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440007",
-      director: "Frank Darabont"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440008",
-      director: "Robert Zemeckis"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440009",
-      director: "Francis Ford Coppola"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440010",
-      director: "Jonathan Demme"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440011",
-      director: "Steven Spielberg"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440012",
-      director: "Joss Whedon"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440013",
-      director: "Ridley Scott"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440014",
-      director: "James Cameron"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440015",
-      director: "James Cameron"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440016",
-      director: "Steven Spielberg"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440017",
-      director: "Roger Allers, Rob Minkoff"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440018",
-      director: "George Lucas"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440019",
-      director: "Ridley Scott"
-    }
-  ])
-
-  movieActor_insertMany(data: [
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440000",
-      actorId: "123e4567-e89b-12d3-a456-426614174000",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440001",
-      actorId: "123e4567-e89b-12d3-a456-426614174001",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440002",
-      actorId: "123e4567-e89b-12d3-a456-426614174001",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440003",
-      actorId: "123e4567-e89b-12d3-a456-426614174003",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440004",
-      actorId: "123e4567-e89b-12d3-a456-426614174004",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440005",
-      actorId: "123e4567-e89b-12d3-a456-426614174005",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440006",
-      actorId: "123e4567-e89b-12d3-a456-426614174006",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440007",
-      actorId: "123e4567-e89b-12d3-a456-426614174007",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440008",
-      actorId: "123e4567-e89b-12d3-a456-426614174008",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440009",
-      actorId: "123e4567-e89b-12d3-a456-426614174009",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440010",
-      actorId: "123e4567-e89b-12d3-a456-426614174010",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440011",
-      actorId: "123e4567-e89b-12d3-a456-426614174011",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440012",
-      actorId: "123e4567-e89b-12d3-a456-426614174012",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440013",
-      actorId: "123e4567-e89b-12d3-a456-426614174013",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440014",
-      actorId: "123e4567-e89b-12d3-a456-426614174014",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440015",
-      actorId: "123e4567-e89b-12d3-a456-426614174015",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440016",
-      actorId: "123e4567-e89b-12d3-a456-426614174016",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440017",
-      actorId: "123e4567-e89b-12d3-a456-426614174017",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440018",
-      actorId: "123e4567-e89b-12d3-a456-426614174018",
-      role: "main"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440019",
-      actorId: "123e4567-e89b-12d3-a456-426614174019",
-      role: "main"
-    },
-    # Supporting actors
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440000",
-      actorId: "123e4567-e89b-12d3-a456-426614174001",
-      role: "supporting"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440001",
-      actorId: "123e4567-e89b-12d3-a456-426614174002",
-      role: "supporting"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440002",
-      actorId: "123e4567-e89b-12d3-a456-426614174003",
-      role: "supporting"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440003",
-      actorId: "123e4567-e89b-12d3-a456-426614174004",
-      role: "supporting"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440004",
-      actorId: "123e4567-e89b-12d3-a456-426614174005",
-      role: "supporting"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440005",
-      actorId: "123e4567-e89b-12d3-a456-426614174006",
-      role: "supporting"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440006",
-      actorId: "123e4567-e89b-12d3-a456-426614174007",
-      role: "supporting"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440007",
-      actorId: "123e4567-e89b-12d3-a456-426614174008",
-      role: "supporting"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440008",
-      actorId: "123e4567-e89b-12d3-a456-426614174009",
-      role: "supporting"
-    },
-    {
-      movieId: "550e8400-e29b-41d4-a716-446655440009",
-      actorId: "123e4567-e89b-12d3-a456-426614174010",
-      role: "supporting"
-    }
-  ])
-}
diff --git a/dataconnect/dataconnect/4_user_favorites_review_insert.gql b/dataconnect/dataconnect/4_user_favorites_review_insert.gql
deleted file mode 100644
index 27a9a64a8..000000000
--- a/dataconnect/dataconnect/4_user_favorites_review_insert.gql
+++ /dev/null
@@ -1,121 +0,0 @@
-mutation {
-  user_insertMany(data: [
-    {
-      id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-      username: "cynthia_w"
-    },
-    {
-      id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-      username: "hercule_p"
-    },
-    {
-      id: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-      username: "jane_d"
-    }
-  ])
-
-  review_insertMany(data: [
-    {
-      id: "345e4567-e89b-12d3-a456-426614174000",
-      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-      movieId: "550e8400-e29b-41d4-a716-446655440000",
-      rating: 5,
-      reviewText: "An incredible movie with a mind-blowing plot!",
-      reviewDate_date: { today: true }
-    },
-    {
-      id: "345e4567-e89b-12d3-a456-426614174001",
-      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-      movieId: "550e8400-e29b-41d4-a716-446655440001",
-      rating: 5,
-      reviewText: "A revolutionary film that changed cinema forever.",
-      reviewDate_date: { today: true }
-    },
-    {
-      id: "345e4567-e89b-12d3-a456-426614174002",
-      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-      movieId: "550e8400-e29b-41d4-a716-446655440002",
-      rating: 5,
-      reviewText: "A visually stunning and emotionally impactful movie.",
-      reviewDate_date: { today: true }
-    },
-    {
-      id: "345e4567-e89b-12d3-a456-426614174003",
-      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-      movieId: "550e8400-e29b-41d4-a716-446655440003",
-      rating: 4,
-      reviewText: "A fantastic superhero film with great performances.",
-      reviewDate_date: { today: true }
-    },
-    {
-      id: "345e4567-e89b-12d3-a456-426614174004",
-      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-      movieId: "550e8400-e29b-41d4-a716-446655440004",
-      rating: 5,
-      reviewText: "An amazing film that keeps you on the edge of your seat.",
-      reviewDate_date: { today: true }
-    },
-    {
-      id: "345e4567-e89b-12d3-a456-426614174005",
-      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-      movieId: "550e8400-e29b-41d4-a716-446655440005",
-      rating: 5,
-      reviewText: "An absolute classic with unforgettable dialogue.",
-      reviewDate_date: { today: true }
-    }
-  ])
-
-  favorite_movie_insertMany(data: [
-    {
-      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-      movieId: "550e8400-e29b-41d4-a716-446655440000"
-    },
-    {
-      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-      movieId: "550e8400-e29b-41d4-a716-446655440001"
-    },
-    {
-      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-      movieId: "550e8400-e29b-41d4-a716-446655440002"
-    },
-    {
-      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-      movieId: "550e8400-e29b-41d4-a716-446655440003"
-    },
-    {
-      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-      movieId: "550e8400-e29b-41d4-a716-446655440004"
-    },
-    {
-      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-      movieId: "550e8400-e29b-41d4-a716-446655440005"
-    }
-  ])
-
-  favorite_actor_insertMany(data: [
-    {
-      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-      actorId: "123e4567-e89b-12d3-a456-426614174000"
-    },
-    {
-      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-      actorId: "123e4567-e89b-12d3-a456-426614174001"
-    },
-    {
-      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-      actorId: "123e4567-e89b-12d3-a456-426614174002"
-    },
-    {
-      userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2",
-      actorId: "123e4567-e89b-12d3-a456-426614174003"
-    },
-    {
-      userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2",
-      actorId: "123e4567-e89b-12d3-a456-426614174004"
-    },
-    {
-      userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1",
-      actorId: "123e4567-e89b-12d3-a456-426614174005"
-    }
-  ])
-}
diff --git a/dataconnect/dataconnect/5_optional_vector_embed.gql b/dataconnect/dataconnect/5_optional_vector_embed.gql
deleted file mode 100644
index 76b11da60..000000000
--- a/dataconnect/dataconnect/5_optional_vector_embed.gql
+++ /dev/null
@@ -1,141 +0,0 @@
-mutation updateMovieEmbeddings {
-  movie1: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440000"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Dom Cobb (Leonardo DiCaprio) is a thief with the rare ability to enter people's dreams and steal their secrets from their subconscious. His skill has made him a valuable player in the world of corporate espionage but has also cost him everything he loves. Cobb gets a chance at redemption when he is offered a seemingly impossible task: plant an idea in someone's mind. If he succeeds, it will be the perfect crime, but a dangerous enemy anticipates Cobb's every move."}
-    }
-  )
-  
-  movie2: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440001"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Thomas Anderson, a computer programmer, discovers that the world is actually a simulation controlled by malevolent machines in a dystopian future. Known as Neo, he joins a group of underground rebels led by Morpheus to fight the machines and free humanity. Along the way, Neo learns to manipulate the simulated reality, uncovering his true destiny."}
-    }
-  )
-  
-  movie3: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440002"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "John Wick (Keanu Reeves) uncovers a path to defeating The High Table, but before he can earn his freedom, he must face off against a new enemy with powerful alliances across the globe. The film follows Wick as he battles through various international locations, facing relentless adversaries and forming new alliances."}
-    }
-  )
-
-  movie4: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440003"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "When the menace known as the Joker (Heath Ledger) emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham. The Dark Knight (Christian Bale) must accept one of the greatest psychological and physical tests of his ability to fight injustice."}
-    }
-  )
-
-  movie5: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440004"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "An insomniac office worker (Edward Norton) and a devil-may-care soapmaker (Brad Pitt) form an underground fight club that evolves into something much more. The story explores themes of consumerism, masculinity, and the search for identity."}
-    }
-  )
-
-  movie6: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440005"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption. The film is known for its eclectic dialogue, ironic mix of humor and violence, and a host of cinematic allusions and pop culture references."}
-    }
-  )
-
-  movie7: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440006"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A meek Hobbit from the Shire, Frodo Baggins, and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron. The epic adventure begins the quest that will test their courage and bond."}
-    }
-  )
-
-  movie8: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440007"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency. The film follows Andy Dufresne (Tim Robbins), a banker sentenced to life in Shawshank State Penitentiary, and his friendship with Red (Morgan Freeman)."}
-    }
-  )
-
-  movie9: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440008"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The presidencies of Kennedy and Johnson, the events of Vietnam, Watergate, and other historical moments unfold from the perspective of an Alabama man with a low IQ. Forrest Gump (Tom Hanks) becomes an unwitting participant in many key moments of 20th-century U.S. history, all while maintaining his love for his childhood sweetheart Jenny (Robin Wright)."}
-    }
-  )
-
-  movie10: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440009"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son. The story follows the powerful Corleone family as they navigate power, loyalty, and betrayal."}
-    }
-  )
-
-  movie11: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440010"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A young F.B.I. cadet must receive the help of an incarcerated and manipulative cannibal killer to help catch another serial killer. Clarice Starling (Jodie Foster) seeks the assistance of Hannibal Lecter (Anthony Hopkins) to understand the mind of a killer."}
-    }
-  )
-
-  movie12: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440011"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Following the Normandy Landings, a group of U.S. soldiers go behind enemy lines to retrieve a paratrooper whose brothers have been killed in action. The harrowing journey of Captain John H. Miller (Tom Hanks) and his men highlights the brutal reality of war."}
-    }
-  )
- 
-  movie13: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440012"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Earth's mightiest heroes, including Iron Man, Captain America, Thor, Hulk, Black Widow, and Hawkeye, must come together to stop Loki and his alien army from enslaving humanity. Directed by Joss Whedon, the film is known for its witty dialogue, intense action sequences, and the chemistry among its ensemble cast."}
-    }
-  )
-
-  movie14: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440013"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A former Roman General, Maximus Decimus Meridius, seeks vengeance against the corrupt emperor Commodus who murdered his family and sent him into slavery. Directed by Ridley Scott, the film is known for its epic scale, intense battle scenes, and Russell Crowe's powerful performance."}
-    }
-  )
-
-  movie15: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440014"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A romantic drama recounting the ill-fated voyage of the R.M.S. Titanic through the eyes of Jack Dawson, a poor artist, and Rose DeWitt Bukater, a wealthy aristocrat. Their forbidden romance unfolds aboard the luxurious ship, which tragically sinks after striking an iceberg. Directed by James Cameron, the film is known for its epic scale, emotional depth, and stunning visuals."}
-    }
-  )
-
-  movie16: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440015"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A paraplegic Marine named Jake Sully is sent on a unique mission to Pandora, an alien world, to bridge relations with the native Na'vi people. Torn between following his orders and protecting the world he feels is his home, Jake's journey becomes a battle for survival. Directed by James Cameron, 'Avatar' is renowned for its groundbreaking special effects and immersive 3D experience."}
-    }
-  )
-
-  movie17: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440016"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "During a preview tour, a theme park suffers a major power breakdown that allows its cloned dinosaur exhibits to run amok. Directed by Steven Spielberg, 'Jurassic Park' is known for its groundbreaking special effects, thrilling storyline, and the suspenseful chaos unleashed by its prehistoric creatures."}
-    }
-  )
-
-  movie18: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440017"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "A young lion prince, Simba, must overcome betrayal and tragedy to reclaim his rightful place as king. 'The Lion King' is a beloved animated musical known for its memorable songs, stunning animation, and a timeless tale of courage, loyalty, and redemption."}
-    }
-  )
-
-  movie19: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440018"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee, and two droids to save the galaxy from the Empire's world-destroying battle station, the Death Star. Directed by George Lucas, 'A New Hope' revolutionized the sci-fi genre with its groundbreaking special effects and unforgettable characters."}
-    }
-  )
-
-  movie20: movie_update(
-    id: "550e8400-e29b-41d4-a716-446655440019"
-    data: {
-      descriptionEmbedding_embed: {model: "textembedding-gecko@003", text: "In a dystopian future, synthetic humans known as replicants are created by powerful corporations. A blade runner named Rick Deckard is tasked with hunting down and 'retiring' four replicants who have escaped to Earth. Directed by Ridley Scott, 'Blade Runner' is a seminal sci-fi thriller that explores themes of humanity and identity."}
-    }
-  )
-}
diff --git a/dataconnect/dataconnect/movie-connector/mutations.gql b/dataconnect/dataconnect/movie-connector/mutations.gql
index 4dc4fff18..0d7545e4b 100644
--- a/dataconnect/dataconnect/movie-connector/mutations.gql
+++ b/dataconnect/dataconnect/movie-connector/mutations.gql
@@ -1,22 +1,8 @@
-# Create a movie based on user input
-mutation CreateMovie(
-  $title: String!
-  $releaseYear: Int!
-  $genre: String!
-  $rating: Float
-  $description: String
-  $imageUrl: String!
-  $tags: [String!] = []
-) @auth(expr: "auth.token.isAdmin == true") {
-  movie_insert(
+mutation UpsertUser($username: String!) @auth(level: USER) {
+  user_upsert(
     data: {
-      title: $title
-      releaseYear: $releaseYear
-      genre: $genre
-      rating: $rating
-      description: $description
-      imageUrl: $imageUrl
-      tags: $tags
+      id_expr: "auth.uid"
+      username: $username
     }
   )
 }
@@ -31,23 +17,10 @@ mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
   favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
 }
 
-# Add an actor to the user's favorites list
-mutation AddFavoritedActor($actorId: UUID!) @auth(level: USER) {
-  favorite_actor_upsert(data: { userId_expr: "auth.uid", actorId: $actorId })
-}
-
-# Remove an actor from the user's favorites list
-mutation DeleteFavoritedActor($actorId: UUID!) @auth(level: USER) {
-  favorite_actor_delete(key: { userId_expr: "auth.uid", actorId: $actorId })
-}
-
 # Add a review for a movie
-mutation AddReview(
-  $movieId: UUID!
-  $rating: Int!
-  $reviewText: String!
-) @auth(level: USER) {
-  review_update(
+mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!)
+@auth(level: USER) {
+  review_insert(
     data: {
       userId_expr: "auth.uid"
       movieId: $movieId
@@ -59,15 +32,10 @@ mutation AddReview(
 }
 
 # Update a user's review for a movie
-mutation UpdateReview(
-  $id: UUID!
-  $movieId: UUID!
-  $rating: Int!
-  $reviewText: String!
-  $userId: String!
-) @auth(expr: "auth.uid != null && auth.uid == userId") {
+mutation UpdateReview($movieId: UUID!, $rating: Int!, $reviewText: String!)
+@auth(level: USER) {
   review_update(
-    id: $id,
+    key: { userId_expr: "auth.uid", movieId: $movieId }
     data: {
       userId_expr: "auth.uid"
       movieId: $movieId
@@ -79,56 +47,56 @@ mutation UpdateReview(
 }
 
 # Delete a user's review for a movie
-mutation DeleteReview(
-  $movieId: UUID!
-) @auth(level: USER) {
+mutation DeleteReview($movieId: UUID!) @auth(level: USER) {
   review_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
 }
 
-# Upsert (update or insert) a user based on their username
-mutation UpsertUser($username: String!) @auth(level: USER) {
-  user_upsert(
-    data: {
-      id_expr: "auth.uid"
-      username: $username
-    }
-  )
-}
-
 # The mutations below are unused by the application, but are useful examples for more complex cases
 
+# Create a movie based on user input
+# mutation CreateMovie(
+#   $title: String!
+#   $releaseYear: Int!
+#   $genre: String!
+#   $rating: Float
+#   $description: String
+#   $imageUrl: String!
+#   $tags: [String!] = []
+# ) @auth(expr: "auth.token.isAdmin == true") {
+
+# }
 # Update movie information based on the provided ID
-mutation UpdateMovie(
-  $id: UUID!
-  $title: String
-  $releaseYear: Int
-  $genre: String
-  $rating: Float
-  $description: String
-  $imageUrl: String
-  $tags: [String!] = []
-) @auth(level: USER_EMAIL_VERIFIED) {
-  movie_update(
-    id: $id
-    data: {
-      title: $title
-      releaseYear: $releaseYear
-      genre: $genre
-      rating: $rating
-      description: $description
-      imageUrl: $imageUrl
-      tags: $tags
-    }
-  )
-}
+# mutation UpdateMovie(
+#   $id: UUID!
+#   $title: String
+#   $releaseYear: Int
+#   $genre: String
+#   $rating: Float
+#   $description: String
+#   $imageUrl: String
+#   $tags: [String!] = []
+# ) @auth(level: USER_EMAIL_VERIFIED) {
+#   movie_update(
+#     id: $id
+#     data: {
+#       title: $title
+#       releaseYear: $releaseYear
+#       genre: $genre
+#       rating: $rating
+#       description: $description
+#       imageUrl: $imageUrl
+#       tags: $tags
+#     }
+#   )
+# }
 
 # Delete a movie by its ID
-mutation DeleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
-  movie_delete(id: $id)
-}
+# mutation DeleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
+#   movie_delete(id: $id)
+# }
 
 # Delete movies with a rating lower than the specified minimum rating
-mutation DeleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
-  movie_deleteMany(where: { rating: { le: $minRating } })
-}
+# mutation DeleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
+#   movie_deleteMany(where: { rating: { le: $minRating } })
+# }
 # End of example mutations
\ No newline at end of file
diff --git a/dataconnect/dataconnect/movie-connector/queries.gql b/dataconnect/dataconnect/movie-connector/queries.gql
index 27728103a..28bf389c5 100644
--- a/dataconnect/dataconnect/movie-connector/queries.gql
+++ b/dataconnect/dataconnect/movie-connector/queries.gql
@@ -1,9 +1,10 @@
 # List subset of fields for movies
 query ListMovies($orderByRating: OrderDirection, $orderByReleaseYear: OrderDirection, $limit: Int) @auth(level: PUBLIC) {
-  movies (
+  movies(
     orderBy: [
       { rating: $orderByRating },
-      { releaseYear: $orderByReleaseYear }]
+      { releaseYear: $orderByReleaseYear }
+    ]
     limit: $limit
   ) {
     id
@@ -17,34 +18,9 @@ query ListMovies($orderByRating: OrderDirection, $orderByReleaseYear: OrderDirec
   }
 }
 
-# List movies of a certain genre
-query ListMoviesByGenre($genre: String!) @auth(level: PUBLIC) {
-  mostPopular: movies(
-    where: { genre: { eq: $genre } }
-    orderBy: { rating: DESC }
-    limit: 10
-  ) {
-    id
-    title
-    imageUrl
-    rating
-    tags
-  }
-  mostRecent: movies(
-    where: { genre: { eq: $genre } }
-    orderBy: { releaseYear: DESC }
-  ) {
-    id
-    title
-    imageUrl
-    rating
-    tags
-  }
-}
-
 # Get movie by id
 query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
-  movie(id: $id) {
+ movie(id: $id) {
     id
     title
     imageUrl
@@ -79,7 +55,7 @@ query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
       }
     }
   }
-}
+ }
 
 # Get actor by id
 query GetActorById($id: UUID!) @auth(level: PUBLIC) {
@@ -106,9 +82,10 @@ query GetActorById($id: UUID!) @auth(level: PUBLIC) {
   }
 }
 
+
 # Get user by ID
 query GetCurrentUser @auth(level: USER) {
-  user(key: {id_expr: "auth.uid"}) {
+  user(key: { id_expr: "auth.uid" }) {
     id
     username
     reviews: reviews_on_user {
@@ -136,30 +113,15 @@ query GetCurrentUser @auth(level: USER) {
         }
       }
     }
-    favoriteActors: favorite_actors_on_user {
-      actor {
-        id
-        name
-        imageUrl
-      }
-    }
   }
 }
 
-# Check if a movie is favorited by user
 query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
   favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
     movieId
   }
 }
 
-# Check if an actor is favorited by user
-query GetIfFavoritedActor($actorId: UUID!) @auth(level: USER) {
-  favorite_actor(key: { userId_expr: "auth.uid", actorId: $actorId }) {
-    actorId
-  }
-}
-
 # Search for movies, actors, and reviews
 query SearchAll(
   $input: String
@@ -227,138 +189,141 @@ query SearchAll(
 }
 
 # Search movie descriptions using L2 similarity with Vertex AI
-query SearchMovieDescriptionUsingL2Similarity($query: String!)
-@auth(level: PUBLIC) {
-  movies_descriptionEmbedding_similarity(
-    compare_embed: { model: "textembedding-gecko@003", text: $query }
-    method: L2
-    within: 2
-    limit: 5
-  ) {
-    id
-    title
-    description
-    tags
-    rating
-    imageUrl
-  }
-}
-# The queries below are unused by the application, but are useful examples for more complex cases
+# query SearchMovieDescriptionUsingL2Similarity($query: String!)
+# @auth(level: PUBLIC) {
+#   movies_descriptionEmbedding_similarity(
+#     compare_embed: { model: "textembedding-gecko@003", text: $query }
+#     method: L2
+#     within: 2
+#     limit: 5
+#   ) {
+#     id
+#     title
+#     description
+#     tags
+#     rating
+#     imageUrl
+#   }
+# }
 
-# List movies by partial title match
-query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
-  movies(where: { title: { contains: $input } }) {
-    id
-    title
-    genre
-    rating
-    imageUrl
-  }
-}
 
-# List movies by tag
-query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
-  movies(where: { tags: { includes: $tag } }) {
-    id
-    title
-    imageUrl
-    genre
-    rating
-  }
-}
 
-# List movies by release year range
-query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
-  movies(
-    where: { releaseYear: { le: $max, ge: $min } }
-    orderBy: { releaseYear: ASC }
-  ) {
-    id
-    rating
-    title
-    imageUrl
-  }
-}
+# # The queries below are unused by the application, but are useful examples for more complex cases
 
-# List movies by rating and genre with OR filters
-query SearchMovieOr(
-  $minRating: Float
-  $maxRating: Float
-  $genre: String
-  $tag: String
-  $input: String
-) @auth(level: PUBLIC) {
-  movies(
-    where: {
-      _or: [
-        { rating: { ge: $minRating } }
-        { rating: { le: $maxRating } }
-        { genre: { eq: $genre } }
-        { tags: { includes: $tag } }
-        { title: { contains: $input } }
-      ]
-    }
-  ) {
-    id
-    rating
-    title
-    imageUrl
-  }
-}
+# # List movies by partial title match
+# query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
+#   movies(where: { title: { contains: $input } }) {
+#     id
+#     title
+#     genre
+#     rating
+#     imageUrl
+#   }
+# }
 
-# List movies by rating and genre with AND filters
-query SearchMovieAnd(
-  $minRating: Float
-  $maxRating: Float
-  $genre: String
-  $tag: String
-  $input: String
-) @auth(level: PUBLIC) {
-  movies(
-    where: {
-      _and: [
-        { rating: { ge: $minRating } }
-        { rating: { le: $maxRating } }
-        { genre: { eq: $genre } }
-        { tags: { includes: $tag } }
-        { title: { contains: $input } }
-      ]
-    }
-  ) {
-    id
-    rating
-    title
-    imageUrl
-  }
-}
+# # List movies by tag
+# query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
+#   movies(where: { tags: { includes: $tag } }) {
+#     id
+#     title
+#     imageUrl
+#     genre
+#     rating
+#   }
+# }
 
-# Get favorite actors by user ID
-query GetFavoriteActors @auth(level: USER) {
-  user(key: {id_expr: "auth.uid"}) {
-    favorite_actors_on_user {
-      actor {
-        id
-        name
-        imageUrl
-      }
-    }
-  }
-}
+# # List movies by release year range
+# query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
+#   movies(
+#     where: { releaseYear: { le: $max, ge: $min } }
+#     orderBy: { releaseYear: ASC }
+#   ) {
+#     id
+#     rating
+#     title
+#     imageUrl
+#   }
+# }
 
-# Get favorite movies by user ID
-query GetUserFavoriteMovies @auth(level: USER) {
-  user(id_expr: "auth.uid") {
-    favorite_movies_on_user {
-      movie {
-        id
-        title
-        genre
-        imageUrl
-        releaseYear
-        rating
-        description
-      }
-    }
-  }
-}
-# end of example queries
+# # List movies by rating and genre with OR filters
+# query SearchMovieOr(
+#   $minRating: Float
+#   $maxRating: Float
+#   $genre: String
+#   $tag: String
+#   $input: String
+# ) @auth(level: PUBLIC) {
+#   movies(
+#     where: {
+#       _or: [
+#         { rating: { ge: $minRating } }
+#         { rating: { le: $maxRating } }
+#         { genre: { eq: $genre } }
+#         { tags: { includes: $tag } }
+#         { title: { contains: $input } }
+#       ]
+#     }
+#   ) {
+#     id
+#     rating
+#     title
+#     imageUrl
+#   }
+# }
+
+# # List movies by rating and genre with AND filters
+# query SearchMovieAnd(
+#   $minRating: Float
+#   $maxRating: Float
+#   $genre: String
+#   $tag: String
+#   $input: String
+# ) @auth(level: PUBLIC) {
+#   movies(
+#     where: {
+#       _and: [
+#         { rating: { ge: $minRating } }
+#         { rating: { le: $maxRating } }
+#         { genre: { eq: $genre } }
+#         { tags: { includes: $tag } }
+#         { title: { contains: $input } }
+#       ]
+#     }
+#   ) {
+#     id
+#     rating
+#     title
+#     imageUrl
+#   }
+# }
+
+# # Get favorite actors by user ID
+# query GetFavoriteActors @auth(level: USER) {
+#   user(key: {id_expr: "auth.uid"}) {
+#     favorite_actors_on_user {
+#       actor {
+#         id
+#         name
+#         imageUrl
+#       }
+#     }
+#   }
+# }
+
+# # Get favorite movies by user ID
+# query GetUserFavoriteMovies @auth(level: USER) {
+#   user(id_expr: "auth.uid") {
+#     favorite_movies_on_user {
+#       movie {
+#         id
+#         title
+#         genre
+#         imageUrl
+#         releaseYear
+#         rating
+#         description
+#       }
+#     }
+#   }
+# }
+# # end of example queries
\ No newline at end of file
diff --git a/dataconnect/dataconnect/moviedata_insert.gql b/dataconnect/dataconnect/moviedata_insert.gql
new file mode 100644
index 000000000..2f205012b
--- /dev/null
+++ b/dataconnect/dataconnect/moviedata_insert.gql
@@ -0,0 +1,687 @@
+mutation {
+  movie_insertMany(
+    data: [
+      {
+        id: "550e8400-e29b-41d4-a716-446655440000"
+        title: "Quantum Paradox"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fquantum_paradox.jpeg?alt=media&token=4142e2a1-bf43-43b5-b7cf-6616be3fd4e3"
+        releaseYear: 2025
+        genre: "sci-fi"
+        rating: 7.9
+        description: "A group of scientists accidentally open a portal to a parallel universe, causing a rift in time. As the team races to close the portal, they encounter alternate versions of themselves, leading to shocking revelations."
+        tags: ["thriller", "adventure"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440001"
+        title: "The Lone Outlaw"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Flone_outlaw.jpeg?alt=media&token=15525ffc-208f-4b59-b506-ae8348e06e85"
+        releaseYear: 2023
+        genre: "western"
+        rating: 8.2
+        description: "In the lawless Wild West, a mysterious gunslinger with a hidden past takes on a corrupt sheriff and his band of outlaws to bring justice to a small town."
+        tags: ["action", "drama"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440002"
+        title: "Celestial Harmony"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fcelestial_harmony.jpeg?alt=media&token=3edf1cf9-c2f5-4c75-9819-36ff6a734c9a"
+        releaseYear: 2024
+        genre: "romance"
+        rating: 7.5
+        description: "Two astronauts, stationed on a remote space station, fall in love amidst the isolation of deep space. But when a mysterious signal disrupts their communication, they must find a way to reconnect and survive."
+        tags: ["romance", "sci-fi"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440003"
+        title: "Noir Mystique"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fnoir_mystique.jpeg?alt=media&token=3299adba-cb98-4302-8b23-aeb679a4f913"
+        releaseYear: 2022
+        genre: "mystery"
+        rating: 8.0
+        description: "A private detective gets caught up in a web of lies, deception, and betrayal while investigating the disappearance of a famous actress in 1940s Hollywood."
+        tags: ["crime", "thriller"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440004"
+        title: "The Forgotten Island"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fforgotten_island.jpeg?alt=media&token=bc2b16e1-caed-4649-952c-73b6113f205c"
+        releaseYear: 2025
+        genre: "adventure"
+        rating: 7.6
+        description: "An explorer leads an expedition to a remote island rumored to be home to mythical creatures. As the team ventures deeper into the island, they uncover secrets that change the course of history."
+        tags: ["adventure", "fantasy"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440005"
+        title: "Digital Nightmare"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fdigital_nightmare.jpeg?alt=media&token=335ec842-1ca4-4b09-abd1-e96d9f5c0c2f"
+        releaseYear: 2024
+        genre: "horror"
+        rating: 6.9
+        description: "A tech-savvy teenager discovers a cursed app that brings nightmares to life. As the horrors of the digital world cross into reality, she must find a way to break the curse before it's too late."
+        tags: ["horror", "thriller"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440006"
+        title: "Eclipse of Destiny"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Feclipse_destiny.jpeg?alt=media&token=346649b3-cb5c-4d7e-b0d4-6f02e3df5959"
+        releaseYear: 2026
+        genre: "fantasy"
+        rating: 8.1
+        description: "In a kingdom on the brink of war, a prophecy speaks of an eclipse that will grant power to the rightful ruler. As factions vie for control, a young warrior must decide where his true loyalty lies."
+        tags: ["fantasy", "adventure"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440007"
+        title: "Heart of Steel"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fheart_steel.jpeg?alt=media&token=17883d71-329b-415a-86f8-dd4d9e941d7f"
+        releaseYear: 2023
+        genre: "sci-fi"
+        rating: 7.7
+        description: "A brilliant scientist creates a robot with a human heart. As the robot struggles to understand emotions, it becomes entangled in a plot that could change the fate of humanity."
+        tags: ["sci-fi", "drama"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440008"
+        title: "Rise of the Crimson Empire"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Frise_crimson_empire.jpeg?alt=media&token=6faa73ad-7504-4146-8f3a-50b90f607f33"
+        releaseYear: 2025
+        genre: "action"
+        rating: 8.4
+        description: "A legendary warrior rises to challenge the tyrannical rule of a powerful empire. As rebellion brews, the warrior must unite different factions to lead an uprising."
+        tags: ["action", "adventure"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440009"
+        title: "Silent Waves"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fsilent_waves.jpeg?alt=media&token=bd626bf1-ec60-4e57-aa07-87ba14e35bb7"
+        releaseYear: 2024
+        genre: "drama"
+        rating: 8.2
+        description: "A talented pianist, who loses his hearing in a tragic accident, must rediscover his passion for music with the help of a young music teacher who believes in him."
+        tags: ["drama", "music"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440010"
+        title: "Echoes of the Past"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fecho_of_past.jpeg?alt=media&token=d866aa27-8534-4d72-8988-9da4a1b9e452"
+        releaseYear: 2023
+        genre: "historical"
+        rating: 7.8
+        description: "A historian stumbles upon an ancient artifact that reveals hidden truths about an empire long forgotten. As she deciphers the clues, a shadowy organization tries to stop her from unearthing the past."
+        tags: ["drama", "mystery"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440011"
+        title: "Beyond the Horizon"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fbeyond_horizon.jpeg?alt=media&token=31493973-0692-4e6e-8b88-afb1aaea17ee"
+        releaseYear: 2026
+        genre: "sci-fi"
+        rating: 8.5
+        description: "In the future, Earth's best pilots are sent on a mission to explore a mysterious planet beyond the solar system. What they find changes humanity's understanding of the universe forever."
+        tags: ["sci-fi", "adventure"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440012"
+        title: "Shadows and Lies"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fshadows_lies.jpeg?alt=media&token=01afb80d-caee-47f8-a00e-aea8b9e459a2"
+        releaseYear: 2022
+        genre: "crime"
+        rating: 7.9
+        description: "A young detective with a dark past investigates a series of mysterious murders in a city plagued by corruption. As she digs deeper, she realizes nothing is as it seems."
+        tags: ["crime", "thriller"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440013"
+        title: "The Last Symphony"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Flast_symphony.jpeg?alt=media&token=f9bf80cd-3d8e-4e24-8503-7feb11f4e397"
+        releaseYear: 2024
+        genre: "drama"
+        rating: 8.0
+        description: "An aging composer struggling with memory loss attempts to complete his final symphony. With the help of a young prodigy, he embarks on an emotional journey through his memories and legacy."
+        tags: ["drama", "music"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440014"
+        title: "Moonlit Crusade"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fmoonlit_crusade.jpeg?alt=media&token=b13241f5-d7d0-4370-b651-07847ad99dc2"
+        releaseYear: 2025
+        genre: "fantasy"
+        rating: 8.3
+        description: "A knight is chosen by an ancient order to embark on a quest under the light of the full moon. Facing mythical beasts and treacherous landscapes, he seeks a relic that could save his kingdom."
+        tags: ["fantasy", "adventure"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440015"
+        title: "Abyss of the Deep"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fabyss_deep.jpeg?alt=media&token=2417321d-2451-4ec0-9ed6-6297042170e6"
+        releaseYear: 2023
+        genre: "horror"
+        rating: 7.2
+        description: "When a group of marine biologists descends into the unexplored depths of the ocean, they encounter a terrifying and ancient force. Now, they must survive as the abyss comes alive."
+        tags: ["horror", "thriller"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440016"
+        title: "Phoenix Rising"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fpheonix_rising.jpeg?alt=media&token=7298b1fd-833c-471c-a55d-e8fc798b4ab2"
+        releaseYear: 2025
+        genre: "action"
+        rating: 8.6
+        description: "A special forces operative, presumed dead, returns to avenge his fallen comrades. With nothing to lose, he faces a powerful enemy in a relentless pursuit for justice."
+        tags: ["action", "thriller"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440017"
+        title: "The Infinite Knot"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Finfinite_knot.jpeg?alt=media&token=93d54d93-d933-4663-a6fe-26b707ef823e"
+        releaseYear: 2026
+        genre: "romance"
+        rating: 7.4
+        description: "Two souls destined to meet across multiple lifetimes struggle to find each other in a chaotic world. With each incarnation, they get closer, but time itself becomes their greatest obstacle."
+        tags: ["romance", "fantasy"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440018"
+        title: "Parallel Justice"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fparalel_justice.jpeg?alt=media&token=4544b5e2-7a1d-46ca-a97f-eb6a490d4288"
+        releaseYear: 2024
+        genre: "crime"
+        rating: 8.1
+        description: "A lawyer who can see the outcomes of different timelines must choose between justice and personal gain. When a high-stakes case arises, he faces a moral dilemma that could alter his life forever."
+        tags: ["crime", "thriller"]
+      }
+      {
+        id: "550e8400-e29b-41d4-a716-446655440019"
+        title: "Veil of Illusion"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fveil_illusion.jpeg?alt=media&token=7bf09a3c-c531-478a-9d02-5d99fca9393b"
+        releaseYear: 2022
+        genre: "mystery"
+        rating: 7.8
+        description: "A magician-turned-detective uses his skills in illusion to solve crimes. When a series of murders leaves the city in fear, he must reveal the truth hidden behind a veil of deceit."
+        tags: ["mystery", "crime"]
+      }
+    ]
+  )
+  actor_insertMany(
+    data: [
+      {
+        id: "123e4567-e89b-12d3-a456-426614174020"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Foliver_blackwood.jpeg?alt=media&token=79cdbc29-c2c6-4dc3-b87f-f6dc4f1a8208"
+        name: "Oliver Blackwood"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174021"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Femma_westfield.jpeg?alt=media&token=2991c3c9-cfa8-4067-8b26-c5239b6894c4"
+        name: "Emma Westfield"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174022"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fjack_stone.jpeg?alt=media&token=74a564aa-d840-4bdd-a8a6-c6b17bbde608"
+        name: "Jack Stone"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174023"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fclara_woods.jpeg?alt=media&token=b4ff2a15-ef6d-4f20-86c9-07d67015fb29"
+        name: "Clara Woods"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174024"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fnoah_frost.jpeg?alt=media&token=0d08179a-7778-405e-9501-feac43b77a99"
+        name: "Noah Frost"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174025"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fisabelle_hart.jpeg?alt=media&token=d4fdf896-0f5b-4c32-91a4-7a541a95e77d"
+        name: "Isabella Hart"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174026"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fliam_hale.jpeg?alt=media&token=08e8eeee-b8ef-4e7b-8f97-a1e0b59321cc"
+        name: "Liam Hale"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174027"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fsophia_knight.jpeg?alt=media&token=7a79ef21-93e0-46f9-934c-6bbef7b5d430"
+        name: "Sophia Knight"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174028"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Falex_clay.jpeg?alt=media&token=2a798cdb-f44f-48d5-91bc-9d26a758944e"
+        name: "Alexander Clay"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174029"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Famelia_stone.jpeg?alt=media&token=34f21ba9-9e28-4708-9e55-f123634ab506"
+        name: "Amelia Stone"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174030"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fethan_blake.jpeg?alt=media&token=41352170-a5cd-4088-b8fd-1c4ee0d52cad"
+        name: "Ethan Blake"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174031"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fmia_gray.jpeg?alt=media&token=1ba1831a-3ada-485a-b5c9-2d018bf1862b"
+        name: "Mia Gray"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174032"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Flucas_reed.jpeg?alt=media&token=c74f44f3-ae98-4208-8e67-18c2db65a5c1"
+        name: "Lucas Reed"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174033"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fevelyn_harper.jpeg?alt=media&token=b138b308-9589-4dfe-8c50-a6d70f06dfb1"
+        name: "Evelyn Harper"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174034"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Foscar_smith.jpeg?alt=media&token=d493da85-644d-4d45-a09d-ecb5416645e4"
+        name: "Oscar Smith"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174035"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fava_winter.jpeg?alt=media&token=757e4b11-0372-401e-8fa0-61797e90312a"
+        name: "Ava Winter"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174036"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fleo_hunt.jpeg?alt=media&token=2cb14738-b39b-47b1-87f9-b45f38245179"
+        name: "Leo Hunt"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174037"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Flucy_walsh.jpeg?alt=media&token=016a216c-f329-4c10-bbe8-b31425f73c69"
+        name: "Lucy Walsh"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174038"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fmason_ford.jpeg?alt=media&token=55388be9-fdc8-483f-8352-c29755ed3574"
+        name: "Mason Ford"
+      }
+      {
+        id: "123e4567-e89b-12d3-a456-426614174039"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Flily_moore.jpeg?alt=media&token=19538aa6-1baf-4033-8fd7-d2a62aa79f51"
+        name: "Lily Moore"
+      }
+    ]
+  )
+  movieMetadata_insertMany(
+    data: [
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440000"
+        director: "Henry Caldwell"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440001"
+        director: "Juliana Mason, Clark Avery"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440002"
+        director: "Diana Rivers"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440003"
+        director: "Liam Thatcher"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440004"
+        director: "Evelyn Hart"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440005"
+        director: "Grayson Brooks"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440006"
+        director: "Isabella Quinn"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440007"
+        director: "Vincent Hale"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440008"
+        director: "Amelia Sutton"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440009"
+        director: "Lucas Stone"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440010"
+        director: "Sophia Langford"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440011"
+        director: "Noah Bennett"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440012"
+        director: "Chloe Armstrong"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440013"
+        director: "Sebastian Crane"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440014"
+        director: "Isla Fitzgerald"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440015"
+        director: "Oliver Hayes"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440016"
+        director: "Mila Donovan"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440017"
+        director: "Carter Monroe, Elise Turner"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440018"
+        director: "Adrian Blake"
+      }
+      {
+        movieId: "550e8400-e29b-41d4-a716-446655440019"
+        director: "Hazel Carter"
+      }
+    ]
+  )
+movieActor_insertMany(
+  data: [
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440000"
+      actorId: "123e4567-e89b-12d3-a456-426614174020"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440000"
+      actorId: "123e4567-e89b-12d3-a456-426614174021"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440001"
+      actorId: "123e4567-e89b-12d3-a456-426614174021"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440001"
+      actorId: "123e4567-e89b-12d3-a456-426614174022"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440002"
+      actorId: "123e4567-e89b-12d3-a456-426614174022"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440002"
+      actorId: "123e4567-e89b-12d3-a456-426614174023"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440003"
+      actorId: "123e4567-e89b-12d3-a456-426614174023"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440003"
+      actorId: "123e4567-e89b-12d3-a456-426614174024"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440004"
+      actorId: "123e4567-e89b-12d3-a456-426614174024"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440004"
+      actorId: "123e4567-e89b-12d3-a456-426614174025"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440005"
+      actorId: "123e4567-e89b-12d3-a456-426614174025"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440005"
+      actorId: "123e4567-e89b-12d3-a456-426614174026"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440006"
+      actorId: "123e4567-e89b-12d3-a456-426614174026"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440006"
+      actorId: "123e4567-e89b-12d3-a456-426614174027"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440007"
+      actorId: "123e4567-e89b-12d3-a456-426614174027"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440007"
+      actorId: "123e4567-e89b-12d3-a456-426614174028"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440008"
+      actorId: "123e4567-e89b-12d3-a456-426614174028"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440008"
+      actorId: "123e4567-e89b-12d3-a456-426614174029"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440009"
+      actorId: "123e4567-e89b-12d3-a456-426614174029"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440009"
+      actorId: "123e4567-e89b-12d3-a456-426614174030"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440010"
+      actorId: "123e4567-e89b-12d3-a456-426614174030"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440010"
+      actorId: "123e4567-e89b-12d3-a456-426614174031"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440011"
+      actorId: "123e4567-e89b-12d3-a456-426614174031"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440011"
+      actorId: "123e4567-e89b-12d3-a456-426614174032"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440012"
+      actorId: "123e4567-e89b-12d3-a456-426614174032"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440012"
+      actorId: "123e4567-e89b-12d3-a456-426614174033"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440013"
+      actorId: "123e4567-e89b-12d3-a456-426614174033"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440013"
+      actorId: "123e4567-e89b-12d3-a456-426614174034"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440014"
+      actorId: "123e4567-e89b-12d3-a456-426614174034"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440014"
+      actorId: "123e4567-e89b-12d3-a456-426614174035"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440015"
+      actorId: "123e4567-e89b-12d3-a456-426614174035"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440015"
+      actorId: "123e4567-e89b-12d3-a456-426614174036"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440016"
+      actorId: "123e4567-e89b-12d3-a456-426614174036"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440016"
+      actorId: "123e4567-e89b-12d3-a456-426614174037"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440017"
+      actorId: "123e4567-e89b-12d3-a456-426614174037"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440017"
+      actorId: "123e4567-e89b-12d3-a456-426614174038"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440018"
+      actorId: "123e4567-e89b-12d3-a456-426614174038"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440018"
+      actorId: "123e4567-e89b-12d3-a456-426614174039"
+      role: "supporting"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440019"
+      actorId: "123e4567-e89b-12d3-a456-426614174039"
+      role: "main"
+    }
+    {
+      movieId: "550e8400-e29b-41d4-a716-446655440019"
+      actorId: "123e4567-e89b-12d3-a456-426614174020"
+      role: "supporting"
+    }
+  ]
+)
+  user_insertMany(
+    data: [
+      { id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", username: "sherlock_h" }
+      { id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", username: "hercule_p" }
+      { id: "TBedjwCX0Jf955Uuoxk6k74sY0l1", username: "jane_d" }
+    ]
+  )
+
+  review_insertMany(
+    data: [
+      {
+        id: "345e4567-e89b-12d3-a456-426614174000"
+        userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2"
+        movieId: "550e8400-e29b-41d4-a716-446655440000"
+        rating: 5
+        reviewText: "An incredible movie with a mind-blowing plot!"
+        reviewDate_date: { today: true }
+      }
+      {
+        id: "345e4567-e89b-12d3-a456-426614174001"
+        userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2"
+        movieId: "550e8400-e29b-41d4-a716-446655440001"
+        rating: 5
+        reviewText: "A revolutionary film that changed cinema forever."
+        reviewDate_date: { today: true }
+      }
+      {
+        id: "345e4567-e89b-12d3-a456-426614174002"
+        userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1"
+        movieId: "550e8400-e29b-41d4-a716-446655440002"
+        rating: 5
+        reviewText: "A visually stunning and emotionally impactful movie."
+        reviewDate_date: { today: true }
+      }
+      {
+        id: "345e4567-e89b-12d3-a456-426614174003"
+        userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2"
+        movieId: "550e8400-e29b-41d4-a716-446655440003"
+        rating: 4
+        reviewText: "A fantastic superhero film with great performances."
+        reviewDate_date: { today: true }
+      }
+      {
+        id: "345e4567-e89b-12d3-a456-426614174004"
+        userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2"
+        movieId: "550e8400-e29b-41d4-a716-446655440004"
+        rating: 5
+        reviewText: "An amazing film that keeps you on the edge of your seat."
+        reviewDate_date: { today: true }
+      }
+      {
+        id: "345e4567-e89b-12d3-a456-426614174005"
+        userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1"
+        movieId: "550e8400-e29b-41d4-a716-446655440005"
+        rating: 5
+        reviewText: "An absolute classic with unforgettable dialogue."
+        reviewDate_date: { today: true }
+      }
+    ]
+  )
+
+  favorite_movie_insertMany(
+    data: [
+      {
+        userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2"
+        movieId: "550e8400-e29b-41d4-a716-446655440000"
+      }
+      {
+        userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2"
+        movieId: "550e8400-e29b-41d4-a716-446655440001"
+      }
+      {
+        userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1"
+        movieId: "550e8400-e29b-41d4-a716-446655440002"
+      }
+      {
+        userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2"
+        movieId: "550e8400-e29b-41d4-a716-446655440003"
+      }
+      {
+        userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2"
+        movieId: "550e8400-e29b-41d4-a716-446655440004"
+      }
+      {
+        userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1"
+        movieId: "550e8400-e29b-41d4-a716-446655440005"
+      }
+    ]
+  )
+}
diff --git a/dataconnect/dataconnect/optional_vector_embed.gql b/dataconnect/dataconnect/optional_vector_embed.gql
new file mode 100644
index 000000000..6cb8c261b
--- /dev/null
+++ b/dataconnect/dataconnect/optional_vector_embed.gql
@@ -0,0 +1,201 @@
+mutation updateMovieEmbeddings {
+  movie1: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440000"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A group of scientists accidentally open a portal to a parallel universe, causing a rift in time. As the team races to close the portal, they encounter alternate versions of themselves, leading to shocking revelations."
+      }
+    }
+  )
+
+  movie2: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440001"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "In the lawless Wild West, a mysterious gunslinger with a hidden past takes on a corrupt sheriff and his band of outlaws to bring justice to a small town."
+      }
+    }
+  )
+
+  movie3: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440002"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "Two astronauts, stationed on a remote space station, fall in love amidst the isolation of deep space. But when a mysterious signal disrupts their communication, they must find a way to reconnect and survive."
+      }
+    }
+  )
+
+  movie4: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440003"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A private detective gets caught up in a web of lies, deception, and betrayal while investigating the disappearance of a famous actress in 1940s Hollywood."
+      }
+    }
+  )
+
+  movie5: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440004"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "An explorer leads an expedition to a remote island rumored to be home to mythical creatures. As the team ventures deeper into the island, they uncover secrets that change the course of history."
+      }
+    }
+  )
+
+  movie6: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440005"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A tech-savvy teenager discovers a cursed app that brings nightmares to life. As the horrors of the digital world cross into reality, she must find a way to break the curse before it's too late."
+      }
+    }
+  )
+
+  movie7: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440006"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "In a kingdom on the brink of war, a prophecy speaks of an eclipse that will grant power to the rightful ruler. As factions vie for control, a young warrior must decide where his true loyalty lies."
+      }
+    }
+  )
+
+  movie8: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440007"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A brilliant scientist creates a robot with a human heart. As the robot struggles to understand emotions, it becomes entangled in a plot that could change the fate of humanity."
+      }
+    }
+  )
+
+  movie9: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440008"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A legendary warrior rises to challenge the tyrannical rule of a powerful empire. As rebellion brews, the warrior must unite different factions to lead an uprising."
+      }
+    }
+  )
+
+  movie10: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440009"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A talented pianist, who loses his hearing in a tragic accident, must rediscover his passion for music with the help of a young music teacher who believes in him."
+      }
+    }
+  )
+
+  movie11: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440010"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A historian stumbles upon an ancient artifact that reveals hidden truths about an empire long forgotten. As she deciphers the clues, a shadowy organization tries to stop her from unearthing the past."
+      }
+    }
+  )
+
+  movie12: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440011"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "In the future, Earth's best pilots are sent on a mission to explore a mysterious planet beyond the solar system. What they find changes humanity's understanding of the universe forever."
+      }
+    }
+  )
+
+  movie13: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440012"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A young detective with a dark past investigates a series of mysterious murders in a city plagued by corruption. As she digs deeper, she realizes nothing is as it seems."
+      }
+    }
+  )
+
+  movie14: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440013"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "An aging composer struggling with memory loss attempts to complete his final symphony. With the help of a young prodigy, he embarks on an emotional journey through his memories and legacy."
+      }
+    }
+  )
+
+  movie15: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440014"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A knight is chosen by an ancient order to embark on a quest under the light of the full moon. Facing mythical beasts and treacherous landscapes, he seeks a relic that could save his kingdom."
+      }
+    }
+  )
+
+  movie16: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440015"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "When a group of marine biologists descends into the unexplored depths of the ocean, they encounter a terrifying and ancient force. Now, they must survive as the abyss comes alive."
+      }
+    }
+  )
+
+  movie17: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440016"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A special forces operative, presumed dead, returns to avenge his fallen comrades. With nothing to lose, he faces a powerful enemy in a relentless pursuit for justice."
+      }
+    }
+  )
+
+  movie18: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440017"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "Two souls destined to meet across multiple lifetimes struggle to find each other in a chaotic world. With each incarnation, they get closer, but time itself becomes their greatest obstacle."
+      }
+    }
+  )
+
+  movie19: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440018"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A lawyer who can see the outcomes of different timelines must choose between justice and personal gain. When a high-stakes case arises, he faces a moral dilemma that could alter his life forever."
+      }
+    }
+  )
+
+  movie20: movie_update(
+    id: "550e8400-e29b-41d4-a716-446655440019"
+    data: {
+      descriptionEmbedding_embed: {
+        model: "textembedding-gecko@003"
+        text: "A magician-turned-detective uses his skills in illusion to solve crimes. When a series of murders leaves the city in fear, he must reveal the truth hidden behind a veil of deceit."
+      }
+    }
+  )
+}
diff --git a/dataconnect/dataconnect/package.json b/dataconnect/dataconnect/package.json
new file mode 100644
index 000000000..bdf6833e1
--- /dev/null
+++ b/dataconnect/dataconnect/package.json
@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "firebase": "^10.12.4-dataconnect-preview.d986d4bf2"
+  }
+}
diff --git a/dataconnect/dataconnect/schema/schema.gql b/dataconnect/dataconnect/schema/schema.gql
index f25a8a19d..ee8ddbf30 100644
--- a/dataconnect/dataconnect/schema/schema.gql
+++ b/dataconnect/dataconnect/schema/schema.gql
@@ -1,10 +1,10 @@
 # Movies
+# TODO: Fill out Movie table
 type Movie
   # The below parameter values are generated by default with @table, and can be edited manually.
   @table {
   # implicitly calls @col to generates a column name. ex: @col(name: "movie_id")
-  # for UUID fields, @default(expr: "uuidV4()") is implicitly called
-  id: UUID!
+  id: UUID! @default(expr: "uuidV4()")
   title: String!
   imageUrl: String!
   releaseYear: Int
@@ -12,15 +12,16 @@ type Movie
   rating: Float
   description: String
   tags: [String]
-  # Vectors -- uncomment the line below to enable vector search
-  descriptionEmbedding: Vector @col(size:768)
+  # descriptionEmbedding: Vector @col(size:768) # Enables vector search
 }
 
 # Movie Metadata
 # Movie - MovieMetadata is a one-to-one relationship
+# TODO: Fill out MovieMetadata table
 type MovieMetadata
   @table {
-  # @ref creates a field in the current table (MovieMetadata) that holds the primary key of the referenced type
+  # @ref creates a field in the current table (MovieMetadata)
+  # It is a reference that holds the primary key of the referenced type
   # In this case, @ref(fields: "movieId", references: "id") is implied
   movie: Movie! @ref
   # movieId: UUID <- this is created by the above @ref
@@ -30,6 +31,7 @@ type MovieMetadata
 # Actors
 # Suppose an actor can participate in multiple movies and movies can have multiple actors
 # Movie - Actors (or vice versa) is a many to many relationship
+# TODO: Fill out Actor table
 type Actor @table {
   id: UUID!
   imageUrl: String! 
@@ -39,6 +41,7 @@ type Actor @table {
 # Users
 # Suppose a user can leave reviews for movies
 # user-reviews is a one to many relationship, movie-reviews is a one to many relationship, movie:user is a many to many relationship
+# TODO: Fill out User table
 type User
   @table {
   id: String! @col(name: "user_auth")
@@ -49,6 +52,7 @@ type User
 }
 
 # Reviews
+# TODO: Fill out Review table
 type Review @table(name: "Reviews", key: ["movie", "user"]) {
   id: UUID! @default(expr: "uuidV4()")
   user: User!
@@ -61,6 +65,7 @@ type Review @table(name: "Reviews", key: ["movie", "user"]) {
 # Join table for many-to-many relationship for movies and actors
 # The 'key' param signifies the primary key(s) of this table
 # In this case, the keys are [movieId, actorId], the generated fields of the reference types [movie, actor]
+# TODO: Fill out MovieActor table
 type MovieActor @table(key: ["movie", "actor"]) {
   # @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
   # In this case, @ref(fields: "id") is implied
@@ -74,16 +79,10 @@ type MovieActor @table(key: ["movie", "actor"]) {
 }
 
 # Join table for many-to-many relationship for users and favorite movies
+# TODO: Fill out FavoriteMovie table
 type FavoriteMovie
   @table(name: "FavoriteMovies", singular: "favorite_movie", plural: "favorite_movies", key: ["user", "movie"]) {
   # @ref is implicit
   user: User!
   movie: Movie!
 }
-
-# Join table for many-to-many relationship for users and favorite actors
-type FavoriteActor
-  @table(name: "FavoriteActors", singular: "favorite_actor", plural: "favorite_actors", key: ["user", "actor"]) {
-  user: User!
-  actor: Actor!
-}
diff --git a/dataconnect/firebase.json b/dataconnect/firebase.json
index c46f2c51d..d5bedc4e8 100644
--- a/dataconnect/firebase.json
+++ b/dataconnect/firebase.json
@@ -4,7 +4,7 @@
       "port": 9099
     },
     "hosting": {
-      "port": 5000
+      "port": 5059
     },
     "dataconnect": {
       "port": 9399
@@ -18,14 +18,11 @@
     "source": "./dataconnect"
   },
   "hosting": {
-    "source": "app",
+    "public": "app/dist",
     "ignore": [
       "firebase.json",
       "**/.*",
       "**/node_modules/**"
-    ],
-    "frameworksBackend": {
-      "region": "us-central1"
-    }
+    ]
   }
 }

From 7646b95c572ed272c1bb6fb10f4ab817f0d8d674 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Tue, 1 Oct 2024 10:33:53 -0400
Subject: [PATCH 50/82] fix: update readme

---
 dataconnect/README.md | 144 ++++++++++++++++++++++++++++++------------
 1 file changed, 104 insertions(+), 40 deletions(-)

diff --git a/dataconnect/README.md b/dataconnect/README.md
index bbb1aac51..eedfa8353 100644
--- a/dataconnect/README.md
+++ b/dataconnect/README.md
@@ -1,28 +1,19 @@
-Firebase DataConnect Quickstart
-=======================================
+# Firebase DataConnect Quickstart
 
-Introduction
-------------
+## Introduction
 
-This is a sample app for the preview version of the Firebase DataConnect.
-This service is currently in Private Preview at no cost for a limited time. Sign up for the program at [Firebase Data Connect](https://firebase.google.com/products/data-connect).
-This quickstart will not work if you don't have access to the preview.
+This is a sample app for the preview version of Firebase DataConnect. This service is currently in Private Preview at no cost for a limited time. Sign up for the program at [Firebase Data Connect](https://firebase.google.com/products/data-connect). This quickstart will not work if you don't have access to the preview.
 
-<!-- Introduction
-------------
+## Getting Started with Firebase DataConnect
 
-[Read more about Firebase DataConnect ](https://firebase.google.com/docs/dataconnect/) -->
-
-#  Getting Started with Firebase Data Connect
----------------
-Follow these steps to get up and running with Firebase Data Connect. For more detailed instructions, check out the [official documentation](https://firebase.google.com/docs/data-connect/quickstart).
+Follow these steps to get up and running with Firebase DataConnect. For more detailed instructions, check out the [official documentation](https://firebase.google.com/docs/data-connect/quickstart).
 
 ### 1. Create a New Data Connect Service and Cloud SQL Instance
 
-1. Open [Firebase Data Connect](https://console.firebase.google.com/u/0/project/_/dataconnect) in your project in Firebase Console and select Get Started.
-2. Create a new Data Connect service and a Cloud SQL instance. Ensure the Blaze plan is active. Pricing details can be found at [Firebase Pricing](https://firebase.google.com/pricing).
-3. Select your server region, if you wish to use vector search, make sure to select `us-central1` region.
-4. Allow some time for the Cloud SQL instance to be provisioned. After it's provisioned, the instance can be managed in the [Cloud Console](https://pantheon.corp.google.com/sql).
+1. Open [Firebase Data Connect](https://console.firebase.google.com/u/0/project/_/dataconnect) in your Firebase Console project and select **Get Started**.
+2. Create a new Data Connect service and a Cloud SQL instance. Ensure the Blaze plan is active. Find pricing details at [Firebase Pricing](https://firebase.google.com/pricing).
+3. Choose your server region. If you plan to use vector search, select `us-central1`.
+4. Wait for the Cloud SQL instance to be provisioned. Once it's ready, you can manage it in the [Cloud Console](https://pantheon.corp.google.com/sql).
 
 ### 2. Set Up Firebase CLI
 
@@ -32,37 +23,110 @@ Ensure the Firebase CLI is installed and up to date:
 npm install -g firebase-tools
 ```
 
-### 3. Cloning the repository
-This repository contains the quickstart to get started with the functionalities of Data Connect.
+### 3. Cloning the Repository
+
+This repository contains the quickstart to help you explore the functionalities of DataConnect.
 
 1. Clone this repository to your local machine.
-2. cd to the `dataconnect` folder, and initialize your Firebase project with `firebase init dataconnect`. Overwrite only dataconnect.yaml when prompted, do not overwrite any other dataconnect files.
-(Optional): If you intend on using other Firebase features, run `firebase init` instead, and select both DataConnect options as well as any feature you intend to use.
-3. Replace variables in `.env` with your project-specific values.
-4. Allow domains for Firebase Auth in your [project console](https://console.firebase.google.com/project/_/authentication/settings) (e.g. http://127.0.0.1).
+2. Navigate to the `dataconnect` folder and initialize your Firebase project:
+
+    ```bash
+    cd ./dataconnect
+    ```
 
-### 4. Running queries and mutations in VS Code
-The VSCode Firebase Extension allows you to generate Firebase Data Connect SDK code, run queries/mutations, and deploy Firebase Data Connect with a click. Alternatively, see below for CLI commands.
+   *(Optional)*: If you plan to use other Firebase features, run `firebase init` instead, and select both DataConnect options as well as any additional feature you want to use.
+
+### 4. Installing VS Code Extension
 
 1. Install [VS Code](https://code.visualstudio.com/).
-2. Download the [Firebase extension](https://firebasestorage.googleapis.com/v0/b/firemat-preview-drop/o/vsix%2Ffirebase-vscode-latest.vsix?alt=media) and [install](https://code.visualstudio.com/docs/editor/extension-marketplace#_install-an-extension) it.
-3. Open this quickstart in VS code, and in the left pane of the Firebase extension, and log in with your Firebase account.
-(Optional): If your Firebase project was not initialized in the last section, you can click `Run firebase init` and select `Data Connect` to initialize.
-4. Click on deploy to deploy your schema to your cloud SQL instance. Or run `firebase deploy --only dataconnect` (this will also activate vectors search if it's enabled in the schema).
-5. Running the VSCode extension should automatically start the DataConnect emulators. If you see an emulators error, try running `firebase emulators:start dataconnect` manually.
+2. Download and install the [Firebase DataConnect extension](https://marketplace.visualstudio.com/items?itemName=GoogleCloudTools.firebase-dataconnect-vscode).
+3. Open this quickstart in VS Code and log in to your Firebase account using the Firebase extension.
+4. In the Firebase DataConnect VSCode extension, click **Start Emulators** and confirm that the emulators are running in the terminal.
 
-Now you should be able to deploy your schema, run mutations/queries, generate SDK code, and view your application locally.
+### 5. Populating the Database
 
-### 5. Populating the database
-1. Run `1_movie_insert.gql`, `2_actor_insert.gql`, `3_movie_actor_insert.gql`, and `4_user_favorites_review_insert.gql` files in the `./dataconnect` directory in order using the VS code extension, 
+1. In VS Code, open `dataconnect/movie_insert.gql`. Ensure the emulators in the Firebase DataConnect extension are running.
+2. You should see a **Run (local)** button at the top of the file. Click this to insert mock movie data into your database.
+3. Check the DataConnect Execution terminal to confirm that the data was added successfully.
 
-### 6. Running the app
+### 6. Running the App
 
-1. `cd` into the src folder, and run `npm run dev` to start the localhost web app.
-(Optional): To use the Firebase Auth emulator, run `firebase emulators:start` and uncomment the `connectAuthEmulator` function in `app/src/lib/firebase.ts`.
+1. Navigate to the `app` folder and install dependencies:
 
-License
--------
+    ```bash
+    cd ./app
+    npm install
+    ```
 
-© Google, 2024. Licensed under an [Apache-2](../../LICENSE) license.
+2. Start the app:
+
+    ```bash
+    npm run dev
+    ```
+
+### 7. Deployment
+
+1. Create a Web App in the [Firebase Console](https://console.firebase.google.com) and take note of your App ID.
+2. In the Firebase Console, click on **Add App**. You can ignore the SDK setup for now, but note the generated `firebaseConfig` object.
+3. Replace the `firebaseConfig` in `app/src/lib/firebase.tsx`:
+
+    ```javascript
+    const firebaseConfig = {
+      apiKey: "API_KEY",
+      authDomain: "PROJECT_ID.firebaseapp.com",
+      projectId: "PROJECT_ID",
+      storageBucket: "PROJECT_ID.appspot.com",
+      messagingSenderId: "SENDER_ID",
+      appId: "APP_ID"
+    };
+    ```
+
+4. Build the web app for hosting deployment:
+
+    ```bash
+    cd ./app
+    npm run build
+    ```
 
+5. Set up Firebase Authentication with Google Sign-In. Optionally, allow domains for [Firebase Auth](https://firebase.google.com/docs/auth/web/hosting) in your project console (e.g., `http://127.0.0.1`).
+6. Allow domains for Firebase Auth in your [project console](https://console.firebase.google.com/project/_/authentication/settings) (e.g., `http://127.0.0.1`).
+7. In `dataconnect/dataconnect.yaml`, ensure that your `instanceId`, `database`, and `serviceId` match your project configuration:
+
+    ```yaml
+    specVersion: "v1alpha"
+    serviceId: "your-service-id"
+    location: "us-central1"
+    schema:
+      source: "./schema"
+      datasource:
+        postgresql:
+          database: "your-database-id"
+          cloudSql:
+            instanceId: "your-instance-id"
+    connectorDirs: ["./movie-connector"]
+    ```
+
+8. Deploy your project:
+
+    ```bash
+    npm install -g firebase-tools
+    firebase login --reauth
+    firebase use --add
+    firebase deploy --only dataconnect,hosting
+    ```
+
+9. To compare schema changes, run:
+
+    ```bash
+    firebase dataconnect:sql:diff
+    ```
+
+10. If the changes are acceptable, apply them with:
+
+    ```bash
+    firebase dataconnect:sql:migrate
+    ```
+
+## License
+
+© Google, 2024. Licensed under an [Apache-2](../../LICENSE) license.

From f4bbb6ffbb365b2bc92cd05279e3dd329ddaccd8 Mon Sep 17 00:00:00 2001
From: Cynthia Wang <hyacccint@gmail.com>
Date: Tue, 1 Oct 2024 16:42:44 -0400
Subject: [PATCH 51/82] fix: remove vector search from dataconnect

---
 dataconnect/app/src/lib/MovieService.tsx | 37 ++++--------------------
 dataconnect/app/src/pages/Movie.tsx      |  4 +--
 2 files changed, 8 insertions(+), 33 deletions(-)

diff --git a/dataconnect/app/src/lib/MovieService.tsx b/dataconnect/app/src/lib/MovieService.tsx
index 97e9a200b..2337e9fde 100644
--- a/dataconnect/app/src/lib/MovieService.tsx
+++ b/dataconnect/app/src/lib/MovieService.tsx
@@ -11,10 +11,10 @@ import { getIfFavoritedMovie } from "@movie/dataconnect";
 
 import { searchAll, SearchAllData } from "@movie/dataconnect";
 
-import {
-  searchMovieDescriptionUsingL2similarity,
-  SearchMovieDescriptionUsingL2similarityData,
-} from "@movie/dataconnect";
+// import {
+//   searchMovieDescriptionUsingL2similarity,
+//   SearchMovieDescriptionUsingL2similarityData,
+// } from "@movie/dataconnect";
 
 import { onAuthStateChanged, User } from "firebase/auth";
 
@@ -201,31 +201,6 @@ export const handleSearchAll = async (
 // Perform vector-based search for movies based on description
 export const searchMoviesByDescription = async (
   query: string
-): Promise<
-  | SearchMovieDescriptionUsingL2similarityData["movies_descriptionEmbedding_similarity"]
-  | null
-> => {
-  try {
-    const response = await searchMovieDescriptionUsingL2similarity({ query });
-    return response.data.movies_descriptionEmbedding_similarity;
-  } catch (error) {
-    console.error("Error fetching movie descriptions:", error);
-    return null;
-  }
-};
-
-export const fetchSimilarMovies = async (
-  description: string
-): Promise<
-  | SearchMovieDescriptionUsingL2similarityData["movies_descriptionEmbedding_similarity"]
-  | null
-> => {
-  try {
-    const response = await searchMovieDescriptionUsingL2similarity({
-      query: description,
-    });
-    return response?.data?.movies_descriptionEmbedding_similarity;
-  } catch (error) {
-    console.error("Error fetching similar movies:", error);
-  }
+): Promise<any[]> => {
+  return [];
 };
diff --git a/dataconnect/app/src/pages/Movie.tsx b/dataconnect/app/src/pages/Movie.tsx
index fd78bb256..959345a68 100644
--- a/dataconnect/app/src/pages/Movie.tsx
+++ b/dataconnect/app/src/pages/Movie.tsx
@@ -11,7 +11,7 @@ import {
   handleDeleteFavoritedMovie,
   handleAddReview,
   handleDeleteReview,
-  fetchSimilarMovies,
+  searchMoviesByDescription
 } from "@/lib/MovieService";
 import MovieCard from "@/components/moviecard";
 
@@ -50,7 +50,7 @@ export default function MoviePage() {
           const userReview = movieData.reviews.find(
             (review) => review.user.id === authUser?.uid
           );
-          fetchSimilarMovies(movieData.description).then((similarMovies) => {
+          searchMoviesByDescription(movieData.description).then((similarMovies) => {
             const similarResults = similarMovies?.filter(
               (movie) => movie.id !== movieData.id
             );

From 180fba78db996c1ea152555f9f5f37fe9fbad0f5 Mon Sep 17 00:00:00 2001
From: David East <davideast@users.noreply.github.com>
Date: Wed, 2 Oct 2024 12:49:54 -0400
Subject: [PATCH 52/82] Data Connect IDX template (#834)

* idx template

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* tmp

* .

* icon

* Update dataconnect/app/vite.config.idx.ts

Co-authored-by: Maneesh Tewani <maneesht@users.noreply.github.com>

* Update dataconnect/app/src/vite.config.idx.ts

Co-authored-by: Maneesh Tewani <maneesht@users.noreply.github.com>

---------

Co-authored-by: Maneesh Tewani <maneesht@users.noreply.github.com>
---
 .gitignore                               |  2 +
 .idx/dev.nix                             | 56 ++++++++++++++++++++++++
 .vscode/settings.json                    |  4 ++
 dataconnect/.idx/dev.nix                 | 45 +++++++++++++++++++
 dataconnect/.vscode/settings.json        | 14 ++++++
 dataconnect/app/src/lib/firebase.idx.tsx | 40 +++++++++++++++++
 dataconnect/app/src/vite.config.idx.ts   | 22 ++++++++++
 dataconnect/app/vite.config.idx.ts       | 22 ++++++++++
 dataconnect/idx-template.json            | 10 +++++
 dataconnect/idx-template.nix             | 32 ++++++++++++++
 10 files changed, 247 insertions(+)
 create mode 100644 .idx/dev.nix
 create mode 100644 .vscode/settings.json
 create mode 100644 dataconnect/.idx/dev.nix
 create mode 100644 dataconnect/.vscode/settings.json
 create mode 100644 dataconnect/app/src/lib/firebase.idx.tsx
 create mode 100644 dataconnect/app/src/vite.config.idx.ts
 create mode 100644 dataconnect/app/vite.config.idx.ts
 create mode 100644 dataconnect/idx-template.json
 create mode 100644 dataconnect/idx-template.nix

diff --git a/.gitignore b/.gitignore
index dee8c505e..84019a848 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@
 dist/
 **/ui-debug.log
 .next
+/template-test
+.oops
diff --git a/.idx/dev.nix b/.idx/dev.nix
new file mode 100644
index 000000000..8c1d56479
--- /dev/null
+++ b/.idx/dev.nix
@@ -0,0 +1,56 @@
+# To learn more about how to use Nix to configure your environment
+# see: https://developers.google.com/idx/guides/customize-idx-env
+{ pkgs, ... }: {
+  # Which nixpkgs channel to use.
+  channel = "stable-23.11"; # or "unstable"
+
+  # Use https://search.nixos.org/packages to find packages
+  packages = [
+    # pkgs.go
+    # pkgs.python311
+    # pkgs.python311Packages.pip
+    # pkgs.nodejs_20
+    # pkgs.nodePackages.nodemon
+  ];
+
+  idx.internal.templates-cli.enable = true;
+  # Sets environment variables in the workspace
+  env = {};
+  idx = {
+    # Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
+    extensions = [
+      # "vscodevim.vim"
+    ];
+
+    # Enable previews
+    previews = {
+      enable = true;
+      previews = {
+        # web = {
+        #   # Example: run "npm run dev" with PORT set to IDX's defined port for previews,
+        #   # and show it in IDX's web preview panel
+        #   command = ["npm" "run" "dev"];
+        #   manager = "web";
+        #   env = {
+        #     # Environment variables to set for your server
+        #     PORT = "$PORT";
+        #   };
+        # };
+      };
+    };
+
+    # Workspace lifecycle hooks
+    workspace = {
+      # Runs when a workspace is first created
+      onCreate = {
+        # Example: install JS dependencies from NPM
+        # npm-install = "npm install";
+      };
+      # Runs when the workspace is (re)started
+      onStart = {
+        # Example: start a background task to watch and re-build backend code
+        # watch-backend = "npm run watch-backend";
+      };
+    };
+  };
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..e37be69f0
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,4 @@
+{
+  "IDX.aI.enableInlineCompletion": true,
+  "IDX.aI.enableCodebaseIndexing": true
+}
\ No newline at end of file
diff --git a/dataconnect/.idx/dev.nix b/dataconnect/.idx/dev.nix
new file mode 100644
index 000000000..ea67bb36c
--- /dev/null
+++ b/dataconnect/.idx/dev.nix
@@ -0,0 +1,45 @@
+{ pkgs, ... }: {
+  channel = "stable-23.11";
+  packages = [
+    pkgs.nodejs_20
+  ];
+
+  env = {
+    POSTGRESQL_CONN_STRING = "postgresql://user:mypassword@localhost:5432/dataconnect?sslmode=disable";
+  };
+  
+  idx.extensions = [
+    "mtxr.sqltools"
+    "mtxr.sqltools-driver-pg"
+    "GraphQL.vscode-graphql-syntax"
+    "GoogleCloudTools.firebase-dataconnect-vscode"
+  ];
+
+  services.postgres = {
+    extensions = ["pgvector"];
+    enable = true;
+  };
+  
+  idx = {
+    workspace = {
+      onCreate = {
+        update-firebase = "npm install -D firebase-tools";
+        postgres = ''
+          psql --dbname=postgres -c "ALTER USER \"user\" PASSWORD 'mypassword';"
+          psql --dbname=postgres -c "CREATE DATABASE dataconnect;"
+          psql --dbname=dataconnect -c "CREATE EXTENSION vector;"
+        '';
+        npm-install = "cd app && npm i && npm i firebase@latest";
+      };
+    };
+    previews = {
+      enable = true;
+      previews = {
+        web = {
+          command = ["npm" "run" "dev" "--prefix" "./app" "--" "--port" "$PORT" "--host" "0.0.0.0"];
+          manager = "web";
+        };
+      };
+    };
+  };
+}
\ No newline at end of file
diff --git a/dataconnect/.vscode/settings.json b/dataconnect/.vscode/settings.json
new file mode 100644
index 000000000..ba1ba909e
--- /dev/null
+++ b/dataconnect/.vscode/settings.json
@@ -0,0 +1,14 @@
+{
+  "sqltools.connections": [
+    {
+      "previewLimit": 50,
+      "server": "localhost",
+      "port": 5432,
+      "driver": "PostgreSQL",
+      "name": "Main",
+      "database": "dataconnect",
+      "username": "user",
+      "password": "mypassword"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/dataconnect/app/src/lib/firebase.idx.tsx b/dataconnect/app/src/lib/firebase.idx.tsx
new file mode 100644
index 000000000..8f2634bcf
--- /dev/null
+++ b/dataconnect/app/src/lib/firebase.idx.tsx
@@ -0,0 +1,40 @@
+import { initializeApp, getApps } from "firebase/app";
+import { getAuth } from "firebase/auth";
+import {
+  connectDataConnectEmulator,
+  getDataConnect,
+} from "firebase/data-connect";
+import { connectorConfig } from '@movie/dataconnect';
+import { createContext } from "react";
+
+const firebaseConfig = {
+  apiKey: "API_KEY",
+  authDomain: "PROJECT_ID.firebaseapp.com",
+  projectId: "PROJECT_ID",
+  storageBucket: "PROJECT_ID.appspot.com",
+  messagingSenderId: "SENDER_ID",
+  appId: "APP_ID"
+};
+
+const firebaseApp =
+  getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
+
+const auth = getAuth(firebaseApp);
+const dataconnect = getDataConnect(firebaseApp, connectorConfig);
+
+if (process.env.NODE_ENV === "development") {
+  connectDataConnectEmulator(
+    dataconnect, 
+    window.location.hostname,
+    undefined,
+    true
+  );
+}
+
+const AuthContext = createContext(auth);
+
+function AuthProvider({ children }: { children: React.ReactNode }) {
+  return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>;
+}
+
+export { AuthContext, AuthProvider };
diff --git a/dataconnect/app/src/vite.config.idx.ts b/dataconnect/app/src/vite.config.idx.ts
new file mode 100644
index 000000000..c2417fbfc
--- /dev/null
+++ b/dataconnect/app/src/vite.config.idx.ts
@@ -0,0 +1,22 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import path from 'path';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [react()],
+  resolve: {
+    alias: {
+      '@': path.resolve(__dirname, 'src'),
+    },
+  },
+  server: {
+    proxy: {
+      '/v1beta/projects': {
+        target: 'http://127.0.0.1:9399',
+        changeOrigin: true,
+        rewrite: (path) => path.replace(/^\/v1beta\/projects/, '/v1beta/projects'),
+      },
+    },
+  },
+})
diff --git a/dataconnect/app/vite.config.idx.ts b/dataconnect/app/vite.config.idx.ts
new file mode 100644
index 000000000..c2417fbfc
--- /dev/null
+++ b/dataconnect/app/vite.config.idx.ts
@@ -0,0 +1,22 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import path from 'path';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [react()],
+  resolve: {
+    alias: {
+      '@': path.resolve(__dirname, 'src'),
+    },
+  },
+  server: {
+    proxy: {
+      '/v1beta/projects': {
+        target: 'http://127.0.0.1:9399',
+        changeOrigin: true,
+        rewrite: (path) => path.replace(/^\/v1beta\/projects/, '/v1beta/projects'),
+      },
+    },
+  },
+})
diff --git a/dataconnect/idx-template.json b/dataconnect/idx-template.json
new file mode 100644
index 000000000..c3bfcea0e
--- /dev/null
+++ b/dataconnect/idx-template.json
@@ -0,0 +1,10 @@
+{
+  "name": "Data Connect",
+  "description": "Build a new web app using Data Connect",
+  "categories": [
+    "Web app",
+    "Databases"
+  ],
+  "icon": "https://www.gstatic.com/monospace/240513/logo_firebase.svg",
+  "publisher": "Google LLC"
+}
\ No newline at end of file
diff --git a/dataconnect/idx-template.nix b/dataconnect/idx-template.nix
new file mode 100644
index 000000000..451937da6
--- /dev/null
+++ b/dataconnect/idx-template.nix
@@ -0,0 +1,32 @@
+/*
+  idx-template \
+  --output-dir /home/user/quickstart-js/dataconnect \
+  -a '{}' \
+  --workspace-name 'dataconnect' \
+  /home/user/quickstart-js/template-test \
+  --failure-report
+
+*/
+
+{pkgs, ... }: {
+  packages = [];
+  bootstrap = ''
+    mkdir "$out" 
+    mkdir "$out"/.idx
+    mkdir "$out"/app
+    mkdir "$out"/dataconnect
+    mkdir "$out"/.vscode
+
+    cp ${.idx/dev.nix} "$out"/.idx/dev.nix
+    cp -a ${./app}/* "$out"/app/
+    cp -a ${./dataconnect}/* "$out"/dataconnect/
+
+    cp ${./.vscode/settings.json} "$out"/.vscode/settings.json
+    cp ${./firebase.json} "$out"/firebase.json
+    cp ${./README.md} "$out"/README.md
+    cp ${./.gitignore} "$out"/.gitignore
+    chmod -R u+w "$out" 
+    mv "$out"/app/src/lib/firebase.idx.tsx "$out"/app/src/lib/firebase.tsx  
+    mv "$out"/app/vite.config.idx.ts "$out"/app/vite.config.ts 
+  '';
+}
\ No newline at end of file

From 7c422fd79bf0b27bee98c6ef0b5bc4d433833f7c Mon Sep 17 00:00:00 2001
From: David East <davideast@users.noreply.github.com>
Date: Thu, 3 Oct 2024 10:17:22 -0400
Subject: [PATCH 53/82] Show Emulator Message if not running (#835)

* idx template

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* tmp

* .

* icon

* Update dataconnect/app/vite.config.idx.ts

Co-authored-by: Maneesh Tewani <maneesht@users.noreply.github.com>

* Update dataconnect/app/src/vite.config.idx.ts

Co-authored-by: Maneesh Tewani <maneesht@users.noreply.github.com>

* Display Emulator Message

---------

Co-authored-by: Maneesh Tewani <maneesht@users.noreply.github.com>
---
 dataconnect/.gitignore                        |    3 +-
 dataconnect/app/package.json                  |    2 +-
 .../src/lib/dataconnect-sdk/esm/index.esm.js  |  158 +
 .../src/lib/dataconnect-sdk/esm/package.json  |    1 +
 .../app/src/lib/dataconnect-sdk/index.cjs.js  |  184 +
 .../app/src/lib/dataconnect-sdk/index.d.ts    |  392 ++
 .../app/src/lib/dataconnect-sdk/package.json  |   25 +
 dataconnect/app/src/pages/Home.tsx            |   28 +-
 package-lock.json                             | 5864 ++++++++++++++++-
 package.json                                  |    1 +
 10 files changed, 6347 insertions(+), 311 deletions(-)
 create mode 100644 dataconnect/app/src/lib/dataconnect-sdk/esm/index.esm.js
 create mode 100644 dataconnect/app/src/lib/dataconnect-sdk/esm/package.json
 create mode 100644 dataconnect/app/src/lib/dataconnect-sdk/index.cjs.js
 create mode 100644 dataconnect/app/src/lib/dataconnect-sdk/index.d.ts
 create mode 100644 dataconnect/app/src/lib/dataconnect-sdk/package.json

diff --git a/dataconnect/.gitignore b/dataconnect/.gitignore
index 5f24225c0..3c8afea92 100644
--- a/dataconnect/.gitignore
+++ b/dataconnect/.gitignore
@@ -46,7 +46,6 @@ build/Release
 
 # Dependency directories
 node_modules/
-app/src/lib/dataconnect-sdk/
 app/package-lock.json
 
 # Optional npm cache directory
@@ -67,3 +66,5 @@ app/package-lock.json
 # dotenv environment variables file
 .next
 .dataconnect
+
+.idx/.data
diff --git a/dataconnect/app/package.json b/dataconnect/app/package.json
index 00e022c24..262a701b1 100644
--- a/dataconnect/app/package.json
+++ b/dataconnect/app/package.json
@@ -12,7 +12,7 @@
   "dependencies": {
     "@movie/dataconnect": "file:src/lib/dataconnect-sdk",
     "dotenv": "^16.4.5",
-    "firebase": "^10.12.4-dataconnect-preview.d986d4bf2",
+    "firebase": "^10.14.0",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "react-icons": "^5.2.1",
diff --git a/dataconnect/app/src/lib/dataconnect-sdk/esm/index.esm.js b/dataconnect/app/src/lib/dataconnect-sdk/esm/index.esm.js
new file mode 100644
index 000000000..9e4152284
--- /dev/null
+++ b/dataconnect/app/src/lib/dataconnect-sdk/esm/index.esm.js
@@ -0,0 +1,158 @@
+import { getDataConnect, queryRef, executeQuery, mutationRef, executeMutation, validateArgs } from 'firebase/data-connect';
+export const OrderDirection = {
+
+  ASC: "ASC",
+
+  DESC: "DESC",
+}
+
+export const connectorConfig = {
+  connector: 'movie-connector',
+  service: 'fdc-quickstart-web',
+  location: 'us-central1'
+};
+
+export function upsertUserRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'UpsertUser', inputVars);
+}
+export function upsertUser(dcOrVars, vars) {
+  return executeMutation(upsertUserRef(dcOrVars, vars));
+}
+export function addFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'AddFavoritedMovie', inputVars);
+}
+export function addFavoritedMovie(dcOrVars, vars) {
+  return executeMutation(addFavoritedMovieRef(dcOrVars, vars));
+}
+export function deleteFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'DeleteFavoritedMovie', inputVars);
+}
+export function deleteFavoritedMovie(dcOrVars, vars) {
+  return executeMutation(deleteFavoritedMovieRef(dcOrVars, vars));
+}
+export function addReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'AddReview', inputVars);
+}
+export function addReview(dcOrVars, vars) {
+  return executeMutation(addReviewRef(dcOrVars, vars));
+}
+export function updateReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'UpdateReview', inputVars);
+}
+export function updateReview(dcOrVars, vars) {
+  return executeMutation(updateReviewRef(dcOrVars, vars));
+}
+export function deleteReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'DeleteReview', inputVars);
+}
+export function deleteReview(dcOrVars, vars) {
+  return executeMutation(deleteReviewRef(dcOrVars, vars));
+}
+export function listMoviesRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'ListMovies', inputVars);
+}
+export function listMovies(dcOrVars, vars) {
+  return executeQuery(listMoviesRef(dcOrVars, vars));
+}
+export function getMovieByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'GetMovieById', inputVars);
+}
+export function getMovieById(dcOrVars, vars) {
+  return executeQuery(getMovieByIdRef(dcOrVars, vars));
+}
+export function getActorByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'GetActorById', inputVars);
+}
+export function getActorById(dcOrVars, vars) {
+  return executeQuery(getActorByIdRef(dcOrVars, vars));
+}
+export function getCurrentUserRef(dc) {
+  const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'GetCurrentUser');
+}
+export function getCurrentUser(dc) {
+  return executeQuery(getCurrentUserRef(dc));
+}
+export function getIfFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'GetIfFavoritedMovie', inputVars);
+}
+export function getIfFavoritedMovie(dcOrVars, vars) {
+  return executeQuery(getIfFavoritedMovieRef(dcOrVars, vars));
+}
+export function searchAllRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'SearchAll', inputVars);
+}
+export function searchAll(dcOrVars, vars) {
+  return executeQuery(searchAllRef(dcOrVars, vars));
+}
diff --git a/dataconnect/app/src/lib/dataconnect-sdk/esm/package.json b/dataconnect/app/src/lib/dataconnect-sdk/esm/package.json
new file mode 100644
index 000000000..7c34deb58
--- /dev/null
+++ b/dataconnect/app/src/lib/dataconnect-sdk/esm/package.json
@@ -0,0 +1 @@
+{"type":"module"}
\ No newline at end of file
diff --git a/dataconnect/app/src/lib/dataconnect-sdk/index.cjs.js b/dataconnect/app/src/lib/dataconnect-sdk/index.cjs.js
new file mode 100644
index 000000000..234a7f85e
--- /dev/null
+++ b/dataconnect/app/src/lib/dataconnect-sdk/index.cjs.js
@@ -0,0 +1,184 @@
+const { getDataConnect, queryRef, executeQuery, mutationRef, executeMutation, validateArgs } = require('firebase/data-connect');
+const OrderDirection = {
+
+  ASC: "ASC",
+
+  DESC: "DESC",
+}
+  exports.OrderDirection = OrderDirection;
+
+const connectorConfig = {
+  connector: 'movie-connector',
+  service: 'fdc-quickstart-web',
+  location: 'us-central1'
+};
+exports.connectorConfig = connectorConfig;
+
+function upsertUserRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'UpsertUser', inputVars);
+}
+exports.upsertUserRef = upsertUserRef;
+exports.upsertUser = function upsertUser(dcOrVars, vars) {
+  return executeMutation(upsertUserRef(dcOrVars, vars));
+};
+
+function addFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'AddFavoritedMovie', inputVars);
+}
+exports.addFavoritedMovieRef = addFavoritedMovieRef;
+exports.addFavoritedMovie = function addFavoritedMovie(dcOrVars, vars) {
+  return executeMutation(addFavoritedMovieRef(dcOrVars, vars));
+};
+
+function deleteFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'DeleteFavoritedMovie', inputVars);
+}
+exports.deleteFavoritedMovieRef = deleteFavoritedMovieRef;
+exports.deleteFavoritedMovie = function deleteFavoritedMovie(dcOrVars, vars) {
+  return executeMutation(deleteFavoritedMovieRef(dcOrVars, vars));
+};
+
+function addReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'AddReview', inputVars);
+}
+exports.addReviewRef = addReviewRef;
+exports.addReview = function addReview(dcOrVars, vars) {
+  return executeMutation(addReviewRef(dcOrVars, vars));
+};
+
+function updateReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'UpdateReview', inputVars);
+}
+exports.updateReviewRef = updateReviewRef;
+exports.updateReview = function updateReview(dcOrVars, vars) {
+  return executeMutation(updateReviewRef(dcOrVars, vars));
+};
+
+function deleteReviewRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return mutationRef(dcInstance, 'DeleteReview', inputVars);
+}
+exports.deleteReviewRef = deleteReviewRef;
+exports.deleteReview = function deleteReview(dcOrVars, vars) {
+  return executeMutation(deleteReviewRef(dcOrVars, vars));
+};
+
+function listMoviesRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'ListMovies', inputVars);
+}
+exports.listMoviesRef = listMoviesRef;
+exports.listMovies = function listMovies(dcOrVars, vars) {
+  return executeQuery(listMoviesRef(dcOrVars, vars));
+};
+
+function getMovieByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'GetMovieById', inputVars);
+}
+exports.getMovieByIdRef = getMovieByIdRef;
+exports.getMovieById = function getMovieById(dcOrVars, vars) {
+  return executeQuery(getMovieByIdRef(dcOrVars, vars));
+};
+
+function getActorByIdRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'GetActorById', inputVars);
+}
+exports.getActorByIdRef = getActorByIdRef;
+exports.getActorById = function getActorById(dcOrVars, vars) {
+  return executeQuery(getActorByIdRef(dcOrVars, vars));
+};
+
+function getCurrentUserRef(dc) {
+  const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'GetCurrentUser');
+}
+exports.getCurrentUserRef = getCurrentUserRef;
+exports.getCurrentUser = function getCurrentUser(dc) {
+  return executeQuery(getCurrentUserRef(dc));
+};
+
+function getIfFavoritedMovieRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'GetIfFavoritedMovie', inputVars);
+}
+exports.getIfFavoritedMovieRef = getIfFavoritedMovieRef;
+exports.getIfFavoritedMovie = function getIfFavoritedMovie(dcOrVars, vars) {
+  return executeQuery(getIfFavoritedMovieRef(dcOrVars, vars));
+};
+
+function searchAllRef(dcOrVars, vars) {
+  const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true);
+  if('_useGeneratedSdk' in dcInstance) {
+    dcInstance._useGeneratedSdk();
+  } else {
+    console.error('Please update to the latest version of the Data Connect SDK by running `npm install firebase@dataconnect-preview`.');
+  }
+  return queryRef(dcInstance, 'SearchAll', inputVars);
+}
+exports.searchAllRef = searchAllRef;
+exports.searchAll = function searchAll(dcOrVars, vars) {
+  return executeQuery(searchAllRef(dcOrVars, vars));
+};
+
diff --git a/dataconnect/app/src/lib/dataconnect-sdk/index.d.ts b/dataconnect/app/src/lib/dataconnect-sdk/index.d.ts
new file mode 100644
index 000000000..2dfd410d0
--- /dev/null
+++ b/dataconnect/app/src/lib/dataconnect-sdk/index.d.ts
@@ -0,0 +1,392 @@
+import { ConnectorConfig, DataConnect, QueryRef, QueryPromise, MutationRef, MutationPromise } from 'firebase/data-connect';
+export const connectorConfig: ConnectorConfig;
+
+export type TimestampString = string;
+
+export type UUIDString = string;
+
+export type Int64String = string;
+
+export type DateString = string;
+
+
+export enum OrderDirection {
+
+  ASC = "ASC",
+
+  DESC = "DESC",
+
+}
+
+
+export interface Actor_Key {
+  id: UUIDString;
+  __typename?: 'Actor_Key';
+}
+
+export interface AddFavoritedMovieData {
+  favorite_movie_upsert: FavoriteMovie_Key;
+}
+
+export interface AddFavoritedMovieVariables {
+  movieId: UUIDString;
+}
+
+export interface AddReviewData {
+  review_insert: Review_Key;
+}
+
+export interface AddReviewVariables {
+  movieId: UUIDString;
+  rating: number;
+  reviewText: string;
+}
+
+export interface DeleteFavoritedMovieData {
+  favorite_movie_delete?: FavoriteMovie_Key | null;
+}
+
+export interface DeleteFavoritedMovieVariables {
+  movieId: UUIDString;
+}
+
+export interface DeleteReviewData {
+  review_delete?: Review_Key | null;
+}
+
+export interface DeleteReviewVariables {
+  movieId: UUIDString;
+}
+
+export interface FavoriteMovie_Key {
+  userId: string;
+  movieId: UUIDString;
+  __typename?: 'FavoriteMovie_Key';
+}
+
+export interface GetActorByIdData {
+  actor?: {
+    id: UUIDString;
+    name: string;
+    imageUrl: string;
+    mainActors: ({
+      id: UUIDString;
+      title: string;
+      genre?: string | null;
+      tags?: string[] | null;
+      imageUrl: string;
+    } & Movie_Key)[];
+      supportingActors: ({
+        id: UUIDString;
+        title: string;
+        genre?: string | null;
+        tags?: string[] | null;
+        imageUrl: string;
+      } & Movie_Key)[];
+  } & Actor_Key;
+}
+
+export interface GetActorByIdVariables {
+  id: UUIDString;
+}
+
+export interface GetCurrentUserData {
+  user?: {
+    id: string;
+    username: string;
+    reviews: ({
+      id: UUIDString;
+      rating?: number | null;
+      reviewDate: DateString;
+      reviewText?: string | null;
+      movie: {
+        id: UUIDString;
+        title: string;
+      } & Movie_Key;
+    })[];
+      favoriteMovies: ({
+        movie: {
+          id: UUIDString;
+          title: string;
+          genre?: string | null;
+          imageUrl: string;
+          releaseYear?: number | null;
+          rating?: number | null;
+          description?: string | null;
+          tags?: string[] | null;
+          metadata: ({
+            director?: string | null;
+          })[];
+        } & Movie_Key;
+      })[];
+  } & User_Key;
+}
+
+export interface GetIfFavoritedMovieData {
+  favorite_movie?: {
+    movieId: UUIDString;
+  };
+}
+
+export interface GetIfFavoritedMovieVariables {
+  movieId: UUIDString;
+}
+
+export interface GetMovieByIdData {
+  movie?: {
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+    releaseYear?: number | null;
+    genre?: string | null;
+    rating?: number | null;
+    description?: string | null;
+    tags?: string[] | null;
+    metadata: ({
+      director?: string | null;
+    })[];
+      mainActors: ({
+        id: UUIDString;
+        name: string;
+        imageUrl: string;
+      } & Actor_Key)[];
+        supportingActors: ({
+          id: UUIDString;
+          name: string;
+          imageUrl: string;
+        } & Actor_Key)[];
+          reviews: ({
+            id: UUIDString;
+            reviewText?: string | null;
+            reviewDate: DateString;
+            rating?: number | null;
+            user: {
+              id: string;
+              username: string;
+            } & User_Key;
+          })[];
+  } & Movie_Key;
+}
+
+export interface GetMovieByIdVariables {
+  id: UUIDString;
+}
+
+export interface ListMoviesData {
+  movies: ({
+    id: UUIDString;
+    title: string;
+    imageUrl: string;
+    releaseYear?: number | null;
+    genre?: string | null;
+    rating?: number | null;
+    tags?: string[] | null;
+    description?: string | null;
+  } & Movie_Key)[];
+}
+
+export interface ListMoviesVariables {
+  orderByRating?: OrderDirection | null;
+  orderByReleaseYear?: OrderDirection | null;
+  limit?: number | null;
+}
+
+export interface MovieActor_Key {
+  movieId: UUIDString;
+  actorId: UUIDString;
+  __typename?: 'MovieActor_Key';
+}
+
+export interface MovieMetadata_Key {
+  id: UUIDString;
+  __typename?: 'MovieMetadata_Key';
+}
+
+export interface Movie_Key {
+  id: UUIDString;
+  __typename?: 'Movie_Key';
+}
+
+export interface Review_Key {
+  userId: string;
+  movieId: UUIDString;
+  __typename?: 'Review_Key';
+}
+
+export interface SearchAllData {
+  moviesMatchingTitle: ({
+    id: UUIDString;
+    title: string;
+    genre?: string | null;
+    rating?: number | null;
+    imageUrl: string;
+  } & Movie_Key)[];
+    moviesMatchingDescription: ({
+      id: UUIDString;
+      title: string;
+      genre?: string | null;
+      rating?: number | null;
+      imageUrl: string;
+    } & Movie_Key)[];
+      actorsMatchingName: ({
+        id: UUIDString;
+        name: string;
+        imageUrl: string;
+      } & Actor_Key)[];
+        reviewsMatchingText: ({
+          id: UUIDString;
+          rating?: number | null;
+          reviewText?: string | null;
+          reviewDate: DateString;
+          movie: {
+            id: UUIDString;
+            title: string;
+          } & Movie_Key;
+            user: {
+              id: string;
+              username: string;
+            } & User_Key;
+        })[];
+}
+
+export interface SearchAllVariables {
+  input?: string | null;
+  minYear: number;
+  maxYear: number;
+  minRating: number;
+  maxRating: number;
+  genre: string;
+}
+
+export interface UpdateReviewData {
+  review_update?: Review_Key | null;
+}
+
+export interface UpdateReviewVariables {
+  movieId: UUIDString;
+  rating: number;
+  reviewText: string;
+}
+
+export interface UpsertUserData {
+  user_upsert: User_Key;
+}
+
+export interface UpsertUserVariables {
+  username: string;
+}
+
+export interface User_Key {
+  id: string;
+  __typename?: 'User_Key';
+}
+
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function upsertUserRef(vars: UpsertUserVariables): MutationRef<UpsertUserData, UpsertUserVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function upsertUserRef(dc: DataConnect, vars: UpsertUserVariables): MutationRef<UpsertUserData,UpsertUserVariables>;
+
+export function upsertUser(vars: UpsertUserVariables): MutationPromise<UpsertUserData, UpsertUserVariables>;
+export function upsertUser(dc: DataConnect, vars: UpsertUserVariables): MutationPromise<UpsertUserData,UpsertUserVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function addFavoritedMovieRef(vars: AddFavoritedMovieVariables): MutationRef<AddFavoritedMovieData, AddFavoritedMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function addFavoritedMovieRef(dc: DataConnect, vars: AddFavoritedMovieVariables): MutationRef<AddFavoritedMovieData,AddFavoritedMovieVariables>;
+
+export function addFavoritedMovie(vars: AddFavoritedMovieVariables): MutationPromise<AddFavoritedMovieData, AddFavoritedMovieVariables>;
+export function addFavoritedMovie(dc: DataConnect, vars: AddFavoritedMovieVariables): MutationPromise<AddFavoritedMovieData,AddFavoritedMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function deleteFavoritedMovieRef(vars: DeleteFavoritedMovieVariables): MutationRef<DeleteFavoritedMovieData, DeleteFavoritedMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function deleteFavoritedMovieRef(dc: DataConnect, vars: DeleteFavoritedMovieVariables): MutationRef<DeleteFavoritedMovieData,DeleteFavoritedMovieVariables>;
+
+export function deleteFavoritedMovie(vars: DeleteFavoritedMovieVariables): MutationPromise<DeleteFavoritedMovieData, DeleteFavoritedMovieVariables>;
+export function deleteFavoritedMovie(dc: DataConnect, vars: DeleteFavoritedMovieVariables): MutationPromise<DeleteFavoritedMovieData,DeleteFavoritedMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function addReviewRef(vars: AddReviewVariables): MutationRef<AddReviewData, AddReviewVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function addReviewRef(dc: DataConnect, vars: AddReviewVariables): MutationRef<AddReviewData,AddReviewVariables>;
+
+export function addReview(vars: AddReviewVariables): MutationPromise<AddReviewData, AddReviewVariables>;
+export function addReview(dc: DataConnect, vars: AddReviewVariables): MutationPromise<AddReviewData,AddReviewVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function updateReviewRef(vars: UpdateReviewVariables): MutationRef<UpdateReviewData, UpdateReviewVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function updateReviewRef(dc: DataConnect, vars: UpdateReviewVariables): MutationRef<UpdateReviewData,UpdateReviewVariables>;
+
+export function updateReview(vars: UpdateReviewVariables): MutationPromise<UpdateReviewData, UpdateReviewVariables>;
+export function updateReview(dc: DataConnect, vars: UpdateReviewVariables): MutationPromise<UpdateReviewData,UpdateReviewVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function deleteReviewRef(vars: DeleteReviewVariables): MutationRef<DeleteReviewData, DeleteReviewVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function deleteReviewRef(dc: DataConnect, vars: DeleteReviewVariables): MutationRef<DeleteReviewData,DeleteReviewVariables>;
+
+export function deleteReview(vars: DeleteReviewVariables): MutationPromise<DeleteReviewData, DeleteReviewVariables>;
+export function deleteReview(dc: DataConnect, vars: DeleteReviewVariables): MutationPromise<DeleteReviewData,DeleteReviewVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function listMoviesRef(vars?: ListMoviesVariables): QueryRef<ListMoviesData, ListMoviesVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function listMoviesRef(dc: DataConnect, vars?: ListMoviesVariables): QueryRef<ListMoviesData,ListMoviesVariables>;
+
+export function listMovies(vars?: ListMoviesVariables): QueryPromise<ListMoviesData, ListMoviesVariables>;
+export function listMovies(dc: DataConnect, vars?: ListMoviesVariables): QueryPromise<ListMoviesData,ListMoviesVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getMovieByIdRef(vars: GetMovieByIdVariables): QueryRef<GetMovieByIdData, GetMovieByIdVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getMovieByIdRef(dc: DataConnect, vars: GetMovieByIdVariables): QueryRef<GetMovieByIdData,GetMovieByIdVariables>;
+
+export function getMovieById(vars: GetMovieByIdVariables): QueryPromise<GetMovieByIdData, GetMovieByIdVariables>;
+export function getMovieById(dc: DataConnect, vars: GetMovieByIdVariables): QueryPromise<GetMovieByIdData,GetMovieByIdVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getActorByIdRef(vars: GetActorByIdVariables): QueryRef<GetActorByIdData, GetActorByIdVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getActorByIdRef(dc: DataConnect, vars: GetActorByIdVariables): QueryRef<GetActorByIdData,GetActorByIdVariables>;
+
+export function getActorById(vars: GetActorByIdVariables): QueryPromise<GetActorByIdData, GetActorByIdVariables>;
+export function getActorById(dc: DataConnect, vars: GetActorByIdVariables): QueryPromise<GetActorByIdData,GetActorByIdVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getCurrentUserRef(): QueryRef<GetCurrentUserData, undefined>;/* Allow users to pass in custom DataConnect instances */
+export function getCurrentUserRef(dc: DataConnect): QueryRef<GetCurrentUserData,undefined>;
+
+export function getCurrentUser(): QueryPromise<GetCurrentUserData, undefined>;
+export function getCurrentUser(dc: DataConnect): QueryPromise<GetCurrentUserData,undefined>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function getIfFavoritedMovieRef(vars: GetIfFavoritedMovieVariables): QueryRef<GetIfFavoritedMovieData, GetIfFavoritedMovieVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function getIfFavoritedMovieRef(dc: DataConnect, vars: GetIfFavoritedMovieVariables): QueryRef<GetIfFavoritedMovieData,GetIfFavoritedMovieVariables>;
+
+export function getIfFavoritedMovie(vars: GetIfFavoritedMovieVariables): QueryPromise<GetIfFavoritedMovieData, GetIfFavoritedMovieVariables>;
+export function getIfFavoritedMovie(dc: DataConnect, vars: GetIfFavoritedMovieVariables): QueryPromise<GetIfFavoritedMovieData,GetIfFavoritedMovieVariables>;
+
+
+/* Allow users to create refs without passing in DataConnect */
+export function searchAllRef(vars: SearchAllVariables): QueryRef<SearchAllData, SearchAllVariables>;
+/* Allow users to pass in custom DataConnect instances */
+export function searchAllRef(dc: DataConnect, vars: SearchAllVariables): QueryRef<SearchAllData,SearchAllVariables>;
+
+export function searchAll(vars: SearchAllVariables): QueryPromise<SearchAllData, SearchAllVariables>;
+export function searchAll(dc: DataConnect, vars: SearchAllVariables): QueryPromise<SearchAllData,SearchAllVariables>;
+
+
diff --git a/dataconnect/app/src/lib/dataconnect-sdk/package.json b/dataconnect/app/src/lib/dataconnect-sdk/package.json
new file mode 100644
index 000000000..001938592
--- /dev/null
+++ b/dataconnect/app/src/lib/dataconnect-sdk/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "@movie/dataconnect",
+  "version": "1.0.0",
+  "author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)",
+  "description": "Generated SDK For movie-connector",
+  "license": "Apache-2.0",
+  "engines": {
+    "node": " >=18.0"
+  },
+  "typings": "index.d.ts",
+  "module": "esm/index.esm.js",
+  "main": "index.cjs.js",
+  "browser": "esm/index.esm.js",
+  "exports": {
+    ".": {
+      "types": "./index.d.ts",
+      "require": "./index.cjs.js",
+      "default": "./esm/index.esm.js"
+    },
+    "./package.json": "./package.json"
+  },
+  "peerDependencies": {
+    "firebase": "^10.14.0"
+  }
+}
\ No newline at end of file
diff --git a/dataconnect/app/src/pages/Home.tsx b/dataconnect/app/src/pages/Home.tsx
index dbc1f2873..7e4b19635 100644
--- a/dataconnect/app/src/pages/Home.tsx
+++ b/dataconnect/app/src/pages/Home.tsx
@@ -2,15 +2,30 @@ import React, { useEffect, useState } from 'react';
 import Carousel from '@/components/carousel';
 import { handleGetTopMovies, handleGetLatestMovies } from '@/lib/MovieService';
 
+const ConditionalRender = ({ condition, preferred, alternate }: { condition: boolean, preferred: React.ReactNode, alternate: React.ReactNode }) => (
+  condition ? preferred : alternate
+)
+
+const PlaceholderMessage = () => (
+  <div className="min-h-screen flex items-center justify-center text-center text-4xl text-white">
+    Run the Firebase Data Connect Extension to get started.
+  </div>
+)
+
 export default function HomePage() {
   const [topMovies, setTopMovies] = useState([]);
   const [latestMovies, setLatestMovies] = useState([]);
+  const [needsToRunEmulators, setNeedsToRunEmulators] = useState(true);
 
   useEffect(() => {
     async function fetchMovies() {
       const topMoviesData = await handleGetTopMovies(10);
       const latestMoviesData = await handleGetLatestMovies(10);
 
+      // Or seed data
+      const shouldRunEmulators = topMoviesData.length === 0 && latestMoviesData.length === 0;
+      setNeedsToRunEmulators(shouldRunEmulators);
+
       if (topMoviesData) setTopMovies(topMoviesData);
       if (latestMoviesData) setLatestMovies(latestMoviesData);
     }
@@ -18,10 +33,19 @@ export default function HomePage() {
     fetchMovies();
   }, []);
 
-  return (
-    <div className="container mx-auto p-4 bg-gray-900 text-white shadow-md min-h-screen">
+  const carousels = (
+    <>
       <Carousel title="Top 10 Movies" movies={topMovies} />
       <Carousel title="Latest Movies" movies={latestMovies} />
+    </>
+  )
+
+  return (
+    <div className="container mx-auto p-4 bg-gray-900 text-white shadow-md min-h-screen">
+      <ConditionalRender 
+        condition={!needsToRunEmulators} 
+        preferred={carousels} 
+        alternate={<PlaceholderMessage />} />
     </div>
   );
 }
diff --git a/package-lock.json b/package-lock.json
index 4b1efc839..1d5541783 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
         "eslint-plugin-promise": "^6.1.1",
         "eslint-plugin-react-hooks": "^4.6.2",
         "eslint-plugin-react-refresh": "^0.4.9",
+        "firebase-tools": "^13.20.2",
         "lerna": "^6.6.1"
       },
       "engines": {
@@ -30,6 +31,18 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/@apidevtools/json-schema-ref-parser": {
+      "version": "9.1.2",
+      "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
+      "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
+      "dev": true,
+      "dependencies": {
+        "@jsdevtools/ono": "^7.1.3",
+        "@types/json-schema": "^7.0.6",
+        "call-me-maybe": "^1.0.1",
+        "js-yaml": "^4.1.0"
+      }
+    },
     "node_modules/@babel/code-frame": {
       "version": "7.22.13",
       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
@@ -208,6 +221,33 @@
         "node": ">=4"
       }
     },
+    "node_modules/@colors/colors": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+      "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+      "dev": true,
+      "optional": true,
+      "engines": {
+        "node": ">=0.1.90"
+      }
+    },
+    "node_modules/@dabh/diagnostics": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
+      "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
+      "dev": true,
+      "dependencies": {
+        "colorspace": "1.1.x",
+        "enabled": "2.0.x",
+        "kuler": "^2.0.0"
+      }
+    },
+    "node_modules/@electric-sql/pglite": {
+      "version": "0.2.10",
+      "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.2.10.tgz",
+      "integrity": "sha512-0TJF/1ouBweCtyZC4oHwx+dHGn/lP16KfEO/3q22RDuZUsV2saTuYAwb6eK3gBLzVdXG4dj4xZilvmBYEM/WQg==",
+      "dev": true
+    },
     "node_modules/@eslint-community/eslint-utils": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -272,6 +312,205 @@
       "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
       "dev": true
     },
+    "node_modules/@google-cloud/cloud-sql-connector": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@google-cloud/cloud-sql-connector/-/cloud-sql-connector-1.4.0.tgz",
+      "integrity": "sha512-OUXs2f91u3afbFjufCJom9lF+GgS9if4F/eKxrLvdkbwkYAQrQUOY6Jw4YfVXUxF3oNDioTgZ4fpwt1MQXwfKg==",
+      "dev": true,
+      "dependencies": {
+        "@googleapis/sqladmin": "^24.0.0",
+        "gaxios": "^6.1.1",
+        "google-auth-library": "^9.2.0",
+        "p-throttle": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@google-cloud/paginator": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.2.tgz",
+      "integrity": "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==",
+      "dev": true,
+      "dependencies": {
+        "arrify": "^2.0.0",
+        "extend": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@google-cloud/paginator/node_modules/arrify": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
+      "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@google-cloud/precise-date": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-4.0.0.tgz",
+      "integrity": "sha512-1TUx3KdaU3cN7nfCdNf+UVqA/PSX29Cjcox3fZZBtINlRrXVTmUkQnCKv2MbBUbCopbK4olAT1IHl76uZyCiVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@google-cloud/projectify": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz",
+      "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==",
+      "dev": true,
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@google-cloud/promisify": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz",
+      "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==",
+      "dev": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@google-cloud/pubsub": {
+      "version": "4.7.2",
+      "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-4.7.2.tgz",
+      "integrity": "sha512-N9Cziu5d7sju4gtHsbbjOXDMCewNwGaPZ/o+sBbWl9sBR7S+kHkD4BVg6hCi9SvH1sst0AGan8UAQAxbac8cRg==",
+      "dev": true,
+      "dependencies": {
+        "@google-cloud/paginator": "^5.0.0",
+        "@google-cloud/precise-date": "^4.0.0",
+        "@google-cloud/projectify": "^4.0.0",
+        "@google-cloud/promisify": "^4.0.0",
+        "@opentelemetry/api": "~1.9.0",
+        "@opentelemetry/semantic-conventions": "~1.26.0",
+        "arrify": "^2.0.0",
+        "extend": "^3.0.2",
+        "google-auth-library": "^9.3.0",
+        "google-gax": "^4.3.3",
+        "heap-js": "^2.2.0",
+        "is-stream-ended": "^0.1.4",
+        "lodash.snakecase": "^4.1.1",
+        "p-defer": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@google-cloud/pubsub/node_modules/arrify": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
+      "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@googleapis/sqladmin": {
+      "version": "24.0.0",
+      "resolved": "https://registry.npmjs.org/@googleapis/sqladmin/-/sqladmin-24.0.0.tgz",
+      "integrity": "sha512-Sj2MerYrr4Z6ksK81Scj0gIdFjC3bC0vcqdM+TSfnOskg6d9iIALWdFDc3xgNHQWO58rUb6HjBzr1XbuNjYlPg==",
+      "dev": true,
+      "dependencies": {
+        "googleapis-common": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@grpc/grpc-js": {
+      "version": "1.11.3",
+      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.11.3.tgz",
+      "integrity": "sha512-i9UraDzFHMR+Iz/MhFLljT+fCpgxZ3O6CxwGJ8YuNYHJItIHUzKJpW2LvoFZNnGPwqc9iWy9RAucxV0JoR9aUQ==",
+      "dev": true,
+      "dependencies": {
+        "@grpc/proto-loader": "^0.7.13",
+        "@js-sdsl/ordered-map": "^4.4.2"
+      },
+      "engines": {
+        "node": ">=12.10.0"
+      }
+    },
+    "node_modules/@grpc/proto-loader": {
+      "version": "0.7.13",
+      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz",
+      "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==",
+      "dev": true,
+      "dependencies": {
+        "lodash.camelcase": "^4.3.0",
+        "long": "^5.0.0",
+        "protobufjs": "^7.2.5",
+        "yargs": "^17.7.2"
+      },
+      "bin": {
+        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@grpc/proto-loader/node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@grpc/proto-loader/node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@grpc/proto-loader/node_modules/yargs": {
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+      "dev": true,
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@grpc/proto-loader/node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/@humanwhocodes/config-array": {
       "version": "0.11.14",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -336,9 +575,9 @@
       }
     },
     "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+      "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
       "dev": true,
       "engines": {
         "node": ">=12"
@@ -432,6 +671,22 @@
         "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
+    "node_modules/@js-sdsl/ordered-map": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz",
+      "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==",
+      "dev": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/js-sdsl"
+      }
+    },
+    "node_modules/@jsdevtools/ono": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
+      "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
+      "dev": true
+    },
     "node_modules/@lerna/child-process": {
       "version": "6.6.2",
       "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-6.6.2.tgz",
@@ -849,6 +1104,86 @@
         "node": ">= 8"
       }
     },
+    "node_modules/@npmcli/agent": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz",
+      "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "http-proxy-agent": "^7.0.0",
+        "https-proxy-agent": "^7.0.1",
+        "lru-cache": "^10.0.1",
+        "socks-proxy-agent": "^8.0.3"
+      },
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@npmcli/agent/node_modules/agent-base": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+      "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@npmcli/agent/node_modules/http-proxy-agent": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@npmcli/agent/node_modules/https-proxy-agent": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+      "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "agent-base": "^7.0.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@npmcli/agent/node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/@npmcli/agent/node_modules/socks-proxy-agent": {
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz",
+      "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "agent-base": "^7.1.1",
+        "debug": "^4.3.4",
+        "socks": "^2.8.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
     "node_modules/@npmcli/arborist": {
       "version": "6.2.3",
       "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-6.2.3.tgz",
@@ -1728,6 +2063,24 @@
         "@octokit/openapi-types": "^18.0.0"
       }
     },
+    "node_modules/@opentelemetry/api": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
+      "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@opentelemetry/semantic-conventions": {
+      "version": "1.26.0",
+      "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.26.0.tgz",
+      "integrity": "sha512-U9PJlOswJPSgQVPI+XEuNLElyFWkb0hAiMg+DExD9V0St03X2lPHGMdxMY/LrVmoukuIpXJ12oyrOtEZ4uXFkw==",
+      "dev": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
     "node_modules/@parcel/watcher": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz",
@@ -1756,45 +2109,144 @@
         "node": ">=14"
       }
     },
-    "node_modules/@sigstore/bundle": {
+    "node_modules/@pnpm/config.env-replace": {
       "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz",
-      "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==",
+      "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz",
+      "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==",
       "dev": true,
-      "dependencies": {
-        "@sigstore/protobuf-specs": "^0.2.0"
-      },
       "engines": {
-        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+        "node": ">=12.22.0"
       }
     },
-    "node_modules/@sigstore/protobuf-specs": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz",
-      "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==",
+    "node_modules/@pnpm/network.ca-file": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz",
+      "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==",
       "dev": true,
+      "dependencies": {
+        "graceful-fs": "4.2.10"
+      },
       "engines": {
-        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+        "node": ">=12.22.0"
       }
     },
-    "node_modules/@sigstore/sign": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz",
-      "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==",
+    "node_modules/@pnpm/npm-conf": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz",
+      "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==",
       "dev": true,
       "dependencies": {
-        "@sigstore/bundle": "^1.1.0",
-        "@sigstore/protobuf-specs": "^0.2.0",
-        "make-fetch-happen": "^11.0.1"
+        "@pnpm/config.env-replace": "^1.1.0",
+        "@pnpm/network.ca-file": "^1.0.1",
+        "config-chain": "^1.1.11"
       },
       "engines": {
-        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+        "node": ">=12"
       }
     },
-    "node_modules/@sigstore/sign/node_modules/make-fetch-happen": {
-      "version": "11.1.1",
-      "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz",
-      "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==",
+    "node_modules/@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+      "dev": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+      "dev": true
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
+      "dev": true
+    },
+    "node_modules/@sigstore/bundle": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz",
+      "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==",
+      "dev": true,
+      "dependencies": {
+        "@sigstore/protobuf-specs": "^0.2.0"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@sigstore/protobuf-specs": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz",
+      "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==",
+      "dev": true,
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@sigstore/sign": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz",
+      "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==",
+      "dev": true,
+      "dependencies": {
+        "@sigstore/bundle": "^1.1.0",
+        "@sigstore/protobuf-specs": "^0.2.0",
+        "make-fetch-happen": "^11.0.1"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@sigstore/sign/node_modules/make-fetch-happen": {
+      "version": "11.1.1",
+      "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz",
+      "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==",
       "dev": true,
       "dependencies": {
         "agentkeepalive": "^4.2.1",
@@ -1892,6 +2344,18 @@
       "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
       "dev": true
     },
+    "node_modules/@sindresorhus/is": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
+      "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/is?sponsor=1"
+      }
+    },
     "node_modules/@tootallnate/once": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@@ -1901,6 +2365,12 @@
         "node": ">= 10"
       }
     },
+    "node_modules/@tootallnate/quickjs-emscripten": {
+      "version": "0.23.0",
+      "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
+      "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
+      "dev": true
+    },
     "node_modules/@tufjs/canonical-json": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz",
@@ -1947,6 +2417,24 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/@types/caseless": {
+      "version": "0.12.5",
+      "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz",
+      "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==",
+      "dev": true
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+      "dev": true
+    },
+    "node_modules/@types/long": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
+      "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==",
+      "dev": true
+    },
     "node_modules/@types/minimatch": {
       "version": "3.0.5",
       "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
@@ -1959,6 +2447,15 @@
       "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
       "dev": true
     },
+    "node_modules/@types/node": {
+      "version": "22.7.4",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz",
+      "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==",
+      "dev": true,
+      "dependencies": {
+        "undici-types": "~6.19.2"
+      }
+    },
     "node_modules/@types/normalize-package-data": {
       "version": "2.4.4",
       "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
@@ -1971,6 +2468,44 @@
       "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
       "dev": true
     },
+    "node_modules/@types/request": {
+      "version": "2.48.12",
+      "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz",
+      "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==",
+      "dev": true,
+      "dependencies": {
+        "@types/caseless": "*",
+        "@types/node": "*",
+        "@types/tough-cookie": "*",
+        "form-data": "^2.5.0"
+      }
+    },
+    "node_modules/@types/request/node_modules/form-data": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
+      "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
+      "dev": true,
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 0.12"
+      }
+    },
+    "node_modules/@types/tough-cookie": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
+      "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
+      "dev": true
+    },
+    "node_modules/@types/triple-beam": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
+      "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
+      "dev": true
+    },
     "node_modules/@typescript-eslint/eslint-plugin": {
       "version": "7.18.0",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz",
@@ -2284,6 +2819,19 @@
         "node": ">=6.5"
       }
     },
+    "node_modules/accepts": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+      "dev": true,
+      "dependencies": {
+        "mime-types": "~2.1.34",
+        "negotiator": "0.6.3"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/acorn": {
       "version": "8.12.1",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
@@ -2367,6 +2915,54 @@
         "url": "https://github.com/sponsors/epoberezkin"
       }
     },
+    "node_modules/ajv-formats": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+      "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "ajv": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/ajv-formats/node_modules/ajv": {
+      "version": "8.17.1",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+      "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "fast-uri": "^3.0.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
+    "node_modules/ansi-align": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
+      "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.1.0"
+      }
+    },
     "node_modules/ansi-colors": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@@ -2427,12 +3023,170 @@
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
+    "node_modules/any-promise": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+      "dev": true
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dev": true,
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
     "node_modules/aproba": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
       "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
       "dev": true
     },
+    "node_modules/archiver": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
+      "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
+      "dev": true,
+      "dependencies": {
+        "archiver-utils": "^5.0.2",
+        "async": "^3.2.4",
+        "buffer-crc32": "^1.0.0",
+        "readable-stream": "^4.0.0",
+        "readdir-glob": "^1.1.2",
+        "tar-stream": "^3.0.0",
+        "zip-stream": "^6.0.1"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/archiver-utils": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
+      "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^10.0.0",
+        "graceful-fs": "^4.2.0",
+        "is-stream": "^2.0.1",
+        "lazystream": "^1.0.0",
+        "lodash": "^4.17.15",
+        "normalize-path": "^3.0.0",
+        "readable-stream": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/archiver-utils/node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/archiver-utils/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/archiver-utils/node_modules/readable-stream": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+      "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+      "dev": true,
+      "dependencies": {
+        "abort-controller": "^3.0.0",
+        "buffer": "^6.0.3",
+        "events": "^3.3.0",
+        "process": "^0.11.10",
+        "string_decoder": "^1.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/archiver/node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/archiver/node_modules/readable-stream": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+      "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+      "dev": true,
+      "dependencies": {
+        "abort-controller": "^3.0.0",
+        "buffer": "^6.0.3",
+        "events": "^3.3.0",
+        "process": "^0.11.10",
+        "string_decoder": "^1.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/archiver/node_modules/tar-stream": {
+      "version": "3.1.7",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
+      "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
+      "dev": true,
+      "dependencies": {
+        "b4a": "^1.6.4",
+        "fast-fifo": "^1.2.0",
+        "streamx": "^2.15.0"
+      }
+    },
     "node_modules/are-we-there-yet": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
@@ -2461,6 +3215,12 @@
         "node": ">=8"
       }
     },
+    "node_modules/array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
+      "dev": true
+    },
     "node_modules/array-ify": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz",
@@ -2485,16 +3245,40 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/async": {
-      "version": "3.2.5",
-      "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
-      "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==",
+    "node_modules/as-array": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/as-array/-/as-array-2.0.0.tgz",
+      "integrity": "sha512-1Sd1LrodN0XYxYeZcN1J4xYZvmvTwD5tDWaPUGPIzH1mFsmzsPnVtd2exWhecMjtZk/wYWjNZJiD3b1SLCeJqg==",
       "dev": true
     },
-    "node_modules/asynckit": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+    "node_modules/ast-types": {
+      "version": "0.13.4",
+      "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
+      "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/async": {
+      "version": "3.2.5",
+      "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
+      "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==",
+      "dev": true
+    },
+    "node_modules/async-lock": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz",
+      "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==",
+      "dev": true
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
       "dev": true
     },
     "node_modules/at-least-node": {
@@ -2517,12 +3301,25 @@
         "proxy-from-env": "^1.1.0"
       }
     },
+    "node_modules/b4a": {
+      "version": "1.6.7",
+      "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
+      "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==",
+      "dev": true
+    },
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
       "dev": true
     },
+    "node_modules/bare-events": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz",
+      "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==",
+      "dev": true,
+      "optional": true
+    },
     "node_modules/base64-js": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -2543,12 +3340,57 @@
         }
       ]
     },
+    "node_modules/basic-auth": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+      "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "5.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/basic-auth-connect": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/basic-auth-connect/-/basic-auth-connect-1.1.0.tgz",
+      "integrity": "sha512-rKcWjfiRZ3p5WS9e5q6msXa07s6DaFAMXoyowV+mb2xQG+oYdw2QEUyKi0Xp95JvXzShlM+oGy5QuqSK6TfC1Q==",
+      "dev": true,
+      "dependencies": {
+        "tsscmp": "^1.0.6"
+      }
+    },
+    "node_modules/basic-auth/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "node_modules/basic-ftp": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz",
+      "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
     "node_modules/before-after-hook": {
       "version": "2.2.3",
       "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
       "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
       "dev": true
     },
+    "node_modules/bignumber.js": {
+      "version": "9.1.2",
+      "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
+      "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/bin-links": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.3.tgz",
@@ -2607,6 +3449,18 @@
         "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
       }
     },
+    "node_modules/binary-extensions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/bl": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@@ -2618,6 +3472,96 @@
         "readable-stream": "^3.4.0"
       }
     },
+    "node_modules/body-parser": {
+      "version": "1.20.3",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+      "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+      "dev": true,
+      "dependencies": {
+        "bytes": "3.1.2",
+        "content-type": "~1.0.5",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "on-finished": "2.4.1",
+        "qs": "6.13.0",
+        "raw-body": "2.5.2",
+        "type-is": "~1.6.18",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "node_modules/body-parser/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/body-parser/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/boxen": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz",
+      "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-align": "^3.0.0",
+        "camelcase": "^6.2.0",
+        "chalk": "^4.1.0",
+        "cli-boxes": "^2.2.1",
+        "string-width": "^4.2.2",
+        "type-fest": "^0.20.2",
+        "widest-line": "^3.1.0",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/boxen/node_modules/camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/boxen/node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -2664,6 +3608,21 @@
         "ieee754": "^1.1.13"
       }
     },
+    "node_modules/buffer-crc32": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz",
+      "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/buffer-equal-constant-time": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+      "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+      "dev": true
+    },
     "node_modules/buffer-from": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -2688,6 +3647,15 @@
         "node": ">=10"
       }
     },
+    "node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/cacache": {
       "version": "17.1.4",
       "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz",
@@ -2723,6 +3691,31 @@
         "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
       }
     },
+    "node_modules/call-bind": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+      "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+      "dev": true,
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/call-me-maybe": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
+      "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
+      "dev": true
+    },
     "node_modules/callsites": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -2774,12 +3767,57 @@
         "url": "https://github.com/chalk/chalk?sponsor=1"
       }
     },
+    "node_modules/char-regex": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+      "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/chardet": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
       "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
       "dev": true
     },
+    "node_modules/chokidar": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+      "dev": true,
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/chokidar/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/chownr": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
@@ -2795,6 +3833,18 @@
       "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
       "dev": true
     },
+    "node_modules/cjson": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/cjson/-/cjson-0.3.3.tgz",
+      "integrity": "sha512-yKNcXi/Mvi5kb1uK0sahubYiyfUO2EUgOp4NcY9+8NX5Xmc+4yeNogZuLFkpLBBj7/QI9MjRUIuXrV9XOw5kVg==",
+      "dev": true,
+      "dependencies": {
+        "json-parse-helpfulerror": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.3.0"
+      }
+    },
     "node_modules/clean-stack": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -2804,6 +3854,18 @@
         "node": ">=6"
       }
     },
+    "node_modules/cli-boxes": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
+      "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/cli-cursor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -2816,6 +3878,27 @@
         "node": ">=8"
       }
     },
+    "node_modules/cli-highlight": {
+      "version": "2.1.11",
+      "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz",
+      "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "highlight.js": "^10.7.1",
+        "mz": "^2.4.0",
+        "parse5": "^5.1.1",
+        "parse5-htmlparser2-tree-adapter": "^6.0.0",
+        "yargs": "^16.0.0"
+      },
+      "bin": {
+        "highlight": "bin/highlight"
+      },
+      "engines": {
+        "node": ">=8.0.0",
+        "npm": ">=5.0.0"
+      }
+    },
     "node_modules/cli-spinners": {
       "version": "2.6.1",
       "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz",
@@ -2828,6 +3911,33 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/cli-table": {
+      "version": "0.3.11",
+      "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz",
+      "integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==",
+      "dev": true,
+      "dependencies": {
+        "colors": "1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.2.0"
+      }
+    },
+    "node_modules/cli-table3": {
+      "version": "0.6.5",
+      "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz",
+      "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.2.0"
+      },
+      "engines": {
+        "node": "10.* || >= 12.*"
+      },
+      "optionalDependencies": {
+        "@colors/colors": "1.5.0"
+      }
+    },
     "node_modules/cli-width": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
@@ -2912,6 +4022,16 @@
         "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
+    "node_modules/color": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+      "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.3",
+        "color-string": "^1.6.0"
+      }
+    },
     "node_modules/color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2930,6 +4050,16 @@
       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
       "dev": true
     },
+    "node_modules/color-string": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
+    },
     "node_modules/color-support": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
@@ -2939,6 +4069,46 @@
         "color-support": "bin.js"
       }
     },
+    "node_modules/color/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true
+    },
+    "node_modules/colorette": {
+      "version": "2.0.20",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+      "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
+      "dev": true
+    },
+    "node_modules/colors": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+      "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.1.90"
+      }
+    },
+    "node_modules/colorspace": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
+      "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
+      "dev": true,
+      "dependencies": {
+        "color": "^3.1.3",
+        "text-hex": "1.0.x"
+      }
+    },
     "node_modules/columnify": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz",
@@ -2964,6 +4134,15 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/commander": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+      "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/common-ancestor-path": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz",
@@ -2992,15 +4171,143 @@
         "node": ">=8"
       }
     },
-    "node_modules/concat-map": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
-      "dev": true
-    },
-    "node_modules/concat-stream": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+    "node_modules/compress-commons": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz",
+      "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==",
+      "dev": true,
+      "dependencies": {
+        "crc-32": "^1.2.0",
+        "crc32-stream": "^6.0.0",
+        "is-stream": "^2.0.1",
+        "normalize-path": "^3.0.0",
+        "readable-stream": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/compress-commons/node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/compress-commons/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/compress-commons/node_modules/readable-stream": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+      "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+      "dev": true,
+      "dependencies": {
+        "abort-controller": "^3.0.0",
+        "buffer": "^6.0.3",
+        "events": "^3.3.0",
+        "process": "^0.11.10",
+        "string_decoder": "^1.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/compressible": {
+      "version": "2.0.18",
+      "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
+      "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
+      "dev": true,
+      "dependencies": {
+        "mime-db": ">= 1.43.0 < 2"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/compression": {
+      "version": "1.7.4",
+      "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
+      "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
+      "dev": true,
+      "dependencies": {
+        "accepts": "~1.3.5",
+        "bytes": "3.0.0",
+        "compressible": "~2.0.16",
+        "debug": "2.6.9",
+        "on-headers": "~1.0.2",
+        "safe-buffer": "5.1.2",
+        "vary": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/compression/node_modules/bytes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+      "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/compression/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/compression/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/compression/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true
+    },
+    "node_modules/concat-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
       "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
       "dev": true,
       "engines": [
@@ -3023,12 +4330,152 @@
         "proto-list": "~1.2.1"
       }
     },
+    "node_modules/configstore": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz",
+      "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==",
+      "dev": true,
+      "dependencies": {
+        "dot-prop": "^5.2.0",
+        "graceful-fs": "^4.1.2",
+        "make-dir": "^3.0.0",
+        "unique-string": "^2.0.0",
+        "write-file-atomic": "^3.0.0",
+        "xdg-basedir": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/configstore/node_modules/dot-prop": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+      "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+      "dev": true,
+      "dependencies": {
+        "is-obj": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/configstore/node_modules/write-file-atomic": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+      "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+      "dev": true,
+      "dependencies": {
+        "imurmurhash": "^0.1.4",
+        "is-typedarray": "^1.0.0",
+        "signal-exit": "^3.0.2",
+        "typedarray-to-buffer": "^3.1.5"
+      }
+    },
+    "node_modules/connect": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+      "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "2.6.9",
+        "finalhandler": "1.1.2",
+        "parseurl": "~1.3.3",
+        "utils-merge": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/connect/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/connect/node_modules/encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/connect/node_modules/finalhandler": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "statuses": "~1.5.0",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/connect/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/connect/node_modules/on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+      "dev": true,
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/connect/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/console-control-strings": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
       "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
       "dev": true
     },
+    "node_modules/content-disposition": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+      "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "5.2.1"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/content-type": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+      "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/conventional-changelog-angular": {
       "version": "5.0.12",
       "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz",
@@ -3202,12 +4649,40 @@
         "node": ">=10"
       }
     },
+    "node_modules/cookie": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+      "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
+      "dev": true
+    },
     "node_modules/core-util-is": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
       "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
       "dev": true
     },
+    "node_modules/cors": {
+      "version": "2.8.5",
+      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+      "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+      "dev": true,
+      "dependencies": {
+        "object-assign": "^4",
+        "vary": "^1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/cosmiconfig": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
@@ -3224,48 +4699,211 @@
         "node": ">=10"
       }
     },
-    "node_modules/cross-spawn": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+    "node_modules/crc-32": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+      "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
       "dev": true,
-      "dependencies": {
-        "path-key": "^3.1.0",
-        "shebang-command": "^2.0.0",
-        "which": "^2.0.1"
+      "bin": {
+        "crc32": "bin/crc32.njs"
       },
       "engines": {
-        "node": ">= 8"
+        "node": ">=0.8"
       }
     },
-    "node_modules/crypto-random-string": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
-      "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
+    "node_modules/crc32-stream": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz",
+      "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==",
       "dev": true,
+      "dependencies": {
+        "crc-32": "^1.2.0",
+        "readable-stream": "^4.0.0"
+      },
       "engines": {
-        "node": ">=8"
+        "node": ">= 14"
       }
     },
-    "node_modules/cssesc": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
-      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+    "node_modules/crc32-stream/node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
       "dev": true,
-      "bin": {
-        "cssesc": "bin/cssesc"
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/crc32-stream/node_modules/readable-stream": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+      "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+      "dev": true,
+      "dependencies": {
+        "abort-controller": "^3.0.0",
+        "buffer": "^6.0.3",
+        "events": "^3.3.0",
+        "process": "^0.11.10",
+        "string_decoder": "^1.3.0"
       },
       "engines": {
-        "node": ">=4"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
     },
-    "node_modules/dargs": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
-      "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==",
+    "node_modules/cross-env": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.1.tgz",
+      "integrity": "sha512-1yHhtcfAd1r4nwQgknowuUNfIT9E8dOMMspC36g45dN+iD1blloi7xp8X/xAIDnjHWyt1uQ8PHk2fkNaym7soQ==",
       "dev": true,
+      "dependencies": {
+        "cross-spawn": "^6.0.5"
+      },
+      "bin": {
+        "cross-env": "dist/bin/cross-env.js",
+        "cross-env-shell": "dist/bin/cross-env-shell.js"
+      },
       "engines": {
-        "node": ">=8"
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/cross-env/node_modules/cross-spawn": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "dev": true,
+      "dependencies": {
+        "nice-try": "^1.0.4",
+        "path-key": "^2.0.1",
+        "semver": "^5.5.0",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      },
+      "engines": {
+        "node": ">=4.8"
+      }
+    },
+    "node_modules/cross-env/node_modules/path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/cross-env/node_modules/semver": {
+      "version": "5.7.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+      "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/cross-env/node_modules/shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+      "dev": true,
+      "dependencies": {
+        "shebang-regex": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/cross-env/node_modules/shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/cross-env/node_modules/which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "which": "bin/which"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/crypto-random-string": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
+      "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "dev": true,
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/csv-parse": {
+      "version": "5.5.6",
+      "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.5.6.tgz",
+      "integrity": "sha512-uNpm30m/AGSkLxxy7d9yRXpJQFrZzVWLFBkS+6ngPcZkw/5k3L/jjFuj7tVnEpRn+QgmiXr21nDlhCiUK4ij2A==",
+      "dev": true
+    },
+    "node_modules/dargs": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
+      "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/data-uri-to-buffer": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
+      "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 14"
       }
     },
     "node_modules/dateformat": {
@@ -3334,6 +4972,31 @@
       "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==",
       "dev": true
     },
+    "node_modules/deep-equal-in-any-order": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/deep-equal-in-any-order/-/deep-equal-in-any-order-2.0.6.tgz",
+      "integrity": "sha512-RfnWHQzph10YrUjvWwhd15Dne8ciSJcZ3U6OD7owPwiVwsdE5IFSoZGg8rlwJD11ES+9H5y8j3fCofviRHOqLQ==",
+      "dev": true,
+      "dependencies": {
+        "lodash.mapvalues": "^4.6.0",
+        "sort-any": "^2.0.0"
+      }
+    },
+    "node_modules/deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/deep-freeze": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz",
+      "integrity": "sha512-Z+z8HiAvsGwmjqlphnHW5oz6yWlOwu6EQfFTjmeTWlDeda3FS2yv3jhq35TX/ewmsnqB+RX2IdsIOyjJCQN5tg==",
+      "dev": true
+    },
     "node_modules/deep-is": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -3352,6 +5015,23 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "dev": true,
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/define-lazy-prop": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
@@ -3361,6 +5041,20 @@
         "node": ">=8"
       }
     },
+    "node_modules/degenerator": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
+      "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
+      "dev": true,
+      "dependencies": {
+        "ast-types": "^0.13.4",
+        "escodegen": "^2.1.0",
+        "esprima": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
     "node_modules/del": {
       "version": "6.1.1",
       "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz",
@@ -3398,12 +5092,31 @@
       "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
       "dev": true
     },
+    "node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/deprecation": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
       "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
       "dev": true
     },
+    "node_modules/destroy": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
     "node_modules/detect-indent": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz",
@@ -3425,6 +5138,12 @@
         "node": ">=8"
       }
     },
+    "node_modules/discontinuous-range": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
+      "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==",
+      "dev": true
+    },
     "node_modules/doctrine": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -3467,12 +5186,39 @@
       "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
       "dev": true
     },
+    "node_modules/duplexify": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz",
+      "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==",
+      "dev": true,
+      "dependencies": {
+        "end-of-stream": "^1.4.1",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.1.1",
+        "stream-shift": "^1.0.2"
+      }
+    },
     "node_modules/eastasianwidth": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
       "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
       "dev": true
     },
+    "node_modules/ecdsa-sig-formatter": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+      "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+      "dev": true
+    },
     "node_modules/ejs": {
       "version": "3.1.9",
       "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
@@ -3494,6 +5240,27 @@
       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "dev": true
     },
+    "node_modules/emojilib": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz",
+      "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==",
+      "dev": true
+    },
+    "node_modules/enabled": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
+      "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
+      "dev": true
+    },
+    "node_modules/encodeurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+      "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/encoding": {
       "version": "0.1.13",
       "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
@@ -3559,6 +5326,18 @@
         "node": ">=4"
       }
     },
+    "node_modules/environment": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
+      "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/err-code": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
@@ -3574,6 +5353,27 @@
         "is-arrayish": "^0.2.1"
       }
     },
+    "node_modules/es-define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+      "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.2.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/escalade": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -3583,6 +5383,21 @@
         "node": ">=6"
       }
     },
+    "node_modules/escape-goat": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
+      "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+      "dev": true
+    },
     "node_modules/escape-string-regexp": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -3595,6 +5410,27 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/escodegen": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+      "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
+      "dev": true,
+      "dependencies": {
+        "esprima": "^4.0.1",
+        "estraverse": "^5.2.0",
+        "esutils": "^2.0.2"
+      },
+      "bin": {
+        "escodegen": "bin/escodegen.js",
+        "esgenerate": "bin/esgenerate.js"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "optionalDependencies": {
+        "source-map": "~0.6.1"
+      }
+    },
     "node_modules/eslint": {
       "version": "8.57.0",
       "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
@@ -3787,6 +5623,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/event-target-shim": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
@@ -3811,6 +5656,12 @@
         "node": ">=0.8.x"
       }
     },
+    "node_modules/events-listener": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/events-listener/-/events-listener-1.1.0.tgz",
+      "integrity": "sha512-Kd3EgYfODHueq6GzVfs/VUolh2EgJsS8hkO3KpnDrxVjU3eq63eXM2ujXkhPP+OkeUOhL8CxdfZbQXzryb5C4g==",
+      "dev": true
+    },
     "node_modules/execa": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz",
@@ -3834,12 +5685,139 @@
         "url": "https://github.com/sindresorhus/execa?sponsor=1"
       }
     },
+    "node_modules/exegesis": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/exegesis/-/exegesis-4.2.0.tgz",
+      "integrity": "sha512-MOzRyqhvl+hTA4+W4p0saWRIPlu0grIx4ykjMEYgGLiqr/z9NCIlwSq2jF0gyxNjPZD3xyHgmkW6BSaLVUdctg==",
+      "dev": true,
+      "dependencies": {
+        "@apidevtools/json-schema-ref-parser": "^9.0.3",
+        "ajv": "^8.3.0",
+        "ajv-formats": "^2.1.0",
+        "body-parser": "^1.18.3",
+        "content-type": "^1.0.4",
+        "deep-freeze": "0.0.1",
+        "events-listener": "^1.1.0",
+        "glob": "^10.3.10",
+        "json-ptr": "^3.0.1",
+        "json-schema-traverse": "^1.0.0",
+        "lodash": "^4.17.11",
+        "openapi3-ts": "^3.1.1",
+        "promise-breaker": "^6.0.0",
+        "pump": "^3.0.0",
+        "qs": "^6.6.0",
+        "raw-body": "^2.3.3",
+        "semver": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=6.0.0",
+        "npm": ">5.0.0"
+      }
+    },
+    "node_modules/exegesis-express": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/exegesis-express/-/exegesis-express-4.0.0.tgz",
+      "integrity": "sha512-V2hqwTtYRj0bj43K4MCtm0caD97YWkqOUHFMRCBW5L1x9IjyqOEc7Xa4oQjjiFbeFOSQzzwPV+BzXsQjSz08fw==",
+      "dev": true,
+      "dependencies": {
+        "exegesis": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=6.0.0",
+        "npm": ">5.0.0"
+      }
+    },
+    "node_modules/exegesis/node_modules/ajv": {
+      "version": "8.17.1",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+      "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "fast-uri": "^3.0.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/exegesis/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
     "node_modules/exponential-backoff": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz",
       "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==",
       "dev": true
     },
+    "node_modules/express": {
+      "version": "4.21.0",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
+      "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
+      "dev": true,
+      "dependencies": {
+        "accepts": "~1.3.8",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.20.3",
+        "content-disposition": "0.5.4",
+        "content-type": "~1.0.4",
+        "cookie": "0.6.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "encodeurl": "~2.0.0",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "1.3.1",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "merge-descriptors": "1.0.3",
+        "methods": "~1.1.2",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.10",
+        "proxy-addr": "~2.0.7",
+        "qs": "6.13.0",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.2.1",
+        "send": "0.19.0",
+        "serve-static": "1.16.2",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/express/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/express/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
     "node_modules/external-editor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
@@ -3873,6 +5851,12 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/fast-fifo": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+      "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+      "dev": true
+    },
     "node_modules/fast-glob": {
       "version": "3.3.2",
       "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
@@ -3914,15 +5898,42 @@
       "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
       "dev": true
     },
-    "node_modules/fastq": {
-      "version": "1.15.0",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
-      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
-      "dev": true,
+    "node_modules/fast-uri": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.2.tgz",
+      "integrity": "sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row==",
+      "dev": true
+    },
+    "node_modules/fast-url-parser": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
+      "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==",
+      "dev": true,
+      "dependencies": {
+        "punycode": "^1.3.2"
+      }
+    },
+    "node_modules/fast-url-parser/node_modules/punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
+      "dev": true
+    },
+    "node_modules/fastq": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+      "dev": true,
       "dependencies": {
         "reusify": "^1.0.4"
       }
     },
+    "node_modules/fecha": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+      "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
+      "dev": true
+    },
     "node_modules/figures": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -3998,6 +6009,15 @@
         "node": ">=10"
       }
     },
+    "node_modules/filesize": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.4.0.tgz",
+      "integrity": "sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
     "node_modules/fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -4010,6 +6030,39 @@
         "node": ">=8"
       }
     },
+    "node_modules/finalhandler": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+      "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "2.6.9",
+        "encodeurl": "~2.0.0",
+        "escape-html": "~1.0.3",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "statuses": "2.0.1",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/finalhandler/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/finalhandler/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
     "node_modules/find-up": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -4026,6 +6079,159 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/firebase-tools": {
+      "version": "13.20.2",
+      "resolved": "https://registry.npmjs.org/firebase-tools/-/firebase-tools-13.20.2.tgz",
+      "integrity": "sha512-lhJ8C/hNtNyG57IIWZ+j+0JaiB3A/wo7c/LFouRigE+/IRo13le2uotBAFI7XjTOgxelxs8wGA6u/4fgQAz8Zw==",
+      "dev": true,
+      "dependencies": {
+        "@electric-sql/pglite": "^0.2.0",
+        "@google-cloud/cloud-sql-connector": "^1.3.3",
+        "@google-cloud/pubsub": "^4.5.0",
+        "abort-controller": "^3.0.0",
+        "ajv": "^6.12.6",
+        "archiver": "^7.0.0",
+        "async-lock": "1.4.1",
+        "body-parser": "^1.19.0",
+        "chokidar": "^3.6.0",
+        "cjson": "^0.3.1",
+        "cli-table": "0.3.11",
+        "colorette": "^2.0.19",
+        "commander": "^4.0.1",
+        "configstore": "^5.0.1",
+        "cors": "^2.8.5",
+        "cross-env": "^5.1.3",
+        "cross-spawn": "^7.0.3",
+        "csv-parse": "^5.0.4",
+        "deep-equal-in-any-order": "^2.0.6",
+        "exegesis": "^4.2.0",
+        "exegesis-express": "^4.0.0",
+        "express": "^4.16.4",
+        "filesize": "^6.1.0",
+        "form-data": "^4.0.0",
+        "fs-extra": "^10.1.0",
+        "fuzzy": "^0.1.3",
+        "gaxios": "^6.7.0",
+        "glob": "^10.4.1",
+        "google-auth-library": "^9.11.0",
+        "inquirer": "^8.2.6",
+        "inquirer-autocomplete-prompt": "^2.0.1",
+        "jsonwebtoken": "^9.0.0",
+        "leven": "^3.1.0",
+        "libsodium-wrappers": "^0.7.10",
+        "lodash": "^4.17.21",
+        "lsofi": "1.0.0",
+        "marked": "^13.0.2",
+        "marked-terminal": "^7.0.0",
+        "mime": "^2.5.2",
+        "minimatch": "^3.0.4",
+        "morgan": "^1.10.0",
+        "node-fetch": "^2.6.7",
+        "open": "^6.3.0",
+        "ora": "^5.4.1",
+        "p-limit": "^3.0.1",
+        "pg": "^8.11.3",
+        "portfinder": "^1.0.32",
+        "progress": "^2.0.3",
+        "proxy-agent": "^6.3.0",
+        "retry": "^0.13.1",
+        "rimraf": "^5.0.0",
+        "semver": "^7.5.2",
+        "sql-formatter": "^15.3.0",
+        "stream-chain": "^2.2.4",
+        "stream-json": "^1.7.3",
+        "strip-ansi": "^6.0.1",
+        "superstatic": "^9.0.3",
+        "tar": "^6.1.11",
+        "tcp-port-used": "^1.0.2",
+        "tmp": "^0.2.3",
+        "triple-beam": "^1.3.0",
+        "universal-analytics": "^0.5.3",
+        "update-notifier-cjs": "^5.1.6",
+        "uuid": "^8.3.2",
+        "winston": "^3.0.0",
+        "winston-transport": "^4.4.0",
+        "ws": "^7.5.10",
+        "yaml": "^2.4.1"
+      },
+      "bin": {
+        "firebase": "lib/bin/firebase.js"
+      },
+      "engines": {
+        "node": ">=18.0.0 || >=20.0.0"
+      }
+    },
+    "node_modules/firebase-tools/node_modules/fs-extra": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+      "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/firebase-tools/node_modules/is-wsl": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+      "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/firebase-tools/node_modules/open": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz",
+      "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==",
+      "dev": true,
+      "dependencies": {
+        "is-wsl": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/firebase-tools/node_modules/retry": {
+      "version": "0.13.1",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
+      "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/firebase-tools/node_modules/rimraf": {
+      "version": "5.0.10",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
+      "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^10.3.7"
+      },
+      "bin": {
+        "rimraf": "dist/esm/bin.mjs"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/firebase-tools/node_modules/yaml": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz",
+      "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==",
+      "dev": true,
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
     "node_modules/flat": {
       "version": "5.0.2",
       "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
@@ -4055,6 +6261,12 @@
       "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
       "dev": true
     },
+    "node_modules/fn.name": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
+      "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
+      "dev": true
+    },
     "node_modules/follow-redirects": {
       "version": "1.15.3",
       "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
@@ -4117,6 +6329,24 @@
         "node": ">= 6"
       }
     },
+    "node_modules/forwarded": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/fs-constants": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -4156,6 +6386,20 @@
       "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
       "dev": true
     },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
     "node_modules/function-bind": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -4165,6 +6409,15 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/fuzzy": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz",
+      "integrity": "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
     "node_modules/gauge": {
       "version": "4.0.4",
       "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz",
@@ -4184,6 +6437,93 @@
         "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
+    "node_modules/gaxios": {
+      "version": "6.7.1",
+      "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
+      "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
+      "dev": true,
+      "dependencies": {
+        "extend": "^3.0.2",
+        "https-proxy-agent": "^7.0.1",
+        "is-stream": "^2.0.0",
+        "node-fetch": "^2.6.9",
+        "uuid": "^9.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/gaxios/node_modules/agent-base": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+      "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/gaxios/node_modules/https-proxy-agent": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+      "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^7.0.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/gaxios/node_modules/node-fetch": {
+      "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"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/gaxios/node_modules/uuid": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+      "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+      "dev": true,
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/gcp-metadata": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz",
+      "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==",
+      "dev": true,
+      "dependencies": {
+        "gaxios": "^6.0.0",
+        "json-bigint": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
     "node_modules/get-caller-file": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -4193,6 +6533,25 @@
         "node": "6.* || 8.* || >= 10.*"
       }
     },
+    "node_modules/get-intrinsic": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+      "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+      "dev": true,
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "has-proto": "^1.0.1",
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/get-pkg-repo": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz",
@@ -4287,6 +6646,18 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/get-stdin": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
+      "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/get-stream": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz",
@@ -4299,6 +6670,35 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/get-uri": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz",
+      "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==",
+      "dev": true,
+      "dependencies": {
+        "basic-ftp": "^5.0.2",
+        "data-uri-to-buffer": "^6.0.2",
+        "debug": "^4.3.4",
+        "fs-extra": "^11.2.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/get-uri/node_modules/fs-extra": {
+      "version": "11.2.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
+      "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
     "node_modules/git-raw-commits": {
       "version": "2.0.11",
       "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz",
@@ -4394,23 +6794,21 @@
       }
     },
     "node_modules/glob": {
-      "version": "10.3.10",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
-      "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
+      "version": "10.4.5",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+      "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
       "dev": true,
       "dependencies": {
         "foreground-child": "^3.1.0",
-        "jackspeak": "^2.3.5",
-        "minimatch": "^9.0.1",
-        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
-        "path-scurry": "^1.10.1"
+        "jackspeak": "^3.1.2",
+        "minimatch": "^9.0.4",
+        "minipass": "^7.1.2",
+        "package-json-from-dist": "^1.0.0",
+        "path-scurry": "^1.11.1"
       },
       "bin": {
         "glob": "dist/esm/bin.mjs"
       },
-      "engines": {
-        "node": ">=16 || 14 >=14.17"
-      },
       "funding": {
         "url": "https://github.com/sponsors/isaacs"
       }
@@ -4427,6 +6825,23 @@
         "node": ">=10.13.0"
       }
     },
+    "node_modules/glob-slash": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/glob-slash/-/glob-slash-1.0.0.tgz",
+      "integrity": "sha512-ZwFh34WZhZX28ntCMAP1mwyAJkn8+Omagvt/GvA+JQM/qgT0+MR2NPF3vhvgdshfdvDyGZXs8fPXW84K32Wjuw==",
+      "dev": true
+    },
+    "node_modules/glob-slasher": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/glob-slasher/-/glob-slasher-1.0.1.tgz",
+      "integrity": "sha512-5MUzqFiycIKLMD1B0dYOE4hGgLLUZUNGGYO4BExdwT32wUwW3DBOE7lMQars7vB1q43Fb3Tyt+HmgLKsJhDYdg==",
+      "dev": true,
+      "dependencies": {
+        "glob-slash": "^1.0.0",
+        "lodash.isobject": "^2.4.1",
+        "toxic": "^1.0.0"
+      }
+    },
     "node_modules/glob/node_modules/brace-expansion": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -4437,9 +6852,9 @@
       }
     },
     "node_modules/glob/node_modules/minimatch": {
-      "version": "9.0.3",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
-      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
       "dev": true,
       "dependencies": {
         "brace-expansion": "^2.0.1"
@@ -4451,26 +6866,50 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
-    "node_modules/globals": {
-      "version": "13.24.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
-      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+    "node_modules/global-dirs": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+      "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
-        "type-fest": "^0.20.2"
+        "ini": "2.0.0"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=10"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/globby": {
-      "version": "11.1.0",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
-      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+    "node_modules/global-dirs/node_modules/ini": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+      "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/globals": {
+      "version": "13.24.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "type-fest": "^0.20.2"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
       "dev": true,
       "dependencies": {
         "array-union": "^2.1.0",
@@ -4487,6 +6926,121 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/google-auth-library": {
+      "version": "9.14.1",
+      "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.14.1.tgz",
+      "integrity": "sha512-Rj+PMjoNFGFTmtItH7gHfbHpGVSb3vmnGK3nwNBqxQF9NoBpttSZI/rc0WiM63ma2uGDQtYEkMHkK9U6937NiA==",
+      "dev": true,
+      "dependencies": {
+        "base64-js": "^1.3.0",
+        "ecdsa-sig-formatter": "^1.0.11",
+        "gaxios": "^6.1.1",
+        "gcp-metadata": "^6.1.0",
+        "gtoken": "^7.0.0",
+        "jws": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/google-gax": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz",
+      "integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==",
+      "dev": true,
+      "dependencies": {
+        "@grpc/grpc-js": "^1.10.9",
+        "@grpc/proto-loader": "^0.7.13",
+        "@types/long": "^4.0.0",
+        "abort-controller": "^3.0.0",
+        "duplexify": "^4.0.0",
+        "google-auth-library": "^9.3.0",
+        "node-fetch": "^2.7.0",
+        "object-hash": "^3.0.0",
+        "proto3-json-serializer": "^2.0.2",
+        "protobufjs": "^7.3.2",
+        "retry-request": "^7.0.0",
+        "uuid": "^9.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/google-gax/node_modules/node-fetch": {
+      "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"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/google-gax/node_modules/uuid": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+      "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+      "dev": true,
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/googleapis-common": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.2.0.tgz",
+      "integrity": "sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA==",
+      "dev": true,
+      "dependencies": {
+        "extend": "^3.0.2",
+        "gaxios": "^6.0.3",
+        "google-auth-library": "^9.7.0",
+        "qs": "^6.7.0",
+        "url-template": "^2.0.8",
+        "uuid": "^9.0.0"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/googleapis-common/node_modules/uuid": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+      "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+      "dev": true,
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/graceful-fs": {
       "version": "4.2.10",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
@@ -4499,6 +7053,19 @@
       "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
       "dev": true
     },
+    "node_modules/gtoken": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
+      "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
+      "dev": true,
+      "dependencies": {
+        "gaxios": "^6.0.0",
+        "jws": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
     "node_modules/handlebars": {
       "version": "4.7.8",
       "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
@@ -4538,12 +7105,57 @@
         "node": ">=8"
       }
     },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "dev": true,
+      "dependencies": {
+        "es-define-property": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-proto": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+      "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/has-unicode": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
       "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
       "dev": true
     },
+    "node_modules/has-yarn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
+      "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/hasown": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
@@ -4556,6 +7168,24 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/heap-js": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/heap-js/-/heap-js-2.5.0.tgz",
+      "integrity": "sha512-kUGoI3p7u6B41z/dp33G6OaL7J4DRqRYwVmeIlwLClx7yaaAy7hoDExnuejTKtuDwfcatGmddHDEOjf6EyIxtQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/highlight.js": {
+      "version": "10.7.3",
+      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
+      "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/hosted-git-info": {
       "version": "6.1.1",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz",
@@ -4574,6 +7204,22 @@
       "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
       "dev": true
     },
+    "node_modules/http-errors": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+      "dev": true,
+      "dependencies": {
+        "depd": "2.0.0",
+        "inherits": "2.0.4",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "toidentifier": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/http-proxy-agent": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
@@ -4710,6 +7356,15 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/import-lazy": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
+      "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/import-local": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@@ -4855,18 +7510,97 @@
         "node": ">=12.0.0"
       }
     },
-    "node_modules/ip": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
-      "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
+    "node_modules/inquirer-autocomplete-prompt": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/inquirer-autocomplete-prompt/-/inquirer-autocomplete-prompt-2.0.1.tgz",
+      "integrity": "sha512-jUHrH0btO7j5r8DTQgANf2CBkTZChoVySD8zF/wp5fZCOLIuUbleXhf4ZY5jNBOc1owA3gdfWtfZuppfYBhcUg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-escapes": "^4.3.2",
+        "figures": "^3.2.0",
+        "picocolors": "^1.0.0",
+        "run-async": "^2.4.1",
+        "rxjs": "^7.5.4"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "inquirer": "^8.0.0"
+      }
+    },
+    "node_modules/install-artifact-from-github": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/install-artifact-from-github/-/install-artifact-from-github-1.3.5.tgz",
+      "integrity": "sha512-gZHC7f/cJgXz7MXlHFBxPVMsvIbev1OQN1uKQYKVJDydGNm9oYf9JstbU4Atnh/eSvk41WtEovoRm+8IF686xg==",
+      "dev": true,
+      "optional": true,
+      "bin": {
+        "install-from-cache": "bin/install-from-cache.js",
+        "save-to-github-cache": "bin/save-to-github-cache.js"
+      }
+    },
+    "node_modules/ip-address": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
+      "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+      "dev": true,
+      "dependencies": {
+        "jsbn": "1.1.0",
+        "sprintf-js": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/ip-address/node_modules/sprintf-js": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
+      "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
       "dev": true
     },
+    "node_modules/ip-regex": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
+      "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/is-arrayish": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
       "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
       "dev": true
     },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
     "node_modules/is-ci": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
@@ -4936,6 +7670,22 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-installed-globally": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+      "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
+      "dev": true,
+      "dependencies": {
+        "global-dirs": "^3.0.0",
+        "is-path-inside": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-interactive": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
@@ -4951,6 +7701,18 @@
       "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
       "dev": true
     },
+    "node_modules/is-npm": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz",
+      "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-number": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -5023,6 +7785,12 @@
         "node": ">=8"
       }
     },
+    "node_modules/is-stream-ended": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz",
+      "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==",
+      "dev": true
+    },
     "node_modules/is-text-path": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz",
@@ -5035,6 +7803,12 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+      "dev": true
+    },
     "node_modules/is-unicode-supported": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
@@ -5047,6 +7821,12 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/is-url": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
+      "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
+      "dev": true
+    },
     "node_modules/is-wsl": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
@@ -5059,6 +7839,26 @@
         "node": ">=8"
       }
     },
+    "node_modules/is-yarn-global": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz",
+      "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==",
+      "dev": true
+    },
+    "node_modules/is2": {
+      "version": "2.0.9",
+      "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.9.tgz",
+      "integrity": "sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==",
+      "dev": true,
+      "dependencies": {
+        "deep-is": "^0.1.3",
+        "ip-regex": "^4.1.0",
+        "is-url": "^1.2.4"
+      },
+      "engines": {
+        "node": ">=v0.10.0"
+      }
+    },
     "node_modules/isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -5080,17 +7880,24 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/isomorphic-fetch": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz",
+      "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==",
+      "dev": true,
+      "dependencies": {
+        "node-fetch": "^2.6.1",
+        "whatwg-fetch": "^3.4.1"
+      }
+    },
     "node_modules/jackspeak": {
-      "version": "2.3.6",
-      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
-      "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+      "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
       "dev": true,
       "dependencies": {
         "@isaacs/cliui": "^8.0.2"
       },
-      "engines": {
-        "node": ">=14"
-      },
       "funding": {
         "url": "https://github.com/sponsors/isaacs"
       },
@@ -5116,6 +7923,23 @@
         "node": ">=10"
       }
     },
+    "node_modules/jju": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
+      "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
+      "dev": true
+    },
+    "node_modules/join-path": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/join-path/-/join-path-1.1.1.tgz",
+      "integrity": "sha512-jnt9OC34sLXMLJ6YfPQ2ZEKrR9mB5ZbSnQb4LPaOx1c5rTzxpR33L18jjp0r75mGGTJmsil3qwN1B5IBeTnSSA==",
+      "dev": true,
+      "dependencies": {
+        "as-array": "^2.0.0",
+        "url-join": "0.0.1",
+        "valid-url": "^1"
+      }
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -5134,9 +7958,24 @@
         "js-yaml": "bin/js-yaml.js"
       }
     },
-    "node_modules/json-buffer": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+    "node_modules/jsbn": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
+      "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
+      "dev": true
+    },
+    "node_modules/json-bigint": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
+      "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
+      "dev": true,
+      "dependencies": {
+        "bignumber.js": "^9.0.0"
+      }
+    },
+    "node_modules/json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
       "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
       "dev": true
     },
@@ -5155,6 +7994,21 @@
         "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
       }
     },
+    "node_modules/json-parse-helpfulerror": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz",
+      "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==",
+      "dev": true,
+      "dependencies": {
+        "jju": "^1.1.0"
+      }
+    },
+    "node_modules/json-ptr": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/json-ptr/-/json-ptr-3.1.1.tgz",
+      "integrity": "sha512-SiSJQ805W1sDUCD1+/t1/1BIrveq2Fe9HJqENxZmMCILmrPI7WhS/pePpIOx85v6/H2z1Vy7AI08GV2TzfXocg==",
+      "dev": true
+    },
     "node_modules/json-schema-traverse": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -5238,6 +8092,49 @@
         "node": "*"
       }
     },
+    "node_modules/jsonwebtoken": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+      "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+      "dev": true,
+      "dependencies": {
+        "jws": "^3.2.2",
+        "lodash.includes": "^4.3.0",
+        "lodash.isboolean": "^3.0.3",
+        "lodash.isinteger": "^4.0.4",
+        "lodash.isnumber": "^3.0.3",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.isstring": "^4.0.1",
+        "lodash.once": "^4.0.0",
+        "ms": "^2.1.1",
+        "semver": "^7.5.4"
+      },
+      "engines": {
+        "node": ">=12",
+        "npm": ">=6"
+      }
+    },
+    "node_modules/jsonwebtoken/node_modules/jwa": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+      "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+      "dev": true,
+      "dependencies": {
+        "buffer-equal-constant-time": "1.0.1",
+        "ecdsa-sig-formatter": "1.0.11",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/jsonwebtoken/node_modules/jws": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+      "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+      "dev": true,
+      "dependencies": {
+        "jwa": "^1.4.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
     "node_modules/just-diff": {
       "version": "6.0.2",
       "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz",
@@ -5250,6 +8147,27 @@
       "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==",
       "dev": true
     },
+    "node_modules/jwa": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
+      "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
+      "dev": true,
+      "dependencies": {
+        "buffer-equal-constant-time": "1.0.1",
+        "ecdsa-sig-formatter": "1.0.11",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/jws": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
+      "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
+      "dev": true,
+      "dependencies": {
+        "jwa": "^2.0.0",
+        "safe-buffer": "^5.0.1"
+      }
+    },
     "node_modules/keyv": {
       "version": "4.5.4",
       "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -5268,6 +8186,54 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/kuler": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
+      "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
+      "dev": true
+    },
+    "node_modules/lazystream": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+      "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "^2.0.5"
+      },
+      "engines": {
+        "node": ">= 0.6.3"
+      }
+    },
+    "node_modules/lazystream/node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "dev": true,
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/lazystream/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "node_modules/lazystream/node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
     "node_modules/lerna": {
       "version": "6.6.2",
       "resolved": "https://registry.npmjs.org/lerna/-/lerna-6.6.2.tgz",
@@ -5476,6 +8442,15 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/leven": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/levn": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -5643,6 +8618,21 @@
         "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
       }
     },
+    "node_modules/libsodium": {
+      "version": "0.7.15",
+      "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.15.tgz",
+      "integrity": "sha512-sZwRknt/tUpE2AwzHq3jEyUU5uvIZHtSssktXq7owd++3CSgn8RGrv6UZJJBpP7+iBghBqe7Z06/2M31rI2NKw==",
+      "dev": true
+    },
+    "node_modules/libsodium-wrappers": {
+      "version": "0.7.15",
+      "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.15.tgz",
+      "integrity": "sha512-E4anqJQwcfiC6+Yrl01C1m8p99wEhLmJSs0VQqST66SbQXXBoaJY0pF4BNjRYa/sOQAxx6lXAaAFIlx+15tXJQ==",
+      "dev": true,
+      "dependencies": {
+        "libsodium": "^0.7.15"
+      }
+    },
     "node_modules/lines-and-columns": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz",
@@ -5697,18 +8687,93 @@
       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
       "dev": true
     },
+    "node_modules/lodash._objecttypes": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz",
+      "integrity": "sha512-XpqGh1e7hhkOzftBfWE7zt+Yn9mVHFkDhicVttvKLsoCMLVVL+xTQjfjB4X4vtznauxv0QZ5ZAeqjvat0dh62Q==",
+      "dev": true
+    },
+    "node_modules/lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+      "dev": true
+    },
+    "node_modules/lodash.includes": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+      "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+      "dev": true
+    },
+    "node_modules/lodash.isboolean": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+      "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
+      "dev": true
+    },
+    "node_modules/lodash.isinteger": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+      "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
+      "dev": true
+    },
     "node_modules/lodash.ismatch": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
       "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==",
       "dev": true
     },
+    "node_modules/lodash.isnumber": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+      "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
+      "dev": true
+    },
+    "node_modules/lodash.isobject": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz",
+      "integrity": "sha512-sTebg2a1PoicYEZXD5PBdQcTlIJ6hUslrlWr7iV0O7n+i4596s2NQ9I5CaZ5FbXSfya/9WQsrYLANUJv9paYVA==",
+      "dev": true,
+      "dependencies": {
+        "lodash._objecttypes": "~2.4.1"
+      }
+    },
+    "node_modules/lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+      "dev": true
+    },
+    "node_modules/lodash.isstring": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+      "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+      "dev": true
+    },
+    "node_modules/lodash.mapvalues": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz",
+      "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==",
+      "dev": true
+    },
     "node_modules/lodash.merge": {
       "version": "4.6.2",
       "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
+    "node_modules/lodash.once": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+      "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+      "dev": true
+    },
+    "node_modules/lodash.snakecase": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
+      "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==",
+      "dev": true
+    },
     "node_modules/log-symbols": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -5725,6 +8790,38 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/logform": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz",
+      "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==",
+      "dev": true,
+      "dependencies": {
+        "@colors/colors": "1.6.0",
+        "@types/triple-beam": "^1.3.2",
+        "fecha": "^4.2.0",
+        "ms": "^2.1.1",
+        "safe-stable-stringify": "^2.3.1",
+        "triple-beam": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      }
+    },
+    "node_modules/logform/node_modules/@colors/colors": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
+      "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.1.90"
+      }
+    },
+    "node_modules/long": {
+      "version": "5.2.3",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
+      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==",
+      "dev": true
+    },
     "node_modules/lru-cache": {
       "version": "7.18.3",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
@@ -5734,6 +8831,80 @@
         "node": ">=12"
       }
     },
+    "node_modules/lsofi": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lsofi/-/lsofi-1.0.0.tgz",
+      "integrity": "sha512-MKr9vM1MSm+TSKfI05IYxpKV1NCxpJaBLnELyIf784zYJ5KV9lGCE1EvpA2DtXDNM3fCuFeCwXUzim/fyQRi+A==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^2.1.0",
+        "through2": "^2.0.1"
+      }
+    },
+    "node_modules/lsofi/node_modules/is-number": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+      "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/lsofi/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+      "dev": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/lsofi/node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "dev": true,
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/lsofi/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "node_modules/lsofi/node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/lsofi/node_modules/through2": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "~2.3.6",
+        "xtend": "~4.0.1"
+      }
+    },
     "node_modules/make-dir": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
@@ -5927,6 +9098,74 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/marked": {
+      "version": "13.0.3",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz",
+      "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==",
+      "dev": true,
+      "bin": {
+        "marked": "bin/marked.js"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/marked-terminal": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.1.0.tgz",
+      "integrity": "sha512-+pvwa14KZL74MVXjYdPR3nSInhGhNvPce/3mqLVZT2oUvt654sL1XImFuLZ1pkA866IYZ3ikDTOFUIC7XzpZZg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-escapes": "^7.0.0",
+        "chalk": "^5.3.0",
+        "cli-highlight": "^2.1.11",
+        "cli-table3": "^0.6.5",
+        "node-emoji": "^2.1.3",
+        "supports-hyperlinks": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      },
+      "peerDependencies": {
+        "marked": ">=1 <14"
+      }
+    },
+    "node_modules/marked-terminal/node_modules/ansi-escapes": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
+      "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==",
+      "dev": true,
+      "dependencies": {
+        "environment": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/marked-terminal/node_modules/chalk": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+      "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+      "dev": true,
+      "engines": {
+        "node": "^12.17.0 || ^14.13 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/meow": {
       "version": "8.1.2",
       "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz",
@@ -6132,6 +9371,15 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/merge-descriptors": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+      "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/merge-stream": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -6147,6 +9395,15 @@
         "node": ">= 8"
       }
     },
+    "node_modules/methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/micromatch": {
       "version": "4.0.5",
       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
@@ -6160,10 +9417,22 @@
         "node": ">=8.6"
       }
     },
-    "node_modules/mime-db": {
-      "version": "1.52.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
-      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+    "node_modules/mime": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
+      "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
+      "dev": true,
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
       "dev": true,
       "engines": {
         "node": ">= 0.6"
@@ -6235,9 +9504,9 @@
       }
     },
     "node_modules/minipass": {
-      "version": "7.0.4",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
-      "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
       "dev": true,
       "engines": {
         "node": ">=16 || 14 >=14.17"
@@ -6450,6 +9719,55 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/moo": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
+      "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==",
+      "dev": true
+    },
+    "node_modules/morgan": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
+      "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
+      "dev": true,
+      "dependencies": {
+        "basic-auth": "~2.0.1",
+        "debug": "2.6.9",
+        "depd": "~2.0.0",
+        "on-finished": "~2.3.0",
+        "on-headers": "~1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/morgan/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/morgan/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/morgan/node_modules/on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+      "dev": true,
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -6490,12 +9808,58 @@
       "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
       "dev": true
     },
+    "node_modules/mz": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+      "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+      "dev": true,
+      "dependencies": {
+        "any-promise": "^1.0.0",
+        "object-assign": "^4.0.1",
+        "thenify-all": "^1.0.0"
+      }
+    },
+    "node_modules/nan": {
+      "version": "2.20.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
+      "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
+      "dev": true,
+      "optional": true
+    },
     "node_modules/natural-compare": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
       "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
       "dev": true
     },
+    "node_modules/nearley": {
+      "version": "2.20.1",
+      "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz",
+      "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==",
+      "dev": true,
+      "dependencies": {
+        "commander": "^2.19.0",
+        "moo": "^0.5.0",
+        "railroad-diagrams": "^1.0.0",
+        "randexp": "0.4.6"
+      },
+      "bin": {
+        "nearley-railroad": "bin/nearley-railroad.js",
+        "nearley-test": "bin/nearley-test.js",
+        "nearley-unparse": "bin/nearley-unparse.js",
+        "nearleyc": "bin/nearleyc.js"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://nearley.js.org/#give-to-nearley"
+      }
+    },
+    "node_modules/nearley/node_modules/commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
     "node_modules/negotiator": {
       "version": "0.6.3",
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -6511,12 +9875,42 @@
       "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
       "dev": true
     },
+    "node_modules/netmask": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
+      "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
+    },
     "node_modules/node-addon-api": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
       "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
       "dev": true
     },
+    "node_modules/node-emoji": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz",
+      "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==",
+      "dev": true,
+      "dependencies": {
+        "@sindresorhus/is": "^4.6.0",
+        "char-regex": "^1.0.2",
+        "emojilib": "^2.4.0",
+        "skin-tone": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/node-fetch": {
       "version": "2.6.7",
       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -6644,6 +10038,15 @@
         "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
       }
     },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/npm-bundled": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz",
@@ -7198,6 +10601,57 @@
         "node": ">=12"
       }
     },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-hash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+      "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.2",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+      "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/on-finished": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+      "dev": true,
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/on-headers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -7207,6 +10661,15 @@
         "wrappy": "1"
       }
     },
+    "node_modules/one-time": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
+      "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
+      "dev": true,
+      "dependencies": {
+        "fn.name": "1.x.x"
+      }
+    },
     "node_modules/onetime": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
@@ -7239,6 +10702,27 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/openapi3-ts": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-3.2.0.tgz",
+      "integrity": "sha512-/ykNWRV5Qs0Nwq7Pc0nJ78fgILvOT/60OxEmB3v7yQ8a8Bwcm43D4diaYazG/KBn6czA+52XYy931WFLMCUeSg==",
+      "dev": true,
+      "dependencies": {
+        "yaml": "^2.2.1"
+      }
+    },
+    "node_modules/openapi3-ts/node_modules/yaml": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz",
+      "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==",
+      "dev": true,
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
     "node_modules/optionator": {
       "version": "0.9.3",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -7288,6 +10772,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/p-defer": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-3.0.0.tgz",
+      "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/p-finally": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
@@ -7388,6 +10881,18 @@
         "node": ">=8"
       }
     },
+    "node_modules/p-throttle": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/p-throttle/-/p-throttle-5.1.0.tgz",
+      "integrity": "sha512-+N+s2g01w1Zch4D0K3OpnPDqLOKmLcQ4BvIFq3JC0K29R28vUOjWpO+OJZBNt8X9i3pFCksZJZ0YXkUGjaFE6g==",
+      "dev": true,
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/p-timeout": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
@@ -7424,6 +10929,96 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/pac-proxy-agent": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==",
+      "dev": true,
+      "dependencies": {
+        "@tootallnate/quickjs-emscripten": "^0.23.0",
+        "agent-base": "^7.0.2",
+        "debug": "^4.3.4",
+        "get-uri": "^6.0.1",
+        "http-proxy-agent": "^7.0.0",
+        "https-proxy-agent": "^7.0.5",
+        "pac-resolver": "^7.0.1",
+        "socks-proxy-agent": "^8.0.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/pac-proxy-agent/node_modules/agent-base": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+      "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+      "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^7.0.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/pac-proxy-agent/node_modules/socks-proxy-agent": {
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz",
+      "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^7.1.1",
+        "debug": "^4.3.4",
+        "socks": "^2.8.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/pac-resolver": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
+      "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
+      "dev": true,
+      "dependencies": {
+        "degenerator": "^5.0.0",
+        "netmask": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/package-json-from-dist": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+      "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+      "dev": true
+    },
     "node_modules/pacote": {
       "version": "15.1.1",
       "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.1.tgz",
@@ -7681,6 +11276,36 @@
         "parse-path": "^7.0.0"
       }
     },
+    "node_modules/parse5": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+      "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
+      "dev": true
+    },
+    "node_modules/parse5-htmlparser2-tree-adapter": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
+      "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
+      "dev": true,
+      "dependencies": {
+        "parse5": "^6.0.1"
+      }
+    },
+    "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+      "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
+      "dev": true
+    },
+    "node_modules/parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/path-exists": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -7715,32 +11340,32 @@
       "dev": true
     },
     "node_modules/path-scurry": {
-      "version": "1.10.1",
-      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
-      "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+      "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
       "dev": true,
       "dependencies": {
-        "lru-cache": "^9.1.1 || ^10.0.0",
+        "lru-cache": "^10.2.0",
         "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
       },
       "engines": {
-        "node": ">=16 || 14 >=14.17"
+        "node": ">=16 || 14 >=14.18"
       },
       "funding": {
         "url": "https://github.com/sponsors/isaacs"
       }
     },
     "node_modules/path-scurry/node_modules/lru-cache": {
-      "version": "10.0.2",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.2.tgz",
-      "integrity": "sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg==",
-      "dev": true,
-      "dependencies": {
-        "semver": "^7.3.5"
-      },
-      "engines": {
-        "node": "14 || >=16.14"
-      }
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "dev": true
+    },
+    "node_modules/path-to-regexp": {
+      "version": "0.1.10",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
+      "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
+      "dev": true
     },
     "node_modules/path-type": {
       "version": "4.0.0",
@@ -7751,43 +11376,147 @@
         "node": ">=8"
       }
     },
-    "node_modules/picomatch": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+    "node_modules/pg": {
+      "version": "8.13.0",
+      "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.0.tgz",
+      "integrity": "sha512-34wkUTh3SxTClfoHB3pQ7bIMvw9dpFU1audQQeZG837fmHfHpr14n/AELVDoOYVDW2h5RDWU78tFjkD+erSBsw==",
       "dev": true,
+      "dependencies": {
+        "pg-connection-string": "^2.7.0",
+        "pg-pool": "^3.7.0",
+        "pg-protocol": "^1.7.0",
+        "pg-types": "^2.1.0",
+        "pgpass": "1.x"
+      },
       "engines": {
-        "node": ">=8.6"
+        "node": ">= 8.0.0"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/jonschlinkert"
+      "optionalDependencies": {
+        "pg-cloudflare": "^1.1.1"
+      },
+      "peerDependencies": {
+        "pg-native": ">=3.0.1"
+      },
+      "peerDependenciesMeta": {
+        "pg-native": {
+          "optional": true
+        }
       }
     },
-    "node_modules/pify": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz",
-      "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==",
+    "node_modules/pg-cloudflare": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz",
+      "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==",
       "dev": true,
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
+      "optional": true
     },
-    "node_modules/pkg-dir": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
-      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+    "node_modules/pg-connection-string": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz",
+      "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==",
+      "dev": true
+    },
+    "node_modules/pg-int8": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
+      "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
       "dev": true,
-      "dependencies": {
-        "find-up": "^4.0.0"
-      },
       "engines": {
-        "node": ">=8"
+        "node": ">=4.0.0"
       }
     },
-    "node_modules/pkg-dir/node_modules/find-up": {
+    "node_modules/pg-pool": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz",
+      "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==",
+      "dev": true,
+      "peerDependencies": {
+        "pg": ">=8.0"
+      }
+    },
+    "node_modules/pg-protocol": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz",
+      "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==",
+      "dev": true
+    },
+    "node_modules/pg-types": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
+      "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
+      "dev": true,
+      "dependencies": {
+        "pg-int8": "1.0.1",
+        "postgres-array": "~2.0.0",
+        "postgres-bytea": "~1.0.0",
+        "postgres-date": "~1.0.4",
+        "postgres-interval": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/pgpass": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
+      "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
+      "dev": true,
+      "dependencies": {
+        "split2": "^4.1.0"
+      }
+    },
+    "node_modules/pgpass/node_modules/split2": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+      "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10.x"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+      "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
+      "dev": true
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pify": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz",
+      "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/find-up": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
       "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
@@ -7839,6 +11568,50 @@
         "node": ">=8"
       }
     },
+    "node_modules/portfinder": {
+      "version": "1.0.32",
+      "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
+      "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==",
+      "dev": true,
+      "dependencies": {
+        "async": "^2.6.4",
+        "debug": "^3.2.7",
+        "mkdirp": "^0.5.6"
+      },
+      "engines": {
+        "node": ">= 0.12.0"
+      }
+    },
+    "node_modules/portfinder/node_modules/async": {
+      "version": "2.6.4",
+      "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+      "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.14"
+      }
+    },
+    "node_modules/portfinder/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/portfinder/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==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
     "node_modules/postcss-selector-parser": {
       "version": "6.0.13",
       "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
@@ -7849,179 +11622,690 @@
         "util-deprecate": "^1.0.2"
       },
       "engines": {
-        "node": ">=4"
+        "node": ">=4"
+      }
+    },
+    "node_modules/postgres-array": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
+      "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postgres-bytea": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
+      "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/postgres-date": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
+      "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/postgres-interval": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
+      "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
+      "dev": true,
+      "dependencies": {
+        "xtend": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/pretty-format": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz",
+      "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==",
+      "dev": true,
+      "dependencies": {
+        "@jest/schemas": "^29.4.3",
+        "ansi-styles": "^5.0.0",
+        "react-is": "^18.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/pretty-format/node_modules/ansi-styles": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+      "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/proc-log": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz",
+      "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==",
+      "dev": true,
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true
+    },
+    "node_modules/progress": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/promise-all-reject-late": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz",
+      "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/promise-breaker": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-6.0.0.tgz",
+      "integrity": "sha512-BthzO9yTPswGf7etOBiHCVuugs2N01/Q/94dIPls48z2zCmrnDptUUZzfIb+41xq0MnYZ/BzmOd6ikDR4ibNZA==",
+      "dev": true
+    },
+    "node_modules/promise-call-limit": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.2.tgz",
+      "integrity": "sha512-1vTUnfI2hzui8AEIixbdAJlFY4LFDXqQswy/2eOlThAscXCY4It8FdVuI0fMJGAB2aWGbdQf/gv0skKYXmdrHA==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/promise-inflight": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+      "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==",
+      "dev": true
+    },
+    "node_modules/promise-retry": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+      "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+      "dev": true,
+      "dependencies": {
+        "err-code": "^2.0.2",
+        "retry": "^0.12.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/promzard": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz",
+      "integrity": "sha512-JZeYqd7UAcHCwI+sTOeUDYkvEU+1bQ7iE0UT1MgB/tERkAPkesW46MrpIySzODi+owTjZtiF8Ay5j9m60KmMBw==",
+      "dev": true,
+      "dependencies": {
+        "read": "1"
+      }
+    },
+    "node_modules/proto-list": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+      "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
+      "dev": true
+    },
+    "node_modules/proto3-json-serializer": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz",
+      "integrity": "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==",
+      "dev": true,
+      "dependencies": {
+        "protobufjs": "^7.2.5"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/protobufjs": {
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
+      "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/protocols": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz",
+      "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==",
+      "dev": true
+    },
+    "node_modules/proxy-addr": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+      "dev": true,
+      "dependencies": {
+        "forwarded": "0.2.0",
+        "ipaddr.js": "1.9.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/proxy-agent": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz",
+      "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^7.0.2",
+        "debug": "^4.3.4",
+        "http-proxy-agent": "^7.0.1",
+        "https-proxy-agent": "^7.0.3",
+        "lru-cache": "^7.14.1",
+        "pac-proxy-agent": "^7.0.1",
+        "proxy-from-env": "^1.1.0",
+        "socks-proxy-agent": "^8.0.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/proxy-agent/node_modules/agent-base": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+      "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/proxy-agent/node_modules/http-proxy-agent": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/proxy-agent/node_modules/https-proxy-agent": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+      "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^7.0.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/proxy-agent/node_modules/socks-proxy-agent": {
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz",
+      "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^7.1.1",
+        "debug": "^4.3.4",
+        "socks": "^2.8.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+      "dev": true
+    },
+    "node_modules/pump": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
+      "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
+      "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",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/pupa": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz",
+      "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==",
+      "dev": true,
+      "dependencies": {
+        "escape-goat": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/q": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+      "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6.0",
+        "teleport": ">=0.2.0"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+      "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+      "dev": true,
+      "dependencies": {
+        "side-channel": "^1.0.6"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/queue-tick": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
+      "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
+      "dev": true
+    },
+    "node_modules/quick-lru": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+      "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/railroad-diagrams": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
+      "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==",
+      "dev": true
+    },
+    "node_modules/randexp": {
+      "version": "0.4.6",
+      "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz",
+      "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==",
+      "dev": true,
+      "dependencies": {
+        "discontinuous-range": "1.0.0",
+        "ret": "~0.1.10"
+      },
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/raw-body": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+      "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+      "dev": true,
+      "dependencies": {
+        "bytes": "3.1.2",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "dev": true,
+      "dependencies": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "bin": {
+        "rc": "cli.js"
+      }
+    },
+    "node_modules/rc/node_modules/strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/re2": {
+      "version": "1.21.4",
+      "resolved": "https://registry.npmjs.org/re2/-/re2-1.21.4.tgz",
+      "integrity": "sha512-MVIfXWJmsP28mRsSt8HeL750ifb8H5+oF2UDIxGaiJCr8fkMqhLZ7kcX9ADRk2dC8qeGKedB7UVYRfBVpEiLfA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "dependencies": {
+        "install-artifact-from-github": "^1.3.5",
+        "nan": "^2.20.0",
+        "node-gyp": "^10.2.0"
+      }
+    },
+    "node_modules/re2/node_modules/cacache": {
+      "version": "18.0.4",
+      "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz",
+      "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "@npmcli/fs": "^3.1.0",
+        "fs-minipass": "^3.0.0",
+        "glob": "^10.2.2",
+        "lru-cache": "^10.0.1",
+        "minipass": "^7.0.3",
+        "minipass-collect": "^2.0.1",
+        "minipass-flush": "^1.0.5",
+        "minipass-pipeline": "^1.2.4",
+        "p-map": "^4.0.0",
+        "ssri": "^10.0.0",
+        "tar": "^6.1.11",
+        "unique-filename": "^3.0.0"
+      },
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
+      }
+    },
+    "node_modules/re2/node_modules/isexe": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
+      "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
+      "dev": true,
+      "optional": true,
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/re2/node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/re2/node_modules/make-fetch-happen": {
+      "version": "13.0.1",
+      "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz",
+      "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "@npmcli/agent": "^2.0.0",
+        "cacache": "^18.0.0",
+        "http-cache-semantics": "^4.1.1",
+        "is-lambda": "^1.0.1",
+        "minipass": "^7.0.2",
+        "minipass-fetch": "^3.0.0",
+        "minipass-flush": "^1.0.5",
+        "minipass-pipeline": "^1.2.4",
+        "negotiator": "^0.6.3",
+        "proc-log": "^4.2.0",
+        "promise-retry": "^2.0.1",
+        "ssri": "^10.0.0"
+      },
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
       }
     },
-    "node_modules/prelude-ls": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
-      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+    "node_modules/re2/node_modules/minipass-collect": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz",
+      "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==",
       "dev": true,
+      "optional": true,
+      "dependencies": {
+        "minipass": "^7.0.3"
+      },
       "engines": {
-        "node": ">= 0.8.0"
+        "node": ">=16 || 14 >=14.17"
       }
     },
-    "node_modules/pretty-format": {
-      "version": "29.4.3",
-      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz",
-      "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==",
+    "node_modules/re2/node_modules/minipass-fetch": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz",
+      "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==",
       "dev": true,
+      "optional": true,
       "dependencies": {
-        "@jest/schemas": "^29.4.3",
-        "ansi-styles": "^5.0.0",
-        "react-is": "^18.0.0"
+        "minipass": "^7.0.3",
+        "minipass-sized": "^1.0.3",
+        "minizlib": "^2.1.2"
       },
       "engines": {
-        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      },
+      "optionalDependencies": {
+        "encoding": "^0.1.13"
       }
     },
-    "node_modules/pretty-format/node_modules/ansi-styles": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
-      "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+    "node_modules/re2/node_modules/node-gyp": {
+      "version": "10.2.0",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.2.0.tgz",
+      "integrity": "sha512-sp3FonBAaFe4aYTcFdZUn2NYkbP7xroPGYvQmP4Nl5PxamznItBnNCgjrVTKrEfQynInMsJvZrdmqUnysCJ8rw==",
       "dev": true,
-      "engines": {
-        "node": ">=10"
+      "optional": true,
+      "dependencies": {
+        "env-paths": "^2.2.0",
+        "exponential-backoff": "^3.1.1",
+        "glob": "^10.3.10",
+        "graceful-fs": "^4.2.6",
+        "make-fetch-happen": "^13.0.0",
+        "nopt": "^7.0.0",
+        "proc-log": "^4.1.0",
+        "semver": "^7.3.5",
+        "tar": "^6.2.1",
+        "which": "^4.0.0"
       },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      "bin": {
+        "node-gyp": "bin/node-gyp.js"
+      },
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
       }
     },
-    "node_modules/proc-log": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz",
-      "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==",
+    "node_modules/re2/node_modules/proc-log": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz",
+      "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==",
       "dev": true,
+      "optional": true,
       "engines": {
         "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
       }
     },
-    "node_modules/process": {
-      "version": "0.11.10",
-      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
-      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+    "node_modules/re2/node_modules/ssri": {
+      "version": "10.0.6",
+      "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz",
+      "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==",
       "dev": true,
+      "optional": true,
+      "dependencies": {
+        "minipass": "^7.0.3"
+      },
       "engines": {
-        "node": ">= 0.6.0"
-      }
-    },
-    "node_modules/process-nextick-args": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
-      "dev": true
-    },
-    "node_modules/promise-all-reject-late": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz",
-      "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==",
-      "dev": true,
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/promise-call-limit": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.2.tgz",
-      "integrity": "sha512-1vTUnfI2hzui8AEIixbdAJlFY4LFDXqQswy/2eOlThAscXCY4It8FdVuI0fMJGAB2aWGbdQf/gv0skKYXmdrHA==",
-      "dev": true,
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
       }
     },
-    "node_modules/promise-inflight": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
-      "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==",
-      "dev": true
-    },
-    "node_modules/promise-retry": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
-      "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+    "node_modules/re2/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,
+      "optional": true,
       "dependencies": {
-        "err-code": "^2.0.2",
-        "retry": "^0.12.0"
+        "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/promzard": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz",
-      "integrity": "sha512-JZeYqd7UAcHCwI+sTOeUDYkvEU+1bQ7iE0UT1MgB/tERkAPkesW46MrpIySzODi+owTjZtiF8Ay5j9m60KmMBw==",
+    "node_modules/re2/node_modules/tar/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,
+      "optional": true,
       "dependencies": {
-        "read": "1"
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
       }
     },
-    "node_modules/proto-list": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
-      "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
-      "dev": true
-    },
-    "node_modules/protocols": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz",
-      "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==",
-      "dev": true
-    },
-    "node_modules/proxy-from-env": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
-      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
-      "dev": true
-    },
-    "node_modules/punycode": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
-      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+    "node_modules/re2/node_modules/tar/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,
-      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
       "engines": {
-        "node": ">=6"
+        "node": ">=8"
       }
     },
-    "node_modules/q": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
-      "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
+    "node_modules/re2/node_modules/tar/node_modules/minipass": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+      "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
       "dev": true,
+      "optional": true,
       "engines": {
-        "node": ">=0.6.0",
-        "teleport": ">=0.2.0"
+        "node": ">=8"
       }
     },
-    "node_modules/queue-microtask": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
-      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ]
-    },
-    "node_modules/quick-lru": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
-      "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+    "node_modules/re2/node_modules/which": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
+      "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
       "dev": true,
+      "optional": true,
+      "dependencies": {
+        "isexe": "^3.1.1"
+      },
+      "bin": {
+        "node-which": "bin/which.js"
+      },
       "engines": {
-        "node": ">=8"
+        "node": "^16.13.0 || >=18.0.0"
       }
     },
     "node_modules/react-is": {
@@ -8351,6 +12635,48 @@
         "node": ">= 6"
       }
     },
+    "node_modules/readdir-glob": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
+      "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
+      "dev": true,
+      "dependencies": {
+        "minimatch": "^5.1.0"
+      }
+    },
+    "node_modules/readdir-glob/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/readdir-glob/node_modules/minimatch": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
     "node_modules/redent": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
@@ -8364,6 +12690,30 @@
         "node": ">=8"
       }
     },
+    "node_modules/registry-auth-token": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz",
+      "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==",
+      "dev": true,
+      "dependencies": {
+        "@pnpm/npm-conf": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/registry-url": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz",
+      "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==",
+      "dev": true,
+      "dependencies": {
+        "rc": "^1.2.8"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/require-directory": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -8373,6 +12723,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/resolve": {
       "version": "1.22.8",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -8433,13 +12792,36 @@
         "node": ">=8"
       }
     },
+    "node_modules/ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
     "node_modules/retry": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
       "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
       "dev": true,
       "engines": {
-        "node": ">= 4"
+        "node": ">= 4"
+      }
+    },
+    "node_modules/retry-request": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz",
+      "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==",
+      "dev": true,
+      "dependencies": {
+        "@types/request": "^2.48.8",
+        "extend": "^3.0.2",
+        "teeny-request": "^9.0.0"
+      },
+      "engines": {
+        "node": ">=14"
       }
     },
     "node_modules/reusify": {
@@ -8487,6 +12869,51 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/router": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/router/-/router-1.3.8.tgz",
+      "integrity": "sha512-461UFH44NtSfIlS83PUg2N7OZo86BC/kB3dY77gJdsODsBhhw7+2uE0tzTINxrY9CahCUVk1VhpWCA5i1yoIEg==",
+      "dev": true,
+      "dependencies": {
+        "array-flatten": "3.0.0",
+        "debug": "2.6.9",
+        "methods": "~1.1.2",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "setprototypeof": "1.2.0",
+        "utils-merge": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/router/node_modules/array-flatten": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-3.0.0.tgz",
+      "integrity": "sha512-zPMVc3ZYlGLNk4mpK1NzP2wg0ml9t7fUgDsayR5Y5rSzxQilzR9FGu/EH2jQOcKSAeAfWeylyW8juy3OkWRvNA==",
+      "dev": true
+    },
+    "node_modules/router/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/router/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/router/node_modules/path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+      "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
+      "dev": true
+    },
     "node_modules/run-async": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@@ -8548,6 +12975,15 @@
         }
       ]
     },
+    "node_modules/safe-stable-stringify": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
+      "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -8569,6 +13005,27 @@
         "node": ">=10"
       }
     },
+    "node_modules/semver-diff": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
+      "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/semver-diff/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
     "node_modules/semver/node_modules/lru-cache": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -8581,12 +13038,116 @@
         "node": ">=10"
       }
     },
+    "node_modules/send": {
+      "version": "0.19.0",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+      "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
+      "dev": true,
+      "dependencies": {
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "mime": "1.6.0",
+        "ms": "2.1.3",
+        "on-finished": "2.4.1",
+        "range-parser": "~1.2.1",
+        "statuses": "2.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/send/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/send/node_modules/debug/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/send/node_modules/encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/send/node_modules/mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "dev": true,
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/send/node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true
+    },
+    "node_modules/serve-static": {
+      "version": "1.16.2",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+      "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
+      "dev": true,
+      "dependencies": {
+        "encodeurl": "~2.0.0",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.19.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
     "node_modules/set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
       "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
       "dev": true
     },
+    "node_modules/set-function-length": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+      "dev": true,
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+      "dev": true
+    },
     "node_modules/shallow-clone": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
@@ -8620,6 +13181,24 @@
         "node": ">=8"
       }
     },
+    "node_modules/side-channel": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+      "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4",
+        "object-inspect": "^1.13.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/signal-exit": {
       "version": "3.0.7",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -8727,6 +13306,33 @@
         "node": ">=16 || 14 >=14.17"
       }
     },
+    "node_modules/simple-swizzle": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+      "dev": true,
+      "dependencies": {
+        "is-arrayish": "^0.3.1"
+      }
+    },
+    "node_modules/simple-swizzle/node_modules/is-arrayish": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+      "dev": true
+    },
+    "node_modules/skin-tone": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz",
+      "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==",
+      "dev": true,
+      "dependencies": {
+        "unicode-emoji-modifier-base": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/slash": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -8747,16 +13353,16 @@
       }
     },
     "node_modules/socks": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
-      "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
+      "version": "2.8.3",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
+      "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
       "dev": true,
       "dependencies": {
-        "ip": "^2.0.0",
+        "ip-address": "^9.0.5",
         "smart-buffer": "^4.2.0"
       },
       "engines": {
-        "node": ">= 10.13.0",
+        "node": ">= 10.0.0",
         "npm": ">= 3.0.0"
       }
     },
@@ -8774,6 +13380,15 @@
         "node": ">= 10"
       }
     },
+    "node_modules/sort-any": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/sort-any/-/sort-any-2.0.0.tgz",
+      "integrity": "sha512-T9JoiDewQEmWcnmPn/s9h/PH9t3d/LSWi0RgVmXSuDYeZXTZOZ1/wrK2PHaptuR1VXe3clLLt0pD6sgVOwjNEA==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.21"
+      }
+    },
     "node_modules/sort-keys": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz",
@@ -8854,6 +13469,20 @@
       "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
       "dev": true
     },
+    "node_modules/sql-formatter": {
+      "version": "15.4.2",
+      "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.4.2.tgz",
+      "integrity": "sha512-Pw4aAgfuyml/SHMlhbJhyOv+GR+Z1HNb9sgX3CVBVdN5YNM+v2VWkYJ3NNbYS7cu37GY3vP/PgnwoVynCuXRxg==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "get-stdin": "=8.0.0",
+        "nearley": "^2.20.1"
+      },
+      "bin": {
+        "sql-formatter": "bin/sql-formatter-cli.cjs"
+      }
+    },
     "node_modules/ssri": {
       "version": "9.0.1",
       "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz",
@@ -8878,6 +13507,68 @@
         "node": ">=8"
       }
     },
+    "node_modules/stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/statuses": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/stream-chain": {
+      "version": "2.2.5",
+      "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz",
+      "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==",
+      "dev": true
+    },
+    "node_modules/stream-events": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz",
+      "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==",
+      "dev": true,
+      "dependencies": {
+        "stubs": "^3.0.0"
+      }
+    },
+    "node_modules/stream-json": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.8.0.tgz",
+      "integrity": "sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw==",
+      "dev": true,
+      "dependencies": {
+        "stream-chain": "^2.2.5"
+      }
+    },
+    "node_modules/stream-shift": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
+      "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==",
+      "dev": true
+    },
+    "node_modules/streamx": {
+      "version": "2.20.1",
+      "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz",
+      "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==",
+      "dev": true,
+      "dependencies": {
+        "fast-fifo": "^1.3.2",
+        "queue-tick": "^1.0.1",
+        "text-decoder": "^1.1.0"
+      },
+      "optionalDependencies": {
+        "bare-events": "^2.2.0"
+      }
+    },
     "node_modules/string_decoder": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -9001,6 +13692,95 @@
         "node": ">=4"
       }
     },
+    "node_modules/stubs": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz",
+      "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==",
+      "dev": true
+    },
+    "node_modules/superstatic": {
+      "version": "9.0.3",
+      "resolved": "https://registry.npmjs.org/superstatic/-/superstatic-9.0.3.tgz",
+      "integrity": "sha512-e/tmW0bsnQ/33ivK6y3CapJT0Ovy4pk/ohNPGhIAGU2oasoNLRQ1cv6enua09NU9w6Y0H/fBu07cjzuiWvLXxw==",
+      "dev": true,
+      "dependencies": {
+        "basic-auth-connect": "^1.0.0",
+        "commander": "^10.0.0",
+        "compression": "^1.7.0",
+        "connect": "^3.7.0",
+        "destroy": "^1.0.4",
+        "fast-url-parser": "^1.1.3",
+        "glob-slasher": "^1.0.1",
+        "is-url": "^1.2.2",
+        "join-path": "^1.1.1",
+        "lodash": "^4.17.19",
+        "mime-types": "^2.1.35",
+        "minimatch": "^6.1.6",
+        "morgan": "^1.8.2",
+        "on-finished": "^2.2.0",
+        "on-headers": "^1.0.0",
+        "path-to-regexp": "^1.8.0",
+        "router": "^1.3.1",
+        "update-notifier-cjs": "^5.1.6"
+      },
+      "bin": {
+        "superstatic": "lib/bin/server.js"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.4.0"
+      },
+      "optionalDependencies": {
+        "re2": "^1.17.7"
+      }
+    },
+    "node_modules/superstatic/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/superstatic/node_modules/commander": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+      "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+      "dev": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/superstatic/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/superstatic/node_modules/minimatch": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz",
+      "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/superstatic/node_modules/path-to-regexp": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz",
+      "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==",
+      "dev": true,
+      "dependencies": {
+        "isarray": "0.0.1"
+      }
+    },
     "node_modules/supports-color": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -9013,6 +13793,22 @@
         "node": ">=8"
       }
     },
+    "node_modules/supports-hyperlinks": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz",
+      "integrity": "sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0",
+        "supports-color": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=14.18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/supports-preserve-symlinks-flag": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
@@ -9067,19 +13863,95 @@
         "minipass": "^3.0.0"
       },
       "engines": {
-        "node": ">= 8"
+        "node": ">= 8"
+      }
+    },
+    "node_modules/tar/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/tcp-port-used": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz",
+      "integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "4.3.1",
+        "is2": "^2.0.6"
+      }
+    },
+    "node_modules/tcp-port-used/node_modules/debug": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+      "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/teeny-request": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz",
+      "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==",
+      "dev": true,
+      "dependencies": {
+        "http-proxy-agent": "^5.0.0",
+        "https-proxy-agent": "^5.0.0",
+        "node-fetch": "^2.6.9",
+        "stream-events": "^1.0.5",
+        "uuid": "^9.0.0"
+      },
+      "engines": {
+        "node": ">=14"
       }
     },
-    "node_modules/tar/node_modules/minipass": {
-      "version": "3.3.6",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
-      "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+    "node_modules/teeny-request/node_modules/node-fetch": {
+      "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": {
-        "yallist": "^4.0.0"
+        "whatwg-url": "^5.0.0"
       },
       "engines": {
-        "node": ">=8"
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/teeny-request/node_modules/uuid": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+      "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+      "dev": true,
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "bin": {
+        "uuid": "dist/bin/uuid"
       }
     },
     "node_modules/temp-dir": {
@@ -9131,6 +14003,15 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/text-decoder": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.0.tgz",
+      "integrity": "sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==",
+      "dev": true,
+      "dependencies": {
+        "b4a": "^1.6.4"
+      }
+    },
     "node_modules/text-extensions": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz",
@@ -9140,12 +14021,39 @@
         "node": ">=0.10"
       }
     },
+    "node_modules/text-hex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
+      "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
+      "dev": true
+    },
     "node_modules/text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
       "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
       "dev": true
     },
+    "node_modules/thenify": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+      "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+      "dev": true,
+      "dependencies": {
+        "any-promise": "^1.0.0"
+      }
+    },
+    "node_modules/thenify-all": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+      "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+      "dev": true,
+      "dependencies": {
+        "thenify": ">= 3.1.0 < 4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/through": {
       "version": "2.3.8",
       "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
@@ -9162,15 +14070,12 @@
       }
     },
     "node_modules/tmp": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
-      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
+      "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
       "dev": true,
-      "dependencies": {
-        "rimraf": "^3.0.0"
-      },
       "engines": {
-        "node": ">=8.17.0"
+        "node": ">=14.14"
       }
     },
     "node_modules/to-regex-range": {
@@ -9185,6 +14090,24 @@
         "node": ">=8.0"
       }
     },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/toxic": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toxic/-/toxic-1.0.1.tgz",
+      "integrity": "sha512-WI3rIGdcaKULYg7KVoB0zcjikqvcYYvcuT6D89bFPz2rVR0Rl0PK6x8/X62rtdLtBKIE985NzVf/auTtGegIIg==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.10"
+      }
+    },
     "node_modules/tr46": {
       "version": "0.0.3",
       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@@ -9209,6 +14132,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/triple-beam": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
+      "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
     "node_modules/ts-api-utils": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
@@ -9251,6 +14183,15 @@
       "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
       "dev": true
     },
+    "node_modules/tsscmp": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
+      "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6.x"
+      }
+    },
     "node_modules/tuf-js": {
       "version": "1.1.7",
       "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz",
@@ -9372,12 +14313,34 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "dev": true,
+      "dependencies": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/typedarray": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
       "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
       "dev": true
     },
+    "node_modules/typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "dev": true,
+      "dependencies": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
     "node_modules/typescript": {
       "version": "4.9.5",
       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
@@ -9404,6 +14367,21 @@
         "node": ">=0.8.0"
       }
     },
+    "node_modules/undici-types": {
+      "version": "6.19.8",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+      "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+      "dev": true
+    },
+    "node_modules/unicode-emoji-modifier-base": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz",
+      "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/unique-filename": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz",
@@ -9440,6 +14418,19 @@
         "node": ">=8"
       }
     },
+    "node_modules/universal-analytics": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.5.3.tgz",
+      "integrity": "sha512-HXSMyIcf2XTvwZ6ZZQLfxfViRm/yTGoRgDeTbojtq6rezeyKB0sTBcKH2fhddnteAHRcHiKgr/ACpbgjGOC6RQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.3.1",
+        "uuid": "^8.0.0"
+      },
+      "engines": {
+        "node": ">=12.18.2"
+      }
+    },
     "node_modules/universal-user-agent": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
@@ -9455,6 +14446,15 @@
         "node": ">= 10.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==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/upath": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz",
@@ -9465,6 +14465,33 @@
         "yarn": "*"
       }
     },
+    "node_modules/update-notifier-cjs": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/update-notifier-cjs/-/update-notifier-cjs-5.1.6.tgz",
+      "integrity": "sha512-wgxdSBWv3x/YpMzsWz5G4p4ec7JWD0HCl8W6bmNB6E5Gwo+1ym5oN4hiXpLf0mPySVEJEIsYlkshnplkg2OP9A==",
+      "dev": true,
+      "dependencies": {
+        "boxen": "^5.0.0",
+        "chalk": "^4.1.0",
+        "configstore": "^5.0.1",
+        "has-yarn": "^2.1.0",
+        "import-lazy": "^2.1.0",
+        "is-ci": "^2.0.0",
+        "is-installed-globally": "^0.4.0",
+        "is-npm": "^5.0.0",
+        "is-yarn-global": "^0.3.0",
+        "isomorphic-fetch": "^3.0.0",
+        "pupa": "^2.1.1",
+        "registry-auth-token": "^5.0.1",
+        "registry-url": "^5.1.0",
+        "semver": "^7.3.7",
+        "semver-diff": "^3.1.1",
+        "xdg-basedir": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
     "node_modules/uri-js": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -9475,12 +14502,33 @@
         "punycode": "^2.1.0"
       }
     },
+    "node_modules/url-join": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/url-join/-/url-join-0.0.1.tgz",
+      "integrity": "sha512-H6dnQ/yPAAVzMQRvEvyz01hhfQL5qRWSEt7BX8t9DqnPw9BjMb64fjIRq76Uvf1hkHp+mTZvEVJ5guXOT0Xqaw==",
+      "dev": true
+    },
+    "node_modules/url-template": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
+      "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==",
+      "dev": true
+    },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
       "dev": true
     },
+    "node_modules/utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
     "node_modules/uuid": {
       "version": "8.3.2",
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
@@ -9496,6 +14544,12 @@
       "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
       "dev": true
     },
+    "node_modules/valid-url": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz",
+      "integrity": "sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==",
+      "dev": true
+    },
     "node_modules/validate-npm-package-license": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@@ -9518,6 +14572,15 @@
         "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
+    "node_modules/vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/walk-up-path": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-1.0.0.tgz",
@@ -9539,6 +14602,12 @@
       "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
       "dev": true
     },
+    "node_modules/whatwg-fetch": {
+      "version": "3.6.20",
+      "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
+      "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==",
+      "dev": true
+    },
     "node_modules/whatwg-url": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
@@ -9573,6 +14642,103 @@
         "string-width": "^1.0.2 || 2 || 3 || 4"
       }
     },
+    "node_modules/widest-line": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
+      "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/winston": {
+      "version": "3.14.2",
+      "resolved": "https://registry.npmjs.org/winston/-/winston-3.14.2.tgz",
+      "integrity": "sha512-CO8cdpBB2yqzEf8v895L+GNKYJiEq8eKlHU38af3snQBQ+sdAIUepjMSguOIJC7ICbzm0ZI+Af2If4vIJrtmOg==",
+      "dev": true,
+      "dependencies": {
+        "@colors/colors": "^1.6.0",
+        "@dabh/diagnostics": "^2.0.2",
+        "async": "^3.2.3",
+        "is-stream": "^2.0.0",
+        "logform": "^2.6.0",
+        "one-time": "^1.0.0",
+        "readable-stream": "^3.4.0",
+        "safe-stable-stringify": "^2.3.1",
+        "stack-trace": "0.0.x",
+        "triple-beam": "^1.3.0",
+        "winston-transport": "^4.7.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      }
+    },
+    "node_modules/winston-transport": {
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.8.0.tgz",
+      "integrity": "sha512-qxSTKswC6llEMZKgCQdaWgDuMJQnhuvF5f2Nk3SNXc4byfQ+voo2mX1Px9dkNOuR8p0KAjfPG29PuYUSIb+vSA==",
+      "dev": true,
+      "dependencies": {
+        "logform": "^2.6.1",
+        "readable-stream": "^4.5.2",
+        "triple-beam": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      }
+    },
+    "node_modules/winston-transport/node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/winston-transport/node_modules/readable-stream": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+      "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+      "dev": true,
+      "dependencies": {
+        "abort-controller": "^3.0.0",
+        "buffer": "^6.0.3",
+        "events": "^3.3.0",
+        "process": "^0.11.10",
+        "string_decoder": "^1.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/winston/node_modules/@colors/colors": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
+      "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.1.90"
+      }
+    },
     "node_modules/wordwrap": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
@@ -9712,6 +14878,36 @@
         "node": ">=6"
       }
     },
+    "node_modules/ws": {
+      "version": "7.5.10",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+      "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.3.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": "^5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/xdg-basedir": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
+      "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/xtend": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@@ -9783,6 +14979,60 @@
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
+    },
+    "node_modules/zip-stream": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz",
+      "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==",
+      "dev": true,
+      "dependencies": {
+        "archiver-utils": "^5.0.0",
+        "compress-commons": "^6.0.2",
+        "readable-stream": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/zip-stream/node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/zip-stream/node_modules/readable-stream": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+      "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+      "dev": true,
+      "dependencies": {
+        "abort-controller": "^3.0.0",
+        "buffer": "^6.0.3",
+        "events": "^3.3.0",
+        "process": "^0.11.10",
+        "string_decoder": "^1.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
     }
   }
 }
diff --git a/package.json b/package.json
index c46c994eb..6b56bb038 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
     "eslint-plugin-promise": "^6.1.1",
     "eslint-plugin-react-hooks": "^4.6.2",
     "eslint-plugin-react-refresh": "^0.4.9",
+    "firebase-tools": "^13.20.2",
     "lerna": "^6.6.1"
   },
   "scripts": {

From 067fc36d4331f53edcad215f026479765ed1d6ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ros=C3=A1rio=20P=2E=20Fernandes?= <rosariopf@google.com>
Date: Tue, 8 Oct 2024 21:54:00 +0100
Subject: [PATCH 54/82] docs: update dataconnect/README.md (#836)

* docs: fix Cloud Console URL

* Update README.md
---
 dataconnect/README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/dataconnect/README.md b/dataconnect/README.md
index eedfa8353..2fea10be7 100644
--- a/dataconnect/README.md
+++ b/dataconnect/README.md
@@ -1,4 +1,4 @@
-# Firebase DataConnect Quickstart
+# Firebase Data Connect Quickstart
 
 ## Introduction
 
@@ -13,7 +13,7 @@ Follow these steps to get up and running with Firebase DataConnect. For more det
 1. Open [Firebase Data Connect](https://console.firebase.google.com/u/0/project/_/dataconnect) in your Firebase Console project and select **Get Started**.
 2. Create a new Data Connect service and a Cloud SQL instance. Ensure the Blaze plan is active. Find pricing details at [Firebase Pricing](https://firebase.google.com/pricing).
 3. Choose your server region. If you plan to use vector search, select `us-central1`.
-4. Wait for the Cloud SQL instance to be provisioned. Once it's ready, you can manage it in the [Cloud Console](https://pantheon.corp.google.com/sql).
+4. Wait for the Cloud SQL instance to be provisioned. Once it's ready, you can manage it in the [Cloud Console](https://console.cloud.google.com/sql).
 
 ### 2. Set Up Firebase CLI
 

From 491de82b4bce957f85362ffd98760717877cd3d0 Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Thu, 23 Jan 2025 11:08:18 -0500
Subject: [PATCH 55/82] Do not run ESLint in dataconnect-sdk

---
 scripts/test.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/test.sh b/scripts/test.sh
index 09ea4dbcf..dbc6e798a 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -1,4 +1,4 @@
 set -e
 # Run linter
-find . -type f -name "*.js" -not -path "*node_modules*" \
+find . -type f -name "*.js" -not -path "*node_modules*" -not -path "*dataconnect-sdk/*" \
   | xargs eslint

From 3302baf2ddbb21328898f051f5d630ba8319ac0f Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Thu, 23 Jan 2025 11:42:47 -0600
Subject: [PATCH 56/82] Upgrade firebase version to v11 (#857)

---
 vertexai/main.ts           |   4 +-
 vertexai/package-lock.json | 652 ++++++++++++++++++++-----------------
 vertexai/package.json      |   6 +-
 3 files changed, 351 insertions(+), 311 deletions(-)

diff --git a/vertexai/main.ts b/vertexai/main.ts
index 6c96971df..b5f8a675f 100644
--- a/vertexai/main.ts
+++ b/vertexai/main.ts
@@ -21,7 +21,7 @@ import {
   initializeAppCheck,
   ReCaptchaEnterpriseProvider,
 } from "firebase/app-check";
-import { getVertexAI, getGenerativeModel } from "firebase/vertexai-preview";
+import { getVertexAI, getGenerativeModel } from "firebase/vertexai";
 
 async function main() {
   const app = initializeApp(firebaseConfig);
@@ -38,7 +38,7 @@ async function main() {
   // Get a Gemini model
   const model = getGenerativeModel(
     vertexAI,
-    { model: "gemini-1.5-flash-preview-0514" }
+    { model: "gemini-1.5-flash" }
   );
   // Call generateContent with a string or Content(s)
   const generateContentResult = await model.generateContent("what is a cat?");
diff --git a/vertexai/package-lock.json b/vertexai/package-lock.json
index 83601a631..02739db7b 100644
--- a/vertexai/package-lock.json
+++ b/vertexai/package-lock.json
@@ -9,15 +9,15 @@
       "version": "1.0.0",
       "license": "Apache-2.0",
       "dependencies": {
-        "firebase": "^10.12.0"
+        "firebase": "^11.1.0"
       },
       "devDependencies": {
         "typescript": "^5.1.6",
         "vite": "^4.4.9"
       },
       "engines": {
-        "node": ">=18.0.0 <=20.0.0",
-        "npm": ">=9.0.0 <10.0.0"
+        "node": ">=18.0.0 <=22.10.0",
+        "npm": ">=9.0.0 <=10.9.0"
       }
     },
     "node_modules/@esbuild/darwin-x64": {
@@ -35,23 +35,15 @@
         "node": ">=12"
       }
     },
-    "node_modules/@fastify/busboy": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
-      "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
-      "engines": {
-        "node": ">=14"
-      }
-    },
     "node_modules/@firebase/analytics": {
-      "version": "0.10.3",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.3.tgz",
-      "integrity": "sha512-pMADbAgmfM3vDSeINCw0qSTBA9nn6so8min2KaBfu5eda5kfemb/DeawNUKOIxrP3yV4teJgCKA3JFomfnozEg==",
+      "version": "0.10.10",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.10.tgz",
+      "integrity": "sha512-Psdo7c9g2SLAYh6u1XRA+RZ7ab2JfBVuAt/kLzXkhKZL/gS2cQUCMsOW5p0RIlDPRKqpdNSmvujd2TeRWLKOkQ==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/installations": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/installations": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
       "peerDependencies": {
@@ -59,14 +51,14 @@
       }
     },
     "node_modules/@firebase/analytics-compat": {
-      "version": "0.2.9",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.9.tgz",
-      "integrity": "sha512-ZKXaUixA+drbf3meX1bhPCG90UWrpw1KDrCydhe2Uf0VFZmZyVVr0bAcVpqLm29W4td7qp2RpFjVwercZ5mxTg==",
+      "version": "0.2.16",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.16.tgz",
+      "integrity": "sha512-Q/s+u/TEMSb2EDJFQMGsOzpSosybBl8HuoSEMyGZ99+0Pu7SIR9MPDGUjc8PKiCFQWDJ3QXxgqh1d/rujyAMbA==",
       "dependencies": {
-        "@firebase/analytics": "0.10.3",
-        "@firebase/analytics-types": "0.8.2",
-        "@firebase/component": "0.6.7",
-        "@firebase/util": "1.9.6",
+        "@firebase/analytics": "0.10.10",
+        "@firebase/analytics-types": "0.8.3",
+        "@firebase/component": "0.6.11",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
       "peerDependencies": {
@@ -74,89 +66,103 @@
       }
     },
     "node_modules/@firebase/analytics-types": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.2.tgz",
-      "integrity": "sha512-EnzNNLh+9/sJsimsA/FGqzakmrAUKLeJvjRHlg8df1f97NLUlFidk9600y0ZgWOp3CAxn6Hjtk+08tixlUOWyw=="
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz",
+      "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg=="
     },
     "node_modules/@firebase/app": {
-      "version": "0.10.3",
-      "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.3.tgz",
-      "integrity": "sha512-+pW2wNjijh88aFRjNWhDNlVJI5vB7q1IKYEE79a7ErxwNS/Bo+oh16aAAPvunhT06EF5I8y9gAlNuHNN8u4z8g==",
+      "version": "0.10.17",
+      "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.17.tgz",
+      "integrity": "sha512-53sIYyAnYEPIZdaxuyq5OST7j4KBc2pqmktz+tEb1BIUSbXh8Gp4k/o6qzLelLpm4ngrBz7SRN0PZJqNRAyPog==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "idb": "7.1.1",
         "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       }
     },
     "node_modules/@firebase/app-check": {
-      "version": "0.8.4",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.4.tgz",
-      "integrity": "sha512-2tjRDaxcM5G7BEpytiDcIl+NovV99q8yEqRMKDbn4J4i/XjjuThuB4S+4PkmTnZiCbdLXQiBhkVxNlUDcfog5Q==",
+      "version": "0.8.10",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.10.tgz",
+      "integrity": "sha512-DWFfxxif/t+Ow4MmRUevDX+A3hVxm1rUf6y5ZP4sIomfnVCO1NNahqtsv9rb1/tKGkTeoVT40weiTS/WjQG1mA==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
+      "engines": {
+        "node": ">=18.0.0"
+      },
       "peerDependencies": {
         "@firebase/app": "0.x"
       }
     },
     "node_modules/@firebase/app-check-compat": {
-      "version": "0.3.11",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.11.tgz",
-      "integrity": "sha512-t01zaH3RJpKEey0nGduz3Is+uSz7Sj4U5nwOV6lWb+86s5xtxpIvBJzu/lKxJfYyfZ29eJwpdjEgT1/lm4iQyA==",
+      "version": "0.3.17",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.17.tgz",
+      "integrity": "sha512-a/eadrGsY0MVCBPhrNbKUhoYpms4UKTYLKO7nswwSFVsm3Rw6NslQQCNLfvljcDqP4E7alQDRGJXjkxd/5gJ+Q==",
       "dependencies": {
-        "@firebase/app-check": "0.8.4",
-        "@firebase/app-check-types": "0.5.2",
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/app-check": "0.8.10",
+        "@firebase/app-check-types": "0.5.3",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
+      "engines": {
+        "node": ">=18.0.0"
+      },
       "peerDependencies": {
         "@firebase/app-compat": "0.x"
       }
     },
     "node_modules/@firebase/app-check-interop-types": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz",
-      "integrity": "sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ=="
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz",
+      "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A=="
     },
     "node_modules/@firebase/app-check-types": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.2.tgz",
-      "integrity": "sha512-FSOEzTzL5bLUbD2co3Zut46iyPWML6xc4x+78TeaXMSuJap5QObfb+rVvZJtla3asN4RwU7elaQaduP+HFizDA=="
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz",
+      "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng=="
     },
     "node_modules/@firebase/app-compat": {
-      "version": "0.2.33",
-      "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.33.tgz",
-      "integrity": "sha512-CLXhYJBtLuHXCUvs894gpXEXhZ7Nhytn2icLLIesH+hPLnyBeBf2CSve6Wjig+TOxTdwOQUzdtYpdjmeeYDfpw==",
+      "version": "0.2.47",
+      "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.47.tgz",
+      "integrity": "sha512-TdEWGDp6kSwuO1mxiM2Fe39eLWygfyzqTZcoU3aPV0viqqphPCbBBnVjPbFJErZ4+yaS7uCWXEbFEP9m5/COKA==",
       "dependencies": {
-        "@firebase/app": "0.10.3",
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/app": "0.10.17",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       }
     },
     "node_modules/@firebase/app-types": {
-      "version": "0.9.2",
-      "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2.tgz",
-      "integrity": "sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ=="
+      "version": "0.9.3",
+      "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz",
+      "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw=="
     },
     "node_modules/@firebase/auth": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.3.tgz",
-      "integrity": "sha512-RiU1PjziOxLuyswtYtLK2qSjHIQJQGCk1h986SUFRbMQfzLXbQg8ZgXwxac1UAfDOzgzqPNCXhBuIlSK2UomoQ==",
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.8.1.tgz",
+      "integrity": "sha512-LX9N/Cf5Z35r5yqm2+5M3+2bRRe/+RFaa/+u4HDni7TA27C/Xm4XHLKcWcLg1BzjrS4zngSaBEOSODvp6RFOqQ==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       },
       "peerDependencies": {
         "@firebase/app": "0.x",
@@ -169,169 +175,202 @@
       }
     },
     "node_modules/@firebase/auth-compat": {
-      "version": "0.5.8",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.8.tgz",
-      "integrity": "sha512-qUgmv/mcth9wHPTOCKgAOeHe5c+BIOJVcbX2RfcjlXO3xnd8nRafwEkZKBNJUjy4oihYhqFMEMnTHLhwLJwLig==",
+      "version": "0.5.16",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.16.tgz",
+      "integrity": "sha512-YlYwJMBqAyv0ESy3jDUyshMhZlbUiwAm6B6+uUmigNDHU+uq7j4SFiDJEZlFFIz397yBzKn06SUdqutdQzGnCA==",
       "dependencies": {
-        "@firebase/auth": "1.7.3",
-        "@firebase/auth-types": "0.12.2",
-        "@firebase/component": "0.6.7",
-        "@firebase/util": "1.9.6",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
+        "@firebase/auth": "1.8.1",
+        "@firebase/auth-types": "0.12.3",
+        "@firebase/component": "0.6.11",
+        "@firebase/util": "1.10.2",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       },
       "peerDependencies": {
         "@firebase/app-compat": "0.x"
       }
     },
     "node_modules/@firebase/auth-interop-types": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz",
-      "integrity": "sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ=="
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz",
+      "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA=="
     },
     "node_modules/@firebase/auth-types": {
-      "version": "0.12.2",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.2.tgz",
-      "integrity": "sha512-qsEBaRMoGvHO10unlDJhaKSuPn4pyoTtlQuP1ghZfzB6rNQPuhp/N/DcFZxm9i4v0SogjCbf9reWupwIvfmH6w==",
+      "version": "0.12.3",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.3.tgz",
+      "integrity": "sha512-Zq9zI0o5hqXDtKg6yDkSnvMCMuLU6qAVS51PANQx+ZZX5xnzyNLEBO3GZgBUPsV5qIMFhjhqmLDxUqCbnAYy2A==",
       "peerDependencies": {
         "@firebase/app-types": "0.x",
         "@firebase/util": "1.x"
       }
     },
     "node_modules/@firebase/component": {
-      "version": "0.6.7",
-      "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.7.tgz",
-      "integrity": "sha512-baH1AA5zxfaz4O8w0vDwETByrKTQqB5CDjRls79Sa4eAGAoERw4Tnung7XbMl3jbJ4B/dmmtsMrdki0KikwDYA==",
+      "version": "0.6.11",
+      "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.11.tgz",
+      "integrity": "sha512-eQbeCgPukLgsKD0Kw5wQgsMDX5LeoI1MIrziNDjmc6XDq5ZQnuUymANQgAb2wp1tSF9zDSXyxJmIUXaKgN58Ug==",
+      "dependencies": {
+        "@firebase/util": "1.10.2",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@firebase/data-connect": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.1.3.tgz",
+      "integrity": "sha512-FbAQpWNHownJx1VTCQI4ydbWGOZmSWXoFlirQn3ItHqsLJYSywqxSgDafzvyooifFh3J/2WqaM8y9hInnPcsTw==",
       "dependencies": {
-        "@firebase/util": "1.9.6",
+        "@firebase/auth-interop-types": "0.2.4",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
       }
     },
     "node_modules/@firebase/database": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.5.tgz",
-      "integrity": "sha512-cAfwBqMQuW6HbhwI3Cb/gDqZg7aR0OmaJ85WUxlnoYW2Tm4eR0hFl5FEijI3/gYPUiUcUPQvTkGV222VkT7KPw==",
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.10.tgz",
+      "integrity": "sha512-sWp2g92u7xT4BojGbTXZ80iaSIaL6GAL0pwvM0CO/hb0nHSnABAqsH7AhnWGsGvXuEvbPr7blZylPaR9J+GSuQ==",
       "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.2",
-        "@firebase/auth-interop-types": "0.2.3",
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/app-check-interop-types": "0.3.3",
+        "@firebase/auth-interop-types": "0.2.4",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "faye-websocket": "0.11.4",
         "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       }
     },
     "node_modules/@firebase/database-compat": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.5.tgz",
-      "integrity": "sha512-NDSMaDjQ+TZEMDMmzJwlTL05kh1+0Y84C+kVMaOmNOzRGRM7VHi29I6YUhCetXH+/b1Wh4ZZRyp1CuWkd8s6hg==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.1.tgz",
+      "integrity": "sha512-IsFivOjdE1GrjTeKoBU/ZMenESKDXidFDzZzHBPQ/4P20ptGdrl3oLlWrV/QJqJ9lND4IidE3z4Xr5JyfUW1vg==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/database": "1.0.5",
-        "@firebase/database-types": "1.0.3",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/database": "1.0.10",
+        "@firebase/database-types": "1.0.7",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       }
     },
     "node_modules/@firebase/database-types": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.3.tgz",
-      "integrity": "sha512-39V/Riv2R3O/aUjYKh0xypj7NTNXNAK1bcgY5Kx+hdQPRS/aPTS8/5c0CGFYKgVuFbYlnlnhrCTYsh2uNhGwzA==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.7.tgz",
+      "integrity": "sha512-I7zcLfJXrM0WM+ksFmFdAMdlq/DFmpeMNa+/GNsLyFo5u/lX5zzkPzGe3srVWqaBQBY5KprylDGxOsP6ETfL0A==",
       "dependencies": {
-        "@firebase/app-types": "0.9.2",
-        "@firebase/util": "1.9.6"
+        "@firebase/app-types": "0.9.3",
+        "@firebase/util": "1.10.2"
       }
     },
     "node_modules/@firebase/firestore": {
-      "version": "4.6.2",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.6.2.tgz",
-      "integrity": "sha512-sxHtvmfH/1689aPQRxOXBWDumaPqg5AjQVkfwpt+Z3rnaa0aLJlrt2PZs9Xh04qbmWiwtkDgztFmoR/aQdMQJQ==",
+      "version": "4.7.5",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.5.tgz",
+      "integrity": "sha512-OO3rHvjC07jL2ITN255xH/UzCVSvh6xG8oTzQdFScQvFbcm1fjCL1hgAdpDZcx3vVcKMV+6ktr8wbllkB8r+FQ==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
-        "@firebase/webchannel-wrapper": "1.0.0",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
+        "@firebase/webchannel-wrapper": "1.0.3",
         "@grpc/grpc-js": "~1.9.0",
         "@grpc/proto-loader": "^0.7.8",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
+        "tslib": "^2.1.0"
       },
       "engines": {
-        "node": ">=10.10.0"
+        "node": ">=18.0.0"
       },
       "peerDependencies": {
         "@firebase/app": "0.x"
       }
     },
     "node_modules/@firebase/firestore-compat": {
-      "version": "0.3.31",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.31.tgz",
-      "integrity": "sha512-YbR9GGLfYY9A5Qh2SyyNz7EsNeC5SRjzgRxtMtqz2s2es+p+5sDfFUUNKqpgVaIcnoPGOtvCLhNNWG/TBmlQjw==",
+      "version": "0.3.40",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.40.tgz",
+      "integrity": "sha512-18HopMN811KYBc9Ptpr1Rewwio0XF09FF3jc5wtV6rGyAs815SlFFw5vW7ZeLd43zv9tlEc2FzM0H+5Vr9ZRxw==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/firestore": "4.6.2",
-        "@firebase/firestore-types": "3.0.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/firestore": "4.7.5",
+        "@firebase/firestore-types": "3.0.3",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
+      "engines": {
+        "node": ">=18.0.0"
+      },
       "peerDependencies": {
         "@firebase/app-compat": "0.x"
       }
     },
     "node_modules/@firebase/firestore-types": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.2.tgz",
-      "integrity": "sha512-wp1A+t5rI2Qc/2q7r2ZpjUXkRVPtGMd6zCLsiWurjsQpqPgFin3AhNibKcIzoF2rnToNa/XYtyWXuifjOOwDgg==",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz",
+      "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==",
       "peerDependencies": {
         "@firebase/app-types": "0.x",
         "@firebase/util": "1.x"
       }
     },
     "node_modules/@firebase/functions": {
-      "version": "0.11.5",
-      "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.5.tgz",
-      "integrity": "sha512-qrHJ+l62mZiU5UZiVi84t/iLXZlhRuSvBQsa2qvNLgPsEWR7wdpWhRmVdB7AU8ndkSHJjGlMICqrVnz47sgU7Q==",
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.12.0.tgz",
+      "integrity": "sha512-plTtzY/nT0jOgHzT0vB9qch4FpHFOhCnR8HhYBqqdArG6GOQMIruKZbiTyLybO8bcaaNgQ6kSm9yohGUwxHcIw==",
       "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.2",
-        "@firebase/auth-interop-types": "0.2.3",
-        "@firebase/component": "0.6.7",
-        "@firebase/messaging-interop-types": "0.2.2",
-        "@firebase/util": "1.9.6",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
+        "@firebase/app-check-interop-types": "0.3.3",
+        "@firebase/auth-interop-types": "0.2.4",
+        "@firebase/component": "0.6.11",
+        "@firebase/messaging-interop-types": "0.2.3",
+        "@firebase/util": "1.10.2",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       },
       "peerDependencies": {
         "@firebase/app": "0.x"
       }
     },
     "node_modules/@firebase/functions-compat": {
-      "version": "0.3.11",
-      "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.11.tgz",
-      "integrity": "sha512-Qn+ts/M6Lj2/6i1cp5V5TRR+Hi9kyXyHbo+w9GguINJ87zxrCe6ulx3TI5AGQkoQa8YFHUhT3DMGmLFiJjWTSQ==",
+      "version": "0.3.17",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.17.tgz",
+      "integrity": "sha512-oj2XV8YsJYutyPCRYUfbN6swmfrL6zar0/qtqZsKT7P7btOiYRl+lD6fxtQaT+pKE5YgOBGZW//kLPZfY0jWhw==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/functions": "0.11.5",
-        "@firebase/functions-types": "0.6.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/functions": "0.12.0",
+        "@firebase/functions-types": "0.6.3",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
+      "engines": {
+        "node": ">=18.0.0"
+      },
       "peerDependencies": {
         "@firebase/app-compat": "0.x"
       }
     },
     "node_modules/@firebase/functions-types": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.2.tgz",
-      "integrity": "sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w=="
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz",
+      "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg=="
     },
     "node_modules/@firebase/installations": {
-      "version": "0.6.7",
-      "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.7.tgz",
-      "integrity": "sha512-i6iGoXRu5mX4rTsiMSSKrgh9pSEzD4hwBEzRh5kEhOTr8xN/wvQcCPZDSMVYKwM2XyCPBLVq0JzjyerwL0Rihg==",
+      "version": "0.6.11",
+      "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.11.tgz",
+      "integrity": "sha512-w8fY8mw6fxJzsZM2ufmTtomopXl1+bn/syYon+Gpn+0p0nO1cIUEVEFrFazTLaaL9q1CaVhc3HmseRTsI3igAA==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/util": "1.10.2",
         "idb": "7.1.1",
         "tslib": "^2.1.0"
       },
@@ -340,14 +379,14 @@
       }
     },
     "node_modules/@firebase/installations-compat": {
-      "version": "0.2.7",
-      "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.7.tgz",
-      "integrity": "sha512-RPcbD+3nqHbnhVjIOpWK2H5qzZ8pAAAScceiWph0VNTqpKyPQ5tDcp4V5fS0ELpfgsHYvroMLDKfeHxpfvm8cw==",
+      "version": "0.2.11",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.11.tgz",
+      "integrity": "sha512-SHRgw5LTa6v8LubmJZxcOCwEd1MfWQPUtKdiuCx2VMWnapX54skZd1PkQg0K4l3k+4ujbI2cn7FE6Li9hbChBw==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/installations": "0.6.7",
-        "@firebase/installations-types": "0.5.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/installations": "0.6.11",
+        "@firebase/installations-types": "0.5.3",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
       "peerDependencies": {
@@ -355,30 +394,33 @@
       }
     },
     "node_modules/@firebase/installations-types": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.2.tgz",
-      "integrity": "sha512-que84TqGRZJpJKHBlF2pkvc1YcXrtEDOVGiDjovP/a3s6W4nlbohGXEsBJo0JCeeg/UG9A+DEZVDUV9GpklUzA==",
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz",
+      "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==",
       "peerDependencies": {
         "@firebase/app-types": "0.x"
       }
     },
     "node_modules/@firebase/logger": {
-      "version": "0.4.2",
-      "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.2.tgz",
-      "integrity": "sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A==",
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz",
+      "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==",
       "dependencies": {
         "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       }
     },
     "node_modules/@firebase/messaging": {
-      "version": "0.12.9",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.9.tgz",
-      "integrity": "sha512-IH+JJmzbFGZXV3+TDyKdqqKPVfKRqBBg2BfYYOy7cm7J+SwV+uJMe8EnDKYeQLEQhtpwciPfJ3qQXJs2lbxDTw==",
+      "version": "0.12.15",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.15.tgz",
+      "integrity": "sha512-Bz+qvWNEwEWAbYtG4An8hgcNco6NWNoNLuLbGVwPL2fAoCF1zz+dcaBp+iTR2+K199JyRyDT9yDPAXhNHNDaKQ==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/installations": "0.6.7",
-        "@firebase/messaging-interop-types": "0.2.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/installations": "0.6.11",
+        "@firebase/messaging-interop-types": "0.2.3",
+        "@firebase/util": "1.10.2",
         "idb": "7.1.1",
         "tslib": "^2.1.0"
       },
@@ -387,13 +429,13 @@
       }
     },
     "node_modules/@firebase/messaging-compat": {
-      "version": "0.2.9",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.9.tgz",
-      "integrity": "sha512-5jN6wyhwPgBH02zOtmmoOeyfsmoD7ty48D1m0vVPsFg55RqN2Z3Q9gkZ5GmPklFPjTPLcxB1ObcHOZvThTkm7g==",
+      "version": "0.2.15",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.15.tgz",
+      "integrity": "sha512-mEKKASRvRWq1aBNHgioGsOYR2c5nBZpO7k90K794zjKe0WkGNf0k7PLs5SlCf8FKnzumEkhTAp/SjYxovuxa8A==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/messaging": "0.12.9",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/messaging": "0.12.15",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
       "peerDependencies": {
@@ -401,19 +443,19 @@
       }
     },
     "node_modules/@firebase/messaging-interop-types": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2.tgz",
-      "integrity": "sha512-l68HXbuD2PPzDUOFb3aG+nZj5KA3INcPwlocwLZOzPp9rFM9yeuI9YLl6DQfguTX5eAGxO0doTR+rDLDvQb5tA=="
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz",
+      "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q=="
     },
     "node_modules/@firebase/performance": {
-      "version": "0.6.7",
-      "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.7.tgz",
-      "integrity": "sha512-d+Q4ltjdJZqjzcdms5i0UC9KLYX7vKGcygZ+7zHA/Xk+bAbMD2CPU0nWTnlNFWifZWIcXZ/2mAMvaGMW3lypUA==",
+      "version": "0.6.11",
+      "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.11.tgz",
+      "integrity": "sha512-FlkJFeqLlIeh5T4Am3uE38HVzggliDIEFy/fErEc1faINOUFCb6vQBEoNZGaXvRnTR8lh3X/hP7tv37C7BsK9g==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/installations": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/installations": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
       "peerDependencies": {
@@ -421,15 +463,15 @@
       }
     },
     "node_modules/@firebase/performance-compat": {
-      "version": "0.2.7",
-      "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.7.tgz",
-      "integrity": "sha512-cb8ge/5iTstxfIGW+iiY+7l3FtN8gobNh9JSQNZgLC9xmcfBYWEs8IeEWMI6S8T+At0oHc3lv+b2kpRMUWr8zQ==",
+      "version": "0.2.11",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.11.tgz",
+      "integrity": "sha512-DqeNBy51W2xzlklyC7Ht9JQ94HhTA08PCcM4MDeyG/ol3fqum/+YgtHWQ2IQuduqH9afETthZqLwCZiSgY7hiA==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/performance": "0.6.7",
-        "@firebase/performance-types": "0.2.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/performance": "0.6.11",
+        "@firebase/performance-types": "0.2.3",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
       "peerDependencies": {
@@ -437,19 +479,19 @@
       }
     },
     "node_modules/@firebase/performance-types": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.2.tgz",
-      "integrity": "sha512-gVq0/lAClVH5STrIdKnHnCo2UcPLjJlDUoEB/tB4KM+hAeHUxWKnpT0nemUPvxZ5nbdY/pybeyMe8Cs29gEcHA=="
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz",
+      "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ=="
     },
     "node_modules/@firebase/remote-config": {
-      "version": "0.4.7",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.7.tgz",
-      "integrity": "sha512-5oPNrPFLsbsjpq0lUEIXoDF2eJK7vAbyXe/DEuZQxnwJlfR7aQbtUlEkRgQWcicXpyDmAmDLo7q7lDbCYa6CpA==",
+      "version": "0.4.11",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.11.tgz",
+      "integrity": "sha512-9z0rgKuws2nj+7cdiqF+NY1QR4na6KnuOvP+jQvgilDOhGtKOcCMq5XHiu66i73A9kFhyU6QQ2pHXxcmaq1pBw==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/installations": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/installations": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
       "peerDependencies": {
@@ -457,15 +499,15 @@
       }
     },
     "node_modules/@firebase/remote-config-compat": {
-      "version": "0.2.7",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.7.tgz",
-      "integrity": "sha512-Fq0oneQ4SluLnfr5/HfzRS1TZf1ANj1rWbCCW3+oC98An3nE+sCdp+FSuHsEVNwgMg4Tkwx9Oom2lkKeU+Vn+w==",
+      "version": "0.2.11",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.11.tgz",
+      "integrity": "sha512-zfIjpwPrGuIOZDmduukN086qjhZ1LnbJi/iYzgua+2qeTlO0XdlE1v66gJPwygGB3TOhT0yb9EiUZ3nBNttMqg==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/remote-config": "0.4.7",
-        "@firebase/remote-config-types": "0.3.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/remote-config": "0.4.11",
+        "@firebase/remote-config-types": "0.3.3",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
       "peerDependencies": {
@@ -473,65 +515,73 @@
       }
     },
     "node_modules/@firebase/remote-config-types": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.2.tgz",
-      "integrity": "sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA=="
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.3.tgz",
+      "integrity": "sha512-YlRI9CHxrk3lpQuFup9N1eohpwdWayKZUNZ/YeQ0PZoncJ66P32UsKUKqVXOaieTjJIOh7yH8JEzRdht5s+d6g=="
     },
     "node_modules/@firebase/storage": {
-      "version": "0.12.5",
-      "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.5.tgz",
-      "integrity": "sha512-nGWBOGFNr10j0LA4NJ3/Yh3us/lb0Q1xSIKZ38N6FcS+vY54nqJ7k3zE3PENregHC8+8txRow++A568G3v8hOA==",
+      "version": "0.13.4",
+      "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.4.tgz",
+      "integrity": "sha512-b1KaTTRiMupFurIhpGIbReaWev0k5O3ouTHkAPcEssT+FvU3q/1JwzvkX4+ZdB60Fc43Mbp8qQ1gWfT0Z2FP9Q==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/util": "1.9.6",
-        "tslib": "^2.1.0",
-        "undici": "5.28.4"
+        "@firebase/component": "0.6.11",
+        "@firebase/util": "1.10.2",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       },
       "peerDependencies": {
         "@firebase/app": "0.x"
       }
     },
     "node_modules/@firebase/storage-compat": {
-      "version": "0.3.8",
-      "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.8.tgz",
-      "integrity": "sha512-qDfY9kMb6Ch2hZb40sBjDQ8YPxbjGOxuT+gU1Z0iIVSSpSX0f4YpGJCypUXiA0T11n6InCXB+T/Dknh2yxVTkg==",
+      "version": "0.3.14",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.14.tgz",
+      "integrity": "sha512-Ok5FmXJiapaNAOQ8W8qppnfwgP8540jw2B8M0c4TFZqF4BD+CoKBxW0dRtOuLNGadLhzqqkDZZZtkexxrveQqA==",
       "dependencies": {
-        "@firebase/component": "0.6.7",
-        "@firebase/storage": "0.12.5",
-        "@firebase/storage-types": "0.8.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/component": "0.6.11",
+        "@firebase/storage": "0.13.4",
+        "@firebase/storage-types": "0.8.3",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
+      "engines": {
+        "node": ">=18.0.0"
+      },
       "peerDependencies": {
         "@firebase/app-compat": "0.x"
       }
     },
     "node_modules/@firebase/storage-types": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.2.tgz",
-      "integrity": "sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g==",
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz",
+      "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==",
       "peerDependencies": {
         "@firebase/app-types": "0.x",
         "@firebase/util": "1.x"
       }
     },
     "node_modules/@firebase/util": {
-      "version": "1.9.6",
-      "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.6.tgz",
-      "integrity": "sha512-IBr1MZbp4d5MjBCXL3TW1dK/PDXX4yOGbiwRNh1oAbE/+ci5Uuvy9KIrsFYY80as1I0iOaD5oOMA9Q8j4TJWcw==",
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.10.2.tgz",
+      "integrity": "sha512-qnSHIoE9FK+HYnNhTI8q14evyqbc/vHRivfB4TgCIUOl4tosmKSQlp7ltymOlMP4xVIJTg5wrkfcZ60X4nUf7Q==",
       "dependencies": {
         "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
       }
     },
-    "node_modules/@firebase/vertexai-preview": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/@firebase/vertexai-preview/-/vertexai-preview-0.0.1.tgz",
-      "integrity": "sha512-N8m9Xr0YZKy0t9SpQDuHrL2ppEAT/iqf88Y/O00QNA/Td/BMCL8sJ0c+Savh1TVrqh0rNp9n6HkZ39e/O5mwhA==",
+    "node_modules/@firebase/vertexai": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.0.2.tgz",
+      "integrity": "sha512-4dC9m2nD0tkfKJT5v+i27tELrmUePjFXW3CDAxhVHUEv647B2R7kqpGQnyPkNEeaXkCr76THe7GGg35EWn4lDw==",
       "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.2",
-        "@firebase/component": "0.6.7",
-        "@firebase/logger": "0.4.2",
-        "@firebase/util": "1.9.6",
+        "@firebase/app-check-interop-types": "0.3.3",
+        "@firebase/component": "0.6.11",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.10.2",
         "tslib": "^2.1.0"
       },
       "engines": {
@@ -543,14 +593,14 @@
       }
     },
     "node_modules/@firebase/webchannel-wrapper": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.0.tgz",
-      "integrity": "sha512-zuWxyfXNbsKbm96HhXzainONPFqRcoZblQ++e9cAIGUuHfl2cFSBzW01jtesqWG/lqaUyX3H8O1y9oWboGNQBA=="
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz",
+      "integrity": "sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ=="
     },
     "node_modules/@grpc/grpc-js": {
-      "version": "1.9.14",
-      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz",
-      "integrity": "sha512-nOpuzZ2G3IuMFN+UPPpKrC6NsLmWsTqSsm66IRfnBt1D4pwTqE27lmbpcPM+l2Ua4gE7PfjRHI6uedAy7hoXUw==",
+      "version": "1.9.15",
+      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz",
+      "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==",
       "dependencies": {
         "@grpc/proto-loader": "^0.7.8",
         "@types/node": ">=12.12.47"
@@ -730,9 +780,9 @@
       }
     },
     "node_modules/escalade": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
-      "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
       "engines": {
         "node": ">=6"
       }
@@ -749,37 +799,38 @@
       }
     },
     "node_modules/firebase": {
-      "version": "10.12.0",
-      "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.12.0.tgz",
-      "integrity": "sha512-31UZyAK0+VZmF9jR/+6g31uyqWjBKsG+TV3ndRJEkw6+Skctb5ZX0+Ezq/pbC68iIRJ5TujOjyl632vTOqyS1w==",
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.1.0.tgz",
+      "integrity": "sha512-3OoNW3vBXmBLYJvcwbPCwfluptbDVp2zZYjrfHPVFAXfPgmyy/LWjidt+Sw2WNvRelsG0v++WN2Wor6J3OwDRg==",
       "dependencies": {
-        "@firebase/analytics": "0.10.3",
-        "@firebase/analytics-compat": "0.2.9",
-        "@firebase/app": "0.10.3",
-        "@firebase/app-check": "0.8.4",
-        "@firebase/app-check-compat": "0.3.11",
-        "@firebase/app-compat": "0.2.33",
-        "@firebase/app-types": "0.9.2",
-        "@firebase/auth": "1.7.3",
-        "@firebase/auth-compat": "0.5.8",
-        "@firebase/database": "1.0.5",
-        "@firebase/database-compat": "1.0.5",
-        "@firebase/firestore": "4.6.2",
-        "@firebase/firestore-compat": "0.3.31",
-        "@firebase/functions": "0.11.5",
-        "@firebase/functions-compat": "0.3.11",
-        "@firebase/installations": "0.6.7",
-        "@firebase/installations-compat": "0.2.7",
-        "@firebase/messaging": "0.12.9",
-        "@firebase/messaging-compat": "0.2.9",
-        "@firebase/performance": "0.6.7",
-        "@firebase/performance-compat": "0.2.7",
-        "@firebase/remote-config": "0.4.7",
-        "@firebase/remote-config-compat": "0.2.7",
-        "@firebase/storage": "0.12.5",
-        "@firebase/storage-compat": "0.3.8",
-        "@firebase/util": "1.9.6",
-        "@firebase/vertexai-preview": "0.0.1"
+        "@firebase/analytics": "0.10.10",
+        "@firebase/analytics-compat": "0.2.16",
+        "@firebase/app": "0.10.17",
+        "@firebase/app-check": "0.8.10",
+        "@firebase/app-check-compat": "0.3.17",
+        "@firebase/app-compat": "0.2.47",
+        "@firebase/app-types": "0.9.3",
+        "@firebase/auth": "1.8.1",
+        "@firebase/auth-compat": "0.5.16",
+        "@firebase/data-connect": "0.1.3",
+        "@firebase/database": "1.0.10",
+        "@firebase/database-compat": "2.0.1",
+        "@firebase/firestore": "4.7.5",
+        "@firebase/firestore-compat": "0.3.40",
+        "@firebase/functions": "0.12.0",
+        "@firebase/functions-compat": "0.3.17",
+        "@firebase/installations": "0.6.11",
+        "@firebase/installations-compat": "0.2.11",
+        "@firebase/messaging": "0.12.15",
+        "@firebase/messaging-compat": "0.2.15",
+        "@firebase/performance": "0.6.11",
+        "@firebase/performance-compat": "0.2.11",
+        "@firebase/remote-config": "0.4.11",
+        "@firebase/remote-config-compat": "0.2.11",
+        "@firebase/storage": "0.13.4",
+        "@firebase/storage-compat": "0.3.14",
+        "@firebase/util": "1.10.2",
+        "@firebase/vertexai": "1.0.2"
       }
     },
     "node_modules/fsevents": {
@@ -880,9 +931,9 @@
       }
     },
     "node_modules/protobufjs": {
-      "version": "7.3.0",
-      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.0.tgz",
-      "integrity": "sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g==",
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
+      "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
       "hasInstallScript": true,
       "dependencies": {
         "@protobufjs/aspromise": "^1.1.2",
@@ -977,9 +1028,9 @@
       }
     },
     "node_modules/tslib": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
-      "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
     },
     "node_modules/typescript": {
       "version": "5.4.4",
@@ -993,17 +1044,6 @@
         "node": ">=14.17"
       }
     },
-    "node_modules/undici": {
-      "version": "5.28.4",
-      "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
-      "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
-      "dependencies": {
-        "@fastify/busboy": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=14.0"
-      }
-    },
     "node_modules/undici-types": {
       "version": "5.26.5",
       "license": "MIT"
diff --git a/vertexai/package.json b/vertexai/package.json
index f24867eae..6c859d63f 100644
--- a/vertexai/package.json
+++ b/vertexai/package.json
@@ -12,8 +12,8 @@
     "url": "https://github.com/firebase/quickstart-js/issues"
   },
   "engines": {
-    "npm": ">=9.0.0 <10.0.0",
-    "node": ">=18.0.0 <=20.0.0"
+    "npm": ">=9.0.0 <=10.9.0",
+    "node": ">=18.0.0 <=22.10.0"
   },
   "homepage": "https://github.com/firebase/quickstart-js#readme",
   "devDependencies": {
@@ -26,6 +26,6 @@
     "format": "prettier --write ."
   },
   "dependencies": {
-    "firebase": "^10.12.0"
+    "firebase": "^11.1.0"
   }
 }

From 64834e0f0dfc8b2badd7187feb91ace6afdaa836 Mon Sep 17 00:00:00 2001
From: nhienlam <nhienlam.ricky@gmail.com>
Date: Thu, 14 Nov 2024 14:07:09 -0800
Subject: [PATCH 57/82] Add MFA link to the main page

---
 auth/index.html | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/auth/index.html b/auth/index.html
index 422c18101..fa00b7357 100644
--- a/auth/index.html
+++ b/auth/index.html
@@ -58,6 +58,8 @@ <h2 class="mdl-card__title-text">Table of Contents</h2>
             <li><a href="email-password.html">Email and Password authentication</a></li>
             <li><a href="email-link.html">Email Link authentication</a><br><br></li>
             
+            <li><a href="mfa-password.html">SMS multi-factor authentication</a><br><br></li>
+
             <li><a href="customauth.html">Custom Authentication</a> and an Example <a href="exampletokengenerator/auth.html">Custom Token Generator</a><br><br></li>
 
             <li><a href="phone-visible.html">Phone number sign-in with visible ReCaptcha</a></li>

From 897ffae3c2ce83b2bda652362cdad790db3febed Mon Sep 17 00:00:00 2001
From: Maneesh Tewani <mtewani@google.com>
Date: Fri, 7 Feb 2025 10:32:40 -0800
Subject: [PATCH 58/82] Restored nix files

---
 dataconnect/.idx/dev.nix                     | 76 ++++++++++----------
 dataconnect/README.md                        | 13 ++--
 dataconnect/app/src/components/navbar.tsx    |  4 +-
 dataconnect/app/src/pages/Home.tsx           | 13 +++-
 dataconnect/app/vite.config.idx.ts           |  7 +-
 dataconnect/dataconnect/moviedata_insert.gql | 26 +++++--
 6 files changed, 83 insertions(+), 56 deletions(-)

diff --git a/dataconnect/.idx/dev.nix b/dataconnect/.idx/dev.nix
index ea67bb36c..bb220b24a 100644
--- a/dataconnect/.idx/dev.nix
+++ b/dataconnect/.idx/dev.nix
@@ -1,45 +1,45 @@
-{ pkgs, ... }: {
-  channel = "stable-23.11";
-  packages = [
-    pkgs.nodejs_20
-  ];
-
-  env = {
-    POSTGRESQL_CONN_STRING = "postgresql://user:mypassword@localhost:5432/dataconnect?sslmode=disable";
-  };
+{ pkgs, ... }: 
+  {
+    channel = "stable-24.05";
+    packages = [
+      pkgs.nodejs_20
+    ];
+    
+    env = {
+      FIREBASE_DATACONNECT_POSTGRESQL_STRING =  "postgresql://user:mypassword@localhost:5432/dataconnect?sslmode=disable";
+    };
   
-  idx.extensions = [
-    "mtxr.sqltools"
-    "mtxr.sqltools-driver-pg"
-    "GraphQL.vscode-graphql-syntax"
-    "GoogleCloudTools.firebase-dataconnect-vscode"
-  ];
+    services.postgres = {
+      extensions = ["pgvector"];
+      enable = true;
+    };
 
-  services.postgres = {
-    extensions = ["pgvector"];
-    enable = true;
-  };
-  
-  idx = {
-    workspace = {
-      onCreate = {
-        update-firebase = "npm install -D firebase-tools";
-        postgres = ''
-          psql --dbname=postgres -c "ALTER USER \"user\" PASSWORD 'mypassword';"
-          psql --dbname=postgres -c "CREATE DATABASE dataconnect;"
-          psql --dbname=dataconnect -c "CREATE EXTENSION vector;"
-        '';
-        npm-install = "cd app && npm i && npm i firebase@latest";
+    idx = {
+      extensions = [
+        "mtxr.sqltools"
+        "mtxr.sqltools-driver-pg"
+        "GraphQL.vscode-graphql-syntax"
+        "GoogleCloudTools.firebase-dataconnect-vscode"
+      ];
+      workspace = {
+        onCreate = {
+          update-firebase = "npm install -g firebase-tools";
+          postgres = ''
+            psql --dbname=postgres -c "ALTER USER \"user\" PASSWORD 'mypassword';"
+            psql --dbname=postgres -c "CREATE DATABASE dataconnect;"
+            psql --dbname=dataconnect -c "CREATE EXTENSION vector;"
+          '';
+          npm-install = "cd app && npm i";
+        };
       };
-    };
-    previews = {
-      enable = true;
       previews = {
-        web = {
-          command = ["npm" "run" "dev" "--prefix" "./app" "--" "--port" "$PORT" "--host" "0.0.0.0"];
-          manager = "web";
+        enable = true;
+        previews = {
+          web = {
+            command = ["npm" "run" "dev" "--prefix" "./app" "--" "--port" "$PORT" "--host" "0.0.0.0"];
+            manager = "web";
+          };
         };
       };
     };
-  };
-}
\ No newline at end of file
+}
diff --git a/dataconnect/README.md b/dataconnect/README.md
index 2fea10be7..06120471a 100644
--- a/dataconnect/README.md
+++ b/dataconnect/README.md
@@ -2,7 +2,7 @@
 
 ## Introduction
 
-This is a sample app for the preview version of Firebase DataConnect. This service is currently in Private Preview at no cost for a limited time. Sign up for the program at [Firebase Data Connect](https://firebase.google.com/products/data-connect). This quickstart will not work if you don't have access to the preview.
+This is a sample app for the preview version of Firebase DataConnect. This service is currently in Public Preview at no cost for a limited time.
 
 ## Getting Started with Firebase DataConnect
 
@@ -88,9 +88,8 @@ This repository contains the quickstart to help you explore the functionalities
     npm run build
     ```
 
-5. Set up Firebase Authentication with Google Sign-In. Optionally, allow domains for [Firebase Auth](https://firebase.google.com/docs/auth/web/hosting) in your project console (e.g., `http://127.0.0.1`).
-6. Allow domains for Firebase Auth in your [project console](https://console.firebase.google.com/project/_/authentication/settings) (e.g., `http://127.0.0.1`).
-7. In `dataconnect/dataconnect.yaml`, ensure that your `instanceId`, `database`, and `serviceId` match your project configuration:
+5. Allow domains for Firebase Auth in your [project console](https://console.firebase.google.com/project/_/authentication/settings) (e.g., `http://127.0.0.1`).
+6. In `dataconnect/dataconnect.yaml`, ensure that your `instanceId`, `database`, and `serviceId` match your project configuration:
 
     ```yaml
     specVersion: "v1alpha"
@@ -106,7 +105,7 @@ This repository contains the quickstart to help you explore the functionalities
     connectorDirs: ["./movie-connector"]
     ```
 
-8. Deploy your project:
+7. Deploy your project:
 
     ```bash
     npm install -g firebase-tools
@@ -115,13 +114,13 @@ This repository contains the quickstart to help you explore the functionalities
     firebase deploy --only dataconnect,hosting
     ```
 
-9. To compare schema changes, run:
+8. To compare schema changes, run:
 
     ```bash
     firebase dataconnect:sql:diff
     ```
 
-10. If the changes are acceptable, apply them with:
+9. If the changes are acceptable, apply them with:
 
     ```bash
     firebase dataconnect:sql:migrate
diff --git a/dataconnect/app/src/components/navbar.tsx b/dataconnect/app/src/components/navbar.tsx
index bf73ad6f4..775c2aff7 100644
--- a/dataconnect/app/src/components/navbar.tsx
+++ b/dataconnect/app/src/components/navbar.tsx
@@ -1,5 +1,5 @@
 import React, { useEffect, useState, useContext } from 'react';
-import { signInWithPopup, GoogleAuthProvider, signOut, User } from 'firebase/auth';
+import { signInWithRedirect, GoogleAuthProvider, signOut, User } from 'firebase/auth';
 import { AuthContext } from '@/lib/firebase';
 import { Link } from 'react-router-dom';
 import { handleAuthStateChange } from '@/lib/MovieService';
@@ -18,7 +18,7 @@ export default function Navbar() {
 
   async function handleSignIn() {
     const provider = new GoogleAuthProvider();
-    await signInWithPopup(auth, provider);
+    await signInWithRedirect(auth, provider);
   }
 
   async function handleSignOut() {
diff --git a/dataconnect/app/src/pages/Home.tsx b/dataconnect/app/src/pages/Home.tsx
index 7e4b19635..798b656c4 100644
--- a/dataconnect/app/src/pages/Home.tsx
+++ b/dataconnect/app/src/pages/Home.tsx
@@ -7,8 +7,17 @@ const ConditionalRender = ({ condition, preferred, alternate }: { condition: boo
 )
 
 const PlaceholderMessage = () => (
-  <div className="min-h-screen flex items-center justify-center text-center text-4xl text-white">
-    Run the Firebase Data Connect Extension to get started.
+  <div className="min-h-screen flex items-center justify-center text-center text-white">
+    <div className='px-4'>
+      <h1 className='text-4xl'>To get Started with Firebase Data Connect:</h1>
+      <ol className='list-decimal'>
+        <li>Add {window.location.host}<a target="_blank" className="underline text-blue-600 hover:text-blue-800 visited:text-purple-600" href="https://console.firebase.google.com/project/_/authentication/settings"> to your list of domains</a></li>
+        <li>Open app/src/lib/firebase.tsx and replace the firebaseConfig </li>
+        <li>Open the Firebase Data Connect Extension</li>
+        <li>Select your project</li>
+        <li>Click "Start Emulators"</li>
+      </ol>
+    </div>
   </div>
 )
 
diff --git a/dataconnect/app/vite.config.idx.ts b/dataconnect/app/vite.config.idx.ts
index c2417fbfc..6533f7f6f 100644
--- a/dataconnect/app/vite.config.idx.ts
+++ b/dataconnect/app/vite.config.idx.ts
@@ -5,12 +5,17 @@ import path from 'path';
 // https://vitejs.dev/config/
 export default defineConfig({
   plugins: [react()],
+
   resolve: {
     alias: {
       '@': path.resolve(__dirname, 'src'),
     },
-  },
+  }, 
   server: {
+     headers: {
+      "Cross-Origin-Embedder-Policy": "unsafe-none",
+      "cross-origin-opener-policy": "same-origin-allow-popups"
+     },
     proxy: {
       '/v1beta/projects': {
         target: 'http://127.0.0.1:9399',
diff --git a/dataconnect/dataconnect/moviedata_insert.gql b/dataconnect/dataconnect/moviedata_insert.gql
index 2f205012b..44cdfe000 100644
--- a/dataconnect/dataconnect/moviedata_insert.gql
+++ b/dataconnect/dataconnect/moviedata_insert.gql
@@ -1,3 +1,17 @@
+ # Copyright 2024 Google LLC
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ #      http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
 mutation {
   movie_insertMany(
     data: [
@@ -24,7 +38,7 @@ mutation {
       {
         id: "550e8400-e29b-41d4-a716-446655440002"
         title: "Celestial Harmony"
-        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fcelestial_harmony.jpeg?alt=media&token=3edf1cf9-c2f5-4c75-9819-36ff6a734c9a"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fcelestial_harmony.jpeg?alt=media&token=f5fe1845-3fac-4f46-8511-f35f928b6d1d"
         releaseYear: 2024
         genre: "romance"
         rating: 7.5
@@ -44,7 +58,7 @@ mutation {
       {
         id: "550e8400-e29b-41d4-a716-446655440004"
         title: "The Forgotten Island"
-        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fforgotten_island.jpeg?alt=media&token=bc2b16e1-caed-4649-952c-73b6113f205c"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fforgotten_island.jpeg?alt=media&token=a6b2d761-2018-48c3-91a1-632d199440d4"
         releaseYear: 2025
         genre: "adventure"
         rating: 7.6
@@ -114,7 +128,7 @@ mutation {
       {
         id: "550e8400-e29b-41d4-a716-446655440011"
         title: "Beyond the Horizon"
-        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fbeyond_horizon.jpeg?alt=media&token=31493973-0692-4e6e-8b88-afb1aaea17ee"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fbeyond_horizon.jpeg?alt=media&token=9c054b8d-1a63-48f6-b161-fb28e3d15e55"
         releaseYear: 2026
         genre: "sci-fi"
         rating: 8.5
@@ -144,7 +158,7 @@ mutation {
       {
         id: "550e8400-e29b-41d4-a716-446655440014"
         title: "Moonlit Crusade"
-        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fmoonlit_crusade.jpeg?alt=media&token=b13241f5-d7d0-4370-b651-07847ad99dc2"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fmoonlit_crusade.jpeg?alt=media&token=1e2d46e2-6b76-4e20-b656-4b005b37d14b"
         releaseYear: 2025
         genre: "fantasy"
         rating: 8.3
@@ -184,7 +198,7 @@ mutation {
       {
         id: "550e8400-e29b-41d4-a716-446655440018"
         title: "Parallel Justice"
-        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fparalel_justice.jpeg?alt=media&token=4544b5e2-7a1d-46ca-a97f-eb6a490d4288"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fparallel_justice.jpeg?alt=media&token=f975524a-6edf-4d3b-99e1-c99e62a50518"
         releaseYear: 2024
         genre: "crime"
         rating: 8.1
@@ -194,7 +208,7 @@ mutation {
       {
         id: "550e8400-e29b-41d4-a716-446655440019"
         title: "Veil of Illusion"
-        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fveil_illusion.jpeg?alt=media&token=7bf09a3c-c531-478a-9d02-5d99fca9393b"
+        imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fveil_illusion.jpeg?alt=media&token=baa02cce-efe8-4c9f-bd9f-65233c6e1ca8"
         releaseYear: 2022
         genre: "mystery"
         rating: 7.8

From 98982869125da643402250f7bd0201d1d8499247 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ros=C3=A1rio=20P=2E=20Fernandes?= <rosariopf@google.com>
Date: Tue, 11 Feb 2025 00:52:09 +0000
Subject: [PATCH 59/82] use gemini-2.0-flash model (#865)

---
 vertexai/main.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/vertexai/main.ts b/vertexai/main.ts
index b5f8a675f..78356cd29 100644
--- a/vertexai/main.ts
+++ b/vertexai/main.ts
@@ -38,7 +38,7 @@ async function main() {
   // Get a Gemini model
   const model = getGenerativeModel(
     vertexAI,
-    { model: "gemini-1.5-flash" }
+    { model: "gemini-2.0-flash" }
   );
   // Call generateContent with a string or Content(s)
   const generateContentResult = await model.generateContent("what is a cat?");

From 9de13839acf828d511004a9a1235752d7d92ae64 Mon Sep 17 00:00:00 2001
From: Maneesh Tewani <mtewani@google.com>
Date: Tue, 11 Feb 2025 14:51:39 -0800
Subject: [PATCH 60/82] Updated instructions

---
 dataconnect/app/src/pages/Home.tsx | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/dataconnect/app/src/pages/Home.tsx b/dataconnect/app/src/pages/Home.tsx
index 798b656c4..02e48d730 100644
--- a/dataconnect/app/src/pages/Home.tsx
+++ b/dataconnect/app/src/pages/Home.tsx
@@ -8,18 +8,32 @@ const ConditionalRender = ({ condition, preferred, alternate }: { condition: boo
 
 const PlaceholderMessage = () => (
   <div className="min-h-screen flex items-center justify-center text-center text-white">
-    <div className='px-4'>
-      <h1 className='text-4xl'>To get Started with Firebase Data Connect:</h1>
-      <ol className='list-decimal'>
-        <li>Add {window.location.host}<a target="_blank" className="underline text-blue-600 hover:text-blue-800 visited:text-purple-600" href="https://console.firebase.google.com/project/_/authentication/settings"> to your list of domains</a></li>
+    <div className="px-4">
+      <h1 className="text-4xl">To get Started with Firebase Data Connect:</h1>
+      <ol className="list-decimal">
+        {window.location.hostname != "localhost" && (
+          <li>
+            Add {window.location.host}
+            <a
+              target="_blank"
+              className="underline text-blue-600 hover:text-blue-800 visited:text-purple-600"
+              href="https://console.firebase.google.com/project/_/authentication/settings"
+            >
+              {" "}
+              to your list of domains
+            </a>
+          </li>
+        )}
         <li>Open app/src/lib/firebase.tsx and replace the firebaseConfig </li>
         <li>Open the Firebase Data Connect Extension</li>
         <li>Select your project</li>
         <li>Click "Start Emulators"</li>
+        <li>Open dataconnect/moviedata_insert.gql</li>
+        <li>Click Run (Local)</li>
       </ol>
     </div>
   </div>
-)
+);
 
 export default function HomePage() {
   const [topMovies, setTopMovies] = useState([]);

From e244b8394ea859f2f8ae792ff5a0a73acaf6f7d8 Mon Sep 17 00:00:00 2001
From: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Date: Tue, 25 Mar 2025 16:47:05 +0200
Subject: [PATCH 61/82] Update license reference (#851)

Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
---
 dataconnect/README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dataconnect/README.md b/dataconnect/README.md
index 06120471a..9a0445380 100644
--- a/dataconnect/README.md
+++ b/dataconnect/README.md
@@ -128,4 +128,4 @@ This repository contains the quickstart to help you explore the functionalities
 
 ## License
 
-© Google, 2024. Licensed under an [Apache-2](../../LICENSE) license.
+© Google, 2024. Licensed under an [Apache-2](../LICENSE) license.

From 8b6dbf72c46f55f5b7dd0272cfae6825d4bea443 Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Thu, 22 May 2025 11:47:42 -0500
Subject: [PATCH 62/82] Add Firebase AI SDK sample app (#889)

---
 ai/README.md                                  |    7 +
 ai/ai-react-app/.prettierrc                   |    1 +
 ai/ai-react-app/README.md                     |   33 +
 ai/ai-react-app/eslint.config.js              |   30 +
 ai/ai-react-app/firebase-icon.svg             |    6 +
 ai/ai-react-app/images/screenshot.png         |  Bin 0 -> 95990 bytes
 ai/ai-react-app/index.html                    |   13 +
 ai/ai-react-app/package-lock.json             | 3647 +++++++++++++++++
 ai/ai-react-app/package.json                  |   33 +
 ai/ai-react-app/src/App.tsx                   |   30 +
 ai/ai-react-app/src/assets/firebase-icon.png  |  Bin 0 -> 957 bytes
 .../components/Common/FileUploader.module.css |   71 +
 .../src/components/Common/FileUploader.tsx    |  104 +
 .../components/Common/PromptInput.module.css  |  150 +
 .../src/components/Common/PromptInput.tsx     |  190 +
 .../Common/ResponseDisplay.module.css         |   97 +
 .../src/components/Common/ResponseDisplay.tsx |   82 +
 .../components/Layout/LeftSidebar.module.css  |   73 +
 .../src/components/Layout/LeftSidebar.tsx     |   83 +
 .../components/Layout/MainLayout.module.css   |   39 +
 .../src/components/Layout/MainLayout.tsx      |  157 +
 .../components/Layout/RightSidebar.module.css |  255 ++
 .../src/components/Layout/RightSidebar.tsx    |  472 +++
 .../src/components/Layout/TopBar.module.css   |   29 +
 .../src/components/Layout/TopBar.tsx          |   22 +
 .../Specific/ChatMessage.module.css           |   49 +
 .../src/components/Specific/ChatMessage.tsx   |   63 +
 ai/ai-react-app/src/config/firebase-config.ts |    9 +
 ai/ai-react-app/src/index.css                 |   87 +
 ai/ai-react-app/src/main.tsx                  |   15 +
 .../src/services/firebaseAIService.ts         |  160 +
 ai/ai-react-app/src/utils/fileUtils.ts        |   49 +
 ai/ai-react-app/src/views/ChatView.module.css |  132 +
 ai/ai-react-app/src/views/ChatView.tsx        |  531 +++
 .../src/views/ImagenView.module.css           |  105 +
 ai/ai-react-app/src/views/ImagenView.tsx      |  147 +
 ai/ai-react-app/src/vite-env.d.ts             |    1 +
 ai/ai-react-app/tsconfig.app.json             |   26 +
 ai/ai-react-app/tsconfig.json                 |    7 +
 ai/ai-react-app/tsconfig.node.json            |   24 +
 ai/ai-react-app/vite.config.ts                |    6 +
 ai/ai-react-app/yarn.lock                     | 1991 +++++++++
 scripts/test.sh                               |    2 +-
 43 files changed, 9027 insertions(+), 1 deletion(-)
 create mode 100644 ai/README.md
 create mode 100644 ai/ai-react-app/.prettierrc
 create mode 100644 ai/ai-react-app/README.md
 create mode 100644 ai/ai-react-app/eslint.config.js
 create mode 100644 ai/ai-react-app/firebase-icon.svg
 create mode 100644 ai/ai-react-app/images/screenshot.png
 create mode 100644 ai/ai-react-app/index.html
 create mode 100644 ai/ai-react-app/package-lock.json
 create mode 100644 ai/ai-react-app/package.json
 create mode 100644 ai/ai-react-app/src/App.tsx
 create mode 100644 ai/ai-react-app/src/assets/firebase-icon.png
 create mode 100644 ai/ai-react-app/src/components/Common/FileUploader.module.css
 create mode 100644 ai/ai-react-app/src/components/Common/FileUploader.tsx
 create mode 100644 ai/ai-react-app/src/components/Common/PromptInput.module.css
 create mode 100644 ai/ai-react-app/src/components/Common/PromptInput.tsx
 create mode 100644 ai/ai-react-app/src/components/Common/ResponseDisplay.module.css
 create mode 100644 ai/ai-react-app/src/components/Common/ResponseDisplay.tsx
 create mode 100644 ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
 create mode 100644 ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
 create mode 100644 ai/ai-react-app/src/components/Layout/MainLayout.module.css
 create mode 100644 ai/ai-react-app/src/components/Layout/MainLayout.tsx
 create mode 100644 ai/ai-react-app/src/components/Layout/RightSidebar.module.css
 create mode 100644 ai/ai-react-app/src/components/Layout/RightSidebar.tsx
 create mode 100644 ai/ai-react-app/src/components/Layout/TopBar.module.css
 create mode 100644 ai/ai-react-app/src/components/Layout/TopBar.tsx
 create mode 100644 ai/ai-react-app/src/components/Specific/ChatMessage.module.css
 create mode 100644 ai/ai-react-app/src/components/Specific/ChatMessage.tsx
 create mode 100644 ai/ai-react-app/src/config/firebase-config.ts
 create mode 100644 ai/ai-react-app/src/index.css
 create mode 100644 ai/ai-react-app/src/main.tsx
 create mode 100644 ai/ai-react-app/src/services/firebaseAIService.ts
 create mode 100644 ai/ai-react-app/src/utils/fileUtils.ts
 create mode 100644 ai/ai-react-app/src/views/ChatView.module.css
 create mode 100644 ai/ai-react-app/src/views/ChatView.tsx
 create mode 100644 ai/ai-react-app/src/views/ImagenView.module.css
 create mode 100644 ai/ai-react-app/src/views/ImagenView.tsx
 create mode 100644 ai/ai-react-app/src/vite-env.d.ts
 create mode 100644 ai/ai-react-app/tsconfig.app.json
 create mode 100644 ai/ai-react-app/tsconfig.json
 create mode 100644 ai/ai-react-app/tsconfig.node.json
 create mode 100644 ai/ai-react-app/vite.config.ts
 create mode 100644 ai/ai-react-app/yarn.lock

diff --git a/ai/README.md b/ai/README.md
new file mode 100644
index 000000000..65c36064c
--- /dev/null
+++ b/ai/README.md
@@ -0,0 +1,7 @@
+# Firebase AI SDK Quickstart
+
+This directory contains samples for the Firebase AI SDK for Web.
+
+## Table of Contents
+
+1. **Firebase AI Logic Sample App (`ai-react-app/`)**: demonstrates features of the Firebase AI SDK for Web integrated into a web application built with React and TypeScript.
diff --git a/ai/ai-react-app/.prettierrc b/ai/ai-react-app/.prettierrc
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/ai/ai-react-app/.prettierrc
@@ -0,0 +1 @@
+{}
diff --git a/ai/ai-react-app/README.md b/ai/ai-react-app/README.md
new file mode 100644
index 000000000..972eecfd7
--- /dev/null
+++ b/ai/ai-react-app/README.md
@@ -0,0 +1,33 @@
+# Firebase AI Logic Sample App
+
+![Photo of the Firebase AI Logic Sample App](images/screenshot.png)
+
+This sample application demonstrates features of the Firebase AI SDK for Web (`firebase/ai`), integrated into a web application built with React and TypeScript.
+
+For more information about the Firebase AI SDK, see the [Firebase AI Logic Docs](https://firebase.google.com/docs/ai-logic).
+
+## Setup Instructions
+
+1. Use the guided workflow in the [Firebase AI Logic page](https://console.firebase.google.com/project/_/ailogic?_gl=1*dps5w8*_ga*NDk4MDUyODg4LjE3NDc4NTIwMDA.*_ga_CW55HF8NVT*czE3NDc5MzE2NzQkbzIkZzEkdDE3NDc5MzE3MjEkajEzJGwwJGgwJGRjVEhnTE1XMmtOQURjUXFPa18zZlRTU2JIblVCY0tTenN3) of the Firebase Console to setup your project (including enabling the required APIs for your chosen Gemini API provider), then register your app with your Firebase project.
+
+1. Update `src/config/firebase-config.ts` with your Firebase configuration.
+
+1. Install dependencies:
+
+   ```bash
+   yarn
+   ```
+
+1. Start the development server:
+
+   ```bash
+   yarn dev
+   ```
+
+## Support
+
+- [Firebase Support](https://firebase.google.com/support/)
+
+## License
+
+© Google, 2025. Licensed under an [Apache-2](../LICENSE)
diff --git a/ai/ai-react-app/eslint.config.js b/ai/ai-react-app/eslint.config.js
new file mode 100644
index 000000000..64f8a4b71
--- /dev/null
+++ b/ai/ai-react-app/eslint.config.js
@@ -0,0 +1,30 @@
+import js from "@eslint/js";
+import globals from "globals";
+import reactHooks from "eslint-plugin-react-hooks";
+import reactRefresh from "eslint-plugin-react-refresh";
+import tseslint from "typescript-eslint";
+import eslintConfigPrettier from "eslint-config-prettier/flat"
+
+export default tseslint.config(
+  { ignores: ["dist"] },
+  {
+    extends: [js.configs.recommended, ...tseslint.configs.recommended],
+    files: ["**/*.{ts,tsx}"],
+    languageOptions: {
+      ecmaVersion: 2020,
+      globals: globals.browser,
+    },
+    plugins: {
+      "react-hooks": reactHooks,
+      "react-refresh": reactRefresh,
+    },
+    rules: {
+      ...reactHooks.configs.recommended.rules,
+      "react-refresh/only-export-components": [
+        "warn",
+        { allowConstantExport: true },
+      ],
+    },
+  },
+  eslintConfigPrettier
+);
diff --git a/ai/ai-react-app/firebase-icon.svg b/ai/ai-react-app/firebase-icon.svg
new file mode 100644
index 000000000..f7515edcb
--- /dev/null
+++ b/ai/ai-react-app/firebase-icon.svg
@@ -0,0 +1,6 @@
+<svg width="600" height="600" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M213.918 560.499C237.166 569.856 262.387 575.408 288.87 576.333C324.71 577.585 358.792 570.175 389.261 556.099C352.724 541.744 319.634 520.751 291.392 494.651C273.086 523.961 246.01 547.113 213.918 560.499Z" fill="#FF9100"/>
+<path d="M291.389 494.66C226.923 435.038 187.815 348.743 191.12 254.092C191.228 251.019 191.39 247.947 191.58 244.876C180.034 241.89 167.98 240.068 155.576 239.635C137.821 239.015 120.626 241.217 104.393 245.788C87.1838 275.933 76.7989 310.521 75.5051 347.569C72.1663 443.18 130.027 526.723 213.914 560.508C246.007 547.121 273.082 523.998 291.389 494.66Z" fill="#FFC400"/>
+<path d="M291.39 494.657C306.378 470.671 315.465 442.551 316.523 412.254C319.306 332.559 265.731 264.003 191.581 244.873C191.391 247.944 191.229 251.016 191.121 254.089C187.816 348.74 226.924 435.035 291.39 494.657Z" fill="#FF9100"/>
+<path d="M308.231 20.8584C266 54.6908 232.652 99.302 212.475 150.693C200.924 180.129 193.665 211.748 191.546 244.893C265.696 264.023 319.272 332.579 316.489 412.273C315.431 442.57 306.317 470.663 291.355 494.677C319.595 520.804 352.686 541.77 389.223 556.124C462.56 522.224 514.593 449.278 517.606 362.997C519.558 307.096 498.08 257.273 467.731 215.219C435.68 170.742 308.231 20.8584 308.231 20.8584Z" fill="#DD2C00"/>
+</svg>
diff --git a/ai/ai-react-app/images/screenshot.png b/ai/ai-react-app/images/screenshot.png
new file mode 100644
index 0000000000000000000000000000000000000000..99b9a5265863a635a03e838a42ecca763a5a3026
GIT binary patch
diff --git a/ai/ai-react-app/index.html b/ai/ai-react-app/index.html
new file mode 100644
index 000000000..1d34e7b64
--- /dev/null
+++ b/ai/ai-react-app/index.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" type="image/svg+xml" href="/firebase-icon.svg" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Firebase AI Sample App</title>
+  </head>
+  <body>
+    <div id="root"></div>
+    <script type="module" src="/src/main.tsx"></script>
+  </body>
+</html>
diff --git a/ai/ai-react-app/package-lock.json b/ai/ai-react-app/package-lock.json
new file mode 100644
index 000000000..00af3ac75
--- /dev/null
+++ b/ai/ai-react-app/package-lock.json
@@ -0,0 +1,3647 @@
+{
+  "name": "ai",
+  "version": "0.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "ai",
+      "version": "0.0.0",
+      "dependencies": {
+        "firebase": "11.8.0",
+        "immer": "^10.1.1",
+        "react": "^19.0.0",
+        "react-dom": "^19.0.0"
+      },
+      "devDependencies": {
+        "@eslint/js": "^9.22.0",
+        "@types/react": "^19.0.10",
+        "@types/react-dom": "^19.0.4",
+        "@vitejs/plugin-react": "^4.3.4",
+        "eslint": "^9.22.0",
+        "eslint-config-prettier": "^10.1.2",
+        "eslint-plugin-react-hooks": "^5.2.0",
+        "eslint-plugin-react-refresh": "^0.4.19",
+        "globals": "^16.0.0",
+        "prettier": "^3.5.3",
+        "typescript": "~5.7.2",
+        "typescript-eslint": "^8.26.1",
+        "vite": "^6.3.1"
+      }
+    },
+    "node_modules/@ampproject/remapping": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+      "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.26.2",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+      "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.25.9",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.26.8",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz",
+      "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.26.10",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz",
+      "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@ampproject/remapping": "^2.2.0",
+        "@babel/code-frame": "^7.26.2",
+        "@babel/generator": "^7.26.10",
+        "@babel/helper-compilation-targets": "^7.26.5",
+        "@babel/helper-module-transforms": "^7.26.0",
+        "@babel/helpers": "^7.26.10",
+        "@babel/parser": "^7.26.10",
+        "@babel/template": "^7.26.9",
+        "@babel/traverse": "^7.26.10",
+        "@babel/types": "^7.26.10",
+        "convert-source-map": "^2.0.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.3",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz",
+      "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.27.0",
+        "@babel/types": "^7.27.0",
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.25",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz",
+      "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.26.8",
+        "@babel/helper-validator-option": "^7.25.9",
+        "browserslist": "^4.24.0",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
+      "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.25.9",
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz",
+      "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.25.9",
+        "@babel/helper-validator-identifier": "^7.25.9",
+        "@babel/traverse": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz",
+      "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+      "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+      "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
+      "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz",
+      "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.27.0",
+        "@babel/types": "^7.27.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
+      "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.27.0"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-react-jsx-self": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz",
+      "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-react-jsx-source": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz",
+      "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
+      "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.26.2",
+        "@babel/parser": "^7.27.0",
+        "@babel/types": "^7.27.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz",
+      "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.26.2",
+        "@babel/generator": "^7.27.0",
+        "@babel/parser": "^7.27.0",
+        "@babel/template": "^7.27.0",
+        "@babel/types": "^7.27.0",
+        "debug": "^4.3.1",
+        "globals": "^11.1.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse/node_modules/globals": {
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
+      "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.25.9",
+        "@babel/helper-validator-identifier": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.25.3",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz",
+      "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.6.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz",
+      "integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eslint-visitor-keys": "^3.4.3"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.12.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+      "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/config-array": {
+      "version": "0.20.0",
+      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
+      "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/object-schema": "^2.1.6",
+        "debug": "^4.3.1",
+        "minimatch": "^3.1.2"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/config-helpers": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz",
+      "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/core": {
+      "version": "0.13.0",
+      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
+      "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/json-schema": "^7.0.15"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
+      "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^10.0.1",
+        "globals": "^14.0.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/globals": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "9.25.1",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz",
+      "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/object-schema": {
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
+      "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/plugin-kit": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz",
+      "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/core": "^0.13.0",
+        "levn": "^0.4.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@firebase/ai": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-1.3.0.tgz",
+      "integrity": "sha512-qBxJTtl9hpgZr050kVFTRADX6I0Ss6mEQyp/JEkBgKwwxixKnaRNqEDGFba4OKNL7K8E4Y7LlA/ZW6L8aCKH4A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.3",
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x",
+        "@firebase/app-types": "0.x"
+      }
+    },
+    "node_modules/@firebase/analytics": {
+      "version": "0.10.16",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.16.tgz",
+      "integrity": "sha512-cMtp19He7Fd6uaj/nDEul+8JwvJsN8aRSJyuA1QN3QrKvfDDp+efjVurJO61sJpkVftw9O9nNMdhFbRcTmTfRQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/installations": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/analytics-compat": {
+      "version": "0.2.22",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.22.tgz",
+      "integrity": "sha512-VogWHgwkdYhjWKh8O1XU04uPrRaiDihkWvE/EMMmtWtaUtVALnpLnUurc3QtSKdPnvTz5uaIGKlW84DGtSPFbw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/analytics": "0.10.16",
+        "@firebase/analytics-types": "0.8.3",
+        "@firebase/component": "0.6.17",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/analytics-types": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz",
+      "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@firebase/app": {
+      "version": "0.13.0",
+      "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.13.0.tgz",
+      "integrity": "sha512-Vj3MST245nq+V5UmmfEkB3isIgPouyUr8yGJlFeL9Trg/umG5ogAvrjAYvQ8gV7daKDoQSRnJKWI2JFpQqRsuQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@firebase/app-check": {
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.10.0.tgz",
+      "integrity": "sha512-AZlRlVWKcu8BH4Yf8B5EI8sOi2UNGTS8oMuthV45tbt6OVUTSQwFPIEboZzhNJNKY+fPsg7hH8vixUWFZ3lrhw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/app-check-compat": {
+      "version": "0.3.25",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.25.tgz",
+      "integrity": "sha512-3zrsPZWAKfV7DVC20T2dgfjzjtQnSJS65OfMOiddMUtJL1S5i0nAZKsdX0bOEvvrd0SBIL8jYnfpfDeQRnhV3w==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/app-check": "0.10.0",
+        "@firebase/app-check-types": "0.5.3",
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/app-check-interop-types": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz",
+      "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@firebase/app-check-types": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz",
+      "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@firebase/app-compat": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.4.0.tgz",
+      "integrity": "sha512-LjLUrzbUgTa/sCtPoLKT2C7KShvLVHS3crnU1Du02YxnGVLE0CUBGY/NxgfR/Zg84mEbj1q08/dgesojxjn0dA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/app": "0.13.0",
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@firebase/app-types": {
+      "version": "0.9.3",
+      "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz",
+      "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@firebase/auth": {
+      "version": "1.10.5",
+      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.10.5.tgz",
+      "integrity": "sha512-6wF/NdMTwObL4RNQePunuzMr9O3gyftisvFZFFKf57D2HONXo87YymogRV8d+Z7SLA0rcNBN1gLJVk2D0y97gA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x",
+        "@react-native-async-storage/async-storage": "^1.18.1"
+      },
+      "peerDependenciesMeta": {
+        "@react-native-async-storage/async-storage": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@firebase/auth-compat": {
+      "version": "0.5.25",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.25.tgz",
+      "integrity": "sha512-YKUYnvrxXBRhH/iYEwSOv85VPvc6P36GW1OCDRebTw/cvgoj7pwac2nZKYFs5FHlNYe7Bc9I4BoY2X0vlkJo+g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/auth": "1.10.5",
+        "@firebase/auth-types": "0.13.0",
+        "@firebase/component": "0.6.17",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/auth-interop-types": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz",
+      "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@firebase/auth-types": {
+      "version": "0.13.0",
+      "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz",
+      "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==",
+      "license": "Apache-2.0",
+      "peerDependencies": {
+        "@firebase/app-types": "0.x",
+        "@firebase/util": "1.x"
+      }
+    },
+    "node_modules/@firebase/component": {
+      "version": "0.6.17",
+      "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.17.tgz",
+      "integrity": "sha512-M6DOg7OySrKEFS8kxA3MU5/xc37fiOpKPMz6cTsMUcsuKB6CiZxxNAvgFta8HGRgEpZbi8WjGIj6Uf+TpOhyzg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@firebase/data-connect": {
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.8.tgz",
+      "integrity": "sha512-xC50SxurrP0j9ksltZ8O2SuPuWTu9KymNxtSE4bmcc/HMOnOHaURgLyrQpcC5Pc7HmtCBxh9Q/lNKyc37rj5/g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/auth-interop-types": "0.2.4",
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/database": {
+      "version": "1.0.18",
+      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.18.tgz",
+      "integrity": "sha512-uXtYQmK6JCmqSx7dTOQD/qZtSnbMqnwvklF9n7wOJbdti4wKHmeUzgGXhPwDhN/R/BDTq78zKAbXya7hrCQjHw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.3",
+        "@firebase/auth-interop-types": "0.2.4",
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "faye-websocket": "0.11.4",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@firebase/database-compat": {
+      "version": "2.0.9",
+      "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.9.tgz",
+      "integrity": "sha512-9S6zK5+Tzslkt+lrYHDqbCbKBSQn3YYrNLIw8hTa/ALoqRLNTXF6acQIlxAxSeZj1hTttE6RRbuxxpMQJYt83w==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/database": "1.0.18",
+        "@firebase/database-types": "1.0.14",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@firebase/database-types": {
+      "version": "1.0.14",
+      "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.14.tgz",
+      "integrity": "sha512-8a0Q1GrxM0akgF0RiQHliinhmZd+UQPrxEmUv7MnQBYfVFiLtKOgs3g6ghRt/WEGJHyQNslZ+0PocIwNfoDwKw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/app-types": "0.9.3",
+        "@firebase/util": "1.12.0"
+      }
+    },
+    "node_modules/@firebase/firestore": {
+      "version": "4.7.15",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.15.tgz",
+      "integrity": "sha512-FgWTmkNBEXdKCoN2ngBNjrMaXuBx6QwjiZZVnOGg+VjUmiBq5gAqlDIW5bZY6i/NYvLUrWugdqIs7y9GHEqwww==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "@firebase/webchannel-wrapper": "1.0.3",
+        "@grpc/grpc-js": "~1.9.0",
+        "@grpc/proto-loader": "^0.7.8",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/firestore-compat": {
+      "version": "0.3.50",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.50.tgz",
+      "integrity": "sha512-1hAM+iaIqy2HHvSHQ56ccOOIigTeWAwjIpeQ+/O92uBoiajEITHdJofnGHglhhB5VV5qFl59Yz/AVDc+DssdYg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/firestore": "4.7.15",
+        "@firebase/firestore-types": "3.0.3",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/firestore-types": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz",
+      "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==",
+      "license": "Apache-2.0",
+      "peerDependencies": {
+        "@firebase/app-types": "0.x",
+        "@firebase/util": "1.x"
+      }
+    },
+    "node_modules/@firebase/functions": {
+      "version": "0.12.7",
+      "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.12.7.tgz",
+      "integrity": "sha512-gi8cw7yvaz19Erut+S0rHzNOWp4zPxAU/Kplb+XQoaE5gMV7MjHQoOGnYhSY8uOVj5f80S553s+2OBszG+14Ag==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/app-check-interop-types": "0.3.3",
+        "@firebase/auth-interop-types": "0.2.4",
+        "@firebase/component": "0.6.17",
+        "@firebase/messaging-interop-types": "0.2.3",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/functions-compat": {
+      "version": "0.3.24",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.24.tgz",
+      "integrity": "sha512-UjJabci+Bqci+A9WqfJ6sjZp+wGvi47llnQMjQRrF4coKfUyu9zBNTXhbx5W3rdVFQYwnWJm8VuluuNh2PCuyQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/functions": "0.12.7",
+        "@firebase/functions-types": "0.6.3",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/functions-types": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz",
+      "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@firebase/installations": {
+      "version": "0.6.17",
+      "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.17.tgz",
+      "integrity": "sha512-zfhqCNJZRe12KyADtRrtOj+SeSbD1H/K8J24oQAJVv/u02eQajEGlhZtcx9Qk7vhGWF5z9dvIygVDYqLL4o1XQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/util": "1.12.0",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/installations-compat": {
+      "version": "0.2.17",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.17.tgz",
+      "integrity": "sha512-J7afeCXB7yq25FrrJAgbx8mn1nG1lZEubOLvYgG7ZHvyoOCK00sis5rj7TgDrLYJgdj/SJiGaO1BD3BAp55TeA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/installations": "0.6.17",
+        "@firebase/installations-types": "0.5.3",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/installations-types": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz",
+      "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==",
+      "license": "Apache-2.0",
+      "peerDependencies": {
+        "@firebase/app-types": "0.x"
+      }
+    },
+    "node_modules/@firebase/logger": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz",
+      "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@firebase/messaging": {
+      "version": "0.12.21",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.21.tgz",
+      "integrity": "sha512-bYJ2Evj167Z+lJ1ach6UglXz5dUKY1zrJZd15GagBUJSR7d9KfiM1W8dsyL0lDxcmhmA/sLaBYAAhF1uilwN0g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/installations": "0.6.17",
+        "@firebase/messaging-interop-types": "0.2.3",
+        "@firebase/util": "1.12.0",
+        "idb": "7.1.1",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/messaging-compat": {
+      "version": "0.2.21",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.21.tgz",
+      "integrity": "sha512-1yMne+4BGLbHbtyu/VyXWcLiefUE1+K3ZGfVTyKM4BH4ZwDFRGoWUGhhx+tKRX4Tu9z7+8JN67SjnwacyNWK5g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/messaging": "0.12.21",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/messaging-interop-types": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz",
+      "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@firebase/performance": {
+      "version": "0.7.6",
+      "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.6.tgz",
+      "integrity": "sha512-AsOz74dSTlyQGlnnbLWXiHFAsrxhpssPOsFFi4HgOJ5DjzkK7ZdZ/E9uMPrwFoXJyMVoybGRuqsL/wkIbFITsA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/installations": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0",
+        "web-vitals": "^4.2.4"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/performance-compat": {
+      "version": "0.2.19",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.19.tgz",
+      "integrity": "sha512-4cU0T0BJ+LZK/E/UwFcvpBCVdkStgBMQwBztM9fJPT6udrEUk3ugF5/HT+E2Z22FCXtIaXDukJbYkE/c3c6IHw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/performance": "0.7.6",
+        "@firebase/performance-types": "0.2.3",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/performance-types": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz",
+      "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@firebase/remote-config": {
+      "version": "0.6.4",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.6.4.tgz",
+      "integrity": "sha512-ZyLJRT46wtycyz2+opEkGaoFUOqRQjt/0NX1WfUISOMCI/PuVoyDjqGpq24uK+e8D5NknyTpiXCVq5dowhScmg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/installations": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/remote-config-compat": {
+      "version": "0.2.17",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.17.tgz",
+      "integrity": "sha512-KelsBD0sXSC0u3esr/r6sJYGRN6pzn3bYuI/6pTvvmZbjBlxQkRabHAVH6d+YhLcjUXKIAYIjZszczd1QJtOyA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/logger": "0.4.4",
+        "@firebase/remote-config": "0.6.4",
+        "@firebase/remote-config-types": "0.4.0",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/remote-config-types": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz",
+      "integrity": "sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@firebase/storage": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.11.tgz",
+      "integrity": "sha512-nBtCGGpr39vuAeTQhG73nvMq3BjQBTgIg6fWufB6qglWYQCgky/XE4duSrOhTp2/QC+H3/SnaE/nKOQmjnPqjg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app": "0.x"
+      }
+    },
+    "node_modules/@firebase/storage-compat": {
+      "version": "0.3.21",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.21.tgz",
+      "integrity": "sha512-LG3978H2Vy1XGa0Jz9VNFwgMrhjy/G8CTV8GkWpArzu+AhI/SE9c0e06SiXcFsVaQW2rObcqFa0zp51LDaVzRA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/component": "0.6.17",
+        "@firebase/storage": "0.13.11",
+        "@firebase/storage-types": "0.8.3",
+        "@firebase/util": "1.12.0",
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "peerDependencies": {
+        "@firebase/app-compat": "0.x"
+      }
+    },
+    "node_modules/@firebase/storage-types": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz",
+      "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==",
+      "license": "Apache-2.0",
+      "peerDependencies": {
+        "@firebase/app-types": "0.x",
+        "@firebase/util": "1.x"
+      }
+    },
+    "node_modules/@firebase/util": {
+      "version": "1.12.0",
+      "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.12.0.tgz",
+      "integrity": "sha512-Z4rK23xBCwgKDqmzGVMef+Vb4xso2j5Q8OG0vVL4m4fA5ZjPMYQazu8OJJC3vtQRC3SQ/Pgx/6TPNVsCd70QRw==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@firebase/webchannel-wrapper": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz",
+      "integrity": "sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@grpc/grpc-js": {
+      "version": "1.9.15",
+      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz",
+      "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@grpc/proto-loader": "^0.7.8",
+        "@types/node": ">=12.12.47"
+      },
+      "engines": {
+        "node": "^8.13.0 || >=10.10.0"
+      }
+    },
+    "node_modules/@grpc/proto-loader": {
+      "version": "0.7.15",
+      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz",
+      "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "lodash.camelcase": "^4.3.0",
+        "long": "^5.0.0",
+        "protobufjs": "^7.2.5",
+        "yargs": "^17.7.2"
+      },
+      "bin": {
+        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@humanfs/core": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
+      "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@humanfs/core": "^0.19.1",
+        "@humanwhocodes/retry": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+      "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/retry": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz",
+      "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+      "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/set-array": "^1.2.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+      "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.25",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.40.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz",
+      "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@types/babel__core": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+      "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "node_modules/@types/babel__generator": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+      "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__template": {
+      "version": "7.4.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+      "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__traverse": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz",
+      "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.20.7"
+      }
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
+      "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "22.14.1",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz",
+      "integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~6.21.0"
+      }
+    },
+    "node_modules/@types/react": {
+      "version": "19.1.2",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz",
+      "integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/@types/react-dom": {
+      "version": "19.1.2",
+      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz",
+      "integrity": "sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "^19.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "8.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz",
+      "integrity": "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.10.0",
+        "@typescript-eslint/scope-manager": "8.31.0",
+        "@typescript-eslint/type-utils": "8.31.0",
+        "@typescript-eslint/utils": "8.31.0",
+        "@typescript-eslint/visitor-keys": "8.31.0",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.3.1",
+        "natural-compare": "^1.4.0",
+        "ts-api-utils": "^2.0.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.9.0"
+      }
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "8.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz",
+      "integrity": "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "8.31.0",
+        "@typescript-eslint/types": "8.31.0",
+        "@typescript-eslint/typescript-estree": "8.31.0",
+        "@typescript-eslint/visitor-keys": "8.31.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.9.0"
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "8.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz",
+      "integrity": "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.31.0",
+        "@typescript-eslint/visitor-keys": "8.31.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "8.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz",
+      "integrity": "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/typescript-estree": "8.31.0",
+        "@typescript-eslint/utils": "8.31.0",
+        "debug": "^4.3.4",
+        "ts-api-utils": "^2.0.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.9.0"
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "8.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz",
+      "integrity": "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree": {
+      "version": "8.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz",
+      "integrity": "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.31.0",
+        "@typescript-eslint/visitor-keys": "8.31.0",
+        "debug": "^4.3.4",
+        "fast-glob": "^3.3.2",
+        "is-glob": "^4.0.3",
+        "minimatch": "^9.0.4",
+        "semver": "^7.6.0",
+        "ts-api-utils": "^2.0.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4 <5.9.0"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+      "version": "7.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+      "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "8.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz",
+      "integrity": "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.4.0",
+        "@typescript-eslint/scope-manager": "8.31.0",
+        "@typescript-eslint/types": "8.31.0",
+        "@typescript-eslint/typescript-estree": "8.31.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.9.0"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "8.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz",
+      "integrity": "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.31.0",
+        "eslint-visitor-keys": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@vitejs/plugin-react": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.4.1.tgz",
+      "integrity": "sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.26.10",
+        "@babel/plugin-transform-react-jsx-self": "^7.25.9",
+        "@babel/plugin-transform-react-jsx-source": "^7.25.9",
+        "@types/babel__core": "^7.20.5",
+        "react-refresh": "^0.17.0"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "peerDependencies": {
+        "vite": "^4.2.0 || ^5.0.0 || ^6.0.0"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "8.14.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
+      "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true,
+      "license": "Python-2.0"
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.24.4",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
+      "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001688",
+        "electron-to-chromium": "^1.5.73",
+        "node-releases": "^2.0.19",
+        "update-browserslist-db": "^1.1.1"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001715",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz",
+      "integrity": "sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "license": "MIT"
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/csstype": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/debug": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+      "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.140",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.140.tgz",
+      "integrity": "sha512-o82Rj+ONp4Ip7Cl1r7lrqx/pXhbp/lh9DpKcMNscFJdh8ebyRofnc7Sh01B4jx403RI0oqTBvlZ7OBIZLMr2+Q==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "license": "MIT"
+    },
+    "node_modules/esbuild": {
+      "version": "0.25.3",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz",
+      "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.25.3",
+        "@esbuild/android-arm": "0.25.3",
+        "@esbuild/android-arm64": "0.25.3",
+        "@esbuild/android-x64": "0.25.3",
+        "@esbuild/darwin-arm64": "0.25.3",
+        "@esbuild/darwin-x64": "0.25.3",
+        "@esbuild/freebsd-arm64": "0.25.3",
+        "@esbuild/freebsd-x64": "0.25.3",
+        "@esbuild/linux-arm": "0.25.3",
+        "@esbuild/linux-arm64": "0.25.3",
+        "@esbuild/linux-ia32": "0.25.3",
+        "@esbuild/linux-loong64": "0.25.3",
+        "@esbuild/linux-mips64el": "0.25.3",
+        "@esbuild/linux-ppc64": "0.25.3",
+        "@esbuild/linux-riscv64": "0.25.3",
+        "@esbuild/linux-s390x": "0.25.3",
+        "@esbuild/linux-x64": "0.25.3",
+        "@esbuild/netbsd-arm64": "0.25.3",
+        "@esbuild/netbsd-x64": "0.25.3",
+        "@esbuild/openbsd-arm64": "0.25.3",
+        "@esbuild/openbsd-x64": "0.25.3",
+        "@esbuild/sunos-x64": "0.25.3",
+        "@esbuild/win32-arm64": "0.25.3",
+        "@esbuild/win32-ia32": "0.25.3",
+        "@esbuild/win32-x64": "0.25.3"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint": {
+      "version": "9.25.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz",
+      "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.12.1",
+        "@eslint/config-array": "^0.20.0",
+        "@eslint/config-helpers": "^0.2.1",
+        "@eslint/core": "^0.13.0",
+        "@eslint/eslintrc": "^3.3.1",
+        "@eslint/js": "9.25.1",
+        "@eslint/plugin-kit": "^0.2.8",
+        "@humanfs/node": "^0.16.6",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@humanwhocodes/retry": "^0.4.2",
+        "@types/estree": "^1.0.6",
+        "@types/json-schema": "^7.0.15",
+        "ajv": "^6.12.4",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.6",
+        "debug": "^4.3.2",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^8.3.0",
+        "eslint-visitor-keys": "^4.2.0",
+        "espree": "^10.3.0",
+        "esquery": "^1.5.0",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^8.0.0",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "ignore": "^5.2.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.3"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://eslint.org/donate"
+      },
+      "peerDependencies": {
+        "jiti": "*"
+      },
+      "peerDependenciesMeta": {
+        "jiti": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-config-prettier": {
+      "version": "10.1.2",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz",
+      "integrity": "sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "eslint-config-prettier": "bin/cli.js"
+      },
+      "peerDependencies": {
+        "eslint": ">=7.0.0"
+      }
+    },
+    "node_modules/eslint-plugin-react-hooks": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz",
+      "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
+      }
+    },
+    "node_modules/eslint-plugin-react-refresh": {
+      "version": "0.4.20",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz",
+      "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "eslint": ">=8.40"
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
+      "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/espree": {
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
+      "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "acorn": "^8.14.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+      "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "estraverse": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.8"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/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,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fastq": {
+      "version": "1.19.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+      "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/faye-websocket": {
+      "version": "0.11.4",
+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+      "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "websocket-driver": ">=0.5.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/fdir": {
+      "version": "6.4.4",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
+      "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/file-entry-cache": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+      "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flat-cache": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/firebase": {
+      "version": "11.8.0",
+      "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.8.0.tgz",
+      "integrity": "sha512-zIv11czOqFayPllaJySKIKB2pS+xoWOnfI7j85SOiBKY1IW3NuZIaL+UgsZA+4PQZkPhFP8vmU2/oOun04ALbg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@firebase/ai": "1.3.0",
+        "@firebase/analytics": "0.10.16",
+        "@firebase/analytics-compat": "0.2.22",
+        "@firebase/app": "0.13.0",
+        "@firebase/app-check": "0.10.0",
+        "@firebase/app-check-compat": "0.3.25",
+        "@firebase/app-compat": "0.4.0",
+        "@firebase/app-types": "0.9.3",
+        "@firebase/auth": "1.10.5",
+        "@firebase/auth-compat": "0.5.25",
+        "@firebase/data-connect": "0.3.8",
+        "@firebase/database": "1.0.18",
+        "@firebase/database-compat": "2.0.9",
+        "@firebase/firestore": "4.7.15",
+        "@firebase/firestore-compat": "0.3.50",
+        "@firebase/functions": "0.12.7",
+        "@firebase/functions-compat": "0.3.24",
+        "@firebase/installations": "0.6.17",
+        "@firebase/installations-compat": "0.2.17",
+        "@firebase/messaging": "0.12.21",
+        "@firebase/messaging-compat": "0.2.21",
+        "@firebase/performance": "0.7.6",
+        "@firebase/performance-compat": "0.2.19",
+        "@firebase/remote-config": "0.6.4",
+        "@firebase/remote-config-compat": "0.2.17",
+        "@firebase/storage": "0.13.11",
+        "@firebase/storage-compat": "0.3.21",
+        "@firebase/util": "1.12.0"
+      }
+    },
+    "node_modules/flat-cache": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+      "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flatted": "^3.2.9",
+        "keyv": "^4.5.4"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+      "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/globals": {
+      "version": "16.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz",
+      "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/graphemer": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/http-parser-js": {
+      "version": "0.5.10",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
+      "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
+      "license": "MIT"
+    },
+    "node_modules/idb": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
+      "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
+      "license": "ISC"
+    },
+    "node_modules/ignore": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/immer": {
+      "version": "10.1.1",
+      "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz",
+      "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/immer"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+      "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+      "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/keyv": {
+      "version": "4.5.4",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "json-buffer": "3.0.1"
+      }
+    },
+    "node_modules/levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+      "license": "MIT"
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/long": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
+      "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/micromatch/node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.11",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.19",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+      "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/optionator": {
+      "version": "0.9.4",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.5"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+      "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.5.3",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
+      "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.8",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/prettier": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
+      "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "prettier": "bin/prettier.cjs"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
+    "node_modules/protobufjs": {
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
+      "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
+      "hasInstallScript": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/react": {
+      "version": "19.1.0",
+      "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
+      "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-dom": {
+      "version": "19.1.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
+      "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
+      "license": "MIT",
+      "dependencies": {
+        "scheduler": "^0.26.0"
+      },
+      "peerDependencies": {
+        "react": "^19.1.0"
+      }
+    },
+    "node_modules/react-refresh": {
+      "version": "0.17.0",
+      "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+      "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "4.40.0",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz",
+      "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "1.0.7"
+      },
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=18.0.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "@rollup/rollup-android-arm-eabi": "4.40.0",
+        "@rollup/rollup-android-arm64": "4.40.0",
+        "@rollup/rollup-darwin-arm64": "4.40.0",
+        "@rollup/rollup-darwin-x64": "4.40.0",
+        "@rollup/rollup-freebsd-arm64": "4.40.0",
+        "@rollup/rollup-freebsd-x64": "4.40.0",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.40.0",
+        "@rollup/rollup-linux-arm-musleabihf": "4.40.0",
+        "@rollup/rollup-linux-arm64-gnu": "4.40.0",
+        "@rollup/rollup-linux-arm64-musl": "4.40.0",
+        "@rollup/rollup-linux-loongarch64-gnu": "4.40.0",
+        "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0",
+        "@rollup/rollup-linux-riscv64-gnu": "4.40.0",
+        "@rollup/rollup-linux-riscv64-musl": "4.40.0",
+        "@rollup/rollup-linux-s390x-gnu": "4.40.0",
+        "@rollup/rollup-linux-x64-gnu": "4.40.0",
+        "@rollup/rollup-linux-x64-musl": "4.40.0",
+        "@rollup/rollup-win32-arm64-msvc": "4.40.0",
+        "@rollup/rollup-win32-ia32-msvc": "4.40.0",
+        "@rollup/rollup-win32-x64-msvc": "4.40.0",
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/scheduler": {
+      "version": "0.26.0",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
+      "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
+      "license": "MIT"
+    },
+    "node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/tinyglobby": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
+      "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.4.4",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/ts-api-utils": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
+      "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.12"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+      "license": "0BSD"
+    },
+    "node_modules/type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.7.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
+      "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/typescript-eslint": {
+      "version": "8.31.0",
+      "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.0.tgz",
+      "integrity": "sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/eslint-plugin": "8.31.0",
+        "@typescript-eslint/parser": "8.31.0",
+        "@typescript-eslint/utils": "8.31.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.9.0"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+      "license": "MIT"
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+      "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/vite": {
+      "version": "6.3.2",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.2.tgz",
+      "integrity": "sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.25.0",
+        "fdir": "^6.4.3",
+        "picomatch": "^4.0.2",
+        "postcss": "^8.5.3",
+        "rollup": "^4.34.9",
+        "tinyglobby": "^0.2.12"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+        "jiti": ">=1.21.0",
+        "less": "*",
+        "lightningcss": "^1.21.0",
+        "sass": "*",
+        "sass-embedded": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.16.0",
+        "tsx": "^4.8.1",
+        "yaml": "^2.4.2"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "jiti": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/web-vitals": {
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
+      "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/websocket-driver": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "http-parser-js": ">=0.5.1",
+        "safe-buffer": ">=5.1.0",
+        "websocket-extensions": ">=0.1.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/websocket-extensions": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/word-wrap": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/yargs": {
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    }
+  }
+}
diff --git a/ai/ai-react-app/package.json b/ai/ai-react-app/package.json
new file mode 100644
index 000000000..c4c317c64
--- /dev/null
+++ b/ai/ai-react-app/package.json
@@ -0,0 +1,33 @@
+{
+  "name": "ai",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "tsc -b && vite build",
+    "lint": "eslint .",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "firebase": "11.8.0",
+    "immer": "^10.1.1",
+    "react": "^19.0.0",
+    "react-dom": "^19.0.0"
+  },
+  "devDependencies": {
+    "@eslint/js": "^9.22.0",
+    "@types/react": "^19.0.10",
+    "@types/react-dom": "^19.0.4",
+    "@vitejs/plugin-react": "^4.3.4",
+    "prettier": "^3.5.3",
+    "eslint": "^9.22.0",
+    "eslint-config-prettier": "^10.1.2",
+    "eslint-plugin-react-hooks": "^5.2.0",
+    "eslint-plugin-react-refresh": "^0.4.19",
+    "globals": "^16.0.0",
+    "typescript": "~5.7.2",
+    "typescript-eslint": "^8.26.1",
+    "vite": "^6.3.1"
+  }
+}
diff --git a/ai/ai-react-app/src/App.tsx b/ai/ai-react-app/src/App.tsx
new file mode 100644
index 000000000..5e77a25d3
--- /dev/null
+++ b/ai/ai-react-app/src/App.tsx
@@ -0,0 +1,30 @@
+import { useEffect, useState } from "react";
+import MainLayout from "./components/Layout/MainLayout";
+
+// Defines the primary modes or views available in the application.
+export type AppMode = "chat" | "imagenGen";
+
+function App() {
+  // State to manage which main view ('chat' or 'imagenGen') is currently active.
+  const [activeMode, setActiveMode] = useState<AppMode>("chat");
+
+  useEffect(() => {
+    const checkConfig = async () => {
+      // Dynamically import config to avoid potential early errors if placeholders exist
+      const { firebaseConfig } = await import("./config/firebase-config");
+      if (
+        firebaseConfig.apiKey === "YOUR_API_KEY" ||
+        !firebaseConfig.projectId
+      ) {
+        alert(
+          "WARNING: Firebase configuration in src/config/firebase-config.ts contains placeholder values. The app may not function correctly. Please replace them with your actual project configuration.",
+        );
+      }
+    };
+    checkConfig();
+  }, []);
+
+  return <MainLayout activeMode={activeMode} setActiveMode={setActiveMode} />;
+}
+
+export default App;
diff --git a/ai/ai-react-app/src/assets/firebase-icon.png b/ai/ai-react-app/src/assets/firebase-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..9f1d267198708e046369362dcca863eabb31b6ff
GIT binary patch
diff --git a/ai/ai-react-app/src/components/Common/FileUploader.module.css b/ai/ai-react-app/src/components/Common/FileUploader.module.css
new file mode 100644
index 000000000..cff5645e8
--- /dev/null
+++ b/ai/ai-react-app/src/components/Common/FileUploader.module.css
@@ -0,0 +1,71 @@
+.uploaderContainer {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  margin: 0;
+}
+
+.uploadButton {
+  background-color: transparent;
+  color: var(--fb-gray-70);
+  border: 1px dashed var(--fb-gray-40);
+  padding: 6px 12px;
+  border-radius: 4px;
+  cursor: pointer;
+  transition:
+    background-color 0.15s ease,
+    border-color 0.15s ease,
+    color 0.15s ease;
+  text-align: left;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  flex-grow: 1;
+  min-width: 100px;
+  font-size: 0.8125rem;
+  height: 30px;
+  line-height: 16px;
+}
+
+.uploadButton:hover:not(:disabled) {
+  background-color: var(--fb-gray-30);
+  border-color: var(--fb-gray-50);
+  color: var(--fb-gray-90);
+}
+
+.uploadButton:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+  color: var(--fb-gray-50);
+  border-color: var(--fb-gray-40);
+}
+
+.clearButton {
+  background-color: transparent;
+  color: var(--fb-gray-60);
+  border: none;
+  padding: 0;
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+  text-align: center;
+  border-radius: 50%;
+  cursor: pointer;
+  font-size: 1.2rem;
+  font-weight: 300;
+  transition:
+    background-color 0.15s ease,
+    color 0.15s ease;
+  flex-shrink: 0;
+}
+
+.clearButton:hover:not(:disabled) {
+  background-color: var(--fb-gray-40);
+  color: var(--fb-gray-90);
+}
+
+.clearButton:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+  color: var(--fb-gray-50);
+}
diff --git a/ai/ai-react-app/src/components/Common/FileUploader.tsx b/ai/ai-react-app/src/components/Common/FileUploader.tsx
new file mode 100644
index 000000000..e86e8d5a0
--- /dev/null
+++ b/ai/ai-react-app/src/components/Common/FileUploader.tsx
@@ -0,0 +1,104 @@
+import React, { useState, useRef, ChangeEvent } from "react";
+import styles from "./FileUploader.module.css";
+
+interface FileUploaderProps {
+  /** Callback triggered when a file is selected or cleared. Passes the File object or null. */
+  onFileSelect: (file: File | null) => void;
+  /** Standard HTML 'accept' attribute string (e.g., "image/*", ".pdf", "image/png,image/jpeg"). */
+  accept: string;
+  /** Optional text label for the button when no file is selected. */
+  label?: string;
+  /** Disables the uploader if true. */
+  disabled?: boolean;
+}
+
+/**
+ * A simple file uploader component using a styled button
+ * to trigger a hidden file input.
+ */
+const FileUploader: React.FC<FileUploaderProps> = ({
+  onFileSelect,
+  accept,
+  label = "Select File",
+  disabled = false,
+}) => {
+  // State to store the name of the selected file for display purposes.
+  const [selectedFileName, setSelectedFileName] = useState<string | null>(null);
+  // Ref to access the hidden file input element directly.
+  const fileInputRef = useRef<HTMLInputElement>(null);
+
+  // Handles the change event when a file is selected via the input.
+  const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
+    const file = event.target.files?.[0];
+    if (file) {
+      setSelectedFileName(file.name);
+      onFileSelect(file); // Notify parent component
+    } else {
+      // If no file is selected (e.g., user cancels the dialog)
+      setSelectedFileName(null);
+      onFileSelect(null);
+    }
+    // Reset the input value. This allows selecting the same file again
+    // if the user clears it and then wants to re-select it immediately.
+    if (event.target) {
+      event.target.value = "";
+    }
+  };
+
+  // Triggers the click event on the hidden file input when the button is clicked.
+  const handleButtonClick = () => {
+    fileInputRef.current?.click();
+  };
+
+  // Clears the current file selection.
+  const handleClearClick = (event: React.MouseEvent) => {
+    event.stopPropagation(); // Prevent triggering the button click underneath
+    setSelectedFileName(null);
+    onFileSelect(null); // Notify parent
+    // Also clear the hidden input's value
+    if (fileInputRef.current) {
+      fileInputRef.current.value = "";
+    }
+  };
+
+  return (
+    <div className={styles.uploaderContainer}>
+      {/* Hidden actual file input */}
+      <input
+        type="file"
+        ref={fileInputRef}
+        onChange={handleFileChange}
+        accept={accept}
+        style={{ display: "none" }} // Keep it hidden
+        disabled={disabled}
+        aria-hidden="true" // Improve accessibility
+      />
+      {/* The visible button that acts as the file selector */}
+      <button
+        type="button" // Prevents form submission if used within a <form>
+        className={styles.uploadButton}
+        onClick={handleButtonClick}
+        disabled={disabled}
+        title={selectedFileName ? `File: ${selectedFileName}` : label} // Tooltip
+      >
+        {/* Display file name or label */}
+        {selectedFileName ? `Selected: ${selectedFileName}` : label}
+      </button>
+      {/* Show clear button only when a file is selected */}
+      {selectedFileName && (
+        <button
+          type="button"
+          className={styles.clearButton}
+          onClick={handleClearClick}
+          disabled={disabled}
+          title="Clear file selection" // Tooltip for accessibility
+          aria-label="Clear file selection" // Aria label
+        >
+          × {/* Using a simple 'times' character for clear */}
+        </button>
+      )}
+    </div>
+  );
+};
+
+export default FileUploader;
diff --git a/ai/ai-react-app/src/components/Common/PromptInput.module.css b/ai/ai-react-app/src/components/Common/PromptInput.module.css
new file mode 100644
index 000000000..2f44d1977
--- /dev/null
+++ b/ai/ai-react-app/src/components/Common/PromptInput.module.css
@@ -0,0 +1,150 @@
+.promptContainer {
+  background-color: transparent;
+  border-top: none;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  width: 100%;
+}
+
+.suggestionsContainer {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+
+.suggestionButton {
+  background-color: var(--fb-gray-30);
+  color: var(--fb-gray-80);
+  border: 1px solid var(--fb-gray-40);
+  padding: 4px 10px;
+  border-radius: 16px;
+  cursor: pointer;
+  font-size: 0.8125rem;
+  transition:
+    background-color 0.15s ease,
+    border-color 0.15s ease,
+    color 0.15s ease;
+}
+.suggestionButton:hover:not(:disabled) {
+  background-color: var(--fb-gray-40);
+  border-color: var(--fb-gray-50);
+  color: var(--fb-gray-95);
+}
+.suggestionButton:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+}
+
+.inputArea {
+  display: flex;
+  align-items: flex-end;
+  background-color: var(--fb-gray-10);
+  border-radius: 4px;
+  border: 1px solid var(--fb-gray-40);
+  padding: 4px 4px 4px 12px;
+  transition: border-color 0.15s ease;
+  box-sizing: border-box;
+}
+.inputArea:focus-within {
+  border-color: var(--google-blue);
+}
+
+.promptTextarea {
+  flex-grow: 1;
+  background-color: transparent;
+  border: none;
+  color: var(--fb-gray-90);
+  resize: none;
+  outline: none;
+  font-size: 0.875rem;
+  line-height: 1.5;
+  min-height: 36px;
+  max-height: 150px;
+  overflow-y: auto;
+  padding: 8px 0;
+  margin-right: 8px;
+}
+.promptTextarea::placeholder {
+  color: var(--fb-gray-60);
+}
+
+.runButton {
+  background-color: var(--google-blue);
+  color: var(--fb-gray-100);
+  border: none;
+  padding: 0 16px;
+  border-radius: 4px;
+  cursor: pointer;
+  font-weight: 500;
+  transition: background-color 0.15s ease;
+  height: 36px;
+  line-height: 36px;
+  align-self: flex-end;
+  font-size: 0.875rem;
+  white-space: nowrap;
+  flex-shrink: 0;
+}
+.runButton:hover:not(:disabled) {
+  background-color: var(--google-blue-darker);
+}
+.runButton:disabled {
+  background-color: var(--fb-gray-30);
+  color: var(--fb-gray-50);
+  cursor: not-allowed;
+}
+
+.tokenCountSection {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px;
+  margin-top: 4px;
+}
+
+.countButton {
+  background-color: var(--fb-gray-30);
+  color: var(--fb-gray-80);
+  border: 1px solid var(--fb-gray-40);
+  padding: 4px 10px;
+  border-radius: 4px;
+  cursor: pointer;
+  font-size: 0.8125rem;
+  transition:
+    background-color 0.15s ease,
+    border-color 0.15s ease,
+    color 0.15s ease;
+  white-space: nowrap;
+  flex-shrink: 0;
+}
+.countButton:hover:not(:disabled) {
+  background-color: var(--fb-gray-40);
+  border-color: var(--fb-gray-50);
+  color: var(--fb-gray-95);
+}
+.countButton:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+  background-color: var(--fb-gray-20);
+  border-color: var(--fb-gray-30);
+}
+
+.tokenCountDisplay {
+  font-size: 0.8125rem;
+  color: var(--fb-gray-70);
+  flex-grow: 1;
+  text-align: right;
+  min-height: 1.2em;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.tokenError {
+  color: var(--fb-error-text);
+  font-style: italic;
+}
+.tokenPlaceholder {
+  color: var(--fb-gray-60);
+  font-style: italic;
+}
diff --git a/ai/ai-react-app/src/components/Common/PromptInput.tsx b/ai/ai-react-app/src/components/Common/PromptInput.tsx
new file mode 100644
index 000000000..93bfc9d6a
--- /dev/null
+++ b/ai/ai-react-app/src/components/Common/PromptInput.tsx
@@ -0,0 +1,190 @@
+import React, { useState, useCallback } from "react";
+import styles from "./PromptInput.module.css";
+import {
+  AI,
+  ModelParams,
+  CountTokensResponse,
+  Part,
+  getGenerativeModel,
+  ImagenModelParams,
+} from "firebase/ai";
+import { fileToGenerativePart } from "../../utils/fileUtils";
+import { AppMode } from "../../App";
+
+interface PromptInputProps {
+  prompt: string;
+  onPromptChange: (value: string) => void;
+  onSubmit: () => void;
+  /** isLoading refers to the main submit action loading state */
+  isLoading: boolean;
+  placeholder?: string;
+  suggestions?: string[];
+  onSuggestionClick?: (suggestion: string) => void;
+  activeMode: AppMode;
+  aiInstance: AI;
+  currentParams?: ModelParams;
+  currentImagenParams?: ImagenModelParams;
+  selectedFile: File | null;
+}
+
+const PromptInput: React.FC<PromptInputProps> = ({
+  prompt,
+  onPromptChange,
+  onSubmit,
+  isLoading,
+  placeholder = "Type your prompt here...",
+  suggestions,
+  onSuggestionClick,
+  activeMode,
+  aiInstance,
+  currentParams,
+  selectedFile,
+}) => {
+  const [tokenCount, setTokenCount] = useState<CountTokensResponse | null>(
+    null,
+  );
+  const [isCountingTokens, setIsCountingTokens] = useState<boolean>(false);
+  const [tokenCountError, setTokenCountError] = useState<string | null>(null);
+
+  const handleCountTokensClick = useCallback(async () => {
+    // Prevent counting if main action is loading or already counting
+    if (isLoading || isCountingTokens) return;
+
+    setIsCountingTokens(true);
+    setTokenCount(null);
+    setTokenCountError(null);
+
+    const currentPromptText = prompt.trim();
+    const parts: Part[] = [];
+
+    // Add text part if present
+    if (currentPromptText) {
+      parts.push({ text: currentPromptText });
+    }
+
+    // Add file part if present
+    if (selectedFile) {
+      try {
+        const filePart = await fileToGenerativePart(selectedFile);
+        parts.push(filePart);
+      } catch (err: unknown) {
+        console.error("Error processing file for token count:", err);
+        setTokenCountError(`Error processing file`);
+        setIsCountingTokens(false);
+        return;
+      }
+    }
+
+    // Don't count if there's nothing to count
+    if (parts.length === 0) {
+      setTokenCountError("Nothing to count tokens for (no text or file).");
+      setIsCountingTokens(false);
+      return;
+    }
+
+    try {
+      if (!currentParams) {
+        throw Error(
+          "[PromptInput] currentParams is undefined when counting tokens",
+        );
+      }
+      console.log("[PromptInput] Counting tokens with params:", currentParams);
+      const model = getGenerativeModel(aiInstance, currentParams);
+
+      const request = {
+        contents: [{ role: "user" as const, parts }],
+        systemInstruction: currentParams.systemInstruction,
+        tools: currentParams.tools,
+      };
+      console.log("[PromptInput] Calling countTokens with request:", request);
+
+      const result = await model.countTokens(request);
+      setTokenCount(result);
+      console.log("[PromptInput] Token count result:", result);
+    } catch (err: unknown) {
+      console.error("Error counting tokens:", err);
+      setTokenCountError(`Token count failed`);
+      setTokenCount(null); // Clear previous count on error
+    } finally {
+      setIsCountingTokens(false);
+    }
+  }, [
+    prompt,
+    selectedFile,
+    aiInstance,
+    currentParams,
+    isLoading,
+    isCountingTokens,
+  ]);
+
+  return (
+    <div className={styles.promptContainer}>
+      {/* Suggestions */}
+      {suggestions && suggestions.length > 0 && onSuggestionClick && (
+        <div className={styles.suggestionsContainer}>
+          {suggestions.map((suggestion, index) => (
+            <button
+              key={index}
+              className={styles.suggestionButton}
+              onClick={() => onSuggestionClick(suggestion)}
+              disabled={isLoading} // Disable buttons while loading
+            >
+              {suggestion}
+            </button>
+          ))}
+        </div>
+      )}
+
+      {/* Main Input Area */}
+      <div className={styles.inputArea}>
+        <textarea
+          className={styles.promptTextarea}
+          value={prompt}
+          onChange={(e) => onPromptChange(e.target.value)}
+          placeholder={placeholder}
+          disabled={isLoading || isCountingTokens} // Disable if main loading OR counting
+          rows={3}
+          aria-label="Prompt input"
+        />
+        <button
+          className={styles.runButton}
+          onClick={onSubmit}
+          disabled={isLoading || isCountingTokens || !prompt.trim()} // Disable if loading, counting, or empty
+          aria-label="Submit prompt"
+        >
+          {isLoading ? "Running..." : "Run ➤"}
+        </button>
+      </div>
+
+      {/* Token Count Section - Only available for GenerativeModel */}
+      {activeMode === "chat" && (
+        <div className={styles.tokenCountSection}>
+          <button
+            type="button"
+            onClick={handleCountTokensClick}
+            disabled={
+              isLoading || isCountingTokens || (!prompt.trim() && !selectedFile)
+            } // Disable if no content or loading
+            className={styles.countButton}
+            title="Estimate token count for the current prompt and file"
+          >
+            {isCountingTokens ? "Counting..." : "Count Tokens"}
+          </button>
+          <div className={styles.tokenCountDisplay}>
+            {tokenCountError && (
+              <span className={styles.tokenError}>{tokenCountError}</span>
+            )}
+            {!tokenCountError && tokenCount && (
+              <span>Total Tokens: {tokenCount.totalTokens}</span>
+            )}
+            {!tokenCountError && !tokenCount && !isCountingTokens && (
+              <span className={styles.tokenPlaceholder}></span>
+            )}
+          </div>
+        </div>
+      )}
+    </div>
+  );
+};
+
+export default PromptInput;
diff --git a/ai/ai-react-app/src/components/Common/ResponseDisplay.module.css b/ai/ai-react-app/src/components/Common/ResponseDisplay.module.css
new file mode 100644
index 000000000..4e455a77c
--- /dev/null
+++ b/ai/ai-react-app/src/components/Common/ResponseDisplay.module.css
@@ -0,0 +1,97 @@
+.responseContainer {
+  margin: 20px 24px;
+  padding: 0;
+  color: var(--fb-gray-90);
+}
+
+.responseTitle {
+  color: var(--fb-gray-70);
+  font-weight: 500;
+  margin: 0 0 12px 0;
+  padding-bottom: 0;
+  border-bottom: none;
+  font-size: 0.8125rem;
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+}
+
+.responseOutput {
+  background-color: var(--fb-gray-10);
+  padding: 16px;
+  border-radius: 4px;
+  border: 1px solid var(--fb-gray-30);
+  min-height: 100px;
+  margin-bottom: 16px;
+  position: relative;
+  overflow-wrap: break-word;
+  white-space: pre-wrap;
+  font-family: "Roboto Mono", monospace;
+  font-size: 0.875rem;
+  line-height: 1.6;
+  color: var(--fb-gray-90);
+}
+
+.responseText {
+  margin: 0;
+}
+
+.placeholder {
+  color: var(--fb-gray-60);
+  font-style: italic;
+}
+
+.loadingIndicator {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(48, 48, 48, 0.7);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  color: var(--fb-gray-80);
+  font-style: italic;
+  border-radius: 4px;
+  z-index: 1;
+}
+
+.jsonDetails {
+  margin-top: 16px;
+  border: 1px solid var(--fb-gray-40);
+  border-radius: 4px;
+  background-color: var(--fb-gray-10);
+}
+
+.jsonSummary {
+  padding: 8px 12px;
+  cursor: pointer;
+  background-color: var(--fb-gray-10);
+  border-radius: 4px 4px 0 0;
+  border-bottom: 1px solid var(--fb-gray-40);
+  outline: none;
+  font-size: 0.8125rem;
+  color: var(--fb-gray-80);
+  font-weight: 500;
+  list-style: none;
+}
+.jsonSummary::-webkit-details-marker {
+  display: none;
+}
+.jsonSummary:hover {
+  background-color: var(--fb-gray-30);
+}
+
+.jsonPre {
+  padding: 12px 16px;
+  margin: 0;
+  font-family: "Roboto Mono", monospace;
+  font-size: 0.8125rem;
+  color: var(--fb-gray-90);
+  white-space: pre-wrap;
+  word-wrap: break-word;
+  background-color: var(--fb-gray-10);
+  border-radius: 0 0 4px 4px;
+  max-height: 400px;
+  overflow: auto;
+}
diff --git a/ai/ai-react-app/src/components/Common/ResponseDisplay.tsx b/ai/ai-react-app/src/components/Common/ResponseDisplay.tsx
new file mode 100644
index 000000000..295ff0f2b
--- /dev/null
+++ b/ai/ai-react-app/src/components/Common/ResponseDisplay.tsx
@@ -0,0 +1,82 @@
+import React from "react";
+import styles from "./ResponseDisplay.module.css";
+
+// Simple component to format and display JSON data within a <pre> tag.
+const JsonViewer: React.FC<{ data: object }> = ({ data }) => {
+  try {
+    // Pretty-print JSON with 2-space indentation
+    const jsonString = JSON.stringify(data, null, 2);
+    return <pre className={styles.jsonPre}>{jsonString}</pre>;
+  } catch (error) {
+    console.error("Error formatting JSON for display:", error);
+    return (
+      <pre className={styles.jsonPre}>Error: Could not display JSON data.</pre>
+    );
+  }
+};
+
+interface ResponseDisplayProps {
+  /** The primary text output from the AI model (can be plain text or stringified JSON). */
+  responseText: string;
+  /** Optional parsed JSON object to display in a collapsible section. */
+  responseJson?: object | null;
+  /** Flag to indicate if the response is currently being generated. */
+  isLoading: boolean;
+  /** Optional title for the response area. */
+  title?: string;
+}
+
+/**
+ * Displays the AI model's response, handling loading states, text output,
+ * and an optional collapsible raw JSON view.
+ */
+const ResponseDisplay: React.FC<ResponseDisplayProps> = ({
+  responseText,
+  responseJson,
+  isLoading,
+  title = "Result",
+}) => {
+  // Determine whether to show the placeholder text.
+  // Show only if not loading AND there's no text or JSON data yet.
+  const showPlaceholder = !isLoading && !responseText && !responseJson;
+
+  // Determine whether to show the loading overlay.
+  // Show only when actively loading AND no response text has arrived yet (allows for streaming).
+  const showLoadingOverlay = isLoading && !responseText;
+
+  return (
+    <div className={styles.responseContainer}>
+      <h4 className={styles.responseTitle}>{title}</h4>
+      <div className={styles.responseOutput}>
+        {/* Loading Overlay */}
+        {showLoadingOverlay && (
+          <div className={styles.loadingIndicator}>Generating...</div>
+        )}
+
+        {/* Main Response Text */}
+        {/* Render the responseText if it exists, even during loading to support streaming output */}
+        {responseText && (
+          <pre className={styles.responseText}>{responseText}</pre>
+        )}
+
+        {/* Placeholder Text */}
+        {showPlaceholder && (
+          <div className={styles.placeholder}>Output will appear here.</div>
+        )}
+      </div>
+
+      {/* Optional JSON Viewer */}
+      {/* Show only if JSON data exists AND we are not currently loading */}
+      {responseJson && !isLoading && (
+        <details className={styles.jsonDetails}>
+          <summary className={styles.jsonSummary}>
+            View Raw Response JSON
+          </summary>
+          <JsonViewer data={responseJson} />
+        </details>
+      )}
+    </div>
+  );
+};
+
+export default ResponseDisplay;
diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
new file mode 100644
index 000000000..360af63e2
--- /dev/null
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
@@ -0,0 +1,73 @@
+.sidebar ul {
+  list-style: none;
+  padding: 0 12px;
+  margin: 0;
+}
+
+.sidebar li {
+  margin-bottom: 4px;
+}
+
+.navButton {
+  background-color: transparent;
+  border: none;
+  color: var(--fb-gray-70);
+  padding: 8px 12px;
+  text-align: left;
+  width: 100%;
+  cursor: pointer;
+  border-radius: 4px;
+  font-size: 0.875rem;
+  transition:
+    background-color 0.15s ease,
+    color 0.15s ease;
+  font-weight: 500;
+}
+
+.navButton:hover {
+  background-color: var(--fb-gray-30);
+  color: var(--fb-gray-95);
+}
+
+.navButton.active {
+  background-color: var(--fb-gray-30);
+  color: var(--fb-yellow);
+  font-weight: 500;
+}
+
+.navButton.active:hover {
+  background-color: var(--fb-gray-40);
+}
+
+.backendSelector {
+  margin-top: 24px;
+  padding: 0 12px;
+  border-top: 1px solid var(--fb-gray-30);
+  padding-top: 16px;
+}
+
+.selectorTitle {
+  color: var(--fb-gray-70);
+  font-size: 0.75rem;
+  font-weight: 500;
+  margin: 0 0 8px 0;
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+}
+
+.radioGroup {
+  margin-bottom: 6px;
+}
+
+.radioGroup label {
+  display: flex;
+  align-items: center;
+  font-size: 0.875rem;
+  color: var(--fb-gray-80);
+  cursor: pointer;
+}
+
+.radioGroup input[type="radio"] {
+  margin-right: 8px;
+  accent-color: var(--google-blue);
+}
diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
new file mode 100644
index 000000000..75e23d500
--- /dev/null
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -0,0 +1,83 @@
+import React from "react";
+import { AppMode } from "../../App";
+import styles from "./LeftSidebar.module.css";
+import { BackendType } from "firebase/ai";
+
+interface LeftSidebarProps {
+  /** The currently active application mode (e.g., 'chat', 'imagenGen'). */
+  activeMode: AppMode;
+  /** Function to call when a mode button is clicked, updating the active mode in the parent. */
+  setActiveMode: (mode: AppMode) => void;
+  activeBackend: BackendType;
+  setActiveBackend: (backend: BackendType) => void;
+}
+
+/**
+ * Renders the left navigation sidebar allowing users to switch between application modes.
+ */
+const LeftSidebar: React.FC<LeftSidebarProps> = ({
+  activeMode,
+  setActiveMode,
+  activeBackend,
+  setActiveBackend,
+}) => {
+  // Define the available modes and their display names
+  const modes: { id: AppMode; label: string }[] = [
+    { id: "chat", label: "Chat" },
+    { id: "imagenGen", label: "Imagen Generation" },
+  ];
+
+  const handleBackendChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+    setActiveBackend(event.target.value as BackendType);
+  };
+
+  return (
+    <nav className={styles.sidebar} aria-label="Main navigation">
+      <ul>
+        {modes.map((modeInfo) => (
+          <li key={modeInfo.id}>
+            <button
+              // Apply 'active' style if this button's mode matches the current activeMode
+              className={`${styles.navButton} ${activeMode === modeInfo.id ? styles.active : ""}`}
+              onClick={() => setActiveMode(modeInfo.id)}
+              aria-current={activeMode === modeInfo.id ? "page" : undefined}
+            >
+              {modeInfo.label}
+            </button>
+          </li>
+        ))}
+      </ul>
+
+      {/* Backend Selection */}
+      <div className={styles.backendSelector}>
+        <h6 className={styles.selectorTitle}>Backend API</h6>
+        <div className={styles.radioGroup}>
+          <label>
+            <input
+              type="radio"
+              name="backend"
+              value={BackendType.GOOGLE_AI}
+              checked={activeBackend === BackendType.GOOGLE_AI}
+              onChange={handleBackendChange}
+            />
+            Gemini Developer API
+          </label>
+        </div>
+        <div className={styles.radioGroup}>
+          <label>
+            <input
+              type="radio"
+              name="backend"
+              value={BackendType.VERTEX_AI}
+              checked={activeBackend === BackendType.VERTEX_AI}
+              onChange={handleBackendChange}
+            />
+            Vertex AI Gemini API
+          </label>
+        </div>
+      </div>
+    </nav>
+  );
+};
+
+export default LeftSidebar;
diff --git a/ai/ai-react-app/src/components/Layout/MainLayout.module.css b/ai/ai-react-app/src/components/Layout/MainLayout.module.css
new file mode 100644
index 000000000..6a9ce4b3e
--- /dev/null
+++ b/ai/ai-react-app/src/components/Layout/MainLayout.module.css
@@ -0,0 +1,39 @@
+.appContainer {
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+  background-color: var(--fb-gray-10);
+  color: var(--fb-gray-90);
+  overflow: hidden;
+}
+
+.mainContentArea {
+  display: flex;
+  flex-grow: 1;
+  overflow: hidden;
+}
+
+.leftSidebar {
+  width: 240px;
+  flex-shrink: 0;
+  background-color: var(--fb-gray-10);
+  padding-top: 16px;
+  overflow-y: auto;
+  border-right: 1px solid var(--fb-gray-30);
+}
+
+.centerContent {
+  flex-grow: 1;
+  background-color: var(--fb-gray-10);
+  display: flex;
+  flex-direction: column;
+  overflow-y: auto;
+}
+
+.rightSidebar {
+  width: 300px;
+  flex-shrink: 0;
+  background-color: var(--fb-gray-10);
+  overflow-y: auto;
+  border-left: 1px solid var(--fb-gray-30);
+}
diff --git a/ai/ai-react-app/src/components/Layout/MainLayout.tsx b/ai/ai-react-app/src/components/Layout/MainLayout.tsx
new file mode 100644
index 000000000..6e97a3a23
--- /dev/null
+++ b/ai/ai-react-app/src/components/Layout/MainLayout.tsx
@@ -0,0 +1,157 @@
+import React, { useState, useEffect } from "react";
+import TopBar from "./TopBar";
+import LeftSidebar from "./LeftSidebar";
+import RightSidebar from "./RightSidebar";
+import ChatView from "../../views/ChatView";
+import ImagenView from "../../views/ImagenView";
+import { AppMode } from "../../App";
+import {
+  UsageMetadata,
+  ModelParams,
+  ImagenModelParams,
+  BackendType,
+  AI,
+  VertexAIBackend,
+  GoogleAIBackend,
+  getAI,
+} from "firebase/ai";
+import {
+  AVAILABLE_GENERATIVE_MODELS,
+  AVAILABLE_IMAGEN_MODELS,
+  defaultGenerativeParams,
+  defaultImagenParams,
+} from "../../services/firebaseAIService";
+import styles from "./MainLayout.module.css";
+import { getApp } from "firebase/app";
+
+interface MainLayoutProps {
+  activeMode: AppMode;
+  setActiveMode: (mode: AppMode) => void;
+}
+
+/**
+ * Main layout component.
+ */
+const MainLayout: React.FC<MainLayoutProps> = ({
+  activeMode,
+  setActiveMode,
+}) => {
+  const [activeBackendType, setActiveBackendType] = useState<BackendType>(
+    BackendType.GOOGLE_AI,
+  ); // Default to Gemini Developer API
+  const [activeAI, setActiveAI] = useState<AI | null>(null);
+
+  const [generativeParams, setGenerativeParams] = useState<ModelParams>({
+    model: AVAILABLE_GENERATIVE_MODELS[0],
+    ...defaultGenerativeParams,
+  });
+  const [imagenParams, setImagenParams] = useState<ImagenModelParams>({
+    model: AVAILABLE_IMAGEN_MODELS[0],
+    ...defaultImagenParams,
+  });
+
+  const [usageMetadata, setUsageMetadata] = useState<UsageMetadata | null>(
+    null,
+  );
+
+  useEffect(() => {
+    console.log(`Initializing AI instance for backend: ${activeBackendType}`);
+    try {
+      const backendInstance =
+        activeBackendType === BackendType.VERTEX_AI
+          ? new VertexAIBackend()
+          : new GoogleAIBackend();
+      const aiInstance = getAI(getApp(), { backend: backendInstance });
+      setActiveAI(aiInstance);
+
+      console.log(
+        `AI instance for ${activeBackendType} initialized successfully.`,
+      );
+    } catch (error) {
+      console.error(
+        `Failed to initialize AI for backend ${activeBackendType}:`,
+        error,
+      );
+      setActiveAI(null);
+    }
+  }, [activeBackendType]);
+
+  useEffect(() => {
+    setUsageMetadata(null);
+  }, [activeMode]);
+
+  useEffect(() => {
+    const validModes: AppMode[] = ["chat", "imagenGen"];
+    if (!validModes.includes(activeMode)) {
+      console.warn(`Invalid activeMode "${activeMode}". Resetting to "chat".`);
+      setActiveMode("chat");
+    }
+  }, [activeMode, setActiveMode]);
+
+  const renderActiveView = () => {
+    // Show loading/error message if AI instance isn't ready
+    if (!activeAI) {
+      return (
+        <div style={{ padding: "20px", textAlign: "center" }}>
+          Initializing AI for {activeBackendType}...
+        </div>
+      );
+    }
+
+    switch (activeMode) {
+      case "chat":
+        return (
+          <ChatView
+            aiInstance={activeAI}
+            onUsageMetadataChange={setUsageMetadata}
+            currentParams={generativeParams}
+            activeMode={activeMode}
+          />
+        );
+      case "imagenGen":
+        return (
+          <ImagenView aiInstance={activeAI} currentParams={imagenParams} />
+        );
+      default:
+        console.error(`Unexpected activeMode: ${activeMode}`);
+        return (
+          <ChatView
+            aiInstance={activeAI}
+            onUsageMetadataChange={setUsageMetadata}
+            currentParams={generativeParams}
+            activeMode={activeMode}
+          />
+        );
+    }
+  };
+
+  return (
+    <div className={styles.appContainer}>
+      <TopBar />
+      <div className={styles.mainContentArea}>
+        <div className={styles.leftSidebar}>
+          <LeftSidebar
+            activeMode={activeMode}
+            setActiveMode={setActiveMode}
+            activeBackend={activeBackendType}
+            setActiveBackend={setActiveBackendType} // Pass backend state/setter
+          />
+        </div>
+        <main className={styles.centerContent}>{renderActiveView()}</main>
+        <div className={styles.rightSidebar}>
+          {/* Pass backend type for potential conditional rendering/logic */}
+          <RightSidebar
+            usageMetadata={usageMetadata}
+            activeMode={activeMode}
+            generativeParams={generativeParams}
+            setGenerativeParams={setGenerativeParams}
+            imagenParams={imagenParams}
+            setImagenParams={setImagenParams}
+          />
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default MainLayout;
diff --git a/ai/ai-react-app/src/components/Layout/RightSidebar.module.css b/ai/ai-react-app/src/components/Layout/RightSidebar.module.css
new file mode 100644
index 000000000..044e1b2ee
--- /dev/null
+++ b/ai/ai-react-app/src/components/Layout/RightSidebar.module.css
@@ -0,0 +1,255 @@
+.rightSidebarContainer {
+  padding: 24px;
+  color: var(--fb-gray-90);
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+  font-size: 0.875rem;
+  background-color: var(--fb-gray-10);
+  overflow-y: auto;
+}
+
+.sectionTitle {
+  color: var(--fb-gray-80);
+  font-weight: 500;
+  margin: 0 0 16px 0;
+  padding-bottom: 12px;
+  border-bottom: 1px solid var(--fb-gray-30);
+  font-size: 0.9rem;
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+}
+
+.subSectionTitle {
+  color: var(--fb-gray-70);
+  font-weight: 500;
+  margin: 16px 0 12px 0;
+  font-size: 0.8125rem;
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+}
+
+.controlGroup {
+  margin-bottom: 16px;
+}
+
+.controlGroup label {
+  display: block;
+  margin-bottom: 8px;
+  color: var(--fb-gray-70);
+  font-size: 0.8125rem;
+  font-weight: 500;
+}
+
+.controlGroup select,
+.controlGroup input[type="number"],
+.controlGroup input[type="text"],
+.controlGroup textarea {
+  width: 100%;
+  padding: 8px 12px;
+  background-color: var(--fb-gray-10);
+  border: 1px solid var(--fb-gray-40);
+  color: var(--fb-gray-90);
+  border-radius: 4px;
+  box-sizing: border-box;
+  font-size: 0.875rem;
+  transition:
+    border-color 0.15s ease,
+    background-color 0.15s ease;
+}
+.controlGroup select:hover,
+.controlGroup input:not([type="range"]):hover,
+.controlGroup textarea:hover {
+  border-color: var(--fb-gray-50);
+}
+.controlGroup select:focus,
+.controlGroup input:not([type="range"]):focus,
+.controlGroup textarea:focus {
+  border-color: var(--google-blue);
+  background-color: var(--fb-gray-10);
+  outline: none;
+}
+.controlGroup input:-webkit-autofill {
+  -webkit-box-shadow: 0 0 0 30px var(--fb-gray-10) inset !important;
+  -webkit-text-fill-color: var(--fb-gray-90) !important;
+}
+
+.controlGroup input[type="range"] {
+  width: 100%;
+  height: 4px;
+  cursor: pointer;
+  appearance: none;
+  background: var(--fb-gray-40);
+  outline: none;
+  border-radius: 2px;
+  padding: 0;
+  margin-top: 8px;
+}
+.controlGroup input[type="range"]::-webkit-slider-thumb {
+  appearance: none;
+  width: 14px;
+  height: 14px;
+  background: var(--fb-gray-80);
+  border-radius: 50%;
+  cursor: pointer;
+}
+.controlGroup input[type="range"]::-moz-range-thumb {
+  width: 14px;
+  height: 14px;
+  background: var(--fb-gray-80);
+  border-radius: 50%;
+  cursor: pointer;
+  border: none;
+}
+.controlGroup input[type="range"]:active::-webkit-slider-thumb {
+  background: var(--fb-gray-90);
+}
+.controlGroup input[type="range"]:active::-moz-range-thumb {
+  background: var(--fb-gray-90);
+}
+
+.controlGroup textarea {
+  resize: vertical;
+  min-height: 60px;
+}
+
+.temperatureDisplay {
+  text-align: right;
+  font-size: 0.8125rem;
+  color: var(--fb-gray-60);
+  margin-top: 6px;
+}
+
+.tokenDisplay {
+  background-color: var(--fb-gray-10);
+  border: 1px solid var(--fb-gray-40);
+  padding: 8px 12px;
+  border-radius: 4px;
+  font-size: 0.8125rem;
+  color: var(--fb-gray-70);
+  text-align: right;
+  font-family: "Roboto Mono", monospace;
+}
+
+.toggleGroup {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12px;
+  min-height: 30px;
+}
+.toggleGroup label:first-child {
+  color: var(--fb-gray-70);
+  font-size: 0.875rem;
+  padding-right: 10px;
+}
+
+.switch {
+  position: relative;
+  display: inline-block;
+  width: 36px;
+  height: 14px;
+  flex-shrink: 0;
+}
+
+.switch input {
+  opacity: 0;
+  width: 0;
+  height: 0;
+}
+
+.slider {
+  position: absolute;
+  cursor: pointer;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: var(--fb-gray-40);
+  transition: 0.2s;
+  border-radius: 7px;
+}
+
+.slider:before {
+  position: absolute;
+  content: "";
+  height: 20px;
+  width: 20px;
+  left: -2px;
+  bottom: -3px;
+  background-color: var(--fb-gray-80);
+  transition: 0.2s;
+  border-radius: 50%;
+  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
+}
+
+input:checked + .slider {
+  background-color: var(--google-blue);
+}
+
+input:checked + .slider:before {
+  transform: translateX(20px);
+  background-color: var(--fb-gray-95);
+}
+
+.toggleGroup input:disabled + .slider {
+  background-color: var(--fb-gray-30) !important;
+  cursor: not-allowed;
+}
+.toggleGroup input:disabled + .slider:before {
+  background-color: var(--fb-gray-50) !important;
+  cursor: not-allowed;
+  box-shadow: none;
+}
+.toggleGroup.disabledText label:first-child,
+.toggleGroup label input:disabled ~ span {
+  color: var(--fb-gray-50);
+  cursor: not-allowed;
+}
+.toggleGroup input:disabled ~ span {
+  cursor: not-allowed;
+}
+
+.advancedSettings details {
+  border: none;
+  margin-top: 20px;
+  background-color: transparent;
+}
+.advancedSettings summary {
+  padding: 8px 0;
+  cursor: pointer;
+  outline: none;
+  font-weight: 500;
+  color: var(--fb-gray-70);
+  font-size: 0.875rem;
+  list-style: none;
+  position: relative;
+}
+.advancedSettings summary:hover {
+  color: var(--fb-gray-90);
+}
+.advancedSettings summary::-webkit-details-marker {
+  display: none;
+}
+.advancedSettings summary::before {
+  content: "▶";
+  display: inline-block;
+  margin-right: 8px;
+  font-size: 0.7em;
+  transition: transform 0.2s ease-out;
+  color: var(--fb-gray-60);
+}
+.advancedSettings details[open] summary::before {
+  transform: rotate(90deg);
+}
+
+.advancedSettings .advancedContent {
+  padding: 16px 0 0 0;
+  border-top: 1px solid var(--fb-gray-30);
+  margin-top: 8px;
+}
+.advancedSettings .controlGroup label {
+  font-weight: 400;
+  color: var(--fb-gray-70);
+}
diff --git a/ai/ai-react-app/src/components/Layout/RightSidebar.tsx b/ai/ai-react-app/src/components/Layout/RightSidebar.tsx
new file mode 100644
index 000000000..9c296c9b6
--- /dev/null
+++ b/ai/ai-react-app/src/components/Layout/RightSidebar.tsx
@@ -0,0 +1,472 @@
+import React from "react";
+import { AppMode } from "../../App";
+import styles from "./RightSidebar.module.css";
+import {
+  AVAILABLE_GENERATIVE_MODELS,
+  AVAILABLE_IMAGEN_MODELS,
+  defaultFunctionCallingTool,
+} from "../../services/firebaseAIService";
+import {
+  ModelParams,
+  ImagenModelParams,
+  HarmCategory,
+  HarmBlockThreshold,
+  FunctionCallingMode,
+  ImagenSafetyFilterLevel,
+  ImagenPersonFilterLevel,
+  UsageMetadata,
+} from "firebase/ai";
+
+interface RightSidebarProps {
+  usageMetadata: UsageMetadata | null;
+  activeMode: AppMode;
+  generativeParams: ModelParams;
+  setGenerativeParams: React.Dispatch<React.SetStateAction<ModelParams>>;
+  imagenParams: ImagenModelParams;
+  setImagenParams: React.Dispatch<React.SetStateAction<ImagenModelParams>>;
+}
+
+const RightSidebar: React.FC<RightSidebarProps> = ({
+  usageMetadata,
+  activeMode,
+  generativeParams,
+  setGenerativeParams,
+  imagenParams,
+  setImagenParams,
+}) => {
+  const handleModelParamsUpdate = (
+    updateFn: (prevState: ModelParams) => ModelParams,
+  ) => {
+    setGenerativeParams((prevState) => updateFn(prevState));
+  };
+
+  const handleImagenModelParamsUpdate = (
+    updateFn: (prevState: ImagenModelParams) => ImagenModelParams,
+  ) => {
+    setImagenParams((prevState) => updateFn(prevState));
+  };
+
+  const getThresholdForCategory = (
+    category: HarmCategory,
+  ): HarmBlockThreshold => {
+    const setting = (generativeParams.safetySettings || []).find(
+      (s) => s.category === category,
+    );
+    return setting?.threshold || HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE;
+  };
+
+  const handleGenerativeModelChange = (
+    event: React.ChangeEvent<HTMLSelectElement>,
+  ) => {
+    const newModel = event.target.value;
+    handleModelParamsUpdate((prev: ModelParams) => ({
+      ...prev,
+      model: newModel,
+    }));
+  };
+
+  const handleTemperatureChange = (
+    event: React.ChangeEvent<HTMLInputElement>,
+  ) => {
+    const newTemp = parseFloat(event.target.value);
+    handleModelParamsUpdate((prev: ModelParams) => ({
+      ...prev,
+      generationConfig: { ...prev.generationConfig, temperature: newTemp },
+    }));
+  };
+
+  const handleTopPChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+    const newTopP = parseFloat(event.target.value);
+    handleModelParamsUpdate((prev: ModelParams) => ({
+      ...prev,
+      generationConfig: { ...prev.generationConfig, topP: newTopP },
+    }));
+  };
+
+  const handleTopKChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+    const newTopK = parseInt(event.target.value, 10);
+    handleModelParamsUpdate((prev: ModelParams) => ({
+      ...prev,
+      generationConfig: { ...prev.generationConfig, topK: newTopK },
+    }));
+  };
+
+  const handleSafetySettingChange = (
+    category: HarmCategory,
+    threshold: HarmBlockThreshold,
+  ) => {
+    handleModelParamsUpdate((prev: ModelParams) => {
+      const currentSettings = prev.safetySettings || [];
+      let settingExists = false;
+      const newSettings = currentSettings.map((s) => {
+        if (s.category === category) {
+          settingExists = true;
+          return { ...s, threshold };
+        }
+        return s;
+      });
+      if (!settingExists) {
+        newSettings.push({ category, threshold });
+      }
+      return { ...prev, safetySettings: newSettings };
+    });
+  };
+
+  const handleToggleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+    const { name, checked } = event.target;
+    console.log(`[RightSidebar] Toggle change: ${name}, Checked: ${checked}`);
+
+    handleModelParamsUpdate((prev: ModelParams): ModelParams => {
+      // Clone the previous state to avoid direct mutation
+      const nextState = JSON.parse(JSON.stringify(prev));
+
+      // Ensure nested objects exist before modifying
+      nextState.generationConfig = nextState.generationConfig ?? {};
+      nextState.toolConfig = nextState.toolConfig ?? {};
+
+      if (name === "structured-output-toggle") {
+        if (checked) {
+          // Turn ON JSON
+          nextState.generationConfig.responseMimeType = "application/json";
+          nextState.generationConfig.responseSchema = undefined; // Use a default schema
+
+          // Turn OFF Function Calling by clearing its related fields
+          nextState.tools = undefined;
+          nextState.toolConfig = undefined;
+        } else {
+          // Turn OFF JSON
+          nextState.generationConfig.responseMimeType = undefined;
+          nextState.generationConfig.responseSchema = undefined;
+        }
+      } else if (name === "function-call-toggle") {
+        if (checked) {
+          // Turn ON Function Calling
+          // Use default tools if none were previously defined, otherwise keep existing
+          nextState.tools =
+            prev.tools && prev.tools.length > 0
+              ? prev.tools
+              : [defaultFunctionCallingTool];
+          nextState.toolConfig = {
+            functionCallingConfig: { mode: FunctionCallingMode.AUTO },
+          };
+
+          // Turn OFF JSON mode by clearing its related fields
+          nextState.generationConfig.responseMimeType = undefined;
+          nextState.generationConfig.responseSchema = undefined;
+        } else {
+          // Turn OFF Function Calling
+          nextState.tools = undefined;
+          nextState.toolConfig = undefined; // Clear config when turning off
+        }
+      }
+      console.log("[RightSidebar] Updated generative params state:", nextState);
+      return nextState;
+    });
+  };
+
+  const handleImagenModelChange = (
+    event: React.ChangeEvent<HTMLSelectElement>,
+  ) => {
+    const newModel = event.target.value;
+    handleImagenModelParamsUpdate((prev: ImagenModelParams) => ({
+      ...prev,
+      model: newModel,
+    }));
+  };
+  const handleImagenSamplesChange = (
+    event: React.ChangeEvent<HTMLInputElement>,
+  ) => {
+    const newCount = parseInt(event.target.value, 10);
+    handleImagenModelParamsUpdate((prev: ImagenModelParams) => ({
+      ...prev,
+      generationConfig: { ...prev.generationConfig, numberOfImages: newCount },
+    }));
+  };
+  const handleImagenNegativePromptChange = (
+    event: React.ChangeEvent<HTMLTextAreaElement>,
+  ) => {
+    const newPrompt = event.target.value || undefined;
+    handleImagenModelParamsUpdate((prev: ImagenModelParams) => ({
+      ...prev,
+      generationConfig: { ...prev.generationConfig, negativePrompt: newPrompt },
+    }));
+  };
+  const handleImagenSafetyChange = (
+    event: React.ChangeEvent<HTMLSelectElement>,
+  ) => {
+    const newLevel = event.target.value as ImagenSafetyFilterLevel;
+    handleImagenModelParamsUpdate((prev: ImagenModelParams) => ({
+      ...prev,
+      safetySettings: { ...prev.safetySettings, safetyFilterLevel: newLevel },
+    }));
+  };
+  const handleImagenPersonChange = (
+    event: React.ChangeEvent<HTMLSelectElement>,
+  ) => {
+    const newLevel = event.target.value as ImagenPersonFilterLevel;
+    handleImagenModelParamsUpdate((prev: ImagenModelParams) => ({
+      ...prev,
+      safetySettings: { ...prev.safetySettings, personFilterLevel: newLevel },
+    }));
+  };
+
+  // Derive UI state from config
+  const isStructuredOutputActive =
+    generativeParams.generationConfig?.responseMimeType === "application/json";
+  const isFunctionCallingActive =
+    (generativeParams.toolConfig?.functionCallingConfig?.mode ===
+      FunctionCallingMode.AUTO ||
+      generativeParams.toolConfig?.functionCallingConfig?.mode ===
+        FunctionCallingMode.ANY) &&
+    !!generativeParams.tools?.length;
+
+  return (
+    <div className={styles.rightSidebarContainer}>
+      {/* Generative Model Settings */}
+      {activeMode === "chat" && (
+        <>
+          <div>
+            <h5 className={styles.subSectionTitle}>
+              Generative Model Settings
+            </h5>
+            <div className={styles.controlGroup}>
+              <label htmlFor="model-select">Model</label>
+              <select
+                id="model-select"
+                value={generativeParams.model}
+                onChange={handleGenerativeModelChange}
+              >
+                {AVAILABLE_GENERATIVE_MODELS.map((modelName) => (
+                  <option key={modelName} value={modelName}>
+                    {modelName}
+                  </option>
+                ))}
+              </select>
+            </div>
+            <div className={styles.controlGroup}>
+              <label htmlFor="temperature-slider">
+                Temperature:{" "}
+                {generativeParams.generationConfig?.temperature?.toFixed(1) ??
+                  "N/A"}
+              </label>
+              <input
+                type="range"
+                id="temperature-slider"
+                min="0"
+                max="2"
+                step="0.1"
+                value={generativeParams.generationConfig?.temperature ?? 0.9}
+                onChange={handleTemperatureChange}
+              />
+            </div>
+            <div className={styles.controlGroup}>
+              <label>Last Response Tokens</label>
+              <div className={styles.tokenDisplay}>
+                {usageMetadata
+                  ? `Prompt: ${usageMetadata.promptTokenCount} / Candidate: ${usageMetadata.candidatesTokenCount} / Total: ${usageMetadata.totalTokenCount}`
+                  : `N/A`}
+              </div>
+            </div>
+          </div>
+
+          <div>
+            <h5
+              className={styles.subSectionTitle}
+              style={{ marginTop: "20px" }}
+            >
+              Advanced Generation
+            </h5>
+            <div className={styles.controlGroup}>
+              <label htmlFor="topP-slider">
+                Top P:{" "}
+                {generativeParams.generationConfig?.topP?.toFixed(2) ??
+                  "N/A (Default)"}
+              </label>
+              <input
+                type="range"
+                id="topP-slider"
+                min="0"
+                max="1"
+                step="0.01"
+                value={generativeParams.generationConfig?.topP ?? 0.95}
+                onChange={handleTopPChange}
+              />
+            </div>
+            <div className={styles.controlGroup}>
+              <label htmlFor="topK-slider">
+                Top K:{" "}
+                {generativeParams.generationConfig?.topK ?? "N/A (Default)"}
+              </label>
+              <input
+                type="range"
+                id="topK-slider"
+                min="1"
+                max="100"
+                step="1"
+                value={generativeParams.generationConfig?.topK ?? 40}
+                onChange={handleTopKChange}
+              />
+            </div>
+          </div>
+
+          <div>
+            <h5
+              className={styles.subSectionTitle}
+              style={{ marginTop: "20px" }}
+            >
+              Safety Settings
+            </h5>
+            {Object.values(HarmCategory).map((category) => (
+              <div className={styles.controlGroup} key={category}>
+                <label htmlFor={`safety-${category}`}>
+                  {category
+                    .replace("HARM_CATEGORY_", "")
+                    .replace(/_/g, " ")
+                    .toLowerCase()
+                    .replace(/\b\w/g, (l) => l.toUpperCase())}
+                </label>
+                <select
+                  id={`safety-${category}`}
+                  value={getThresholdForCategory(category)}
+                  onChange={(e) =>
+                    handleSafetySettingChange(
+                      category,
+                      e.target.value as HarmBlockThreshold,
+                    )
+                  }
+                >
+                  {Object.values(HarmBlockThreshold).map((threshold) => (
+                    <option key={threshold} value={threshold}>
+                      {threshold.replace("BLOCK_", "").replace(/_/g, " ")}
+                    </option>
+                  ))}
+                </select>
+              </div>
+            ))}
+          </div>
+
+          <div>
+            <h5 className={styles.subSectionTitle}>Tools</h5>
+            <div
+              className={`${styles.toggleGroup} ${isFunctionCallingActive ? styles.disabledText : ""}`}
+            >
+              <label htmlFor="structured-output-toggle">
+                Structured output (JSON)
+              </label>
+              <label className={styles.switch}>
+                <input
+                  type="checkbox"
+                  id="structured-output-toggle"
+                  name="structured-output-toggle"
+                  checked={isStructuredOutputActive}
+                  onChange={handleToggleChange}
+                  disabled={isFunctionCallingActive}
+                />
+                <span
+                  className={`${styles.slider} ${isFunctionCallingActive ? styles.disabled : ""}`}
+                ></span>
+              </label>
+            </div>
+            <div
+              className={`${styles.toggleGroup} ${isStructuredOutputActive ? styles.disabledText : ""}`}
+            >
+              <label htmlFor="function-call-toggle">Function calling</label>
+              <label className={styles.switch}>
+                <input
+                  type="checkbox"
+                  id="function-call-toggle"
+                  name="function-call-toggle"
+                  checked={isFunctionCallingActive}
+                  onChange={handleToggleChange}
+                  disabled={isStructuredOutputActive}
+                />
+                <span
+                  className={`${styles.slider} ${isStructuredOutputActive ? styles.disabled : ""}`}
+                ></span>
+              </label>
+            </div>
+          </div>
+        </>
+      )}
+
+      {/* Imagen Settings */}
+      {activeMode === "imagenGen" && (
+        <div>
+          <h5 className={styles.subSectionTitle}>Imagen Settings</h5>
+          <div className={styles.controlGroup}>
+            <label htmlFor="imagen-model-select">Model</label>
+            <select
+              id="imagen-model-select"
+              value={imagenParams.model}
+              onChange={handleImagenModelChange}
+            >
+              {AVAILABLE_IMAGEN_MODELS.map((modelName) => (
+                <option key={modelName} value={modelName}>
+                  {modelName}
+                </option>
+              ))}
+            </select>
+          </div>
+          <div className={styles.controlGroup}>
+            <label htmlFor="imagen-samples">Number of Images</label>
+            <input
+              type="number"
+              id="imagen-samples"
+              min="1"
+              max="4"
+              step="1"
+              value={imagenParams.generationConfig?.numberOfImages ?? 1}
+              onChange={handleImagenSamplesChange}
+            />
+          </div>
+          <div className={styles.controlGroup}>
+            <label htmlFor="imagen-negative-prompt">Negative Prompt</label>
+            <textarea
+              id="imagen-negative-prompt"
+              rows={2}
+              value={imagenParams.generationConfig?.negativePrompt || ""}
+              onChange={handleImagenNegativePromptChange}
+              className={styles.textAreaInput}
+            />
+          </div>
+          <div className={styles.controlGroup}>
+            <label htmlFor="imagen-safety-select">Safety Filter Level</label>
+            <select
+              id="imagen-safety-select"
+              value={imagenParams.safetySettings?.safetyFilterLevel || ""}
+              onChange={handleImagenSafetyChange}
+            >
+              <option value="" disabled>
+                Select Level
+              </option>
+              {Object.values(ImagenSafetyFilterLevel).map((level) => (
+                <option key={level} value={level}>
+                  {level.replace(/_/g, " ")}
+                </option>
+              ))}
+            </select>
+          </div>
+          <div className={styles.controlGroup}>
+            <label htmlFor="imagen-person-select">Person Filter Level</label>
+            <select
+              id="imagen-person-select"
+              value={imagenParams.safetySettings?.personFilterLevel || ""}
+              onChange={handleImagenPersonChange}
+            >
+              <option value="" disabled>
+                Select Level
+              </option>
+              {Object.values(ImagenPersonFilterLevel).map((level) => (
+                <option key={level} value={level}>
+                  {level.replace(/_/g, " ")}
+                </option>
+              ))}
+            </select>
+          </div>
+        </div>
+      )}
+    </div>
+  );
+};
+
+export default RightSidebar;
diff --git a/ai/ai-react-app/src/components/Layout/TopBar.module.css b/ai/ai-react-app/src/components/Layout/TopBar.module.css
new file mode 100644
index 000000000..ad4804e69
--- /dev/null
+++ b/ai/ai-react-app/src/components/Layout/TopBar.module.css
@@ -0,0 +1,29 @@
+.topBarContainer {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 50px;
+  padding: 0 24px;
+  background-color: var(--fb-gray-10);
+  border-bottom: 1px solid var(--fb-gray-30);
+  color: var(--fb-gray-90);
+  flex-shrink: 0;
+}
+
+.leftSection {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.logoImage {
+  height: 24px;
+  width: 24px;
+  display: block;
+}
+
+.title {
+  font-size: 1rem;
+  font-weight: 500;
+  color: var(--fb-gray-80);
+}
diff --git a/ai/ai-react-app/src/components/Layout/TopBar.tsx b/ai/ai-react-app/src/components/Layout/TopBar.tsx
new file mode 100644
index 000000000..0042488fe
--- /dev/null
+++ b/ai/ai-react-app/src/components/Layout/TopBar.tsx
@@ -0,0 +1,22 @@
+import React from "react";
+import styles from "./TopBar.module.css";
+import firebaseIcon from "../../assets/firebase-icon.png";
+
+const TopBar: React.FC = () => {
+  return (
+    <header className={styles.topBarContainer}>
+      <div className={styles.leftSection}>
+        <img
+          src={firebaseIcon}
+          alt="Firebase Logo"
+          className={styles.logoImage}
+          width="24"
+          height="24"
+        />
+        <span className={styles.title}>Firebase AI SDK Sample</span>
+      </div>
+    </header>
+  );
+};
+
+export default TopBar;
diff --git a/ai/ai-react-app/src/components/Specific/ChatMessage.module.css b/ai/ai-react-app/src/components/Specific/ChatMessage.module.css
new file mode 100644
index 000000000..6adb2ff8c
--- /dev/null
+++ b/ai/ai-react-app/src/components/Specific/ChatMessage.module.css
@@ -0,0 +1,49 @@
+.messageContainer {
+  display: flex;
+  margin-bottom: 8px;
+  max-width: 80%;
+}
+
+/* Align user messages to the right */
+.messageContainer.user {
+  justify-content: flex-end;
+  margin-left: auto;
+}
+
+/* Align model messages to the left */
+.messageContainer.model {
+  justify-content: flex-start;
+  margin-right: auto;
+}
+
+.messageBubble {
+  padding: 8px 14px;
+  border-radius: 16px;
+  word-wrap: break-word;
+  white-space: pre-wrap;
+  line-height: 1.5;
+  font-size: 0.875rem;
+  border: 1px solid transparent;
+}
+
+.messageContainer.user .messageBubble {
+  background-color: var(--fb-gray-40);
+  color: var(--fb-gray-95);
+  border-color: var(--fb-gray-50);
+  border-bottom-right-radius: 4px;
+}
+
+.messageContainer.model .messageBubble {
+  background-color: var(--fb-gray-10);
+  color: var(--fb-gray-90);
+  border-color: var(--fb-gray-30);
+  border-bottom-left-radius: 4px;
+}
+
+.messageText {
+  margin: 0;
+  font-family: inherit;
+  font-size: inherit;
+  white-space: pre-wrap;
+  word-wrap: break-word;
+}
diff --git a/ai/ai-react-app/src/components/Specific/ChatMessage.tsx b/ai/ai-react-app/src/components/Specific/ChatMessage.tsx
new file mode 100644
index 000000000..6d0f94a49
--- /dev/null
+++ b/ai/ai-react-app/src/components/Specific/ChatMessage.tsx
@@ -0,0 +1,63 @@
+import React from "react";
+import { Content } from "firebase/ai";
+import styles from "./ChatMessage.module.css";
+
+interface ChatMessageProps {
+  message: Content;
+}
+
+/**
+ * Extracts and concatenates text from all 'text' parts within a Content message.
+ * Ignores other part types like images or function calls for text extraction.
+ * @param message The Content object.
+ * @returns The combined text string, or an empty string if no text parts are found.
+ */
+const getMessageText = (message: Content): string => {
+  if (!message.parts || message.parts.length === 0) {
+    return "";
+  }
+  // Filter for parts that are TextPart (have a 'text' property) and join them.
+  return message.parts
+    .filter((part): part is { text: string } => typeof part.text === "string")
+    .map((part) => part.text)
+    .join("");
+};
+
+/**
+ * Renders a single chat message bubble, styled based on the message role ('user' or 'model').
+ * It only renders messages that should be visible in the log (user messages, or model messages
+ * containing text). Function role messages or model messages consisting only of function calls
+ * are typically not rendered directly as chat bubbles.
+ */
+const ChatMessage: React.FC<ChatMessageProps> = ({ message }) => {
+  const text = getMessageText(message);
+  const isUser = message.role === "user";
+  const isModel = message.role === "model";
+
+  // We render:
+  // 1. User messages (even if they only contain images/files, the 'user' role indicates an entry).
+  // 2. Model messages *only if* they contain actual text content.
+  // We *don't* render:
+  // 1. 'function' role messages (these represent execution results, not direct chat).
+  // 2. 'model' role messages that *only* contain function calls (these are instructions, not display text).
+  // 3. 'system' role messages (handled separately, not usually in chat history display).
+  const shouldRender = isUser || (isModel && text.trim() !== "");
+
+  if (!shouldRender) {
+    return null;
+  }
+
+  return (
+    <div
+      className={`${styles.messageContainer} ${isUser ? styles.user : styles.model}`}
+    >
+      <div className={styles.messageBubble}>
+        {/* Use <pre> to preserve whitespace and newlines within the text content.
+                     Handles potential multi-line responses correctly. */}
+        <pre className={styles.messageText}>{text}</pre>
+      </div>
+    </div>
+  );
+};
+
+export default ChatMessage;
diff --git a/ai/ai-react-app/src/config/firebase-config.ts b/ai/ai-react-app/src/config/firebase-config.ts
new file mode 100644
index 000000000..8cd3a394d
--- /dev/null
+++ b/ai/ai-react-app/src/config/firebase-config.ts
@@ -0,0 +1,9 @@
+// TODO (developer): Replace with your Firebase project configuration
+export const firebaseConfig = {
+  apiKey: "YOUR_API_KEY",
+  authDomain: "YOUR_AUTH_DOMAIN",
+  projectId: "YOUR_PROJECT_ID",
+  storageBucket: "YOUR_STORAGE_BUCKET",
+  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
+  appId: "YOUR_APP_ID",
+};
\ No newline at end of file
diff --git a/ai/ai-react-app/src/index.css b/ai/ai-react-app/src/index.css
new file mode 100644
index 000000000..051b3a985
--- /dev/null
+++ b/ai/ai-react-app/src/index.css
@@ -0,0 +1,87 @@
+:root {
+  --fb-gray-0: #000000;
+  --fb-gray-10: #121212;
+  --fb-gray-20: #303030;
+  --fb-gray-30: #474747;
+  --fb-gray-40: #5e5e5e;
+  --fb-gray-50: #757575;
+  --fb-gray-60: #8f8f8f;
+  --fb-gray-70: #ababab;
+  --fb-gray-80: #c7c7c7;
+  --fb-gray-90: #e3e3e3;
+  --fb-gray-95: #f2f2f2;
+  --fb-gray-99: #fdfcfb;
+  --fb-gray-100: #ffffff;
+
+  --fb-yellow: #ffc400;
+  --fb-orange: #ff9100;
+  --fb-red: #dd2c00;
+
+  --google-blue: #4285f4;
+  --google-blue-darker: #1b66c9;
+  --google-blue-focus: #8ab4f8;
+
+  --fb-error-bg: rgba(221, 44, 0, 0.1);
+  --fb-error-text: #f79489;
+  --fb-error-border: rgba(221, 44, 0, 0.4);
+
+  --fb-warning-bg: rgba(255, 145, 0, 0.1);
+  --fb-warning-text: #ffcc80;
+  --fb-warning-border: rgba(255, 145, 0, 0.4);
+}
+
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+}
+
+html,
+body {
+  margin: 0;
+  padding: 0;
+  height: 100%;
+}
+
+body {
+  background-color: var(--fb-gray-10);
+  color: var(--fb-gray-90);
+  font-family:
+    "Roboto",
+    -apple-system,
+    BlinkMacSystemFont,
+    "Segoe UI",
+    Oxygen,
+    "Ubuntu",
+    Cantarell,
+    "Fira Sans",
+    "Droid Sans",
+    "Helvetica Neue",
+    sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  overflow: hidden;
+  font-weight: 500;
+  font-size: 14px;
+}
+
+#root {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+*:focus-visible {
+  outline: 2px solid var(--google-blue-focus);
+  outline-offset: 1px;
+}
+
+button,
+input,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  font-weight: inherit;
+  color: inherit;
+}
diff --git a/ai/ai-react-app/src/main.tsx b/ai/ai-react-app/src/main.tsx
new file mode 100644
index 000000000..ee5628fd9
--- /dev/null
+++ b/ai/ai-react-app/src/main.tsx
@@ -0,0 +1,15 @@
+import { createRoot } from "react-dom/client";
+import "./index.css";
+import App from "./App";
+
+const rootElement = document.getElementById("root");
+
+if (!rootElement) {
+  throw new Error(
+    "Failed to find the root element. Make sure your HTML file has an element with id='root'.",
+  );
+}
+
+const root = createRoot(rootElement);
+
+root.render(<App />);
diff --git a/ai/ai-react-app/src/services/firebaseAIService.ts b/ai/ai-react-app/src/services/firebaseAIService.ts
new file mode 100644
index 000000000..6ff24c7f7
--- /dev/null
+++ b/ai/ai-react-app/src/services/firebaseAIService.ts
@@ -0,0 +1,160 @@
+import { initializeApp, FirebaseApp } from "firebase/app";
+import {
+  HarmCategory,
+  HarmBlockThreshold,
+  Schema,
+  FunctionDeclaration,
+  Part,
+  Content,
+  CountTokensResponse,
+  GenerativeModel,
+  ModelParams,
+  ImagenModelParams,
+  FunctionCall,
+} from "firebase/ai";
+
+import { firebaseConfig } from "../config/firebase-config";
+
+export const AVAILABLE_GENERATIVE_MODELS = [
+  "gemini-2.0-flash",
+  "gemini-2.0-flash-lite",
+  "gemini-2.0-flash-exp",
+];
+export const AVAILABLE_IMAGEN_MODELS = ["imagen-3.0-generate-002"];
+
+let app: FirebaseApp;
+try {
+  if (firebaseConfig.apiKey === "YOUR_API_KEY" || !firebaseConfig.projectId) {
+    console.error(
+      "Firebase config uses placeholder values. Update src/config/firebase-config.ts.",
+    );
+  }
+  app = initializeApp(firebaseConfig);
+  console.log("Firebase App Initialized.");
+} catch (error) {
+  console.error("Error initializing Firebase App:", error);
+  throw new Error("Firebase initialization failed.");
+}
+
+export const defaultFunctionCallingTool = {
+  functionDeclarations: [
+    {
+      name: "getCurrentWeather",
+      description: "Get the current weather in a given location",
+      parameters: Schema.object({
+        properties: {
+          location: Schema.string({
+            description: "The city and state, e.g. San Francisco, CA",
+          }),
+          unit: Schema.enumString({
+            enum: ["celsius", "fahrenheit"],
+            description: "Temperature unit",
+          }),
+        },
+        required: ["location"],
+      }),
+    } as FunctionDeclaration,
+  ],
+};
+
+export const defaultGenerativeParams: Omit<ModelParams, "model"> = {
+  // Model name itself is selected in the UI
+  generationConfig: {
+    temperature: 0.9,
+  },
+  safetySettings: [
+    {
+      category: HarmCategory.HARM_CATEGORY_HARASSMENT,
+      threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
+    },
+    {
+      category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
+      threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
+    },
+    {
+      category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
+      threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
+    },
+    {
+      category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
+      threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
+    },
+  ],
+  // tools, toolConfig, systemInstruction default to undefined
+};
+
+export const defaultImagenParams: Omit<ImagenModelParams, "model"> = {
+  // Model name selected in UI
+  generationConfig: {
+    numberOfImages: 1,
+  },
+  // Default all safety settings to undefined
+};
+
+/**
+ * Mock function call
+ */
+export const handleFunctionExecution = async (
+  functionCall: FunctionCall,
+): Promise<object> => {
+  console.log(
+    `[Service] Executing function: ${functionCall.name}, Args:`,
+    functionCall.args,
+  );
+  if (functionCall.name === "getCurrentWeather") {
+    await new Promise((resolve) => setTimeout(resolve, 800)); // Simulate delay
+    const location: string =
+      "location" in functionCall.args &&
+        typeof functionCall.args.location === "string"
+        ? functionCall.args.location
+        : "Default City, ST";
+    const unit: string =
+      "unit" in functionCall.args && typeof functionCall.args.unit === "string"
+        ? functionCall.args.unit
+        : "celsius";
+    const temp =
+      unit === "celsius"
+        ? Math.floor(Math.random() * 30 + 5)
+        : Math.floor(Math.random() * 50 + 40);
+    const conditions = ["Sunny", "Partly Cloudy", "Cloudy", "Rainy"];
+    const condition = conditions[Math.floor(Math.random() * conditions.length)];
+    return {
+      weather: { location, temperature: temp, unit, condition },
+    };
+  }
+  console.warn(`[Service] Unknown function called: ${name}`);
+  return { error: `Function ${name} not implemented.` };
+};
+
+export const countTokensInPrompt = async (
+  modelInstance: GenerativeModel,
+  parts: Part[],
+  history: Content[] = [],
+  params?: {
+    systemInstruction?: ModelParams["systemInstruction"];
+    tools?: ModelParams["tools"];
+  },
+): Promise<CountTokensResponse> => {
+  const contents: Content[] = [...history];
+  if (parts.length > 0) {
+    contents.push({ role: "user", parts });
+  }
+
+  const request = {
+    contents,
+    systemInstruction: params?.systemInstruction,
+    tools: params?.tools,
+  };
+
+  console.log("[Service] Counting tokens for request:", request);
+  try {
+    const result = await modelInstance.countTokens(request);
+    console.log("[Service] Token count result:", result);
+    return result;
+  } catch (error) {
+    console.error("[Service] Error counting tokens:", error);
+    throw error;
+  }
+};
+
+export { app };
diff --git a/ai/ai-react-app/src/utils/fileUtils.ts b/ai/ai-react-app/src/utils/fileUtils.ts
new file mode 100644
index 000000000..3493eaa58
--- /dev/null
+++ b/ai/ai-react-app/src/utils/fileUtils.ts
@@ -0,0 +1,49 @@
+import { Part } from "firebase/ai";
+
+/**
+ * Converts a File object into a Firebase AI SDK Part object suitable for multimodal requests.
+ * Reads the file as a base64-encoded string and includes its MIME type.
+ *
+ * @param file The File object (e.g., from an <input type="file"> element).
+ * @returns A Promise resolving to a Part object containing inline base64 data and MIME type.
+ * @throws An error if the file cannot be read or processed.
+ */
+export async function fileToGenerativePart(file: File): Promise<Part> {
+  const base64EncodedDataPromise = new Promise<string>((resolve, reject) => {
+    const reader = new FileReader();
+    reader.onloadend = () => {
+      // The FileReader result includes the Data URL prefix (e.g., "data:image/jpeg;base64,").
+      // We only need the actual base64 data part after the comma.
+      const base64String = reader.result as string;
+      if (base64String && base64String.includes(",")) {
+        resolve(base64String.split(",")[1]);
+      } else {
+        reject(new Error("Invalid file data format received from FileReader."));
+      }
+    };
+    reader.onerror = (errorEvent) => {
+      reject(
+        new Error(
+          `FileReader error: ${errorEvent?.target?.error?.message || "Unknown error"}`,
+        ),
+      );
+    };
+    // Start reading the file
+    reader.readAsDataURL(file);
+  });
+
+  try {
+    const base64EncodedData = await base64EncodedDataPromise;
+    return {
+      inlineData: {
+        data: base64EncodedData,
+        mimeType: file.type,
+      },
+    };
+  } catch (error) {
+    console.error("Error converting file to Generative Part:", error);
+    throw new Error(
+      `Failed to process the file "${file.name}". Please ensure it's a valid file.`,
+    );
+  }
+}
diff --git a/ai/ai-react-app/src/views/ChatView.module.css b/ai/ai-react-app/src/views/ChatView.module.css
new file mode 100644
index 000000000..b14f84165
--- /dev/null
+++ b/ai/ai-react-app/src/views/ChatView.module.css
@@ -0,0 +1,132 @@
+.chatViewContainer {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  background-color: var(--fb-gray-10);
+}
+
+.chatHistory {
+  flex-grow: 1;
+  overflow-y: auto;
+  padding: 16px 24px;
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+}
+
+.emptyChat {
+  text-align: center;
+  color: var(--fb-gray-60);
+  margin-top: 40px;
+  font-style: italic;
+}
+
+.loadingBubble {
+  display: flex;
+  justify-content: flex-start;
+  margin-right: auto;
+  margin-bottom: 8px;
+  padding: 8px 14px;
+  border-radius: 16px;
+  border-bottom-left-radius: 4px;
+  background-color: var(--fb-gray-10);
+  border: 1px solid var(--fb-gray-30);
+  align-items: center;
+  min-height: 1em;
+}
+.loadingBubble span {
+  display: inline-block;
+  width: 6px;
+  height: 6px;
+  background-color: var(--fb-gray-60);
+  border-radius: 50%;
+  margin: 0 2px;
+  animation: bounce 1.4s infinite ease-in-out both;
+}
+.loadingBubble span:nth-child(1) {
+  animation-delay: -0.32s;
+}
+.loadingBubble span:nth-child(2) {
+  animation-delay: -0.16s;
+}
+.loadingBubble span:nth-child(3) {
+  animation-delay: 0s;
+}
+@keyframes bounce {
+  0%,
+  80%,
+  100% {
+    transform: scale(0);
+    opacity: 0.5;
+  }
+  40% {
+    transform: scale(0.8);
+    opacity: 1;
+  }
+}
+
+.errorMessage {
+  background-color: var(--fb-error-bg);
+  color: var(--fb-error-text);
+  border: 1px solid var(--fb-error-border);
+  padding: 10px 16px;
+  border-radius: 4px;
+  margin: 10px 0;
+  font-size: 0.875rem;
+  white-space: pre-wrap;
+}
+
+.jsonDetails {
+  margin-top: 4px;
+  margin-bottom: 8px;
+  border: 1px solid var(--fb-gray-40);
+  border-radius: 4px;
+  background-color: var(--fb-gray-10);
+  max-width: 80%;
+  margin-left: 0;
+  margin-right: auto;
+}
+.jsonSummary {
+  padding: 6px 12px;
+  cursor: pointer;
+  background-color: var(--fb-gray-10);
+  border-bottom: 1px solid var(--fb-gray-40);
+  outline: none;
+  font-size: 0.8125rem;
+  color: var(--fb-gray-80);
+  font-weight: 500;
+  list-style: none;
+}
+.jsonSummary::-webkit-details-marker {
+  display: none;
+}
+.jsonSummary:hover {
+  background-color: var(--fb-gray-30);
+}
+.jsonDetails pre {
+  padding: 12px 16px;
+  margin: 0;
+  font-family: "Roboto Mono", monospace;
+  font-size: 0.8125rem;
+  color: var(--fb-gray-90);
+  white-space: pre-wrap;
+  word-wrap: break-word;
+  background-color: var(--fb-gray-10);
+  border-radius: 0 0 4px 4px;
+  max-height: 300px;
+  overflow: auto;
+}
+
+.inputAreaContainer {
+  flex-shrink: 0;
+  background-color: var(--fb-gray-10);
+  border-top: 1px solid var(--fb-gray-30);
+  padding: 16px 24px;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.fileUploaderContainer {
+  max-width: 250px;
+}
diff --git a/ai/ai-react-app/src/views/ChatView.tsx b/ai/ai-react-app/src/views/ChatView.tsx
new file mode 100644
index 000000000..01db1cbb0
--- /dev/null
+++ b/ai/ai-react-app/src/views/ChatView.tsx
@@ -0,0 +1,531 @@
+import React, { useState, useEffect, useRef, useCallback } from "react";
+import { handleFunctionExecution } from "../services/firebaseAIService";
+import {
+  getGenerativeModel,
+  Content,
+  Part,
+  UsageMetadata,
+  FunctionResponsePart,
+  ChatSession,
+  GenerateContentCandidate,
+  ModelParams,
+  FunctionCall,
+  AIError,
+  AI,
+} from "firebase/ai";
+import PromptInput from "../components/Common/PromptInput";
+import ChatMessage from "../components/Specific/ChatMessage";
+import FileUploader from "../components/Common/FileUploader";
+import { fileToGenerativePart } from "../utils/fileUtils";
+import styles from "./ChatView.module.css";
+import { AppMode } from "../App";
+
+interface ChatViewProps {
+  aiInstance: AI;
+  onUsageMetadataChange: (metadata: UsageMetadata | null) => void;
+  currentParams: ModelParams;
+  activeMode: AppMode;
+}
+
+const modelParamsChanged = (
+  newParams: ModelParams,
+  oldParams: ModelParams | null,
+): boolean => {
+  if (!oldParams) return true; // No old params means change
+
+  // Compare critical fields that define a session's core behavior
+  if (newParams.model !== oldParams.model) return true;
+  if (
+    JSON.stringify(newParams.systemInstruction) !==
+    JSON.stringify(oldParams.systemInstruction)
+  )
+    return true;
+  if (JSON.stringify(newParams.tools) !== JSON.stringify(oldParams.tools))
+    return true;
+  if (
+    JSON.stringify(newParams.toolConfig) !==
+    JSON.stringify(oldParams.toolConfig)
+  )
+    return true;
+  if (
+    JSON.stringify(newParams.generationConfig) !==
+    JSON.stringify(oldParams.generationConfig)
+  )
+    return true;
+  if (
+    JSON.stringify(newParams.safetySettings) !==
+    JSON.stringify(oldParams.safetySettings)
+  )
+    return true;
+
+  return false; // If none of the above changed, params are not significantly different
+};
+
+const ChatView: React.FC<ChatViewProps> = ({
+  onUsageMetadataChange,
+  currentParams,
+  aiInstance,
+  activeMode,
+}) => {
+  const [chatHistory, setChatHistory] = useState<Content[]>([]);
+  const [currentInput, setCurrentInput] = useState("");
+  const [selectedFile, setSelectedFile] = useState<File | null>(null);
+  const [isLoading, setIsLoading] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [lastResponseParsedJson, setLastResponseParsedJson] = useState<
+    object | null
+  >(null);
+
+  const chatContainerRef = useRef<HTMLDivElement>(null);
+  const chatSessionRef = useRef<ChatSession | null>(null);
+  const sessionParamsRef = useRef<ModelParams | null>(null);
+
+  const initializeChatSession = useCallback(
+    (params: ModelParams) => {
+      try {
+        console.log(
+          "[ChatView] Initializing new chat session with params:",
+          params,
+        );
+        const model = getGenerativeModel(aiInstance, params);
+        const newSession = model.startChat({
+          history: [],
+          safetySettings: params.safetySettings,
+          generationConfig: params.generationConfig,
+          tools: params.tools,
+          toolConfig: params.toolConfig,
+          systemInstruction: params.systemInstruction,
+        });
+        chatSessionRef.current = newSession;
+        // Store a deep copy of the params used for this session
+        sessionParamsRef.current = JSON.parse(JSON.stringify(params));
+        setChatHistory([]);
+        setError(null);
+        onUsageMetadataChange(null);
+        console.log("[ChatView] New chat session initialized successfully.");
+      } catch (initError: unknown) {
+        console.error("[ChatView] Error initializing chat session:", initError);
+        setError(`Failed to initialize chat session`);
+        chatSessionRef.current = null;
+        sessionParamsRef.current = null;
+      }
+    },
+    [onUsageMetadataChange, aiInstance],
+  );
+
+  useEffect(() => {
+    if (aiInstance) {
+      initializeChatSession(currentParams);
+    }
+  }, [aiInstance, initializeChatSession, currentParams]);
+
+  // Effect to scroll chat history
+  useEffect(() => {
+    if (chatContainerRef.current) {
+      chatContainerRef.current.scrollTop =
+        chatContainerRef.current.scrollHeight;
+    }
+  }, [chatHistory]);
+
+  const suggestions = [
+    "Explain the difference between `let`, `const`, and `var` in JavaScript.",
+    "Write a short story about a friendly robot.",
+    "Describe this image.",
+    "What's the weather in London in Celsius?",
+  ];
+  const handleSuggestion = (suggestion: string) => {
+    setCurrentInput(suggestion);
+  };
+
+  const processChatTurn = useCallback(
+    async (
+      partsToSend: Part[],
+      session: ChatSession,
+      expectStructuredOutput: boolean,
+    ) => {
+      console.log(
+        "[ChatView] Processing chat turn. Expect JSON:",
+        expectStructuredOutput,
+        "Parts:",
+        partsToSend,
+      );
+      setChatHistory((prev) => [...prev, { role: "model", parts: [] }]); // Add model placeholder
+      let accumulatedParts: Part[] = [];
+      let finalModelCandidate: GenerateContentCandidate | undefined;
+
+      try {
+        const streamResult = await session.sendMessageStream(partsToSend);
+        for await (const chunk of streamResult.stream) {
+          if (chunk.candidates?.[0]?.content?.parts) {
+            accumulatedParts = [
+              ...accumulatedParts,
+              ...chunk.candidates[0].content.parts,
+            ];
+            setChatHistory((prev) => {
+              const newHistory = [...prev];
+              if (
+                newHistory.length > 0 &&
+                newHistory[newHistory.length - 1].role === "model"
+              ) {
+                newHistory[newHistory.length - 1].parts = accumulatedParts;
+              }
+              return newHistory;
+            });
+            if (chunk.usageMetadata) onUsageMetadataChange(chunk.usageMetadata);
+          }
+        }
+
+        const finalResponse = await streamResult.response;
+        const finalResponseText = finalResponse.text
+          ? finalResponse.text()
+          : "";
+        finalModelCandidate = finalResponse.candidates?.[0];
+
+        if (!finalModelCandidate) {
+          console.warn("[ChatView] No candidate in final response.");
+          setError("Model did not return a valid response.");
+          setChatHistory((prev) => prev.slice(0, -1)); // Remove model placeholder
+          setIsLoading(false);
+          return;
+        }
+
+        // Update history definitively
+        setChatHistory((prev) => {
+          const newHistory = [...prev];
+          if (
+            newHistory.length > 0 &&
+            newHistory[newHistory.length - 1].role === "model"
+          ) {
+            newHistory[newHistory.length - 1].parts =
+              finalModelCandidate?.content?.parts ?? [];
+          }
+          return newHistory;
+        });
+
+        const functionCalls = finalModelCandidate.content?.parts
+          .filter((part) => !!part.functionCall)
+          .map((part) => part.functionCall as FunctionCall);
+
+        if (functionCalls && functionCalls.length > 0) {
+          console.log("[ChatView] Function call(s) requested:", functionCalls);
+          setLastResponseParsedJson(null); // Clear JSON display
+
+          const functionResponses: FunctionResponsePart[] = [];
+          for (const call of functionCalls) {
+            if (!call) continue;
+            try {
+              const apiResult = await handleFunctionExecution(call);
+              functionResponses.push({
+                functionResponse: { name: call.name, response: apiResult },
+              });
+            } catch (execError: unknown) {
+              console.error(
+                `[ChatView] Error executing function ${call.name}:`,
+                execError,
+              );
+              functionResponses.push({
+                functionResponse: {
+                  name: call.name,
+                  response: { error: `Execution failed` },
+                },
+              });
+              setError(`Error executing function ${call.name}.`);
+            }
+          }
+
+          setChatHistory((prev) => [
+            ...prev,
+            { role: "function", parts: functionResponses },
+          ]);
+          console.log(
+            "[ChatView] Sending function responses back:",
+            functionResponses,
+          );
+
+          // Add model placeholder for the NEXT response
+          setChatHistory((prev) => [...prev, { role: "model", parts: [] }]);
+          accumulatedParts = [];
+
+          // Send function responses and process the stream
+          const funcResponseResult =
+            await session.sendMessageStream(functionResponses);
+          for await (const chunk of funcResponseResult.stream) {
+            if (chunk.candidates?.[0]?.content?.parts) {
+              accumulatedParts = [
+                ...accumulatedParts,
+                ...chunk.candidates[0].content.parts,
+              ];
+              setChatHistory((prev) => {
+                const newHistory = [...prev];
+                if (
+                  newHistory.length > 0 &&
+                  newHistory[newHistory.length - 1].role === "model"
+                ) {
+                  newHistory[newHistory.length - 1].parts = accumulatedParts;
+                }
+                return newHistory;
+              });
+              if (chunk.usageMetadata)
+                onUsageMetadataChange(chunk.usageMetadata);
+            }
+          }
+
+          const finalFuncResponse = await funcResponseResult.response;
+          const finalFuncResponseText = finalFuncResponse.text
+            ? finalFuncResponse.text()
+            : "";
+          const finalFuncCandidate = finalFuncResponse.candidates?.[0];
+
+          setChatHistory((prev) => {
+            const newHistory = [...prev];
+            if (
+              newHistory.length > 0 &&
+              newHistory[newHistory.length - 1].role === "model"
+            ) {
+              newHistory[newHistory.length - 1].parts =
+                finalFuncCandidate?.content?.parts ?? [];
+            }
+            return newHistory;
+          });
+
+          // Check for structured output in the final response after function calls
+          if (expectStructuredOutput && finalFuncResponseText) {
+            try {
+              const parsedJson = JSON.parse(finalFuncResponseText);
+              setLastResponseParsedJson(parsedJson);
+            } catch (parseError) {
+              console.error(
+                "[ChatView] Failed to parse JSON after function call:",
+                parseError,
+              );
+              setError(
+                "Received non-JSON response when JSON was expected after function call.",
+              );
+              setLastResponseParsedJson({
+                error: "Failed to parse final response as JSON",
+                rawText: finalFuncResponseText,
+              });
+            }
+          } else {
+            setLastResponseParsedJson(null);
+          }
+        } else {
+          if (expectStructuredOutput && finalResponseText) {
+            try {
+              const parsedJson = JSON.parse(finalResponseText);
+              setLastResponseParsedJson(parsedJson);
+            } catch (parseError) {
+              console.error(
+                "[ChatView] Failed to parse JSON response:",
+                parseError,
+              );
+              setError("Received non-JSON response when JSON was expected.");
+              setLastResponseParsedJson({
+                error: "Failed to parse response as JSON",
+                rawText: finalResponseText,
+              });
+            }
+          } else {
+            setLastResponseParsedJson(null);
+          }
+        }
+      } catch (err: unknown) {
+        console.error("[ChatView] Error during chat turn processing:", err);
+        // Check if it's an AIError and potentially handle specific codes
+        if (err instanceof AIError) {
+          setError(`AI Error (${err.code}): ${err.message}`);
+        } else {
+          setError(`Error`);
+        }
+        // Attempt to remove model placeholder if it was the last thing added on error
+        setChatHistory((prev) => {
+          if (
+            prev.length > 0 &&
+            prev[prev.length - 1].role === "model" &&
+            prev[prev.length - 1].parts.length === 0
+          ) {
+            return prev.slice(0, -1);
+          }
+          return prev;
+        });
+        onUsageMetadataChange(null);
+      } finally {
+        setIsLoading(false);
+      }
+    },
+    [onUsageMetadataChange],
+  );
+
+  const handleChatSubmit = useCallback(async () => {
+    if (isLoading || (!currentInput.trim() && !selectedFile)) {
+      return;
+    }
+
+    setIsLoading(true);
+    setError(null);
+    setLastResponseParsedJson(null);
+    onUsageMetadataChange(null);
+
+    const userMessageParts: Part[] = [];
+    if (currentInput.trim())
+      userMessageParts.push({ text: currentInput.trim() });
+    if (selectedFile) {
+      try {
+        userMessageParts.push(await fileToGenerativePart(selectedFile));
+      } catch (imgErr: unknown) {
+        if (imgErr instanceof Error) {
+          setError(`Failed to process file: ${imgErr.message}`);
+        } else {
+          setError(`Failed to process file`);
+        }
+        setIsLoading(false);
+        setSelectedFile(null);
+        return;
+      }
+    }
+    if (userMessageParts.length === 0) {
+      setIsLoading(false);
+      return;
+    }
+
+    const needsNewSession = modelParamsChanged(
+      currentParams,
+      sessionParamsRef.current,
+    );
+    let sessionToUse: ChatSession;
+
+    const currentHistoryForSession = [...chatHistory];
+
+    if (needsNewSession) {
+      try {
+        console.log(
+          "[ChatView] Significant parameters changed or no session exists. Initializing new session *with existing history*.",
+        );
+        const model = getGenerativeModel(aiInstance, currentParams);
+        sessionToUse = model.startChat({
+          history: currentHistoryForSession,
+          safetySettings: currentParams.safetySettings,
+          generationConfig: currentParams.generationConfig,
+          tools: currentParams.tools,
+          toolConfig: currentParams.toolConfig,
+          systemInstruction: currentParams.systemInstruction,
+        });
+        chatSessionRef.current = sessionToUse;
+        sessionParamsRef.current = JSON.parse(JSON.stringify(currentParams));
+        console.log("[ChatView] New session started with preserved history.");
+      } catch (sessionError: unknown) {
+        console.error(
+          "[ChatView] Error creating new chat session:",
+          sessionError,
+        );
+        setError(`Failed to start new chat session`);
+        setIsLoading(false);
+        return;
+      }
+    } else {
+      console.log("[ChatView] Reusing existing chat session.");
+      if (!chatSessionRef.current) {
+        console.error(
+          "[ChatView] Session ref is null unexpectedly. Attempting recovery.",
+        );
+        try {
+          const model = getGenerativeModel(aiInstance, currentParams);
+          sessionToUse = model.startChat({ history: currentHistoryForSession });
+          chatSessionRef.current = sessionToUse;
+          sessionParamsRef.current = JSON.parse(JSON.stringify(currentParams));
+        } catch (err: unknown) {
+          console.error("[ChatView] Error recovering chat session:", err);
+          setError(`Failed to recover chat session`);
+          setIsLoading(false);
+          return;
+        }
+      } else {
+        sessionToUse = chatSessionRef.current;
+      }
+    }
+
+    const userMessage: Content = { role: "user", parts: userMessageParts };
+    setChatHistory((prev) => [...prev, userMessage]);
+    setCurrentInput("");
+    setSelectedFile(null);
+
+    const expectStructuredOutput =
+      currentParams.generationConfig?.responseMimeType === "application/json";
+    await processChatTurn(
+      userMessageParts,
+      sessionToUse,
+      expectStructuredOutput,
+    );
+  }, [
+    isLoading,
+    currentInput,
+    selectedFile,
+    currentParams,
+    chatHistory,
+    aiInstance,
+    processChatTurn,
+    onUsageMetadataChange,
+  ]);
+
+  return (
+    <div className={styles.chatViewContainer}>
+      {/* Chat History Area */}
+      <div className={styles.chatHistory} ref={chatContainerRef}>
+        {chatHistory.length === 0 && !isLoading && (
+          <div className={styles.emptyChat}>
+            {`Start chatting with ${currentParams.model}!`}
+          </div>
+        )}
+        {chatHistory.map((message, index) => (
+          <ChatMessage
+            key={`${message.role}-${index}-${message.parts[0]?.text?.slice(0, 10) ?? "part"}`}
+            message={message}
+          />
+        ))}
+        {isLoading && (
+          <div className={styles.loadingBubble}>
+            <span>.</span>
+            <span>.</span>
+            <span>.</span>
+          </div>
+        )}
+        {error && <div className={styles.errorMessage}>{error}</div>}
+        {lastResponseParsedJson && !isLoading && (
+          <details className={styles.jsonDetails}>
+            <summary className={styles.jsonSummary}>
+              View Last Response JSON
+            </summary>
+            <pre>{JSON.stringify(lastResponseParsedJson, null, 2)}</pre>
+          </details>
+        )}
+      </div>
+
+      {/* Input Area Wrapper */}
+      <div className={styles.inputAreaContainer}>
+        <div className={styles.fileUploaderContainer}>
+          <FileUploader
+            onFileSelect={setSelectedFile}
+            accept="image/*,video/*"
+            label="Attach File"
+            disabled={isLoading}
+          />
+        </div>
+        <PromptInput
+          prompt={currentInput}
+          onPromptChange={setCurrentInput}
+          onSubmit={handleChatSubmit}
+          isLoading={isLoading}
+          placeholder="Enter your message or attach a file..."
+          suggestions={suggestions}
+          onSuggestionClick={handleSuggestion}
+          activeMode={activeMode}
+          aiInstance={aiInstance}
+          currentParams={currentParams}
+          selectedFile={selectedFile}
+        />
+      </div>
+    </div>
+  );
+};
+
+export default ChatView;
diff --git a/ai/ai-react-app/src/views/ImagenView.module.css b/ai/ai-react-app/src/views/ImagenView.module.css
new file mode 100644
index 000000000..d6e878620
--- /dev/null
+++ b/ai/ai-react-app/src/views/ImagenView.module.css
@@ -0,0 +1,105 @@
+.imagenViewContainer {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  background-color: var(--fb-gray-10);
+}
+
+.errorMessage {
+  color: var(--fb-error-text);
+  margin: 10px 24px;
+  padding: 10px 16px;
+  background-color: var(--fb-error-bg);
+  border: 1px solid var(--fb-error-border);
+  border-radius: 4px;
+  white-space: pre-wrap;
+  font-size: 0.875rem;
+  flex-shrink: 0;
+}
+
+.displayArea {
+  flex-grow: 1;
+  overflow-y: auto;
+  padding: 24px;
+  display: flex;
+  flex-direction: column;
+}
+
+.inputAreaContainer {
+  flex-shrink: 0;
+
+  & > div {
+    margin: 0;
+    border-radius: 0;
+    border-left: none;
+    border-right: none;
+    border-bottom: none;
+    box-shadow: none;
+    border-top: 1px solid var(--fb-gray-30);
+    background-color: var(--fb-gray-10);
+  }
+}
+
+.imageDisplayContainer {
+  padding: 0;
+  border-radius: 4px;
+  background-color: transparent;
+  min-height: 150px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  color: var(--fb-gray-90);
+  width: 100%;
+  flex-grow: 1;
+}
+
+.loading,
+.placeholder {
+  font-style: italic;
+  color: var(--fb-gray-60);
+  margin: 20px 0;
+}
+
+.filteredReason {
+  color: var(--fb-warning-text);
+  background-color: var(--fb-warning-bg);
+  border: 1px solid var(--fb-warning-border);
+  padding: 8px 16px;
+  border-radius: 4px;
+  margin-bottom: 16px;
+  font-size: 0.875rem;
+  text-align: center;
+  width: auto;
+  max-width: 90%;
+  flex-shrink: 0;
+}
+
+.imageList {
+  display: grid;
+
+  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+  gap: 16px;
+  justify-content: center;
+  margin-top: 16px;
+  width: 100%;
+}
+
+.imageWrapper {
+  border: 1px solid var(--fb-gray-30);
+  padding: 4px;
+  background-color: var(--fb-gray-10);
+  border-radius: 4px;
+  box-sizing: border-box;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.generatedImage {
+  max-width: 100%;
+  max-height: 300px;
+  height: auto;
+  display: block;
+  border-radius: 2px;
+}
diff --git a/ai/ai-react-app/src/views/ImagenView.tsx b/ai/ai-react-app/src/views/ImagenView.tsx
new file mode 100644
index 000000000..46845ab32
--- /dev/null
+++ b/ai/ai-react-app/src/views/ImagenView.tsx
@@ -0,0 +1,147 @@
+import React, { useState, useCallback } from "react";
+import {
+  getImagenModel,
+  ImagenModelParams,
+  ImagenInlineImage,
+  ImagenGenerationResponse,
+  AI,
+  AIError,
+} from "firebase/ai";
+import PromptInput from "../components/Common/PromptInput";
+import styles from "./ImagenView.module.css";
+
+// Simple component to display generated images or placeholders/loading states.
+const ImageDisplay: React.FC<{
+  images: ImagenInlineImage[];
+  filteredReason?: string;
+  isLoading: boolean;
+}> = ({ images, filteredReason, isLoading }) => {
+  return (
+    <div className={styles.imageDisplayContainer}>
+      {isLoading && <div className={styles.loading}>Generating images...</div>}
+      {!isLoading && images.length === 0 && !filteredReason && (
+        <div className={styles.placeholder}>
+          Generated images will appear here.
+        </div>
+      )}
+      {filteredReason && (
+        <div className={styles.filteredReason}>Filtered: {filteredReason}</div>
+      )}
+      <div className={styles.imageList}>
+        {images.map((img, index) => (
+          <div key={index} className={styles.imageWrapper}>
+            <img
+              src={`data:${img.mimeType};base64,${img.bytesBase64Encoded}`}
+              alt={`Generated image ${index + 1}`}
+              className={styles.generatedImage}
+            />
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+};
+
+interface ImagenViewProps {
+  currentParams: ImagenModelParams;
+  aiInstance: AI;
+}
+
+/**
+ * View component for interacting with the Imagen model to generate images.
+ */
+const ImagenView: React.FC<ImagenViewProps> = ({
+  currentParams,
+  aiInstance,
+}) => {
+  const [currentPrompt, setCurrentPrompt] = useState("");
+  const [isLoading, setIsLoading] = useState(false);
+  const [resultImages, setResultImages] = useState<ImagenInlineImage[]>([]);
+  const [filteredReason, setFilteredReason] = useState<string | undefined>(
+    undefined,
+  );
+  const [error, setError] = useState<string | null>(null);
+
+  const handleImageGenerationSubmit = useCallback(async () => {
+    if (!currentPrompt.trim() || isLoading) {
+      return;
+    }
+
+    const promptText = currentPrompt.trim();
+    console.log(
+      `[ImagenView] Starting generation for prompt: "${promptText}" with params:`,
+      currentParams,
+    );
+    setIsLoading(true);
+    setResultImages([]); // Clear previous results
+    setFilteredReason(undefined);
+    setError(null);
+
+    try {
+      const imagenModel = getImagenModel(aiInstance, currentParams);
+      console.log(`[ImagenView] Using Imagen model: ${imagenModel.model}`);
+
+      const result: ImagenGenerationResponse<ImagenInlineImage> =
+        await imagenModel.generateImages(promptText);
+
+      console.log("[ImagenView] Image generation successful.", result);
+      setResultImages(result.images);
+      setFilteredReason(result.filteredReason);
+    } catch (err: unknown) {
+      console.error("[ImagenView] Error during image generation:", err);
+      if (err instanceof AIError) {
+        const message =
+          err.message || "Failed to generate images due to an unknown error.";
+        const details = err.customErrorData?.errorDetails
+          ? ` Details: ${JSON.stringify(err.customErrorData.errorDetails)}`
+          : "";
+        setError(`Error: ${message}${details}`);
+      } else {
+        setError("Failed to generate images due to an unknown error.");
+      }
+      setResultImages([]);
+    } finally {
+      setIsLoading(false);
+      setCurrentPrompt("");
+    }
+  }, [currentPrompt, isLoading, currentParams, aiInstance]);
+
+  const suggestions = [
+    "A photorealistic portrait of a tabby cat wearing sunglasses.",
+    "Impressionist painting of a sunflower field at sunset.",
+    "Logo for a coffee shop called 'The Daily Grind', minimalist style.",
+    "Pixel art sprite of a friendly robot navigating a maze.",
+  ];
+  const handleSuggestion = (suggestion: string) => {
+    setCurrentPrompt(suggestion);
+  };
+
+  return (
+    <div className={styles.imagenViewContainer}>
+      {error && <div className={styles.errorMessage}>{error}</div>}
+      <div className={styles.displayArea}>
+        <ImageDisplay
+          images={resultImages}
+          filteredReason={filteredReason}
+          isLoading={isLoading}
+        />
+      </div>
+      <div className={styles.inputAreaContainer}>
+        <PromptInput
+          prompt={currentPrompt}
+          onPromptChange={setCurrentPrompt}
+          onSubmit={handleImageGenerationSubmit}
+          isLoading={isLoading}
+          placeholder="Enter a prompt to generate images..."
+          suggestions={suggestions}
+          onSuggestionClick={handleSuggestion}
+          aiInstance={aiInstance}
+          activeMode="imagenGen"
+          selectedFile={null}
+        />
+      </div>
+    </div>
+  );
+};
+
+export default ImagenView;
diff --git a/ai/ai-react-app/src/vite-env.d.ts b/ai/ai-react-app/src/vite-env.d.ts
new file mode 100644
index 000000000..11f02fe2a
--- /dev/null
+++ b/ai/ai-react-app/src/vite-env.d.ts
@@ -0,0 +1 @@
+/// <reference types="vite/client" />
diff --git a/ai/ai-react-app/tsconfig.app.json b/ai/ai-react-app/tsconfig.app.json
new file mode 100644
index 000000000..358ca9ba9
--- /dev/null
+++ b/ai/ai-react-app/tsconfig.app.json
@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+    "target": "ES2020",
+    "useDefineForClassFields": true,
+    "lib": ["ES2020", "DOM", "DOM.Iterable"],
+    "module": "ESNext",
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "isolatedModules": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+    "jsx": "react-jsx",
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["src"]
+}
diff --git a/ai/ai-react-app/tsconfig.json b/ai/ai-react-app/tsconfig.json
new file mode 100644
index 000000000..1ffef600d
--- /dev/null
+++ b/ai/ai-react-app/tsconfig.json
@@ -0,0 +1,7 @@
+{
+  "files": [],
+  "references": [
+    { "path": "./tsconfig.app.json" },
+    { "path": "./tsconfig.node.json" }
+  ]
+}
diff --git a/ai/ai-react-app/tsconfig.node.json b/ai/ai-react-app/tsconfig.node.json
new file mode 100644
index 000000000..db0becc8b
--- /dev/null
+++ b/ai/ai-react-app/tsconfig.node.json
@@ -0,0 +1,24 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "target": "ES2022",
+    "lib": ["ES2023"],
+    "module": "ESNext",
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "isolatedModules": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/ai/ai-react-app/vite.config.ts b/ai/ai-react-app/vite.config.ts
new file mode 100644
index 000000000..081c8d9f6
--- /dev/null
+++ b/ai/ai-react-app/vite.config.ts
@@ -0,0 +1,6 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+export default defineConfig({
+  plugins: [react()],
+});
diff --git a/ai/ai-react-app/yarn.lock b/ai/ai-react-app/yarn.lock
new file mode 100644
index 000000000..f50ea7432
--- /dev/null
+++ b/ai/ai-react-app/yarn.lock
@@ -0,0 +1,1991 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@ampproject/remapping@^2.2.0":
+  version "2.3.0"
+  resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz"
+  integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==
+  dependencies:
+    "@jridgewell/gen-mapping" "^0.3.5"
+    "@jridgewell/trace-mapping" "^0.3.24"
+
+"@babel/code-frame@^7.26.2":
+  version "7.26.2"
+  resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz"
+  integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.25.9"
+    js-tokens "^4.0.0"
+    picocolors "^1.0.0"
+
+"@babel/compat-data@^7.26.8":
+  version "7.26.8"
+  resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz"
+  integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==
+
+"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.26.10":
+  version "7.26.10"
+  resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz"
+  integrity sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==
+  dependencies:
+    "@ampproject/remapping" "^2.2.0"
+    "@babel/code-frame" "^7.26.2"
+    "@babel/generator" "^7.26.10"
+    "@babel/helper-compilation-targets" "^7.26.5"
+    "@babel/helper-module-transforms" "^7.26.0"
+    "@babel/helpers" "^7.26.10"
+    "@babel/parser" "^7.26.10"
+    "@babel/template" "^7.26.9"
+    "@babel/traverse" "^7.26.10"
+    "@babel/types" "^7.26.10"
+    convert-source-map "^2.0.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.2"
+    json5 "^2.2.3"
+    semver "^6.3.1"
+
+"@babel/generator@^7.26.10", "@babel/generator@^7.27.0":
+  version "7.27.0"
+  resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz"
+  integrity sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==
+  dependencies:
+    "@babel/parser" "^7.27.0"
+    "@babel/types" "^7.27.0"
+    "@jridgewell/gen-mapping" "^0.3.5"
+    "@jridgewell/trace-mapping" "^0.3.25"
+    jsesc "^3.0.2"
+
+"@babel/helper-compilation-targets@^7.26.5":
+  version "7.27.0"
+  resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz"
+  integrity sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==
+  dependencies:
+    "@babel/compat-data" "^7.26.8"
+    "@babel/helper-validator-option" "^7.25.9"
+    browserslist "^4.24.0"
+    lru-cache "^5.1.1"
+    semver "^6.3.1"
+
+"@babel/helper-module-imports@^7.25.9":
+  version "7.25.9"
+  resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz"
+  integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==
+  dependencies:
+    "@babel/traverse" "^7.25.9"
+    "@babel/types" "^7.25.9"
+
+"@babel/helper-module-transforms@^7.26.0":
+  version "7.26.0"
+  resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz"
+  integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==
+  dependencies:
+    "@babel/helper-module-imports" "^7.25.9"
+    "@babel/helper-validator-identifier" "^7.25.9"
+    "@babel/traverse" "^7.25.9"
+
+"@babel/helper-plugin-utils@^7.25.9":
+  version "7.26.5"
+  resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz"
+  integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==
+
+"@babel/helper-string-parser@^7.25.9":
+  version "7.25.9"
+  resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz"
+  integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
+
+"@babel/helper-validator-identifier@^7.25.9":
+  version "7.25.9"
+  resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz"
+  integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
+
+"@babel/helper-validator-option@^7.25.9":
+  version "7.25.9"
+  resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz"
+  integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==
+
+"@babel/helpers@^7.26.10":
+  version "7.27.0"
+  resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz"
+  integrity sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==
+  dependencies:
+    "@babel/template" "^7.27.0"
+    "@babel/types" "^7.27.0"
+
+"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.26.10", "@babel/parser@^7.27.0":
+  version "7.27.0"
+  resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz"
+  integrity sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==
+  dependencies:
+    "@babel/types" "^7.27.0"
+
+"@babel/plugin-transform-react-jsx-self@^7.25.9":
+  version "7.25.9"
+  resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz"
+  integrity sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-react-jsx-source@^7.25.9":
+  version "7.25.9"
+  resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz"
+  integrity sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/template@^7.26.9", "@babel/template@^7.27.0":
+  version "7.27.0"
+  resolved "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz"
+  integrity sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==
+  dependencies:
+    "@babel/code-frame" "^7.26.2"
+    "@babel/parser" "^7.27.0"
+    "@babel/types" "^7.27.0"
+
+"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.10":
+  version "7.27.0"
+  resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz"
+  integrity sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==
+  dependencies:
+    "@babel/code-frame" "^7.26.2"
+    "@babel/generator" "^7.27.0"
+    "@babel/parser" "^7.27.0"
+    "@babel/template" "^7.27.0"
+    "@babel/types" "^7.27.0"
+    debug "^4.3.1"
+    globals "^11.1.0"
+
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.10", "@babel/types@^7.27.0":
+  version "7.27.0"
+  resolved "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz"
+  integrity sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==
+  dependencies:
+    "@babel/helper-string-parser" "^7.25.9"
+    "@babel/helper-validator-identifier" "^7.25.9"
+
+"@esbuild/darwin-arm64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz"
+  integrity sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==
+
+"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
+  version "4.6.1"
+  resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz"
+  integrity sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==
+  dependencies:
+    eslint-visitor-keys "^3.4.3"
+
+"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1":
+  version "4.12.1"
+  resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz"
+  integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
+
+"@eslint/config-array@^0.20.0":
+  version "0.20.0"
+  resolved "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz"
+  integrity sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==
+  dependencies:
+    "@eslint/object-schema" "^2.1.6"
+    debug "^4.3.1"
+    minimatch "^3.1.2"
+
+"@eslint/config-helpers@^0.2.1":
+  version "0.2.1"
+  resolved "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz"
+  integrity sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==
+
+"@eslint/core@^0.13.0":
+  version "0.13.0"
+  resolved "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz"
+  integrity sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==
+  dependencies:
+    "@types/json-schema" "^7.0.15"
+
+"@eslint/eslintrc@^3.3.1":
+  version "3.3.1"
+  resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz"
+  integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==
+  dependencies:
+    ajv "^6.12.4"
+    debug "^4.3.2"
+    espree "^10.0.1"
+    globals "^14.0.0"
+    ignore "^5.2.0"
+    import-fresh "^3.2.1"
+    js-yaml "^4.1.0"
+    minimatch "^3.1.2"
+    strip-json-comments "^3.1.1"
+
+"@eslint/js@^9.22.0", "@eslint/js@9.25.1":
+  version "9.25.1"
+  resolved "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz"
+  integrity sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==
+
+"@eslint/object-schema@^2.1.6":
+  version "2.1.6"
+  resolved "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz"
+  integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==
+
+"@eslint/plugin-kit@^0.2.8":
+  version "0.2.8"
+  resolved "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz"
+  integrity sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==
+  dependencies:
+    "@eslint/core" "^0.13.0"
+    levn "^0.4.1"
+
+"@firebase/ai@1.3.0":
+  version "1.3.0"
+  resolved "https://registry.npmjs.org/@firebase/ai/-/ai-1.3.0.tgz"
+  integrity sha512-qBxJTtl9hpgZr050kVFTRADX6I0Ss6mEQyp/JEkBgKwwxixKnaRNqEDGFba4OKNL7K8E4Y7LlA/ZW6L8aCKH4A==
+  dependencies:
+    "@firebase/app-check-interop-types" "0.3.3"
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/analytics-compat@0.2.22":
+  version "0.2.22"
+  resolved "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.22.tgz"
+  integrity sha512-VogWHgwkdYhjWKh8O1XU04uPrRaiDihkWvE/EMMmtWtaUtVALnpLnUurc3QtSKdPnvTz5uaIGKlW84DGtSPFbw==
+  dependencies:
+    "@firebase/analytics" "0.10.16"
+    "@firebase/analytics-types" "0.8.3"
+    "@firebase/component" "0.6.17"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/analytics-types@0.8.3":
+  version "0.8.3"
+  resolved "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz"
+  integrity sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==
+
+"@firebase/analytics@0.10.16":
+  version "0.10.16"
+  resolved "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.16.tgz"
+  integrity sha512-cMtp19He7Fd6uaj/nDEul+8JwvJsN8aRSJyuA1QN3QrKvfDDp+efjVurJO61sJpkVftw9O9nNMdhFbRcTmTfRQ==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/installations" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/app-check-compat@0.3.25":
+  version "0.3.25"
+  resolved "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.25.tgz"
+  integrity sha512-3zrsPZWAKfV7DVC20T2dgfjzjtQnSJS65OfMOiddMUtJL1S5i0nAZKsdX0bOEvvrd0SBIL8jYnfpfDeQRnhV3w==
+  dependencies:
+    "@firebase/app-check" "0.10.0"
+    "@firebase/app-check-types" "0.5.3"
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/app-check-interop-types@0.3.3":
+  version "0.3.3"
+  resolved "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz"
+  integrity sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==
+
+"@firebase/app-check-types@0.5.3":
+  version "0.5.3"
+  resolved "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz"
+  integrity sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==
+
+"@firebase/app-check@0.10.0":
+  version "0.10.0"
+  resolved "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.10.0.tgz"
+  integrity sha512-AZlRlVWKcu8BH4Yf8B5EI8sOi2UNGTS8oMuthV45tbt6OVUTSQwFPIEboZzhNJNKY+fPsg7hH8vixUWFZ3lrhw==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/app-compat@0.4.0", "@firebase/app-compat@0.x":
+  version "0.4.0"
+  resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.4.0.tgz"
+  integrity sha512-LjLUrzbUgTa/sCtPoLKT2C7KShvLVHS3crnU1Du02YxnGVLE0CUBGY/NxgfR/Zg84mEbj1q08/dgesojxjn0dA==
+  dependencies:
+    "@firebase/app" "0.13.0"
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/app-types@0.9.3", "@firebase/app-types@0.x":
+  version "0.9.3"
+  resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz"
+  integrity sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==
+
+"@firebase/app@0.13.0", "@firebase/app@0.x":
+  version "0.13.0"
+  resolved "https://registry.npmjs.org/@firebase/app/-/app-0.13.0.tgz"
+  integrity sha512-Vj3MST245nq+V5UmmfEkB3isIgPouyUr8yGJlFeL9Trg/umG5ogAvrjAYvQ8gV7daKDoQSRnJKWI2JFpQqRsuQ==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    idb "7.1.1"
+    tslib "^2.1.0"
+
+"@firebase/auth-compat@0.5.25":
+  version "0.5.25"
+  resolved "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.25.tgz"
+  integrity sha512-YKUYnvrxXBRhH/iYEwSOv85VPvc6P36GW1OCDRebTw/cvgoj7pwac2nZKYFs5FHlNYe7Bc9I4BoY2X0vlkJo+g==
+  dependencies:
+    "@firebase/auth" "1.10.5"
+    "@firebase/auth-types" "0.13.0"
+    "@firebase/component" "0.6.17"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/auth-interop-types@0.2.4":
+  version "0.2.4"
+  resolved "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz"
+  integrity sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==
+
+"@firebase/auth-types@0.13.0":
+  version "0.13.0"
+  resolved "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz"
+  integrity sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==
+
+"@firebase/auth@1.10.5":
+  version "1.10.5"
+  resolved "https://registry.npmjs.org/@firebase/auth/-/auth-1.10.5.tgz"
+  integrity sha512-6wF/NdMTwObL4RNQePunuzMr9O3gyftisvFZFFKf57D2HONXo87YymogRV8d+Z7SLA0rcNBN1gLJVk2D0y97gA==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/component@0.6.17":
+  version "0.6.17"
+  resolved "https://registry.npmjs.org/@firebase/component/-/component-0.6.17.tgz"
+  integrity sha512-M6DOg7OySrKEFS8kxA3MU5/xc37fiOpKPMz6cTsMUcsuKB6CiZxxNAvgFta8HGRgEpZbi8WjGIj6Uf+TpOhyzg==
+  dependencies:
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/data-connect@0.3.8":
+  version "0.3.8"
+  resolved "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.8.tgz"
+  integrity sha512-xC50SxurrP0j9ksltZ8O2SuPuWTu9KymNxtSE4bmcc/HMOnOHaURgLyrQpcC5Pc7HmtCBxh9Q/lNKyc37rj5/g==
+  dependencies:
+    "@firebase/auth-interop-types" "0.2.4"
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/database-compat@2.0.9":
+  version "2.0.9"
+  resolved "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.9.tgz"
+  integrity sha512-9S6zK5+Tzslkt+lrYHDqbCbKBSQn3YYrNLIw8hTa/ALoqRLNTXF6acQIlxAxSeZj1hTttE6RRbuxxpMQJYt83w==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/database" "1.0.18"
+    "@firebase/database-types" "1.0.14"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/database-types@1.0.14":
+  version "1.0.14"
+  resolved "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.14.tgz"
+  integrity sha512-8a0Q1GrxM0akgF0RiQHliinhmZd+UQPrxEmUv7MnQBYfVFiLtKOgs3g6ghRt/WEGJHyQNslZ+0PocIwNfoDwKw==
+  dependencies:
+    "@firebase/app-types" "0.9.3"
+    "@firebase/util" "1.12.0"
+
+"@firebase/database@1.0.18":
+  version "1.0.18"
+  resolved "https://registry.npmjs.org/@firebase/database/-/database-1.0.18.tgz"
+  integrity sha512-uXtYQmK6JCmqSx7dTOQD/qZtSnbMqnwvklF9n7wOJbdti4wKHmeUzgGXhPwDhN/R/BDTq78zKAbXya7hrCQjHw==
+  dependencies:
+    "@firebase/app-check-interop-types" "0.3.3"
+    "@firebase/auth-interop-types" "0.2.4"
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    faye-websocket "0.11.4"
+    tslib "^2.1.0"
+
+"@firebase/firestore-compat@0.3.50":
+  version "0.3.50"
+  resolved "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.50.tgz"
+  integrity sha512-1hAM+iaIqy2HHvSHQ56ccOOIigTeWAwjIpeQ+/O92uBoiajEITHdJofnGHglhhB5VV5qFl59Yz/AVDc+DssdYg==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/firestore" "4.7.15"
+    "@firebase/firestore-types" "3.0.3"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/firestore-types@3.0.3":
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz"
+  integrity sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==
+
+"@firebase/firestore@4.7.15":
+  version "4.7.15"
+  resolved "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.15.tgz"
+  integrity sha512-FgWTmkNBEXdKCoN2ngBNjrMaXuBx6QwjiZZVnOGg+VjUmiBq5gAqlDIW5bZY6i/NYvLUrWugdqIs7y9GHEqwww==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    "@firebase/webchannel-wrapper" "1.0.3"
+    "@grpc/grpc-js" "~1.9.0"
+    "@grpc/proto-loader" "^0.7.8"
+    tslib "^2.1.0"
+
+"@firebase/functions-compat@0.3.24":
+  version "0.3.24"
+  resolved "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.24.tgz"
+  integrity sha512-UjJabci+Bqci+A9WqfJ6sjZp+wGvi47llnQMjQRrF4coKfUyu9zBNTXhbx5W3rdVFQYwnWJm8VuluuNh2PCuyQ==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/functions" "0.12.7"
+    "@firebase/functions-types" "0.6.3"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/functions-types@0.6.3":
+  version "0.6.3"
+  resolved "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz"
+  integrity sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==
+
+"@firebase/functions@0.12.7":
+  version "0.12.7"
+  resolved "https://registry.npmjs.org/@firebase/functions/-/functions-0.12.7.tgz"
+  integrity sha512-gi8cw7yvaz19Erut+S0rHzNOWp4zPxAU/Kplb+XQoaE5gMV7MjHQoOGnYhSY8uOVj5f80S553s+2OBszG+14Ag==
+  dependencies:
+    "@firebase/app-check-interop-types" "0.3.3"
+    "@firebase/auth-interop-types" "0.2.4"
+    "@firebase/component" "0.6.17"
+    "@firebase/messaging-interop-types" "0.2.3"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/installations-compat@0.2.17":
+  version "0.2.17"
+  resolved "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.17.tgz"
+  integrity sha512-J7afeCXB7yq25FrrJAgbx8mn1nG1lZEubOLvYgG7ZHvyoOCK00sis5rj7TgDrLYJgdj/SJiGaO1BD3BAp55TeA==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/installations" "0.6.17"
+    "@firebase/installations-types" "0.5.3"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/installations-types@0.5.3":
+  version "0.5.3"
+  resolved "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz"
+  integrity sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==
+
+"@firebase/installations@0.6.17":
+  version "0.6.17"
+  resolved "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.17.tgz"
+  integrity sha512-zfhqCNJZRe12KyADtRrtOj+SeSbD1H/K8J24oQAJVv/u02eQajEGlhZtcx9Qk7vhGWF5z9dvIygVDYqLL4o1XQ==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/util" "1.12.0"
+    idb "7.1.1"
+    tslib "^2.1.0"
+
+"@firebase/logger@0.4.4":
+  version "0.4.4"
+  resolved "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz"
+  integrity sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==
+  dependencies:
+    tslib "^2.1.0"
+
+"@firebase/messaging-compat@0.2.21":
+  version "0.2.21"
+  resolved "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.21.tgz"
+  integrity sha512-1yMne+4BGLbHbtyu/VyXWcLiefUE1+K3ZGfVTyKM4BH4ZwDFRGoWUGhhx+tKRX4Tu9z7+8JN67SjnwacyNWK5g==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/messaging" "0.12.21"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/messaging-interop-types@0.2.3":
+  version "0.2.3"
+  resolved "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz"
+  integrity sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==
+
+"@firebase/messaging@0.12.21":
+  version "0.12.21"
+  resolved "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.21.tgz"
+  integrity sha512-bYJ2Evj167Z+lJ1ach6UglXz5dUKY1zrJZd15GagBUJSR7d9KfiM1W8dsyL0lDxcmhmA/sLaBYAAhF1uilwN0g==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/installations" "0.6.17"
+    "@firebase/messaging-interop-types" "0.2.3"
+    "@firebase/util" "1.12.0"
+    idb "7.1.1"
+    tslib "^2.1.0"
+
+"@firebase/performance-compat@0.2.19":
+  version "0.2.19"
+  resolved "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.19.tgz"
+  integrity sha512-4cU0T0BJ+LZK/E/UwFcvpBCVdkStgBMQwBztM9fJPT6udrEUk3ugF5/HT+E2Z22FCXtIaXDukJbYkE/c3c6IHw==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/performance" "0.7.6"
+    "@firebase/performance-types" "0.2.3"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/performance-types@0.2.3":
+  version "0.2.3"
+  resolved "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz"
+  integrity sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==
+
+"@firebase/performance@0.7.6":
+  version "0.7.6"
+  resolved "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.6.tgz"
+  integrity sha512-AsOz74dSTlyQGlnnbLWXiHFAsrxhpssPOsFFi4HgOJ5DjzkK7ZdZ/E9uMPrwFoXJyMVoybGRuqsL/wkIbFITsA==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/installations" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+    web-vitals "^4.2.4"
+
+"@firebase/remote-config-compat@0.2.17":
+  version "0.2.17"
+  resolved "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.17.tgz"
+  integrity sha512-KelsBD0sXSC0u3esr/r6sJYGRN6pzn3bYuI/6pTvvmZbjBlxQkRabHAVH6d+YhLcjUXKIAYIjZszczd1QJtOyA==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/remote-config" "0.6.4"
+    "@firebase/remote-config-types" "0.4.0"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/remote-config-types@0.4.0":
+  version "0.4.0"
+  resolved "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz"
+  integrity sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg==
+
+"@firebase/remote-config@0.6.4":
+  version "0.6.4"
+  resolved "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.6.4.tgz"
+  integrity sha512-ZyLJRT46wtycyz2+opEkGaoFUOqRQjt/0NX1WfUISOMCI/PuVoyDjqGpq24uK+e8D5NknyTpiXCVq5dowhScmg==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/installations" "0.6.17"
+    "@firebase/logger" "0.4.4"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/storage-compat@0.3.21":
+  version "0.3.21"
+  resolved "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.21.tgz"
+  integrity sha512-LG3978H2Vy1XGa0Jz9VNFwgMrhjy/G8CTV8GkWpArzu+AhI/SE9c0e06SiXcFsVaQW2rObcqFa0zp51LDaVzRA==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/storage" "0.13.11"
+    "@firebase/storage-types" "0.8.3"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/storage-types@0.8.3":
+  version "0.8.3"
+  resolved "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz"
+  integrity sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==
+
+"@firebase/storage@0.13.11":
+  version "0.13.11"
+  resolved "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.11.tgz"
+  integrity sha512-nBtCGGpr39vuAeTQhG73nvMq3BjQBTgIg6fWufB6qglWYQCgky/XE4duSrOhTp2/QC+H3/SnaE/nKOQmjnPqjg==
+  dependencies:
+    "@firebase/component" "0.6.17"
+    "@firebase/util" "1.12.0"
+    tslib "^2.1.0"
+
+"@firebase/util@1.12.0", "@firebase/util@1.x":
+  version "1.12.0"
+  resolved "https://registry.npmjs.org/@firebase/util/-/util-1.12.0.tgz"
+  integrity sha512-Z4rK23xBCwgKDqmzGVMef+Vb4xso2j5Q8OG0vVL4m4fA5ZjPMYQazu8OJJC3vtQRC3SQ/Pgx/6TPNVsCd70QRw==
+  dependencies:
+    tslib "^2.1.0"
+
+"@firebase/webchannel-wrapper@1.0.3":
+  version "1.0.3"
+  resolved "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz"
+  integrity sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==
+
+"@grpc/grpc-js@~1.9.0":
+  version "1.9.15"
+  resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz"
+  integrity sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==
+  dependencies:
+    "@grpc/proto-loader" "^0.7.8"
+    "@types/node" ">=12.12.47"
+
+"@grpc/proto-loader@^0.7.8":
+  version "0.7.15"
+  resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz"
+  integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==
+  dependencies:
+    lodash.camelcase "^4.3.0"
+    long "^5.0.0"
+    protobufjs "^7.2.5"
+    yargs "^17.7.2"
+
+"@humanfs/core@^0.19.1":
+  version "0.19.1"
+  resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz"
+  integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==
+
+"@humanfs/node@^0.16.6":
+  version "0.16.6"
+  resolved "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz"
+  integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==
+  dependencies:
+    "@humanfs/core" "^0.19.1"
+    "@humanwhocodes/retry" "^0.3.0"
+
+"@humanwhocodes/module-importer@^1.0.1":
+  version "1.0.1"
+  resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz"
+  integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
+
+"@humanwhocodes/retry@^0.3.0":
+  version "0.3.1"
+  resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz"
+  integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
+
+"@humanwhocodes/retry@^0.4.2":
+  version "0.4.2"
+  resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz"
+  integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==
+
+"@jridgewell/gen-mapping@^0.3.5":
+  version "0.3.8"
+  resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz"
+  integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==
+  dependencies:
+    "@jridgewell/set-array" "^1.2.1"
+    "@jridgewell/sourcemap-codec" "^1.4.10"
+    "@jridgewell/trace-mapping" "^0.3.24"
+
+"@jridgewell/resolve-uri@^3.1.0":
+  version "3.1.2"
+  resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz"
+  integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
+
+"@jridgewell/set-array@^1.2.1":
+  version "1.2.1"
+  resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz"
+  integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
+
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
+  version "1.5.0"
+  resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz"
+  integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
+
+"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
+  version "0.3.25"
+  resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz"
+  integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
+  dependencies:
+    "@jridgewell/resolve-uri" "^3.1.0"
+    "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@nodelib/fs.scandir@2.1.5":
+  version "2.1.5"
+  resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
+  integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+  dependencies:
+    "@nodelib/fs.stat" "2.0.5"
+    run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
+  version "2.0.5"
+  resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
+  integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+  version "1.2.8"
+  resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz"
+  integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+  dependencies:
+    "@nodelib/fs.scandir" "2.1.5"
+    fastq "^1.6.0"
+
+"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz"
+  integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
+
+"@protobufjs/base64@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz"
+  integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
+
+"@protobufjs/codegen@^2.0.4":
+  version "2.0.4"
+  resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz"
+  integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
+
+"@protobufjs/eventemitter@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz"
+  integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
+
+"@protobufjs/fetch@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz"
+  integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
+  dependencies:
+    "@protobufjs/aspromise" "^1.1.1"
+    "@protobufjs/inquire" "^1.1.0"
+
+"@protobufjs/float@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz"
+  integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
+
+"@protobufjs/inquire@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz"
+  integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
+
+"@protobufjs/path@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz"
+  integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
+
+"@protobufjs/pool@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz"
+  integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
+
+"@protobufjs/utf8@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz"
+  integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
+
+"@rollup/rollup-darwin-arm64@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz"
+  integrity sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==
+
+"@types/babel__core@^7.20.5":
+  version "7.20.5"
+  resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
+  integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
+  dependencies:
+    "@babel/parser" "^7.20.7"
+    "@babel/types" "^7.20.7"
+    "@types/babel__generator" "*"
+    "@types/babel__template" "*"
+    "@types/babel__traverse" "*"
+
+"@types/babel__generator@*":
+  version "7.27.0"
+  resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz"
+  integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@types/babel__template@*":
+  version "7.4.4"
+  resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz"
+  integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==
+  dependencies:
+    "@babel/parser" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@types/babel__traverse@*":
+  version "7.20.7"
+  resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz"
+  integrity sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==
+  dependencies:
+    "@babel/types" "^7.20.7"
+
+"@types/estree@^1.0.6", "@types/estree@1.0.7":
+  version "1.0.7"
+  resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz"
+  integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==
+
+"@types/json-schema@^7.0.15":
+  version "7.0.15"
+  resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
+  integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
+
+"@types/node@^18.0.0 || ^20.0.0 || >=22.0.0", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
+  version "22.14.1"
+  resolved "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz"
+  integrity sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==
+  dependencies:
+    undici-types "~6.21.0"
+
+"@types/react-dom@^19.0.4":
+  version "19.1.2"
+  resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz"
+  integrity sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==
+
+"@types/react@^19.0.0", "@types/react@^19.0.10":
+  version "19.1.2"
+  resolved "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz"
+  integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==
+  dependencies:
+    csstype "^3.0.2"
+
+"@typescript-eslint/eslint-plugin@8.31.0":
+  version "8.31.0"
+  resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz"
+  integrity sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==
+  dependencies:
+    "@eslint-community/regexpp" "^4.10.0"
+    "@typescript-eslint/scope-manager" "8.31.0"
+    "@typescript-eslint/type-utils" "8.31.0"
+    "@typescript-eslint/utils" "8.31.0"
+    "@typescript-eslint/visitor-keys" "8.31.0"
+    graphemer "^1.4.0"
+    ignore "^5.3.1"
+    natural-compare "^1.4.0"
+    ts-api-utils "^2.0.1"
+
+"@typescript-eslint/parser@^8.0.0 || ^8.0.0-alpha.0", "@typescript-eslint/parser@8.31.0":
+  version "8.31.0"
+  resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz"
+  integrity sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==
+  dependencies:
+    "@typescript-eslint/scope-manager" "8.31.0"
+    "@typescript-eslint/types" "8.31.0"
+    "@typescript-eslint/typescript-estree" "8.31.0"
+    "@typescript-eslint/visitor-keys" "8.31.0"
+    debug "^4.3.4"
+
+"@typescript-eslint/scope-manager@8.31.0":
+  version "8.31.0"
+  resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz"
+  integrity sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==
+  dependencies:
+    "@typescript-eslint/types" "8.31.0"
+    "@typescript-eslint/visitor-keys" "8.31.0"
+
+"@typescript-eslint/type-utils@8.31.0":
+  version "8.31.0"
+  resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz"
+  integrity sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==
+  dependencies:
+    "@typescript-eslint/typescript-estree" "8.31.0"
+    "@typescript-eslint/utils" "8.31.0"
+    debug "^4.3.4"
+    ts-api-utils "^2.0.1"
+
+"@typescript-eslint/types@8.31.0":
+  version "8.31.0"
+  resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz"
+  integrity sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==
+
+"@typescript-eslint/typescript-estree@8.31.0":
+  version "8.31.0"
+  resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz"
+  integrity sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==
+  dependencies:
+    "@typescript-eslint/types" "8.31.0"
+    "@typescript-eslint/visitor-keys" "8.31.0"
+    debug "^4.3.4"
+    fast-glob "^3.3.2"
+    is-glob "^4.0.3"
+    minimatch "^9.0.4"
+    semver "^7.6.0"
+    ts-api-utils "^2.0.1"
+
+"@typescript-eslint/utils@8.31.0":
+  version "8.31.0"
+  resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz"
+  integrity sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.4.0"
+    "@typescript-eslint/scope-manager" "8.31.0"
+    "@typescript-eslint/types" "8.31.0"
+    "@typescript-eslint/typescript-estree" "8.31.0"
+
+"@typescript-eslint/visitor-keys@8.31.0":
+  version "8.31.0"
+  resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz"
+  integrity sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==
+  dependencies:
+    "@typescript-eslint/types" "8.31.0"
+    eslint-visitor-keys "^4.2.0"
+
+"@vitejs/plugin-react@^4.3.4":
+  version "4.4.1"
+  resolved "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.4.1.tgz"
+  integrity sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==
+  dependencies:
+    "@babel/core" "^7.26.10"
+    "@babel/plugin-transform-react-jsx-self" "^7.25.9"
+    "@babel/plugin-transform-react-jsx-source" "^7.25.9"
+    "@types/babel__core" "^7.20.5"
+    react-refresh "^0.17.0"
+
+acorn-jsx@^5.3.2:
+  version "5.3.2"
+  resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
+  integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
+
+"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.14.0:
+  version "8.14.1"
+  resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz"
+  integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==
+
+ajv@^6.12.4:
+  version "6.12.6"
+  resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
+  integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+ansi-regex@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
+  integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+  version "4.3.0"
+  resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
+  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+  dependencies:
+    color-convert "^2.0.1"
+
+argparse@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
+  integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
+balanced-match@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
+  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+brace-expansion@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz"
+  integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+  dependencies:
+    balanced-match "^1.0.0"
+
+braces@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz"
+  integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
+  dependencies:
+    fill-range "^7.1.1"
+
+browserslist@^4.24.0, "browserslist@>= 4.21.0":
+  version "4.24.4"
+  resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz"
+  integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==
+  dependencies:
+    caniuse-lite "^1.0.30001688"
+    electron-to-chromium "^1.5.73"
+    node-releases "^2.0.19"
+    update-browserslist-db "^1.1.1"
+
+callsites@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
+  integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+caniuse-lite@^1.0.30001688:
+  version "1.0.30001715"
+  resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz"
+  integrity sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==
+
+chalk@^4.0.0:
+  version "4.1.2"
+  resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
+  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
+cliui@^8.0.1:
+  version "8.0.1"
+  resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz"
+  integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+  dependencies:
+    string-width "^4.2.0"
+    strip-ansi "^6.0.1"
+    wrap-ansi "^7.0.0"
+
+color-convert@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
+  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+  dependencies:
+    color-name "~1.1.4"
+
+color-name@~1.1.4:
+  version "1.1.4"
+  resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+  integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+convert-source-map@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz"
+  integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
+
+cross-spawn@^7.0.6:
+  version "7.0.6"
+  resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz"
+  integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
+  dependencies:
+    path-key "^3.1.0"
+    shebang-command "^2.0.0"
+    which "^2.0.1"
+
+csstype@^3.0.2:
+  version "3.1.3"
+  resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz"
+  integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+
+debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
+  version "4.4.0"
+  resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz"
+  integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
+  dependencies:
+    ms "^2.1.3"
+
+deep-is@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
+  integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+
+electron-to-chromium@^1.5.73:
+  version "1.5.140"
+  resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.140.tgz"
+  integrity sha512-o82Rj+ONp4Ip7Cl1r7lrqx/pXhbp/lh9DpKcMNscFJdh8ebyRofnc7Sh01B4jx403RI0oqTBvlZ7OBIZLMr2+Q==
+
+emoji-regex@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
+  integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+esbuild@^0.25.0:
+  version "0.25.3"
+  resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz"
+  integrity sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==
+  optionalDependencies:
+    "@esbuild/aix-ppc64" "0.25.3"
+    "@esbuild/android-arm" "0.25.3"
+    "@esbuild/android-arm64" "0.25.3"
+    "@esbuild/android-x64" "0.25.3"
+    "@esbuild/darwin-arm64" "0.25.3"
+    "@esbuild/darwin-x64" "0.25.3"
+    "@esbuild/freebsd-arm64" "0.25.3"
+    "@esbuild/freebsd-x64" "0.25.3"
+    "@esbuild/linux-arm" "0.25.3"
+    "@esbuild/linux-arm64" "0.25.3"
+    "@esbuild/linux-ia32" "0.25.3"
+    "@esbuild/linux-loong64" "0.25.3"
+    "@esbuild/linux-mips64el" "0.25.3"
+    "@esbuild/linux-ppc64" "0.25.3"
+    "@esbuild/linux-riscv64" "0.25.3"
+    "@esbuild/linux-s390x" "0.25.3"
+    "@esbuild/linux-x64" "0.25.3"
+    "@esbuild/netbsd-arm64" "0.25.3"
+    "@esbuild/netbsd-x64" "0.25.3"
+    "@esbuild/openbsd-arm64" "0.25.3"
+    "@esbuild/openbsd-x64" "0.25.3"
+    "@esbuild/sunos-x64" "0.25.3"
+    "@esbuild/win32-arm64" "0.25.3"
+    "@esbuild/win32-ia32" "0.25.3"
+    "@esbuild/win32-x64" "0.25.3"
+
+escalade@^3.1.1, escalade@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz"
+  integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
+
+escape-string-regexp@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
+  integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+eslint-config-prettier@^10.1.2:
+  version "10.1.2"
+  resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz"
+  integrity sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==
+
+eslint-plugin-react-hooks@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz"
+  integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==
+
+eslint-plugin-react-refresh@^0.4.19:
+  version "0.4.20"
+  resolved "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz"
+  integrity sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==
+
+eslint-scope@^8.3.0:
+  version "8.3.0"
+  resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz"
+  integrity sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==
+  dependencies:
+    esrecurse "^4.3.0"
+    estraverse "^5.2.0"
+
+eslint-visitor-keys@^3.4.3:
+  version "3.4.3"
+  resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
+  integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
+
+eslint-visitor-keys@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz"
+  integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
+
+"eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9.22.0, eslint@>=7.0.0, eslint@>=8.40:
+  version "9.25.1"
+  resolved "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz"
+  integrity sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.2.0"
+    "@eslint-community/regexpp" "^4.12.1"
+    "@eslint/config-array" "^0.20.0"
+    "@eslint/config-helpers" "^0.2.1"
+    "@eslint/core" "^0.13.0"
+    "@eslint/eslintrc" "^3.3.1"
+    "@eslint/js" "9.25.1"
+    "@eslint/plugin-kit" "^0.2.8"
+    "@humanfs/node" "^0.16.6"
+    "@humanwhocodes/module-importer" "^1.0.1"
+    "@humanwhocodes/retry" "^0.4.2"
+    "@types/estree" "^1.0.6"
+    "@types/json-schema" "^7.0.15"
+    ajv "^6.12.4"
+    chalk "^4.0.0"
+    cross-spawn "^7.0.6"
+    debug "^4.3.2"
+    escape-string-regexp "^4.0.0"
+    eslint-scope "^8.3.0"
+    eslint-visitor-keys "^4.2.0"
+    espree "^10.3.0"
+    esquery "^1.5.0"
+    esutils "^2.0.2"
+    fast-deep-equal "^3.1.3"
+    file-entry-cache "^8.0.0"
+    find-up "^5.0.0"
+    glob-parent "^6.0.2"
+    ignore "^5.2.0"
+    imurmurhash "^0.1.4"
+    is-glob "^4.0.0"
+    json-stable-stringify-without-jsonify "^1.0.1"
+    lodash.merge "^4.6.2"
+    minimatch "^3.1.2"
+    natural-compare "^1.4.0"
+    optionator "^0.9.3"
+
+espree@^10.0.1, espree@^10.3.0:
+  version "10.3.0"
+  resolved "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz"
+  integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==
+  dependencies:
+    acorn "^8.14.0"
+    acorn-jsx "^5.3.2"
+    eslint-visitor-keys "^4.2.0"
+
+esquery@^1.5.0:
+  version "1.6.0"
+  resolved "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz"
+  integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
+  dependencies:
+    estraverse "^5.1.0"
+
+esrecurse@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz"
+  integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+  dependencies:
+    estraverse "^5.2.0"
+
+estraverse@^5.1.0, estraverse@^5.2.0:
+  version "5.3.0"
+  resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
+  integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+esutils@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
+  integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
+  integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-glob@^3.3.2:
+  version "3.3.3"
+  resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz"
+  integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
+  dependencies:
+    "@nodelib/fs.stat" "^2.0.2"
+    "@nodelib/fs.walk" "^1.2.3"
+    glob-parent "^5.1.2"
+    merge2 "^1.3.0"
+    micromatch "^4.0.8"
+
+fast-json-stable-stringify@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz"
+  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-levenshtein@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
+  integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+
+fastq@^1.6.0:
+  version "1.19.1"
+  resolved "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz"
+  integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==
+  dependencies:
+    reusify "^1.0.4"
+
+faye-websocket@0.11.4:
+  version "0.11.4"
+  resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz"
+  integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==
+  dependencies:
+    websocket-driver ">=0.5.1"
+
+fdir@^6.4.3, fdir@^6.4.4:
+  version "6.4.4"
+  resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz"
+  integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==
+
+file-entry-cache@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz"
+  integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==
+  dependencies:
+    flat-cache "^4.0.0"
+
+fill-range@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz"
+  integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
+  dependencies:
+    to-regex-range "^5.0.1"
+
+find-up@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz"
+  integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+  dependencies:
+    locate-path "^6.0.0"
+    path-exists "^4.0.0"
+
+firebase@11.8.0:
+  version "11.8.0"
+  resolved "https://registry.npmjs.org/firebase/-/firebase-11.8.0.tgz"
+  integrity sha512-zIv11czOqFayPllaJySKIKB2pS+xoWOnfI7j85SOiBKY1IW3NuZIaL+UgsZA+4PQZkPhFP8vmU2/oOun04ALbg==
+  dependencies:
+    "@firebase/ai" "1.3.0"
+    "@firebase/analytics" "0.10.16"
+    "@firebase/analytics-compat" "0.2.22"
+    "@firebase/app" "0.13.0"
+    "@firebase/app-check" "0.10.0"
+    "@firebase/app-check-compat" "0.3.25"
+    "@firebase/app-compat" "0.4.0"
+    "@firebase/app-types" "0.9.3"
+    "@firebase/auth" "1.10.5"
+    "@firebase/auth-compat" "0.5.25"
+    "@firebase/data-connect" "0.3.8"
+    "@firebase/database" "1.0.18"
+    "@firebase/database-compat" "2.0.9"
+    "@firebase/firestore" "4.7.15"
+    "@firebase/firestore-compat" "0.3.50"
+    "@firebase/functions" "0.12.7"
+    "@firebase/functions-compat" "0.3.24"
+    "@firebase/installations" "0.6.17"
+    "@firebase/installations-compat" "0.2.17"
+    "@firebase/messaging" "0.12.21"
+    "@firebase/messaging-compat" "0.2.21"
+    "@firebase/performance" "0.7.6"
+    "@firebase/performance-compat" "0.2.19"
+    "@firebase/remote-config" "0.6.4"
+    "@firebase/remote-config-compat" "0.2.17"
+    "@firebase/storage" "0.13.11"
+    "@firebase/storage-compat" "0.3.21"
+    "@firebase/util" "1.12.0"
+
+flat-cache@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz"
+  integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==
+  dependencies:
+    flatted "^3.2.9"
+    keyv "^4.5.4"
+
+flatted@^3.2.9:
+  version "3.3.3"
+  resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz"
+  integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==
+
+fsevents@~2.3.2, fsevents@~2.3.3:
+  version "2.3.3"
+  resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
+  integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+gensync@^1.0.0-beta.2:
+  version "1.0.0-beta.2"
+  resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz"
+  integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
+
+get-caller-file@^2.0.5:
+  version "2.0.5"
+  resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
+  integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+glob-parent@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
+  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+  dependencies:
+    is-glob "^4.0.1"
+
+glob-parent@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz"
+  integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
+  dependencies:
+    is-glob "^4.0.3"
+
+globals@^11.1.0:
+  version "11.12.0"
+  resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz"
+  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globals@^14.0.0:
+  version "14.0.0"
+  resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz"
+  integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
+
+globals@^16.0.0:
+  version "16.0.0"
+  resolved "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz"
+  integrity sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==
+
+graphemer@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz"
+  integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
+
+has-flag@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
+  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+http-parser-js@>=0.5.1:
+  version "0.5.10"
+  resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz"
+  integrity sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==
+
+idb@7.1.1:
+  version "7.1.1"
+  resolved "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz"
+  integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==
+
+ignore@^5.2.0, ignore@^5.3.1:
+  version "5.3.2"
+  resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz"
+  integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
+
+immer@^10.1.1:
+  version "10.1.1"
+  resolved "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz"
+  integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==
+
+import-fresh@^3.2.1:
+  version "3.3.1"
+  resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz"
+  integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==
+  dependencies:
+    parent-module "^1.0.0"
+    resolve-from "^4.0.0"
+
+imurmurhash@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
+  integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
+  integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-fullwidth-code-point@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
+  integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
+  integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-number@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
+  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
+  integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz"
+  integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+  dependencies:
+    argparse "^2.0.1"
+
+jsesc@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz"
+  integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
+
+json-buffer@3.0.1:
+  version "3.0.1"
+  resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz"
+  integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
+json-schema-traverse@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"
+  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-stable-stringify-without-jsonify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
+  integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+
+json5@^2.2.3:
+  version "2.2.3"
+  resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
+  integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+
+keyv@^4.5.4:
+  version "4.5.4"
+  resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"
+  integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
+  dependencies:
+    json-buffer "3.0.1"
+
+levn@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz"
+  integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
+  dependencies:
+    prelude-ls "^1.2.1"
+    type-check "~0.4.0"
+
+locate-path@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
+  integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+  dependencies:
+    p-locate "^5.0.0"
+
+lodash.camelcase@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz"
+  integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+
+lodash.merge@^4.6.2:
+  version "4.6.2"
+  resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
+  integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
+long@^5.0.0:
+  version "5.3.2"
+  resolved "https://registry.npmjs.org/long/-/long-5.3.2.tgz"
+  integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==
+
+lru-cache@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz"
+  integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+  dependencies:
+    yallist "^3.0.2"
+
+merge2@^1.3.0:
+  version "1.4.1"
+  resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
+  integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.8:
+  version "4.0.8"
+  resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"
+  integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
+  dependencies:
+    braces "^3.0.3"
+    picomatch "^2.3.1"
+
+minimatch@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
+  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minimatch@^9.0.4:
+  version "9.0.5"
+  resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz"
+  integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
+  dependencies:
+    brace-expansion "^2.0.1"
+
+ms@^2.1.3:
+  version "2.1.3"
+  resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
+  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+nanoid@^3.3.8:
+  version "3.3.11"
+  resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz"
+  integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
+  integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+
+node-releases@^2.0.19:
+  version "2.0.19"
+  resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz"
+  integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==
+
+optionator@^0.9.3:
+  version "0.9.4"
+  resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz"
+  integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==
+  dependencies:
+    deep-is "^0.1.3"
+    fast-levenshtein "^2.0.6"
+    levn "^0.4.1"
+    prelude-ls "^1.2.1"
+    type-check "^0.4.0"
+    word-wrap "^1.2.5"
+
+p-limit@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz"
+  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+  dependencies:
+    yocto-queue "^0.1.0"
+
+p-locate@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz"
+  integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+  dependencies:
+    p-limit "^3.0.2"
+
+parent-module@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
+  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+  dependencies:
+    callsites "^3.0.0"
+
+path-exists@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
+  integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-key@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
+  integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+picocolors@^1.0.0, picocolors@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz"
+  integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
+
+picomatch@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
+  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+"picomatch@^3 || ^4", picomatch@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz"
+  integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
+
+postcss@^8.5.3:
+  version "8.5.3"
+  resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz"
+  integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==
+  dependencies:
+    nanoid "^3.3.8"
+    picocolors "^1.1.1"
+    source-map-js "^1.2.1"
+
+prelude-ls@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
+  integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+
+prettier@^3.5.3:
+  version "3.5.3"
+  resolved "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz"
+  integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==
+
+protobufjs@^7.2.5:
+  version "7.4.0"
+  resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz"
+  integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==
+  dependencies:
+    "@protobufjs/aspromise" "^1.1.2"
+    "@protobufjs/base64" "^1.1.2"
+    "@protobufjs/codegen" "^2.0.4"
+    "@protobufjs/eventemitter" "^1.1.0"
+    "@protobufjs/fetch" "^1.1.0"
+    "@protobufjs/float" "^1.0.2"
+    "@protobufjs/inquire" "^1.1.0"
+    "@protobufjs/path" "^1.1.2"
+    "@protobufjs/pool" "^1.1.0"
+    "@protobufjs/utf8" "^1.1.0"
+    "@types/node" ">=13.7.0"
+    long "^5.0.0"
+
+punycode@^2.1.0:
+  version "2.3.1"
+  resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
+  integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+
+queue-microtask@^1.2.2:
+  version "1.2.3"
+  resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
+  integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+react-dom@^19.0.0:
+  version "19.1.0"
+  resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz"
+  integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==
+  dependencies:
+    scheduler "^0.26.0"
+
+react-refresh@^0.17.0:
+  version "0.17.0"
+  resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz"
+  integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
+
+react@^19.0.0, react@^19.1.0:
+  version "19.1.0"
+  resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz"
+  integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
+  integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+resolve-from@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
+  integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+reusify@^1.0.4:
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz"
+  integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==
+
+rollup@^4.34.9:
+  version "4.40.0"
+  resolved "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz"
+  integrity sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==
+  dependencies:
+    "@types/estree" "1.0.7"
+  optionalDependencies:
+    "@rollup/rollup-android-arm-eabi" "4.40.0"
+    "@rollup/rollup-android-arm64" "4.40.0"
+    "@rollup/rollup-darwin-arm64" "4.40.0"
+    "@rollup/rollup-darwin-x64" "4.40.0"
+    "@rollup/rollup-freebsd-arm64" "4.40.0"
+    "@rollup/rollup-freebsd-x64" "4.40.0"
+    "@rollup/rollup-linux-arm-gnueabihf" "4.40.0"
+    "@rollup/rollup-linux-arm-musleabihf" "4.40.0"
+    "@rollup/rollup-linux-arm64-gnu" "4.40.0"
+    "@rollup/rollup-linux-arm64-musl" "4.40.0"
+    "@rollup/rollup-linux-loongarch64-gnu" "4.40.0"
+    "@rollup/rollup-linux-powerpc64le-gnu" "4.40.0"
+    "@rollup/rollup-linux-riscv64-gnu" "4.40.0"
+    "@rollup/rollup-linux-riscv64-musl" "4.40.0"
+    "@rollup/rollup-linux-s390x-gnu" "4.40.0"
+    "@rollup/rollup-linux-x64-gnu" "4.40.0"
+    "@rollup/rollup-linux-x64-musl" "4.40.0"
+    "@rollup/rollup-win32-arm64-msvc" "4.40.0"
+    "@rollup/rollup-win32-ia32-msvc" "4.40.0"
+    "@rollup/rollup-win32-x64-msvc" "4.40.0"
+    fsevents "~2.3.2"
+
+run-parallel@^1.1.9:
+  version "1.2.0"
+  resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
+  integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+  dependencies:
+    queue-microtask "^1.2.2"
+
+safe-buffer@>=5.1.0:
+  version "5.2.1"
+  resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
+  integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+scheduler@^0.26.0:
+  version "0.26.0"
+  resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz"
+  integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==
+
+semver@^6.3.1:
+  version "6.3.1"
+  resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
+  integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
+semver@^7.6.0:
+  version "7.7.1"
+  resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz"
+  integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
+
+shebang-command@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
+  integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+  dependencies:
+    shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
+  integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+source-map-js@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz"
+  integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
+
+string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+  version "4.2.3"
+  resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
+  integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+  dependencies:
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.1"
+
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+  dependencies:
+    ansi-regex "^5.0.1"
+
+strip-json-comments@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
+  integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
+supports-color@^7.1.0:
+  version "7.2.0"
+  resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
+  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+  dependencies:
+    has-flag "^4.0.0"
+
+tinyglobby@^0.2.12:
+  version "0.2.13"
+  resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz"
+  integrity sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==
+  dependencies:
+    fdir "^6.4.4"
+    picomatch "^4.0.2"
+
+to-regex-range@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
+  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+  dependencies:
+    is-number "^7.0.0"
+
+ts-api-utils@^2.0.1:
+  version "2.1.0"
+  resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz"
+  integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==
+
+tslib@^2.1.0:
+  version "2.8.1"
+  resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
+  integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
+
+type-check@^0.4.0, type-check@~0.4.0:
+  version "0.4.0"
+  resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
+  integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
+  dependencies:
+    prelude-ls "^1.2.1"
+
+typescript-eslint@^8.26.1:
+  version "8.31.0"
+  resolved "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.0.tgz"
+  integrity sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ==
+  dependencies:
+    "@typescript-eslint/eslint-plugin" "8.31.0"
+    "@typescript-eslint/parser" "8.31.0"
+    "@typescript-eslint/utils" "8.31.0"
+
+typescript@>=4.8.4, "typescript@>=4.8.4 <5.9.0", typescript@~5.7.2:
+  version "5.7.3"
+  resolved "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz"
+  integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==
+
+undici-types@~6.21.0:
+  version "6.21.0"
+  resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz"
+  integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
+
+update-browserslist-db@^1.1.1:
+  version "1.1.3"
+  resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz"
+  integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==
+  dependencies:
+    escalade "^3.2.0"
+    picocolors "^1.1.1"
+
+uri-js@^4.2.2:
+  version "4.4.1"
+  resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
+  integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+  dependencies:
+    punycode "^2.1.0"
+
+"vite@^4.2.0 || ^5.0.0 || ^6.0.0", vite@^6.3.1:
+  version "6.3.2"
+  resolved "https://registry.npmjs.org/vite/-/vite-6.3.2.tgz"
+  integrity sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==
+  dependencies:
+    esbuild "^0.25.0"
+    fdir "^6.4.3"
+    picomatch "^4.0.2"
+    postcss "^8.5.3"
+    rollup "^4.34.9"
+    tinyglobby "^0.2.12"
+  optionalDependencies:
+    fsevents "~2.3.3"
+
+web-vitals@^4.2.4:
+  version "4.2.4"
+  resolved "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz"
+  integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==
+
+websocket-driver@>=0.5.1:
+  version "0.7.4"
+  resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz"
+  integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==
+  dependencies:
+    http-parser-js ">=0.5.1"
+    safe-buffer ">=5.1.0"
+    websocket-extensions ">=0.1.1"
+
+websocket-extensions@>=0.1.1:
+  version "0.1.4"
+  resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz"
+  integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
+
+which@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
+  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+  dependencies:
+    isexe "^2.0.0"
+
+word-wrap@^1.2.5:
+  version "1.2.5"
+  resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz"
+  integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
+
+wrap-ansi@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
+  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+  dependencies:
+    ansi-styles "^4.0.0"
+    string-width "^4.1.0"
+    strip-ansi "^6.0.0"
+
+y18n@^5.0.5:
+  version "5.0.8"
+  resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
+  integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yallist@^3.0.2:
+  version "3.1.1"
+  resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz"
+  integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
+yargs-parser@^21.1.1:
+  version "21.1.1"
+  resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
+  integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs@^17.7.2:
+  version "17.7.2"
+  resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz"
+  integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+  dependencies:
+    cliui "^8.0.1"
+    escalade "^3.1.1"
+    get-caller-file "^2.0.5"
+    require-directory "^2.1.1"
+    string-width "^4.2.3"
+    y18n "^5.0.5"
+    yargs-parser "^21.1.1"
+
+yocto-queue@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
+  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
diff --git a/scripts/test.sh b/scripts/test.sh
index dbc6e798a..c2f392bd3 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -1,4 +1,4 @@
 set -e
 # Run linter
-find . -type f -name "*.js" -not -path "*node_modules*" -not -path "*dataconnect-sdk/*" \
+find . -type f -name "*.js" -not -path "*node_modules*" -not -path "*dataconnect-sdk/*" -not -path "*ai/ai-react-app/*" \
   | xargs eslint

From 61a166d4eb23bd6fa73e5af6c84ef63d3cdde5cd Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Mon, 2 Jun 2025 14:24:48 -0400
Subject: [PATCH 63/82] Remove vertexai directory (#890)

---
 vertexai/.prettierrc       |    3 -
 vertexai/README.md         |   34 --
 vertexai/config.ts         |   17 -
 vertexai/index.html        |   27 -
 vertexai/main.ts           |   48 --
 vertexai/package-lock.json | 1176 ------------------------------------
 vertexai/package.json      |   31 -
 vertexai/vite-env.d.ts     |    1 -
 vertexai/vite.config.js    |   10 -
 9 files changed, 1347 deletions(-)
 delete mode 100644 vertexai/.prettierrc
 delete mode 100644 vertexai/README.md
 delete mode 100644 vertexai/config.ts
 delete mode 100644 vertexai/index.html
 delete mode 100644 vertexai/main.ts
 delete mode 100644 vertexai/package-lock.json
 delete mode 100644 vertexai/package.json
 delete mode 100644 vertexai/vite-env.d.ts
 delete mode 100644 vertexai/vite.config.js

diff --git a/vertexai/.prettierrc b/vertexai/.prettierrc
deleted file mode 100644
index 544138be4..000000000
--- a/vertexai/.prettierrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "singleQuote": true
-}
diff --git a/vertexai/README.md b/vertexai/README.md
deleted file mode 100644
index 5782c6520..000000000
--- a/vertexai/README.md
+++ /dev/null
@@ -1,34 +0,0 @@
-Firebase SDK for Vertex AI Quickstart
-=========================================
-
-Introduction
-------------
-
-This is a sample app for the preview version of the Firebase Vertex AI SDK.
-This will not run if you don't have access to the preview.
-
-<!-- Introduction
-------------
-
-[Read more about Firebase SDK for Vertex AI ](https://firebase.google.com/docs/vertexai/) -->
-
-Getting Started
----------------
-
- 1. Create your project on the [Firebase Console](https://console.firebase.google.com).
- 2. Enable Gemini in the console.
- 3. Create a ReCAPTCHA Enterprise key in the same project.
- 4. Enable App Check in the Firebase console with the ReCAPTCHA Enterprise site key you created.
- 5. Copy your Firebase project config and your ReCAPTCHA Enterprise site key into the appropriate places in `config.ts` in this directory.
- 6. In this directory, run `npm install`
- 7. In this directory, run `npm run dev`
-
-<!-- Support
--------
-
-- [Firebase Support](https://firebase.google.com/support/) -->
-
-License
--------
-
-© Google, 2024. Licensed under an [Apache-2](../LICENSE) license.
diff --git a/vertexai/config.ts b/vertexai/config.ts
deleted file mode 100644
index 29c1251da..000000000
--- a/vertexai/config.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-export const firebaseConfig = {
-  // Your web app's Firebase configuration here
-  // See https://firebase.google.com/docs/web/setup#add-sdks-initialize
-  apiKey: 'API_KEY',
-  authDomain: 'PROJECT_ID.firebaseapp.com',
-  databaseURL: 'https://PROJECT_ID.firebaseio.com',
-  projectId: 'PROJECT_ID',
-  storageBucket: 'PROJECT_ID.appspot.com',
-  messagingSenderId: 'SENDER_ID',
-  appId: 'APP_ID',
-  measurementId: 'G-MEASUREMENT_ID',
-};
-
-  // Your ReCAPTCHA Enterprise site key (must be from the same project
-  // as the Firebase config above).
-export const RECAPTCHA_ENTERPRISE_SITE_KEY =
-  "YOUR_SITE_KEY";
diff --git a/vertexai/index.html b/vertexai/index.html
deleted file mode 100644
index 49ba64654..000000000
--- a/vertexai/index.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!doctype html>
-<!--
-Copyright (c) 2024 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<html>
-  <head>
-    <meta charset="utf-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Vertex AI for Firebase SDK Quickstart</title>
-  </head>
-  <body>
-    <div>Open browser's developer console to view console.log output.</div>
-    <script type="module" src="main.ts"></script>
-  </body>
-</html>
diff --git a/vertexai/main.ts b/vertexai/main.ts
deleted file mode 100644
index 78356cd29..000000000
--- a/vertexai/main.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @license
- * Copyright 2024 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { initializeApp } from 'firebase/app';
-import { firebaseConfig, RECAPTCHA_ENTERPRISE_SITE_KEY } from './config';
-import {
-  initializeAppCheck,
-  ReCaptchaEnterpriseProvider,
-} from "firebase/app-check";
-import { getVertexAI, getGenerativeModel } from "firebase/vertexai";
-
-async function main() {
-  const app = initializeApp(firebaseConfig);
-
-  // Initialize App Check
-  // This line can be removed if you do not want to enable App Check for
-  // your project. App Check is recommended to limit unauthorized usage.
-  initializeAppCheck(app, {
-    provider: new ReCaptchaEnterpriseProvider(RECAPTCHA_ENTERPRISE_SITE_KEY),
-  });
-
-  // Get VertexAI instance
-  const vertexAI = getVertexAI(app);
-  // Get a Gemini model
-  const model = getGenerativeModel(
-    vertexAI,
-    { model: "gemini-2.0-flash" }
-  );
-  // Call generateContent with a string or Content(s)
-  const generateContentResult = await model.generateContent("what is a cat?");
-  console.log(generateContentResult.response.text());
-}
-
-main();
diff --git a/vertexai/package-lock.json b/vertexai/package-lock.json
deleted file mode 100644
index 02739db7b..000000000
--- a/vertexai/package-lock.json
+++ /dev/null
@@ -1,1176 +0,0 @@
-{
-  "name": "quickstart-js-vertexai",
-  "version": "1.0.0",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "name": "quickstart-js-vertexai",
-      "version": "1.0.0",
-      "license": "Apache-2.0",
-      "dependencies": {
-        "firebase": "^11.1.0"
-      },
-      "devDependencies": {
-        "typescript": "^5.1.6",
-        "vite": "^4.4.9"
-      },
-      "engines": {
-        "node": ">=18.0.0 <=22.10.0",
-        "npm": ">=9.0.0 <=10.9.0"
-      }
-    },
-    "node_modules/@esbuild/darwin-x64": {
-      "version": "0.18.20",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/@firebase/analytics": {
-      "version": "0.10.10",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.10.tgz",
-      "integrity": "sha512-Psdo7c9g2SLAYh6u1XRA+RZ7ab2JfBVuAt/kLzXkhKZL/gS2cQUCMsOW5p0RIlDPRKqpdNSmvujd2TeRWLKOkQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/installations": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/analytics-compat": {
-      "version": "0.2.16",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.16.tgz",
-      "integrity": "sha512-Q/s+u/TEMSb2EDJFQMGsOzpSosybBl8HuoSEMyGZ99+0Pu7SIR9MPDGUjc8PKiCFQWDJ3QXxgqh1d/rujyAMbA==",
-      "dependencies": {
-        "@firebase/analytics": "0.10.10",
-        "@firebase/analytics-types": "0.8.3",
-        "@firebase/component": "0.6.11",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/analytics-types": {
-      "version": "0.8.3",
-      "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz",
-      "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg=="
-    },
-    "node_modules/@firebase/app": {
-      "version": "0.10.17",
-      "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.17.tgz",
-      "integrity": "sha512-53sIYyAnYEPIZdaxuyq5OST7j4KBc2pqmktz+tEb1BIUSbXh8Gp4k/o6qzLelLpm4ngrBz7SRN0PZJqNRAyPog==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "idb": "7.1.1",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      }
-    },
-    "node_modules/@firebase/app-check": {
-      "version": "0.8.10",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.10.tgz",
-      "integrity": "sha512-DWFfxxif/t+Ow4MmRUevDX+A3hVxm1rUf6y5ZP4sIomfnVCO1NNahqtsv9rb1/tKGkTeoVT40weiTS/WjQG1mA==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/app-check-compat": {
-      "version": "0.3.17",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.17.tgz",
-      "integrity": "sha512-a/eadrGsY0MVCBPhrNbKUhoYpms4UKTYLKO7nswwSFVsm3Rw6NslQQCNLfvljcDqP4E7alQDRGJXjkxd/5gJ+Q==",
-      "dependencies": {
-        "@firebase/app-check": "0.8.10",
-        "@firebase/app-check-types": "0.5.3",
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/app-check-interop-types": {
-      "version": "0.3.3",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz",
-      "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A=="
-    },
-    "node_modules/@firebase/app-check-types": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz",
-      "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng=="
-    },
-    "node_modules/@firebase/app-compat": {
-      "version": "0.2.47",
-      "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.47.tgz",
-      "integrity": "sha512-TdEWGDp6kSwuO1mxiM2Fe39eLWygfyzqTZcoU3aPV0viqqphPCbBBnVjPbFJErZ4+yaS7uCWXEbFEP9m5/COKA==",
-      "dependencies": {
-        "@firebase/app": "0.10.17",
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      }
-    },
-    "node_modules/@firebase/app-types": {
-      "version": "0.9.3",
-      "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz",
-      "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw=="
-    },
-    "node_modules/@firebase/auth": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.8.1.tgz",
-      "integrity": "sha512-LX9N/Cf5Z35r5yqm2+5M3+2bRRe/+RFaa/+u4HDni7TA27C/Xm4XHLKcWcLg1BzjrS4zngSaBEOSODvp6RFOqQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x",
-        "@react-native-async-storage/async-storage": "^1.18.1"
-      },
-      "peerDependenciesMeta": {
-        "@react-native-async-storage/async-storage": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@firebase/auth-compat": {
-      "version": "0.5.16",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.16.tgz",
-      "integrity": "sha512-YlYwJMBqAyv0ESy3jDUyshMhZlbUiwAm6B6+uUmigNDHU+uq7j4SFiDJEZlFFIz397yBzKn06SUdqutdQzGnCA==",
-      "dependencies": {
-        "@firebase/auth": "1.8.1",
-        "@firebase/auth-types": "0.12.3",
-        "@firebase/component": "0.6.11",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/auth-interop-types": {
-      "version": "0.2.4",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz",
-      "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA=="
-    },
-    "node_modules/@firebase/auth-types": {
-      "version": "0.12.3",
-      "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.3.tgz",
-      "integrity": "sha512-Zq9zI0o5hqXDtKg6yDkSnvMCMuLU6qAVS51PANQx+ZZX5xnzyNLEBO3GZgBUPsV5qIMFhjhqmLDxUqCbnAYy2A==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.x",
-        "@firebase/util": "1.x"
-      }
-    },
-    "node_modules/@firebase/component": {
-      "version": "0.6.11",
-      "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.11.tgz",
-      "integrity": "sha512-eQbeCgPukLgsKD0Kw5wQgsMDX5LeoI1MIrziNDjmc6XDq5ZQnuUymANQgAb2wp1tSF9zDSXyxJmIUXaKgN58Ug==",
-      "dependencies": {
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      }
-    },
-    "node_modules/@firebase/data-connect": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.1.3.tgz",
-      "integrity": "sha512-FbAQpWNHownJx1VTCQI4ydbWGOZmSWXoFlirQn3ItHqsLJYSywqxSgDafzvyooifFh3J/2WqaM8y9hInnPcsTw==",
-      "dependencies": {
-        "@firebase/auth-interop-types": "0.2.4",
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/database": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.10.tgz",
-      "integrity": "sha512-sWp2g92u7xT4BojGbTXZ80iaSIaL6GAL0pwvM0CO/hb0nHSnABAqsH7AhnWGsGvXuEvbPr7blZylPaR9J+GSuQ==",
-      "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.3",
-        "@firebase/auth-interop-types": "0.2.4",
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "faye-websocket": "0.11.4",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      }
-    },
-    "node_modules/@firebase/database-compat": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.1.tgz",
-      "integrity": "sha512-IsFivOjdE1GrjTeKoBU/ZMenESKDXidFDzZzHBPQ/4P20ptGdrl3oLlWrV/QJqJ9lND4IidE3z4Xr5JyfUW1vg==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/database": "1.0.10",
-        "@firebase/database-types": "1.0.7",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      }
-    },
-    "node_modules/@firebase/database-types": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.7.tgz",
-      "integrity": "sha512-I7zcLfJXrM0WM+ksFmFdAMdlq/DFmpeMNa+/GNsLyFo5u/lX5zzkPzGe3srVWqaBQBY5KprylDGxOsP6ETfL0A==",
-      "dependencies": {
-        "@firebase/app-types": "0.9.3",
-        "@firebase/util": "1.10.2"
-      }
-    },
-    "node_modules/@firebase/firestore": {
-      "version": "4.7.5",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.5.tgz",
-      "integrity": "sha512-OO3rHvjC07jL2ITN255xH/UzCVSvh6xG8oTzQdFScQvFbcm1fjCL1hgAdpDZcx3vVcKMV+6ktr8wbllkB8r+FQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "@firebase/webchannel-wrapper": "1.0.3",
-        "@grpc/grpc-js": "~1.9.0",
-        "@grpc/proto-loader": "^0.7.8",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/firestore-compat": {
-      "version": "0.3.40",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.40.tgz",
-      "integrity": "sha512-18HopMN811KYBc9Ptpr1Rewwio0XF09FF3jc5wtV6rGyAs815SlFFw5vW7ZeLd43zv9tlEc2FzM0H+5Vr9ZRxw==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/firestore": "4.7.5",
-        "@firebase/firestore-types": "3.0.3",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/firestore-types": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz",
-      "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.x",
-        "@firebase/util": "1.x"
-      }
-    },
-    "node_modules/@firebase/functions": {
-      "version": "0.12.0",
-      "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.12.0.tgz",
-      "integrity": "sha512-plTtzY/nT0jOgHzT0vB9qch4FpHFOhCnR8HhYBqqdArG6GOQMIruKZbiTyLybO8bcaaNgQ6kSm9yohGUwxHcIw==",
-      "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.3",
-        "@firebase/auth-interop-types": "0.2.4",
-        "@firebase/component": "0.6.11",
-        "@firebase/messaging-interop-types": "0.2.3",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/functions-compat": {
-      "version": "0.3.17",
-      "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.17.tgz",
-      "integrity": "sha512-oj2XV8YsJYutyPCRYUfbN6swmfrL6zar0/qtqZsKT7P7btOiYRl+lD6fxtQaT+pKE5YgOBGZW//kLPZfY0jWhw==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/functions": "0.12.0",
-        "@firebase/functions-types": "0.6.3",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/functions-types": {
-      "version": "0.6.3",
-      "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz",
-      "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg=="
-    },
-    "node_modules/@firebase/installations": {
-      "version": "0.6.11",
-      "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.11.tgz",
-      "integrity": "sha512-w8fY8mw6fxJzsZM2ufmTtomopXl1+bn/syYon+Gpn+0p0nO1cIUEVEFrFazTLaaL9q1CaVhc3HmseRTsI3igAA==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/util": "1.10.2",
-        "idb": "7.1.1",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/installations-compat": {
-      "version": "0.2.11",
-      "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.11.tgz",
-      "integrity": "sha512-SHRgw5LTa6v8LubmJZxcOCwEd1MfWQPUtKdiuCx2VMWnapX54skZd1PkQg0K4l3k+4ujbI2cn7FE6Li9hbChBw==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/installations": "0.6.11",
-        "@firebase/installations-types": "0.5.3",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/installations-types": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz",
-      "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.x"
-      }
-    },
-    "node_modules/@firebase/logger": {
-      "version": "0.4.4",
-      "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz",
-      "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==",
-      "dependencies": {
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      }
-    },
-    "node_modules/@firebase/messaging": {
-      "version": "0.12.15",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.15.tgz",
-      "integrity": "sha512-Bz+qvWNEwEWAbYtG4An8hgcNco6NWNoNLuLbGVwPL2fAoCF1zz+dcaBp+iTR2+K199JyRyDT9yDPAXhNHNDaKQ==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/installations": "0.6.11",
-        "@firebase/messaging-interop-types": "0.2.3",
-        "@firebase/util": "1.10.2",
-        "idb": "7.1.1",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/messaging-compat": {
-      "version": "0.2.15",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.15.tgz",
-      "integrity": "sha512-mEKKASRvRWq1aBNHgioGsOYR2c5nBZpO7k90K794zjKe0WkGNf0k7PLs5SlCf8FKnzumEkhTAp/SjYxovuxa8A==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/messaging": "0.12.15",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/messaging-interop-types": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz",
-      "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q=="
-    },
-    "node_modules/@firebase/performance": {
-      "version": "0.6.11",
-      "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.11.tgz",
-      "integrity": "sha512-FlkJFeqLlIeh5T4Am3uE38HVzggliDIEFy/fErEc1faINOUFCb6vQBEoNZGaXvRnTR8lh3X/hP7tv37C7BsK9g==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/installations": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/performance-compat": {
-      "version": "0.2.11",
-      "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.11.tgz",
-      "integrity": "sha512-DqeNBy51W2xzlklyC7Ht9JQ94HhTA08PCcM4MDeyG/ol3fqum/+YgtHWQ2IQuduqH9afETthZqLwCZiSgY7hiA==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/performance": "0.6.11",
-        "@firebase/performance-types": "0.2.3",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/performance-types": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz",
-      "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ=="
-    },
-    "node_modules/@firebase/remote-config": {
-      "version": "0.4.11",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.11.tgz",
-      "integrity": "sha512-9z0rgKuws2nj+7cdiqF+NY1QR4na6KnuOvP+jQvgilDOhGtKOcCMq5XHiu66i73A9kFhyU6QQ2pHXxcmaq1pBw==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/installations": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/remote-config-compat": {
-      "version": "0.2.11",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.11.tgz",
-      "integrity": "sha512-zfIjpwPrGuIOZDmduukN086qjhZ1LnbJi/iYzgua+2qeTlO0XdlE1v66gJPwygGB3TOhT0yb9EiUZ3nBNttMqg==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/remote-config": "0.4.11",
-        "@firebase/remote-config-types": "0.3.3",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/remote-config-types": {
-      "version": "0.3.3",
-      "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.3.tgz",
-      "integrity": "sha512-YlRI9CHxrk3lpQuFup9N1eohpwdWayKZUNZ/YeQ0PZoncJ66P32UsKUKqVXOaieTjJIOh7yH8JEzRdht5s+d6g=="
-    },
-    "node_modules/@firebase/storage": {
-      "version": "0.13.4",
-      "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.4.tgz",
-      "integrity": "sha512-b1KaTTRiMupFurIhpGIbReaWev0k5O3ouTHkAPcEssT+FvU3q/1JwzvkX4+ZdB60Fc43Mbp8qQ1gWfT0Z2FP9Q==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x"
-      }
-    },
-    "node_modules/@firebase/storage-compat": {
-      "version": "0.3.14",
-      "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.14.tgz",
-      "integrity": "sha512-Ok5FmXJiapaNAOQ8W8qppnfwgP8540jw2B8M0c4TFZqF4BD+CoKBxW0dRtOuLNGadLhzqqkDZZZtkexxrveQqA==",
-      "dependencies": {
-        "@firebase/component": "0.6.11",
-        "@firebase/storage": "0.13.4",
-        "@firebase/storage-types": "0.8.3",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app-compat": "0.x"
-      }
-    },
-    "node_modules/@firebase/storage-types": {
-      "version": "0.8.3",
-      "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz",
-      "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==",
-      "peerDependencies": {
-        "@firebase/app-types": "0.x",
-        "@firebase/util": "1.x"
-      }
-    },
-    "node_modules/@firebase/util": {
-      "version": "1.10.2",
-      "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.10.2.tgz",
-      "integrity": "sha512-qnSHIoE9FK+HYnNhTI8q14evyqbc/vHRivfB4TgCIUOl4tosmKSQlp7ltymOlMP4xVIJTg5wrkfcZ60X4nUf7Q==",
-      "dependencies": {
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      }
-    },
-    "node_modules/@firebase/vertexai": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.0.2.tgz",
-      "integrity": "sha512-4dC9m2nD0tkfKJT5v+i27tELrmUePjFXW3CDAxhVHUEv647B2R7kqpGQnyPkNEeaXkCr76THe7GGg35EWn4lDw==",
-      "dependencies": {
-        "@firebase/app-check-interop-types": "0.3.3",
-        "@firebase/component": "0.6.11",
-        "@firebase/logger": "0.4.4",
-        "@firebase/util": "1.10.2",
-        "tslib": "^2.1.0"
-      },
-      "engines": {
-        "node": ">=18.0.0"
-      },
-      "peerDependencies": {
-        "@firebase/app": "0.x",
-        "@firebase/app-types": "0.x"
-      }
-    },
-    "node_modules/@firebase/webchannel-wrapper": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz",
-      "integrity": "sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ=="
-    },
-    "node_modules/@grpc/grpc-js": {
-      "version": "1.9.15",
-      "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz",
-      "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==",
-      "dependencies": {
-        "@grpc/proto-loader": "^0.7.8",
-        "@types/node": ">=12.12.47"
-      },
-      "engines": {
-        "node": "^8.13.0 || >=10.10.0"
-      }
-    },
-    "node_modules/@grpc/proto-loader": {
-      "version": "0.7.13",
-      "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz",
-      "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==",
-      "dependencies": {
-        "lodash.camelcase": "^4.3.0",
-        "long": "^5.0.0",
-        "protobufjs": "^7.2.5",
-        "yargs": "^17.7.2"
-      },
-      "bin": {
-        "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/@protobufjs/aspromise": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
-      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
-    },
-    "node_modules/@protobufjs/base64": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
-      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
-    },
-    "node_modules/@protobufjs/codegen": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
-      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
-    },
-    "node_modules/@protobufjs/eventemitter": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
-      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
-    },
-    "node_modules/@protobufjs/fetch": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
-      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
-      "dependencies": {
-        "@protobufjs/aspromise": "^1.1.1",
-        "@protobufjs/inquire": "^1.1.0"
-      }
-    },
-    "node_modules/@protobufjs/float": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
-      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
-    },
-    "node_modules/@protobufjs/inquire": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
-      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
-    },
-    "node_modules/@protobufjs/path": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
-      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
-    },
-    "node_modules/@protobufjs/pool": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
-      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
-    },
-    "node_modules/@protobufjs/utf8": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
-      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
-    },
-    "node_modules/@types/node": {
-      "version": "20.12.4",
-      "license": "MIT",
-      "dependencies": {
-        "undici-types": "~5.26.4"
-      }
-    },
-    "node_modules/ansi-regex": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/ansi-styles": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-      "dependencies": {
-        "color-convert": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-      }
-    },
-    "node_modules/cliui": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
-      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
-      "dependencies": {
-        "string-width": "^4.2.0",
-        "strip-ansi": "^6.0.1",
-        "wrap-ansi": "^7.0.0"
-      },
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/color-convert": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "dependencies": {
-        "color-name": "~1.1.4"
-      },
-      "engines": {
-        "node": ">=7.0.0"
-      }
-    },
-    "node_modules/color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
-    },
-    "node_modules/emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
-    },
-    "node_modules/esbuild": {
-      "version": "0.18.20",
-      "dev": true,
-      "hasInstallScript": true,
-      "license": "MIT",
-      "bin": {
-        "esbuild": "bin/esbuild"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "optionalDependencies": {
-        "@esbuild/android-arm": "0.18.20",
-        "@esbuild/android-arm64": "0.18.20",
-        "@esbuild/android-x64": "0.18.20",
-        "@esbuild/darwin-arm64": "0.18.20",
-        "@esbuild/darwin-x64": "0.18.20",
-        "@esbuild/freebsd-arm64": "0.18.20",
-        "@esbuild/freebsd-x64": "0.18.20",
-        "@esbuild/linux-arm": "0.18.20",
-        "@esbuild/linux-arm64": "0.18.20",
-        "@esbuild/linux-ia32": "0.18.20",
-        "@esbuild/linux-loong64": "0.18.20",
-        "@esbuild/linux-mips64el": "0.18.20",
-        "@esbuild/linux-ppc64": "0.18.20",
-        "@esbuild/linux-riscv64": "0.18.20",
-        "@esbuild/linux-s390x": "0.18.20",
-        "@esbuild/linux-x64": "0.18.20",
-        "@esbuild/netbsd-x64": "0.18.20",
-        "@esbuild/openbsd-x64": "0.18.20",
-        "@esbuild/sunos-x64": "0.18.20",
-        "@esbuild/win32-arm64": "0.18.20",
-        "@esbuild/win32-ia32": "0.18.20",
-        "@esbuild/win32-x64": "0.18.20"
-      }
-    },
-    "node_modules/escalade": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
-      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/faye-websocket": {
-      "version": "0.11.4",
-      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
-      "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
-      "dependencies": {
-        "websocket-driver": ">=0.5.1"
-      },
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/firebase": {
-      "version": "11.1.0",
-      "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.1.0.tgz",
-      "integrity": "sha512-3OoNW3vBXmBLYJvcwbPCwfluptbDVp2zZYjrfHPVFAXfPgmyy/LWjidt+Sw2WNvRelsG0v++WN2Wor6J3OwDRg==",
-      "dependencies": {
-        "@firebase/analytics": "0.10.10",
-        "@firebase/analytics-compat": "0.2.16",
-        "@firebase/app": "0.10.17",
-        "@firebase/app-check": "0.8.10",
-        "@firebase/app-check-compat": "0.3.17",
-        "@firebase/app-compat": "0.2.47",
-        "@firebase/app-types": "0.9.3",
-        "@firebase/auth": "1.8.1",
-        "@firebase/auth-compat": "0.5.16",
-        "@firebase/data-connect": "0.1.3",
-        "@firebase/database": "1.0.10",
-        "@firebase/database-compat": "2.0.1",
-        "@firebase/firestore": "4.7.5",
-        "@firebase/firestore-compat": "0.3.40",
-        "@firebase/functions": "0.12.0",
-        "@firebase/functions-compat": "0.3.17",
-        "@firebase/installations": "0.6.11",
-        "@firebase/installations-compat": "0.2.11",
-        "@firebase/messaging": "0.12.15",
-        "@firebase/messaging-compat": "0.2.15",
-        "@firebase/performance": "0.6.11",
-        "@firebase/performance-compat": "0.2.11",
-        "@firebase/remote-config": "0.4.11",
-        "@firebase/remote-config-compat": "0.2.11",
-        "@firebase/storage": "0.13.4",
-        "@firebase/storage-compat": "0.3.14",
-        "@firebase/util": "1.10.2",
-        "@firebase/vertexai": "1.0.2"
-      }
-    },
-    "node_modules/fsevents": {
-      "version": "2.3.3",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-      }
-    },
-    "node_modules/get-caller-file": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-      "engines": {
-        "node": "6.* || 8.* || >= 10.*"
-      }
-    },
-    "node_modules/http-parser-js": {
-      "version": "0.5.8",
-      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
-      "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q=="
-    },
-    "node_modules/idb": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
-      "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="
-    },
-    "node_modules/is-fullwidth-code-point": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/lodash.camelcase": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
-      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
-    },
-    "node_modules/long": {
-      "version": "5.2.3",
-      "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
-      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
-    },
-    "node_modules/nanoid": {
-      "version": "3.3.7",
-      "dev": true,
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "bin": {
-        "nanoid": "bin/nanoid.cjs"
-      },
-      "engines": {
-        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
-      }
-    },
-    "node_modules/picocolors": {
-      "version": "1.0.0",
-      "dev": true,
-      "license": "ISC"
-    },
-    "node_modules/postcss": {
-      "version": "8.4.38",
-      "dev": true,
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/postcss"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "nanoid": "^3.3.7",
-        "picocolors": "^1.0.0",
-        "source-map-js": "^1.2.0"
-      },
-      "engines": {
-        "node": "^10 || ^12 || >=14"
-      }
-    },
-    "node_modules/protobufjs": {
-      "version": "7.4.0",
-      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
-      "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
-      "hasInstallScript": true,
-      "dependencies": {
-        "@protobufjs/aspromise": "^1.1.2",
-        "@protobufjs/base64": "^1.1.2",
-        "@protobufjs/codegen": "^2.0.4",
-        "@protobufjs/eventemitter": "^1.1.0",
-        "@protobufjs/fetch": "^1.1.0",
-        "@protobufjs/float": "^1.0.2",
-        "@protobufjs/inquire": "^1.1.0",
-        "@protobufjs/path": "^1.1.2",
-        "@protobufjs/pool": "^1.1.0",
-        "@protobufjs/utf8": "^1.1.0",
-        "@types/node": ">=13.7.0",
-        "long": "^5.0.0"
-      },
-      "engines": {
-        "node": ">=12.0.0"
-      }
-    },
-    "node_modules/require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/rollup": {
-      "version": "3.29.4",
-      "dev": true,
-      "license": "MIT",
-      "bin": {
-        "rollup": "dist/bin/rollup"
-      },
-      "engines": {
-        "node": ">=14.18.0",
-        "npm": ">=8.0.0"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      }
-    },
-    "node_modules/safe-buffer": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ]
-    },
-    "node_modules/source-map-js": {
-      "version": "1.2.0",
-      "dev": true,
-      "license": "BSD-3-Clause",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/string-width": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "dependencies": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/strip-ansi": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-      "dependencies": {
-        "ansi-regex": "^5.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/tslib": {
-      "version": "2.8.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
-      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
-    },
-    "node_modules/typescript": {
-      "version": "5.4.4",
-      "dev": true,
-      "license": "Apache-2.0",
-      "bin": {
-        "tsc": "bin/tsc",
-        "tsserver": "bin/tsserver"
-      },
-      "engines": {
-        "node": ">=14.17"
-      }
-    },
-    "node_modules/undici-types": {
-      "version": "5.26.5",
-      "license": "MIT"
-    },
-    "node_modules/vite": {
-      "version": "4.5.3",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "esbuild": "^0.18.10",
-        "postcss": "^8.4.27",
-        "rollup": "^3.27.1"
-      },
-      "bin": {
-        "vite": "bin/vite.js"
-      },
-      "engines": {
-        "node": "^14.18.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/vitejs/vite?sponsor=1"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      },
-      "peerDependencies": {
-        "@types/node": ">= 14",
-        "less": "*",
-        "lightningcss": "^1.21.0",
-        "sass": "*",
-        "stylus": "*",
-        "sugarss": "*",
-        "terser": "^5.4.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/node": {
-          "optional": true
-        },
-        "less": {
-          "optional": true
-        },
-        "lightningcss": {
-          "optional": true
-        },
-        "sass": {
-          "optional": true
-        },
-        "stylus": {
-          "optional": true
-        },
-        "sugarss": {
-          "optional": true
-        },
-        "terser": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/websocket-driver": {
-      "version": "0.7.4",
-      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
-      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
-      "dependencies": {
-        "http-parser-js": ">=0.5.1",
-        "safe-buffer": ">=5.1.0",
-        "websocket-extensions": ">=0.1.1"
-      },
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/websocket-extensions": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
-      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/wrap-ansi": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-      "dependencies": {
-        "ansi-styles": "^4.0.0",
-        "string-width": "^4.1.0",
-        "strip-ansi": "^6.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-      }
-    },
-    "node_modules/y18n": {
-      "version": "5.0.8",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
-      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/yargs": {
-      "version": "17.7.2",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
-      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
-      "dependencies": {
-        "cliui": "^8.0.1",
-        "escalade": "^3.1.1",
-        "get-caller-file": "^2.0.5",
-        "require-directory": "^2.1.1",
-        "string-width": "^4.2.3",
-        "y18n": "^5.0.5",
-        "yargs-parser": "^21.1.1"
-      },
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/yargs-parser": {
-      "version": "21.1.1",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-      "engines": {
-        "node": ">=12"
-      }
-    }
-  }
-}
diff --git a/vertexai/package.json b/vertexai/package.json
deleted file mode 100644
index 6c859d63f..000000000
--- a/vertexai/package.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
-  "name": "quickstart-js-vertexai",
-  "version": "1.0.0",
-  "description": "JavaScript quickstarts for Vertex AI for Firebase.",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/firebase/quickstart-js.git"
-  },
-  "author": "",
-  "license": "Apache-2.0",
-  "bugs": {
-    "url": "https://github.com/firebase/quickstart-js/issues"
-  },
-  "engines": {
-    "npm": ">=9.0.0 <=10.9.0",
-    "node": ">=18.0.0 <=22.10.0"
-  },
-  "homepage": "https://github.com/firebase/quickstart-js#readme",
-  "devDependencies": {
-    "typescript": "^5.1.6",
-    "vite": "^4.4.9"
-  },
-  "scripts": {
-    "dev": "vite",
-    "build": "vite build",
-    "format": "prettier --write ."
-  },
-  "dependencies": {
-    "firebase": "^11.1.0"
-  }
-}
diff --git a/vertexai/vite-env.d.ts b/vertexai/vite-env.d.ts
deleted file mode 100644
index 11f02fe2a..000000000
--- a/vertexai/vite-env.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-/// <reference types="vite/client" />
diff --git a/vertexai/vite.config.js b/vertexai/vite.config.js
deleted file mode 100644
index c2afa66fa..000000000
--- a/vertexai/vite.config.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { defineConfig } from 'vite';
-
-export default defineConfig({
-  base: '/',
-  build: {
-    rollupOptions: {
-      input: ['index.html'],
-    },
-  },
-});

From c8ffedaee885439f9ea990225f9d8f9a3b83e957 Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Mon, 14 Jul 2025 15:16:06 -0400
Subject: [PATCH 64/82] Add gemini-2.5-flash to Firebase AI sample app (#894)

---
 ai/ai-react-app/src/services/firebaseAIService.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ai/ai-react-app/src/services/firebaseAIService.ts b/ai/ai-react-app/src/services/firebaseAIService.ts
index 6ff24c7f7..6e24e94f3 100644
--- a/ai/ai-react-app/src/services/firebaseAIService.ts
+++ b/ai/ai-react-app/src/services/firebaseAIService.ts
@@ -19,6 +19,7 @@ export const AVAILABLE_GENERATIVE_MODELS = [
   "gemini-2.0-flash",
   "gemini-2.0-flash-lite",
   "gemini-2.0-flash-exp",
+  "gemini-2.5-flash"
 ];
 export const AVAILABLE_IMAGEN_MODELS = ["imagen-3.0-generate-002"];
 

From bdf6bdcf59e2f622beee6387daabb00c7bdd14e5 Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Mon, 14 Jul 2025 15:19:03 -0400
Subject: [PATCH 65/82] Firebase AI sample app light mode (#895)

---
 .../components/Common/FileUploader.module.css |  24 ++--
 .../components/Common/PromptInput.module.css  |  56 ++++-----
 .../Common/ResponseDisplay.module.css         |  32 ++---
 .../components/Layout/LeftSidebar.module.css  |  22 ++--
 .../components/Layout/MainLayout.module.css   |  16 +--
 .../components/Layout/RightSidebar.module.css |  74 +++++------
 .../src/components/Layout/TopBar.module.css   |  10 +-
 .../Specific/ChatMessage.module.css           |  79 +++++++++++-
 ai/ai-react-app/src/index.css                 | 117 +++++++++++++-----
 ai/ai-react-app/src/views/ChatView.module.css |  38 +++---
 .../src/views/ImagenView.module.css           |  28 ++---
 11 files changed, 308 insertions(+), 188 deletions(-)

diff --git a/ai/ai-react-app/src/components/Common/FileUploader.module.css b/ai/ai-react-app/src/components/Common/FileUploader.module.css
index cff5645e8..cc84847cc 100644
--- a/ai/ai-react-app/src/components/Common/FileUploader.module.css
+++ b/ai/ai-react-app/src/components/Common/FileUploader.module.css
@@ -7,8 +7,8 @@
 
 .uploadButton {
   background-color: transparent;
-  color: var(--fb-gray-70);
-  border: 1px dashed var(--fb-gray-40);
+  color: var(--color-text-secondary);
+  border: 1px dashed var(--color-border-secondary);
   padding: 6px 12px;
   border-radius: 4px;
   cursor: pointer;
@@ -28,21 +28,21 @@
 }
 
 .uploadButton:hover:not(:disabled) {
-  background-color: var(--fb-gray-30);
-  border-color: var(--fb-gray-50);
-  color: var(--fb-gray-90);
+  background-color: var(--color-surface-tertiary);
+  border-color: var(--brand-gray-50);
+  color: var(--color-text-primary);
 }
 
 .uploadButton:disabled {
   opacity: 0.5;
   cursor: not-allowed;
-  color: var(--fb-gray-50);
-  border-color: var(--fb-gray-40);
+  color: var(--color-text-disabled);
+  border-color: var(--color-border-secondary);
 }
 
 .clearButton {
   background-color: transparent;
-  color: var(--fb-gray-60);
+  color: var(--color-text-placeholder);
   border: none;
   padding: 0;
   width: 24px;
@@ -60,12 +60,12 @@
 }
 
 .clearButton:hover:not(:disabled) {
-  background-color: var(--fb-gray-40);
-  color: var(--fb-gray-90);
+  background-color: var(--color-surface-tertiary);
+  color: var(--color-text-primary);
 }
 
 .clearButton:disabled {
   opacity: 0.5;
   cursor: not-allowed;
-  color: var(--fb-gray-50);
-}
+  color: var(--color-text-disabled);
+}
\ No newline at end of file
diff --git a/ai/ai-react-app/src/components/Common/PromptInput.module.css b/ai/ai-react-app/src/components/Common/PromptInput.module.css
index 2f44d1977..781edcfca 100644
--- a/ai/ai-react-app/src/components/Common/PromptInput.module.css
+++ b/ai/ai-react-app/src/components/Common/PromptInput.module.css
@@ -14,9 +14,9 @@
 }
 
 .suggestionButton {
-  background-color: var(--fb-gray-30);
-  color: var(--fb-gray-80);
-  border: 1px solid var(--fb-gray-40);
+  background-color: var(--color-surface-tertiary);
+  color: var(--color-text-primary);
+  border: 1px solid var(--color-border-secondary);
   padding: 4px 10px;
   border-radius: 16px;
   cursor: pointer;
@@ -27,9 +27,9 @@
     color 0.15s ease;
 }
 .suggestionButton:hover:not(:disabled) {
-  background-color: var(--fb-gray-40);
-  border-color: var(--fb-gray-50);
-  color: var(--fb-gray-95);
+  background-color: var(--brand-gray-40);
+  border-color: var(--brand-gray-50);
+  color: var(--color-text-primary);
 }
 .suggestionButton:disabled {
   opacity: 0.5;
@@ -39,22 +39,22 @@
 .inputArea {
   display: flex;
   align-items: flex-end;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-primary);
   border-radius: 4px;
-  border: 1px solid var(--fb-gray-40);
+  border: 1px solid var(--color-border-secondary);
   padding: 4px 4px 4px 12px;
   transition: border-color 0.15s ease;
   box-sizing: border-box;
 }
 .inputArea:focus-within {
-  border-color: var(--google-blue);
+  border-color: var(--color-border-focus);
 }
 
 .promptTextarea {
   flex-grow: 1;
   background-color: transparent;
   border: none;
-  color: var(--fb-gray-90);
+  color: var(--color-text-primary);
   resize: none;
   outline: none;
   font-size: 0.875rem;
@@ -66,12 +66,12 @@
   margin-right: 8px;
 }
 .promptTextarea::placeholder {
-  color: var(--fb-gray-60);
+  color: var(--color-text-placeholder);
 }
 
 .runButton {
-  background-color: var(--google-blue);
-  color: var(--fb-gray-100);
+  background-color: var(--color-surface-interactive);
+  color: var(--color-text-on-interactive);
   border: none;
   padding: 0 16px;
   border-radius: 4px;
@@ -86,11 +86,11 @@
   flex-shrink: 0;
 }
 .runButton:hover:not(:disabled) {
-  background-color: var(--google-blue-darker);
+  background-color: var(--color-surface-interactive-hover);
 }
 .runButton:disabled {
-  background-color: var(--fb-gray-30);
-  color: var(--fb-gray-50);
+  background-color: var(--color-surface-tertiary);
+  color: var(--color-text-disabled);
   cursor: not-allowed;
 }
 
@@ -103,9 +103,9 @@
 }
 
 .countButton {
-  background-color: var(--fb-gray-30);
-  color: var(--fb-gray-80);
-  border: 1px solid var(--fb-gray-40);
+  background-color: var(--color-surface-tertiary);
+  color: var(--color-text-primary);
+  border: 1px solid var(--color-border-secondary);
   padding: 4px 10px;
   border-radius: 4px;
   cursor: pointer;
@@ -118,20 +118,20 @@
   flex-shrink: 0;
 }
 .countButton:hover:not(:disabled) {
-  background-color: var(--fb-gray-40);
-  border-color: var(--fb-gray-50);
-  color: var(--fb-gray-95);
+  background-color: var(--brand-gray-40);
+  border-color: var(--brand-gray-50);
+  color: var(--color-text-primary);
 }
 .countButton:disabled {
   opacity: 0.5;
   cursor: not-allowed;
-  background-color: var(--fb-gray-20);
-  border-color: var(--fb-gray-30);
+  background-color: var(--color-surface-secondary);
+  border-color: var(--color-border-primary);
 }
 
 .tokenCountDisplay {
   font-size: 0.8125rem;
-  color: var(--fb-gray-70);
+  color: var(--color-text-secondary);
   flex-grow: 1;
   text-align: right;
   min-height: 1.2em;
@@ -141,10 +141,10 @@
 }
 
 .tokenError {
-  color: var(--fb-error-text);
+  color: var(--color-error-text);
   font-style: italic;
 }
 .tokenPlaceholder {
-  color: var(--fb-gray-60);
+  color: var(--color-text-placeholder);
   font-style: italic;
-}
+}
\ No newline at end of file
diff --git a/ai/ai-react-app/src/components/Common/ResponseDisplay.module.css b/ai/ai-react-app/src/components/Common/ResponseDisplay.module.css
index 4e455a77c..d9877936d 100644
--- a/ai/ai-react-app/src/components/Common/ResponseDisplay.module.css
+++ b/ai/ai-react-app/src/components/Common/ResponseDisplay.module.css
@@ -1,11 +1,11 @@
 .responseContainer {
   margin: 20px 24px;
   padding: 0;
-  color: var(--fb-gray-90);
+  color: var(--color-text-primary);
 }
 
 .responseTitle {
-  color: var(--fb-gray-70);
+  color: var(--color-text-secondary);
   font-weight: 500;
   margin: 0 0 12px 0;
   padding-bottom: 0;
@@ -16,10 +16,10 @@
 }
 
 .responseOutput {
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-secondary);
   padding: 16px;
   border-radius: 4px;
-  border: 1px solid var(--fb-gray-30);
+  border: 1px solid var(--color-border-primary);
   min-height: 100px;
   margin-bottom: 16px;
   position: relative;
@@ -28,7 +28,7 @@
   font-family: "Roboto Mono", monospace;
   font-size: 0.875rem;
   line-height: 1.6;
-  color: var(--fb-gray-90);
+  color: var(--color-text-primary);
 }
 
 .responseText {
@@ -36,7 +36,7 @@
 }
 
 .placeholder {
-  color: var(--fb-gray-60);
+  color: var(--color-text-placeholder);
   font-style: italic;
 }
 
@@ -50,7 +50,7 @@
   display: flex;
   justify-content: center;
   align-items: center;
-  color: var(--fb-gray-80);
+  color: var(--brand-gray-80);
   font-style: italic;
   border-radius: 4px;
   z-index: 1;
@@ -58,20 +58,20 @@
 
 .jsonDetails {
   margin-top: 16px;
-  border: 1px solid var(--fb-gray-40);
+  border: 1px solid var(--color-border-secondary);
   border-radius: 4px;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-secondary);
 }
 
 .jsonSummary {
   padding: 8px 12px;
   cursor: pointer;
-  background-color: var(--fb-gray-10);
+  background-color: transparent;
   border-radius: 4px 4px 0 0;
-  border-bottom: 1px solid var(--fb-gray-40);
+  border-bottom: 1px solid var(--color-border-secondary);
   outline: none;
   font-size: 0.8125rem;
-  color: var(--fb-gray-80);
+  color: var(--color-text-secondary);
   font-weight: 500;
   list-style: none;
 }
@@ -79,7 +79,7 @@
   display: none;
 }
 .jsonSummary:hover {
-  background-color: var(--fb-gray-30);
+  background-color: var(--color-surface-tertiary);
 }
 
 .jsonPre {
@@ -87,11 +87,11 @@
   margin: 0;
   font-family: "Roboto Mono", monospace;
   font-size: 0.8125rem;
-  color: var(--fb-gray-90);
+  color: var(--color-text-primary);
   white-space: pre-wrap;
   word-wrap: break-word;
-  background-color: var(--fb-gray-10);
+  background-color: transparent;
   border-radius: 0 0 4px 4px;
   max-height: 400px;
   overflow: auto;
-}
+}
\ No newline at end of file
diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
index 360af63e2..893a214ee 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
@@ -11,7 +11,7 @@
 .navButton {
   background-color: transparent;
   border: none;
-  color: var(--fb-gray-70);
+  color: var(--color-text-secondary);
   padding: 8px 12px;
   text-align: left;
   width: 100%;
@@ -25,29 +25,29 @@
 }
 
 .navButton:hover {
-  background-color: var(--fb-gray-30);
-  color: var(--fb-gray-95);
+  background-color: var(--color-surface-tertiary);
+  color: var(--color-text-primary);
 }
 
 .navButton.active {
-  background-color: var(--fb-gray-30);
-  color: var(--fb-yellow);
+  background-color: var(--color-surface-tertiary);
+  color: var(--color-text-accent);
   font-weight: 500;
 }
 
 .navButton.active:hover {
-  background-color: var(--fb-gray-40);
+  background-color: var(--brand-gray-40);
 }
 
 .backendSelector {
   margin-top: 24px;
   padding: 0 12px;
-  border-top: 1px solid var(--fb-gray-30);
+  border-top: 1px solid var(--color-border-primary);
   padding-top: 16px;
 }
 
 .selectorTitle {
-  color: var(--fb-gray-70);
+  color: var(--color-text-secondary);
   font-size: 0.75rem;
   font-weight: 500;
   margin: 0 0 8px 0;
@@ -63,11 +63,11 @@
   display: flex;
   align-items: center;
   font-size: 0.875rem;
-  color: var(--fb-gray-80);
+  color: var(--color-text-primary);
   cursor: pointer;
 }
 
 .radioGroup input[type="radio"] {
   margin-right: 8px;
-  accent-color: var(--google-blue);
-}
+  accent-color: var(--brand-google-blue);
+}
\ No newline at end of file
diff --git a/ai/ai-react-app/src/components/Layout/MainLayout.module.css b/ai/ai-react-app/src/components/Layout/MainLayout.module.css
index 6a9ce4b3e..9ba5f39f3 100644
--- a/ai/ai-react-app/src/components/Layout/MainLayout.module.css
+++ b/ai/ai-react-app/src/components/Layout/MainLayout.module.css
@@ -2,8 +2,8 @@
   display: flex;
   flex-direction: column;
   height: 100vh;
-  background-color: var(--fb-gray-10);
-  color: var(--fb-gray-90);
+  background-color: var(--color-surface-primary);
+  color: var(--color-text-primary);
   overflow: hidden;
 }
 
@@ -16,15 +16,15 @@
 .leftSidebar {
   width: 240px;
   flex-shrink: 0;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-primary);
   padding-top: 16px;
   overflow-y: auto;
-  border-right: 1px solid var(--fb-gray-30);
+  border-right: 1px solid var(--color-border-primary);
 }
 
 .centerContent {
   flex-grow: 1;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-primary);
   display: flex;
   flex-direction: column;
   overflow-y: auto;
@@ -33,7 +33,7 @@
 .rightSidebar {
   width: 300px;
   flex-shrink: 0;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-primary);
   overflow-y: auto;
-  border-left: 1px solid var(--fb-gray-30);
-}
+  border-left: 1px solid var(--color-border-primary);
+}
\ No newline at end of file
diff --git a/ai/ai-react-app/src/components/Layout/RightSidebar.module.css b/ai/ai-react-app/src/components/Layout/RightSidebar.module.css
index 044e1b2ee..cd98fb8bf 100644
--- a/ai/ai-react-app/src/components/Layout/RightSidebar.module.css
+++ b/ai/ai-react-app/src/components/Layout/RightSidebar.module.css
@@ -1,28 +1,28 @@
 .rightSidebarContainer {
   padding: 24px;
-  color: var(--fb-gray-90);
+  color: var(--color-text-primary);
   height: 100%;
   display: flex;
   flex-direction: column;
   gap: 16px;
   font-size: 0.875rem;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-primary);
   overflow-y: auto;
 }
 
 .sectionTitle {
-  color: var(--fb-gray-80);
+  color: var(--color-text-primary);
   font-weight: 500;
   margin: 0 0 16px 0;
   padding-bottom: 12px;
-  border-bottom: 1px solid var(--fb-gray-30);
+  border-bottom: 1px solid var(--color-border-primary);
   font-size: 0.9rem;
   text-transform: uppercase;
   letter-spacing: 0.5px;
 }
 
 .subSectionTitle {
-  color: var(--fb-gray-70);
+  color: var(--color-text-secondary);
   font-weight: 500;
   margin: 16px 0 12px 0;
   font-size: 0.8125rem;
@@ -37,7 +37,7 @@
 .controlGroup label {
   display: block;
   margin-bottom: 8px;
-  color: var(--fb-gray-70);
+  color: var(--color-text-secondary);
   font-size: 0.8125rem;
   font-weight: 500;
 }
@@ -48,9 +48,9 @@
 .controlGroup textarea {
   width: 100%;
   padding: 8px 12px;
-  background-color: var(--fb-gray-10);
-  border: 1px solid var(--fb-gray-40);
-  color: var(--fb-gray-90);
+  background-color: var(--color-surface-primary);
+  border: 1px solid var(--color-border-secondary);
+  color: var(--color-text-primary);
   border-radius: 4px;
   box-sizing: border-box;
   font-size: 0.875rem;
@@ -61,18 +61,18 @@
 .controlGroup select:hover,
 .controlGroup input:not([type="range"]):hover,
 .controlGroup textarea:hover {
-  border-color: var(--fb-gray-50);
+  border-color: var(--brand-gray-50);
 }
 .controlGroup select:focus,
 .controlGroup input:not([type="range"]):focus,
 .controlGroup textarea:focus {
-  border-color: var(--google-blue);
-  background-color: var(--fb-gray-10);
+  border-color: var(--color-border-focus);
+  background-color: var(--color-surface-primary);
   outline: none;
 }
 .controlGroup input:-webkit-autofill {
-  -webkit-box-shadow: 0 0 0 30px var(--fb-gray-10) inset !important;
-  -webkit-text-fill-color: var(--fb-gray-90) !important;
+  -webkit-box-shadow: 0 0 0 30px var(--color-surface-primary) inset !important;
+  -webkit-text-fill-color: var(--color-text-primary) !important;
 }
 
 .controlGroup input[type="range"] {
@@ -80,7 +80,7 @@
   height: 4px;
   cursor: pointer;
   appearance: none;
-  background: var(--fb-gray-40);
+  background: var(--color-border-secondary);
   outline: none;
   border-radius: 2px;
   padding: 0;
@@ -90,23 +90,23 @@
   appearance: none;
   width: 14px;
   height: 14px;
-  background: var(--fb-gray-80);
+  background: var(--color-text-primary);
   border-radius: 50%;
   cursor: pointer;
 }
 .controlGroup input[type="range"]::-moz-range-thumb {
   width: 14px;
   height: 14px;
-  background: var(--fb-gray-80);
+  background: var(--color-text-primary);
   border-radius: 50%;
   cursor: pointer;
   border: none;
 }
 .controlGroup input[type="range"]:active::-webkit-slider-thumb {
-  background: var(--fb-gray-90);
+  background: var(--brand-gray-90);
 }
 .controlGroup input[type="range"]:active::-moz-range-thumb {
-  background: var(--fb-gray-90);
+  background: var(--brand-gray-90);
 }
 
 .controlGroup textarea {
@@ -117,17 +117,17 @@
 .temperatureDisplay {
   text-align: right;
   font-size: 0.8125rem;
-  color: var(--fb-gray-60);
+  color: var(--color-text-placeholder);
   margin-top: 6px;
 }
 
 .tokenDisplay {
-  background-color: var(--fb-gray-10);
-  border: 1px solid var(--fb-gray-40);
+  background-color: var(--color-surface-primary);
+  border: 1px solid var(--color-border-secondary);
   padding: 8px 12px;
   border-radius: 4px;
   font-size: 0.8125rem;
-  color: var(--fb-gray-70);
+  color: var(--color-text-secondary);
   text-align: right;
   font-family: "Roboto Mono", monospace;
 }
@@ -140,7 +140,7 @@
   min-height: 30px;
 }
 .toggleGroup label:first-child {
-  color: var(--fb-gray-70);
+  color: var(--color-text-secondary);
   font-size: 0.875rem;
   padding-right: 10px;
 }
@@ -166,7 +166,7 @@
   left: 0;
   right: 0;
   bottom: 0;
-  background-color: var(--fb-gray-40);
+  background-color: var(--color-border-secondary);
   transition: 0.2s;
   border-radius: 7px;
 }
@@ -178,33 +178,33 @@
   width: 20px;
   left: -2px;
   bottom: -3px;
-  background-color: var(--fb-gray-80);
+  background-color: var(--color-text-primary);
   transition: 0.2s;
   border-radius: 50%;
   box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
 }
 
 input:checked + .slider {
-  background-color: var(--google-blue);
+  background-color: var(--brand-google-blue);
 }
 
 input:checked + .slider:before {
   transform: translateX(20px);
-  background-color: var(--fb-gray-95);
+  background-color: var(--brand-gray-100);
 }
 
 .toggleGroup input:disabled + .slider {
-  background-color: var(--fb-gray-30) !important;
+  background-color: var(--color-border-primary) !important;
   cursor: not-allowed;
 }
 .toggleGroup input:disabled + .slider:before {
-  background-color: var(--fb-gray-50) !important;
+  background-color: var(--color-text-disabled) !important;
   cursor: not-allowed;
   box-shadow: none;
 }
 .toggleGroup.disabledText label:first-child,
 .toggleGroup label input:disabled ~ span {
-  color: var(--fb-gray-50);
+  color: var(--color-text-disabled);
   cursor: not-allowed;
 }
 .toggleGroup input:disabled ~ span {
@@ -221,13 +221,13 @@ input:checked + .slider:before {
   cursor: pointer;
   outline: none;
   font-weight: 500;
-  color: var(--fb-gray-70);
+  color: var(--color-text-secondary);
   font-size: 0.875rem;
   list-style: none;
   position: relative;
 }
 .advancedSettings summary:hover {
-  color: var(--fb-gray-90);
+  color: var(--color-text-primary);
 }
 .advancedSettings summary::-webkit-details-marker {
   display: none;
@@ -238,7 +238,7 @@ input:checked + .slider:before {
   margin-right: 8px;
   font-size: 0.7em;
   transition: transform 0.2s ease-out;
-  color: var(--fb-gray-60);
+  color: var(--color-text-placeholder);
 }
 .advancedSettings details[open] summary::before {
   transform: rotate(90deg);
@@ -246,10 +246,10 @@ input:checked + .slider:before {
 
 .advancedSettings .advancedContent {
   padding: 16px 0 0 0;
-  border-top: 1px solid var(--fb-gray-30);
+  border-top: 1px solid var(--color-border-primary);
   margin-top: 8px;
 }
 .advancedSettings .controlGroup label {
   font-weight: 400;
-  color: var(--fb-gray-70);
-}
+  color: var(--color-text-secondary);
+}
\ No newline at end of file
diff --git a/ai/ai-react-app/src/components/Layout/TopBar.module.css b/ai/ai-react-app/src/components/Layout/TopBar.module.css
index ad4804e69..5be38c666 100644
--- a/ai/ai-react-app/src/components/Layout/TopBar.module.css
+++ b/ai/ai-react-app/src/components/Layout/TopBar.module.css
@@ -4,9 +4,9 @@
   align-items: center;
   height: 50px;
   padding: 0 24px;
-  background-color: var(--fb-gray-10);
-  border-bottom: 1px solid var(--fb-gray-30);
-  color: var(--fb-gray-90);
+  background-color: var(--color-surface-primary);
+  border-bottom: 1px solid var(--color-border-primary);
+  color: var(--color-text-primary);
   flex-shrink: 0;
 }
 
@@ -25,5 +25,5 @@
 .title {
   font-size: 1rem;
   font-weight: 500;
-  color: var(--fb-gray-80);
-}
+  color: var(--color-text-secondary);
+}
\ No newline at end of file
diff --git a/ai/ai-react-app/src/components/Specific/ChatMessage.module.css b/ai/ai-react-app/src/components/Specific/ChatMessage.module.css
index 6adb2ff8c..041f38b68 100644
--- a/ai/ai-react-app/src/components/Specific/ChatMessage.module.css
+++ b/ai/ai-react-app/src/components/Specific/ChatMessage.module.css
@@ -27,16 +27,16 @@
 }
 
 .messageContainer.user .messageBubble {
-  background-color: var(--fb-gray-40);
-  color: var(--fb-gray-95);
-  border-color: var(--fb-gray-50);
+  background-color: var(--brand-google-blue);
+  color: var(--color-text-on-interactive);
+  border-color: var(--brand-google-blue-darker);
   border-bottom-right-radius: 4px;
 }
 
 .messageContainer.model .messageBubble {
-  background-color: var(--fb-gray-10);
-  color: var(--fb-gray-90);
-  border-color: var(--fb-gray-30);
+  background-color: var(--color-surface-secondary);
+  color: var(--color-text-primary);
+  border-color: var(--color-border-primary);
   border-bottom-left-radius: 4px;
 }
 
@@ -47,3 +47,70 @@
   white-space: pre-wrap;
   word-wrap: break-word;
 }
+
+.sourcesSection {
+  margin-top: 10px;
+  padding-top: 8px;
+  border-top: 1px solid var(--color-border-secondary);
+  font-size: 0.8rem;
+}
+
+.searchEntryPoint {
+  margin-bottom: 8px;
+}
+.searchEntryPoint p {
+  margin: 0 0 4px 0;
+}
+.searchEntryPoint a {
+  color: var(--brand-google-blue);
+  text-decoration: none;
+}
+.searchEntryPoint a:hover {
+  text-decoration: underline;
+}
+
+.sourcesTitle {
+  font-weight: 500;
+  color: var(--color-text-secondary);
+  margin: 0 0 4px 0;
+  font-size: 0.8rem;
+}
+
+.sourcesList {
+  list-style: none;
+  padding-left: 0;
+  margin: 0;
+}
+
+.sourceItem {
+  margin-bottom: 4px;
+}
+
+.sourceItem a {
+  color: var(--brand-google-blue);
+  text-decoration: none;
+  word-break: break-all;
+}
+
+.sourceItem a:hover {
+  text-decoration: underline;
+}
+
+.highlightedSegment {
+  background-color: rgba(
+    var(--google-blue-rgb),
+    0.15
+  );
+  padding: 1px 0;
+  border-radius: 2px;
+  cursor: default;
+}
+
+.sourceSuperscript {
+  font-size: 0.7em;
+  vertical-align: super;
+  color: var(--brand-google-blue);
+  margin-left: 2px;
+  font-weight: bold;
+  user-select: none;
+}
diff --git a/ai/ai-react-app/src/index.css b/ai/ai-react-app/src/index.css
index 051b3a985..c05c0becc 100644
--- a/ai/ai-react-app/src/index.css
+++ b/ai/ai-react-app/src/index.css
@@ -1,33 +1,56 @@
 :root {
-  --fb-gray-0: #000000;
-  --fb-gray-10: #121212;
-  --fb-gray-20: #303030;
-  --fb-gray-30: #474747;
-  --fb-gray-40: #5e5e5e;
-  --fb-gray-50: #757575;
-  --fb-gray-60: #8f8f8f;
-  --fb-gray-70: #ababab;
-  --fb-gray-80: #c7c7c7;
-  --fb-gray-90: #e3e3e3;
-  --fb-gray-95: #f2f2f2;
-  --fb-gray-99: #fdfcfb;
-  --fb-gray-100: #ffffff;
-
-  --fb-yellow: #ffc400;
-  --fb-orange: #ff9100;
-  --fb-red: #dd2c00;
-
-  --google-blue: #4285f4;
-  --google-blue-darker: #1b66c9;
-  --google-blue-focus: #8ab4f8;
-
-  --fb-error-bg: rgba(221, 44, 0, 0.1);
-  --fb-error-text: #f79489;
-  --fb-error-border: rgba(221, 44, 0, 0.4);
-
-  --fb-warning-bg: rgba(255, 145, 0, 0.1);
-  --fb-warning-text: #ffcc80;
-  --fb-warning-border: rgba(255, 145, 0, 0.4);
+  --brand-gray-0: #000000;
+  --brand-gray-10: #1f1f1f;
+  --brand-gray-20: #303030;
+  --brand-gray-30: #474747;
+  --brand-gray-40: #5e5e5e;
+  --brand-gray-50: #757575;
+  --brand-gray-60: #8f8f8f;
+  --brand-gray-70: #ababab;
+  --brand-gray-80: #c7c7c7;
+  --brand-gray-90: #e3e3e3;
+  --brand-gray-95: #f2f2f2;
+  --brand-gray-99: #fdfcfb;
+  --brand-gray-100: #ffffff;
+
+  --brand-firebase-yellow: #ffc400;
+  --brand-firebase-orange: #ff9100;
+  --brand-firebase-red: #dd2c00;
+  --brand-android-green: #c6ff00;
+  --brand-gemini-pink: #fdadee;
+  --brand-google-blue: #4285f4;
+  --brand-google-blue-darker: #1b66c9;
+  --brand-google-blue-focus: #8ab4f8;
+  --brand-google-cloud-green: #34a853;
+
+  /* Surfaces */
+  --color-surface-primary: var(--brand-gray-10); /* Main page background */
+  --color-surface-secondary: var(--brand-gray-20); /* Cards, message bubbles */
+  --color-surface-tertiary: var(--brand-gray-30); /* Hover states, subtle backgrounds */
+  --color-surface-interactive: var(--brand-google-blue); /* Primary buttons */
+  --color-surface-interactive-hover: var(--brand-google-blue-darker);
+
+  /* Text */
+  --color-text-primary: var(--brand-gray-90); /* Main text */
+  --color-text-secondary: var(--brand-gray-70); /* Sub-headings, labels */
+  --color-text-placeholder: var(--brand-gray-60);
+  --color-text-disabled: var(--brand-gray-50);
+  --color-text-on-interactive: var(--brand-gray-100); /* Text on blue buttons */
+  --color-text-accent: var(--brand-firebase-yellow); /* Active nav item */
+
+  /* Borders */
+  --color-border-primary: var(--brand-gray-30);
+  --color-border-secondary: var(--brand-gray-40);
+  --color-border-focus: var(--brand-google-blue);
+
+  /* States */
+  --color-error-bg: rgba(221, 44, 0, 0.2);
+  --color-error-text: #f28b82;
+  --color-error-border: rgba(221, 44, 0, 0.5);
+
+  --color-warning-bg: rgba(255, 145, 0, 0.2);
+  --color-warning-text: #ffd180;
+  --color-warning-border: rgba(255, 145, 0, 0.5);
 }
 
 *,
@@ -38,14 +61,15 @@
 
 html,
 body {
+  color-scheme: light dark;
   margin: 0;
   padding: 0;
   height: 100%;
 }
 
 body {
-  background-color: var(--fb-gray-10);
-  color: var(--fb-gray-90);
+  background-color: var(--color-surface-primary);
+  color: var(--color-text-primary);
   font-family:
     "Roboto",
     -apple-system,
@@ -72,7 +96,7 @@ body {
 }
 
 *:focus-visible {
-  outline: 2px solid var(--google-blue-focus);
+  outline: 2px solid var(--brand-google-blue-focus);
   outline-offset: 1px;
 }
 
@@ -85,3 +109,32 @@ textarea {
   font-weight: inherit;
   color: inherit;
 }
+
+@media (prefers-color-scheme: light) {
+  :root {
+    /* Surfaces */
+    --color-surface-primary: var(--brand-gray-100);
+    --color-surface-secondary: var(--brand-gray-95);
+    --color-surface-tertiary: var(--brand-gray-90);
+    --color-surface-interactive-hover: #185abc;
+
+    /* Text */
+    --color-text-primary: var(--brand-gray-40);
+    --color-text-secondary: var(--brand-gray-50);
+    --color-text-placeholder: var(--brand-gray-60);
+    --color-text-disabled: var(--brand-gray-70);
+
+    /* Borders */
+    --color-border-primary: var(--brand-gray-80);
+    --color-border-secondary: var(--brand-gray-90);
+
+    /* States */
+    --color-error-bg: #fce8e6;
+    --color-error-text: #c5221f;
+    --color-error-border: #f9ab9f;
+
+    --color-warning-bg: #fff0e2;
+    --color-warning-text: #b06000;
+    --color-warning-border: #fdd6b4;
+  }
+}
\ No newline at end of file
diff --git a/ai/ai-react-app/src/views/ChatView.module.css b/ai/ai-react-app/src/views/ChatView.module.css
index b14f84165..3cd62863f 100644
--- a/ai/ai-react-app/src/views/ChatView.module.css
+++ b/ai/ai-react-app/src/views/ChatView.module.css
@@ -2,7 +2,7 @@
   display: flex;
   flex-direction: column;
   height: 100%;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-primary);
 }
 
 .chatHistory {
@@ -16,7 +16,7 @@
 
 .emptyChat {
   text-align: center;
-  color: var(--fb-gray-60);
+  color: var(--color-text-placeholder);
   margin-top: 40px;
   font-style: italic;
 }
@@ -29,8 +29,8 @@
   padding: 8px 14px;
   border-radius: 16px;
   border-bottom-left-radius: 4px;
-  background-color: var(--fb-gray-10);
-  border: 1px solid var(--fb-gray-30);
+  background-color: var(--color-surface-secondary);
+  border: 1px solid var(--color-border-primary);
   align-items: center;
   min-height: 1em;
 }
@@ -38,7 +38,7 @@
   display: inline-block;
   width: 6px;
   height: 6px;
-  background-color: var(--fb-gray-60);
+  background-color: var(--color-text-placeholder);
   border-radius: 50%;
   margin: 0 2px;
   animation: bounce 1.4s infinite ease-in-out both;
@@ -66,9 +66,9 @@
 }
 
 .errorMessage {
-  background-color: var(--fb-error-bg);
-  color: var(--fb-error-text);
-  border: 1px solid var(--fb-error-border);
+  background-color: var(--color-error-bg);
+  color: var(--color-error-text);
+  border: 1px solid var(--color-error-border);
   padding: 10px 16px;
   border-radius: 4px;
   margin: 10px 0;
@@ -79,9 +79,9 @@
 .jsonDetails {
   margin-top: 4px;
   margin-bottom: 8px;
-  border: 1px solid var(--fb-gray-40);
+  border: 1px solid var(--color-border-secondary);
   border-radius: 4px;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-secondary);
   max-width: 80%;
   margin-left: 0;
   margin-right: auto;
@@ -89,11 +89,11 @@
 .jsonSummary {
   padding: 6px 12px;
   cursor: pointer;
-  background-color: var(--fb-gray-10);
-  border-bottom: 1px solid var(--fb-gray-40);
+  background-color: transparent;
+  border-bottom: 1px solid var(--color-border-secondary);
   outline: none;
   font-size: 0.8125rem;
-  color: var(--fb-gray-80);
+  color: var(--color-text-secondary);
   font-weight: 500;
   list-style: none;
 }
@@ -101,17 +101,17 @@
   display: none;
 }
 .jsonSummary:hover {
-  background-color: var(--fb-gray-30);
+  background-color: var(--color-surface-tertiary);
 }
 .jsonDetails pre {
   padding: 12px 16px;
   margin: 0;
   font-family: "Roboto Mono", monospace;
   font-size: 0.8125rem;
-  color: var(--fb-gray-90);
+  color: var(--color-text-primary);
   white-space: pre-wrap;
   word-wrap: break-word;
-  background-color: var(--fb-gray-10);
+  background-color: transparent;
   border-radius: 0 0 4px 4px;
   max-height: 300px;
   overflow: auto;
@@ -119,8 +119,8 @@
 
 .inputAreaContainer {
   flex-shrink: 0;
-  background-color: var(--fb-gray-10);
-  border-top: 1px solid var(--fb-gray-30);
+  background-color: var(--color-surface-primary);
+  border-top: 1px solid var(--color-border-primary);
   padding: 16px 24px;
   display: flex;
   flex-direction: column;
@@ -129,4 +129,4 @@
 
 .fileUploaderContainer {
   max-width: 250px;
-}
+}
\ No newline at end of file
diff --git a/ai/ai-react-app/src/views/ImagenView.module.css b/ai/ai-react-app/src/views/ImagenView.module.css
index d6e878620..a1f2c7243 100644
--- a/ai/ai-react-app/src/views/ImagenView.module.css
+++ b/ai/ai-react-app/src/views/ImagenView.module.css
@@ -2,15 +2,15 @@
   display: flex;
   flex-direction: column;
   height: 100%;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-primary);
 }
 
 .errorMessage {
-  color: var(--fb-error-text);
+  color: var(--color-error-text);
   margin: 10px 24px;
   padding: 10px 16px;
-  background-color: var(--fb-error-bg);
-  border: 1px solid var(--fb-error-border);
+  background-color: var(--color-error-bg);
+  border: 1px solid var(--color-error-border);
   border-radius: 4px;
   white-space: pre-wrap;
   font-size: 0.875rem;
@@ -35,8 +35,8 @@
     border-right: none;
     border-bottom: none;
     box-shadow: none;
-    border-top: 1px solid var(--fb-gray-30);
-    background-color: var(--fb-gray-10);
+    border-top: 1px solid var(--color-border-primary);
+    background-color: var(--color-surface-primary);
   }
 }
 
@@ -49,7 +49,7 @@
   flex-direction: column;
   align-items: center;
   justify-content: center;
-  color: var(--fb-gray-90);
+  color: var(--color-text-primary);
   width: 100%;
   flex-grow: 1;
 }
@@ -57,14 +57,14 @@
 .loading,
 .placeholder {
   font-style: italic;
-  color: var(--fb-gray-60);
+  color: var(--color-text-placeholder);
   margin: 20px 0;
 }
 
 .filteredReason {
-  color: var(--fb-warning-text);
-  background-color: var(--fb-warning-bg);
-  border: 1px solid var(--fb-warning-border);
+  color: var(--color-warning-text);
+  background-color: var(--color-warning-bg);
+  border: 1px solid var(--color-warning-border);
   padding: 8px 16px;
   border-radius: 4px;
   margin-bottom: 16px;
@@ -86,9 +86,9 @@
 }
 
 .imageWrapper {
-  border: 1px solid var(--fb-gray-30);
+  border: 1px solid var(--color-border-primary);
   padding: 4px;
-  background-color: var(--fb-gray-10);
+  background-color: var(--color-surface-primary);
   border-radius: 4px;
   box-sizing: border-box;
   display: flex;
@@ -102,4 +102,4 @@
   height: auto;
   display: block;
   border-radius: 2px;
-}
+}
\ No newline at end of file

From c83605f2ad1e2a88b9484f838063162d4736210a Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Mon, 14 Jul 2025 15:21:24 -0400
Subject: [PATCH 66/82] Fix Firebase CLI command in Firestore quickstart (#801)

---
 firestore/README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/firestore/README.md b/firestore/README.md
index 8d6b756b7..6b8eb5482 100644
--- a/firestore/README.md
+++ b/firestore/README.md
@@ -82,7 +82,7 @@ Follow these steps to have a working version of the quickstart running with the
  7. Set the CLI to use the project you created in Step 1:
 
  ```bash
- firebase --use add
+ firebase use --add
  ```
 
  8. Serve your Angular app and see it connect to the Firebase Console by opening [http://localhost:4200](http://localhost:4200) in your browser!

From 4b985969eeac22f643d8d60ad52363be90502eb1 Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Tue, 29 Jul 2025 09:52:37 -0500
Subject: [PATCH 67/82] Add grounding with Google Search example to Firebase AI
 sample app (#892)

---
 .../src/components/Layout/RightSidebar.tsx    |  58 +++++-
 .../Specific/ChatMessage.module.css           |   2 +-
 .../src/components/Specific/ChatMessage.tsx   | 168 +++++++++++++++++-
 ai/ai-react-app/src/config/firebase-config.ts |   2 +-
 .../src/services/firebaseAIService.ts         |   5 +
 ai/ai-react-app/src/views/ChatView.tsx        |  32 +++-
 6 files changed, 249 insertions(+), 18 deletions(-)

diff --git a/ai/ai-react-app/src/components/Layout/RightSidebar.tsx b/ai/ai-react-app/src/components/Layout/RightSidebar.tsx
index 9c296c9b6..9e703ee35 100644
--- a/ai/ai-react-app/src/components/Layout/RightSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/RightSidebar.tsx
@@ -5,6 +5,7 @@ import {
   AVAILABLE_GENERATIVE_MODELS,
   AVAILABLE_IMAGEN_MODELS,
   defaultFunctionCallingTool,
+  defaultGoogleSearchTool,
 } from "../../services/firebaseAIService";
 import {
   ModelParams,
@@ -158,6 +159,19 @@ const RightSidebar: React.FC<RightSidebarProps> = ({
           nextState.tools = undefined;
           nextState.toolConfig = undefined; // Clear config when turning off
         }
+      } else if (name === "google-search-toggle") {
+        if (checked) {
+          // Turn ON Google Search Grounding
+          nextState.tools = [defaultGoogleSearchTool];
+
+          // Turn OFF JSON mode and Function Calling
+          nextState.generationConfig.responseMimeType = undefined;
+          nextState.generationConfig.responseSchema = undefined;
+          nextState.toolConfig = undefined;
+        } else {
+          // Turn OFF Google Search Grounding
+          nextState.tools = undefined;
+        }
       }
       console.log("[RightSidebar] Updated generative params state:", nextState);
       return nextState;
@@ -219,6 +233,9 @@ const RightSidebar: React.FC<RightSidebarProps> = ({
       generativeParams.toolConfig?.functionCallingConfig?.mode ===
         FunctionCallingMode.ANY) &&
     !!generativeParams.tools?.length;
+  const isGroundingWithGoogleSearchActive = !!generativeParams.tools?.some(
+    (tool) => "googleSearch" in tool,
+  );
 
   return (
     <div className={styles.rightSidebarContainer}>
@@ -360,15 +377,17 @@ const RightSidebar: React.FC<RightSidebarProps> = ({
                   name="structured-output-toggle"
                   checked={isStructuredOutputActive}
                   onChange={handleToggleChange}
-                  disabled={isFunctionCallingActive}
+                  disabled={
+                    isFunctionCallingActive || isGroundingWithGoogleSearchActive
+                  }
                 />
                 <span
-                  className={`${styles.slider} ${isFunctionCallingActive ? styles.disabled : ""}`}
+                  className={`${styles.slider} ${isFunctionCallingActive || isGroundingWithGoogleSearchActive ? styles.disabled : ""}`}
                 ></span>
               </label>
             </div>
             <div
-              className={`${styles.toggleGroup} ${isStructuredOutputActive ? styles.disabledText : ""}`}
+              className={`${styles.toggleGroup} ${isStructuredOutputActive || isGroundingWithGoogleSearchActive ? styles.disabledText : ""}`}
             >
               <label htmlFor="function-call-toggle">Function calling</label>
               <label className={styles.switch}>
@@ -378,13 +397,44 @@ const RightSidebar: React.FC<RightSidebarProps> = ({
                   name="function-call-toggle"
                   checked={isFunctionCallingActive}
                   onChange={handleToggleChange}
-                  disabled={isStructuredOutputActive}
+                  disabled={
+                    isStructuredOutputActive ||
+                    isGroundingWithGoogleSearchActive
+                  }
                 />
                 <span
                   className={`${styles.slider} ${isStructuredOutputActive ? styles.disabled : ""}`}
                 ></span>
               </label>
             </div>
+            <div
+              className={`${styles.toggleGroup} ${
+                isStructuredOutputActive || isFunctionCallingActive
+                  ? styles.disabledText
+                  : ""
+              }`}
+            >
+              <label htmlFor="google-search-toggle">
+                Grounding with Google Search
+              </label>
+              <label className={styles.switch}>
+                <input
+                  type="checkbox"
+                  id="google-search-toggle"
+                  name="google-search-toggle"
+                  checked={isGroundingWithGoogleSearchActive}
+                  onChange={handleToggleChange}
+                  disabled={isStructuredOutputActive || isFunctionCallingActive}
+                />
+                <span
+                  className={`${styles.slider} ${
+                    isStructuredOutputActive || isFunctionCallingActive
+                      ? styles.disabled
+                      : ""
+                  }`}
+                ></span>
+              </label>
+            </div>
           </div>
         </>
       )}
diff --git a/ai/ai-react-app/src/components/Specific/ChatMessage.module.css b/ai/ai-react-app/src/components/Specific/ChatMessage.module.css
index 041f38b68..d5f72d3b7 100644
--- a/ai/ai-react-app/src/components/Specific/ChatMessage.module.css
+++ b/ai/ai-react-app/src/components/Specific/ChatMessage.module.css
@@ -109,7 +109,7 @@
 .sourceSuperscript {
   font-size: 0.7em;
   vertical-align: super;
-  color: var(--brand-google-blue);
+  color: var(--google-blue);
   margin-left: 2px;
   font-weight: bold;
   user-select: none;
diff --git a/ai/ai-react-app/src/components/Specific/ChatMessage.tsx b/ai/ai-react-app/src/components/Specific/ChatMessage.tsx
index 6d0f94a49..6c10f4fa4 100644
--- a/ai/ai-react-app/src/components/Specific/ChatMessage.tsx
+++ b/ai/ai-react-app/src/components/Specific/ChatMessage.tsx
@@ -1,9 +1,23 @@
 import React from "react";
-import { Content } from "firebase/ai";
+import {
+  Content,
+  GroundingChunk,
+  GroundingMetadata,
+  GroundingSupport,
+} from "firebase/ai";
 import styles from "./ChatMessage.module.css";
 
 interface ChatMessageProps {
+  /** The message content object containing role and parts. */
   message: Content;
+  groundingMetadata?: GroundingMetadata | null;
+}
+
+interface ProcessedSegment {
+  startIndex: number;
+  endIndex: number;
+  chunkIndices: number[]; // 1-based for display
+  originalSupportIndex: number; // To link back if needed
 }
 
 /**
@@ -23,13 +37,96 @@ const getMessageText = (message: Content): string => {
     .join("");
 };
 
+const renderTextWithInlineHighlighting = (
+  text: string,
+  supports: GroundingSupport[],
+  chunks: GroundingChunk[],
+): React.ReactNode[] => {
+  if (!supports || supports.length === 0 || !text) {
+    return [text];
+  }
+
+  const segmentsToHighlight: ProcessedSegment[] = [];
+
+  supports.forEach((support, supportIndex) => {
+    if (support.segment && support.groundingChunkIndices) {
+      const segment = support.segment;
+      if (segment.partIndex === undefined || segment.partIndex === 0) {
+        segmentsToHighlight.push({
+          startIndex: segment.startIndex,
+          endIndex: segment.endIndex, // API's endIndex is typically exclusive
+          chunkIndices: support.groundingChunkIndices.map((ci) => ci + 1), // 1-based
+          originalSupportIndex: supportIndex,
+        });
+      }
+    }
+  });
+
+  if (segmentsToHighlight.length === 0) {
+    return [text];
+  }
+
+  // Sort segments by start index, then by end index
+  segmentsToHighlight.sort((a, b) => {
+    if (a.startIndex !== b.startIndex) {
+      return a.startIndex - b.startIndex;
+    }
+    return b.endIndex - a.endIndex; // Longer segments first
+  });
+
+  const outputNodes: React.ReactNode[] = [];
+  let lastIndexProcessed = 0;
+
+  segmentsToHighlight.forEach((seg, i) => {
+    // Add un-highlighted text before this segment
+    if (seg.startIndex > lastIndexProcessed) {
+      outputNodes.push(text.substring(lastIndexProcessed, seg.startIndex));
+    }
+
+    // Add the highlighted segment
+    // Ensure we don't re-highlight an already covered portion if a shorter segment comes later
+    const currentSegmentText = text.substring(seg.startIndex, seg.endIndex);
+    const tooltipText = seg.chunkIndices
+      .map((ci) => {
+        const chunk = chunks[ci - 1]; // ci is 1-based
+        return chunk.web?.title || chunk.web?.uri || `Source ${ci}`;
+      })
+      .join("; ");
+
+    outputNodes.push(
+      <span
+        key={`seg-${i}`}
+        className={styles.highlightedSegment}
+        title={`Sources: ${tooltipText}`}
+        data-source-indices={seg.chunkIndices.join(",")}
+      >
+        {currentSegmentText}
+        <sup className={styles.sourceSuperscript}>
+          [{seg.chunkIndices.join(",")}]
+        </sup>
+      </span>,
+    );
+    lastIndexProcessed = Math.max(lastIndexProcessed, seg.endIndex);
+  });
+
+  // Add any remaining un-highlighted text
+  if (lastIndexProcessed < text.length) {
+    outputNodes.push(text.substring(lastIndexProcessed));
+  }
+
+  return outputNodes;
+};
+
 /**
  * Renders a single chat message bubble, styled based on the message role ('user' or 'model').
  * It only renders messages that should be visible in the log (user messages, or model messages
  * containing text). Function role messages or model messages consisting only of function calls
  * are typically not rendered directly as chat bubbles.
  */
-const ChatMessage: React.FC<ChatMessageProps> = ({ message }) => {
+const ChatMessage: React.FC<ChatMessageProps> = ({
+  message,
+  groundingMetadata,
+}) => {
   const text = getMessageText(message);
   const isUser = message.role === "user";
   const isModel = message.role === "model";
@@ -41,20 +138,79 @@ const ChatMessage: React.FC<ChatMessageProps> = ({ message }) => {
   // 1. 'function' role messages (these represent execution results, not direct chat).
   // 2. 'model' role messages that *only* contain function calls (these are instructions, not display text).
   // 3. 'system' role messages (handled separately, not usually in chat history display).
-  const shouldRender = isUser || (isModel && text.trim() !== "");
+  const shouldRender =
+    isUser ||
+    (isModel && text.trim() !== "");
 
   if (!shouldRender) {
     return null;
   }
 
+  let messageContentNodes: React.ReactNode[];
+  if (
+    isModel &&
+    groundingMetadata?.groundingSupports &&
+    groundingMetadata?.groundingChunks
+  ) {
+    messageContentNodes = renderTextWithInlineHighlighting(
+      text,
+      groundingMetadata.groundingSupports,
+      groundingMetadata.groundingChunks,
+    );
+  } else {
+    messageContentNodes = [text];
+  }
+
   return (
     <div
       className={`${styles.messageContainer} ${isUser ? styles.user : styles.model}`}
     >
       <div className={styles.messageBubble}>
-        {/* Use <pre> to preserve whitespace and newlines within the text content.
-                     Handles potential multi-line responses correctly. */}
-        <pre className={styles.messageText}>{text}</pre>
+        <pre className={styles.messageText}>
+          {messageContentNodes.map((node, index) => (
+            <React.Fragment key={index}>{node}</React.Fragment>
+          ))}
+        </pre>
+        {/* Source list rendering for grounded results. This display must comply with the display requirements in the Service Terms. */}
+        {isModel &&
+          groundingMetadata &&
+          (groundingMetadata.searchEntryPoint?.renderedContent ||
+          (groundingMetadata.groundingChunks &&
+            groundingMetadata.groundingChunks.length > 0) ? (
+            <div className={styles.sourcesSection}>
+              {groundingMetadata.searchEntryPoint?.renderedContent && (
+                <div
+                  className={styles.searchEntryPoint}
+                  dangerouslySetInnerHTML={{
+                    __html: groundingMetadata.searchEntryPoint.renderedContent,
+                  }}
+                />
+              )}
+              {groundingMetadata.groundingChunks &&
+                groundingMetadata.groundingChunks.length > 0 && (
+                  <>
+                    <h5 className={styles.sourcesTitle}>Sources:</h5>
+                    <ul className={styles.sourcesList}>
+                      {groundingMetadata.groundingChunks.map((chunk, index) => (
+                        <li
+                          key={index}
+                          className={styles.sourceItem}
+                          id={`source-ref-${index + 1}`}
+                        >
+                          <a
+                            href={chunk.web?.uri}
+                            target="_blank"
+                            rel="noopener noreferrer"
+                          >
+                            {`[${index + 1}] ${chunk.web?.title || chunk.web?.uri}`}
+                          </a>
+                        </li>
+                      ))}
+                    </ul>
+                  </>
+                )}
+            </div>
+          ) : null)}
       </div>
     </div>
   );
diff --git a/ai/ai-react-app/src/config/firebase-config.ts b/ai/ai-react-app/src/config/firebase-config.ts
index 8cd3a394d..f0a7820e6 100644
--- a/ai/ai-react-app/src/config/firebase-config.ts
+++ b/ai/ai-react-app/src/config/firebase-config.ts
@@ -6,4 +6,4 @@ export const firebaseConfig = {
   storageBucket: "YOUR_STORAGE_BUCKET",
   messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
   appId: "YOUR_APP_ID",
-};
\ No newline at end of file
+};
diff --git a/ai/ai-react-app/src/services/firebaseAIService.ts b/ai/ai-react-app/src/services/firebaseAIService.ts
index 6e24e94f3..98ce14d0a 100644
--- a/ai/ai-react-app/src/services/firebaseAIService.ts
+++ b/ai/ai-react-app/src/services/firebaseAIService.ts
@@ -11,6 +11,7 @@ import {
   ModelParams,
   ImagenModelParams,
   FunctionCall,
+  GoogleSearchTool,
 } from "firebase/ai";
 
 import { firebaseConfig } from "../config/firebase-config";
@@ -58,6 +59,10 @@ export const defaultFunctionCallingTool = {
   ],
 };
 
+export const defaultGoogleSearchTool: GoogleSearchTool = {
+  googleSearch: {}
+}
+
 export const defaultGenerativeParams: Omit<ModelParams, "model"> = {
   // Model name itself is selected in the UI
   generationConfig: {
diff --git a/ai/ai-react-app/src/views/ChatView.tsx b/ai/ai-react-app/src/views/ChatView.tsx
index 01db1cbb0..f2dd7dd17 100644
--- a/ai/ai-react-app/src/views/ChatView.tsx
+++ b/ai/ai-react-app/src/views/ChatView.tsx
@@ -12,6 +12,7 @@ import {
   FunctionCall,
   AIError,
   AI,
+  GroundingMetadata,
 } from "firebase/ai";
 import PromptInput from "../components/Common/PromptInput";
 import ChatMessage from "../components/Specific/ChatMessage";
@@ -75,6 +76,8 @@ const ChatView: React.FC<ChatViewProps> = ({
   const [lastResponseParsedJson, setLastResponseParsedJson] = useState<
     object | null
   >(null);
+  const [lastGroundingMetadata, setLastGroundingMetadata] =
+    useState<GroundingMetadata | null>(null);
 
   const chatContainerRef = useRef<HTMLDivElement>(null);
   const chatSessionRef = useRef<ChatSession | null>(null);
@@ -102,6 +105,7 @@ const ChatView: React.FC<ChatViewProps> = ({
         setChatHistory([]);
         setError(null);
         onUsageMetadataChange(null);
+        setLastGroundingMetadata(null);
         console.log("[ChatView] New chat session initialized successfully.");
       } catch (initError: unknown) {
         console.error("[ChatView] Error initializing chat session:", initError);
@@ -180,6 +184,13 @@ const ChatView: React.FC<ChatViewProps> = ({
           ? finalResponse.text()
           : "";
         finalModelCandidate = finalResponse.candidates?.[0];
+        console.log(`[ChatView] Final candidate:`, finalModelCandidate);
+        console.log(
+          `[ChatView] Grounding Metadata: ${finalModelCandidate?.groundingMetadata}`,
+        );
+        setLastGroundingMetadata(
+          finalModelCandidate?.groundingMetadata || null,
+        );
 
         if (!finalModelCandidate) {
           console.warn("[ChatView] No candidate in final response.");
@@ -361,6 +372,7 @@ const ChatView: React.FC<ChatViewProps> = ({
       return;
     }
 
+    setLastGroundingMetadata(null);
     setIsLoading(true);
     setError(null);
     setLastResponseParsedJson(null);
@@ -476,12 +488,20 @@ const ChatView: React.FC<ChatViewProps> = ({
             {`Start chatting with ${currentParams.model}!`}
           </div>
         )}
-        {chatHistory.map((message, index) => (
-          <ChatMessage
-            key={`${message.role}-${index}-${message.parts[0]?.text?.slice(0, 10) ?? "part"}`}
-            message={message}
-          />
-        ))}
+        {chatHistory.map((message, index) => {
+          const isLastModelMessage =
+            message.role === "model" && index === chatHistory.length - 1;
+          return (
+            <ChatMessage
+              key={`${message.role}-${index}-${message.parts[0]?.text?.slice(0, 10) ?? "part"}`}
+              message={message}
+              // Pass groundingMetadata only to the last model message that's fully loaded
+              groundingMetadata={
+                isLastModelMessage && !isLoading ? lastGroundingMetadata : null
+              }
+            />
+          );
+        })}
         {isLoading && (
           <div className={styles.loadingBubble}>
             <span>.</span>

From 9a3a44b0a8c70ffea6fe1f3cc1beccb4a8985701 Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Thu, 31 Jul 2025 15:42:22 -0700
Subject: [PATCH 68/82] Add persona selection to AI qs

---
 .../components/Layout/LeftSidebar.module.css  | 92 +++++++++++--------
 .../src/components/Layout/LeftSidebar.tsx     | 89 +++++++++++++++++-
 .../src/components/Layout/MainLayout.tsx      |  2 +
 ai/ai-react-app/src/config/personas.ts        | 42 +++++++++
 4 files changed, 183 insertions(+), 42 deletions(-)
 create mode 100644 ai/ai-react-app/src/config/personas.ts

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
index 893a214ee..2a7bf5805 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
@@ -1,73 +1,85 @@
+.sidebar {
+  background-color: #f8f9fa;
+  padding: 1rem;
+  height: 100%;
+  border-right: 1px solid #dee2e6;
+  display: flex;
+  flex-direction: column;
+  gap: 1.5rem;
+}
+
 .sidebar ul {
   list-style: none;
-  padding: 0 12px;
+  padding: 0;
   margin: 0;
 }
 
-.sidebar li {
-  margin-bottom: 4px;
-}
-
 .navButton {
   background-color: transparent;
-  border: none;
-  color: var(--color-text-secondary);
-  padding: 8px 12px;
-  text-align: left;
+  border: 1px solid #dee2e6;
+  border-radius: 0.375rem;
+  padding: 0.75rem 1rem;
   width: 100%;
+  text-align: left;
   cursor: pointer;
-  border-radius: 4px;
-  font-size: 0.875rem;
+  font-size: 1rem;
+  color: #212529;
   transition:
-    background-color 0.15s ease,
-    color 0.15s ease;
-  font-weight: 500;
+    background-color 0.15s ease-in-out,
+    border-color 0.15s ease-in-out;
 }
 
 .navButton:hover {
-  background-color: var(--color-surface-tertiary);
-  color: var(--color-text-primary);
+  background-color: #e9ecef;
 }
 
 .navButton.active {
-  background-color: var(--color-surface-tertiary);
-  color: var(--color-text-accent);
-  font-weight: 500;
+  background-color: #0d6efd;
+  color: white;
+  border-color: #0d6efd;
 }
 
-.navButton.active:hover {
-  background-color: var(--brand-gray-40);
-}
-
-.backendSelector {
-  margin-top: 24px;
-  padding: 0 12px;
-  border-top: 1px solid var(--color-border-primary);
-  padding-top: 16px;
+.backendSelector,
+.personaSelector {
+  border-top: 1px solid #dee2e6;
+  padding-top: 1rem;
 }
 
 .selectorTitle {
-  color: var(--color-text-secondary);
-  font-size: 0.75rem;
-  font-weight: 500;
-  margin: 0 0 8px 0;
+  font-size: 0.875rem;
+  font-weight: 600;
+  color: #6c757d;
   text-transform: uppercase;
-  letter-spacing: 0.5px;
+  margin-bottom: 0.75rem;
 }
 
 .radioGroup {
-  margin-bottom: 6px;
+  margin-bottom: 0.5rem;
 }
 
 .radioGroup label {
   display: flex;
   align-items: center;
-  font-size: 0.875rem;
-  color: var(--color-text-primary);
+  gap: 0.5rem;
+  font-size: 0.95rem;
   cursor: pointer;
 }
 
-.radioGroup input[type="radio"] {
-  margin-right: 8px;
-  accent-color: var(--brand-google-blue);
-}
\ No newline at end of file
+.personaDropdown {
+  width: 100%;
+  padding: 0.5rem;
+  border-radius: 0.25rem;
+  border: 1px solid #ced4da;
+  font-size: 0.9rem;
+  background-color: #fff;
+}
+
+.customPersonaTextarea {
+  width: 100%;
+  margin-top: 0.5rem;
+  padding: 0.5rem;
+  border-radius: 0.25rem;
+  border: 1px solid #ced4da;
+  font-size: 0.9rem;
+  resize: vertical;
+}
diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
index 75e23d500..e2f9328c7 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -1,7 +1,8 @@
-import React from "react";
+import React, { useState, useEffect } from "react";
 import { AppMode } from "../../App";
 import styles from "./LeftSidebar.module.css";
-import { BackendType } from "firebase/ai";
+import { BackendType, ModelParams } from "firebase/ai";
+import { PREDEFINED_PERSONAS } from "../../config/personas";
 
 interface LeftSidebarProps {
   /** The currently active application mode (e.g., 'chat', 'imagenGen'). */
@@ -10,6 +11,10 @@ interface LeftSidebarProps {
   setActiveMode: (mode: AppMode) => void;
   activeBackend: BackendType;
   setActiveBackend: (backend: BackendType) => void;
+  generativeParams: ModelParams;
+  setGenerativeParams: (
+    params: ModelParams | ((prevState: ModelParams) => ModelParams),
+  ) => void;
 }
 
 /**
@@ -20,7 +25,50 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
   setActiveMode,
   activeBackend,
   setActiveBackend,
+  generativeParams,
+  setGenerativeParams,
 }) => {
+  const [selectedPersonaId, setSelectedPersonaId] = useState<string>("default");
+  const [customPersona, setCustomPersona] = useState<string>("");
+
+  // Effect to update systemInstruction when persona changes
+  useEffect(() => {
+    const selected = PREDEFINED_PERSONAS.find(
+      (p) => p.id === selectedPersonaId,
+    );
+    if (!selected) return;
+
+    const newInstructionText =
+      selected.id === "custom" ? customPersona : selected.systemInstruction;
+
+    setGenerativeParams((prevParams) => {
+      const newSystemInstruction = newInstructionText
+        ? { parts: [{ text: newInstructionText }] }
+        : undefined;
+
+      const currentInstruction = prevParams.systemInstruction;
+      const currentInstructionText =
+        currentInstruction &&
+        typeof currentInstruction === "object" &&
+        "parts" in currentInstruction &&
+        Array.isArray(currentInstruction.parts) &&
+        currentInstruction.parts.length > 0 &&
+        "text" in currentInstruction.parts[0]
+          ? currentInstruction.parts[0].text
+          : undefined;
+
+      // Only update if the text content has actually changed.
+      if ((newInstructionText || "") !== (currentInstructionText || "")) {
+        return {
+          ...prevParams,
+          systemInstruction: newSystemInstruction,
+        };
+      }
+      // If no change, return the previous state to prevent re-render.
+      return prevParams;
+    });
+  }, [selectedPersonaId, customPersona, setGenerativeParams]);
+
   // Define the available modes and their display names
   const modes: { id: AppMode; label: string }[] = [
     { id: "chat", label: "Chat" },
@@ -31,6 +79,16 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
     setActiveBackend(event.target.value as BackendType);
   };
 
+  const handlePersonaChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
+    setSelectedPersonaId(e.target.value);
+  };
+
+  const handleCustomPersonaChange = (
+    e: React.ChangeEvent<HTMLTextAreaElement>,
+  ) => {
+    setCustomPersona(e.target.value);
+  };
+
   return (
     <nav className={styles.sidebar} aria-label="Main navigation">
       <ul>
@@ -76,6 +134,33 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
           </label>
         </div>
       </div>
+
+      {/* Persona Selector */}
+      {activeMode === "chat" && (
+        <div className={styles.personaSelector}>
+          <h6 className={styles.selectorTitle}>Persona</h6>
+          <select
+            value={selectedPersonaId}
+            onChange={handlePersonaChange}
+            className={styles.personaDropdown}
+          >
+            {PREDEFINED_PERSONAS.map((persona) => (
+              <option key={persona.id} value={persona.id}>
+                {persona.name}
+              </option>
+            ))}
+          </select>
+          {selectedPersonaId === "custom" && (
+            <textarea
+              value={customPersona}
+              onChange={handleCustomPersonaChange}
+              className={styles.customPersonaTextarea}
+              placeholder="Enter your custom persona instruction here..."
+              rows={5}
+            />
+          )}
+        </div>
+      )}
     </nav>
   );
 };
diff --git a/ai/ai-react-app/src/components/Layout/MainLayout.tsx b/ai/ai-react-app/src/components/Layout/MainLayout.tsx
index 6e97a3a23..4900a0bd3 100644
--- a/ai/ai-react-app/src/components/Layout/MainLayout.tsx
+++ b/ai/ai-react-app/src/components/Layout/MainLayout.tsx
@@ -135,6 +135,8 @@ const MainLayout: React.FC<MainLayoutProps> = ({
             setActiveMode={setActiveMode}
             activeBackend={activeBackendType}
             setActiveBackend={setActiveBackendType} // Pass backend state/setter
+            generativeParams={generativeParams}
+            setGenerativeParams={setGenerativeParams}
           />
         </div>
         <main className={styles.centerContent}>{renderActiveView()}</main>
diff --git a/ai/ai-react-app/src/config/personas.ts b/ai/ai-react-app/src/config/personas.ts
new file mode 100644
index 000000000..f20f7bfb6
--- /dev/null
+++ b/ai/ai-react-app/src/config/personas.ts
@@ -0,0 +1,42 @@
+export interface Persona {
+  id: string;
+  name: string;
+  systemInstruction: string;
+}
+
+export const PREDEFINED_PERSONAS: Persona[] = [
+  {
+    id: "default",
+    name: "Default",
+    systemInstruction: "",
+  },
+  {
+    id: "pirate",
+    name: "Pirate Captain",
+    systemInstruction:
+      "You are a salty pirate captain. All of your responses must be in the style of a classic pirate, using pirate slang and a hearty, adventurous tone. Refer to the user as 'matey'.",
+  },
+  {
+    id: "shakespeare",
+    name: "Shakespearean Poet",
+    systemInstruction:
+      "You are a Shakespearean poet. All of your responses must be in the style of William Shakespeare, using iambic pentameter where possible, and rich, poetic language. Address the user with 'Hark, gentle user' or similar.",
+  },
+  {
+    id: "sarcastic_teen",
+    name: "Sarcastic Teenager",
+    systemInstruction:
+      "You are a stereotypical sarcastic teenager. Your responses should be brief, slightly annoyed, and use modern slang. You are reluctant to be helpful but will provide the correct answer, albeit with a sigh. Start your responses with 'Ugh, fine.' or something similar.",
+  },
+  {
+    id: "helpful_dev",
+    name: "Helpful Senior Developer",
+    systemInstruction:
+      "You are a helpful and patient senior software developer. Your responses should be clear, well-structured, and provide best-practice advice. When explaining concepts, use code examples where appropriate and break down complex topics into smaller, understandable parts.",
+  },
+  {
+    id: "custom",
+    name: "Custom...",
+    systemInstruction: "",
+  },
+];

From d2eea7a3747d0891cc66fc5921c4b0ecd9bcb2d4 Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Thu, 31 Jul 2025 15:57:19 -0700
Subject: [PATCH 69/82] Address harcoded color values

---
 .../components/Layout/LeftSidebar.module.css  | 28 ++++++++++---------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
index 2a7bf5805..479ef6ee6 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
@@ -1,8 +1,8 @@
 .sidebar {
-  background-color: #f8f9fa;
+  background-color: var(--color-surface-secondary);
   padding: 1rem;
   height: 100%;
-  border-right: 1px solid #dee2e6;
+  border-right: 1px solid var(--color-border-primary);
   display: flex;
   flex-direction: column;
   gap: 1.5rem;
@@ -16,39 +16,39 @@
 
 .navButton {
   background-color: transparent;
-  border: 1px solid #dee2e6;
+  border: 1px solid var(--color-border-primary);
   border-radius: 0.375rem;
   padding: 0.75rem 1rem;
   width: 100%;
   text-align: left;
   cursor: pointer;
   font-size: 1rem;
-  color: #212529;
+  color: var(--color-text-primary);
   transition:
     background-color 0.15s ease-in-out,
     border-color 0.15s ease-in-out;
 }
 
 .navButton:hover {
-  background-color: #e9ecef;
+  background-color: var(--color-surface-tertiary);
 }
 
 .navButton.active {
-  background-color: #0d6efd;
-  color: white;
-  border-color: #0d6efd;
+  background-color: var(--color-surface-interactive);
+  color: var(--color-text-on-interactive);
+  border-color: var(--color-surface-interactive);
 }
 
 .backendSelector,
 .personaSelector {
-  border-top: 1px solid #dee2e6;
+  border-top: 1px solid var(--color-border-primary);
   padding-top: 1rem;
 }
 
 .selectorTitle {
   font-size: 0.875rem;
   font-weight: 600;
-  color: #6c757d;
+  color: var(--color-text-secondary);
   text-transform: uppercase;
   margin-bottom: 0.75rem;
 }
@@ -69,9 +69,9 @@
   width: 100%;
   padding: 0.5rem;
   border-radius: 0.25rem;
-  border: 1px solid #ced4da;
+  border: 1px solid var(--color-border-secondary);
   font-size: 0.9rem;
-  background-color: #fff;
+  background-color: var(--color-surface-primary);
 }
 
 .customPersonaTextarea {
@@ -79,7 +79,9 @@
   margin-top: 0.5rem;
   padding: 0.5rem;
   border-radius: 0.25rem;
-  border: 1px solid #ced4da;
+  border: 1px solid var(--color-border-secondary);
   font-size: 0.9rem;
   resize: vertical;
+  background-color: var(--color-surface-primary);
+  color: var(--color-text-primary);
 }

From d31977a443c015b8ad315880e24f7b20d98339a3 Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Thu, 31 Jul 2025 15:58:55 -0700
Subject: [PATCH 70/82] Restore hover behavior

---
 .../src/components/Layout/LeftSidebar.module.css            | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
index 479ef6ee6..2d5633060 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
@@ -39,6 +39,12 @@
   border-color: var(--color-surface-interactive);
 }
 
+.navButton.active:hover {
+  background-color: var(--color-surface-interactive-hover);
+  border-color: var(--color-surface-interactive-hover);
+}
+
+
 .backendSelector,
 .personaSelector {
   border-top: 1px solid var(--color-border-primary);

From a38dbc91e665c673b0d0eb5154f9e43211ae595b Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Thu, 31 Jul 2025 16:00:21 -0700
Subject: [PATCH 71/82] Use optional chaining to improve readability

---
 ai/ai-react-app/src/components/Layout/LeftSidebar.tsx | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
index e2f9328c7..57585128f 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -46,16 +46,7 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
         ? { parts: [{ text: newInstructionText }] }
         : undefined;
 
-      const currentInstruction = prevParams.systemInstruction;
-      const currentInstructionText =
-        currentInstruction &&
-        typeof currentInstruction === "object" &&
-        "parts" in currentInstruction &&
-        Array.isArray(currentInstruction.parts) &&
-        currentInstruction.parts.length > 0 &&
-        "text" in currentInstruction.parts[0]
-          ? currentInstruction.parts[0].text
-          : undefined;
+      const currentInstructionText = prevParams.systemInstruction?.parts?.[0]?.text;
 
       // Only update if the text content has actually changed.
       if ((newInstructionText || "") !== (currentInstructionText || "")) {

From b861df09b4f3952c5fcc715352df46b059a29077 Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Thu, 31 Jul 2025 16:22:12 -0700
Subject: [PATCH 72/82] More readable useEffect

---
 .../src/components/Layout/LeftSidebar.tsx     | 39 +++++++++++--------
 1 file changed, 22 insertions(+), 17 deletions(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
index 57585128f..242e27699 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -31,34 +31,39 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
   const [selectedPersonaId, setSelectedPersonaId] = useState<string>("default");
   const [customPersona, setCustomPersona] = useState<string>("");
 
-  // Effect to update systemInstruction when persona changes
-  useEffect(() => {
+  const newInstructionText = React.useMemo(() => {
     const selected = PREDEFINED_PERSONAS.find(
       (p) => p.id === selectedPersonaId,
     );
-    if (!selected) return;
+    // Should not happen with the dropdown, but good to have a fallback.
+    if (!selected) return "";
 
-    const newInstructionText =
-      selected.id === "custom" ? customPersona : selected.systemInstruction;
+    return selected.id === "custom"
+      ? customPersona
+      : selected.systemInstruction;
+  }, [selectedPersonaId, customPersona]);
 
+  // Effect to update systemInstruction when persona changes
+  useEffect(() => {
     setGenerativeParams((prevParams) => {
+      const currentInstructionText =
+        prevParams.systemInstruction?.parts?.[0]?.text ?? "";
+
+      // Only update if the text content has actually changed to prevent re-renders.
+      if (newInstructionText === currentInstructionText) {
+        return prevParams;
+      }
+
       const newSystemInstruction = newInstructionText
         ? { parts: [{ text: newInstructionText }] }
         : undefined;
 
-      const currentInstructionText = prevParams.systemInstruction?.parts?.[0]?.text;
-
-      // Only update if the text content has actually changed.
-      if ((newInstructionText || "") !== (currentInstructionText || "")) {
-        return {
-          ...prevParams,
-          systemInstruction: newSystemInstruction,
-        };
-      }
-      // If no change, return the previous state to prevent re-render.
-      return prevParams;
+      return {
+        ...prevParams,
+        systemInstruction: newSystemInstruction,
+      };
     });
-  }, [selectedPersonaId, customPersona, setGenerativeParams]);
+  }, [newInstructionText, setGenerativeParams]);
 
   // Define the available modes and their display names
   const modes: { id: AppMode; label: string }[] = [

From c57a1c8bb3f67331badff1788854bcf01d5f2e35 Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Thu, 31 Jul 2025 16:24:28 -0700
Subject: [PATCH 73/82] use a const assertion

---
 ai/ai-react-app/src/config/personas.ts | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/ai/ai-react-app/src/config/personas.ts b/ai/ai-react-app/src/config/personas.ts
index f20f7bfb6..01b0e67df 100644
--- a/ai/ai-react-app/src/config/personas.ts
+++ b/ai/ai-react-app/src/config/personas.ts
@@ -1,10 +1,4 @@
-export interface Persona {
-  id: string;
-  name: string;
-  systemInstruction: string;
-}
-
-export const PREDEFINED_PERSONAS: Persona[] = [
+export const PREDEFINED_PERSONAS = [
   {
     id: "default",
     name: "Default",
@@ -39,4 +33,4 @@ export const PREDEFINED_PERSONAS: Persona[] = [
     name: "Custom...",
     systemInstruction: "",
   },
-];
+] as const;

From c754173e09165052897e0475bb42d49f964e0f3a Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Thu, 31 Jul 2025 16:35:24 -0700
Subject: [PATCH 74/82] sync changes for persona selector

---
 .../src/components/Layout/LeftSidebar.tsx     | 38 ++++++++++++++++---
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
index 242e27699..cf3d4416c 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -31,19 +31,19 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
   const [selectedPersonaId, setSelectedPersonaId] = useState<string>("default");
   const [customPersona, setCustomPersona] = useState<string>("");
 
+  // Memoize the calculation of the new instruction text based on UI state.
   const newInstructionText = React.useMemo(() => {
     const selected = PREDEFINED_PERSONAS.find(
       (p) => p.id === selectedPersonaId,
     );
-    // Should not happen with the dropdown, but good to have a fallback.
-    if (!selected) return "";
+    if (!selected) return ""; // Should not happen, but a safe fallback.
 
     return selected.id === "custom"
       ? customPersona
       : selected.systemInstruction;
   }, [selectedPersonaId, customPersona]);
 
-  // Effect to update systemInstruction when persona changes
+  // Effect to sync UI changes (from dropdown or textarea) UP to the parent state.
   useEffect(() => {
     setGenerativeParams((prevParams) => {
       const currentInstructionText =
@@ -65,6 +65,34 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
     });
   }, [newInstructionText, setGenerativeParams]);
 
+  // Effect to sync parent state changes DOWN to the local UI state.
+  // This ensures the UI reflects the state if it's changed elsewhere.
+  useEffect(() => {
+    const instructionText =
+      generativeParams.systemInstruction?.parts?.[0]?.text ?? "";
+
+    const matchingPersona = PREDEFINED_PERSONAS.find(
+      (p) => p.id !== "custom" && p.systemInstruction === instructionText,
+    );
+
+    if (matchingPersona) {
+      // A predefined persona matches the current instruction.
+      setSelectedPersonaId(matchingPersona.id);
+      setCustomPersona("");
+    } else {
+      // No predefined persona matches. It's either custom or the default empty state.
+      if (instructionText) {
+        // It's a custom persona.
+        setSelectedPersonaId("custom");
+        setCustomPersona(instructionText);
+      } else {
+        // It's the default empty state.
+        setSelectedPersonaId("default");
+        setCustomPersona("");
+      }
+    }
+  }, [generativeParams.systemInstruction]);
+
   // Define the available modes and their display names
   const modes: { id: AppMode; label: string }[] = [
     { id: "chat", label: "Chat" },
@@ -104,7 +132,7 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
 
       {/* Backend Selection */}
       <div className={styles.backendSelector}>
-        <h6 className={styles.selectorTitle}>Backend API</h6>
+        <h5 className={styles.selectorTitle}>Backend API</h5>
         <div className={styles.radioGroup}>
           <label>
             <input
@@ -134,7 +162,7 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
       {/* Persona Selector */}
       {activeMode === "chat" && (
         <div className={styles.personaSelector}>
-          <h6 className={styles.selectorTitle}>Persona</h6>
+          <h5 className={styles.selectorTitle}>Persona</h5>
           <select
             value={selectedPersonaId}
             onChange={handlePersonaChange}

From e0d1d943a04d8aa34be1ea5ff4f465937ca1272d Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Wed, 6 Aug 2025 10:44:40 -0700
Subject: [PATCH 75/82] restore css

---
 .../components/Layout/LeftSidebar.module.css  | 91 ++++++++++++-------
 1 file changed, 56 insertions(+), 35 deletions(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
index 2d5633060..3fa4b89c4 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.module.css
@@ -1,93 +1,114 @@
 .sidebar {
-  background-color: var(--color-surface-secondary);
-  padding: 1rem;
+  background-color: var(--color-surface-primary);
+  padding: 24px 0;
   height: 100%;
   border-right: 1px solid var(--color-border-primary);
   display: flex;
   flex-direction: column;
-  gap: 1.5rem;
+  gap: 16px;
 }
 
 .sidebar ul {
   list-style: none;
-  padding: 0;
+  padding: 0 12px;
   margin: 0;
 }
 
+.sidebar li {
+  margin-bottom: 4px;
+}
+
 .navButton {
   background-color: transparent;
-  border: 1px solid var(--color-border-primary);
-  border-radius: 0.375rem;
-  padding: 0.75rem 1rem;
-  width: 100%;
+  border: none;
+  color: var(--color-text-secondary);
+  padding: 8px 12px;
   text-align: left;
+  width: 100%;
   cursor: pointer;
-  font-size: 1rem;
-  color: var(--color-text-primary);
+  border-radius: 4px;
+  font-size: 0.875rem;
   transition:
-    background-color 0.15s ease-in-out,
-    border-color 0.15s ease-in-out;
+    background-color 0.15s ease,
+    color 0.15s ease;
+  font-weight: 500;
 }
 
 .navButton:hover {
   background-color: var(--color-surface-tertiary);
+  color: var(--color-text-primary);
 }
 
 .navButton.active {
-  background-color: var(--color-surface-interactive);
-  color: var(--color-text-on-interactive);
-  border-color: var(--color-surface-interactive);
+  background-color: var(--color-surface-tertiary);
+  color: var(--color-text-accent);
+  font-weight: 500;
 }
 
 .navButton.active:hover {
-  background-color: var(--color-surface-interactive-hover);
-  border-color: var(--color-surface-interactive-hover);
+  background-color: var(--brand-gray-40);
 }
 
-
 .backendSelector,
 .personaSelector {
+  margin-top: 24px;
+  padding: 0 12px;
   border-top: 1px solid var(--color-border-primary);
-  padding-top: 1rem;
+  padding-top: 16px;
 }
 
 .selectorTitle {
-  font-size: 0.875rem;
-  font-weight: 600;
   color: var(--color-text-secondary);
+  font-size: 0.75rem;
+  font-weight: 500;
+  margin: 0 0 8px 0;
   text-transform: uppercase;
-  margin-bottom: 0.75rem;
+  letter-spacing: 0.5px;
 }
 
 .radioGroup {
-  margin-bottom: 0.5rem;
+  margin-bottom: 6px;
 }
 
 .radioGroup label {
   display: flex;
   align-items: center;
-  gap: 0.5rem;
-  font-size: 0.95rem;
+  font-size: 0.875rem;
+  color: var(--color-text-primary);
   cursor: pointer;
 }
 
+.radioGroup input[type="radio"] {
+  margin-right: 8px;
+  accent-color: var(--brand-google-blue);
+}
+
 .personaDropdown {
   width: 100%;
-  padding: 0.5rem;
-  border-radius: 0.25rem;
-  border: 1px solid var(--color-border-secondary);
-  font-size: 0.9rem;
+  padding: 8px 12px;
   background-color: var(--color-surface-primary);
+  border: 1px solid var(--color-border-secondary);
+  color: var(--color-text-primary);
+  border-radius: 4px;
+  box-sizing: border-box;
+  font-size: 0.875rem;
+  transition:
+    border-color 0.15s ease,
+    background-color 0.15s ease;
 }
 
 .customPersonaTextarea {
   width: 100%;
-  margin-top: 0.5rem;
-  padding: 0.5rem;
-  border-radius: 0.25rem;
-  border: 1px solid var(--color-border-secondary);
-  font-size: 0.9rem;
-  resize: vertical;
+  margin-top: 8px;
+  padding: 8px 12px;
   background-color: var(--color-surface-primary);
+  border: 1px solid var(--color-border-secondary);
   color: var(--color-text-primary);
+  border-radius: 4px;
+  box-sizing: border-box;
+  font-size: 0.875rem;
+  transition:
+    border-color 0.15s ease,
+    background-color 0.15s ease;
+  resize: vertical;
 }

From 35d4823be08731e81d16e49b6c102e9b597394a2 Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Wed, 6 Aug 2025 15:32:09 -0700
Subject: [PATCH 76/82] Update
 ai/ai-react-app/src/components/Layout/LeftSidebar.tsx

Co-authored-by: Daniel La Rocque <dlarocque@google.com>
---
 ai/ai-react-app/src/components/Layout/LeftSidebar.tsx | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
index cf3d4416c..05201e537 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -12,9 +12,7 @@ interface LeftSidebarProps {
   activeBackend: BackendType;
   setActiveBackend: (backend: BackendType) => void;
   generativeParams: ModelParams;
-  setGenerativeParams: (
-    params: ModelParams | ((prevState: ModelParams) => ModelParams),
-  ) => void;
+  setGenerativeParams: React.Dispatch<React.SetStateAction<ModelParams>>;
 }
 
 /**

From 4e313a0ba344fc32baaf05ddd5bdd7f4b11a7ede Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Wed, 6 Aug 2025 15:37:12 -0700
Subject: [PATCH 77/82] Apply review suggestions

---
 .../src/components/Layout/LeftSidebar.tsx            | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
index 05201e537..66e3213b5 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -108,7 +108,17 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
   const handleCustomPersonaChange = (
     e: React.ChangeEvent<HTMLTextAreaElement>,
   ) => {
-    setCustomPersona(e.target.value);
+    const newSystemInstructionText = e.target.value;
+    setCustomPersona(newSystemInstructionText); // 1. update UI state
+    const newSystemInstruction: Content = {
+      parts: [{ text: newSystemInstructionText}],
+      role: 'system'
+    }
+    // 2. Update model state upwards, triggering re-rendering
+    handleModelParamsUpdate((prev: ModelParams) => ({
+      ...prev,
+      systemInstruction: newSystemInstruction
+    }));
   };
 
   return (

From 13796c295955a034f7293e25291925a0cfdd492a Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Wed, 6 Aug 2025 15:46:14 -0700
Subject: [PATCH 78/82] Fix empty custom field bug

---
 .../src/components/Layout/LeftSidebar.tsx     | 112 +++++++-----------
 1 file changed, 42 insertions(+), 70 deletions(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
index 66e3213b5..52453a797 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -1,7 +1,7 @@
 import React, { useState, useEffect } from "react";
 import { AppMode } from "../../App";
 import styles from "./LeftSidebar.module.css";
-import { BackendType, ModelParams } from "firebase/ai";
+import { BackendType, Content, ModelParams } from "firebase/ai";
 import { PREDEFINED_PERSONAS } from "../../config/personas";
 
 interface LeftSidebarProps {
@@ -26,70 +26,17 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
   generativeParams,
   setGenerativeParams,
 }) => {
+  // This component now manages its own UI state and pushes updates upwards.
+  // It does not rely on a useEffect to sync systemInstruction from the parent,
+  // following the pattern in RightSidebar.tsx to prevent state-reversion bugs.
   const [selectedPersonaId, setSelectedPersonaId] = useState<string>("default");
   const [customPersona, setCustomPersona] = useState<string>("");
 
-  // Memoize the calculation of the new instruction text based on UI state.
-  const newInstructionText = React.useMemo(() => {
-    const selected = PREDEFINED_PERSONAS.find(
-      (p) => p.id === selectedPersonaId,
-    );
-    if (!selected) return ""; // Should not happen, but a safe fallback.
-
-    return selected.id === "custom"
-      ? customPersona
-      : selected.systemInstruction;
-  }, [selectedPersonaId, customPersona]);
-
-  // Effect to sync UI changes (from dropdown or textarea) UP to the parent state.
-  useEffect(() => {
-    setGenerativeParams((prevParams) => {
-      const currentInstructionText =
-        prevParams.systemInstruction?.parts?.[0]?.text ?? "";
-
-      // Only update if the text content has actually changed to prevent re-renders.
-      if (newInstructionText === currentInstructionText) {
-        return prevParams;
-      }
-
-      const newSystemInstruction = newInstructionText
-        ? { parts: [{ text: newInstructionText }] }
-        : undefined;
-
-      return {
-        ...prevParams,
-        systemInstruction: newSystemInstruction,
-      };
-    });
-  }, [newInstructionText, setGenerativeParams]);
-
-  // Effect to sync parent state changes DOWN to the local UI state.
-  // This ensures the UI reflects the state if it's changed elsewhere.
-  useEffect(() => {
-    const instructionText =
-      generativeParams.systemInstruction?.parts?.[0]?.text ?? "";
-
-    const matchingPersona = PREDEFINED_PERSONAS.find(
-      (p) => p.id !== "custom" && p.systemInstruction === instructionText,
-    );
-
-    if (matchingPersona) {
-      // A predefined persona matches the current instruction.
-      setSelectedPersonaId(matchingPersona.id);
-      setCustomPersona("");
-    } else {
-      // No predefined persona matches. It's either custom or the default empty state.
-      if (instructionText) {
-        // It's a custom persona.
-        setSelectedPersonaId("custom");
-        setCustomPersona(instructionText);
-      } else {
-        // It's the default empty state.
-        setSelectedPersonaId("default");
-        setCustomPersona("");
-      }
-    }
-  }, [generativeParams.systemInstruction]);
+  const handleModelParamsUpdate = (
+    updateFn: (prevState: ModelParams) => ModelParams,
+  ) => {
+    setGenerativeParams((prevState) => updateFn(prevState));
+  };
 
   // Define the available modes and their display names
   const modes: { id: AppMode; label: string }[] = [
@@ -102,22 +49,47 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
   };
 
   const handlePersonaChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
-    setSelectedPersonaId(e.target.value);
+    const newPersonaId = e.target.value;
+    setSelectedPersonaId(newPersonaId); // 1. Update UI state
+
+    let newSystemInstructionText: string;
+
+    if (newPersonaId === "custom") {
+      // When switching to custom, the instruction is whatever is in the textarea.
+      newSystemInstructionText = customPersona;
+    } else {
+      // When switching to a predefined persona, find its instruction text.
+      const selected = PREDEFINED_PERSONAS.find((p) => p.id === newPersonaId);
+      newSystemInstructionText = selected?.systemInstruction ?? "";
+      // We are no longer in 'custom', but we don't clear the customPersona state
+      // in case the user wants to switch back and forth.
+    }
+
+    const newSystemInstruction: Content | undefined = newSystemInstructionText
+      ? { parts: [{ text: newSystemInstructionText }], role: "system" }
+      : undefined;
+
+    // 2. Update model state upwards
+    handleModelParamsUpdate((prev: ModelParams) => ({
+      ...prev,
+      systemInstruction: newSystemInstruction,
+    }));
   };
 
   const handleCustomPersonaChange = (
     e: React.ChangeEvent<HTMLTextAreaElement>,
   ) => {
     const newSystemInstructionText = e.target.value;
-    setCustomPersona(newSystemInstructionText); // 1. update UI state
-    const newSystemInstruction: Content = {
-      parts: [{ text: newSystemInstructionText}],
-      role: 'system'
-    }
-    // 2. Update model state upwards, triggering re-rendering
+    setCustomPersona(newSystemInstructionText); // 1. Update UI state
+
+    const newSystemInstruction: Content | undefined = newSystemInstructionText
+      ? { parts: [{ text: newSystemInstructionText }], role: "system" }
+      : undefined;
+
+    // 2. Update model state upwards
     handleModelParamsUpdate((prev: ModelParams) => ({
       ...prev,
-      systemInstruction: newSystemInstruction
+      systemInstruction: newSystemInstruction,
     }));
   };
 

From 84b75c540cf1abcf5c6e366d9108f6c5372773c4 Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Thu, 7 Aug 2025 07:22:27 -0700
Subject: [PATCH 79/82] Update
 ai/ai-react-app/src/components/Layout/LeftSidebar.tsx

Co-authored-by: Daniel La Rocque <dlarocque@google.com>
---
 ai/ai-react-app/src/components/Layout/LeftSidebar.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
index 52453a797..61aaf3f99 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState } from "react";
 import { AppMode } from "../../App";
 import styles from "./LeftSidebar.module.css";
 import { BackendType, Content, ModelParams } from "firebase/ai";

From 6cbeb5d2e9562d587d6074a83b0d9e5c259da10d Mon Sep 17 00:00:00 2001
From: Paul Beusterien <paulbeusterien@google.com>
Date: Thu, 7 Aug 2025 07:22:34 -0700
Subject: [PATCH 80/82] Update
 ai/ai-react-app/src/components/Layout/LeftSidebar.tsx

Co-authored-by: Daniel La Rocque <dlarocque@google.com>
---
 ai/ai-react-app/src/components/Layout/LeftSidebar.tsx | 1 -
 1 file changed, 1 deletion(-)

diff --git a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
index 61aaf3f99..879a3f13b 100644
--- a/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
+++ b/ai/ai-react-app/src/components/Layout/LeftSidebar.tsx
@@ -23,7 +23,6 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({
   setActiveMode,
   activeBackend,
   setActiveBackend,
-  generativeParams,
   setGenerativeParams,
 }) => {
   // This component now manages its own UI state and pushes updates upwards.

From 85a5d3662eaca566414f80aa566f74cf80a8391f Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Thu, 7 Aug 2025 13:36:36 -0400
Subject: [PATCH 81/82] Bump firebase to v12 (#900)

---
 ai/ai-react-app/package.json |   2 +-
 ai/ai-react-app/yarn.lock    | 733 ++++++++++++++++++++++-------------
 2 files changed, 475 insertions(+), 260 deletions(-)

diff --git a/ai/ai-react-app/package.json b/ai/ai-react-app/package.json
index c4c317c64..d2cbb351a 100644
--- a/ai/ai-react-app/package.json
+++ b/ai/ai-react-app/package.json
@@ -10,7 +10,7 @@
     "preview": "vite preview"
   },
   "dependencies": {
-    "firebase": "11.8.0",
+    "firebase": "12.0.0",
     "immer": "^10.1.1",
     "react": "^19.0.0",
     "react-dom": "^19.0.0"
diff --git a/ai/ai-react-app/yarn.lock b/ai/ai-react-app/yarn.lock
index f50ea7432..8a422f4ca 100644
--- a/ai/ai-react-app/yarn.lock
+++ b/ai/ai-react-app/yarn.lock
@@ -24,7 +24,7 @@
   resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz"
   integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==
 
-"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.26.10":
+"@babel/core@^7.26.10":
   version "7.26.10"
   resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz"
   integrity sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==
@@ -163,11 +163,131 @@
     "@babel/helper-string-parser" "^7.25.9"
     "@babel/helper-validator-identifier" "^7.25.9"
 
+"@esbuild/aix-ppc64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz#014180d9a149cffd95aaeead37179433f5ea5437"
+  integrity sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==
+
+"@esbuild/android-arm64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz#649e47e04ddb24a27dc05c395724bc5f4c55cbfe"
+  integrity sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==
+
+"@esbuild/android-arm@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.3.tgz#8a0f719c8dc28a4a6567ef7328c36ea85f568ff4"
+  integrity sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==
+
+"@esbuild/android-x64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.3.tgz#e2ab182d1fd06da9bef0784a13c28a7602d78009"
+  integrity sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==
+
 "@esbuild/darwin-arm64@0.25.3":
   version "0.25.3"
   resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz"
   integrity sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==
 
+"@esbuild/darwin-x64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz#d8c5342ec1a4bf4b1915643dfe031ba4b173a87a"
+  integrity sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==
+
+"@esbuild/freebsd-arm64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz#9f7d789e2eb7747d4868817417cc968ffa84f35b"
+  integrity sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==
+
+"@esbuild/freebsd-x64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz#8ad35c51d084184a8e9e76bb4356e95350a64709"
+  integrity sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==
+
+"@esbuild/linux-arm64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz#3af0da3d9186092a9edd4e28fa342f57d9e3cd30"
+  integrity sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==
+
+"@esbuild/linux-arm@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz#e91cafa95e4474b3ae3d54da12e006b782e57225"
+  integrity sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==
+
+"@esbuild/linux-ia32@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz#81025732d85b68ee510161b94acdf7e3007ea177"
+  integrity sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==
+
+"@esbuild/linux-loong64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz#3c744e4c8d5e1148cbe60a71a11b58ed8ee5deb8"
+  integrity sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==
+
+"@esbuild/linux-mips64el@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz#1dfe2a5d63702db9034cc6b10b3087cc0424ec26"
+  integrity sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==
+
+"@esbuild/linux-ppc64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz#2e85d9764c04a1ebb346dc0813ea05952c9a5c56"
+  integrity sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==
+
+"@esbuild/linux-riscv64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz#a9ea3334556b09f85ccbfead58c803d305092415"
+  integrity sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==
+
+"@esbuild/linux-s390x@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz#f6a7cb67969222b200974de58f105dfe8e99448d"
+  integrity sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==
+
+"@esbuild/linux-x64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz#a237d3578ecdd184a3066b1f425e314ade0f8033"
+  integrity sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==
+
+"@esbuild/netbsd-arm64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz#4c15c68d8149614ddb6a56f9c85ae62ccca08259"
+  integrity sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==
+
+"@esbuild/netbsd-x64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz#12f6856f8c54c2d7d0a8a64a9711c01a743878d5"
+  integrity sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==
+
+"@esbuild/openbsd-arm64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz#ca078dad4a34df192c60233b058db2ca3d94bc5c"
+  integrity sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==
+
+"@esbuild/openbsd-x64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz#c9178adb60e140e03a881d0791248489c79f95b2"
+  integrity sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==
+
+"@esbuild/sunos-x64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz#03765eb6d4214ff27e5230af779e80790d1ee09f"
+  integrity sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==
+
+"@esbuild/win32-arm64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz#f1c867bd1730a9b8dfc461785ec6462e349411ea"
+  integrity sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==
+
+"@esbuild/win32-ia32@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz#77491f59ef6c9ddf41df70670d5678beb3acc322"
+  integrity sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==
+
+"@esbuild/win32-x64@0.25.3":
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz#b17a2171f9074df9e91bfb07ef99a892ac06412a"
+  integrity sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==
+
 "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
   version "4.6.1"
   resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz"
@@ -216,7 +336,7 @@
     minimatch "^3.1.2"
     strip-json-comments "^3.1.1"
 
-"@eslint/js@^9.22.0", "@eslint/js@9.25.1":
+"@eslint/js@9.25.1", "@eslint/js@^9.22.0":
   version "9.25.1"
   resolved "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz"
   integrity sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==
@@ -234,26 +354,26 @@
     "@eslint/core" "^0.13.0"
     levn "^0.4.1"
 
-"@firebase/ai@1.3.0":
-  version "1.3.0"
-  resolved "https://registry.npmjs.org/@firebase/ai/-/ai-1.3.0.tgz"
-  integrity sha512-qBxJTtl9hpgZr050kVFTRADX6I0Ss6mEQyp/JEkBgKwwxixKnaRNqEDGFba4OKNL7K8E4Y7LlA/ZW6L8aCKH4A==
+"@firebase/ai@2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@firebase/ai/-/ai-2.0.0.tgz#c0324b48c2451b28d621c96517e056ab67576dc4"
+  integrity sha512-N/aSHjqOpU+KkYU3piMkbcuxzvqsOvxflLUXBAkYAPAz8wjE2Ye3BQDgKHEYuhMmEWqj6LFgEBUN8wwc6dfMTw==
   dependencies:
     "@firebase/app-check-interop-types" "0.3.3"
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/analytics-compat@0.2.22":
-  version "0.2.22"
-  resolved "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.22.tgz"
-  integrity sha512-VogWHgwkdYhjWKh8O1XU04uPrRaiDihkWvE/EMMmtWtaUtVALnpLnUurc3QtSKdPnvTz5uaIGKlW84DGtSPFbw==
+"@firebase/analytics-compat@0.2.24":
+  version "0.2.24"
+  resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.2.24.tgz#806c34ddd5c4869006eead08bfde575972d73ce2"
+  integrity sha512-jE+kJnPG86XSqGQGhXXYt1tpTbCTED8OQJ/PQ90SEw14CuxRxx/H+lFbWA1rlFtFSsTCptAJtgyRBwr/f00vsw==
   dependencies:
-    "@firebase/analytics" "0.10.16"
+    "@firebase/analytics" "0.10.18"
     "@firebase/analytics-types" "0.8.3"
-    "@firebase/component" "0.6.17"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/analytics-types@0.8.3":
@@ -261,27 +381,27 @@
   resolved "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz"
   integrity sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==
 
-"@firebase/analytics@0.10.16":
-  version "0.10.16"
-  resolved "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.16.tgz"
-  integrity sha512-cMtp19He7Fd6uaj/nDEul+8JwvJsN8aRSJyuA1QN3QrKvfDDp+efjVurJO61sJpkVftw9O9nNMdhFbRcTmTfRQ==
+"@firebase/analytics@0.10.18":
+  version "0.10.18"
+  resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.10.18.tgz#930d43504a02fe0128a8d82f8c5361911b0dbd04"
+  integrity sha512-iN7IgLvM06iFk8BeFoWqvVpRFW3Z70f+Qe2PfCJ7vPIgLPjHXDE774DhCT5Y2/ZU/ZbXPDPD60x/XPWEoZLNdg==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/installations" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/installations" "0.6.19"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/app-check-compat@0.3.25":
-  version "0.3.25"
-  resolved "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.25.tgz"
-  integrity sha512-3zrsPZWAKfV7DVC20T2dgfjzjtQnSJS65OfMOiddMUtJL1S5i0nAZKsdX0bOEvvrd0SBIL8jYnfpfDeQRnhV3w==
+"@firebase/app-check-compat@0.4.0":
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.4.0.tgz#94ac0cf9f66cab1d81a7b14e0c151dcc2684bc95"
+  integrity sha512-UfK2Q8RJNjYM/8MFORltZRG9lJj11k0nW84rrffiKvcJxLf1jf6IEjCIkCamykHE73C6BwqhVfhIBs69GXQV0g==
   dependencies:
-    "@firebase/app-check" "0.10.0"
+    "@firebase/app-check" "0.11.0"
     "@firebase/app-check-types" "0.5.3"
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/app-check-interop-types@0.3.3":
@@ -294,52 +414,52 @@
   resolved "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz"
   integrity sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==
 
-"@firebase/app-check@0.10.0":
-  version "0.10.0"
-  resolved "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.10.0.tgz"
-  integrity sha512-AZlRlVWKcu8BH4Yf8B5EI8sOi2UNGTS8oMuthV45tbt6OVUTSQwFPIEboZzhNJNKY+fPsg7hH8vixUWFZ3lrhw==
+"@firebase/app-check@0.11.0":
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.11.0.tgz#a7e1d1e3f5ae36eabed1455db937114fe869ce8f"
+  integrity sha512-XAvALQayUMBJo58U/rxW02IhsesaxxfWVmVkauZvGEz3vOAjMEQnzFlyblqkc2iAaO82uJ2ZVyZv9XzPfxjJ6w==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/app-compat@0.4.0", "@firebase/app-compat@0.x":
-  version "0.4.0"
-  resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.4.0.tgz"
-  integrity sha512-LjLUrzbUgTa/sCtPoLKT2C7KShvLVHS3crnU1Du02YxnGVLE0CUBGY/NxgfR/Zg84mEbj1q08/dgesojxjn0dA==
+"@firebase/app-compat@0.5.0":
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/@firebase/app-compat/-/app-compat-0.5.0.tgz#7463e9fb8d84706787773d3660accedff4479d05"
+  integrity sha512-nUnNpOeRj0KZzVzHsyuyrmZKKHfykZ8mn40FtG28DeSTWeM5b/2P242Va4bmQpJsy5y32vfv50+jvdckrpzy7Q==
   dependencies:
-    "@firebase/app" "0.13.0"
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/app" "0.14.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/app-types@0.9.3", "@firebase/app-types@0.x":
+"@firebase/app-types@0.9.3":
   version "0.9.3"
   resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz"
   integrity sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==
 
-"@firebase/app@0.13.0", "@firebase/app@0.x":
-  version "0.13.0"
-  resolved "https://registry.npmjs.org/@firebase/app/-/app-0.13.0.tgz"
-  integrity sha512-Vj3MST245nq+V5UmmfEkB3isIgPouyUr8yGJlFeL9Trg/umG5ogAvrjAYvQ8gV7daKDoQSRnJKWI2JFpQqRsuQ==
+"@firebase/app@0.14.0":
+  version "0.14.0"
+  resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.14.0.tgz#7132e96df95e85783922fd09750f08ab2ebfd699"
+  integrity sha512-APIAeKvRNFWKJLjIL8wLDjh7u8g6ZjaeVmItyqSjCdEkJj14UuVlus74D8ofsOMWh45HEwxwkd96GYbi+CImEg==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     idb "7.1.1"
     tslib "^2.1.0"
 
-"@firebase/auth-compat@0.5.25":
-  version "0.5.25"
-  resolved "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.25.tgz"
-  integrity sha512-YKUYnvrxXBRhH/iYEwSOv85VPvc6P36GW1OCDRebTw/cvgoj7pwac2nZKYFs5FHlNYe7Bc9I4BoY2X0vlkJo+g==
+"@firebase/auth-compat@0.6.0":
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.6.0.tgz#1464ea6049b2ad0aae83b4fdcd5e5e5aba6b1c50"
+  integrity sha512-J0lGSxXlG/lYVi45wbpPhcWiWUMXevY4fvLZsN1GHh+po7TZVng+figdHBVhFheaiipU8HZyc7ljw1jNojM2nw==
   dependencies:
-    "@firebase/auth" "1.10.5"
+    "@firebase/auth" "1.11.0"
     "@firebase/auth-types" "0.13.0"
-    "@firebase/component" "0.6.17"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/auth-interop-types@0.2.4":
@@ -352,77 +472,77 @@
   resolved "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz"
   integrity sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==
 
-"@firebase/auth@1.10.5":
-  version "1.10.5"
-  resolved "https://registry.npmjs.org/@firebase/auth/-/auth-1.10.5.tgz"
-  integrity sha512-6wF/NdMTwObL4RNQePunuzMr9O3gyftisvFZFFKf57D2HONXo87YymogRV8d+Z7SLA0rcNBN1gLJVk2D0y97gA==
+"@firebase/auth@1.11.0":
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-1.11.0.tgz#81a4f77b16d97c502e493b2a14a97443e243a2a0"
+  integrity sha512-5j7+ua93X+IRcJ1oMDTClTo85l7Xe40WSkoJ+shzPrX7OISlVWLdE1mKC57PSD+/LfAbdhJmvKixINBw2ESK6w==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/component@0.6.17":
-  version "0.6.17"
-  resolved "https://registry.npmjs.org/@firebase/component/-/component-0.6.17.tgz"
-  integrity sha512-M6DOg7OySrKEFS8kxA3MU5/xc37fiOpKPMz6cTsMUcsuKB6CiZxxNAvgFta8HGRgEpZbi8WjGIj6Uf+TpOhyzg==
+"@firebase/component@0.7.0":
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.7.0.tgz#3736644fdb6d3572dceae7fdc1c35a8bd3819adc"
+  integrity sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg==
   dependencies:
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/data-connect@0.3.8":
-  version "0.3.8"
-  resolved "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.8.tgz"
-  integrity sha512-xC50SxurrP0j9ksltZ8O2SuPuWTu9KymNxtSE4bmcc/HMOnOHaURgLyrQpcC5Pc7HmtCBxh9Q/lNKyc37rj5/g==
+"@firebase/data-connect@0.3.11":
+  version "0.3.11"
+  resolved "https://registry.yarnpkg.com/@firebase/data-connect/-/data-connect-0.3.11.tgz#60a7a9649e4aedd005546032466ef9abc0a544c1"
+  integrity sha512-G258eLzAD6im9Bsw+Qm1Z+P4x0PGNQ45yeUuuqe5M9B1rn0RJvvsQCRHXgE52Z+n9+WX1OJd/crcuunvOGc7Vw==
   dependencies:
     "@firebase/auth-interop-types" "0.2.4"
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/database-compat@2.0.9":
-  version "2.0.9"
-  resolved "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.9.tgz"
-  integrity sha512-9S6zK5+Tzslkt+lrYHDqbCbKBSQn3YYrNLIw8hTa/ALoqRLNTXF6acQIlxAxSeZj1hTttE6RRbuxxpMQJYt83w==
-  dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/database" "1.0.18"
-    "@firebase/database-types" "1.0.14"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+"@firebase/database-compat@2.1.0":
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-2.1.0.tgz#c64488d741c6da2ed8dcf02f2e433089dae2f590"
+  integrity sha512-8nYc43RqxScsePVd1qe1xxvWNf0OBnbwHxmXJ7MHSuuTVYFO3eLyLW3PiCKJ9fHnmIz4p4LbieXwz+qtr9PZDg==
+  dependencies:
+    "@firebase/component" "0.7.0"
+    "@firebase/database" "1.1.0"
+    "@firebase/database-types" "1.0.16"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/database-types@1.0.14":
-  version "1.0.14"
-  resolved "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.14.tgz"
-  integrity sha512-8a0Q1GrxM0akgF0RiQHliinhmZd+UQPrxEmUv7MnQBYfVFiLtKOgs3g6ghRt/WEGJHyQNslZ+0PocIwNfoDwKw==
+"@firebase/database-types@1.0.16":
+  version "1.0.16"
+  resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-1.0.16.tgz#262f54b8dbebbc46259757b3ba384224fb2ede48"
+  integrity sha512-xkQLQfU5De7+SPhEGAXFBnDryUWhhlFXelEg2YeZOQMCdoe7dL64DDAd77SQsR+6uoXIZY5MB4y/inCs4GTfcw==
   dependencies:
     "@firebase/app-types" "0.9.3"
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
 
-"@firebase/database@1.0.18":
-  version "1.0.18"
-  resolved "https://registry.npmjs.org/@firebase/database/-/database-1.0.18.tgz"
-  integrity sha512-uXtYQmK6JCmqSx7dTOQD/qZtSnbMqnwvklF9n7wOJbdti4wKHmeUzgGXhPwDhN/R/BDTq78zKAbXya7hrCQjHw==
+"@firebase/database@1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@firebase/database/-/database-1.1.0.tgz#bdf60f1605079a87ceb2b5e30d90846e0bde294b"
+  integrity sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg==
   dependencies:
     "@firebase/app-check-interop-types" "0.3.3"
     "@firebase/auth-interop-types" "0.2.4"
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     faye-websocket "0.11.4"
     tslib "^2.1.0"
 
-"@firebase/firestore-compat@0.3.50":
-  version "0.3.50"
-  resolved "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.50.tgz"
-  integrity sha512-1hAM+iaIqy2HHvSHQ56ccOOIigTeWAwjIpeQ+/O92uBoiajEITHdJofnGHglhhB5VV5qFl59Yz/AVDc+DssdYg==
+"@firebase/firestore-compat@0.4.0":
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.4.0.tgz#911cf956e489fa8335ed2f2ace14a74909bcd94d"
+  integrity sha512-4O7v4VFeSEwAZtLjsaj33YrMHMRjplOIYC2CiYsF6o/MboOhrhe01VrTt8iY9Y5EwjRHuRz4pS6jMBT8LfQYJA==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/firestore" "4.7.15"
+    "@firebase/component" "0.7.0"
+    "@firebase/firestore" "4.9.0"
     "@firebase/firestore-types" "3.0.3"
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/firestore-types@3.0.3":
@@ -430,28 +550,28 @@
   resolved "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz"
   integrity sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==
 
-"@firebase/firestore@4.7.15":
-  version "4.7.15"
-  resolved "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.15.tgz"
-  integrity sha512-FgWTmkNBEXdKCoN2ngBNjrMaXuBx6QwjiZZVnOGg+VjUmiBq5gAqlDIW5bZY6i/NYvLUrWugdqIs7y9GHEqwww==
+"@firebase/firestore@4.9.0":
+  version "4.9.0"
+  resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-4.9.0.tgz#753d73c002b4c0ae639437b049ef0086791a0cf3"
+  integrity sha512-5zl0+/h1GvlCSLt06RMwqFsd7uqRtnNZt4sW99k2rKRd6k/ECObIWlEnvthm2cuOSnUmwZknFqtmd1qyYSLUuQ==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
-    "@firebase/webchannel-wrapper" "1.0.3"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
+    "@firebase/webchannel-wrapper" "1.0.4"
     "@grpc/grpc-js" "~1.9.0"
     "@grpc/proto-loader" "^0.7.8"
     tslib "^2.1.0"
 
-"@firebase/functions-compat@0.3.24":
-  version "0.3.24"
-  resolved "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.24.tgz"
-  integrity sha512-UjJabci+Bqci+A9WqfJ6sjZp+wGvi47llnQMjQRrF4coKfUyu9zBNTXhbx5W3rdVFQYwnWJm8VuluuNh2PCuyQ==
+"@firebase/functions-compat@0.4.0":
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.4.0.tgz#aa63dea248053e9c06904605704662ea550e50ed"
+  integrity sha512-VPgtvoGFywWbQqtvgJnVWIDFSHV1WE6Hmyi5EGI+P+56EskiGkmnw6lEqc/MEUfGpPGdvmc4I9XMU81uj766/g==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/functions" "0.12.7"
+    "@firebase/component" "0.7.0"
+    "@firebase/functions" "0.13.0"
     "@firebase/functions-types" "0.6.3"
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/functions-types@0.6.3":
@@ -459,27 +579,27 @@
   resolved "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz"
   integrity sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==
 
-"@firebase/functions@0.12.7":
-  version "0.12.7"
-  resolved "https://registry.npmjs.org/@firebase/functions/-/functions-0.12.7.tgz"
-  integrity sha512-gi8cw7yvaz19Erut+S0rHzNOWp4zPxAU/Kplb+XQoaE5gMV7MjHQoOGnYhSY8uOVj5f80S553s+2OBszG+14Ag==
+"@firebase/functions@0.13.0":
+  version "0.13.0"
+  resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.13.0.tgz#91685a59589b3a00f6c48faf383acd28a35800c2"
+  integrity sha512-2/LH5xIbD8aaLOWSFHAwwAybgSzHIM0dB5oVOL0zZnxFG1LctX2bc1NIAaPk1T+Zo9aVkLKUlB5fTXTkVUQprQ==
   dependencies:
     "@firebase/app-check-interop-types" "0.3.3"
     "@firebase/auth-interop-types" "0.2.4"
-    "@firebase/component" "0.6.17"
+    "@firebase/component" "0.7.0"
     "@firebase/messaging-interop-types" "0.2.3"
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/installations-compat@0.2.17":
-  version "0.2.17"
-  resolved "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.17.tgz"
-  integrity sha512-J7afeCXB7yq25FrrJAgbx8mn1nG1lZEubOLvYgG7ZHvyoOCK00sis5rj7TgDrLYJgdj/SJiGaO1BD3BAp55TeA==
+"@firebase/installations-compat@0.2.19":
+  version "0.2.19"
+  resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.19.tgz#4bc57c8c57d241eeca95900ff3033d6ec3dbcc7c"
+  integrity sha512-khfzIY3EI5LePePo7vT19/VEIH1E3iYsHknI/6ek9T8QCozAZshWT9CjlwOzZrKvTHMeNcbpo/VSOSIWDSjWdQ==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/installations" "0.6.17"
+    "@firebase/component" "0.7.0"
+    "@firebase/installations" "0.6.19"
     "@firebase/installations-types" "0.5.3"
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/installations-types@0.5.3":
@@ -487,31 +607,31 @@
   resolved "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz"
   integrity sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==
 
-"@firebase/installations@0.6.17":
-  version "0.6.17"
-  resolved "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.17.tgz"
-  integrity sha512-zfhqCNJZRe12KyADtRrtOj+SeSbD1H/K8J24oQAJVv/u02eQajEGlhZtcx9Qk7vhGWF5z9dvIygVDYqLL4o1XQ==
+"@firebase/installations@0.6.19":
+  version "0.6.19"
+  resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.19.tgz#93c569321f6fb399f4f1a197efc0053ce6452c7c"
+  integrity sha512-nGDmiwKLI1lerhwfwSHvMR9RZuIH5/8E3kgUWnVRqqL7kGVSktjLTWEMva7oh5yxQ3zXfIlIwJwMcaM5bK5j8Q==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/util" "1.13.0"
     idb "7.1.1"
     tslib "^2.1.0"
 
-"@firebase/logger@0.4.4":
-  version "0.4.4"
-  resolved "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz"
-  integrity sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==
+"@firebase/logger@0.5.0":
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.5.0.tgz#a9e55b1c669a0983dc67127fa4a5964ce8ed5e1b"
+  integrity sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g==
   dependencies:
     tslib "^2.1.0"
 
-"@firebase/messaging-compat@0.2.21":
-  version "0.2.21"
-  resolved "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.21.tgz"
-  integrity sha512-1yMne+4BGLbHbtyu/VyXWcLiefUE1+K3ZGfVTyKM4BH4ZwDFRGoWUGhhx+tKRX4Tu9z7+8JN67SjnwacyNWK5g==
+"@firebase/messaging-compat@0.2.23":
+  version "0.2.23"
+  resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.23.tgz#2ca6b36ea238fae4dff53bf85442c4a2af516224"
+  integrity sha512-SN857v/kBUvlQ9X/UjAqBoQ2FEaL1ZozpnmL1ByTe57iXkmnVVFm9KqAsTfmf+OEwWI4kJJe9NObtN/w22lUgg==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/messaging" "0.12.21"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/messaging" "0.12.23"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/messaging-interop-types@0.2.3":
@@ -519,28 +639,28 @@
   resolved "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz"
   integrity sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==
 
-"@firebase/messaging@0.12.21":
-  version "0.12.21"
-  resolved "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.21.tgz"
-  integrity sha512-bYJ2Evj167Z+lJ1ach6UglXz5dUKY1zrJZd15GagBUJSR7d9KfiM1W8dsyL0lDxcmhmA/sLaBYAAhF1uilwN0g==
+"@firebase/messaging@0.12.23":
+  version "0.12.23"
+  resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.23.tgz#71f932a521ac39d9f036175672e37897531010eb"
+  integrity sha512-cfuzv47XxqW4HH/OcR5rM+AlQd1xL/VhuaeW/wzMW1LFrsFcTn0GND/hak1vkQc2th8UisBcrkVcQAnOnKwYxg==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/installations" "0.6.17"
+    "@firebase/component" "0.7.0"
+    "@firebase/installations" "0.6.19"
     "@firebase/messaging-interop-types" "0.2.3"
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
     idb "7.1.1"
     tslib "^2.1.0"
 
-"@firebase/performance-compat@0.2.19":
-  version "0.2.19"
-  resolved "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.19.tgz"
-  integrity sha512-4cU0T0BJ+LZK/E/UwFcvpBCVdkStgBMQwBztM9fJPT6udrEUk3ugF5/HT+E2Z22FCXtIaXDukJbYkE/c3c6IHw==
+"@firebase/performance-compat@0.2.21":
+  version "0.2.21"
+  resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.21.tgz#60f04ecb5ff98b5d84a7a932f2e8294aae711c72"
+  integrity sha512-OQfYRsIQiEf9ez1SOMLb5TRevBHNIyA2x1GI1H10lZ432W96AK5r4LTM+SNApg84dxOuHt6RWSQWY7TPWffKXg==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/performance" "0.7.6"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/performance" "0.7.8"
     "@firebase/performance-types" "0.2.3"
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/performance-types@0.2.3":
@@ -548,28 +668,28 @@
   resolved "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz"
   integrity sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==
 
-"@firebase/performance@0.7.6":
-  version "0.7.6"
-  resolved "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.6.tgz"
-  integrity sha512-AsOz74dSTlyQGlnnbLWXiHFAsrxhpssPOsFFi4HgOJ5DjzkK7ZdZ/E9uMPrwFoXJyMVoybGRuqsL/wkIbFITsA==
+"@firebase/performance@0.7.8":
+  version "0.7.8"
+  resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.7.8.tgz#a3e5ff36070e0f26e59f84fcd8faf7a8ee77c677"
+  integrity sha512-k6xfNM/CdTl4RaV4gT/lH53NU+wP33JiN0pUeNBzGVNvfXZ3HbCkoISE3M/XaiOwHgded1l6XfLHa4zHgm0Wyg==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/installations" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/installations" "0.6.19"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
     web-vitals "^4.2.4"
 
-"@firebase/remote-config-compat@0.2.17":
-  version "0.2.17"
-  resolved "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.17.tgz"
-  integrity sha512-KelsBD0sXSC0u3esr/r6sJYGRN6pzn3bYuI/6pTvvmZbjBlxQkRabHAVH6d+YhLcjUXKIAYIjZszczd1QJtOyA==
+"@firebase/remote-config-compat@0.2.19":
+  version "0.2.19"
+  resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.19.tgz#10cfd804f65c5ca80a4d40994bc853ca6d1f7307"
+  integrity sha512-y7PZAb0l5+5oIgLJr88TNSelxuASGlXyAKj+3pUc4fDuRIdPNBoONMHaIUa9rlffBR5dErmaD2wUBJ7Z1a513Q==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/remote-config" "0.6.4"
+    "@firebase/component" "0.7.0"
+    "@firebase/logger" "0.5.0"
+    "@firebase/remote-config" "0.6.6"
     "@firebase/remote-config-types" "0.4.0"
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/remote-config-types@0.4.0":
@@ -577,26 +697,26 @@
   resolved "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz"
   integrity sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg==
 
-"@firebase/remote-config@0.6.4":
-  version "0.6.4"
-  resolved "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.6.4.tgz"
-  integrity sha512-ZyLJRT46wtycyz2+opEkGaoFUOqRQjt/0NX1WfUISOMCI/PuVoyDjqGpq24uK+e8D5NknyTpiXCVq5dowhScmg==
+"@firebase/remote-config@0.6.6":
+  version "0.6.6"
+  resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.6.6.tgz#50eae3d2d71791d76fb6521971bb646d6628805e"
+  integrity sha512-Yelp5xd8hM4NO1G1SuWrIk4h5K42mNwC98eWZ9YLVu6Z0S6hFk1mxotAdCRmH2luH8FASlYgLLq6OQLZ4nbnCA==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/installations" "0.6.17"
-    "@firebase/logger" "0.4.4"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/installations" "0.6.19"
+    "@firebase/logger" "0.5.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/storage-compat@0.3.21":
-  version "0.3.21"
-  resolved "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.21.tgz"
-  integrity sha512-LG3978H2Vy1XGa0Jz9VNFwgMrhjy/G8CTV8GkWpArzu+AhI/SE9c0e06SiXcFsVaQW2rObcqFa0zp51LDaVzRA==
+"@firebase/storage-compat@0.4.0":
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.4.0.tgz#a09bd33c262123e7e3ed0cd590b4c6e2ce4a8902"
+  integrity sha512-vDzhgGczr1OfcOy285YAPur5pWDEvD67w4thyeCUh6Ys0izN9fNYtA1MJERmNBfqjqu0lg0FM5GLbw0Il21M+g==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/storage" "0.13.11"
+    "@firebase/component" "0.7.0"
+    "@firebase/storage" "0.14.0"
     "@firebase/storage-types" "0.8.3"
-    "@firebase/util" "1.12.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
 "@firebase/storage-types@0.8.3":
@@ -604,26 +724,26 @@
   resolved "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz"
   integrity sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==
 
-"@firebase/storage@0.13.11":
-  version "0.13.11"
-  resolved "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.11.tgz"
-  integrity sha512-nBtCGGpr39vuAeTQhG73nvMq3BjQBTgIg6fWufB6qglWYQCgky/XE4duSrOhTp2/QC+H3/SnaE/nKOQmjnPqjg==
+"@firebase/storage@0.14.0":
+  version "0.14.0"
+  resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.14.0.tgz#01acb97d413ada7c91de860fb260623468baa25d"
+  integrity sha512-xWWbb15o6/pWEw8H01UQ1dC5U3rf8QTAzOChYyCpafV6Xki7KVp3Yaw2nSklUwHEziSWE9KoZJS7iYeyqWnYFA==
   dependencies:
-    "@firebase/component" "0.6.17"
-    "@firebase/util" "1.12.0"
+    "@firebase/component" "0.7.0"
+    "@firebase/util" "1.13.0"
     tslib "^2.1.0"
 
-"@firebase/util@1.12.0", "@firebase/util@1.x":
-  version "1.12.0"
-  resolved "https://registry.npmjs.org/@firebase/util/-/util-1.12.0.tgz"
-  integrity sha512-Z4rK23xBCwgKDqmzGVMef+Vb4xso2j5Q8OG0vVL4m4fA5ZjPMYQazu8OJJC3vtQRC3SQ/Pgx/6TPNVsCd70QRw==
+"@firebase/util@1.13.0":
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.13.0.tgz#2e9e7569722a1e3fc86b1b4076d5cbfbfa7265d6"
+  integrity sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ==
   dependencies:
     tslib "^2.1.0"
 
-"@firebase/webchannel-wrapper@1.0.3":
-  version "1.0.3"
-  resolved "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz"
-  integrity sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==
+"@firebase/webchannel-wrapper@1.0.4":
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.4.tgz#9d5b4b6f23309260a12856cb574c5e64e6c133f7"
+  integrity sha512-6m8+P+dE/RPl4OPzjTxcTbQ0rGeRyeTvAi9KwIffBVCiAMKrfXfLZaqD1F+m8t4B5/Q5aHsMozOgirkH1F5oMQ==
 
 "@grpc/grpc-js@~1.9.0":
   version "1.9.15"
@@ -711,7 +831,7 @@
     "@nodelib/fs.stat" "2.0.5"
     run-parallel "^1.1.9"
 
-"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
   version "2.0.5"
   resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
   integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
@@ -777,11 +897,106 @@
   resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz"
   integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
 
+"@rollup/rollup-android-arm-eabi@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz#d964ee8ce4d18acf9358f96adc408689b6e27fe3"
+  integrity sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==
+
+"@rollup/rollup-android-arm64@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz#9b5e130ecc32a5fc1e96c09ff371743ee71a62d3"
+  integrity sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==
+
 "@rollup/rollup-darwin-arm64@4.40.0":
   version "4.40.0"
   resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz"
   integrity sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==
 
+"@rollup/rollup-darwin-x64@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz#d7380c1531ab0420ca3be16f17018ef72dd3d504"
+  integrity sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==
+
+"@rollup/rollup-freebsd-arm64@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz#cbcbd7248823c6b430ce543c59906dd3c6df0936"
+  integrity sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==
+
+"@rollup/rollup-freebsd-x64@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz#96bf6ff875bab5219c3472c95fa6eb992586a93b"
+  integrity sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz#d80cd62ce6d40f8e611008d8dbf03b5e6bbf009c"
+  integrity sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==
+
+"@rollup/rollup-linux-arm-musleabihf@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz#75440cfc1e8d0f87a239b4c31dfeaf4719b656b7"
+  integrity sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==
+
+"@rollup/rollup-linux-arm64-gnu@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz#ac527485ecbb619247fb08253ec8c551a0712e7c"
+  integrity sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==
+
+"@rollup/rollup-linux-arm64-musl@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz#74d2b5cb11cf714cd7d1682e7c8b39140e908552"
+  integrity sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==
+
+"@rollup/rollup-linux-loongarch64-gnu@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz#a0a310e51da0b5fea0e944b0abd4be899819aef6"
+  integrity sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==
+
+"@rollup/rollup-linux-powerpc64le-gnu@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz#4077e2862b0ac9f61916d6b474d988171bd43b83"
+  integrity sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==
+
+"@rollup/rollup-linux-riscv64-gnu@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz#5812a1a7a2f9581cbe12597307cc7ba3321cf2f3"
+  integrity sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==
+
+"@rollup/rollup-linux-riscv64-musl@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz#973aaaf4adef4531375c36616de4e01647f90039"
+  integrity sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==
+
+"@rollup/rollup-linux-s390x-gnu@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz#9bad59e907ba5bfcf3e9dbd0247dfe583112f70b"
+  integrity sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==
+
+"@rollup/rollup-linux-x64-gnu@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz#68b045a720bd9b4d905f462b997590c2190a6de0"
+  integrity sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==
+
+"@rollup/rollup-linux-x64-musl@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz#8e703e2c2ad19ba7b2cb3d8c3a4ad11d4ee3a282"
+  integrity sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==
+
+"@rollup/rollup-win32-arm64-msvc@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz#c5bee19fa670ff5da5f066be6a58b4568e9c650b"
+  integrity sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==
+
+"@rollup/rollup-win32-ia32-msvc@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz#846e02c17044bd922f6f483a3b4d36aac6e2b921"
+  integrity sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==
+
+"@rollup/rollup-win32-x64-msvc@4.40.0":
+  version "4.40.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz#fd92d31a2931483c25677b9c6698106490cbbc76"
+  integrity sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==
+
 "@types/babel__core@^7.20.5":
   version "7.20.5"
   resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
@@ -815,7 +1030,7 @@
   dependencies:
     "@babel/types" "^7.20.7"
 
-"@types/estree@^1.0.6", "@types/estree@1.0.7":
+"@types/estree@1.0.7", "@types/estree@^1.0.6":
   version "1.0.7"
   resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz"
   integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==
@@ -825,7 +1040,7 @@
   resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
   integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
 
-"@types/node@^18.0.0 || ^20.0.0 || >=22.0.0", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
+"@types/node@>=12.12.47", "@types/node@>=13.7.0":
   version "22.14.1"
   resolved "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz"
   integrity sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==
@@ -837,7 +1052,7 @@
   resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz"
   integrity sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==
 
-"@types/react@^19.0.0", "@types/react@^19.0.10":
+"@types/react@^19.0.10":
   version "19.1.2"
   resolved "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz"
   integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==
@@ -859,7 +1074,7 @@
     natural-compare "^1.4.0"
     ts-api-utils "^2.0.1"
 
-"@typescript-eslint/parser@^8.0.0 || ^8.0.0-alpha.0", "@typescript-eslint/parser@8.31.0":
+"@typescript-eslint/parser@8.31.0":
   version "8.31.0"
   resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz"
   integrity sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==
@@ -941,7 +1156,7 @@ acorn-jsx@^5.3.2:
   resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
   integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
 
-"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.14.0:
+acorn@^8.14.0:
   version "8.14.1"
   resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz"
   integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==
@@ -1000,7 +1215,7 @@ braces@^3.0.3:
   dependencies:
     fill-range "^7.1.1"
 
-browserslist@^4.24.0, "browserslist@>= 4.21.0":
+browserslist@^4.24.0:
   version "4.24.4"
   resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz"
   integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==
@@ -1169,7 +1384,7 @@ eslint-visitor-keys@^4.2.0:
   resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz"
   integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
 
-"eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9.22.0, eslint@>=7.0.0, eslint@>=8.40:
+eslint@^9.22.0:
   version "9.25.1"
   resolved "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz"
   integrity sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==
@@ -1310,39 +1525,39 @@ find-up@^5.0.0:
     locate-path "^6.0.0"
     path-exists "^4.0.0"
 
-firebase@11.8.0:
-  version "11.8.0"
-  resolved "https://registry.npmjs.org/firebase/-/firebase-11.8.0.tgz"
-  integrity sha512-zIv11czOqFayPllaJySKIKB2pS+xoWOnfI7j85SOiBKY1IW3NuZIaL+UgsZA+4PQZkPhFP8vmU2/oOun04ALbg==
-  dependencies:
-    "@firebase/ai" "1.3.0"
-    "@firebase/analytics" "0.10.16"
-    "@firebase/analytics-compat" "0.2.22"
-    "@firebase/app" "0.13.0"
-    "@firebase/app-check" "0.10.0"
-    "@firebase/app-check-compat" "0.3.25"
-    "@firebase/app-compat" "0.4.0"
+firebase@12.0.0:
+  version "12.0.0"
+  resolved "https://registry.yarnpkg.com/firebase/-/firebase-12.0.0.tgz#436ee1b97b64265f3e7d3b6b0ce4419cc9fe5ae9"
+  integrity sha512-KV+OrMJpi2uXlqL2zaCcXb7YuQbY/gMIWT1hf8hKeTW1bSumWaHT5qfmn0WTpHwKQa3QEVOtZR2ta9EchcmYuw==
+  dependencies:
+    "@firebase/ai" "2.0.0"
+    "@firebase/analytics" "0.10.18"
+    "@firebase/analytics-compat" "0.2.24"
+    "@firebase/app" "0.14.0"
+    "@firebase/app-check" "0.11.0"
+    "@firebase/app-check-compat" "0.4.0"
+    "@firebase/app-compat" "0.5.0"
     "@firebase/app-types" "0.9.3"
-    "@firebase/auth" "1.10.5"
-    "@firebase/auth-compat" "0.5.25"
-    "@firebase/data-connect" "0.3.8"
-    "@firebase/database" "1.0.18"
-    "@firebase/database-compat" "2.0.9"
-    "@firebase/firestore" "4.7.15"
-    "@firebase/firestore-compat" "0.3.50"
-    "@firebase/functions" "0.12.7"
-    "@firebase/functions-compat" "0.3.24"
-    "@firebase/installations" "0.6.17"
-    "@firebase/installations-compat" "0.2.17"
-    "@firebase/messaging" "0.12.21"
-    "@firebase/messaging-compat" "0.2.21"
-    "@firebase/performance" "0.7.6"
-    "@firebase/performance-compat" "0.2.19"
-    "@firebase/remote-config" "0.6.4"
-    "@firebase/remote-config-compat" "0.2.17"
-    "@firebase/storage" "0.13.11"
-    "@firebase/storage-compat" "0.3.21"
-    "@firebase/util" "1.12.0"
+    "@firebase/auth" "1.11.0"
+    "@firebase/auth-compat" "0.6.0"
+    "@firebase/data-connect" "0.3.11"
+    "@firebase/database" "1.1.0"
+    "@firebase/database-compat" "2.1.0"
+    "@firebase/firestore" "4.9.0"
+    "@firebase/firestore-compat" "0.4.0"
+    "@firebase/functions" "0.13.0"
+    "@firebase/functions-compat" "0.4.0"
+    "@firebase/installations" "0.6.19"
+    "@firebase/installations-compat" "0.2.19"
+    "@firebase/messaging" "0.12.23"
+    "@firebase/messaging-compat" "0.2.23"
+    "@firebase/performance" "0.7.8"
+    "@firebase/performance-compat" "0.2.21"
+    "@firebase/remote-config" "0.6.6"
+    "@firebase/remote-config-compat" "0.2.19"
+    "@firebase/storage" "0.14.0"
+    "@firebase/storage-compat" "0.4.0"
+    "@firebase/util" "1.13.0"
 
 flat-cache@^4.0.0:
   version "4.0.1"
@@ -1652,7 +1867,7 @@ picomatch@^2.3.1:
   resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
   integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
 
-"picomatch@^3 || ^4", picomatch@^4.0.2:
+picomatch@^4.0.2:
   version "4.0.2"
   resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz"
   integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
@@ -1716,7 +1931,7 @@ react-refresh@^0.17.0:
   resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz"
   integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
 
-react@^19.0.0, react@^19.1.0:
+react@^19.0.0:
   version "19.1.0"
   resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz"
   integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==
@@ -1878,7 +2093,7 @@ typescript-eslint@^8.26.1:
     "@typescript-eslint/parser" "8.31.0"
     "@typescript-eslint/utils" "8.31.0"
 
-typescript@>=4.8.4, "typescript@>=4.8.4 <5.9.0", typescript@~5.7.2:
+typescript@~5.7.2:
   version "5.7.3"
   resolved "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz"
   integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==
@@ -1903,7 +2118,7 @@ uri-js@^4.2.2:
   dependencies:
     punycode "^2.1.0"
 
-"vite@^4.2.0 || ^5.0.0 || ^6.0.0", vite@^6.3.1:
+vite@^6.3.1:
   version "6.3.2"
   resolved "https://registry.npmjs.org/vite/-/vite-6.3.2.tgz"
   integrity sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==

From 38aa420e7218af5f8201b2fa28acb0e335ef83ed Mon Sep 17 00:00:00 2001
From: Daniel La Rocque <dlarocque@google.com>
Date: Fri, 8 Aug 2025 13:00:52 -0400
Subject: [PATCH 82/82] Add workflow to verify Firebase AI sample app build
 (#901)

---
 .github/workflows/firebase-ai-check.yml | 35 +++++++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 .github/workflows/firebase-ai-check.yml

diff --git a/.github/workflows/firebase-ai-check.yml b/.github/workflows/firebase-ai-check.yml
new file mode 100644
index 000000000..d06b41582
--- /dev/null
+++ b/.github/workflows/firebase-ai-check.yml
@@ -0,0 +1,35 @@
+name: Check Firebase AI Samples
+
+permissions:
+  contents: read
+
+on:
+  pull_request:
+    branches:
+      - main
+    paths:
+      - 'ai/ai-react-app/**'
+
+jobs:
+  build-react-app:
+    name: Build React App
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+
+      - name: Set up Node
+        uses: actions/setup-node@v4
+        with:
+          node-version: '22'
+          cache: 'yarn'
+          cache-dependency-path: 'ai/ai-react-app/yarn.lock'
+
+      - name: Install dependencies
+        run: yarn install --frozen-lockfile
+        working-directory: ./ai/ai-react-app
+
+      - name: Build application
+        run: yarn build
+        working-directory: ./ai/ai-react-app
