diff --git a/README.md b/README.md index 0c768126b..e4e749e1f 100644 --- a/README.md +++ b/README.md @@ -19,17 +19,17 @@ by conforming to Angular conventions. ## Example use ```ts -import { provideFirebaseApp, getApp, initializeApp } from '@angular/fire/app'; +import { provideFirebaseApp, initializeApp } from '@angular/fire/app'; import { getFirestore, provideFirestore } from '@angular/fire/firestore'; -@NgModule({ - imports: [ +export const appConfig: ApplicationConfig = { + providers: [ provideFirebaseApp(() => initializeApp({ ... })), provideFirestore(() => getFirestore()), + ... ], ... }) -export class AppModule { } ``` ```ts @@ -44,11 +44,14 @@ interface Item { @Component({ selector: 'app-root', + standalone: true, template: ` ` }) @@ -96,11 +99,11 @@ We have three sample apps in this repository: Get help on our [Q&A board](https://github.com/angular/angularfire/discussions?discussions_q=category%3AQ%26A), the official [Firebase Mailing List](https://groups.google.com/forum/#!forum/firebase-talk), the [Firebase Community Slack](https://firebase.community/) (`#angularfire2`), the [Angular Community Discord](http://discord.gg/angular) (`#firebase`), [Gitter](https://gitter.im/angular/angularfire2), the [Firebase subreddit](https://www.reddit.com/r/firebase), or [Stack Overflow](https://stackoverflow.com/questions/tagged/angularfire2). -> **NOTE:** AngularFire is maintained by Googlers but is not a supported Firebase product. Questions on the mailing list and issues filed here are answered on a best-effort basis by maintainers and other community members. If you are able to reproduce a problem with Firebase outside of AngularFire's implementation, please [file an issue on the Firebase JS SDK](https://github.com/firebase/firebase-js-sdk/issues) or reach out to the personalized [Firebase support channel](https://firebase.google.com/support/). +> **NOTE:** While relatively stable, AngularFire is a [developer preview](https://angular.io/guide/releases#developer-preview) and is subject to change before general availability. Questions on the mailing list and issues filed here are answered on a best-effort basis by maintainers and other community members. If you are able to reproduce a problem with Firebase outside of AngularFire's implementation, please [file an issue on the Firebase JS SDK](https://github.com/firebase/firebase-js-sdk/issues) or reach out to the personalized [Firebase support channel](https://firebase.google.com/support/). ## Developer Guide -This developer guide assumes you're using the new tree-shakable AngularFire API, [if you're looking for the compatability API you can find the documentation here](docs/compat.md). +This developer guide assumes you're using the new tree-shakable AngularFire API, [if you're looking for the compatibility API you can find the documentation here](docs/compat.md). [See the v7 upgrade guide for more information on this change.](docs/version-7-upgrade.md). @@ -188,9 +191,3 @@ import { } from '@angular/fire/app-check'; - -### Deploying your site - -* Deploy to Firebase Hosting -* Angular Universal: Deploy to Cloud Functions -* Angular Universal: Deploy to Cloud Run diff --git a/package-lock.json b/package-lock.json index 18e35de3e..378b9a0ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@angular/platform-browser-dynamic": "^17.0.0", "@angular/router": "^17.0.0", "@schematics/angular": "^17.0.0", - "firebase": "^10.7.0", + "firebase": "^10.12.0", "firebase-admin": "^9.11.1", "firebase-functions": "^3.6.0", "firebase-tools": "^13.0.0", @@ -3557,14 +3557,14 @@ } }, "node_modules/@firebase/analytics": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.0.tgz", - "integrity": "sha512-Locv8gAqx0e+GX/0SI3dzmBY5e9kjVDtD+3zCFLJ0tH2hJwuCAiL+5WkHuxKj92rqQj/rvkBUCfA1ewlX2hehg==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/installations": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.3.tgz", + "integrity": "sha512-pMADbAgmfM3vDSeINCw0qSTBA9nn6so8min2KaBfu5eda5kfemb/DeawNUKOIxrP3yV4teJgCKA3JFomfnozEg==", + "dependencies": { + "@firebase/component": "0.6.7", + "@firebase/installations": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3572,14 +3572,14 @@ } }, "node_modules/@firebase/analytics-compat": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.6.tgz", - "integrity": "sha512-4MqpVLFkGK7NJf/5wPEEP7ePBJatwYpyjgJ+wQHQGHfzaCDgntOnl9rL2vbVGGKCnRqWtZDIWhctB86UWXaX2Q==", - "dependencies": { - "@firebase/analytics": "0.10.0", - "@firebase/analytics-types": "0.8.0", - "@firebase/component": "0.6.4", - "@firebase/util": "1.9.3", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.9.tgz", + "integrity": "sha512-ZKXaUixA+drbf3meX1bhPCG90UWrpw1KDrCydhe2Uf0VFZmZyVVr0bAcVpqLm29W4td7qp2RpFjVwercZ5mxTg==", + "dependencies": { + "@firebase/analytics": "0.10.3", + "@firebase/analytics-types": "0.8.2", + "@firebase/component": "0.6.7", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3587,30 +3587,30 @@ } }, "node_modules/@firebase/analytics-types": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.0.tgz", - "integrity": "sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw==" + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.2.tgz", + "integrity": "sha512-EnzNNLh+9/sJsimsA/FGqzakmrAUKLeJvjRHlg8df1f97NLUlFidk9600y0ZgWOp3CAxn6Hjtk+08tixlUOWyw==" }, "node_modules/@firebase/app": { - "version": "0.9.25", - "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.25.tgz", - "integrity": "sha512-fX22gL5USXhOK21Hlh3oTeOzQZ6th6S2JrjXNEpBARmwzuUkqmVGVdsOCIFYIsLpK0dQE3o8xZnLrRg5wnzZ/g==", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.3.tgz", + "integrity": "sha512-+pW2wNjijh88aFRjNWhDNlVJI5vB7q1IKYEE79a7ErxwNS/Bo+oh16aAAPvunhT06EF5I8y9gAlNuHNN8u4z8g==", "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "idb": "7.1.1", "tslib": "^2.1.0" } }, "node_modules/@firebase/app-check": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.1.tgz", - "integrity": "sha512-zi3vbM5tb/eGRWyiqf+1DXbxFu9Q07dnm46rweodgUpH9B8svxYkHfNwYWx7F5mjHU70SQDuaojH1We5ws9OKA==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.4.tgz", + "integrity": "sha512-2tjRDaxcM5G7BEpytiDcIl+NovV99q8yEqRMKDbn4J4i/XjjuThuB4S+4PkmTnZiCbdLXQiBhkVxNlUDcfog5Q==", "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3618,15 +3618,15 @@ } }, "node_modules/@firebase/app-check-compat": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.8.tgz", - "integrity": "sha512-EaETtChR4UgMokJFw+r6jfcIyCTUZSe0a6ivF37D9MxlG9G3wzK1COyXgxoX96GzXmDPc2aubX4PxCrdVHhrnA==", - "dependencies": { - "@firebase/app-check": "0.8.1", - "@firebase/app-check-types": "0.5.0", - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.11.tgz", + "integrity": "sha512-t01zaH3RJpKEey0nGduz3Is+uSz7Sj4U5nwOV6lWb+86s5xtxpIvBJzu/lKxJfYyfZ29eJwpdjEgT1/lm4iQyA==", + "dependencies": { + "@firebase/app-check": "0.8.4", + "@firebase/app-check-types": "0.5.2", + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3634,42 +3634,42 @@ } }, "node_modules/@firebase/app-check-interop-types": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.0.tgz", - "integrity": "sha512-xAxHPZPIgFXnI+vb4sbBjZcde7ZluzPPaSK7Lx3/nmuVk4TjZvnL8ONnkd4ERQKL8WePQySU+pRcWkh8rDf5Sg==" + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz", + "integrity": "sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ==" }, "node_modules/@firebase/app-check-types": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.0.tgz", - "integrity": "sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ==" + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.2.tgz", + "integrity": "sha512-FSOEzTzL5bLUbD2co3Zut46iyPWML6xc4x+78TeaXMSuJap5QObfb+rVvZJtla3asN4RwU7elaQaduP+HFizDA==" }, "node_modules/@firebase/app-compat": { - "version": "0.2.25", - "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.25.tgz", - "integrity": "sha512-B/JtCp1FsTuzlh1tIGQpYM2AXps21/zlzpFsk5LRsROOTRhBcR2N45AyaONPFD06C0yS0Tw19foxADzHyOSC3A==", - "dependencies": { - "@firebase/app": "0.9.25", - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "0.2.33", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.33.tgz", + "integrity": "sha512-CLXhYJBtLuHXCUvs894gpXEXhZ7Nhytn2icLLIesH+hPLnyBeBf2CSve6Wjig+TOxTdwOQUzdtYpdjmeeYDfpw==", + "dependencies": { + "@firebase/app": "0.10.3", + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" } }, "node_modules/@firebase/app-types": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", - "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2.tgz", + "integrity": "sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ==" }, "node_modules/@firebase/auth": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.5.1.tgz", - "integrity": "sha512-sVi7rq2YneLGJFqHa5S6nDfCHix9yuVV3RLhj/pWPlB4a36ofXal4E6PJwpeMc8uLjWEr1aovYN1jkXWNB6Avw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.3.tgz", + "integrity": "sha512-RiU1PjziOxLuyswtYtLK2qSjHIQJQGCk1h986SUFRbMQfzLXbQg8ZgXwxac1UAfDOzgzqPNCXhBuIlSK2UomoQ==", "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0", - "undici": "5.26.5" + "undici": "5.28.4" }, "peerDependencies": { "@firebase/app": "0.x", @@ -3682,25 +3682,25 @@ } }, "node_modules/@firebase/auth-compat": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.1.tgz", - "integrity": "sha512-rgDZnrDoekRvtzXVji8Z61wxxkof6pTkjYEkybILrjM8tGP9tx4xa9qGpF4ax3AzF+rKr7mIa9NnoXEK4UNqmQ==", - "dependencies": { - "@firebase/auth": "1.5.1", - "@firebase/auth-types": "0.12.0", - "@firebase/component": "0.6.4", - "@firebase/util": "1.9.3", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.8.tgz", + "integrity": "sha512-qUgmv/mcth9wHPTOCKgAOeHe5c+BIOJVcbX2RfcjlXO3xnd8nRafwEkZKBNJUjy4oihYhqFMEMnTHLhwLJwLig==", + "dependencies": { + "@firebase/auth": "1.7.3", + "@firebase/auth-types": "0.12.2", + "@firebase/component": "0.6.7", + "@firebase/util": "1.9.6", "tslib": "^2.1.0", - "undici": "5.26.5" + "undici": "5.28.4" }, "peerDependencies": { "@firebase/app-compat": "0.x" } }, "node_modules/@firebase/auth-compat/node_modules/undici": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz", - "integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -3709,23 +3709,23 @@ } }, "node_modules/@firebase/auth-interop-types": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", - "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz", + "integrity": "sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ==" }, "node_modules/@firebase/auth-types": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.0.tgz", - "integrity": "sha512-pPwaZt+SPOshK8xNoiQlK5XIrS97kFYc3Rc7xmy373QsOJ9MmqXxLaYssP5Kcds4wd2qK//amx/c+A8O2fVeZA==", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.2.tgz", + "integrity": "sha512-qsEBaRMoGvHO10unlDJhaKSuPn4pyoTtlQuP1ghZfzB6rNQPuhp/N/DcFZxm9i4v0SogjCbf9reWupwIvfmH6w==", "peerDependencies": { "@firebase/app-types": "0.x", "@firebase/util": "1.x" } }, "node_modules/@firebase/auth/node_modules/undici": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz", - "integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -3734,63 +3734,63 @@ } }, "node_modules/@firebase/component": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", - "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.7.tgz", + "integrity": "sha512-baH1AA5zxfaz4O8w0vDwETByrKTQqB5CDjRls79Sa4eAGAoERw4Tnung7XbMl3jbJ4B/dmmtsMrdki0KikwDYA==", "dependencies": { - "@firebase/util": "1.9.3", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" } }, "node_modules/@firebase/database": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.2.tgz", - "integrity": "sha512-8X6NBJgUQzDz0xQVaCISoOLINKat594N2eBbMR3Mu/MH/ei4WM+aAMlsNzngF22eljXu1SILP5G3evkyvsG3Ng==", - "dependencies": { - "@firebase/app-check-interop-types": "0.3.0", - "@firebase/auth-interop-types": "0.2.1", - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.5.tgz", + "integrity": "sha512-cAfwBqMQuW6HbhwI3Cb/gDqZg7aR0OmaJ85WUxlnoYW2Tm4eR0hFl5FEijI3/gYPUiUcUPQvTkGV222VkT7KPw==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.2", + "@firebase/auth-interop-types": "0.2.3", + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "faye-websocket": "0.11.4", "tslib": "^2.1.0" } }, "node_modules/@firebase/database-compat": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.2.tgz", - "integrity": "sha512-09ryJnXDvuycsxn8aXBzLhBTuCos3HEnCOBWY6hosxfYlNCGnLvG8YMlbSAt5eNhf7/00B095AEfDsdrrLjxqA==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/database": "1.0.2", - "@firebase/database-types": "1.0.0", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.5.tgz", + "integrity": "sha512-NDSMaDjQ+TZEMDMmzJwlTL05kh1+0Y84C+kVMaOmNOzRGRM7VHi29I6YUhCetXH+/b1Wh4ZZRyp1CuWkd8s6hg==", + "dependencies": { + "@firebase/component": "0.6.7", + "@firebase/database": "1.0.5", + "@firebase/database-types": "1.0.3", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" } }, "node_modules/@firebase/database-types": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.0.tgz", - "integrity": "sha512-SjnXStoE0Q56HcFgNQ+9SsmJc0c8TqGARdI/T44KXy+Ets3r6x/ivhQozT66bMnCEjJRywYoxNurRTMlZF8VNg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.3.tgz", + "integrity": "sha512-39V/Riv2R3O/aUjYKh0xypj7NTNXNAK1bcgY5Kx+hdQPRS/aPTS8/5c0CGFYKgVuFbYlnlnhrCTYsh2uNhGwzA==", "dependencies": { - "@firebase/app-types": "0.9.0", - "@firebase/util": "1.9.3" + "@firebase/app-types": "0.9.2", + "@firebase/util": "1.9.6" } }, "node_modules/@firebase/firestore": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.4.0.tgz", - "integrity": "sha512-VeDXD9PUjvcWY1tInBOMTIu2pijR3YYy+QAe5cxCo1Q1vW+aA/mpQHhebPM1J6b4Zd1MuUh8xpBRvH9ujKR56A==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.6.2.tgz", + "integrity": "sha512-sxHtvmfH/1689aPQRxOXBWDumaPqg5AjQVkfwpt+Z3rnaa0aLJlrt2PZs9Xh04qbmWiwtkDgztFmoR/aQdMQJQ==", "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", - "@firebase/webchannel-wrapper": "0.10.5", + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", + "@firebase/webchannel-wrapper": "1.0.0", "@grpc/grpc-js": "~1.9.0", "@grpc/proto-loader": "^0.7.8", "tslib": "^2.1.0", - "undici": "5.26.5" + "undici": "5.28.4" }, "engines": { "node": ">=10.10.0" @@ -3800,14 +3800,14 @@ } }, "node_modules/@firebase/firestore-compat": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.23.tgz", - "integrity": "sha512-uUTBiP0GLVBETaOCfB11d33OWB8x1r2G1Xrl0sRK3Va0N5LJ/GRvKVSGfM7VScj+ypeHe8RpdwKoCqLpN1e+uA==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/firestore": "4.4.0", - "@firebase/firestore-types": "3.0.0", - "@firebase/util": "1.9.3", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.31.tgz", + "integrity": "sha512-YbR9GGLfYY9A5Qh2SyyNz7EsNeC5SRjzgRxtMtqz2s2es+p+5sDfFUUNKqpgVaIcnoPGOtvCLhNNWG/TBmlQjw==", + "dependencies": { + "@firebase/component": "0.6.7", + "@firebase/firestore": "4.6.2", + "@firebase/firestore-types": "3.0.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3815,18 +3815,18 @@ } }, "node_modules/@firebase/firestore-types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.0.tgz", - "integrity": "sha512-Meg4cIezHo9zLamw0ymFYBD4SMjLb+ZXIbuN7T7ddXN6MGoICmOTq3/ltdCGoDCS2u+H1XJs2u/cYp75jsX9Qw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.2.tgz", + "integrity": "sha512-wp1A+t5rI2Qc/2q7r2ZpjUXkRVPtGMd6zCLsiWurjsQpqPgFin3AhNibKcIzoF2rnToNa/XYtyWXuifjOOwDgg==", "peerDependencies": { "@firebase/app-types": "0.x", "@firebase/util": "1.x" } }, "node_modules/@firebase/firestore/node_modules/undici": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz", - "integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -3835,31 +3835,31 @@ } }, "node_modules/@firebase/functions": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.0.tgz", - "integrity": "sha512-n1PZxKnJ++k73Q8khTPwihlbeKo6emnGzE0hX6QVQJsMq82y/XKmNpw2t/q30VJgwaia3ZXU1fd1C5wHncL+Zg==", - "dependencies": { - "@firebase/app-check-interop-types": "0.3.0", - "@firebase/auth-interop-types": "0.2.1", - "@firebase/component": "0.6.4", - "@firebase/messaging-interop-types": "0.2.0", - "@firebase/util": "1.9.3", + "version": "0.11.5", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.5.tgz", + "integrity": "sha512-qrHJ+l62mZiU5UZiVi84t/iLXZlhRuSvBQsa2qvNLgPsEWR7wdpWhRmVdB7AU8ndkSHJjGlMICqrVnz47sgU7Q==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.2", + "@firebase/auth-interop-types": "0.2.3", + "@firebase/component": "0.6.7", + "@firebase/messaging-interop-types": "0.2.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0", - "undici": "5.26.5" + "undici": "5.28.4" }, "peerDependencies": { "@firebase/app": "0.x" } }, "node_modules/@firebase/functions-compat": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.6.tgz", - "integrity": "sha512-RQpO3yuHtnkqLqExuAT2d0u3zh8SDbeBYK5EwSCBKI9mjrFeJRXBnd3pEG+x5SxGJLy56/5pQf73mwt0OuH5yg==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.11.tgz", + "integrity": "sha512-Qn+ts/M6Lj2/6i1cp5V5TRR+Hi9kyXyHbo+w9GguINJ87zxrCe6ulx3TI5AGQkoQa8YFHUhT3DMGmLFiJjWTSQ==", "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/functions": "0.11.0", - "@firebase/functions-types": "0.6.0", - "@firebase/util": "1.9.3", + "@firebase/component": "0.6.7", + "@firebase/functions": "0.11.5", + "@firebase/functions-types": "0.6.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3867,14 +3867,14 @@ } }, "node_modules/@firebase/functions-types": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.0.tgz", - "integrity": "sha512-hfEw5VJtgWXIRf92ImLkgENqpL6IWpYaXVYiRkFY1jJ9+6tIhWM7IzzwbevwIIud/jaxKVdRzD7QBWfPmkwCYw==" + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.2.tgz", + "integrity": "sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w==" }, "node_modules/@firebase/functions/node_modules/undici": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz", - "integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -3883,13 +3883,13 @@ } }, "node_modules/@firebase/installations": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.4.tgz", - "integrity": "sha512-u5y88rtsp7NYkCHC3ElbFBrPtieUybZluXyzl7+4BsIz4sqb4vSAuwHEUgCgCeaQhvsnxDEU6icly8U9zsJigA==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.7.tgz", + "integrity": "sha512-i6iGoXRu5mX4rTsiMSSKrgh9pSEzD4hwBEzRh5kEhOTr8xN/wvQcCPZDSMVYKwM2XyCPBLVq0JzjyerwL0Rihg==", "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/util": "1.9.3", - "idb": "7.0.1", + "@firebase/component": "0.6.7", + "@firebase/util": "1.9.6", + "idb": "7.1.1", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3897,14 +3897,14 @@ } }, "node_modules/@firebase/installations-compat": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.4.tgz", - "integrity": "sha512-LI9dYjp0aT9Njkn9U4JRrDqQ6KXeAmFbRC0E7jI7+hxl5YmRWysq5qgQl22hcWpTk+cm3es66d/apoDU/A9n6Q==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/installations": "0.6.4", - "@firebase/installations-types": "0.5.0", - "@firebase/util": "1.9.3", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.7.tgz", + "integrity": "sha512-RPcbD+3nqHbnhVjIOpWK2H5qzZ8pAAAScceiWph0VNTqpKyPQ5tDcp4V5fS0ELpfgsHYvroMLDKfeHxpfvm8cw==", + "dependencies": { + "@firebase/component": "0.6.7", + "@firebase/installations": "0.6.7", + "@firebase/installations-types": "0.5.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3912,35 +3912,30 @@ } }, "node_modules/@firebase/installations-types": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.0.tgz", - "integrity": "sha512-9DP+RGfzoI2jH7gY4SlzqvZ+hr7gYzPODrbzVD82Y12kScZ6ZpRg/i3j6rleto8vTFC8n6Len4560FnV1w2IRg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.2.tgz", + "integrity": "sha512-que84TqGRZJpJKHBlF2pkvc1YcXrtEDOVGiDjovP/a3s6W4nlbohGXEsBJo0JCeeg/UG9A+DEZVDUV9GpklUzA==", "peerDependencies": { "@firebase/app-types": "0.x" } }, - "node_modules/@firebase/installations/node_modules/idb": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", - "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==" - }, "node_modules/@firebase/logger": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", - "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.2.tgz", + "integrity": "sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@firebase/messaging": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.5.tgz", - "integrity": "sha512-i/rrEI2k9ueFhdIr8KQsptWGskrsnkC5TkohCTrJKz9P0C/PbNv14IAMkwhMJTqIur5VwuOnrUkc9Kdz7awekw==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/installations": "0.6.4", - "@firebase/messaging-interop-types": "0.2.0", - "@firebase/util": "1.9.3", + "version": "0.12.9", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.9.tgz", + "integrity": "sha512-IH+JJmzbFGZXV3+TDyKdqqKPVfKRqBBg2BfYYOy7cm7J+SwV+uJMe8EnDKYeQLEQhtpwciPfJ3qQXJs2lbxDTw==", + "dependencies": { + "@firebase/component": "0.6.7", + "@firebase/installations": "0.6.7", + "@firebase/messaging-interop-types": "0.2.2", + "@firebase/util": "1.9.6", "idb": "7.1.1", "tslib": "^2.1.0" }, @@ -3949,13 +3944,13 @@ } }, "node_modules/@firebase/messaging-compat": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.5.tgz", - "integrity": "sha512-qHQZxm4hEG8/HFU/ls5/bU+rpnlPDoZoqi3ATMeb6s4hovYV9+PfV5I7ZrKV5eFFv47Hx1PWLe5uPnS4e7gMwQ==", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.9.tgz", + "integrity": "sha512-5jN6wyhwPgBH02zOtmmoOeyfsmoD7ty48D1m0vVPsFg55RqN2Z3Q9gkZ5GmPklFPjTPLcxB1ObcHOZvThTkm7g==", "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/messaging": "0.12.5", - "@firebase/util": "1.9.3", + "@firebase/component": "0.6.7", + "@firebase/messaging": "0.12.9", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3963,19 +3958,19 @@ } }, "node_modules/@firebase/messaging-interop-types": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.0.tgz", - "integrity": "sha512-ujA8dcRuVeBixGR9CtegfpU4YmZf3Lt7QYkcj693FFannwNuZgfAYaTmbJ40dtjB81SAu6tbFPL9YLNT15KmOQ==" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2.tgz", + "integrity": "sha512-l68HXbuD2PPzDUOFb3aG+nZj5KA3INcPwlocwLZOzPp9rFM9yeuI9YLl6DQfguTX5eAGxO0doTR+rDLDvQb5tA==" }, "node_modules/@firebase/performance": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.4.tgz", - "integrity": "sha512-HfTn/bd8mfy/61vEqaBelNiNnvAbUtME2S25A67Nb34zVuCSCRIX4SseXY6zBnOFj3oLisaEqhVcJmVPAej67g==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/installations": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.7.tgz", + "integrity": "sha512-d+Q4ltjdJZqjzcdms5i0UC9KLYX7vKGcygZ+7zHA/Xk+bAbMD2CPU0nWTnlNFWifZWIcXZ/2mAMvaGMW3lypUA==", + "dependencies": { + "@firebase/component": "0.6.7", + "@firebase/installations": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3983,15 +3978,15 @@ } }, "node_modules/@firebase/performance-compat": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.4.tgz", - "integrity": "sha512-nnHUb8uP9G8islzcld/k6Bg5RhX62VpbAb/Anj7IXs/hp32Eb2LqFPZK4sy3pKkBUO5wcrlRWQa6wKOxqlUqsg==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/performance": "0.6.4", - "@firebase/performance-types": "0.2.0", - "@firebase/util": "1.9.3", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.7.tgz", + "integrity": "sha512-cb8ge/5iTstxfIGW+iiY+7l3FtN8gobNh9JSQNZgLC9xmcfBYWEs8IeEWMI6S8T+At0oHc3lv+b2kpRMUWr8zQ==", + "dependencies": { + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/performance": "0.6.7", + "@firebase/performance-types": "0.2.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -3999,19 +3994,19 @@ } }, "node_modules/@firebase/performance-types": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.0.tgz", - "integrity": "sha512-kYrbr8e/CYr1KLrLYZZt2noNnf+pRwDq2KK9Au9jHrBMnb0/C9X9yWSXmZkFt4UIdsQknBq8uBB7fsybZdOBTA==" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.2.tgz", + "integrity": "sha512-gVq0/lAClVH5STrIdKnHnCo2UcPLjJlDUoEB/tB4KM+hAeHUxWKnpT0nemUPvxZ5nbdY/pybeyMe8Cs29gEcHA==" }, "node_modules/@firebase/remote-config": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.4.tgz", - "integrity": "sha512-x1ioTHGX8ZwDSTOVp8PBLv2/wfwKzb4pxi0gFezS5GCJwbLlloUH4YYZHHS83IPxnua8b6l0IXUaWd0RgbWwzQ==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/installations": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.7.tgz", + "integrity": "sha512-5oPNrPFLsbsjpq0lUEIXoDF2eJK7vAbyXe/DEuZQxnwJlfR7aQbtUlEkRgQWcicXpyDmAmDLo7q7lDbCYa6CpA==", + "dependencies": { + "@firebase/component": "0.6.7", + "@firebase/installations": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -4019,15 +4014,15 @@ } }, "node_modules/@firebase/remote-config-compat": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.4.tgz", - "integrity": "sha512-FKiki53jZirrDFkBHglB3C07j5wBpitAaj8kLME6g8Mx+aq7u9P7qfmuSRytiOItADhWUj7O1JIv7n9q87SuwA==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/remote-config": "0.4.4", - "@firebase/remote-config-types": "0.3.0", - "@firebase/util": "1.9.3", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.7.tgz", + "integrity": "sha512-Fq0oneQ4SluLnfr5/HfzRS1TZf1ANj1rWbCCW3+oC98An3nE+sCdp+FSuHsEVNwgMg4Tkwx9Oom2lkKeU+Vn+w==", + "dependencies": { + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/remote-config": "0.4.7", + "@firebase/remote-config-types": "0.3.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -4035,33 +4030,33 @@ } }, "node_modules/@firebase/remote-config-types": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.0.tgz", - "integrity": "sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA==" + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.2.tgz", + "integrity": "sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA==" }, "node_modules/@firebase/storage": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.0.tgz", - "integrity": "sha512-SGs02Y/mmWBRsqZiYLpv4Sf7uZYZzMWVNN+aKiDqPsFBCzD6hLvGkXz+u98KAl8FqcjgB8BtSu01wm4pm76KHA==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.5.tgz", + "integrity": "sha512-nGWBOGFNr10j0LA4NJ3/Yh3us/lb0Q1xSIKZ38N6FcS+vY54nqJ7k3zE3PENregHC8+8txRow++A568G3v8hOA==", "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/util": "1.9.3", + "@firebase/component": "0.6.7", + "@firebase/util": "1.9.6", "tslib": "^2.1.0", - "undici": "5.26.5" + "undici": "5.28.4" }, "peerDependencies": { "@firebase/app": "0.x" } }, "node_modules/@firebase/storage-compat": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.3.tgz", - "integrity": "sha512-WNtjYPhpOA1nKcRu5lIodX0wZtP8pI0VxDJnk6lr+av7QZNS1s6zvr+ERDTve+Qu4Hq/ZnNaf3kBEQR2ccXn6A==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.8.tgz", + "integrity": "sha512-qDfY9kMb6Ch2hZb40sBjDQ8YPxbjGOxuT+gU1Z0iIVSSpSX0f4YpGJCypUXiA0T11n6InCXB+T/Dknh2yxVTkg==", "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/storage": "0.12.0", - "@firebase/storage-types": "0.8.0", - "@firebase/util": "1.9.3", + "@firebase/component": "0.6.7", + "@firebase/storage": "0.12.5", + "@firebase/storage-types": "0.8.2", + "@firebase/util": "1.9.6", "tslib": "^2.1.0" }, "peerDependencies": { @@ -4069,18 +4064,18 @@ } }, "node_modules/@firebase/storage-types": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.0.tgz", - "integrity": "sha512-isRHcGrTs9kITJC0AVehHfpraWFui39MPaU7Eo8QfWlqW7YPymBmRgjDrlOgFdURh6Cdeg07zmkLP5tzTKRSpg==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.2.tgz", + "integrity": "sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g==", "peerDependencies": { "@firebase/app-types": "0.x", "@firebase/util": "1.x" } }, "node_modules/@firebase/storage/node_modules/undici": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz", - "integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -4089,17 +4084,36 @@ } }, "node_modules/@firebase/util": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", - "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "version": "1.9.6", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.6.tgz", + "integrity": "sha512-IBr1MZbp4d5MjBCXL3TW1dK/PDXX4yOGbiwRNh1oAbE/+ci5Uuvy9KIrsFYY80as1I0iOaD5oOMA9Q8j4TJWcw==", "dependencies": { "tslib": "^2.1.0" } }, + "node_modules/@firebase/vertexai-preview": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@firebase/vertexai-preview/-/vertexai-preview-0.0.1.tgz", + "integrity": "sha512-N8m9Xr0YZKy0t9SpQDuHrL2ppEAT/iqf88Y/O00QNA/Td/BMCL8sJ0c+Savh1TVrqh0rNp9n6HkZ39e/O5mwhA==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.2", + "@firebase/component": "0.6.7", + "@firebase/logger": "0.4.2", + "@firebase/util": "1.9.6", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@firebase/app-types": "0.x" + } + }, "node_modules/@firebase/webchannel-wrapper": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.5.tgz", - "integrity": "sha512-eSkJsnhBWv5kCTSU1tSUVl9mpFu+5NXXunZc83le8GMjMlsWwQArSc7cJJ4yl+aDFY0NGLi0AjZWMn1axOrkRg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.0.tgz", + "integrity": "sha512-zuWxyfXNbsKbm96HhXzainONPFqRcoZblQ++e9cAIGUuHfl2cFSBzW01jtesqWG/lqaUyX3H8O1y9oWboGNQBA==" }, "node_modules/@gar/promisify": { "version": "1.1.3", @@ -4515,9 +4529,9 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.9.12", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.12.tgz", - "integrity": "sha512-Um5MBuge32TS3lAKX02PGCnFM4xPT996yLgZNb5H03pn6NyJ4Iwn5YcPq6Jj9yxGRk7WOgaZFtVRH5iTdYBeUg==", + "version": "1.9.14", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz", + "integrity": "sha512-nOpuzZ2G3IuMFN+UPPpKrC6NsLmWsTqSsm66IRfnBt1D4pwTqE27lmbpcPM+l2Ua4gE7PfjRHI6uedAy7hoXUw==", "dependencies": { "@grpc/proto-loader": "^0.7.8", "@types/node": ">=12.12.47" @@ -4527,9 +4541,9 @@ } }, "node_modules/@grpc/grpc-js/node_modules/@types/node": { - "version": "20.10.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.3.tgz", - "integrity": "sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "dependencies": { "undici-types": "~5.26.4" } @@ -11421,36 +11435,37 @@ } }, "node_modules/firebase": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.7.1.tgz", - "integrity": "sha512-Mlt7y7zQ43FtKp4SCyYie3tnrOL3UMF2XXiV4ZXMrC0d0wtcOYmABuybhkJpJCKILpdekxr39wjnaai0DZlWFg==", - "dependencies": { - "@firebase/analytics": "0.10.0", - "@firebase/analytics-compat": "0.2.6", - "@firebase/app": "0.9.25", - "@firebase/app-check": "0.8.1", - "@firebase/app-check-compat": "0.3.8", - "@firebase/app-compat": "0.2.25", - "@firebase/app-types": "0.9.0", - "@firebase/auth": "1.5.1", - "@firebase/auth-compat": "0.5.1", - "@firebase/database": "1.0.2", - "@firebase/database-compat": "1.0.2", - "@firebase/firestore": "4.4.0", - "@firebase/firestore-compat": "0.3.23", - "@firebase/functions": "0.11.0", - "@firebase/functions-compat": "0.3.6", - "@firebase/installations": "0.6.4", - "@firebase/installations-compat": "0.2.4", - "@firebase/messaging": "0.12.5", - "@firebase/messaging-compat": "0.2.5", - "@firebase/performance": "0.6.4", - "@firebase/performance-compat": "0.2.4", - "@firebase/remote-config": "0.4.4", - "@firebase/remote-config-compat": "0.2.4", - "@firebase/storage": "0.12.0", - "@firebase/storage-compat": "0.3.3", - "@firebase/util": "1.9.3" + "version": "10.12.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.12.0.tgz", + "integrity": "sha512-31UZyAK0+VZmF9jR/+6g31uyqWjBKsG+TV3ndRJEkw6+Skctb5ZX0+Ezq/pbC68iIRJ5TujOjyl632vTOqyS1w==", + "dependencies": { + "@firebase/analytics": "0.10.3", + "@firebase/analytics-compat": "0.2.9", + "@firebase/app": "0.10.3", + "@firebase/app-check": "0.8.4", + "@firebase/app-check-compat": "0.3.11", + "@firebase/app-compat": "0.2.33", + "@firebase/app-types": "0.9.2", + "@firebase/auth": "1.7.3", + "@firebase/auth-compat": "0.5.8", + "@firebase/database": "1.0.5", + "@firebase/database-compat": "1.0.5", + "@firebase/firestore": "4.6.2", + "@firebase/firestore-compat": "0.3.31", + "@firebase/functions": "0.11.5", + "@firebase/functions-compat": "0.3.11", + "@firebase/installations": "0.6.7", + "@firebase/installations-compat": "0.2.7", + "@firebase/messaging": "0.12.9", + "@firebase/messaging-compat": "0.2.9", + "@firebase/performance": "0.6.7", + "@firebase/performance-compat": "0.2.7", + "@firebase/remote-config": "0.4.7", + "@firebase/remote-config-compat": "0.2.7", + "@firebase/storage": "0.12.5", + "@firebase/storage-compat": "0.3.8", + "@firebase/util": "1.9.6", + "@firebase/vertexai-preview": "0.0.1" } }, "node_modules/firebase-admin": { diff --git a/package.json b/package.json index 471cfb2b3..c7690dd7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/fire", - "version": "17.0.0", + "version": "17.1.0", "description": "Angular + Firebase = ❤️", "private": true, "scripts": { @@ -55,7 +55,7 @@ "@angular/platform-browser-dynamic": "^17.0.0", "@angular/router": "^17.0.0", "@schematics/angular": "^17.0.0", - "firebase": "^10.7.0", + "firebase": "^10.12.0", "firebase-admin": "^9.11.1", "firebase-functions": "^3.6.0", "firebase-tools": "^13.0.0", diff --git a/src/app/firebase.ts b/src/app/firebase.ts index b7cb140af..7d9487193 100644 --- a/src/app/firebase.ts +++ b/src/app/firebase.ts @@ -6,6 +6,7 @@ import { getApp as _getApp, getApps as _getApps, initializeApp as _initializeApp, + initializeServerApp as _initializeServerApp, onLog as _onLog, registerVersion as _registerVersion, setLogLevel as _setLogLevel @@ -15,6 +16,7 @@ export const deleteApp = ɵzoneWrap(_deleteApp, true); export const getApp = ɵzoneWrap(_getApp, true); export const getApps = ɵzoneWrap(_getApps, true); export const initializeApp = ɵzoneWrap(_initializeApp, true); +export const initializeServerApp = ɵzoneWrap(_initializeServerApp, true); export const onLog = ɵzoneWrap(_onLog, true); export const registerVersion = ɵzoneWrap(_registerVersion, true); export const setLogLevel = ɵzoneWrap(_setLogLevel, true); diff --git a/src/package.json b/src/package.json index dcff7dc6b..b0cfefbc0 100644 --- a/src/package.json +++ b/src/package.json @@ -34,7 +34,7 @@ "firebase-tools": { "optional": true } }, "dependencies": { - "firebase": "^10.7.0", + "firebase": "^10.12.0", "rxfire": "^6.0.5", "@angular-devkit/schematics": "^17.0.0", "@schematics/angular": "^17.0.0", diff --git a/src/schematics/common.ts b/src/schematics/common.ts index 061603b69..814f59562 100644 --- a/src/schematics/common.ts +++ b/src/schematics/common.ts @@ -1,6 +1,6 @@ import { SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics'; import * as semver from 'semver'; -import { FirebaseHostingSite, FirebaseRc } from './interfaces'; +import { FirebaseHostingSite } from './interfaces'; export const shortSiteName = (site?: FirebaseHostingSite) => site?.name?.split('/').pop(); @@ -18,44 +18,6 @@ export const overwriteIfExists = ( } }; -function emptyFirebaseRc() { - return { - targets: {} - }; -} - -function generateFirebaseRcTarget(firebaseProject: string, firebaseHostingSite: FirebaseHostingSite|undefined, project: string) { - return { - hosting: { - [project]: [ - shortSiteName(firebaseHostingSite) ?? firebaseProject - ] - } - }; -} - -export function generateFirebaseRc( - tree: Tree, - path: string, - firebaseProject: string, - firebaseHostingSite: FirebaseHostingSite|undefined, - project: string -) { - const firebaseRc: FirebaseRc = tree.exists(path) - ? safeReadJSON(path, tree) - : emptyFirebaseRc(); - - firebaseRc.targets = firebaseRc.targets || {}; - firebaseRc.targets[firebaseProject] = generateFirebaseRcTarget( - firebaseProject, - firebaseHostingSite, - project - ); - firebaseRc.projects = { default: firebaseProject }; - - overwriteIfExists(tree, path, stringifyFormatted(firebaseRc)); -} - export function safeReadJSON(path: string, tree: Tree) { try { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion diff --git a/src/schematics/deploy/actions.ts b/src/schematics/deploy/actions.ts index 6ee2d6038..c57ec293d 100644 --- a/src/schematics/deploy/actions.ts +++ b/src/schematics/deploy/actions.ts @@ -390,6 +390,8 @@ export default async function deploy( options: DeployBuilderOptions, firebaseToken?: string, ) { + const legacyNgDeploy = !options.version || options.version < 2; + if (!firebaseToken && !process.env.GOOGLE_APPLICATION_CREDENTIALS) { await firebaseTools.login(); const user = await firebaseTools.login({ projectRoot: context.workspaceRoot }); @@ -401,6 +403,12 @@ export default async function deploy( console.log(`Using Google Application Credentials.`); } + if (legacyNgDeploy) { + console.error(`Legacy ng-deploy Firebase is deprecated. +Please migrate to Firebase Hosting's integration with Angular https://firebase.google.com/docs/hosting/frameworks/angular +or the new Firebase App Hosting product https://firebase.google.com/docs/app-hosting`); + } + if (prerenderBuildTarget) { const run = await context.scheduleTarget( targetFromTargetString(prerenderBuildTarget.name), @@ -465,7 +473,7 @@ export default async function deploy( firebaseTools.logger.logger.add(logger); - if ((!options.version || options.version < 2) && serverBuildTarget) { + if (legacyNgDeploy && serverBuildTarget) { if (options.ssr === 'cloud-run') { await deployToCloudRun( firebaseTools, diff --git a/src/schematics/interfaces.ts b/src/schematics/interfaces.ts index aceae61a9..aaddfe5a7 100644 --- a/src/schematics/interfaces.ts +++ b/src/schematics/interfaces.ts @@ -1,7 +1,6 @@ import { RuntimeOptions } from 'firebase-functions'; export const enum FEATURES { - Hosting, Authentication, Analytics, AppCheck, @@ -12,10 +11,10 @@ export const enum FEATURES { Firestore, Storage, RemoteConfig, + VertexAI, } export const featureOptions = [ - { name: 'ng deploy -- hosting', value: FEATURES.Hosting }, { name: 'Authentication', value: FEATURES.Authentication }, { name: 'Google Analytics', value: FEATURES.Analytics }, { name: 'App Check', value: FEATURES.AppCheck }, @@ -26,6 +25,7 @@ export const featureOptions = [ { name: 'Performance Monitoring', value: FEATURES.Performance }, { name: 'Cloud Storage', value: FEATURES.Storage }, { name: 'Remote Config', value: FEATURES.RemoteConfig }, + { name: 'VertexAI (preview)', value: FEATURES.VertexAI }, ]; export const enum PROJECT_TYPE { Static, CloudFunctions, CloudRun, WebFrameworks } diff --git a/src/schematics/ng-add.jasmine.ts b/src/schematics/ng-add.jasmine.ts deleted file mode 100644 index 2b82f72fc..000000000 --- a/src/schematics/ng-add.jasmine.ts +++ /dev/null @@ -1,563 +0,0 @@ -import { SchematicsException, Tree } from '@angular-devkit/schematics'; -import { FEATURES } from './interfaces'; -import { setupProject } from './setup'; -import 'jasmine'; - -const PROJECT_NAME = 'pie-ka-chu'; -const PROJECT_ROOT = 'pirojok'; -const FIREBASE_PROJECT = 'pirojok-111e3'; -const OTHER_PROJECT_NAME = 'pi-catch-you'; -const OTHER_FIREBASE_PROJECT_NAME = 'bi-catch-you-77e7e'; - -function generateAngularJson() { - return { - defaultProject: PROJECT_NAME, - projects: { - [PROJECT_NAME]: { - projectType: 'application', - root: PROJECT_ROOT, - architect: { - build: { - options: { - outputPath: 'dist/ikachu' - } - } - } - }, - [OTHER_PROJECT_NAME]: { - projectType: 'application', - root: PROJECT_ROOT, - architect: { - build: { - options: { - outputPath: 'dist/ikachu' - } - } - } - } - } - }; -} - -function generatePackageJson() { - return { - name: 'foo', - private: true, - }; -} - -function generateAngularJsonWithServer() { - return { - defaultProject: PROJECT_NAME, - projects: { - [PROJECT_NAME]: { - projectType: 'application', - root: PROJECT_ROOT, - architect: { - build: { - options: { - outputPath: 'dist/ikachu' - } - }, - server: { - options: { - outputPath: 'dist/server' - } - } - } - }, - [OTHER_PROJECT_NAME]: { - projectType: 'application', - root: PROJECT_ROOT, - architect: { - build: { - options: { - outputPath: 'dist/ikachu' - } - }, - server: { - options: { - outputPath: 'dist/server' - } - } - } - } - } - }; -} - -const initialFirebaseJson = `{ - "hosting": [ - { - "target": "pie-ka-chu", - "source": ".", - "frameworksBackend": {} - } - ] -}`; - -const initialFirebaserc = `{ - "targets": { - "pirojok-111e3": { - "hosting": { - "pie-ka-chu": [ - "pirojok-111e3" - ] - } - } - }, - "projects": { - "default": "pirojok-111e3" - } -}`; - -const initialAngularJson = `{ - "defaultProject": "pie-ka-chu", - "projects": { - "pie-ka-chu": { - "projectType": "application", - "root": "pirojok", - "architect": { - "build": { - "options": { - "outputPath": "dist/ikachu" - } - }, - "deploy": { - "builder": "@angular/fire:deploy", - "options": { - "version": 2 - }, - "configurations": { - "production": {}, - "development": {} - }, - "defaultConfiguration": "production" - } - } - }, - "pi-catch-you": { - "projectType": "application", - "root": "pirojok", - "architect": { - "build": { - "options": { - "outputPath": "dist/ikachu" - } - } - } - } - } -}`; - -const overwriteFirebaseJson = `{ - "hosting": [ - { - "target": "pie-ka-chu", - "source": ".", - "frameworksBackend": {} - } - ] -}`; - -const overwriteFirebaserc = `{ - "targets": { - "pirojok-111e3": { - "hosting": { - "pie-ka-chu": [ - "pirojok-111e3" - ] - } - } - }, - "projects": { - "default": "pirojok-111e3" - } -}`; - -const overwriteAngularJson = `{ - "defaultProject": "pie-ka-chu", - "projects": { - "pie-ka-chu": { - "projectType": "application", - "root": "pirojok", - "architect": { - "build": { - "options": { - "outputPath": "dist/ikachu" - } - }, - "deploy": { - "builder": "@angular/fire:deploy", - "options": { - "version": 2 - }, - "configurations": { - "production": {}, - "development": {} - }, - "defaultConfiguration": "production" - } - } - }, - "pi-catch-you": { - "projectType": "application", - "root": "pirojok", - "architect": { - "build": { - "options": { - "outputPath": "dist/ikachu" - } - } - } - } - } -}`; - -const projectFirebaseJson = `{ - "hosting": [ - { - "target": "pie-ka-chu", - "source": ".", - "frameworksBackend": {} - }, - { - "target": "pi-catch-you", - "source": ".", - "frameworksBackend": {} - } - ] -}`; - -const projectFirebaserc = `{ - "targets": { - "pirojok-111e3": { - "hosting": { - "pie-ka-chu": [ - "pirojok-111e3" - ] - } - }, - "bi-catch-you-77e7e": { - "hosting": { - "pi-catch-you": [ - "bi-catch-you-77e7e" - ] - } - } - }, - "projects": { - "default": "bi-catch-you-77e7e" - } -}`; - -const projectAngularJson = `{ - "defaultProject": "pie-ka-chu", - "projects": { - "pie-ka-chu": { - "projectType": "application", - "root": "pirojok", - "architect": { - "build": { - "options": { - "outputPath": "dist/ikachu" - } - }, - "deploy": { - "builder": "@angular/fire:deploy", - "options": { - "version": 2 - }, - "configurations": { - "production": {}, - "development": {} - }, - "defaultConfiguration": "production" - } - } - }, - "pi-catch-you": { - "projectType": "application", - "root": "pirojok", - "architect": { - "build": { - "options": { - "outputPath": "dist/ikachu" - } - }, - "deploy": { - "builder": "@angular/fire:deploy", - "options": { - "version": 2 - }, - "configurations": { - "production": {}, - "development": {} - }, - "defaultConfiguration": "production" - } - } - } - } -}`; - -const universalFirebaseJson = { - hosting: [{ - target: 'pie-ka-chu', - source: '.', - frameworksBackend: {}, - }], -}; - -describe('ng-add', () => { - describe('generating files', () => { - let tree: Tree; - - beforeEach(() => { - tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - tree.create('package.json', JSON.stringify(generatePackageJson())); - }); - - it('generates new files if starting from scratch', () => { - setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - }); - expect(tree.read('firebase.json')?.toString()).toEqual(initialFirebaseJson); - expect(tree.read('.firebaserc')?.toString()).toEqual(initialFirebaserc); - expect(tree.read('angular.json')?.toString()).toEqual(initialAngularJson); - }); - - it('uses default project', () => { - setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: undefined, - }); - expect(tree.read('firebase.json')?.toString()).toEqual(overwriteFirebaseJson); - expect(tree.read('.firebaserc')?.toString()).toEqual(overwriteFirebaserc); - expect(tree.read('angular.json')?.toString()).toEqual(overwriteAngularJson); - }); - - it('runs if source root is relative to workspace root', () => { - const angularJson = generateAngularJson(); - const project: {root: string, sourceRoot?: string} = angularJson.projects[PROJECT_NAME]; - project.sourceRoot = `${project.root}/src`; - tree.overwrite('angular.json', JSON.stringify(angularJson)); - setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: undefined, - }); - }); - - it('overrides existing files', () => { - setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - }); - setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: OTHER_FIREBASE_PROJECT_NAME } as any, - project: OTHER_PROJECT_NAME, - }); - expect(tree.read('firebase.json')?.toString()).toEqual(projectFirebaseJson); - expect(tree.read('.firebaserc')?.toString()).toEqual(projectFirebaserc); - expect(tree.read('angular.json')?.toString()).toEqual(projectAngularJson); - }); - }); - - describe('error handling', () => { - it('fails if project not defined', () => { - const tree = Tree.empty(); - const angularJSON = generateAngularJson(); - delete angularJSON.defaultProject; - tree.create('angular.json', JSON.stringify(angularJSON)); - tree.create('package.json', JSON.stringify(generatePackageJson())); - expect(() => setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: undefined, - })).toThrow( - new SchematicsException('No Angular project selected and no default project in the workspace') - ); - }); - - it('Should throw if angular.json not found', () => { - expect(() => setupProject(Tree.empty(), {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - })).toThrow(new SchematicsException('Could not find angular.json')); - }); - - it('Should throw if angular.json can not be parsed', () => { - const tree = Tree.empty(); - tree.create('angular.json', 'hi'); - tree.create('package.json', JSON.stringify(generatePackageJson())); - expect(() => setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - })).toThrow(new SchematicsException('Could not parse angular.json')); - }); - - it('Should throw if specified project does not exist ', () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify({ projects: {} })); - tree.create('package.json', JSON.stringify(generatePackageJson())); - expect(() => setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - })).toThrow(new SchematicsException('The specified Angular project is not defined in this workspace')); - }); - - it('Should throw if specified project is not application', () => { - const tree = Tree.empty(); - tree.create( - 'angular.json', - JSON.stringify({ - projects: { [PROJECT_NAME]: { projectType: 'pokemon' } } - }) - ); - tree.create('package.json', JSON.stringify(generatePackageJson())); - expect(() => setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - })).toThrow(new SchematicsException('Deploy requires an Angular project type of "application" in angular.json')); - }); - - it('Should throw if app does not have architect configured', () => { - const tree = Tree.empty(); - tree.create( - 'angular.json', - JSON.stringify({ - projects: { [PROJECT_NAME]: { projectType: 'application' } } - }) - ); - tree.create('package.json', JSON.stringify(generatePackageJson())); - expect(() => setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - })).toThrow( - new SchematicsException('Angular project "pie-ka-chu" has a malformed angular.json') - ); - }); - - /* TODO do something other than throw - it('Should throw if firebase.json has the project already', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - const tempTree = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - universalProject: false, - project: PROJECT_NAME - }); - - expect(() => - setupProject(tempTree, { - firebaseProject: FIREBASE_PROJECT, - universalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/already exists in firebase.json/); - }); - - it('Should throw if firebase.json is broken', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - tree.create('firebase.json', `I'm broken 😔`); - expect(() => - setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - universalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/firebase.json: Unexpected token/); - });*/ - - it('Should throw if .firebaserc is broken', () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - tree.create('package.json', JSON.stringify(generatePackageJson())); - tree.create('.firebaserc', `I'm broken 😔`); - expect(() => setupProject(tree, {} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - })).toThrow( - parseInt(process.versions.node, 10) >= 20 ? - new SchematicsException(`Error when parsing .firebaserc: Unexpected token 'I', "I'm broken 😔" is not valid JSON`) : - new SchematicsException('Error when parsing .firebaserc: Unexpected token I in JSON at position 0') - ); - }); - - /* TODO do something else - - it('Should throw if firebase.json has the project already', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - const tempTree = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - universalProject: false, - project: PROJECT_NAME - }); - - expect(() => - setupProject(tempTree, { - firebaseProject: FIREBASE_PROJECT, - universalProject: false, - project: OTHER_PROJECT_NAME - }) - ).toThrowError(/ already defined in .firebaserc/); - }); - - it('Should throw if firebase.json is broken', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - - const tempTree = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - universalProject: false, - project: PROJECT_NAME - }); - - expect(() => - setupProject(tempTree, { - firebaseProject: FIREBASE_PROJECT, - universalProject: false, - project: OTHER_PROJECT_NAME - }) - ).toThrowError(/ already defined in .firebaserc/); - }); */ - - describe('universal app', () => { - - it('should add a @angular/fire builder', () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJsonWithServer())); - tree.create('package.json', JSON.stringify(generatePackageJson())); - - // TODO mock addTask - setupProject(tree, {addTask: () => undefined} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - }); - - const angularJSON = tree.read('angular.json')?.toString(); - const workspace = angularJSON && JSON.parse(angularJSON); - expect(workspace?.projects['pie-ka-chu']?.architect?.deploy).toBeTruthy(); - }); - - it('should configure firebase.json', () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJsonWithServer())); - tree.create('package.json', JSON.stringify(generatePackageJson())); - - // TODO mock addTask - setupProject(tree, {addTask: () => undefined} as any, [FEATURES.Hosting], { - firebaseProject: { projectId: FIREBASE_PROJECT } as any, - project: PROJECT_NAME, - }); - - const firebaseJsonData= tree.read('firebase.json')?.toString(); - const firebaseJson = firebaseJsonData && JSON.parse(firebaseJsonData); - expect(firebaseJson).toEqual(universalFirebaseJson); - }); - }); - }); -}); diff --git a/src/schematics/setup/index.ts b/src/schematics/setup/index.ts index 4cf04bb37..5bdebf9e7 100644 --- a/src/schematics/setup/index.ts +++ b/src/schematics/setup/index.ts @@ -1,36 +1,24 @@ import { writeFileSync } from 'fs'; import { join } from 'path'; import { asWindowsPath, normalize } from '@angular-devkit/core'; -import { SchematicContext, SchematicsException, Tree, chain } from '@angular-devkit/schematics'; +import { SchematicContext, Tree, chain } from '@angular-devkit/schematics'; import { addRootProvider } from '@schematics/angular/utility'; -import { - generateFirebaseRc, - overwriteIfExists, - safeReadJSON, - stringifyFormatted -} from '../common'; import { getFirebaseTools } from '../firebaseTools'; import { - DeployOptions, FEATURES, FirebaseApp, FirebaseHostingSite, FirebaseProject, - NgAddNormalizedOptions + DeployOptions, FEATURES, FirebaseApp, FirebaseProject, } from '../interfaces'; -import { FirebaseJSON, Workspace, WorkspaceProject } from '../interfaces'; import { addIgnoreFiles, featureToRules, - getFirebaseProjectNameFromHost, getProject, getWorkspace + getFirebaseProjectNameFromHost, + getProject, } from '../utils'; -import { appPrompt, featuresPrompt, projectPrompt, projectTypePrompt, sitePrompt, userPrompt } from './prompts'; +import { appPrompt, featuresPrompt, projectPrompt, userPrompt } from './prompts'; export interface SetupConfig extends DeployOptions { firebaseProject: FirebaseProject, firebaseApp?: FirebaseApp, - firebaseHostingSite?: FirebaseHostingSite, sdkConfig?: Record, - buildTarget?: [string, string], - serveTarget?: [string, string], - project?: string, - ssrRegion?: string, } export const setupProject = @@ -39,30 +27,7 @@ export const setupProject = addIgnoreFiles(tree); - if (features.includes(FEATURES.Hosting)) { - const { path: workspacePath, workspace } = getWorkspace(tree); - const { project, projectName } = getProject(config, tree); - setupFirebase({ - workspace, - workspacePath, - options: { - project: projectName, - firebaseProject: config.firebaseProject, - firebaseApp: config.firebaseApp, - firebaseHostingSite: config.firebaseHostingSite, - sdkConfig: config.sdkConfig, - buildTarget: config.buildTarget, - serveTarget: config.serveTarget, - ssrRegion: config.ssrRegion, - }, - tree, - context, - project - }); - } - - const featuresToImport = features.filter(it => it !== FEATURES.Hosting); - if (featuresToImport.length > 0) { + if (features.length) { return chain([ addRootProvider(projectName, ({code, external}) => { external('initializeApp', '@angular/fire/app'); @@ -96,31 +61,18 @@ export const ngAddSetupProject = ( await firebaseTools.login.use(user.email, { projectRoot }); } - const { project: ngProject, projectName: ngProjectName } = getProject(options, host); + const { projectName: ngProjectName } = getProject(options, host); const [ defaultProjectName ] = getFirebaseProjectNameFromHost(host, ngProjectName); const firebaseProject = await projectPrompt(defaultProjectName, { projectRoot, account: user.email }); - - let hosting = { }; - let firebaseHostingSite: FirebaseHostingSite|undefined; - - if (features.includes(FEATURES.Hosting)) { - // TODO read existing settings from angular.json, if available - const results = await projectTypePrompt(ngProject, ngProjectName); - hosting = { ...hosting, ...results }; - firebaseHostingSite = await sitePrompt(firebaseProject, { projectRoot }); - } - - let firebaseApp: FirebaseApp|undefined; let sdkConfig: Record|undefined; - if (features.find(it => it !== FEATURES.Hosting)) { + if (features.length) { - const defaultAppId = firebaseHostingSite?.appId; - firebaseApp = await appPrompt(firebaseProject, defaultAppId, { projectRoot }); + firebaseApp = await appPrompt(firebaseProject, undefined, { projectRoot }); const result = await firebaseTools.apps.sdkconfig('web', firebaseApp.appId, { nonInteractive: true, projectRoot }); sdkConfig = result.sdkConfig; @@ -128,88 +80,8 @@ export const ngAddSetupProject = ( } return setupProject(host, context, features, { - ...options, ...hosting, firebaseProject, firebaseApp, firebaseHostingSite, sdkConfig, + ...options, firebaseProject, firebaseApp, sdkConfig, }); } }; - -export function generateFirebaseJson( - tree: Tree, - path: string, - project: string, - region: string|undefined, -) { - const firebaseJson: FirebaseJSON = tree.exists(path) - ? safeReadJSON(path, tree) - : {}; - - const newConfig = { - target: project, - source: '.', - frameworksBackend: { - region - } - }; - if (firebaseJson.hosting === undefined) { - firebaseJson.hosting = [newConfig]; - } else if (Array.isArray(firebaseJson.hosting)) { - const existingConfigIndex = firebaseJson.hosting.findIndex(config => config.target === newConfig.target); - if (existingConfigIndex > -1) { - firebaseJson.hosting.splice(existingConfigIndex, 1, newConfig); - } else { - firebaseJson.hosting.push(newConfig); - } - } else { - firebaseJson.hosting = [firebaseJson.hosting, newConfig]; - } - - overwriteIfExists(tree, path, stringifyFormatted(firebaseJson)); -} - -export const setupFirebase = (config: { - project: WorkspaceProject; - options: NgAddNormalizedOptions; - workspacePath: string; - workspace: Workspace; - tree: Tree; - context: SchematicContext; -}) => { - const { tree, workspacePath, workspace, options } = config; - const project = workspace.projects[options.project]; - - if (!project.architect) { - throw new SchematicsException(`Angular project "${options.project}" has a malformed angular.json`); - } - - project.architect.deploy = { - builder: '@angular/fire:deploy', - options: { - version: 2, - }, - configurations: { - production: { - buildTarget: options.buildTarget?.[0], - serveTarget: options.serveTarget?.[0], - }, - development: { - buildTarget: options.buildTarget?.[1], - serveTarget: options.serveTarget?.[1], - } - }, - defaultConfiguration: 'production', - }; - - tree.overwrite(workspacePath, JSON.stringify(workspace, null, 2)); - - generateFirebaseJson(tree, 'firebase.json', options.project, options.ssrRegion); - generateFirebaseRc( - tree, - '.firebaserc', - options.firebaseProject.projectId, - options.firebaseHostingSite, - options.project - ); - - return tree; -}; diff --git a/src/schematics/setup/prompts.ts b/src/schematics/setup/prompts.ts index b014df259..1bc8a85ca 100644 --- a/src/schematics/setup/prompts.ts +++ b/src/schematics/setup/prompts.ts @@ -1,16 +1,14 @@ import { spawnSync } from 'child_process'; import * as fuzzy from 'fuzzy'; import * as inquirer from 'inquirer'; -import { shortSiteName } from '../common'; import { getFirebaseTools } from '../firebaseTools'; -import { FEATURES, FirebaseApp, FirebaseHostingSite, FirebaseProject, PROJECT_TYPE, WorkspaceProject, featureOptions } from '../interfaces'; -import { isSSRApp, isUniversalApp, shortAppId } from '../utils'; +import { FEATURES, FirebaseApp, FirebaseProject, featureOptions } from '../interfaces'; +import { shortAppId } from '../utils'; // eslint-disable-next-line @typescript-eslint/no-var-requires inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt')); const NEW_OPTION = '~~angularfire-new~~'; -const DEFAULT_SITE_TYPE = 'DEFAULT_SITE'; // `fuzzy` passes either the original list of projects or an internal object // which contains the project as a property. @@ -22,10 +20,6 @@ const isApp = (elem: FirebaseApp | fuzzy.FilterResult): elem is Fir return (elem as { original: FirebaseApp }).original === undefined; }; -const isSite = (elem: FirebaseHostingSite | fuzzy.FilterResult): elem is FirebaseHostingSite => { - return (elem as { original: FirebaseHostingSite }).original === undefined; -}; - export const searchProjects = (projects: FirebaseProject[]) => // eslint-disable-next-line @typescript-eslint/require-await async (_: any, input: string) => { @@ -78,33 +72,6 @@ export const searchApps = (apps: FirebaseApp[]) => }); }; -export const searchSites = (sites: FirebaseHostingSite[]) => - // eslint-disable-next-line @typescript-eslint/require-await - async (_: any, input: string) => { - sites.unshift({ - name: NEW_OPTION, - defaultUrl: '[CREATE NEW SITE]', - } as any); - return fuzzy.filter(input, sites, { - extract(el) { - return el.defaultUrl; - } - }).map((result) => { - let original: FirebaseHostingSite; - if (isSite(result)) { - original = result; - } else { - original = result.original; - } - return { - name: original.defaultUrl, - title: original.defaultUrl, - value: shortSiteName(original), - }; - }); - }; - - type Prompt = (questions: { name: K, source: (...args) => Promise<{ value: U }[]>, default?: U | ((o: U[]) => U | Promise), [key: string]: any }) => Promise<{[T in K]: U }>; @@ -118,7 +85,7 @@ export const featuresPrompt = async (): Promise => { name: 'features', choices: featureOptions, message: 'What features would you like to setup?', - default: [FEATURES.Hosting], + default: [], }) as { features: FEATURES[] }; return features; }; @@ -206,64 +173,3 @@ export const appPrompt = async ({ projectId: project }: FirebaseProject, default // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return (apps).find(it => shortAppId(it) === appId)!; }; - -export const sitePrompt = async ({ projectId: project }: FirebaseProject, options: any) => { - const firebaseTools = await getFirebaseTools(); - const sites = await firebaseTools.hosting.sites.list({ ...options, project }).then(it => { - if (it.sites.length === 0) { - // newly created projects don't return their default site, stub one - return [{ - name: project, - defaultUrl: `https://${project}.web.app`, - type: DEFAULT_SITE_TYPE, - appId: undefined, - } as FirebaseHostingSite]; - } else { - return it.sites; - } - }); - const { siteName } = await autocomplete({ - type: 'autocomplete', - name: 'siteName', - source: searchSites(sites), - message: 'Please select a hosting site:', - default: _ => shortSiteName(sites.find(site => site.type === DEFAULT_SITE_TYPE)), - }); - if (siteName === NEW_OPTION) { - const { subdomain } = await inquirer.prompt({ - type: 'input', - name: 'subdomain', - message: 'Please provide an unique, URL-friendly id for the site (.web.app):', - }) as { subdomain: string }; - return await firebaseTools.hosting.sites.create(subdomain, { ...options, nonInteractive: true, project }); - } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return (sites).find(it => shortSiteName(it) === siteName)!; -}; - -const DEFAULT_REGION = 'us-central1'; -const ALLOWED_SSR_REGIONS = [ - { name: 'us-central1 (Iowa)', value: 'us-central1' }, - { name: 'us-west1 (Oregon)', value: 'us-west1' }, - { name: 'us-east1 (South Carolina)', value: 'us-east1' }, - { name: 'europe-west1 (Belgium)', value: 'europe-west1' }, - { name: 'asia-east1 (Taiwan)', value: 'asia-east1' }, -]; - -export const projectTypePrompt = async (project: WorkspaceProject, name: string) => { - const buildTarget = [`${name}:build:production`, `${name}:build:development`]; - const serveTarget = isUniversalApp(project) ? - [`${name}:serve-ssr:production`, `${name}:serve-ssr:development`] : - [`${name}:serve:production`, `${name}:serve:development`]; - if (isUniversalApp(project) || isSSRApp(project)) { - const { ssrRegion } = await inquirer.prompt({ - type: 'list', - name: 'ssrRegion', - choices: ALLOWED_SSR_REGIONS, - message: 'In which region would you like to host server-side content?', - default: DEFAULT_REGION, - }) as { ssrRegion: string }; - return { projectType: PROJECT_TYPE.WebFrameworks, ssrRegion, buildTarget, serveTarget }; - } - return { projectType: PROJECT_TYPE.WebFrameworks, buildTarget, serveTarget }; -}; diff --git a/src/schematics/utils.ts b/src/schematics/utils.ts index aeab94762..eff08361f 100644 --- a/src/schematics/utils.ts +++ b/src/schematics/utils.ts @@ -1,26 +1,9 @@ import { readFileSync } from 'fs'; import { join } from 'path'; import { Rule, SchematicsException, Tree, chain } from '@angular-devkit/schematics'; -import ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript'; import { addRootProvider } from '@schematics/angular/utility'; -import { findNode } from '@schematics/angular/utility/ast-utils'; -import { InsertChange, ReplaceChange, applyToUpdateRecorder } from '@schematics/angular/utility/change'; import { overwriteIfExists } from './common'; -import { DeployOptions, FEATURES, FirebaseApp, FirebaseRc, Workspace, WorkspaceProject } from './interfaces'; - -// We consider a project to be a universal project if it has a `server` architect -// target. If it does, it knows how to build the application's server. -export const isUniversalApp = ( - project: WorkspaceProject -) => project.architect?.server; - -export const isSSRApp = ( - project: WorkspaceProject -) => !!project.architect?.build.options?.ssr; - -export const hasPrerenderOption = ( - project: WorkspaceProject -) => project.architect?.prerender; +import { DeployOptions, FEATURES, FirebaseApp, FirebaseRc, Workspace } from './interfaces'; export const shortAppId = (app?: FirebaseApp) => app?.appId?.split('/').pop(); @@ -109,55 +92,6 @@ const projectFromRc = (rc: FirebaseRc, target: string): [string|undefined, strin return [project || defaultProject, site]; }; -/** - * Adds a package to the package.json - */ -export function addEnvironmentEntry( - host: Tree, - filePath: string, - data: string, -): Tree { - const fileExists = host.exists(filePath); - if (fileExists) { - const buffer = host.read(filePath); - if (!buffer) { - throw new SchematicsException(`Cannot read ${filePath}`); - } - const sourceFile = ts.createSourceFile(filePath, buffer.toString('utf-8'), ts.ScriptTarget.Latest, true); - - const envIdentifier = findNode(sourceFile as any, ts.SyntaxKind.Identifier, 'environment'); - if (!envIdentifier?.parent) { - throw new SchematicsException(`Cannot find 'environment' identifier in ${filePath}`); - } - - const envObjectLiteral = envIdentifier.parent.getChildren().find(({ kind }) => kind === ts.SyntaxKind.ObjectLiteralExpression); - if (!envObjectLiteral) { - throw new SchematicsException(`${filePath} is not in the expected format`); - } - const firebaseIdentifier = findNode(envObjectLiteral, ts.SyntaxKind.Identifier, 'firebase'); - - const recorder = host.beginUpdate(filePath); - if (firebaseIdentifier?.parent) { - const change = new ReplaceChange(filePath, firebaseIdentifier.parent.pos, firebaseIdentifier.parent.getFullText(), data); - applyToUpdateRecorder(recorder, [change]); - } else { - const openBracketToken = envObjectLiteral.getChildren().find(({ kind }) => kind === ts.SyntaxKind.OpenBraceToken); - if (openBracketToken) { - const change = new InsertChange(filePath, openBracketToken.end, `${data},`); - applyToUpdateRecorder(recorder, [change]); - } else { - throw new SchematicsException(`${filePath} is not in the expected format`); - } - } - host.commitUpdate(recorder); - } else { - host.create(filePath, `export const environment = {${data}, -};`); - } - - return host; -} - // TODO rewrite using typescript export function addFixesToServer(host: Tree) { const serverPath = `/server.ts`; @@ -253,6 +187,11 @@ export function featureToRules(features: FEATURES[], projectName: string) { external('getRemoteConfig', '@angular/fire/remote-config'); return code`${external('provideRemoteConfig', '@angular/fire/remote-config')}(() => getRemoteConfig())`; }); + case FEATURES.VertexAI: + return addRootProvider(projectName, ({code, external}) => { + external('getVertexAI', '@angular/fire/vertexai-preview'); + return code`${external('provideVertexAI', '@angular/fire/vertexai-preview')}(() => getVertexAI())`; + }); default: return undefined; } diff --git a/src/vertexai-preview/firebase.ts b/src/vertexai-preview/firebase.ts new file mode 100644 index 000000000..8d46493ce --- /dev/null +++ b/src/vertexai-preview/firebase.ts @@ -0,0 +1,10 @@ +// DO NOT MODIFY, this file is autogenerated by tools/build.ts +export * from 'firebase/vertexai-preview'; +import { ɵzoneWrap } from '@angular/fire'; +import { + getGenerativeModel as _getGenerativeModel, + getVertexAI as _getVertexAI +} from 'firebase/vertexai-preview'; + +export const getVertexAI = ɵzoneWrap(_getVertexAI, true); +export const getGenerativeModel = ɵzoneWrap(_getGenerativeModel, true); diff --git a/src/vertexai-preview/ng-package.json b/src/vertexai-preview/ng-package.json new file mode 100644 index 000000000..d3032da35 --- /dev/null +++ b/src/vertexai-preview/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public_api.ts" + } +} diff --git a/src/vertexai-preview/package.json b/src/vertexai-preview/package.json new file mode 100644 index 000000000..8dce418a5 --- /dev/null +++ b/src/vertexai-preview/package.json @@ -0,0 +1,3 @@ +{ + "$schema": "../../node_modules/ng-packagr/package.schema.json" +} diff --git a/src/vertexai-preview/public_api.ts b/src/vertexai-preview/public_api.ts new file mode 100644 index 000000000..ab750d9af --- /dev/null +++ b/src/vertexai-preview/public_api.ts @@ -0,0 +1,3 @@ +export { VertexAI, VertexAIInstances, vertexAIInstance$ } from './vertexai'; +export { provideVertexAI, VertexAIModule } from './vertexai.module'; +export * from './firebase'; diff --git a/src/vertexai-preview/vertexai.module.ts b/src/vertexai-preview/vertexai.module.ts new file mode 100644 index 000000000..f4b49a6f2 --- /dev/null +++ b/src/vertexai-preview/vertexai.module.ts @@ -0,0 +1,79 @@ +import { + EnvironmentProviders, + InjectionToken, + Injector, + NgModule, + NgZone, + Optional, + makeEnvironmentProviders, +} from '@angular/core'; +import { VERSION, ɵAngularFireSchedulers, ɵgetDefaultInstanceOf } from '@angular/fire'; +import { ɵAppCheckInstances } from '@angular/fire'; +import { FirebaseApp, FirebaseApps } from '@angular/fire/app'; +import { registerVersion } from 'firebase/app'; +import { VertexAI as FirebaseVertexAI } from 'firebase/vertexai-preview'; +import { VERTEX_AI_PROVIDER_NAME, VertexAI, VertexAIInstances } from './vertexai'; + +export const PROVIDED_VERTEX_AI_INSTANCES = new InjectionToken('angularfire2.vertexai-instances'); + +export function defaultVertexAIInstanceFactory(provided: FirebaseVertexAI[]|undefined, defaultApp: FirebaseApp) { + const defaultVertexAI = ɵgetDefaultInstanceOf(VERTEX_AI_PROVIDER_NAME, provided, defaultApp); + return defaultVertexAI && new VertexAI(defaultVertexAI); +} + +export function vertexAIInstanceFactory(fn: (injector: Injector) => FirebaseVertexAI) { + return (zone: NgZone, injector: Injector) => { + const vertexAI = zone.runOutsideAngular(() => fn(injector)); + return new VertexAI(vertexAI); + }; +} + +const VERTEX_AI_INSTANCES_PROVIDER = { + provide: VertexAIInstances, + deps: [ + [new Optional(), PROVIDED_VERTEX_AI_INSTANCES ], + ] +}; + +const DEFAULT_VERTEX_AI_INSTANCE_PROVIDER = { + provide: VertexAI, + useFactory: defaultVertexAIInstanceFactory, + deps: [ + [new Optional(), PROVIDED_VERTEX_AI_INSTANCES ], + FirebaseApp, + ] +}; + +@NgModule({ + providers: [ + DEFAULT_VERTEX_AI_INSTANCE_PROVIDER, + VERTEX_AI_INSTANCES_PROVIDER, + ] +}) +export class VertexAIModule { + constructor() { + registerVersion('angularfire', VERSION.full, 'vertexai'); + } +} + +export function provideVertexAI(fn: (injector: Injector) => FirebaseVertexAI, ...deps: any[]): EnvironmentProviders { + registerVersion('angularfire', VERSION.full, 'vertexai'); + + return makeEnvironmentProviders([ + DEFAULT_VERTEX_AI_INSTANCE_PROVIDER, + VERTEX_AI_INSTANCES_PROVIDER, + { + provide: PROVIDED_VERTEX_AI_INSTANCES, + useFactory: vertexAIInstanceFactory(fn), + multi: true, + deps: [ + NgZone, + Injector, + ɵAngularFireSchedulers, + FirebaseApps, + [new Optional(), ɵAppCheckInstances ], + ...deps, + ] + } + ]); +} diff --git a/src/vertexai-preview/vertexai.spec.ts b/src/vertexai-preview/vertexai.spec.ts new file mode 100644 index 000000000..87e61da93 --- /dev/null +++ b/src/vertexai-preview/vertexai.spec.ts @@ -0,0 +1,38 @@ +import { TestBed } from '@angular/core/testing'; +import { FirebaseApp, getApp, initializeApp, provideFirebaseApp } from '@angular/fire/app'; +import { VertexAI, getVertexAI, provideVertexAI } from '@angular/fire/vertexai-preview'; +import { COMMON_CONFIG } from '../test-config'; +import { rando } from '../utils'; + +describe('VertexAI', () => { + let app: FirebaseApp; + let vertexAI: VertexAI; + let providedVertexAI: VertexAI; + let appName: string; + + describe('single injection', () => { + + beforeEach(() => { + appName = rando(); + TestBed.configureTestingModule({ + providers: [ + provideFirebaseApp(() => initializeApp(COMMON_CONFIG, appName)), + provideVertexAI(() => { + providedVertexAI = getVertexAI(getApp(appName)); + return providedVertexAI; + }), + ], + }); + app = TestBed.inject(FirebaseApp); + vertexAI = TestBed.inject(VertexAI); + }); + + it('should be injectable', () => { + expect(providedVertexAI).toBeTruthy(); + expect(vertexAI).toEqual(providedVertexAI); + expect(vertexAI.app).toEqual(app); + }); + + }); + +}); diff --git a/src/vertexai-preview/vertexai.ts b/src/vertexai-preview/vertexai.ts new file mode 100644 index 000000000..3cdceb4f0 --- /dev/null +++ b/src/vertexai-preview/vertexai.ts @@ -0,0 +1,30 @@ +import { ɵgetAllInstancesOf } from '@angular/fire'; +import { VertexAI as FirebaseVertexAI } from 'firebase/vertexai-preview'; +import { from, timer } from 'rxjs'; +import { concatMap, distinct } from 'rxjs/operators'; + +// see notes in core/firebase.app.module.ts for why we're building the class like this +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface VertexAI extends FirebaseVertexAI {} + +export class VertexAI { + constructor(vertexai: FirebaseVertexAI) { + return vertexai; + } +} + +export const VERTEX_AI_PROVIDER_NAME = 'vertexai'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface VertexAIInstances extends Array {} + +export class VertexAIInstances { + constructor() { + return ɵgetAllInstancesOf(VERTEX_AI_PROVIDER_NAME); + } +} + +export const vertexAIInstance$ = timer(0, 300).pipe( + concatMap(() => from(ɵgetAllInstancesOf(VERTEX_AI_PROVIDER_NAME))), + distinct(), +); diff --git a/tools/build.ts b/tools/build.ts index 03a936242..6fe2dfb30 100644 --- a/tools/build.ts +++ b/tools/build.ts @@ -119,6 +119,7 @@ ${exportedZoneWrappedFns} collection: { exportName: 'collectionSnapshots' }, }), reexport('firestore/lite', 'firebase', 'firebase/firestore/lite', tsKeys()), + reexport('vertexai-preview', 'firebase', 'firebase/vertexai-preview', tsKeys()), ]); }