From cb046c40ca993ec9d57d826106c54f8af6d5e920 Mon Sep 17 00:00:00 2001 From: Chad Nuttall Date: Sun, 27 Sep 2026 19:09:36 -0400 Subject: [PATCH 1/2] chore(deps): migrate firebase-admin to v14 with module split (#223) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - firebase-admin ^13.10.0 -> ^14.5.0 (app and functions). - Split src/lib/firebase-admin.ts into firebase-admin-app/-auth/-db/ -storage so each service graph loads only where imported — Firestore- and Storage-only routes no longer pull firebase-admin/auth, whose jwks-rsa -> jose chain caused the #144 Vercel ERR_REQUIRE_ESM outage. - Scoped override jwks-rsa -> jose@5.10.0: firebase-admin 14 resolves jwks-rsa@4 -> jose@6 (ESM-only), and Vercel's serverless loader has no require(esm) bridge — verified failing in a live Preview on deepdivebrewing-web PR #142. tests/firebase-admin-runtime.test.ts (CJS-only subprocess) now also covers firebase-admin/storage. - next.config.ts: serverExternalPackages keeps firebase-admin out of the server bundle. - functions/index.js: the legacy require("firebase-admin") namespace call migrated to firebase-admin/app (v14 removed admin.* services; only initializeApp was used). - scripts/check-admin-import.mjs wired into npm test: credential-free plain-Node import of every Admin entrypoint the app uses. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- functions/index.js | 4 +- functions/package-lock.json | 42 +- functions/package.json | 2 +- next.config.ts | 5 + package-lock.json | 755 +++++++++++------- package.json | 12 +- scripts/audit-firestore.ts | 2 +- scripts/check-admin-import.mjs | 45 ++ scripts/db-backup.ts | 2 +- scripts/db-restore.ts | 2 +- scripts/migrate-firestore.ts | 2 +- scripts/reconcile-migration.ts | 2 +- src/app/admin/homepage/actions.ts | 2 +- src/app/admin/registrations/actions.ts | 2 +- src/app/api/auth/session/route.ts | 2 +- src/app/api/cron/sweep-receipts/route.ts | 2 +- src/lib/auth.ts | 2 +- ...irebase-admin.ts => firebase-admin-app.ts} | 22 +- src/lib/firebase-admin-auth.ts | 7 + src/lib/firebase-admin-db.ts | 7 + src/lib/firebase-admin-storage.ts | 17 + tests/admin-actions.test.ts | 2 +- tests/auth.test.ts | 2 +- tests/firebase-admin-env.test.ts | 2 +- tests/firebase-admin-runtime.test.ts | 1 + tests/session-route.test.ts | 2 +- 26 files changed, 612 insertions(+), 335 deletions(-) create mode 100644 scripts/check-admin-import.mjs rename src/lib/{firebase-admin.ts => firebase-admin-app.ts} (68%) create mode 100644 src/lib/firebase-admin-auth.ts create mode 100644 src/lib/firebase-admin-db.ts create mode 100644 src/lib/firebase-admin-storage.ts diff --git a/functions/index.js b/functions/index.js index 114039a..b6c397f 100644 --- a/functions/index.js +++ b/functions/index.js @@ -1,10 +1,10 @@ const functions = require("firebase-functions/v2"); const logger = require("firebase-functions/logger"); -const admin = require("firebase-admin"); +const {initializeApp} = require("firebase-admin/app"); const crypto = require("crypto"); const {triggerVercelRebuild} = require("./lib/rebuild"); -admin.initializeApp(); +initializeApp(); // Get environment variables const { diff --git a/functions/package-lock.json b/functions/package-lock.json index 3ffea3f..4e12da6 100644 --- a/functions/package-lock.json +++ b/functions/package-lock.json @@ -7,7 +7,7 @@ "name": "functions", "dependencies": { "axios": "^1.6.0", - "firebase-admin": "^14.4.0", + "firebase-admin": "^14.5.0", "firebase-functions": "^7.4.0" }, "devDependencies": { @@ -2122,16 +2122,16 @@ } }, "node_modules/firebase-admin": { - "version": "14.4.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-14.4.0.tgz", - "integrity": "sha512-yEx+GCsHvjH2svh4j1ATW57o8tlfjRQ0klTxvn7XCKUPXWiUQaRTHSzPSqhXtsLYSe4IwTqR7qqrh2sA45A0HA==", + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-14.5.0.tgz", + "integrity": "sha512-DElmgmaH9aPXu2dWXGQiDoan33UfTnbfAAKaue4fwEZxmpdaNrTk5DmuFn+vVDki2KZ6TiaC0IHRWcEzcDxB3Q==", "license": "Apache-2.0", "dependencies": { "@fastify/busboy": "^3.0.0", "@firebase/database-compat": "^2.1.4", "@firebase/database-types": "^1.0.20", "fast-deep-equal": "^3.1.1", - "google-auth-library": "^10.6.2", + "google-auth-library": "^11.1.0", "jsonwebtoken": "^9.0.0", "jwks-rsa": "^4.0.1" }, @@ -2158,43 +2158,43 @@ } }, "node_modules/firebase-admin/node_modules/gcp-metadata": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", - "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-9.0.4.tgz", + "integrity": "sha512-p6WvbXOhfwnVtv/MyPq5kBiVhfV/qglMIxwwTVNEI1Ha1HmOgz5uHYHtYO6SfGckFaXe8blA11IJJ3wqXmvmBA==", "license": "Apache-2.0", "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", + "gaxios": "^7.1.3", + "google-logging-utils": "^2.0.0", "json-bigint": "^1.0.0" }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/firebase-admin/node_modules/google-auth-library": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.9.1.tgz", - "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-11.1.0.tgz", + "integrity": "sha512-YIBq5KNoHQrZ9PM4PeodDBqqBGlSTIxh1zibN8u3zNIO9UJg8gvKuCpdKV7fWXhsZ2zRkU6FhGrgKNgLJ2IRgw==", "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", - "gcp-metadata": "8.1.2", - "google-logging-utils": "1.1.3", + "gcp-metadata": "^9.0.0", + "google-logging-utils": "^2.0.0", "jws": "^4.0.0" }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/firebase-admin/node_modules/google-logging-utils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", - "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-2.0.1.tgz", + "integrity": "sha512-HMhaQghlOTvbcb3c4T5jmmOMtG3JUF1iOQMezaJXL86CDS+Tm2vHd0IeLFRAx3+ewd+bo9E1HFHoy17X5aJa9A==", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=22" } }, "node_modules/firebase-admin/node_modules/node-fetch": { diff --git a/functions/package.json b/functions/package.json index 5d38309..5bb0258 100644 --- a/functions/package.json +++ b/functions/package.json @@ -16,7 +16,7 @@ "main": "index.js", "dependencies": { "axios": "^1.6.0", - "firebase-admin": "^14.4.0", + "firebase-admin": "^14.5.0", "firebase-functions": "^7.4.0" }, "devDependencies": { diff --git a/next.config.ts b/next.config.ts index 2d78062..2e542da 100644 --- a/next.config.ts +++ b/next.config.ts @@ -10,6 +10,11 @@ const nextConfig: NextConfig = { }, ], }, + // Keep firebase-admin outside the server bundle: its auth graph pulls + // jwks-rsa -> jose, and bundling the Node-specific chain into a + // serverless chunk caused the #144 Vercel runtime outage + // (ERR_REQUIRE_ESM). Load the real node_modules at runtime instead. + serverExternalPackages: ["firebase-admin"], // Enable video optimization experimental: { optimizePackageImports: ['lucide-react'], diff --git a/package-lock.json b/package-lock.json index e397def..7117847 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "drizzle-orm": "^0.45.2", "fast-xml-parser": "^5.3.4", "firebase": "^12.19.0", - "firebase-admin": "^13.10.0", + "firebase-admin": "^14.5.0", "framer-motion": "^13.4.0", "klaro": "^0.7.21", "lucide-react": "^1.47.0", @@ -2587,34 +2587,264 @@ } }, "node_modules/@google-cloud/firestore": { - "version": "7.11.6", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.11.6.tgz", - "integrity": "sha512-EW/O8ktzwLfyWBOsNuhRoMi8lrC3clHM5LVFhGvO1HCsLozCOOXRAlHrYBoE6HL42Sc8yYMuCb2XqcnJ4OOEpw==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-9.2.0.tgz", + "integrity": "sha512-4BI2686ygMkef0Pe4QnX9hnWeGCUjaAP5m+Ow5/yNWwGxGadO741Ct28MRXW9czg0pnvz919INKbQdCgUMcfeA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@opentelemetry/api": "^1.3.0", - "fast-deep-equal": "^3.1.1", + "@google-cloud/firestore-api": "^0.2.0", + "@opentelemetry/api": "^1.9.0", + "fast-deep-equal": "^3.1.3", "functional-red-black-tree": "^1.0.1", - "google-gax": "^4.3.3", - "protobufjs": "^7.2.6" + "google-gax": "^6.0.1", + "protobufjs": "^7.5.3" }, "engines": { - "node": ">=14.0.0" + "node": ">=22" + } + }, + "node_modules/@google-cloud/firestore-api": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore-api/-/firestore-api-0.2.0.tgz", + "integrity": "sha512-wfHJPZmLqzpy6FN6U+7HkkP/AKhGsbHSpEy/qL2TyI3/pKRAvpamQxZ2qvps5hMRgAjfuHCim+oeJj9RveCaqg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "google-gax": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/@grpc/grpc-js": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.5.tgz", + "integrity": "sha512-7VZM+SVdEcUUqSQeNI3zM8Qs/BhQKZndPo2h5VkYkAM8Iz0wJIa8mKV5ekQGqG8UUsnkQ0NMxIxwkIHYvj0qOw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/@grpc/proto-loader": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.1.tgz", + "integrity": "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/gaxios": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.3.1.tgz", + "integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/gcp-metadata": { + "version": "8.1.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.4.tgz", + "integrity": "sha512-iJ9KMsiu+xKtNRX0PmGLSaIU3bUBAyzWTyqKemKPzNPsmmsBCQYmlNg+brEbES7IHSXtdVwzBPzx1vz3FAaipw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "gaxios": "7.1.3", + "google-logging-utils": "1.1.3", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/gcp-metadata/node_modules/gaxios": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz", + "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2", + "rimraf": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/google-auth-library": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz", + "integrity": "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.0.0", + "gcp-metadata": "^8.0.0", + "google-logging-utils": "^1.0.0", + "gtoken": "^8.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/google-gax": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-5.0.8.tgz", + "integrity": "sha512-M4vpZcXQIC1gqIVGQ7eaU3jXQA6zecStyTXu514TYfThlgSurYJOxHZo9fzU6hAgwPWvuEynAVHWyaIk80VeEA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@grpc/grpc-js": "^1.12.6", + "@grpc/proto-loader": "^0.8.0", + "duplexify": "^4.1.3", + "google-auth-library": "10.5.0", + "google-logging-utils": "1.1.3", + "node-fetch": "^3.3.2", + "object-hash": "^3.0.0", + "proto3-json-serializer": "3.0.4", + "protobufjs": "^7.5.4", + "retry-request": "^8.0.2", + "rimraf": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/gtoken": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", + "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==", + "license": "MIT", + "optional": true, + "dependencies": { + "gaxios": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "optional": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/proto3-json-serializer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-3.0.4.tgz", + "integrity": "sha512-E1sbAYg3aEbXrq0n1ojJkRHQJGE1kaE/O6GLA94y8rnJBfgvOPTOd1b9hOceQK1FFZI9qMh1vBERCyO2ifubcw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "protobufjs": "^7.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/retry-request": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-8.0.4.tgz", + "integrity": "sha512-pI6/7eabUYkZxamkOq0g0uMxKLLGnjzhefY+vL8bVXag5rto4OU2YBTPytWLuHH7aEKD6fn7kJycQfid0Mwnkw==", + "license": "MIT", + "optional": true, + "dependencies": { + "extend": "^3.0.2", + "teeny-request": "^10.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/firestore-api/node_modules/teeny-request": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-10.1.4.tgz", + "integrity": "sha512-R1Cg4Vu0UULeDfHL/kjABLaTW++9yD/B6n2g48y5dJ04hsEaxcfmAqbNDzNsbqAYJyIpZafjklLG9YxRu9uzOg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2", + "stream-events": "^1.0.5" + }, + "engines": { + "node": ">=18" } }, "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==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-7.1.0.tgz", + "integrity": "sha512-PNCXdAQgNoQODZuqyhmkN2nUpB2q9UFzawZ1oyCDyEyhcheRoCKJJhSKhEIeKpM/NCLnC6Q4We4HEkGCwNDnCA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "arrify": "^2.0.0", "extend": "^3.0.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=22" } }, "node_modules/@google-cloud/precise-date": { @@ -2628,23 +2858,23 @@ } }, "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==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-6.1.0.tgz", + "integrity": "sha512-tKAx9q6vTtbgZcqCojKWK8k6Dy2XBsE7BkNrrBsblxNXrKImYnljqeGfYh9qnTrlTjC9F19pTyCkGcl3pFMW/w==", "license": "Apache-2.0", "optional": true, "engines": { - "node": ">=14.0.0" + "node": ">=22" } }, "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==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-6.1.0.tgz", + "integrity": "sha512-H+Rytzi5zYMyoAmU/zgYLgq7fJ9FY4QQEg4k6gfFx/RY1COJ2xxyIfe8bZ62lqEbWM1DJH7IYETqTFmqNtuUhQ==", "license": "Apache-2.0", "optional": true, "engines": { - "node": ">=14" + "node": ">=22" } }, "node_modules/@google-cloud/pubsub": { @@ -2949,15 +3179,15 @@ } }, "node_modules/@google-cloud/storage": { - "version": "7.22.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.22.0.tgz", - "integrity": "sha512-W98gTQOAntEeEQ7/pZxSQXxfUO5CiQcXJRsxBpUa6UU25n8YN/VtogPBi0H+MAmUrn/6bY/sBhFansoWEsr2/g==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-8.2.0.tgz", + "integrity": "sha512-7ckgSjeEprV92VrlLjpYFA3PFerflvFtF7Ea86oQXGNCprGZq5rtpAVK0zgWnCy+44mLjms42M7MiWa433gz2A==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@google-cloud/paginator": "^5.0.0", - "@google-cloud/projectify": "^4.0.0", - "@google-cloud/promisify": "<4.1.0", + "@google-cloud/paginator": "^7.0.1", + "@google-cloud/projectify": "^6.0.1", + "@google-cloud/promisify": "^6.0.1", "abort-controller": "^3.0.0", "async-retry": "^1.3.3", "duplexify": "^4.1.3", @@ -2967,11 +3197,11 @@ "html-entities": "^2.5.2", "mime": "^3.0.0", "p-limit": "^3.0.1", - "retry-request": "^7.0.0", - "teeny-request": "^9.0.0" + "retry-request": "^9.0.1", + "teeny-request": "^11.0.1" }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/@googleapis/sqladmin": { @@ -4010,7 +4240,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -4028,7 +4258,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -4041,7 +4271,7 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -4054,7 +4284,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -4072,7 +4302,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -4088,7 +4318,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -5337,7 +5567,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "license": "MIT", "optional": true, "engines": { @@ -7855,16 +8084,6 @@ } } }, - "node_modules/@tootallnate/once": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", - "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", - "license": "MIT", - "optional": true, - "engines": { - "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", @@ -7890,13 +8109,6 @@ "dev": true, "license": "MIT" }, - "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==", - "license": "MIT", - "optional": true - }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -7944,13 +8156,6 @@ "@types/node": "*" } }, - "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==", - "license": "MIT", - "optional": true - }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", @@ -7985,32 +8190,12 @@ "node_modules/@types/react-dom": { "version": "19.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", - "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", - "devOptional": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.3.0" - } - }, - "node_modules/@types/request": { - "version": "2.48.13", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.13.tgz", - "integrity": "sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.5" - } - }, - "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==", + "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", + "devOptional": true, "license": "MIT", - "optional": true + "peerDependencies": { + "@types/react": "^19.3.0" + } }, "node_modules/@types/triple-beam": { "version": "1.3.5", @@ -9288,7 +9473,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9369,7 +9554,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/autoprefixer": { @@ -9895,7 +10080,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -10387,7 +10572,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -11129,7 +11314,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -11875,7 +12060,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -11903,7 +12088,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/ecdsa-sig-formatter": { @@ -11932,7 +12117,7 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/emojilib": { @@ -12093,7 +12278,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -12103,7 +12288,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -12147,7 +12332,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -12160,7 +12345,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -13057,15 +13242,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, - "node_modules/farmhash-modern": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/farmhash-modern/-/farmhash-modern-1.1.0.tgz", - "integrity": "sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA==", - "license": "MIT", - "engines": { - "node": ">=18.0.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", @@ -13346,26 +13522,25 @@ } }, "node_modules/firebase-admin": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-13.10.0.tgz", - "integrity": "sha512-rbuCrJvYRwqBqvbccMS8fj/x2zsaMisdf5RQbRzQzr14Rbq9r2UlpuBHqWAwrO6c9dIRF56xF/xoepXsD5yDuQ==", + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-14.5.0.tgz", + "integrity": "sha512-DElmgmaH9aPXu2dWXGQiDoan33UfTnbfAAKaue4fwEZxmpdaNrTk5DmuFn+vVDki2KZ6TiaC0IHRWcEzcDxB3Q==", "license": "Apache-2.0", "dependencies": { "@fastify/busboy": "^3.0.0", - "@firebase/database-compat": "^2.0.0", - "@firebase/database-types": "^1.0.6", - "farmhash-modern": "^1.1.0", + "@firebase/database-compat": "^2.1.4", + "@firebase/database-types": "^1.0.20", "fast-deep-equal": "^3.1.1", - "google-auth-library": "^10.6.1", + "google-auth-library": "^11.1.0", "jsonwebtoken": "^9.0.0", - "jwks-rsa": "^3.1.0" + "jwks-rsa": "^4.0.1" }, "engines": { - "node": ">=18" + "node": ">=22" }, "optionalDependencies": { - "@google-cloud/firestore": "^7.11.0", - "@google-cloud/storage": "^7.19.0" + "@google-cloud/firestore": "^9.1.0", + "@google-cloud/storage": "^8.1.0" } }, "node_modules/firebase-admin/node_modules/data-uri-to-buffer": { @@ -13392,43 +13567,43 @@ } }, "node_modules/firebase-admin/node_modules/gcp-metadata": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", - "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-9.0.4.tgz", + "integrity": "sha512-p6WvbXOhfwnVtv/MyPq5kBiVhfV/qglMIxwwTVNEI1Ha1HmOgz5uHYHtYO6SfGckFaXe8blA11IJJ3wqXmvmBA==", "license": "Apache-2.0", "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", + "gaxios": "^7.1.3", + "google-logging-utils": "^2.0.0", "json-bigint": "^1.0.0" }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/firebase-admin/node_modules/google-auth-library": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.9.1.tgz", - "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-11.1.0.tgz", + "integrity": "sha512-YIBq5KNoHQrZ9PM4PeodDBqqBGlSTIxh1zibN8u3zNIO9UJg8gvKuCpdKV7fWXhsZ2zRkU6FhGrgKNgLJ2IRgw==", "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", - "gcp-metadata": "8.1.2", - "google-logging-utils": "1.1.3", + "gcp-metadata": "^9.0.0", + "google-logging-utils": "^2.0.0", "jws": "^4.0.0" }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/firebase-admin/node_modules/google-logging-utils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", - "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-2.0.1.tgz", + "integrity": "sha512-HMhaQghlOTvbcb3c4T5jmmOMtG3JUF1iOQMezaJXL86CDS+Tm2vHd0IeLFRAx3+ewd+bo9E1HFHoy17X5aJa9A==", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=22" } }, "node_modules/firebase-admin/node_modules/node-fetch": { @@ -13680,7 +13855,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -13693,24 +13868,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/form-data": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.6.tgz", - "integrity": "sha512-Ogz/E85h9tlfJzpI6TuFpGcHZFhLrb9Gw8wq9v40CxSCPnv7ahKr6Xgtkn0KYCDQJ8DNn5VoMO8EXr9V5PadyA==", - "license": "MIT", - "optional": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.4", - "mime-types": "^2.1.35", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -13929,7 +14086,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -13963,7 +14120,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -14024,7 +14181,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -14076,7 +14233,7 @@ "version": "2.1.7", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -14086,7 +14243,7 @@ "version": "9.0.9", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.2" @@ -14162,27 +14319,26 @@ } }, "node_modules/google-gax": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.6.1.tgz", - "integrity": "sha512-V6eky/xz2mcKfAd1Ioxyd6nmA61gao3n01C+YeuIwu3vzM9EDR6wcVzMSIbLMDXWeoi9SHYctXuKYC5uJUT3eQ==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-6.7.0.tgz", + "integrity": "sha512-v9QQ0c3MFCqG5K0/wfao7Bkk3knNxfnBHRb0UAssQvZJsf9DitRrguMrrSAfFcaEf3L6DHflbUyfW2NUt9aKFw==", "license": "Apache-2.0", "optional": 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", + "@grpc/grpc-js": "^1.12.6", + "@grpc/proto-loader": "^0.8.0", + "@opentelemetry/api": "^1.9.0", + "duplexify": "^4.1.3", + "google-auth-library": "^11.0.0", + "google-logging-utils": "^2.0.0", + "node-fetch": "^3.3.2", "object-hash": "^3.0.0", - "proto3-json-serializer": "^2.0.2", - "protobufjs": "^7.3.2", - "retry-request": "^7.0.0", - "uuid": "^9.0.1" + "proto3-json-serializer": "^4.0.0", + "protobufjs": "^7.5.4", + "retry-request": "^9.0.0" }, "engines": { - "node": ">=14" + "node": ">=22" } }, "node_modules/google-gax/node_modules/@grpc/grpc-js": { @@ -14199,7 +14355,7 @@ "node": ">=12.10.0" } }, - "node_modules/google-gax/node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": { + "node_modules/google-gax/node_modules/@grpc/proto-loader": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.1.tgz", "integrity": "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==", @@ -14218,6 +14374,93 @@ "node": ">=6" } }, + "node_modules/google-gax/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/google-gax/node_modules/gaxios": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.3.1.tgz", + "integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-gax/node_modules/gcp-metadata": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-9.0.4.tgz", + "integrity": "sha512-p6WvbXOhfwnVtv/MyPq5kBiVhfV/qglMIxwwTVNEI1Ha1HmOgz5uHYHtYO6SfGckFaXe8blA11IJJ3wqXmvmBA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "gaxios": "^7.1.3", + "google-logging-utils": "^2.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/google-gax/node_modules/google-auth-library": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-11.1.0.tgz", + "integrity": "sha512-YIBq5KNoHQrZ9PM4PeodDBqqBGlSTIxh1zibN8u3zNIO9UJg8gvKuCpdKV7fWXhsZ2zRkU6FhGrgKNgLJ2IRgw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "^9.0.0", + "google-logging-utils": "^2.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/google-gax/node_modules/google-logging-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-2.0.1.tgz", + "integrity": "sha512-HMhaQghlOTvbcb3c4T5jmmOMtG3JUF1iOQMezaJXL86CDS+Tm2vHd0IeLFRAx3+ewd+bo9E1HFHoy17X5aJa9A==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=22" + } + }, + "node_modules/google-gax/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "optional": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/google-logging-utils": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", @@ -14353,7 +14596,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -14437,7 +14680,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -14450,7 +14693,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -14592,7 +14835,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -15494,7 +15737,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, + "devOptional": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -15844,25 +16087,26 @@ } }, "node_modules/jwks-rsa": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.2.2.tgz", - "integrity": "sha512-BqTyEDV+lS8F2trk3A+qJnxV5Q9EqKCBJOPti3W97r7qTympCZjb7h2X6f2kc+0K3rsSTY1/6YG2eaXKoj497w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-4.1.0.tgz", + "integrity": "sha512-sbkByqyATKYJP5F4RXj03N5TUNC0QLTjCAZvwTzC4BwJZ8e0/cWxN8YROnyUth2g1/ONWi4eSFHeu6oYalrc3Q==", "license": "MIT", "dependencies": { "@types/jsonwebtoken": "^9.0.4", "debug": "^4.3.4", - "jose": "^4.15.4", + "jose": "^6.1.3", "limiter": "^1.1.5", - "lru-memoizer": "^2.2.0" + "lru-cache": "^11.0.0", + "lru-memoizer": "^3.0.0" }, "engines": { - "node": ">=14" + "node": "^20.19.0 || ^22.12.0 || >= 23.0.0" } }, "node_modules/jwks-rsa/node_modules/jose": { - "version": "4.15.9", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", - "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -16505,25 +16749,13 @@ } }, "node_modules/lru-memoizer": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz", - "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-3.0.0.tgz", + "integrity": "sha512-m83w/cYXLdUIboKSPxzPAGfYnk+vqeDYXuoSrQRw1q+yVEd8IXhvMufN8Q5TIPe7e2jyX4SRNrDJI2Skw1yznQ==", "license": "MIT", "dependencies": { "lodash.clonedeep": "^4.5.0", - "lru-cache": "6.0.0" - } - }, - "node_modules/lru-memoizer/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "lru-cache": "^11.0.1" } }, "node_modules/lsofi": { @@ -16656,7 +16888,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -16745,7 +16977,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -16755,7 +16987,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -17723,7 +17955,7 @@ "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, + "devOptional": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { @@ -17815,7 +18047,7 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, + "devOptional": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -17832,7 +18064,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/path-to-regexp": { @@ -18378,16 +18610,16 @@ "license": "ISC" }, "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==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-4.0.2.tgz", + "integrity": "sha512-VUQlb/J2WjOG8BKhdLwJUz+MKxSMtBGYh+TaNmRtiYVhlIzXjzeAGIx7gtc3lXlA2iURzfF2+cXaQvC2ofwzpg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "protobufjs": "^7.2.5" + "protobufjs": "^7.5.4" }, "engines": { - "node": ">=14.0.0" + "node": ">=22" } }, "node_modules/protobufjs": { @@ -19018,18 +19250,17 @@ } }, "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==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-9.0.1.tgz", + "integrity": "sha512-4kGHEBl0ME6gR+8QB1sPMyg58jUxLUcCZNeqLDrfqzk0eWQN8XJFmeu7fmZCjlZCRW0S2u64Ik1HkO/0sWgCYQ==", "license": "MIT", "optional": true, "dependencies": { - "@types/request": "^2.48.8", "extend": "^3.0.2", - "teeny-request": "^9.0.0" + "teeny-request": "^11.0.0" }, "engines": { - "node": ">=14" + "node": ">=22" } }, "node_modules/reusify": { @@ -19046,7 +19277,7 @@ "version": "5.0.10", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "glob": "^10.3.7" @@ -19743,7 +19974,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=14" @@ -20019,7 +20250,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -20034,7 +20265,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/string-width/node_modules/emoji-regex": { @@ -20173,7 +20404,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -20588,62 +20819,48 @@ "license": "MIT" }, "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==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-11.0.1.tgz", + "integrity": "sha512-bNr5j2YjSdajgCVsp+8JVjRf1uHIbpNISLeKp/7V1NnVMX3Gh6H/kECNGlm2Q3I68ACODQ0iv6aZ3Rvm8WgLGA==", "license": "Apache-2.0", "optional": 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" + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2", + "stream-events": "^1.0.5" }, "engines": { - "node": ">=14" + "node": ">=22" } }, - "node_modules/teeny-request/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/teeny-request/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "license": "MIT", "optional": true, - "dependencies": { - "debug": "4" - }, "engines": { - "node": ">= 6.0.0" + "node": ">= 12" } }, - "node_modules/teeny-request/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "node_modules/teeny-request/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "license": "MIT", "optional": true, "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/teeny-request/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "6", - "debug": "4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "engines": { - "node": ">= 6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/teex": { @@ -22004,7 +22221,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -22128,12 +22345,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/yaml": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", diff --git a/package.json b/package.json index 46e8614..d41dae7 100644 --- a/package.json +++ b/package.json @@ -20,13 +20,14 @@ "db:restore": "tsx scripts/db-restore.ts", "migrate:firestore": "tsx scripts/migrate-firestore.ts", "test:db": "vitest run tests/db", - "test": "vitest run", + "test": "npm run check:admin-import && vitest run", "test:watch": "vitest", "test:rules": "firebase emulators:exec --only auth,firestore,storage --project demo-sfpca \"node --test \\\"tests/*.test.mjs\\\"\"", "test:maintenance": "vitest run tests/maintenance.test.ts", "test:e2e": "firebase emulators:exec --only auth,firestore --project demo-sfpca \"playwright test\"", "test:e2e:headed": "firebase emulators:exec --only auth,firestore --project demo-sfpca \"playwright test --headed\"", - "deploy:functions": "node scripts/deploy-functions.js" + "deploy:functions": "node scripts/deploy-functions.js", + "check:admin-import": "node scripts/check-admin-import.mjs" }, "dependencies": { "@radix-ui/react-checkbox": "^1.3.11", @@ -45,7 +46,7 @@ "drizzle-orm": "^0.45.2", "fast-xml-parser": "^5.3.4", "firebase": "^12.19.0", - "firebase-admin": "^13.10.0", + "firebase-admin": "^14.5.0", "framer-motion": "^13.4.0", "klaro": "^0.7.21", "lucide-react": "^1.47.0", @@ -86,6 +87,9 @@ "vitest": "^5.0.1" }, "overrides": { - "fast-xml-parser": "^5.3.4" + "fast-xml-parser": "^5.3.4", + "jwks-rsa": { + "jose": "5.10.0" + } } } diff --git a/scripts/audit-firestore.ts b/scripts/audit-firestore.ts index c68baa3..6fbec0f 100644 --- a/scripts/audit-firestore.ts +++ b/scripts/audit-firestore.ts @@ -74,7 +74,7 @@ async function audit( } async function main() { - const { adminDb } = await import("../src/lib/firebase-admin"); + const { adminDb } = await import("../src/lib/firebase-admin-db"); const fs = adminDb(); for (const c of ["animals", "animalRegistrations", "admins"]) { await audit(fs, c); diff --git a/scripts/check-admin-import.mjs b/scripts/check-admin-import.mjs new file mode 100644 index 0000000..bd8eacd --- /dev/null +++ b/scripts/check-admin-import.mjs @@ -0,0 +1,45 @@ +// Server-runtime smoke check for the firebase-admin dependency chain. +// +// Why this exists: issue #144 — a firebase-admin/jwks-rsa/jose combination +// installed, typechecked, and built cleanly, then crashed the deployed +// Vercel serverless function with ERR_REQUIRE_ESM on first import. +// This script loads the same entrypoints through plain Node ESM — no +// bundler, no test transform — the closest credential-free signal to the +// deployed runtime. (tests/firebase-admin-runtime.test.ts additionally +// loads them under a CommonJS-only subprocess, matching Vercel exactly.) +// +// Run: node scripts/check-admin-import.mjs (wired into `npm test`) + +import { readFileSync } from "node:fs"; +import { findPackageJSON } from "node:module"; + +const entrypoints = { + "firebase-admin/app": ["initializeApp", "cert", "getApps"], + "firebase-admin/auth": ["getAuth"], + "firebase-admin/firestore": ["getFirestore"], + "firebase-admin/storage": ["getStorage"], +}; + +// firebase-admin's exports map does not expose ./package.json, so locate +// it via Node's own package resolution. +const pkgJsonPath = findPackageJSON("firebase-admin", import.meta.url); +const { version } = JSON.parse(readFileSync(pkgJsonPath, "utf8")); +if (!version.startsWith("14.")) { + console.error( + `firebase-admin@${version} loaded — expected the 14.x line ` + + `(issue #223).`, + ); + process.exit(1); +} + +for (const [entry, names] of Object.entries(entrypoints)) { + const mod = await import(entry); + for (const name of names) { + if (typeof mod[name] !== "function") { + console.error(`${entry}: expected export "${name}" to be a function`); + process.exit(1); + } + } +} + +console.log(`firebase-admin@${version}: server import chain OK`); diff --git a/scripts/db-backup.ts b/scripts/db-backup.ts index a79f8d5..c2d2eff 100644 --- a/scripts/db-backup.ts +++ b/scripts/db-backup.ts @@ -88,7 +88,7 @@ async function main() { // Lazy import so missing Firebase env fails with the Admin SDK's // explicit missing-var error rather than at module load. - const { adminBucket } = await import("../src/lib/firebase-admin"); + const { adminBucket } = await import("../src/lib/firebase-admin-storage"); const bucket = adminBucket(); const t1 = Date.now(); diff --git a/scripts/db-restore.ts b/scripts/db-restore.ts index f65553d..b9d20b5 100644 --- a/scripts/db-restore.ts +++ b/scripts/db-restore.ts @@ -118,7 +118,7 @@ async function apiRetry(pathname: string, init?: RequestInit, attempts = 15) { async function fetchDump(): Promise { if (fs.existsSync(dumpArg!)) return dumpArg!; - const { adminBucket } = await import("../src/lib/firebase-admin"); + const { adminBucket } = await import("../src/lib/firebase-admin-storage"); const dest = path.join(os.tmpdir(), path.basename(dumpArg!)); console.log(`db-restore: downloading ${dumpArg} from Storage…`); await adminBucket().file(dumpArg!).download({ destination: dest }); diff --git a/scripts/migrate-firestore.ts b/scripts/migrate-firestore.ts index d6189c5..081f236 100644 --- a/scripts/migrate-firestore.ts +++ b/scripts/migrate-firestore.ts @@ -152,7 +152,7 @@ async function main() { ); } - const { adminDb } = await import("../src/lib/firebase-admin"); + const { adminDb } = await import("../src/lib/firebase-admin-db"); const fs = adminDb(); const pg = dbUrlValid ? postgres(dbUrl!, { max: 1, prepare: false }) : null; const db = pg ? drizzle(pg) : null; diff --git a/scripts/reconcile-migration.ts b/scripts/reconcile-migration.ts index 2d9c52b..5e49f71 100644 --- a/scripts/reconcile-migration.ts +++ b/scripts/reconcile-migration.ts @@ -90,7 +90,7 @@ async function main() { `db=${target.pathname.slice(1)}`, ); - const { adminDb } = await import("../src/lib/firebase-admin"); + const { adminDb } = await import("../src/lib/firebase-admin-db"); const fs = adminDb(); const pg = postgres(dbUrl!, { max: 1, prepare: false }); const db = drizzle(pg); diff --git a/src/app/admin/homepage/actions.ts b/src/app/admin/homepage/actions.ts index 26fe8c1..4028347 100644 --- a/src/app/admin/homepage/actions.ts +++ b/src/app/admin/homepage/actions.ts @@ -1,6 +1,6 @@ "use server"; -import { adminDb } from "@/lib/firebase-admin"; +import { adminDb } from "@/lib/firebase-admin-db"; import { requireAdmin } from "@/lib/auth"; import { Homepage } from "@/lib/types"; import { logError } from "@/lib/logger"; diff --git a/src/app/admin/registrations/actions.ts b/src/app/admin/registrations/actions.ts index d0168b0..44c2602 100644 --- a/src/app/admin/registrations/actions.ts +++ b/src/app/admin/registrations/actions.ts @@ -6,7 +6,7 @@ // private (no public-read Storage rule). import { requireAdmin } from "@/lib/auth"; -import { adminReceiptBucket } from "@/lib/firebase-admin"; +import { adminReceiptBucket } from "@/lib/firebase-admin-storage"; import { createRegistration, getRegistrationQueues, diff --git a/src/app/api/auth/session/route.ts b/src/app/api/auth/session/route.ts index c9a6ba9..41a6bfa 100644 --- a/src/app/api/auth/session/route.ts +++ b/src/app/api/auth/session/route.ts @@ -1,5 +1,5 @@ import { NextRequest, NextResponse } from "next/server"; -import { adminAuth } from "@/lib/firebase-admin"; +import { adminAuth } from "@/lib/firebase-admin-auth"; import { isAdmin, isExpectedAuthError } from "@/lib/auth"; import { provisionAdminUser } from "@/lib/registry/admin-users"; import { upsertAuthIdentity } from "@/lib/registry/persons"; diff --git a/src/app/api/cron/sweep-receipts/route.ts b/src/app/api/cron/sweep-receipts/route.ts index fdc2df9..f97a241 100644 --- a/src/app/api/cron/sweep-receipts/route.ts +++ b/src/app/api/cron/sweep-receipts/route.ts @@ -8,7 +8,7 @@ // the variable is unset so the route is never publicly callable. import { NextRequest, NextResponse } from "next/server"; -import { adminReceiptBucket } from "@/lib/firebase-admin"; +import { adminReceiptBucket } from "@/lib/firebase-admin-storage"; import { getRegistryDb } from "@/lib/db/client"; import { sweepOrphanedReceipts } from "@/lib/registry/receipt-sweep"; import { logError } from "@/lib/logger"; diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 74a2c82..abdb8ac 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,4 +1,4 @@ -import { adminAuth } from "./firebase-admin"; +import { adminAuth } from "./firebase-admin-auth"; import { findAdminUser } from "./registry/admin-users"; import { resolveOwnerSession } from "./registry/persons"; import { logError } from "./logger"; diff --git a/src/lib/firebase-admin.ts b/src/lib/firebase-admin-app.ts similarity index 68% rename from src/lib/firebase-admin.ts rename to src/lib/firebase-admin-app.ts index b16d1a7..e81bb67 100644 --- a/src/lib/firebase-admin.ts +++ b/src/lib/firebase-admin-app.ts @@ -1,7 +1,4 @@ import { initializeApp, getApps, cert, App } from "firebase-admin/app"; -import { getAuth } from "firebase-admin/auth"; -import { getFirestore } from "firebase-admin/firestore"; -import { getStorage } from "firebase-admin/storage"; let adminApp: App; @@ -19,7 +16,7 @@ export function missingAdminEnvVars( return REQUIRED_ADMIN_ENV.filter((name) => !env[name]); } -function getAdminApp() { +export function getAdminApp() { if (getApps().length === 0) { // Emulator hosts signal a local/E2E run: no credentials are needed or // used, and a demo-* project ID can never reach production services. @@ -56,20 +53,3 @@ function getAdminApp() { } return adminApp; } - -export const adminAuth = () => getAuth(getAdminApp()); -export const adminDb = () => getFirestore(getAdminApp()); -export const adminStorage = () => getStorage(getAdminApp()); - -// Receipt objects live under receipts/ in the default -// bucket. Signed URLs are minted here (never via the client SDK) so -// admin review can read private receipts without public-read rules. -export const adminReceiptBucket = () => adminBucket(); - -// Generic default-bucket accessor — used by the db-backup scripts for -// the db-backups/ prefix (deny-all client rules; Admin SDK bypasses). -export const adminBucket = () => - adminStorage().bucket( - process.env.FIREBASE_ADMIN_STORAGE_BUCKET ?? - process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, - ); diff --git a/src/lib/firebase-admin-auth.ts b/src/lib/firebase-admin-auth.ts new file mode 100644 index 0000000..8b1980c --- /dev/null +++ b/src/lib/firebase-admin-auth.ts @@ -0,0 +1,7 @@ +import { getAuth } from "firebase-admin/auth"; +import { getAdminApp } from "./firebase-admin-app"; + +// Auth is isolated in its own module: only callers that verify tokens or +// manage users import the firebase-admin/auth graph (jwks-rsa -> jose), +// the dependency chain behind the #144 Vercel ERR_REQUIRE_ESM outage. +export const adminAuth = () => getAuth(getAdminApp()); diff --git a/src/lib/firebase-admin-db.ts b/src/lib/firebase-admin-db.ts new file mode 100644 index 0000000..8735e54 --- /dev/null +++ b/src/lib/firebase-admin-db.ts @@ -0,0 +1,7 @@ +import { getFirestore } from "firebase-admin/firestore"; +import { getAdminApp } from "./firebase-admin-app"; + +// Firestore lives in its own module so Firestore-only routes and scripts +// never import firebase-admin/auth — its jwks-rsa -> ESM-only jose chain +// is the failure that caused the #144 Vercel runtime outage. +export const adminDb = () => getFirestore(getAdminApp()); diff --git a/src/lib/firebase-admin-storage.ts b/src/lib/firebase-admin-storage.ts new file mode 100644 index 0000000..0dd36a2 --- /dev/null +++ b/src/lib/firebase-admin-storage.ts @@ -0,0 +1,17 @@ +import { getStorage } from "firebase-admin/storage"; +import { getAdminApp } from "./firebase-admin-app"; + +export const adminStorage = () => getStorage(getAdminApp()); + +// Receipt objects live under receipts/ in the default +// bucket. Signed URLs are minted here (never via the client SDK) so +// admin review can read private receipts without public-read rules. +export const adminReceiptBucket = () => adminBucket(); + +// Generic default-bucket accessor — used by the db-backup scripts for +// the db-backups/ prefix (deny-all client rules; Admin SDK bypasses). +export const adminBucket = () => + adminStorage().bucket( + process.env.FIREBASE_ADMIN_STORAGE_BUCKET ?? + process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, + ); diff --git a/tests/admin-actions.test.ts b/tests/admin-actions.test.ts index a820290..ea24229 100644 --- a/tests/admin-actions.test.ts +++ b/tests/admin-actions.test.ts @@ -14,7 +14,7 @@ vi.mock("@/lib/auth", () => ({ requireAdmin: mockRequireAdmin, })); -vi.mock("@/lib/firebase-admin", () => ({ +vi.mock("@/lib/firebase-admin-db", () => ({ adminDb: () => ({ collection: () => ({ doc: () => ({ set: mockDocSet, get: mockDocGet }), diff --git a/tests/auth.test.ts b/tests/auth.test.ts index 26d65af..8e878f5 100644 --- a/tests/auth.test.ts +++ b/tests/auth.test.ts @@ -15,7 +15,7 @@ const { mockLogError: vi.fn(), })); -vi.mock("@/lib/firebase-admin", () => ({ +vi.mock("@/lib/firebase-admin-auth", () => ({ adminAuth: () => ({ verifySessionCookie: mockVerifySessionCookie, }), diff --git a/tests/firebase-admin-env.test.ts b/tests/firebase-admin-env.test.ts index 870dcf7..8aaaec0 100644 --- a/tests/firebase-admin-env.test.ts +++ b/tests/firebase-admin-env.test.ts @@ -2,7 +2,7 @@ // missing env vars — never a cryptic cert() failure, and never the // values themselves. import { describe, expect, test } from "vitest"; -import { missingAdminEnvVars } from "@/lib/firebase-admin"; +import { missingAdminEnvVars } from "@/lib/firebase-admin-app"; describe("missingAdminEnvVars", () => { test("names every missing required variable", () => { diff --git a/tests/firebase-admin-runtime.test.ts b/tests/firebase-admin-runtime.test.ts index cb2e5b0..01cdd17 100644 --- a/tests/firebase-admin-runtime.test.ts +++ b/tests/firebase-admin-runtime.test.ts @@ -18,6 +18,7 @@ const ADMIN_MODULES = [ "firebase-admin/app", "firebase-admin/auth", "firebase-admin/firestore", + "firebase-admin/storage", ] as const; // Spawning Node and loading firebase-admin takes a few seconds — allow diff --git a/tests/session-route.test.ts b/tests/session-route.test.ts index 09866dd..6cc6eae 100644 --- a/tests/session-route.test.ts +++ b/tests/session-route.test.ts @@ -26,7 +26,7 @@ const { mockProvisionOwnerLink: vi.fn(), })); -vi.mock("@/lib/firebase-admin", () => ({ +vi.mock("@/lib/firebase-admin-auth", () => ({ adminAuth: () => ({ verifyIdToken: mockVerifyIdToken, createSessionCookie: mockCreateSessionCookie, From 5010c296d5bf46545a23f9e791408dfbc93dd8be Mon Sep 17 00:00:00 2001 From: Chad Nuttall Date: Tue, 29 Sep 2026 19:49:19 -0400 Subject: [PATCH 2/2] fix: repoint adminBucket imports to firebase-admin-storage after merge Main's vet-documents and animal-merge routes postdate the firebase-admin module split, so they still imported the removed '@/lib/firebase-admin' barrel. Point them at firebase-admin-storage, which owns adminBucket. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- src/app/admin/animals/[id]/actions.ts | 2 +- src/app/admin/documents/[id]/route.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/admin/animals/[id]/actions.ts b/src/app/admin/animals/[id]/actions.ts index b336efa..a25ffe2 100644 --- a/src/app/admin/animals/[id]/actions.ts +++ b/src/app/admin/animals/[id]/actions.ts @@ -99,7 +99,7 @@ import { getAnimalMergeInfo, type AnimalMergeInfo, } from "@/lib/registry/merge"; -import { adminBucket } from "@/lib/firebase-admin"; +import { adminBucket } from "@/lib/firebase-admin-storage"; import { isVetDocumentFile, VET_DOC_PATH_RE } from "@/lib/medical"; import { logError, type LogSubsystem } from "@/lib/logger"; diff --git a/src/app/admin/documents/[id]/route.ts b/src/app/admin/documents/[id]/route.ts index e58a36e..8a6586f 100644 --- a/src/app/admin/documents/[id]/route.ts +++ b/src/app/admin/documents/[id]/route.ts @@ -16,7 +16,7 @@ import { requireAdmin } from "@/lib/auth"; import { getRegistryDb } from "@/lib/db/client"; import { auditEvents } from "@/lib/db/schema"; import { getVetDocumentStoragePath } from "@/lib/registry/medical"; -import { adminBucket } from "@/lib/firebase-admin"; +import { adminBucket } from "@/lib/firebase-admin-storage"; import { logError } from "@/lib/logger"; export const dynamic = "force-dynamic";