From bcf9ca9dadd0cda099c9cca59ca5a880e7285fc1 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 20 Apr 2026 15:46:44 -0700 Subject: [PATCH 1/8] initial changes for next --- app/components/ImageLayout.tsx | 2 +- app/firebase/data.ts | 122 +++--- app/routes/generate.tsx | 2 +- app/routes/recipes.tsx | 10 +- firestore.rules | 20 +- package-lock.json | 757 +++++++++++++++------------------ package.json | 12 +- 7 files changed, 431 insertions(+), 494 deletions(-) diff --git a/app/components/ImageLayout.tsx b/app/components/ImageLayout.tsx index 955a3d8..a2bfee8 100644 --- a/app/components/ImageLayout.tsx +++ b/app/components/ImageLayout.tsx @@ -45,7 +45,7 @@ const Layout: React.FC = () => { ...generatedRecipe, authorId: user.uid, averageRating: 0, - saves: 0, + likes: 0, tags: generatedRecipe.tags || [] }; const savedRecipeId = await publishRecipe(user.uid, recipeToSave); diff --git a/app/firebase/data.ts b/app/firebase/data.ts index 9bf73f9..fdad231 100644 --- a/app/firebase/data.ts +++ b/app/firebase/data.ts @@ -1,5 +1,5 @@ import { initializeFirestore, addDoc, collection, getDoc, doc, deleteDoc, updateDoc, persistentLocalCache, setDoc, getDocs, query, where, runTransaction, increment } from "firebase/firestore"; -import { execute, field, countAll } from "firebase/firestore/pipelines"; +import { execute, field, countAll, subcollection, average, variable, score, documentMatches } from "firebase/firestore/pipelines"; import { firebaseApp } from "./firebase"; export interface Review { @@ -36,7 +36,7 @@ export interface Recipe { authorId: string; tags: string[]; averageRating: number; - saves: number; + likes: number; prepTime: string; cookTime: string; servings: string; @@ -70,17 +70,32 @@ export async function publishRecipe(userId: string, recipe: Omit): } export async function getRecipe(recipeId: string): Promise { - const recipeRef = doc(db, `recipes/${recipeId}`); - const recipeSnapshot = await getDoc(recipeRef); + const pipeline = db.pipeline() + .documents([`recipes/${recipeId}`]) + .define(field("__name__").as("parentRecipeId")) + .addFields( + subcollection("reviews") + .aggregate(average("rating").as("avg")) + .toScalarExpression() + .as("averageRating"), + db.pipeline() + .collection("likes") + .where(field("recipeId").equal(variable("parentRecipeId"))) + .aggregate(countAll().as("count")) + .toScalarExpression() + .as("likes") + ); + + const { results } = await execute(pipeline); + const result = results[0]; - if (!recipeSnapshot.exists()) { + if (!result) { return null; } - const recipeData = recipeSnapshot.data() as Recipe; return { - ...recipeData, - id: recipeSnapshot.id, + ...result.data(), + id: result.id, } as Recipe; } @@ -96,52 +111,24 @@ export async function addReview(recipeId: string, userId: string, rating: number rating, text: text || "" }); - - // get the new average of all reviews - const pipeline = db.pipeline() - .collection(`recipes/${recipeId}/reviews`) - .aggregate(field("rating").average().as("averageRating")); - const { results } = await execute(pipeline); - const data = results[0]?.data(); - - let average = data && 'averageRating' in data ? data.averageRating as number : null; - if (!average) { - // there isn't an average yet, so set it to our new review score - average = rating; - } - - // set the new average rating - await runTransaction(db, async transaction => { - const recipeRef = doc(db, `recipes/${recipeId}`); - transaction.update(recipeRef, { averageRating: average }); - }); } export async function likeRecipe(userId: string, recipeId: string) { const likeId = `${recipeId}_${userId}`; - await setDoc(doc(db, "saves", likeId), { + await setDoc(doc(db, "likes", likeId), { userId, recipeId }); - - - // increment the total likes on the recipe itself - const recipeRef = doc(db, `recipes/${recipeId}`); - await updateDoc(recipeRef, { saves: increment(1) }); } export async function unlikeRecipe(userId: string, recipeId: string) { const likeId = `${recipeId}_${userId}`; - await deleteDoc(doc(db, "saves", likeId)); - - // decrement the total likes on the recipe itself - const recipeRef = doc(db, `recipes/${recipeId}`); - await updateDoc(recipeRef, { saves: increment(-1) }); + await deleteDoc(doc(db, "likes", likeId)); } export async function isRecipeLikedByUser(userId: string, recipeId: string): Promise { const pipeline = db.pipeline() - .collection("saves") + .collection("likes") .where(field("userId").equal(userId)) .where(field("recipeId").equal(recipeId)) .limit(1); @@ -155,17 +142,36 @@ export async function queryRecipes(filters: { minRating?: number; tags?: string[]; authorId?: string; - savedOnly?: true; + likedOnly?: boolean; sort?: string; }): Promise { let pipeline = db.pipeline().collection("recipes"); - if (filters.authorId) { - pipeline = pipeline.where(field("authorId").equal(filters.authorId)); + if (filters.searchTerm) { + pipeline = pipeline.search({ + query: documentMatches(filters.searchTerm), + addFields: [ + score().as("searchScore") + ] + }); } - if (filters.searchTerm) { - pipeline = pipeline.where(field("title").like(`%${filters.searchTerm}%`)); + pipeline = pipeline.define(field("__name__").as("parentRecipeId")) + .addFields( + subcollection("reviews") + .aggregate(average("rating").as("avg")) + .toScalarExpression() + .as("averageRating"), + db.pipeline() + .collection("likes") + .where(field("recipeId").equal(variable("parentRecipeId"))) + .aggregate(countAll().as("count")) + .toScalarExpression() + .as("likes") + ); + + if (filters.authorId) { + pipeline = pipeline.where(field("authorId").equal(filters.authorId)); } if (filters.minRating && filters.minRating > 0) { @@ -176,16 +182,24 @@ export async function queryRecipes(filters: { pipeline = pipeline.where(field("tags").arrayContainsAny(filters.tags)); } - switch (filters.sort) { - case 'title': - pipeline = pipeline.sort(field('title').ascending()); - break; - case 'rating': - pipeline = pipeline.sort(field('averageRating').descending()); - break; - case 'saves': - pipeline = pipeline.sort(field('saves').descending()); - break; + if (filters.likedOnly) { + pipeline = pipeline.where(field("likes").greaterThan(0)); + } + + if (filters.sort) { + switch (filters.sort) { + case 'title': + pipeline = pipeline.sort(field('title').ascending()); + break; + case 'rating': + pipeline = pipeline.sort(field('averageRating').descending()); + break; + case 'likes': + pipeline = pipeline.sort(field('likes').descending()); + break; + } + } else if (filters.searchTerm) { + pipeline = pipeline.sort(field('searchScore').descending()); } const { results } = await execute(pipeline); diff --git a/app/routes/generate.tsx b/app/routes/generate.tsx index 6a415fc..9cecf7f 100644 --- a/app/routes/generate.tsx +++ b/app/routes/generate.tsx @@ -53,7 +53,7 @@ export default function GeneratePage() { ...generatedRecipe, authorId: user.uid, averageRating: 0, - saves: 0, + likes: 0, tags: generatedRecipe.tags || [] }; const savedRecipeId = await publishRecipe(user.uid, recipeToSave); diff --git a/app/routes/recipes.tsx b/app/routes/recipes.tsx index 4e0c9be..8a89e69 100644 --- a/app/routes/recipes.tsx +++ b/app/routes/recipes.tsx @@ -87,7 +87,7 @@ const FilterPanel: React.FC<{ const [searchParams, setSearchParams] = useSearchParams(); const name = searchParams.get('q') || ''; - const sortBy = (searchParams.get('sort') as 'rating' | 'title' | 'saves') || ''; + const sortBy = (searchParams.get('sort') as 'rating' | 'title' | 'likes') || ''; const myRecipes = searchParams.get('myRecipes') === 'on'; const searchParamsSelectedTags: string[] = searchParams.get('tags')?.split(',').filter(Boolean) || []; const searchParamsMinRating = Number(searchParams.get('minRating')) || 0; @@ -250,11 +250,11 @@ const FilterPanel: React.FC<{ - Saves + Likes @@ -336,7 +336,7 @@ export default function RecipesPage({ loaderData }: Route.loaderData) {
- {recipe.saves || 0} saves + {recipe.likes || 0} likes
diff --git a/firestore.rules b/firestore.rules index cdc078c..14e0683 100644 --- a/firestore.rules +++ b/firestore.rules @@ -5,15 +5,15 @@ service cloud.firestore { // Recipes collection - root level // Anyone authenticated can read recipes - // Only the author can create/update/delete their own recipes + // Only the author can create/delete their own recipes match /recipes/{recipeId} { allow read: if request.auth != null; allow create: if request.auth != null && request.resource.data.authorId == request.auth.uid; + // Note: Updates to denormalized averageRating/likes are no longer needed + // as they are calculated on-the-fly via subqueries. allow update: if request.auth != null - && ( - request.resource.data.diff(resource.data).affectedKeys().hasOnly(["saves"]) - || request.resource.data.diff(resource.data).affectedKeys().hasOnly(["averageRating"])); + && resource.data.authorId == request.auth.uid; allow delete: if request.auth != null && resource.data.authorId == request.auth.uid; @@ -25,18 +25,16 @@ service cloud.firestore { allow read: if request.auth != null; allow create: if request.auth != null && request.resource.data.userId == request.auth.uid; - allow update: if request.auth != null - && request.resource.data.diff(resource.data).affectedKeys().hasOnly(["saves", "averageRating"]); allow delete: if request.auth != null && resource.data.userId == request.auth.uid; } } - // Saves collection - root level (bookmarks) - // Anyone authenticated can read saves - // Users can only create saves with their own userId - // Users can only delete their own saves - match /saves/{saveId} { + // Likes collection - root level (bookmarks) + // Anyone authenticated can read likes + // Users can only create likes with their own userId + // Users can only delete their own likes + match /likes/{likeId} { allow read: if request.auth != null; allow create: if request.auth != null && request.resource.data.userId == request.auth.uid; diff --git a/package-lock.json b/package-lock.json index ecfd748..dd0a587 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@tailwindcss/vite": "^4.1.18", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "firebase": "^12.5.0-eap-firestore-pipelines.2.e4cdd2e06", + "firebase": "^12.12.0", "isbot": "^5", "lucide-react": "^0.562.0", "react": "^19.1.0", @@ -1122,72 +1122,67 @@ } }, "node_modules/@firebase/ai": { - "version": "2.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-2.5.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-ZMHpwMCFL6zDDXdqFDx7KKKOqxkb29QHxM7r/Yqtv6Lkpky/yagR5A18PUVOni3fIeNz9UMGTeK2PTOsh75Inw==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/app-check-interop-types": "0.3.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-2.11.0.tgz", + "integrity": "sha512-+oqOne/h5J51LezazR+VyzKe3AK455W29JXnb4jOeVvQhC7FymledN5+XE+w5vEcMhRQ6n1f62fdGs4A44X32A==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/app-types": "0.9.3-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x", + "@firebase/app-types": "0.x" } }, "node_modules/@firebase/analytics": { - "version": "0.10.19-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.19-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-LHuebTOzWoRzLeqaXOKgdZeT5GRHuFvBtKluQS456IgEmBLW27QPFrhjO6zvFvAPtqtK5Zcn2BtmLJTwrzYihg==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/installations": "0.6.19-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.10.21", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.21.tgz", + "integrity": "sha512-j2y2q65BlgLGB5Pwjhv/Jopw2X/TBTzvAtI5z/DSp56U4wBj7LfhBfzbdCtFPges+Wz0g55GdoawXibOH5jGng==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/analytics-compat": { - "version": "0.2.25-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.25-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-4wQT8SP+rZXB6tYKAamoBp0Bmcoc9FPbIqnAo9qkbdyM3oVqDMJ2cwrn5XK6VaUJ1d1Aw585Cfb1yu8cdHoQhA==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/analytics": "0.10.19-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/analytics-types": "0.8.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.27.tgz", + "integrity": "sha512-ZObpYpAxL6JfgH7GnvlDD0sbzGZ0o4nijV8skatV9ZX49hJtCYbFqaEcPYptT94rgX1KUoKEderC7/fa7hybtw==", + "dependencies": { + "@firebase/analytics": "0.10.21", + "@firebase/analytics-types": "0.8.3", + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/analytics-types": { - "version": "0.8.3-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-EyJ/mP4PAp8mLSIFdqiIlv21dopDCDOpkl/uUAT40T5A3rU/FirBLFigNDLKDJELfSPXqa+ie5BkK9ZFubm4LA==", - "license": "Apache-2.0" + "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.14.5-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.5-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-WKXfIVmtFpfcWMOqO0LoOdYji924DzpHAd8nH5eFRkqhIorLNcECuamE+eyzorkT4+yzblbsS5ovxBaXajT+PQ==", - "license": "Apache-2.0", + "version": "0.14.11", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.11.tgz", + "integrity": "sha512-yxADFW35LYkP8oSGobGsYIrI42I+GPCvKTNHx4meT9Yq3C950IVz1eANoBk822I9tbKv1wyv9P4Bv1G5TpucFw==", "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "idb": "7.1.1", "tslib": "^2.1.0" }, @@ -1196,65 +1191,60 @@ } }, "node_modules/@firebase/app-check": { - "version": "0.11.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.11.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-vZT0+sWOHPwUx4yBTLPMJS6kV1iAc0ivHa9arAS/t3YBqUjLZmvnrNMQ+pxZwrS1MvFKc4tta6zp/MdHRT1bCA==", - "license": "Apache-2.0", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.11.2.tgz", + "integrity": "sha512-jcXQVMHAQ5AEKzVD5C7s5fmAYeFOuN6lAJeNTgZK2B9aLnofWaJt8u1A8Idm8gpsBBYSaY3cVyeH5SWMOVPBLQ==", "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/app-check-compat": { - "version": "0.4.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.4.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-DfkRKAuERSRHFvZFxfHRF+Yzt53x5FJ6WIUeBePwxtY9Zv3gGaeoYUceIxpFMzieQU06i6QMF0GbvMLjhhbidA==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/app-check": "0.11.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/app-check-types": "0.5.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.4.2.tgz", + "integrity": "sha512-M91NhxqbSkI0ChkJWy69blC+rPr6HEgaeRllddSaU1pQ/7IiegeCQM9pPDIgvWnwnBSzKhUHpe6ro/jhJ+cvzw==", + "dependencies": { + "@firebase/app-check": "0.11.2", + "@firebase/app-check-types": "0.5.3", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/app-check-interop-types": { - "version": "0.3.3-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-Tw/1zsqaGwtwdkipoULhRDnkHZoj5FTe/pLY5NxtSO+3Hulz15ZCOJqQbZnUSeoy50zrcPwsoG8Souvgv6Zpfw==", - "license": "Apache-2.0" + "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-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-C7CNHN+4KVm6gYaSw9dyl5edEKBeMYatZx8rsX7CA/WLVfHmk6BpEVLDugo+L7N39F9mNYWxdSuI7kTIczRpNg==", - "license": "Apache-2.0" + "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.5.5-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.5-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-AW69+V1pG5uM+svsi2HX6Idkx4AALYEUTWRjDXCpYhPeSZLIGr/cuU54Shcjx3emjpby5ePma7lY/+NPYZvkig==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.11.tgz", + "integrity": "sha512-KaACDjXkK5VLpI01vEs592R7/8s5DjFdIXfKoR385ly1SmK3Tu+jMHCIB4MsiY5jsez6v7VlEX/3rJ90dVkHyA==", + "dependencies": { + "@firebase/app": "0.14.11", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { @@ -1262,28 +1252,29 @@ } }, "node_modules/@firebase/app-types": { - "version": "0.9.3-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-GBdqE9dVOVbCnUOFXWiFk58CgV4U3satUjvQ/KyiF6LfXwfChgsmYHkwk20SvHfER4F0J9C/Pj2koTNqGi0uAg==", - "license": "Apache-2.0" + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.4.tgz", + "integrity": "sha512-crX9TA5SVYZwLPG7/R16IsH8FLlgkPXjJUVhsVpHVDSqJiq3D/NuFTM5ctxGTExXAOeIn//69tQw47CPerM8MQ==", + "dependencies": { + "@firebase/logger": "0.5.0" + } }, "node_modules/@firebase/auth": { - "version": "1.11.1-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.11.1-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-I6HLNPsQ3Ornq1bp4FzkA3k4WdUNf+lyu+4NIevjktRNp1GvDmeatmPlB27Nx7QbjiEwRpTk4yKVtml1KNT4Og==", - "license": "Apache-2.0", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.13.0.tgz", + "integrity": "sha512-mKkSLNym3UbnnZ06dAmtqzp5EpPGCANGCZDJbkoR135aoUdKG6Aizwcnp29RzsQpwH0nmy5nay17Sfbsh9oY8A==", "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06", - "@react-native-async-storage/async-storage": "^1.18.1" + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^2.2.0 || ^3.0.0" }, "peerDependenciesMeta": { "@react-native-async-storage/async-storage": { @@ -1292,47 +1283,43 @@ } }, "node_modules/@firebase/auth-compat": { - "version": "0.6.1-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.6.1-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-HPrQzbwu0LC4m0kVAdKlDD5bP7ANsgwJcj/MDXxLu9GquCyK5HRPyuxmNtR2IhsuRY4fVrVHKVC5QcWtftP+CQ==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/auth": "1.11.1-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/auth-types": "0.13.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.6.5.tgz", + "integrity": "sha512-IfVsafZ3QiXbsydXTP/XMI0wVYbJLI1rkb8Qqf03/h5FnL+upbbPOb+6Yj3RpcX+Y1iP5Uh18lxTHlXfbiyAow==", + "dependencies": { + "@firebase/auth": "1.13.0", + "@firebase/auth-types": "0.13.0", + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/auth-interop-types": { - "version": "0.2.4-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-Uz42uhNwXd8J5HPWBNRbxPIcf3fLonW2AhK9Gxi8jCIRq9xWKfUgEGw1a4ffuSCTXNlo2lFofAxZ+ZYtXGEnow==", - "license": "Apache-2.0" + "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.13.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-CR6tqzkOBILphsnnhO1sKqfQQosrusQ60a+wRDGO44tIjdmR6jHOZ206rWbBdyjLyW6+sYCF+nOLqDWzyzm0hw==", - "license": "Apache-2.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==", "peerDependencies": { - "@firebase/app-types": "0.9.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" } }, "node_modules/@firebase/component": { - "version": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.7.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-c3+5S0uGsTFycG0HcZN5IVyL6WOymY5a5Kb7uDhkPgAvApH5uK/zYCZ3BccNTnVlqkFueuEOzjMJX7VL9ZC4LQ==", - "license": "Apache-2.0", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.7.2.tgz", + "integrity": "sha512-iyVDGc6Vjx7Rm0cAdccLH/NG6fADsgJak/XW9IA2lPf8AjIlsemOpFGKczYyPHxm4rnKdR8z6sK4+KEC7NwmEg==", "dependencies": { - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { @@ -1340,32 +1327,30 @@ } }, "node_modules/@firebase/data-connect": { - "version": "0.3.11-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.11-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-RW6xx69vm3EH2xSkGDdh5yiVskyrj7IilInPAFPUL06ZErXC/DwMQ6obfrlJiroYAPg+CoBVNACVNF2Kp4Fk3A==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/auth-interop-types": "0.2.4-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.6.0.tgz", + "integrity": "sha512-OiugPRcdlhqXF97oR9CjVObILmsWU0dFUS0gXNYEe4bDfpW8pZmQ5GqhIPPtLWbT/0W2lMJJD7VILFMk+xuHPg==", + "dependencies": { + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/database": { - "version": "1.1.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.1.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-pyVk2YQaPEFLq0Vhx1+D1d85ScItaHCyAq7wGBnLU1jpSjjt62PdxdQ1h4IQRq+sahRhiL50K+yYpz8Nkz69fQ==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/app-check-interop-types": "0.3.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/auth-interop-types": "0.2.4-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.1.2.tgz", + "integrity": "sha512-lP96CMjMPy/+d1d9qaaHjHHdzdwvEOuyyLq9ehX89e2XMKwS1jHNzYBO+42bdSumuj5ukPbmnFtViZu8YOMT+w==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "faye-websocket": "0.11.4", "tslib": "^2.1.0" }, @@ -1374,16 +1359,15 @@ } }, "node_modules/@firebase/database-compat": { - "version": "2.1.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.1.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-LInQyPckpmpZytEL7su2lVtsd0EbSzW2OnhKzM286W9dP9ksDvQp9DBZlxAtwrJzjb/F20+myOCTupuFY5NQvA==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/database": "1.1.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/database-types": "1.0.16-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.1.3.tgz", + "integrity": "sha512-GMyfWjD8mehjg/QpNkY/tl9G/MoeugPeg91n9D0atggxbWuKF/2KhVPHZDH+XmoP0EKYqMWYTtKxBsaBaNKLYQ==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/database": "1.1.2", + "@firebase/database-types": "1.0.19", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { @@ -1391,25 +1375,23 @@ } }, "node_modules/@firebase/database-types": { - "version": "1.0.16-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.16-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-puHvqfISx3jXb55lRBi5fuz/UeE5l9elumYJgDPdtOyDzMVjg1OTjPNfsDGQigWFjgxRKfV1rAE/n8KgQE5zfg==", - "license": "Apache-2.0", + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.19.tgz", + "integrity": "sha512-FqewjUZmV9LqFfuEnmgdcUpiOUz7qwLXxnm/H8BcMFEzQXtd1yyUDm8ex5VRad2nuTE+ahOuCjUAM/cyDncO+g==", "dependencies": { - "@firebase/app-types": "0.9.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-types": "0.9.4", + "@firebase/util": "1.15.0" } }, "node_modules/@firebase/firestore": { - "version": "4.9.2-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.9.2-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-Jg3Hkkpd9N4ybAtkz/74SsV2NtXGprcIabeBAyncEhp4tBsR0DVIsCExT3176OzHe5jsTCzgREZCZa+3dq/XnQ==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/webchannel-wrapper": "1.0.5-eap-firestore-pipelines.2.e4cdd2e06", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.14.0.tgz", + "integrity": "sha512-bZc6YOjRkMBVA16527tgzi6iN9n//xRB3Mmx/R+Gr6UAP/+xrIKOejQIcn1hh+tCzNT8jO0jI+kWox5J4tB/qQ==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "@firebase/webchannel-wrapper": "1.0.5", "@grpc/grpc-js": "~1.9.0", "@grpc/proto-loader": "^0.7.8", "tslib": "^2.1.0" @@ -1418,128 +1400,119 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/firestore-compat": { - "version": "0.4.2-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.4.2-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-dxOfKloa/ALp7hULU/ELJehduxhDXFnDvMUvKgZPkp0zWdNIwYLt4JSRPX03mdV4BVud++jxHclm6jEKItgAdQ==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/firestore": "4.9.2-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/firestore-types": "3.0.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.4.8.tgz", + "integrity": "sha512-WK9NJRpnosGD2nuyjdr7K+Ht7AxRYJlTF62myI4rRA7ibJOosbecvjacR5oirJ7s1BgNS6qzcBw7n4fD3a5w1w==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/firestore": "4.14.0", + "@firebase/firestore-types": "3.0.3", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/firestore-types": { - "version": "3.0.3-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-Vo6T59at2QVuyflgtUWhubGbrN0xI6gTkF/hth8pT1TbfSY2ORl6J8SpwczmXYJbHoFUB6ZcbB5rT9j23iD+AQ==", - "license": "Apache-2.0", + "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.9.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" } }, "node_modules/@firebase/functions": { - "version": "0.13.1-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.13.1-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-bsSSwAnIAeWCAiyN5QA5oR6SK9FpiX0amMT7kEbbfM5pkvV0douBJJHBBLfU6dKMdFPgxGtFtlmecLLgB9TDiw==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/app-check-interop-types": "0.3.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/auth-interop-types": "0.2.4-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/messaging-interop-types": "0.2.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.13.3.tgz", + "integrity": "sha512-csO7ckK3SSs+NUZW1nms9EK7ckHe/1QOjiP8uAkCYa7ND18s44vjE9g3KxEeIUpyEPqZaX1EhJuFyZjHigAcYw==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.2", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/functions-compat": { - "version": "0.4.1-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.4.1-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-GEcE+iuNBAx00H+xR7s1thUvCiszjx6JKWOBMnEYGDWyTJPQBLSneBy6okfhvH0woH1QZBNIUxRAimH4kT72wg==", - "license": "Apache-2.0", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.4.3.tgz", + "integrity": "sha512-BxkEwWgx1of0tKaao/r2VR6WBLk/RAiyztatiONPrPE8gkitFkOnOCxf8i9cUyA5hX5RGt5H30uNn25Q6QNEmQ==", "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/functions": "0.13.1-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/functions-types": "0.6.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "@firebase/component": "0.7.2", + "@firebase/functions": "0.13.3", + "@firebase/functions-types": "0.6.3", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/functions-types": { - "version": "0.6.3-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-9wj5JmjDPzohUn2s6faPLB/QwFDkobofkC2jZruGl2TB6ModN/MDyUFx5PbtuZkNkjzAeZeLcSl11FTv5wLdWA==", - "license": "Apache-2.0" + "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.19-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.19-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-jt1pfPWYPE7sRodukfhJ0fv7dPCkroU6YLLrwhUgWiQB3OE1Suxd1A5mLM+ZlfASNqFTMn/JqtqS+ANwKUt6hg==", - "license": "Apache-2.0", + "version": "0.6.21", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.21.tgz", + "integrity": "sha512-xGFGTeICJZ5vhrmmDukeczIcFULFXybojML2+QSDFoKj5A7zbGN7KzFGSKNhDkIxpjzsYG9IleJyUebuAcmqWA==", "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", "idb": "7.1.1", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/installations-compat": { - "version": "0.2.19-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.19-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-YfJTlsliplb4l/gMvvtyQaNe1q58ziunZ+FJ3JpMgvjg0Duhi0VG3Mo3cZdroG8B2eTfqgJzmLkr+1ADpMno2g==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/installations": "0.6.19-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/installations-types": "0.5.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.2.21", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.21.tgz", + "integrity": "sha512-zahIUkaVKbR8zmTeBHkdfaVl6JGWlhVoSjF7CVH33nFqD3SlPEpEEegn2GNT5iAfsVdtlCyJJ9GW4YKjq+RJKQ==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/installations-types": "0.5.3", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/installations-types": { - "version": "0.5.3-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-tOY5XigEC4wvKEL8K0/0N1vTxqZhcNjj9D/cvmnw+yWWQXuQ8xUvBSyhLL+vBzN08lTfXHx1nB2Xj64qJv85Eg==", - "license": "Apache-2.0", + "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.9.3-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-types": "0.x" } }, "node_modules/@firebase/logger": { - "version": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.5.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-QjT8AAStSk578HDe7ttAGzc23W1ppOTXqGr+kJX+KMSoLGkej12uBcDTFmYh2lURwVJKNG8O/4kb4n5llrGodA==", - "license": "Apache-2.0", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.5.0.tgz", + "integrity": "sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g==", "dependencies": { "tslib": "^2.1.0" }, @@ -1548,174 +1521,161 @@ } }, "node_modules/@firebase/messaging": { - "version": "0.12.23-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.23-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-WZLsyqELBmdRusowKgQJkeaCjD8DdImqxPnoxUebZqqUEYr2+fJoSPuJVCTvHmUmlSjcXT6fQMSmbaLsRtPgAg==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/installations": "0.6.19-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/messaging-interop-types": "0.2.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.12.25", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.25.tgz", + "integrity": "sha512-7RhDwoDHlOK1/ou0/LeubxmjcngsTjDdrY/ssg2vwAVpUuVAhQzQvuCAOYxcX5wNC1zCgQ54AP1vdngBwbCmOQ==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.15.0", "idb": "7.1.1", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/messaging-compat": { - "version": "0.2.23-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.23-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-S8atiwyrNWibyFCjiOV2LUjKsO5nIwpgwJZeya+JzkReT9wNPME1T/qYM2NxwBrXBXvSeYLOJd8siu6BOV2AoA==", - "license": "Apache-2.0", + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.25.tgz", + "integrity": "sha512-eoOQqGLtRlseTdiemTN44LlHZpltK5gnhq8XVUuLgtIOG+odtDzrz2UoTpcJWSzaJQVxNLb/x9f39tHdDM4N4w==", "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/messaging": "0.12.23-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "@firebase/component": "0.7.2", + "@firebase/messaging": "0.12.25", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/messaging-interop-types": { - "version": "0.2.3-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-/RAyA4IE6I9wGFupl3aqHKl3BOE5r5HbIRGisqCup3AQt0UkMoBGojw+MIhiQyHMrk9QUSS5Juc4SiWqi81vBA==", - "license": "Apache-2.0" + "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.7.9-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.9-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-gqJOzPKcvtMEBcHAtpzE26Su8NvxDyh00UETMuUNBZ0BzUViwD/FFG6C0Oazrm6TMnUnx47WUkuM332RzBHaHA==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/installations": "0.6.19-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.11.tgz", + "integrity": "sha512-V3uAhrz7IYJuji+OgT3qYTGKxpek/TViXti9OSsUJ4AexZ3jQjYH5Yrn7JvBxk8MGiSLsC872hh+BxQiPZsm7g==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0", "web-vitals": "^4.2.4" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/performance-compat": { - "version": "0.2.22-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.22-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-vfD1OouiMVmCX9IRstiaGxpcR8D8b0f5/I0fs1zyQByJv0GtUa4NC+PNNcpxdvZLR9o7NsCsfMI/XMQ3ar1Siw==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/performance": "0.7.9-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/performance-types": "0.2.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.2.24", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.24.tgz", + "integrity": "sha512-YRlejH8wLt7ThWao+HXoKUHUrZKGYq+otxkPS+8nuE5PeN1cBXX7NAJl9ueuUkBwMIrnKdnDqL/voHXxDAAt3g==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/performance": "0.7.11", + "@firebase/performance-types": "0.2.3", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/performance-types": { - "version": "0.2.3-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-QlxN5Wp2HLoZj0iius0B14C0ksXy/+XtPLkzK3j67dIanBEykdyuNbHPgr/tWwedjMMAq9MRMkACXiKD0J1qkg==", - "license": "Apache-2.0" + "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.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.7.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-pMQwYvzKpnO76vt0DM6gSs+6QJ/ONxXtH/Q2TU9AvabgSDl8LAmAnc1T0KWwDSx0UzJlKNfHJvXxEy6etjGx/g==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/installations": "0.6.19-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.8.2.tgz", + "integrity": "sha512-5EXqOThV4upjK9D38d/qOSVwOqRhemlaOFk9vCkMNNALeIlwr+4pLjtLNo4qoY8etQmU/1q4aIATE9N8PFqg0g==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/remote-config-compat": { - "version": "0.2.20-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.20-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-7iQ9cN66Z79cUW2xh6WGvQjyoVRU3gQ+xj5qyWkl4rJgQanp8MdJs/5Z1U5Kf1QZAdLeoLi6QLQtl4Iwjewl6A==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/logger": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/remote-config": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/remote-config-types": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.2.23", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.23.tgz", + "integrity": "sha512-4+KqRRHEUUmKT6tFmnpWATOsaFfmSuBs1jXH8JzVtMLEYqq/WS9IDM92OdefFDSrAA2xGd0WN004z8mKeIIscw==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/remote-config": "0.8.2", + "@firebase/remote-config-types": "0.5.0", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/remote-config-types": { - "version": "0.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.5.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-2He6m8U/9y+oK6OJUuI8v2E25Ch8Uz2PcPpRNtl7dHhuN8jRVrNEv7w5bIE8iPgnm+iPxCKcmtpUdYxu1HzMPw==", - "license": "Apache-2.0" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.5.0.tgz", + "integrity": "sha512-vI3bqLoF14L/GchtgayMiFpZJF+Ao3uR8WCde0XpYNkSokDpAKca2DxvcfeZv7lZUqkUwQPL2wD83d3vQ4vvrg==" }, "node_modules/@firebase/storage": { - "version": "0.14.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.14.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-4pu13bFv5p4Ax3HmxuQ7Vcfj6r5dVWSQ2yWQX93w11gEfLVcfRugunt6hu6jHKa1PspVaeKYngVadooEoIGfEA==", - "license": "Apache-2.0", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.14.2.tgz", + "integrity": "sha512-o/culaTeJ8GRpKXRJov21rux/n9dRaSOWLebyatFP2sqEdCxQPjVA1H9Z2fzYwQxMIU0JVmC7SPPmU11v7L6vQ==", "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app": "0.x" } }, "node_modules/@firebase/storage-compat": { - "version": "0.4.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.4.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-Z0D9LtTQMj7Hbhoa8bIPNuTmifE/s5pCejxjreE+3jwtdZmXCFoaHxzrs3v+mLGlsKtLrTwiA9ZFtwyU0o+nuA==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/component": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/storage": "0.14.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/storage-types": "0.8.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.4.2.tgz", + "integrity": "sha512-R+aB38wxCH5zjIO/xu9KznI7fgiPuZAG98uVm1NcidHyyupGgIDLKigGmRGBZMnxibe/m2oxNKoZpfEbUX2aQQ==", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/storage": "0.14.2", + "@firebase/storage-types": "0.8.3", + "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/storage-types": { - "version": "0.8.3-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-7/uuEmAJU+zrKyLi7wieEOCqq+zFEcpSz870eRpPMouDSIvU6V72vBKXIA1eunhWR+8QZhZ/IhkyrH5wGwsELg==", - "license": "Apache-2.0", + "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.9.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06" + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" } }, "node_modules/@firebase/util": { - "version": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.13.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-vTnPozBjw0YdeTtbKZunxe3lgYCutfZ5txqHyGu+0qMkSsKKB/R/gdJ6GXOX3n9ctcRV79fp2y07U7W2x/Uuug==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.15.0.tgz", + "integrity": "sha512-AmWf3cHAOMbrCPG4xdPKQaj5iHnyYfyLKZxwz+Xf55bqKbpAmcYifB4jQinT2W9XhDRHISOoPyBOariJpCG6FA==", "hasInstallScript": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" }, @@ -1724,16 +1684,14 @@ } }, "node_modules/@firebase/webchannel-wrapper": { - "version": "1.0.5-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.5-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-zerZ1HNaainDG42FzcXqTRSIbHR9d3w9B6CEmmHpiQQypABUp2ymCAE6mFtUKb2kr2QiAeVngHzea+LAZzz/2w==", - "license": "Apache-2.0" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.5.tgz", + "integrity": "sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw==" }, "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" @@ -1746,7 +1704,6 @@ "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", @@ -1923,32 +1880,27 @@ "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" + "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==", - "license": "BSD-3-Clause" + "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==", - "license": "BSD-3-Clause" + "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==", - "license": "BSD-3-Clause" + "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==", - "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -1957,32 +1909,27 @@ "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" + "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==", - "license": "BSD-3-Clause" + "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==", - "license": "BSD-3-Clause" + "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==", - "license": "BSD-3-Clause" + "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==", - "license": "BSD-3-Clause" + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@radix-ui/primitive": { "version": "1.1.3", @@ -3708,7 +3655,6 @@ "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" } @@ -4076,7 +4022,6 @@ "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", @@ -4396,8 +4341,7 @@ "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" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/encodeurl": { "version": "2.0.0", @@ -4887,7 +4831,6 @@ "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" }, @@ -4972,39 +4915,38 @@ } }, "node_modules/firebase": { - "version": "12.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "resolved": "https://registry.npmjs.org/firebase/-/firebase-12.5.0-eap-firestore-pipelines.2.e4cdd2e06.tgz", - "integrity": "sha512-8RLbcZHHWjIODgjJTRNf1uOlI9DQjBWeJM5V57mu/orLa1vovGQQCOAu3ukoleXIisuMc2bgQHuIDyUcT7Cw/g==", - "license": "Apache-2.0", - "dependencies": { - "@firebase/ai": "2.5.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/analytics": "0.10.19-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/analytics-compat": "0.2.25-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/app": "0.14.5-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/app-check": "0.11.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/app-check-compat": "0.4.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/app-compat": "0.5.5-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/app-types": "0.9.3-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/auth": "1.11.1-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/auth-compat": "0.6.1-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/data-connect": "0.3.11-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/database": "1.1.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/database-compat": "2.1.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/firestore": "4.9.2-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/firestore-compat": "0.4.2-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/functions": "0.13.1-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/functions-compat": "0.4.1-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/installations": "0.6.19-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/installations-compat": "0.2.19-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/messaging": "0.12.23-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/messaging-compat": "0.2.23-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/performance": "0.7.9-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/performance-compat": "0.2.22-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/remote-config": "0.7.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/remote-config-compat": "0.2.20-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/storage": "0.14.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/storage-compat": "0.4.0-eap-firestore-pipelines.2.e4cdd2e06", - "@firebase/util": "1.13.0-eap-firestore-pipelines.2.e4cdd2e06" + "version": "12.12.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-12.12.0.tgz", + "integrity": "sha512-5Ap+pN5iEJUvBlQEZEmLuUm7Gvu6I5xv1jZ5SiSNyw4jrwlHo+4tmZv3OPPoKfN9eo1kBwyyBvi+pWHIPXwfYw==", + "dependencies": { + "@firebase/ai": "2.11.0", + "@firebase/analytics": "0.10.21", + "@firebase/analytics-compat": "0.2.27", + "@firebase/app": "0.14.11", + "@firebase/app-check": "0.11.2", + "@firebase/app-check-compat": "0.4.2", + "@firebase/app-compat": "0.5.11", + "@firebase/app-types": "0.9.4", + "@firebase/auth": "1.13.0", + "@firebase/auth-compat": "0.6.5", + "@firebase/data-connect": "0.6.0", + "@firebase/database": "1.1.2", + "@firebase/database-compat": "2.1.3", + "@firebase/firestore": "4.14.0", + "@firebase/firestore-compat": "0.4.8", + "@firebase/functions": "0.13.3", + "@firebase/functions-compat": "0.4.3", + "@firebase/installations": "0.6.21", + "@firebase/installations-compat": "0.2.21", + "@firebase/messaging": "0.12.25", + "@firebase/messaging-compat": "0.2.25", + "@firebase/performance": "0.7.11", + "@firebase/performance-compat": "0.2.24", + "@firebase/remote-config": "0.8.2", + "@firebase/remote-config-compat": "0.2.23", + "@firebase/storage": "0.14.2", + "@firebase/storage-compat": "0.4.2", + "@firebase/util": "1.15.0" } }, "node_modules/flat-cache": { @@ -5084,7 +5026,6 @@ "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.*" } @@ -5304,8 +5245,7 @@ "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" + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==" }, "node_modules/iconv-lite": { "version": "0.4.24", @@ -5322,8 +5262,7 @@ "node_modules/idb": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", - "license": "ISC" + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" }, "node_modules/ignore": { "version": "5.3.2", @@ -5431,7 +5370,6 @@ "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" } @@ -5885,8 +5823,7 @@ "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" + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -5898,8 +5835,7 @@ "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" + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" }, "node_modules/longest-streak": { "version": "3.1.0", @@ -7036,11 +6972,10 @@ } }, "node_modules/protobufjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", - "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", + "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", "hasInstallScript": true, - "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -7273,7 +7208,6 @@ "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" } @@ -7618,7 +7552,6 @@ "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", @@ -7646,7 +7579,6 @@ "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" }, @@ -8302,14 +8234,12 @@ "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" + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==" }, "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", @@ -8323,7 +8253,6 @@ "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" } @@ -8358,7 +8287,6 @@ "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", @@ -8375,7 +8303,6 @@ "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" } @@ -8391,7 +8318,6 @@ "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", @@ -8409,7 +8335,6 @@ "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" } diff --git a/package.json b/package.json index 73fd7d9..a6047ec 100644 --- a/package.json +++ b/package.json @@ -10,24 +10,24 @@ "typecheck": "react-router typegen && tsc" }, "dependencies": { - "@react-router/node": "7.12.0", - "@react-router/serve": "7.12.0", "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", + "@react-router/node": "7.12.0", + "@react-router/serve": "7.12.0", "@tailwindcss/vite": "^4.1.18", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "firebase": "^12.5.0-eap-firestore-pipelines.2.e4cdd2e06", + "firebase": "^12.12.0", + "isbot": "^5", "lucide-react": "^0.562.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-markdown": "^10.1.0", "react-router": "^7.12.0", "tailwind-merge": "^3.4.0", - "tailwindcss": "^4.1.18", - "isbot": "^5" + "tailwindcss": "^4.1.18" }, "devDependencies": { "@eslint/js": "^9.30.1", @@ -47,4 +47,4 @@ "vite": "^7.1.11", "vite-tsconfig-paths": "^5.1.4" } -} \ No newline at end of file +} From b73174f06d9836dce3f34da3b36d42719de8e59f Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 20 Apr 2026 16:14:26 -0700 Subject: [PATCH 2/8] fix lint --- app/components/Recipe.tsx | 2 +- app/components/ui/button.tsx | 1 + app/components/ui/navigation-menu.tsx | 1 + app/firebase/data.ts | 2 +- app/firebase/firebaseAILogic.ts | 2 +- app/routes/chat.tsx | 4 ++-- app/routes/generate.tsx | 4 ++-- app/routes/home.tsx | 6 +++--- app/routes/image.tsx | 4 ++-- app/routes/recipe.$recipeId.tsx | 1 + app/routes/recipes.tsx | 5 +++-- eslint.config.js | 2 +- 12 files changed, 19 insertions(+), 15 deletions(-) diff --git a/app/components/Recipe.tsx b/app/components/Recipe.tsx index f63ad1b..8adcbc2 100644 --- a/app/components/Recipe.tsx +++ b/app/components/Recipe.tsx @@ -13,7 +13,7 @@ import type { Recipe } from "../firebase/data"; import { deleteRecipe, addReview, likeRecipe, unlikeRecipe } from "../firebase/data"; import { getUser } from "../firebase/auth"; -const InfoBox = ({ icon: Icon, label, value }: { icon: any, label: string, value: string | number }) => ( +const InfoBox = ({ icon: Icon, label, value }: { icon: React.ElementType, label: string, value: string | number }) => (
diff --git a/app/components/ui/button.tsx b/app/components/ui/button.tsx index 37a7d4b..3f5bac6 100644 --- a/app/components/ui/button.tsx +++ b/app/components/ui/button.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-refresh/only-export-components */ import * as React from "react" import { Slot } from "@radix-ui/react-slot" import { cva, type VariantProps } from "class-variance-authority" diff --git a/app/components/ui/navigation-menu.tsx b/app/components/ui/navigation-menu.tsx index 1199945..23d9e2c 100644 --- a/app/components/ui/navigation-menu.tsx +++ b/app/components/ui/navigation-menu.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-refresh/only-export-components */ import * as React from "react" import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu" import { cva } from "class-variance-authority" diff --git a/app/firebase/data.ts b/app/firebase/data.ts index fdad231..3a71ed3 100644 --- a/app/firebase/data.ts +++ b/app/firebase/data.ts @@ -1,4 +1,4 @@ -import { initializeFirestore, addDoc, collection, getDoc, doc, deleteDoc, updateDoc, persistentLocalCache, setDoc, getDocs, query, where, runTransaction, increment } from "firebase/firestore"; +import { initializeFirestore, addDoc, collection, doc, deleteDoc, setDoc } from "firebase/firestore"; import { execute, field, countAll, subcollection, average, variable, score, documentMatches } from "firebase/firestore/pipelines"; import { firebaseApp } from "./firebase"; diff --git a/app/firebase/firebaseAILogic.ts b/app/firebase/firebaseAILogic.ts index 74da79b..4c95d7e 100644 --- a/app/firebase/firebaseAILogic.ts +++ b/app/firebase/firebaseAILogic.ts @@ -104,7 +104,7 @@ export async function generateStructuredJsonRecipe( async function fileToGenerativePart(file: File) { const base64EncodedDataPromise = new Promise((resolve) => { const reader = new FileReader(); - reader.onloadend = () => resolve(reader.result ? (reader.result as String).split(',')[1] : ''); + reader.onloadend = () => resolve(reader.result ? (reader.result as string).split(',')[1] : ''); reader.readAsDataURL(file); }); return { diff --git a/app/routes/chat.tsx b/app/routes/chat.tsx index 57dcc67..b7a9d26 100644 --- a/app/routes/chat.tsx +++ b/app/routes/chat.tsx @@ -1,4 +1,4 @@ -import type { Route } from "./+types/chat"; +/* eslint-disable react-refresh/only-export-components */ import React, { useCallback, useMemo, useState } from "react"; import { ai } from "../firebase/firebase"; import { getGenerativeModel } from "firebase/ai"; @@ -9,7 +9,7 @@ import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/componen import { Input } from "@/components/ui/input"; import { Spinner } from "@/components/ui/spinner"; -export function meta({ }: Route.MetaArgs) { +export function meta() { return [ { title: "Chat - Friendly Meals" }, { name: "description", content: "Chat about cooking with AI" }, diff --git a/app/routes/generate.tsx b/app/routes/generate.tsx index 9cecf7f..ce113cf 100644 --- a/app/routes/generate.tsx +++ b/app/routes/generate.tsx @@ -1,4 +1,4 @@ -import type { Route } from "./+types/generate"; +/* eslint-disable react-refresh/only-export-components */ import { useState } from "react"; import { IngredientInput } from "@/components/IngredientInput"; @@ -11,7 +11,7 @@ import { ChevronDown, ChevronUp, Sparkles } from "lucide-react"; import { getUser } from "@/firebase/auth"; import { useNavigate } from "react-router"; -export function meta({ }: Route.MetaArgs) { +export function meta() { return [ { title: "Generate Recipe - Friendly Meals" }, { name: "description", content: "Generate a new recipe with AI" }, diff --git a/app/routes/home.tsx b/app/routes/home.tsx index 4c8d908..befe152 100644 --- a/app/routes/home.tsx +++ b/app/routes/home.tsx @@ -1,8 +1,8 @@ -import type { Route } from "./+types/home"; +/* eslint-disable react-refresh/only-export-components */ import { Button } from "@/components/ui/button" -import { Sparkles, Camera, MessageCircle, BookOpen, Flame, Database } from "lucide-react" +import { Sparkles, Camera, MessageCircle, BookOpen, Flame } from "lucide-react" -export function meta({ }: Route.MetaArgs) { +export function meta() { return [ { title: "Friendly Meals - AI-Powered Recipe Generator" }, { name: "description", content: "Generate recipes with Firebase AI Logic and Firestore Pipelines" }, diff --git a/app/routes/image.tsx b/app/routes/image.tsx index 9671961..99527ca 100644 --- a/app/routes/image.tsx +++ b/app/routes/image.tsx @@ -1,7 +1,7 @@ -import type { Route } from "./+types/image"; +/* eslint-disable react-refresh/only-export-components */ import ImageLayout from "../components/ImageLayout"; -export function meta({ }: Route.MetaArgs) { +export function meta() { return [ { title: "Scan Recipe - Friendly Meals" }, { name: "description", content: "Scan an image to extract a recipe" }, diff --git a/app/routes/recipe.$recipeId.tsx b/app/routes/recipe.$recipeId.tsx index a349885..c880f47 100644 --- a/app/routes/recipe.$recipeId.tsx +++ b/app/routes/recipe.$recipeId.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-refresh/only-export-components */ import type { Route } from "./+types/recipe.$recipeId"; import Recipe from "../components/Recipe"; import { isRecipeLikedByUser, getRecipe } from "../firebase/data"; diff --git a/app/routes/recipes.tsx b/app/routes/recipes.tsx index 8a89e69..2cc2073 100644 --- a/app/routes/recipes.tsx +++ b/app/routes/recipes.tsx @@ -1,8 +1,9 @@ +/* eslint-disable react-refresh/only-export-components */ import type { Route } from "./+types/recipes"; import { queryRecipes, getTop5Tags } from "@/firebase/data"; import { getUser } from "@/firebase/auth"; -import React, { useState, useEffect, useRef } from "react"; +import React, { useState, useRef } from "react"; import { Empty, EmptyHeader, @@ -26,7 +27,7 @@ import { } from "@/components/ui/item" import { Star, ChevronDown, ChevronUp, Search, X } from "lucide-react"; -export function meta({ }: Route.MetaArgs) { +export function meta() { return [ { title: "All Recipes - Friendly Meals" }, { name: "description", content: "Browse all recipes" }, diff --git a/eslint.config.js b/eslint.config.js index d94e7de..2d24e34 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -6,7 +6,7 @@ import tseslint from 'typescript-eslint' import { globalIgnores } from 'eslint/config' export default tseslint.config([ - globalIgnores(['dist']), + globalIgnores(['dist', '.react-router']), { files: ['**/*.{ts,tsx}'], extends: [ From f514470ac5984eff45db904bd62863ec7a671317 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Tue, 21 Apr 2026 14:38:43 -0700 Subject: [PATCH 3/8] fix likes --- app/firebase/data.ts | 7 ++++--- app/routes/recipes.tsx | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/firebase/data.ts b/app/firebase/data.ts index 3a71ed3..44768a2 100644 --- a/app/firebase/data.ts +++ b/app/firebase/data.ts @@ -1,5 +1,5 @@ import { initializeFirestore, addDoc, collection, doc, deleteDoc, setDoc } from "firebase/firestore"; -import { execute, field, countAll, subcollection, average, variable, score, documentMatches } from "firebase/firestore/pipelines"; +import { execute, field, countAll, subcollection, average, variable, score, documentMatches, documentId } from "firebase/firestore/pipelines"; import { firebaseApp } from "./firebase"; export interface Review { @@ -72,7 +72,7 @@ export async function publishRecipe(userId: string, recipe: Omit): export async function getRecipe(recipeId: string): Promise { const pipeline = db.pipeline() .documents([`recipes/${recipeId}`]) - .define(field("__name__").as("parentRecipeId")) + .define(documentId(field("__name__")).as("parentRecipeId")) .addFields( subcollection("reviews") .aggregate(average("rating").as("avg")) @@ -156,7 +156,7 @@ export async function queryRecipes(filters: { }); } - pipeline = pipeline.define(field("__name__").as("parentRecipeId")) + pipeline = pipeline.define(documentId(field("__name__")).as("parentRecipeId")) .addFields( subcollection("reviews") .aggregate(average("rating").as("avg")) @@ -203,5 +203,6 @@ export async function queryRecipes(filters: { } const { results } = await execute(pipeline); + console.log(results); return results.map(result => ({ ...result.data(), id: result.id }) as Recipe); } \ No newline at end of file diff --git a/app/routes/recipes.tsx b/app/routes/recipes.tsx index 2cc2073..783e2b2 100644 --- a/app/routes/recipes.tsx +++ b/app/routes/recipes.tsx @@ -19,6 +19,7 @@ import { Link, useSearchParams, useNavigate, Form } from "react-router"; import type { Recipe } from "../firebase/data"; import { Item, + ItemMedia, ItemContent, ItemDescription, ItemGroup, @@ -321,6 +322,15 @@ export default function RecipesPage({ loaderData }: Route.loaderData) { {recipes.map((recipe: Recipe) => ( + {recipe.imageUri && ( + + {recipe.title} + + )} {recipe.title}
From 0596f78576b95722ea29268c0838f0c18ab0226f Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Tue, 21 Apr 2026 14:44:35 -0700 Subject: [PATCH 4/8] remove console.log --- app/firebase/data.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/firebase/data.ts b/app/firebase/data.ts index 44768a2..01a618f 100644 --- a/app/firebase/data.ts +++ b/app/firebase/data.ts @@ -203,6 +203,5 @@ export async function queryRecipes(filters: { } const { results } = await execute(pipeline); - console.log(results); return results.map(result => ({ ...result.data(), id: result.id }) as Recipe); } \ No newline at end of file From 53076ad9b86b83c55dab349bf302177973978b13 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Tue, 21 Apr 2026 15:09:32 -0700 Subject: [PATCH 5/8] fix likesOnly filter --- app/firebase/data.ts | 14 ++++++++++++-- app/routes/recipes.tsx | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/firebase/data.ts b/app/firebase/data.ts index 01a618f..fa149df 100644 --- a/app/firebase/data.ts +++ b/app/firebase/data.ts @@ -144,6 +144,7 @@ export async function queryRecipes(filters: { authorId?: string; likedOnly?: boolean; sort?: string; + userId?: string; }): Promise { let pipeline = db.pipeline().collection("recipes"); @@ -182,8 +183,17 @@ export async function queryRecipes(filters: { pipeline = pipeline.where(field("tags").arrayContainsAny(filters.tags)); } - if (filters.likedOnly) { - pipeline = pipeline.where(field("likes").greaterThan(0)); + if (filters.likedOnly && filters.userId) { + pipeline = pipeline.addFields( + db.pipeline() + .collection("likes") + .where(field("userId").equal(filters.userId)) + .where(field("recipeId").equal(variable("parentRecipeId"))) + .limit(1) + .select("userId") + .toScalarExpression() + .as("isLikedByMe") + ).where(field("isLikedByMe").equal(null).not()); } if (filters.sort) { diff --git a/app/routes/recipes.tsx b/app/routes/recipes.tsx index 783e2b2..8eadbdb 100644 --- a/app/routes/recipes.tsx +++ b/app/routes/recipes.tsx @@ -45,7 +45,8 @@ export async function clientLoader({ request }: Route.ClientLoaderArgs) { tags: url.searchParams.get('tags') ? url.searchParams.get('tags')!.split(',') : undefined, authorId: url.searchParams.get('myRecipes') === 'on' ? user.uid : undefined, likedOnly: url.searchParams.get('likedOnly') === 'on', - sort: url.searchParams.get('sort') || undefined + sort: url.searchParams.get('sort') || undefined, + userId: user.uid }; const [recipes, topTags] = await Promise.all([ @@ -91,6 +92,7 @@ const FilterPanel: React.FC<{ const name = searchParams.get('q') || ''; const sortBy = (searchParams.get('sort') as 'rating' | 'title' | 'likes') || ''; const myRecipes = searchParams.get('myRecipes') === 'on'; + const likedOnly = searchParams.get('likedOnly') === 'on'; const searchParamsSelectedTags: string[] = searchParams.get('tags')?.split(',').filter(Boolean) || []; const searchParamsMinRating = Number(searchParams.get('minRating')) || 0; @@ -179,6 +181,18 @@ const FilterPanel: React.FC<{ + + + + {/* Rating */} Minimum Rating From 29d6be97d2f5cf824aa8989a6b2b39533e24cd46 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Tue, 21 Apr 2026 15:26:41 -0700 Subject: [PATCH 6/8] add default sort --- app/routes/recipes.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/routes/recipes.tsx b/app/routes/recipes.tsx index 8eadbdb..f7a6344 100644 --- a/app/routes/recipes.tsx +++ b/app/routes/recipes.tsx @@ -90,7 +90,7 @@ const FilterPanel: React.FC<{ const [searchParams, setSearchParams] = useSearchParams(); const name = searchParams.get('q') || ''; - const sortBy = (searchParams.get('sort') as 'rating' | 'title' | 'likes') || ''; + const sortBy = (searchParams.get('sort') as 'rating' | 'title' | 'likes' | 'default') || ''; const myRecipes = searchParams.get('myRecipes') === 'on'; const likedOnly = searchParams.get('likedOnly') === 'on'; const searchParamsSelectedTags: string[] = searchParams.get('tags')?.split(',').filter(Boolean) || []; @@ -241,7 +241,17 @@ const FilterPanel: React.FC<{ {/* Sort By */} Sort By -
+
+