From 02c52c6035d59b1ecc83e39e02f4d78a9ca42a00 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 11 Apr 2025 14:30:44 -0700 Subject: [PATCH 01/67] Added test project to fdc --- .../js/default-connector/README.md | 257 ++++++ .../js/default-connector/esm/index.esm.js | 28 + .../js/default-connector/esm/package.json | 1 + .../js/default-connector/index.cjs.js | 28 + .../js/default-connector/index.d.ts | 50 ++ .../js/default-connector/package.json | 25 + .../dataconnect/connector/connector.yaml | 6 + .../dataconnect/connector/mutations.gql | 33 + .../dataconnect/connector/queries.gql | 78 ++ .../dataconnect/dataconnect.yaml | 12 + .../dataconnect/schema/schema.gql | 52 ++ .../example-integration/dataconnect/test | 0 .../firebase-js-config.json | 3 + .../example-integration/firebase.json | 10 + .../example-integration/package.json | 22 + .../data-connect/example-integration/test.ts | 7 + .../example-integration/testscript.sh | 11 + .../example-integration/tsconfig.json | 10 + .../example-integration/yarn.lock | 802 ++++++++++++++++++ 19 files changed, 1435 insertions(+) create mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/README.md create mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js create mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/package.json create mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js create mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts create mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/package.json create mode 100644 packages/data-connect/example-integration/dataconnect/connector/connector.yaml create mode 100644 packages/data-connect/example-integration/dataconnect/connector/mutations.gql create mode 100644 packages/data-connect/example-integration/dataconnect/connector/queries.gql create mode 100644 packages/data-connect/example-integration/dataconnect/dataconnect.yaml create mode 100644 packages/data-connect/example-integration/dataconnect/schema/schema.gql create mode 100644 packages/data-connect/example-integration/dataconnect/test create mode 100644 packages/data-connect/example-integration/firebase-js-config.json create mode 100644 packages/data-connect/example-integration/firebase.json create mode 100644 packages/data-connect/example-integration/package.json create mode 100644 packages/data-connect/example-integration/test.ts create mode 100755 packages/data-connect/example-integration/testscript.sh create mode 100644 packages/data-connect/example-integration/tsconfig.json create mode 100644 packages/data-connect/example-integration/yarn.lock diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/README.md b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/README.md new file mode 100644 index 00000000000..b3f5971d704 --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/README.md @@ -0,0 +1,257 @@ +# Table of Contents +- [**Overview**](#generated-typescript-readme) +- [**Accessing the connector**](#accessing-the-connector) + - [*Connecting to the local Emulator*](#connecting-to-the-local-emulator) +- [**Queries**](#queries) + - [*ListMovies*](#listmovies) +- [**Mutations**](#mutations) + - [*CreateMovie*](#createmovie) + +# Generated TypeScript README +This README will guide you through the process of using the generated TypeScript SDK package for the connector `default`. It will also provide examples on how to use your generated SDK to call your Data Connect queries and mutations. + +***NOTE:** This README is generated alongside the generated SDK. If you make changes to this file, they will be overwritten when the SDK is regenerated.* + +You can use this generated SDK by importing from the package `@firebasegen/default-connector` as shown below. Both CommonJS and ESM imports are supported. + +You can also follow the instructions from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#set-client). + +# Accessing the connector +A connector is a collection of Queries and Mutations. One SDK is generated for each connector - this SDK is generated for the connector `default`. + +You can find more information about connectors in the [Data Connect documentation](https://firebase.google.com/docs/data-connect#how-does). + +```javascript +import { getDataConnect } from 'firebase/data-connect'; +import { connectorConfig } from '@firebasegen/default-connector'; + +const dataConnect = getDataConnect(connectorConfig); +``` + +## Connecting to the local Emulator +By default, the connector will connect to the production service. + +To connect to the emulator, you can use the following code. +You can also follow the emulator instructions from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#instrument-clients). + +```javascript +import { connectDataConnectEmulator, getDataConnect } from 'firebase/data-connect'; +import { connectorConfig } from '@firebasegen/default-connector'; + +const dataConnect = getDataConnect(connectorConfig); +connectDataConnectEmulator(dataConnect, 'localhost', 9399); +``` + +After it's initialized, you can call your Data Connect [queries](#queries) and [mutations](#mutations) from your generated SDK. + +# Queries + +There are two ways to execute a Data Connect Query using the generated Web SDK: +- Using a Query Reference function, which returns a `QueryRef` + - The `QueryRef` can be used as an argument to `executeQuery()`, which will execute the Query and return a `QueryPromise` +- Using an action shortcut function, which returns a `QueryPromise` + - Calling the action shortcut function will execute the Query and return a `QueryPromise` + +The following is true for both the action shortcut function and the `QueryRef` function: +- The `QueryPromise` returned will resolve to the result of the Query once it has finished executing +- If the Query accepts arguments, both the action shortcut function and the `QueryRef` function accept a single argument: an object that contains all the required variables (and the optional variables) for the Query +- Both functions can be called with or without passing in a `DataConnect` instance as an argument. If no `DataConnect` argument is passed in, then the generated SDK will call `getDataConnect(connectorConfig)` behind the scenes for you. + +Below are examples of how to use the `default` connector's generated functions to execute each query. You can also follow the examples from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#using-queries). + +## ListMovies +You can execute the `ListMovies` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [default-connector/index.d.ts](./index.d.ts): +```javascript +listMovies(): QueryPromise; + +listMoviesRef(): QueryRef; +``` +You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function. +```javascript +listMovies(dc: DataConnect): QueryPromise; + +listMoviesRef(dc: DataConnect): QueryRef; +``` + +### Variables +The `ListMovies` query has no variables. +### Return Type +Recall that executing the `ListMovies` query returns a `QueryPromise` that resolves to an object with a `data` property. + +The `data` property is an object of type `ListMoviesData`, which is defined in [default-connector/index.d.ts](./index.d.ts). It has the following fields: +```javascript +export interface ListMoviesData { + movies: ({ + id: UUIDString; + title: string; + imageUrl: string; + genre?: string | null; + } & Movie_Key)[]; +} +``` +### Using `ListMovies`'s action shortcut function + +```javascript +import { getDataConnect } from 'firebase/data-connect'; +import { connectorConfig, listMovies } from '@firebasegen/default-connector'; + + +// Call the `listMovies()` function to execute the query. +// You can use the `await` keyword to wait for the promise to resolve. +const { data } = await listMovies(); + +// You can also pass in a `DataConnect` instance to the action shortcut function. +const dataConnect = getDataConnect(connectorConfig); +const { data } = await listMovies(dataConnect); + +console.log(data.movies); + +// Or, you can use the `Promise` API. +listMovies().then((response) => { + const data = response.data; + console.log(data.movies); +}); +``` + +### Using `ListMovies`'s `QueryRef` function + +```javascript +import { getDataConnect, executeQuery } from 'firebase/data-connect'; +import { connectorConfig, listMoviesRef } from '@firebasegen/default-connector'; + + +// Call the `listMoviesRef()` function to get a reference to the query. +const ref = listMoviesRef(); + +// You can also pass in a `DataConnect` instance to the `QueryRef` function. +const dataConnect = getDataConnect(connectorConfig); +const ref = listMoviesRef(dataConnect); + +// Call `executeQuery()` on the reference to execute the query. +// You can use the `await` keyword to wait for the promise to resolve. +const { data } = await executeQuery(ref); + +console.log(data.movies); + +// Or, you can use the `Promise` API. +executeQuery(ref).then((response) => { + const data = response.data; + console.log(data.movies); +}); +``` + +# Mutations + +There are two ways to execute a Data Connect Mutation using the generated Web SDK: +- Using a Mutation Reference function, which returns a `MutationRef` + - The `MutationRef` can be used as an argument to `executeMutation()`, which will execute the Mutation and return a `MutationPromise` +- Using an action shortcut function, which returns a `MutationPromise` + - Calling the action shortcut function will execute the Mutation and return a `MutationPromise` + +The following is true for both the action shortcut function and the `MutationRef` function: +- The `MutationPromise` returned will resolve to the result of the Mutation once it has finished executing +- If the Mutation accepts arguments, both the action shortcut function and the `MutationRef` function accept a single argument: an object that contains all the required variables (and the optional variables) for the Mutation +- Both functions can be called with or without passing in a `DataConnect` instance as an argument. If no `DataConnect` argument is passed in, then the generated SDK will call `getDataConnect(connectorConfig)` behind the scenes for you. + +Below are examples of how to use the `default` connector's generated functions to execute each mutation. You can also follow the examples from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#using-mutations). + +## CreateMovie +You can execute the `CreateMovie` mutation using the following action shortcut function, or by calling `executeMutation()` after calling the following `MutationRef` function, both of which are defined in [default-connector/index.d.ts](./index.d.ts): +```javascript +createMovie(vars: CreateMovieVariables): MutationPromise; + +createMovieRef(vars: CreateMovieVariables): MutationRef; +``` +You can also pass in a `DataConnect` instance to the action shortcut function or `MutationRef` function. +```javascript +createMovie(dc: DataConnect, vars: CreateMovieVariables): MutationPromise; + +createMovieRef(dc: DataConnect, vars: CreateMovieVariables): MutationRef; +``` + +### Variables +The `CreateMovie` mutation requires an argument of type `CreateMovieVariables`, which is defined in [default-connector/index.d.ts](./index.d.ts). It has the following fields: + +```javascript +export interface CreateMovieVariables { + title: string; + genre: string; + imageUrl: string; +} +``` +### Return Type +Recall that executing the `CreateMovie` mutation returns a `MutationPromise` that resolves to an object with a `data` property. + +The `data` property is an object of type `CreateMovieData`, which is defined in [default-connector/index.d.ts](./index.d.ts). It has the following fields: +```javascript +export interface CreateMovieData { + movie_insert: Movie_Key; +} +``` +### Using `CreateMovie`'s action shortcut function + +```javascript +import { getDataConnect } from 'firebase/data-connect'; +import { connectorConfig, createMovie, CreateMovieVariables } from '@firebasegen/default-connector'; + +// The `CreateMovie` mutation requires an argument of type `CreateMovieVariables`: +const createMovieVars: CreateMovieVariables = { + title: ..., + genre: ..., + imageUrl: ..., +}; + +// Call the `createMovie()` function to execute the mutation. +// You can use the `await` keyword to wait for the promise to resolve. +const { data } = await createMovie(createMovieVars); +// Variables can be defined inline as well. +const { data } = await createMovie({ title: ..., genre: ..., imageUrl: ..., }); + +// You can also pass in a `DataConnect` instance to the action shortcut function. +const dataConnect = getDataConnect(connectorConfig); +const { data } = await createMovie(dataConnect, createMovieVars); + +console.log(data.movie_insert); + +// Or, you can use the `Promise` API. +createMovie(createMovieVars).then((response) => { + const data = response.data; + console.log(data.movie_insert); +}); +``` + +### Using `CreateMovie`'s `MutationRef` function + +```javascript +import { getDataConnect, executeMutation } from 'firebase/data-connect'; +import { connectorConfig, createMovieRef, CreateMovieVariables } from '@firebasegen/default-connector'; + +// The `CreateMovie` mutation requires an argument of type `CreateMovieVariables`: +const createMovieVars: CreateMovieVariables = { + title: ..., + genre: ..., + imageUrl: ..., +}; + +// Call the `createMovieRef()` function to get a reference to the mutation. +const ref = createMovieRef(createMovieVars); +// Variables can be defined inline as well. +const ref = createMovieRef({ title: ..., genre: ..., imageUrl: ..., }); + +// You can also pass in a `DataConnect` instance to the `MutationRef` function. +const dataConnect = getDataConnect(connectorConfig); +const ref = createMovieRef(dataConnect, createMovieVars); + +// Call `executeMutation()` on the reference to execute the mutation. +// You can use the `await` keyword to wait for the promise to resolve. +const { data } = await executeMutation(ref); + +console.log(data.movie_insert); + +// Or, you can use the `Promise` API. +executeMutation(ref).then((response) => { + const data = response.data; + console.log(data.movie_insert); +}); +``` + diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js new file mode 100644 index 00000000000..28675a48069 --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js @@ -0,0 +1,28 @@ +import { queryRef, executeQuery, mutationRef, executeMutation, validateArgs } from 'firebase/data-connect'; + +export const connectorConfig = { + connector: 'default', + service: 'fdc-test', + location: 'us-central1' +}; + +export function createMovieRef(dcOrVars, vars) { + const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true); + dcInstance._useGeneratedSdk(); + return mutationRef(dcInstance, 'CreateMovie', inputVars); +} + +export function createMovie(dcOrVars, vars) { + return executeMutation(createMovieRef(dcOrVars, vars)); +} + +export function listMoviesRef(dc) { + const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined); + dcInstance._useGeneratedSdk(); + return queryRef(dcInstance, 'ListMovies'); +} + +export function listMovies(dc) { + return executeQuery(listMoviesRef(dc)); +} + diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/package.json b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/package.json new file mode 100644 index 00000000000..7c34deb5837 --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/package.json @@ -0,0 +1 @@ +{"type":"module"} \ No newline at end of file diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js new file mode 100644 index 00000000000..7f8250f2599 --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js @@ -0,0 +1,28 @@ +const { queryRef, executeQuery, mutationRef, executeMutation, validateArgs } = require('firebase/data-connect'); + +const connectorConfig = { + connector: 'default', + service: 'fdc-test', + location: 'us-central1' +}; +exports.connectorConfig = connectorConfig; + +exports.createMovieRef = function createMovieRef(dcOrVars, vars) { + const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true); + dcInstance._useGeneratedSdk(); + return mutationRef(dcInstance, 'CreateMovie', inputVars); +} + +exports.createMovie = function createMovie(dcOrVars, vars) { + return executeMutation(createMovieRef(dcOrVars, vars)); +}; + +exports.listMoviesRef = function listMoviesRef(dc) { + const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined); + dcInstance._useGeneratedSdk(); + return queryRef(dcInstance, 'ListMovies'); +} + +exports.listMovies = function listMovies(dc) { + return executeQuery(listMoviesRef(dc)); +}; diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts new file mode 100644 index 00000000000..5d821c79cc9 --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts @@ -0,0 +1,50 @@ +import { ConnectorConfig, DataConnect, QueryRef, QueryPromise, MutationRef, MutationPromise } from 'firebase/data-connect'; + +export const connectorConfig: ConnectorConfig; + +export type TimestampString = string; +export type UUIDString = string; +export type Int64String = string; +export type DateString = string; + + +export interface CreateMovieData { + movie_insert: Movie_Key; +} + +export interface CreateMovieVariables { + title: string; + genre: string; + imageUrl: string; +} + +export interface ListMoviesData { + movies: ({ + id: UUIDString; + title: string; + imageUrl: string; + genre?: string | null; + } & Movie_Key)[]; +} + +export interface Movie_Key { + id: UUIDString; + __typename?: 'Movie_Key'; +} + +/* Allow users to create refs without passing in DataConnect */ +export function createMovieRef(vars: CreateMovieVariables): MutationRef; +/* Allow users to pass in custom DataConnect instances */ +export function createMovieRef(dc: DataConnect, vars: CreateMovieVariables): MutationRef; + +export function createMovie(vars: CreateMovieVariables): MutationPromise; +export function createMovie(dc: DataConnect, vars: CreateMovieVariables): MutationPromise; + +/* Allow users to create refs without passing in DataConnect */ +export function listMoviesRef(): QueryRef; +/* Allow users to pass in custom DataConnect instances */ +export function listMoviesRef(dc: DataConnect): QueryRef; + +export function listMovies(): QueryPromise; +export function listMovies(dc: DataConnect): QueryPromise; + diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/package.json b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/package.json new file mode 100644 index 00000000000..d0c9852ce3e --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/package.json @@ -0,0 +1,25 @@ +{ + "name": "@firebasegen/default-connector", + "version": "1.0.0", + "author": "Firebase (https://firebase.google.com/)", + "description": "Generated SDK For default", + "license": "Apache-2.0", + "engines": { + "node": " >=18.0" + }, + "typings": "index.d.ts", + "module": "esm/index.esm.js", + "main": "index.cjs.js", + "browser": "esm/index.esm.js", + "exports": { + ".": { + "types": "./index.d.ts", + "require": "./index.cjs.js", + "default": "./esm/index.esm.js" + }, + "./package.json": "./package.json" + }, + "peerDependencies": { + "firebase": "^10.14.0 || ^11.3.0" + } +} \ No newline at end of file diff --git a/packages/data-connect/example-integration/dataconnect/connector/connector.yaml b/packages/data-connect/example-integration/dataconnect/connector/connector.yaml new file mode 100644 index 00000000000..b698515fe9f --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect/connector/connector.yaml @@ -0,0 +1,6 @@ +connectorId: default +generate: + javascriptSdk: + outputDir: ../../dataconnect-generated/js/default-connector + package: "@firebasegen/default-connector" +# packageJsonDir: ../.. diff --git a/packages/data-connect/example-integration/dataconnect/connector/mutations.gql b/packages/data-connect/example-integration/dataconnect/connector/mutations.gql new file mode 100644 index 00000000000..2379afeb89c --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect/connector/mutations.gql @@ -0,0 +1,33 @@ +# # Example mutations for a simple movie app + +# # Create a movie based on user input +mutation CreateMovie($title: String!, $genre: String!, $imageUrl: String!) +@auth(level: USER_EMAIL_VERIFIED) { + movie_insert(data: { title: $title, genre: $genre, imageUrl: $imageUrl }) +} + +# # Upsert (update or insert) a user's username based on their auth.uid +# mutation UpsertUser($username: String!) @auth(level: USER) { +# # The "auth.uid" server value ensures that users can only register their own user. +# user_upsert(data: { id_expr: "auth.uid", username: $username }) +# } + +# # Add a review for a movie +# mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!) +# @auth(level: USER) { +# review_upsert( +# data: { +# userId_expr: "auth.uid" +# movieId: $movieId +# rating: $rating +# reviewText: $reviewText +# # reviewDate defaults to today in the schema. No need to set it manually. +# } +# ) +# } + +# # Logged in user can delete their review for a movie +# mutation DeleteReview($movieId: UUID!) @auth(level: USER) { +# # The "auth.uid" server value ensures that users can only delete their own reviews. +# review_delete(key: { userId_expr: "auth.uid", movieId: $movieId }) +# } diff --git a/packages/data-connect/example-integration/dataconnect/connector/queries.gql b/packages/data-connect/example-integration/dataconnect/connector/queries.gql new file mode 100644 index 00000000000..cb1a6f630bc --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect/connector/queries.gql @@ -0,0 +1,78 @@ +# # Example queries for a simple movie app. + +# # @auth() directives control who can call each operation. +# # Anyone should be able to list all movies, so the auth level is set to PUBLIC +query ListMovies @auth(level: PUBLIC) { + movies { + id + title + imageUrl + genre + } +} + +# # List all users, only admins should be able to list all users, so we use NO_ACCESS +# query ListUsers @auth(level: NO_ACCESS) { +# users { +# id +# username +# } +# } + +# # Logged in users can list all their reviews and movie titles associated with the review +# # Since the query uses the uid of the current authenticated user, we set auth level to USER +# query ListUserReviews @auth(level: USER) { +# user(key: { id_expr: "auth.uid" }) { +# id +# username +# # _on_ makes it easy to grab info from another table +# # Here, we use it to grab all the reviews written by the user. +# reviews: reviews_on_user { +# rating +# reviewDate +# reviewText +# movie { +# id +# title +# } +# } +# } +# } + +# # Get movie by id +# query GetMovieById($id: UUID!) @auth(level: PUBLIC) { +# movie(id: $id) { +# id +# title +# imageUrl +# genre +# metadata: movieMetadata_on_movie { +# rating +# releaseYear +# description +# } +# reviews: reviews_on_movie { +# reviewText +# reviewDate +# rating +# user { +# id +# username +# } +# } +# } +# } + +# # Search for movies, actors, and reviews +# query SearchMovie($titleInput: String, $genre: String) @auth(level: PUBLIC) { +# movies( +# where: { +# _and: [{ genre: { eq: $genre } }, { title: { contains: $titleInput } }] +# } +# ) { +# id +# title +# genre +# imageUrl +# } +# } diff --git a/packages/data-connect/example-integration/dataconnect/dataconnect.yaml b/packages/data-connect/example-integration/dataconnect/dataconnect.yaml new file mode 100644 index 00000000000..623fad3e209 --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect/dataconnect.yaml @@ -0,0 +1,12 @@ +specVersion: "v1beta" +serviceId: "fdc-test" +location: "us-central1" +schema: + source: "./schema" + datasource: + postgresql: + database: "fdcdb" + cloudSql: + instanceId: "fdc-test-fdc" + # schemaValidation: "COMPATIBLE" +connectorDirs: ["./connector"] diff --git a/packages/data-connect/example-integration/dataconnect/schema/schema.gql b/packages/data-connect/example-integration/dataconnect/schema/schema.gql new file mode 100644 index 00000000000..f114d9a678a --- /dev/null +++ b/packages/data-connect/example-integration/dataconnect/schema/schema.gql @@ -0,0 +1,52 @@ +# # Example schema for simple movie review app + +# # User table is keyed by Firebase Auth UID. +# type User @table { +# # `@default(expr: "auth.uid")` sets it to Firebase Auth UID during insert and upsert. +# id: String! @default(expr: "auth.uid") +# username: String! @col(dataType: "varchar(50)") +# # The `user: User!` field in the Review table generates the following one-to-many query field. +# # reviews_on_user: [Review!]! +# # The `Review` join table the following many-to-many query field. +# # movies_via_Review: [Movie!]! +# } + +# # Movie is keyed by a randomly generated UUID. +type Movie @table { + # If you do not pass a 'key' to `@table`, Data Connect automatically adds the following 'id' column. + # Feel free to uncomment and customize it. + # id: UUID! @default(expr: "uuidV4()") + title: String! + imageUrl: String! + genre: String +} + +# # MovieMetadata is a metadata attached to a Movie. +# # Movie <-> MovieMetadata is a one-to-one relationship +# type MovieMetadata @table { +# # @unique ensures each Movie can only one MovieMetadata. +# movie: Movie! @unique +# # The movie field adds the following foreign key field. Feel free to uncomment and customize it. +# # movieId: UUID! +# rating: Float +# releaseYear: Int +# description: String +# } + +# # Reviews is a join table between User and Movie. +# # It has a composite primary keys `userUid` and `movieId`. +# # A user can leave reviews for many movies. A movie can have reviews from many users. +# # User <-> Review is a one-to-many relationship +# # Movie <-> Review is a one-to-many relationship +# # Movie <-> User is a many-to-many relationship +# type Review @table(name: "Reviews", key: ["movie", "user"]) { +# user: User! +# # The user field adds the following foreign key field. Feel free to uncomment and customize it. +# # userUid: String! +# movie: Movie! +# # The movie field adds the following foreign key field. Feel free to uncomment and customize it. +# # movieId: UUID! +# rating: Int +# reviewText: String +# reviewDate: Date! @default(expr: "request.time") +# } diff --git a/packages/data-connect/example-integration/dataconnect/test b/packages/data-connect/example-integration/dataconnect/test new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/data-connect/example-integration/firebase-js-config.json b/packages/data-connect/example-integration/firebase-js-config.json new file mode 100644 index 00000000000..0e0dcd235c4 --- /dev/null +++ b/packages/data-connect/example-integration/firebase-js-config.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/packages/data-connect/example-integration/firebase.json b/packages/data-connect/example-integration/firebase.json new file mode 100644 index 00000000000..6c9ad90b440 --- /dev/null +++ b/packages/data-connect/example-integration/firebase.json @@ -0,0 +1,10 @@ +{ + "emulators": { + "dataconnect": { + "dataDir": "dataconnect/.dataconnect/pgliteData" + } + }, + "dataconnect": { + "source": "dataconnect" + } +} diff --git a/packages/data-connect/example-integration/package.json b/packages/data-connect/example-integration/package.json new file mode 100644 index 00000000000..c530ffe0952 --- /dev/null +++ b/packages/data-connect/example-integration/package.json @@ -0,0 +1,22 @@ +{ + "name": "fdc-test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/node": "^22.13.14", + "ts-node": "^10.9.2", + "tslib": "^2.8.1", + "typescript": "^5.8.2" + }, + "dependencies": { + "firebase": "11.5.0" + } +} diff --git a/packages/data-connect/example-integration/test.ts b/packages/data-connect/example-integration/test.ts new file mode 100644 index 00000000000..86030405c15 --- /dev/null +++ b/packages/data-connect/example-integration/test.ts @@ -0,0 +1,7 @@ +import { listMovies } from './dataconnect-generated/js/default-connector'; +import * as json from './firebase-js-config.json'; +import { initializeApp } from 'firebase/app'; + +initializeApp(json); +listMovies(); + diff --git a/packages/data-connect/example-integration/testscript.sh b/packages/data-connect/example-integration/testscript.sh new file mode 100755 index 00000000000..6a56cb4d536 --- /dev/null +++ b/packages/data-connect/example-integration/testscript.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +statusResult=$(git status --porcelain | wc -l) +if [[ statusResult -eq "0" ]] +then + echo 'no changes found' +else + echo 'The workspace is modified:' + echo "$statusResult" +fi + diff --git a/packages/data-connect/example-integration/tsconfig.json b/packages/data-connect/example-integration/tsconfig.json new file mode 100644 index 00000000000..e3c427a3163 --- /dev/null +++ b/packages/data-connect/example-integration/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ES5", + "module": "CommonJS", + "resolveJsonModule": true, + "sourceMap": true, + "noEmit": true, + "skipLibCheck": false + } + } diff --git a/packages/data-connect/example-integration/yarn.lock b/packages/data-connect/example-integration/yarn.lock new file mode 100644 index 00000000000..cb23e2383e1 --- /dev/null +++ b/packages/data-connect/example-integration/yarn.lock @@ -0,0 +1,802 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@firebase/analytics-compat@0.2.18": + version "0.2.18" + resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.2.18.tgz#5ea9bdea188d4c91938f539af4c4414813ddc5c9" + integrity sha512-Hw9mzsSMZaQu6wrTbi3kYYwGw9nBqOHr47pVLxfr5v8CalsdrG5gfs9XUlPOZjHRVISp3oQrh1j7d3E+ulHPjQ== + dependencies: + "@firebase/analytics" "0.10.12" + "@firebase/analytics-types" "0.8.3" + "@firebase/component" "0.6.13" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/analytics-types@0.8.3": + version "0.8.3" + resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.8.3.tgz#d08cd39a6209693ca2039ba7a81570dfa6c1518f" + integrity sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg== + +"@firebase/analytics@0.10.12": + version "0.10.12" + resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.10.12.tgz#b49b9351b8cb19da007320a52932b953fff90d71" + integrity sha512-iDCGnw6qdFqwI5ywkgece99WADJNoymu+nLIQI4fZM/vCZ3bEo4wlpEetW71s1HqGpI0hQStiPhqVjFxDb2yyw== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/installations" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/app-check-compat@0.3.20": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.3.20.tgz#0dfce42699402f3b621be98857a8109b9397a37b" + integrity sha512-/twgmlnNAaZ/wbz3kcQrL/26b+X+zUX+lBmu5LwwEcWcpnb+mrVEAKhD7/ttm52dxYiSWtLDeuXy3FXBhqBC5A== + dependencies: + "@firebase/app-check" "0.8.13" + "@firebase/app-check-types" "0.5.3" + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/app-check-interop-types@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz#ed9c4a4f48d1395ef378f007476db3940aa5351a" + integrity sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A== + +"@firebase/app-check-types@0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@firebase/app-check-types/-/app-check-types-0.5.3.tgz#38ba954acf4bffe451581a32fffa20337f11d8e5" + integrity sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng== + +"@firebase/app-check@0.8.13": + version "0.8.13" + resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.8.13.tgz#20b212d0ea5b79c9492f434abc276d4f28b19371" + integrity sha512-ONsgml8/dplUOAP42JQO6hhiWDEwR9+RUTLenxAN9S8N6gel/sDQ9Ci721Py1oASMGdDU8v9R7xAZxzvOX5lPg== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/app-compat@0.2.52": + version "0.2.52" + resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.52.tgz#71ac4334c2dc841be3f101ab1f7d00412568a885" + integrity sha512-0p/l1KiwhwwYTcPWoleFQHftOnYzeXvyVf3WNZyKFBAoQMpCVW6bVm/uO1bXF91AwU1JN0og888Y6Sc8avqZ+A== + dependencies: + "@firebase/app" "0.11.3" + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/app-types@0.9.3": + version "0.9.3" + resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.3.tgz#8408219eae9b1fb74f86c24e7150a148460414ad" + integrity sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw== + +"@firebase/app@0.11.3": + version "0.11.3" + resolved "https://registry.npmjs.org/@firebase/app/-/app-0.11.3.tgz#80abcb65a1dce743d081022d2934fe69e60c1d41" + integrity sha512-QlTZl/RcqPSonYxB87n8KgAUW2L6ZZz0W4D91PVmQ1tJPsKsKPrWAFHL0ii2cQW6FxTxfNjbZ7kucuIcKXk3tw== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/auth-compat@0.5.19": + version "0.5.19" + resolved "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.19.tgz#6f393e85496754bfc4f31758bc0718a88f9c2f30" + integrity sha512-v898POphOIBJliKF76SiGOXh4EdhO5fM6S9a2ZKf/8wHdBea/qwxwZoVVya4DW6Mi7vWyp1lIzHbFgwRz8G9TA== + dependencies: + "@firebase/auth" "1.9.1" + "@firebase/auth-types" "0.13.0" + "@firebase/component" "0.6.13" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/auth-interop-types@0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz#176a08686b0685596ff03d7879b7e4115af53de0" + integrity sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA== + +"@firebase/auth-types@0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.13.0.tgz#ae6e0015e3bd4bfe18edd0942b48a0a118a098d9" + integrity sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg== + +"@firebase/auth@1.9.1": + version "1.9.1" + resolved "https://registry.npmjs.org/@firebase/auth/-/auth-1.9.1.tgz#5fca654e003a7fa0b3bbb247782633c3aab67ce4" + integrity sha512-9KKo5SNVkyJzftsW+daS+PGDbeJ+MFJWXQFHDqqPPH3acWHtiNnGHH5HGpIJErEELrsm9xMPie5zfZ0XpGU8+w== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/component@0.6.13": + version "0.6.13" + resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.6.13.tgz#6513379f1c09264133969d87282ce0d5bbbb2cd9" + integrity sha512-I/Eg1NpAtZ8AAfq8mpdfXnuUpcLxIDdCDtTzWSh+FXnp/9eCKJ3SNbOCKrUCyhLzNa2SiPJYruei0sxVjaOTeg== + dependencies: + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/data-connect@0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.2.tgz#8a74af2e111fe1a36d7bf37c55a7c2469e8a051f" + integrity sha512-PYG55JRTmvYrUuXXmYBsZexwKVP9aR3mIRRHxB9V2bQeRDZky6JtRZnH3GLhf4ZsxZy5Ewd8ul/jTOYR4gpD9w== + dependencies: + "@firebase/auth-interop-types" "0.2.4" + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/database-compat@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-2.0.5.tgz#110f612901995f9800f2435f58686e0c6f3d2544" + integrity sha512-CNf1UbvWh6qIaSf4sn6sx2DTDz/em/D7QxULH1LTxxDQHr9+CeYGvlAqrKnk4ZH0P0eIHyQFQU7RwkUJI0B9gQ== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/database" "1.0.14" + "@firebase/database-types" "1.0.10" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/database-types@1.0.10": + version "1.0.10" + resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-1.0.10.tgz#14cfed45bb06394cf1641e19265cbf90e4f6fb51" + integrity sha512-mH6RC1E9/Pv8jf1/p+M8YFTX+iu+iHDN89hecvyO7wHrI4R1V0TXjxOHvX3nLJN1sfh0CWG6CHZ0VlrSmK/cwg== + dependencies: + "@firebase/app-types" "0.9.3" + "@firebase/util" "1.11.0" + +"@firebase/database@1.0.14": + version "1.0.14" + resolved "https://registry.yarnpkg.com/@firebase/database/-/database-1.0.14.tgz#1d579b345c0f926eaddb7703051999489300c3bd" + integrity sha512-9nxYtkHAG02/Nh2Ssms1T4BbWPPjiwohCvkHDUl4hNxnki1kPgsLo5xe9kXNzbacOStmVys+RUXvwzynQSKmUQ== + dependencies: + "@firebase/app-check-interop-types" "0.3.3" + "@firebase/auth-interop-types" "0.2.4" + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + faye-websocket "0.11.4" + tslib "^2.1.0" + +"@firebase/firestore-compat@0.3.45": + version "0.3.45" + resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.3.45.tgz#93061f7d3644cd511749c9268d146e8c8c49a5de" + integrity sha512-uRvi7AYPmsDl7UZwPyV7jgDGYusEZ2+U2g7MndbQHKIA8fNHpYC6QrzMs58+/IjX+kF/lkUn67Vrr0AkVjlY+Q== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/firestore" "4.7.10" + "@firebase/firestore-types" "3.0.3" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/firestore-types@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-3.0.3.tgz#7d0c3dd8850c0193d8f5ee0cc8f11961407742c1" + integrity sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q== + +"@firebase/firestore@4.7.10": + version "4.7.10" + resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-4.7.10.tgz#6fe0cd31fcd7f4a8e13f9585f53e9300cf3114c0" + integrity sha512-6nKsyo2U+jYSCcSE5sjMdDNA23DMUvYPUvsYGg09CNvcTO8GGKsPs7SpOhspsB91mbacq+u627CDAx3FUhPSSQ== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + "@firebase/webchannel-wrapper" "1.0.3" + "@grpc/grpc-js" "~1.9.0" + "@grpc/proto-loader" "^0.7.8" + tslib "^2.1.0" + +"@firebase/functions-compat@0.3.20": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.3.20.tgz#addf89242be8b4d63feacb15ef27785e16c5e220" + integrity sha512-iIudmYDAML6n3c7uXO2YTlzra2/J6lnMzmJTXNthvrKVMgNMaseNoQP1wKfchK84hMuSF8EkM4AvufwbJ+Juew== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/functions" "0.12.3" + "@firebase/functions-types" "0.6.3" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/functions-types@0.6.3": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.6.3.tgz#f5faf770248b13f45d256f614230da6a11bfb654" + integrity sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg== + +"@firebase/functions@0.12.3": + version "0.12.3" + resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.12.3.tgz#b3e395aed1641d0d7169a22698c684a2745e02dd" + integrity sha512-Wv7JZMUkKLb1goOWRtsu3t7m97uK6XQvjQLPvn8rncY91+VgdU72crqnaYCDI/ophNuBEmuK8mn0/pAnjUeA6A== + dependencies: + "@firebase/app-check-interop-types" "0.3.3" + "@firebase/auth-interop-types" "0.2.4" + "@firebase/component" "0.6.13" + "@firebase/messaging-interop-types" "0.2.3" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/installations-compat@0.2.13": + version "0.2.13" + resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.13.tgz#0db0867ed58b782f7e2d142d9289a9eef1da24d5" + integrity sha512-f/o6MqCI7LD/ulY9gvgkv6w5k6diaReD8BFHd/y/fEdpsXmFWYS/g28GXCB72bRVBOgPpkOUNl+VsMvDwlRKmw== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/installations" "0.6.13" + "@firebase/installations-types" "0.5.3" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/installations-types@0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.5.3.tgz#cac8a14dd49f09174da9df8ae453f9b359c3ef2f" + integrity sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA== + +"@firebase/installations@0.6.13": + version "0.6.13" + resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.13.tgz#a2a00aebb5dfb74fae08600ea98cd2681211dd3c" + integrity sha512-6ZpkUiaygPFwgVneYxuuOuHnSPnTA4KefLEaw/sKk/rNYgC7X6twaGfYb0sYLpbi9xV4i5jXsqZ3WO+yaguNgg== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/util" "1.11.0" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/logger@0.4.4": + version "0.4.4" + resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.4.4.tgz#29e8379d20fd1149349a195ee6deee4573a86f48" + integrity sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g== + dependencies: + tslib "^2.1.0" + +"@firebase/messaging-compat@0.2.17": + version "0.2.17" + resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.17.tgz#fc223495319fe3784347dea77094b6e03548647d" + integrity sha512-5Q+9IG7FuedusdWHVQRjpA3OVD9KUWp/IPegcv0s5qSqRLBjib7FlAeWxN+VL0Ew43tuPJBY2HKhEecuizmO1Q== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/messaging" "0.12.17" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/messaging-interop-types@0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz#e647c9cd1beecfe6a6e82018a6eec37555e4da3e" + integrity sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q== + +"@firebase/messaging@0.12.17": + version "0.12.17" + resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.17.tgz#41eaeee70a89136715a4f7cb2b1a602423fc44ec" + integrity sha512-W3CnGhTm6Nx8XGb6E5/+jZTuxX/EK8Vur4QXvO1DwZta/t0xqWMRgO9vNsZFMYBqFV4o3j4F9qK/iddGYwWS6g== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/installations" "0.6.13" + "@firebase/messaging-interop-types" "0.2.3" + "@firebase/util" "1.11.0" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/performance-compat@0.2.15": + version "0.2.15" + resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.15.tgz#4e5034add63917cb6357938126e9e6562d0e7208" + integrity sha512-wUxsw7hGBEMN6XfvYQqwPIQp5LcJXawWM5tmYp6L7ClCoTQuEiCKHWWVurJgN8Q1YHzoHVgjNfPQAOVu29iMVg== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/performance" "0.7.2" + "@firebase/performance-types" "0.2.3" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/performance-types@0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.2.3.tgz#5ce64e90fa20ab5561f8b62a305010cf9fab86fb" + integrity sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ== + +"@firebase/performance@0.7.2": + version "0.7.2" + resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.7.2.tgz#e30ee3e3c120c53f48bde7bdd915687f1e3b27e1" + integrity sha512-DXLLp0R0jdxH/yTmv+WTkOzsLl8YYecXh4lGZE0dzqC0IV8k+AxpLSSWvOTCkAETze8yEU/iF+PtgYVlGjfMMQ== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/installations" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + web-vitals "^4.2.4" + +"@firebase/remote-config-compat@0.2.13": + version "0.2.13" + resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.13.tgz#4a35c2c6bb582d96aecc45da18f5094359cb5361" + integrity sha512-UmHoO7TxAEJPIZf8e1Hy6CeFGMeyjqSCpgoBkQZYXFI2JHhzxIyDpr8jVKJJN1dmAePKZ5EX7dC13CmcdTOl7Q== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/remote-config" "0.6.0" + "@firebase/remote-config-types" "0.4.0" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/remote-config-types@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz#91b9a836d5ca30ced68c1516163b281fbb544537" + integrity sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg== + +"@firebase/remote-config@0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.6.0.tgz#24a6966a4d092260983ba8597cc039f5795cd35f" + integrity sha512-Yrk4l5+6FJLPHC6irNHMzgTtJ3NfHXlAXVChCBdNFtgmzyGmufNs/sr8oA0auEfIJ5VpXCaThRh3P4OdQxiAlQ== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/installations" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/storage-compat@0.3.17": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.3.17.tgz#67f6bbc498971e6e404e0ea660fa5df81c5ba5ea" + integrity sha512-CBlODWEZ5b6MJWVh21VZioxwxNwVfPA9CAdsk+ZgVocJQQbE2oDW1XJoRcgthRY1HOitgbn4cVrM+NlQtuUYhw== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/storage" "0.13.7" + "@firebase/storage-types" "0.8.3" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/storage-types@0.8.3": + version "0.8.3" + resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.8.3.tgz#2531ef593a3452fc12c59117195d6485c6632d3d" + integrity sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg== + +"@firebase/storage@0.13.7": + version "0.13.7" + resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.13.7.tgz#809fc23685ad9ba8fdfb3bc758e3353867c9e796" + integrity sha512-FkRyc24rK+Y6EaQ1tYFm3TevBnnfSNA0VyTfew2hrYyL/aYfatBg7HOgktUdB4kWMHNA9VoTotzZTGoLuK92wg== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/util@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.11.0.tgz#e74ee2dc260ec4f9e75fe5d52bc4b0254d9872a9" + integrity sha512-PzSrhIr++KI6y4P6C/IdgBNMkEx0Ex6554/cYd0Hm+ovyFSJtJXqb/3OSIdnBoa2cpwZT1/GW56EmRc5qEc5fQ== + dependencies: + tslib "^2.1.0" + +"@firebase/vertexai@1.2.0": + version "1.2.0" + resolved "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.2.0.tgz#8f8a4ae75284c3067c0a06c7d0bef922571e6dd7" + integrity sha512-WUYIzFpOipjFXT2i0hT26wivJoIximizQptVs3KAxFAqbVlO8sjKPsMkgz0bh+tdKlqP4SUDda71fMUZXUKHgA== + dependencies: + "@firebase/app-check-interop-types" "0.3.3" + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + +"@firebase/webchannel-wrapper@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz#a73bab8eb491d7b8b7be2f0e6c310647835afe83" + integrity sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ== + +"@grpc/grpc-js@~1.9.0": + version "1.9.15" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.15.tgz#433d7ac19b1754af690ea650ab72190bd700739b" + integrity sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ== + dependencies: + "@grpc/proto-loader" "^0.7.8" + "@types/node" ">=12.12.47" + +"@grpc/proto-loader@^0.7.8": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" + integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@^22.13.14": + version "22.14.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.14.0.tgz#d3bfa3936fef0dbacd79ea3eb17d521c628bb47e" + integrity sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA== + dependencies: + undici-types "~6.21.0" + +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.4.1: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +faye-websocket@0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +firebase@11.5.0: + version "11.5.0" + resolved "https://registry.npmjs.org/firebase/-/firebase-11.5.0.tgz#9a358ed8c7e805de8df64061840b2593ae706165" + integrity sha512-ZTpO/zD5nYqY02bGpXCg1dRNLggTXPQZdLQeSeur3jYH270p1QkAZZJsm/lrKZ2W4ZjBlafTxxs4OwN38Vyocw== + dependencies: + "@firebase/analytics" "0.10.12" + "@firebase/analytics-compat" "0.2.18" + "@firebase/app" "0.11.3" + "@firebase/app-check" "0.8.13" + "@firebase/app-check-compat" "0.3.20" + "@firebase/app-compat" "0.2.52" + "@firebase/app-types" "0.9.3" + "@firebase/auth" "1.9.1" + "@firebase/auth-compat" "0.5.19" + "@firebase/data-connect" "0.3.2" + "@firebase/database" "1.0.14" + "@firebase/database-compat" "2.0.5" + "@firebase/firestore" "4.7.10" + "@firebase/firestore-compat" "0.3.45" + "@firebase/functions" "0.12.3" + "@firebase/functions-compat" "0.3.20" + "@firebase/installations" "0.6.13" + "@firebase/installations-compat" "0.2.13" + "@firebase/messaging" "0.12.17" + "@firebase/messaging-compat" "0.2.17" + "@firebase/performance" "0.7.2" + "@firebase/performance-compat" "0.2.15" + "@firebase/remote-config" "0.6.0" + "@firebase/remote-config-compat" "0.2.13" + "@firebase/storage" "0.13.7" + "@firebase/storage-compat" "0.3.17" + "@firebase/util" "1.11.0" + "@firebase/vertexai" "1.2.0" + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +http-parser-js@>=0.5.1: + version "0.5.9" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.9.tgz#b817b3ca0edea6236225000d795378707c169cec" + integrity sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw== + +idb@7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" + integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +long@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.1.tgz#9d4222d3213f38a5ec809674834e0f0ab21abe96" + integrity sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng== + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +protobufjs@^7.2.5: + version "7.4.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.4.0.tgz#7efe324ce9b3b61c82aae5de810d287bc08a248a" + integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +safe-buffer@>=5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@^2.1.0, tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +typescript@^5.8.2: + version "5.8.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4" + integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ== + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +web-vitals@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.4.tgz#1d20bc8590a37769bd0902b289550936069184b7" + integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw== + +websocket-driver@>=0.5.1: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== From 37d0f189795071ceba6de013054a25a863033a3b Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 11 Apr 2025 14:34:15 -0700 Subject: [PATCH 02/67] Fixed formatting --- .../js/default-connector/esm/index.esm.js | 35 ++++++++++-- .../js/default-connector/index.cjs.js | 38 +++++++++++-- .../js/default-connector/index.d.ts | 54 +++++++++++++++---- .../data-connect/example-integration/test.ts | 18 ++++++- 4 files changed, 126 insertions(+), 19 deletions(-) diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js index 28675a48069..e88d2d56d35 100644 --- a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js +++ b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js @@ -1,4 +1,27 @@ -import { queryRef, executeQuery, mutationRef, executeMutation, validateArgs } from 'firebase/data-connect'; +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + queryRef, + executeQuery, + mutationRef, + executeMutation, + validateArgs +} from 'firebase/data-connect'; export const connectorConfig = { connector: 'default', @@ -7,7 +30,12 @@ export const connectorConfig = { }; export function createMovieRef(dcOrVars, vars) { - const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true); + const { dc: dcInstance, vars: inputVars } = validateArgs( + connectorConfig, + dcOrVars, + vars, + true + ); dcInstance._useGeneratedSdk(); return mutationRef(dcInstance, 'CreateMovie', inputVars); } @@ -17,7 +45,7 @@ export function createMovie(dcOrVars, vars) { } export function listMoviesRef(dc) { - const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined); + const { dc: dcInstance } = validateArgs(connectorConfig, dc, undefined); dcInstance._useGeneratedSdk(); return queryRef(dcInstance, 'ListMovies'); } @@ -25,4 +53,3 @@ export function listMoviesRef(dc) { export function listMovies(dc) { return executeQuery(listMoviesRef(dc)); } - diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js index 7f8250f2599..814406ff090 100644 --- a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js +++ b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js @@ -1,4 +1,27 @@ -const { queryRef, executeQuery, mutationRef, executeMutation, validateArgs } = require('firebase/data-connect'); +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const { + queryRef, + executeQuery, + mutationRef, + executeMutation, + validateArgs +} = require('firebase/data-connect'); const connectorConfig = { connector: 'default', @@ -8,20 +31,25 @@ const connectorConfig = { exports.connectorConfig = connectorConfig; exports.createMovieRef = function createMovieRef(dcOrVars, vars) { - const { dc: dcInstance, vars: inputVars} = validateArgs(connectorConfig, dcOrVars, vars, true); + const { dc: dcInstance, vars: inputVars } = validateArgs( + connectorConfig, + dcOrVars, + vars, + true + ); dcInstance._useGeneratedSdk(); return mutationRef(dcInstance, 'CreateMovie', inputVars); -} +}; exports.createMovie = function createMovie(dcOrVars, vars) { return executeMutation(createMovieRef(dcOrVars, vars)); }; exports.listMoviesRef = function listMoviesRef(dc) { - const { dc: dcInstance} = validateArgs(connectorConfig, dc, undefined); + const { dc: dcInstance } = validateArgs(connectorConfig, dc, undefined); dcInstance._useGeneratedSdk(); return queryRef(dcInstance, 'ListMovies'); -} +}; exports.listMovies = function listMovies(dc) { return executeQuery(listMoviesRef(dc)); diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts index 5d821c79cc9..474fefd0f4b 100644 --- a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts +++ b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts @@ -1,4 +1,28 @@ -import { ConnectorConfig, DataConnect, QueryRef, QueryPromise, MutationRef, MutationPromise } from 'firebase/data-connect'; +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ConnectorConfig, + DataConnect, + QueryRef, + QueryPromise, + MutationRef, + MutationPromise +} from 'firebase/data-connect'; export const connectorConfig: ConnectorConfig; @@ -7,7 +31,6 @@ export type UUIDString = string; export type Int64String = string; export type DateString = string; - export interface CreateMovieData { movie_insert: Movie_Key; } @@ -33,18 +56,31 @@ export interface Movie_Key { } /* Allow users to create refs without passing in DataConnect */ -export function createMovieRef(vars: CreateMovieVariables): MutationRef; +export function createMovieRef( + vars: CreateMovieVariables +): MutationRef; /* Allow users to pass in custom DataConnect instances */ -export function createMovieRef(dc: DataConnect, vars: CreateMovieVariables): MutationRef; +export function createMovieRef( + dc: DataConnect, + vars: CreateMovieVariables +): MutationRef; -export function createMovie(vars: CreateMovieVariables): MutationPromise; -export function createMovie(dc: DataConnect, vars: CreateMovieVariables): MutationPromise; +export function createMovie( + vars: CreateMovieVariables +): MutationPromise; +export function createMovie( + dc: DataConnect, + vars: CreateMovieVariables +): MutationPromise; /* Allow users to create refs without passing in DataConnect */ export function listMoviesRef(): QueryRef; /* Allow users to pass in custom DataConnect instances */ -export function listMoviesRef(dc: DataConnect): QueryRef; +export function listMoviesRef( + dc: DataConnect +): QueryRef; export function listMovies(): QueryPromise; -export function listMovies(dc: DataConnect): QueryPromise; - +export function listMovies( + dc: DataConnect +): QueryPromise; diff --git a/packages/data-connect/example-integration/test.ts b/packages/data-connect/example-integration/test.ts index 86030405c15..cc177b8e47c 100644 --- a/packages/data-connect/example-integration/test.ts +++ b/packages/data-connect/example-integration/test.ts @@ -1,7 +1,23 @@ +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { listMovies } from './dataconnect-generated/js/default-connector'; import * as json from './firebase-js-config.json'; import { initializeApp } from 'firebase/app'; initializeApp(json); listMovies(); - From a4d7813ef59e2514c9f0c5802c76ceb5ac94bab0 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 11 Apr 2025 14:42:56 -0700 Subject: [PATCH 03/67] Fix linting --- packages/data-connect/.eslintrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/data-connect/.eslintrc.js b/packages/data-connect/.eslintrc.js index faef63a0395..a6d8d8c7c84 100644 --- a/packages/data-connect/.eslintrc.js +++ b/packages/data-connect/.eslintrc.js @@ -24,7 +24,7 @@ module.exports = { tsconfigRootDir: __dirname }, plugins: ['import'], - ignorePatterns: ['compat/*'], + ignorePatterns: ['compat/*', 'example-integration/*'], rules: { 'no-console': ['error', { allow: ['warn', 'error'] }], '@typescript-eslint/no-unused-vars': [ From 170b15a624b151880c7c5e37b5fb006a55325da0 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 11 Apr 2025 14:47:03 -0700 Subject: [PATCH 04/67] Excluded example integration from tsconfig --- packages/data-connect/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/data-connect/tsconfig.json b/packages/data-connect/tsconfig.json index 58561f50f5d..ba35aaa2516 100644 --- a/packages/data-connect/tsconfig.json +++ b/packages/data-connect/tsconfig.json @@ -4,5 +4,5 @@ "outDir": "dist", "strict": false }, - "exclude": ["dist/**/*", "test/**/*"] + "exclude": ["dist/**/*", "test/**/*", "example-integration/**/*"] } From ec405ae24325adecb340785c34e81f5c65001bd7 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 11 Apr 2025 14:57:06 -0700 Subject: [PATCH 05/67] Fixed example-integration package.json --- packages/data-connect/example-integration/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/data-connect/example-integration/package.json b/packages/data-connect/example-integration/package.json index c530ffe0952..4cfd55079dc 100644 --- a/packages/data-connect/example-integration/package.json +++ b/packages/data-connect/example-integration/package.json @@ -2,7 +2,6 @@ "name": "fdc-test", "version": "1.0.0", "description": "", - "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "tsc" From 248f6547ea990ed52ac8702622e310dc9f98495e Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 23 Apr 2025 10:43:38 -0700 Subject: [PATCH 06/67] Added ssl check for firestore --- packages/firestore/src/lite-api/database.ts | 7 ++++++- packages/firestore/test/unit/api/database.test.ts | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index 9a68e2a86d6..5c344fb72c6 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -325,6 +325,11 @@ export function connectFirestoreEmulator( } = {} ): void { firestore = cast(firestore, Firestore); + let ssl = false; + if (/^https:\/\//.test(host)) { + ssl = true; + host = host.substring(8); + } const settings = firestore._getSettings(); const existingConfig = { ...settings, @@ -340,7 +345,7 @@ export function connectFirestoreEmulator( const newConfig = { ...settings, host: newHostSetting, - ssl: false, + ssl, emulatorOptions: options }; // No-op if the new configuration matches the current configuration. This supports SSR diff --git a/packages/firestore/test/unit/api/database.test.ts b/packages/firestore/test/unit/api/database.test.ts index 1cc1df51063..8d05c039e0e 100644 --- a/packages/firestore/test/unit/api/database.test.ts +++ b/packages/firestore/test/unit/api/database.test.ts @@ -564,6 +564,17 @@ describe('Settings', () => { expect(db._getEmulatorOptions()).to.equal(emulatorOptions); }); + it('sets ssl to true if prefixed with https://', () => { + // Use a new instance of Firestore in order to configure settings. + const db = newTestFirestore(); + const emulatorOptions = { mockUserToken: 'test' }; + connectFirestoreEmulator(db, 'https://127.0.0.1', 9000, emulatorOptions); + + expect(db._getSettings().host).to.exist.and.to.equal('127.0.0.1:9000'); + expect(db._getSettings().ssl).to.exist.and.to.be.true; + expect(db._getEmulatorOptions()).to.equal(emulatorOptions); + }); + it('prefers host from useEmulator to host from settings', () => { // Use a new instance of Firestore in order to configure settings. const db = newTestFirestore(); From 14ef1bcc5c43d3cefa07e7f686043f3fbcf550e2 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 23 Apr 2025 11:07:56 -0700 Subject: [PATCH 07/67] Added ssl checks for RTDB --- packages/database-compat/test/database.test.ts | 16 ++++++++++++++++ packages/database/src/api/Database.ts | 15 +++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/database-compat/test/database.test.ts b/packages/database-compat/test/database.test.ts index fa21058591f..95b3b0a9b87 100644 --- a/packages/database-compat/test/database.test.ts +++ b/packages/database-compat/test/database.test.ts @@ -292,6 +292,22 @@ describe('Database Tests', () => { expect((db as any)._delegate._repo.repoInfo_.isUsingEmulator).to.be.false; }); + it('uses ssl when useEmulator is called with https is specified', () => { + const db = firebase.database(); + db.useEmulator('https://localhost', 80); + expect((db as any)._delegate._repo.repoInfo_.isUsingEmulator).to.be.true; + expect((db as any)._delegate._repo.repoInfo_.host).to.equal('localhost:80'); + expect((db as any)._delegate._repo.repoInfo_.secure).to.be.true; + }); + + it('uses ssl when useEmulator is called with wss is specified', () => { + const db = firebase.database(); + db.useEmulator('wss://localhost', 80); + expect((db as any)._delegate._repo.repoInfo_.isUsingEmulator).to.be.true; + expect((db as any)._delegate._repo.repoInfo_.host).to.equal('localhost:80'); + expect((db as any)._delegate._repo.repoInfo_.secure).to.be.true; + }); + it('cannot call useEmulator after use', () => { const db = (firebase as any).database(); diff --git a/packages/database/src/api/Database.ts b/packages/database/src/api/Database.ts index 32fd4674a44..60c6148f77e 100644 --- a/packages/database/src/api/Database.ts +++ b/packages/database/src/api/Database.ts @@ -89,9 +89,19 @@ function repoManagerApplyEmulatorSettings( emulatorOptions: RepoInfoEmulatorOptions, tokenProvider?: AuthTokenProvider ): void { + let ssl = false; + let finalHost = hostAndPort; + if (/^https:\/\//.test(finalHost)) { + ssl = true; + finalHost = finalHost.substring(8); + } + if (/^wss:\/\//.test(finalHost)) { + ssl = true; + finalHost = finalHost.substring(6); + } repo.repoInfo_ = new RepoInfo( - hostAndPort, - /* secure= */ false, + finalHost, + /* secure= */ ssl, repo.repoInfo_.namespace, repo.repoInfo_.webSocketOnly, repo.repoInfo_.nodeAdmin, @@ -352,6 +362,7 @@ export function connectDatabaseEmulator( ): void { db = getModularInstance(db); db._checkNotDeleted('useEmulator'); + const hostAndPort = `${host}:${port}`; const repo = db._repoInternal; if (db._instanceStarted) { From df4a1158c4e5f7bf375c23798b7652c37a3806a2 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 23 Apr 2025 11:11:37 -0700 Subject: [PATCH 08/67] Removed unnecessary files --- .../js/default-connector/README.md | 257 ------ .../js/default-connector/esm/index.esm.js | 55 -- .../js/default-connector/esm/package.json | 1 - .../js/default-connector/index.cjs.js | 56 -- .../js/default-connector/index.d.ts | 86 -- .../js/default-connector/package.json | 25 - .../dataconnect/connector/connector.yaml | 6 - .../dataconnect/connector/mutations.gql | 33 - .../dataconnect/connector/queries.gql | 78 -- .../dataconnect/dataconnect.yaml | 12 - .../dataconnect/schema/schema.gql | 52 -- .../example-integration/dataconnect/test | 0 .../firebase-js-config.json | 3 - .../example-integration/firebase.json | 10 - .../example-integration/package.json | 21 - .../data-connect/example-integration/test.ts | 23 - .../example-integration/testscript.sh | 11 - .../example-integration/tsconfig.json | 10 - .../example-integration/yarn.lock | 802 ------------------ 19 files changed, 1541 deletions(-) delete mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/README.md delete mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js delete mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/package.json delete mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js delete mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts delete mode 100644 packages/data-connect/example-integration/dataconnect-generated/js/default-connector/package.json delete mode 100644 packages/data-connect/example-integration/dataconnect/connector/connector.yaml delete mode 100644 packages/data-connect/example-integration/dataconnect/connector/mutations.gql delete mode 100644 packages/data-connect/example-integration/dataconnect/connector/queries.gql delete mode 100644 packages/data-connect/example-integration/dataconnect/dataconnect.yaml delete mode 100644 packages/data-connect/example-integration/dataconnect/schema/schema.gql delete mode 100644 packages/data-connect/example-integration/dataconnect/test delete mode 100644 packages/data-connect/example-integration/firebase-js-config.json delete mode 100644 packages/data-connect/example-integration/firebase.json delete mode 100644 packages/data-connect/example-integration/package.json delete mode 100644 packages/data-connect/example-integration/test.ts delete mode 100755 packages/data-connect/example-integration/testscript.sh delete mode 100644 packages/data-connect/example-integration/tsconfig.json delete mode 100644 packages/data-connect/example-integration/yarn.lock diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/README.md b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/README.md deleted file mode 100644 index b3f5971d704..00000000000 --- a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/README.md +++ /dev/null @@ -1,257 +0,0 @@ -# Table of Contents -- [**Overview**](#generated-typescript-readme) -- [**Accessing the connector**](#accessing-the-connector) - - [*Connecting to the local Emulator*](#connecting-to-the-local-emulator) -- [**Queries**](#queries) - - [*ListMovies*](#listmovies) -- [**Mutations**](#mutations) - - [*CreateMovie*](#createmovie) - -# Generated TypeScript README -This README will guide you through the process of using the generated TypeScript SDK package for the connector `default`. It will also provide examples on how to use your generated SDK to call your Data Connect queries and mutations. - -***NOTE:** This README is generated alongside the generated SDK. If you make changes to this file, they will be overwritten when the SDK is regenerated.* - -You can use this generated SDK by importing from the package `@firebasegen/default-connector` as shown below. Both CommonJS and ESM imports are supported. - -You can also follow the instructions from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#set-client). - -# Accessing the connector -A connector is a collection of Queries and Mutations. One SDK is generated for each connector - this SDK is generated for the connector `default`. - -You can find more information about connectors in the [Data Connect documentation](https://firebase.google.com/docs/data-connect#how-does). - -```javascript -import { getDataConnect } from 'firebase/data-connect'; -import { connectorConfig } from '@firebasegen/default-connector'; - -const dataConnect = getDataConnect(connectorConfig); -``` - -## Connecting to the local Emulator -By default, the connector will connect to the production service. - -To connect to the emulator, you can use the following code. -You can also follow the emulator instructions from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#instrument-clients). - -```javascript -import { connectDataConnectEmulator, getDataConnect } from 'firebase/data-connect'; -import { connectorConfig } from '@firebasegen/default-connector'; - -const dataConnect = getDataConnect(connectorConfig); -connectDataConnectEmulator(dataConnect, 'localhost', 9399); -``` - -After it's initialized, you can call your Data Connect [queries](#queries) and [mutations](#mutations) from your generated SDK. - -# Queries - -There are two ways to execute a Data Connect Query using the generated Web SDK: -- Using a Query Reference function, which returns a `QueryRef` - - The `QueryRef` can be used as an argument to `executeQuery()`, which will execute the Query and return a `QueryPromise` -- Using an action shortcut function, which returns a `QueryPromise` - - Calling the action shortcut function will execute the Query and return a `QueryPromise` - -The following is true for both the action shortcut function and the `QueryRef` function: -- The `QueryPromise` returned will resolve to the result of the Query once it has finished executing -- If the Query accepts arguments, both the action shortcut function and the `QueryRef` function accept a single argument: an object that contains all the required variables (and the optional variables) for the Query -- Both functions can be called with or without passing in a `DataConnect` instance as an argument. If no `DataConnect` argument is passed in, then the generated SDK will call `getDataConnect(connectorConfig)` behind the scenes for you. - -Below are examples of how to use the `default` connector's generated functions to execute each query. You can also follow the examples from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#using-queries). - -## ListMovies -You can execute the `ListMovies` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [default-connector/index.d.ts](./index.d.ts): -```javascript -listMovies(): QueryPromise; - -listMoviesRef(): QueryRef; -``` -You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function. -```javascript -listMovies(dc: DataConnect): QueryPromise; - -listMoviesRef(dc: DataConnect): QueryRef; -``` - -### Variables -The `ListMovies` query has no variables. -### Return Type -Recall that executing the `ListMovies` query returns a `QueryPromise` that resolves to an object with a `data` property. - -The `data` property is an object of type `ListMoviesData`, which is defined in [default-connector/index.d.ts](./index.d.ts). It has the following fields: -```javascript -export interface ListMoviesData { - movies: ({ - id: UUIDString; - title: string; - imageUrl: string; - genre?: string | null; - } & Movie_Key)[]; -} -``` -### Using `ListMovies`'s action shortcut function - -```javascript -import { getDataConnect } from 'firebase/data-connect'; -import { connectorConfig, listMovies } from '@firebasegen/default-connector'; - - -// Call the `listMovies()` function to execute the query. -// You can use the `await` keyword to wait for the promise to resolve. -const { data } = await listMovies(); - -// You can also pass in a `DataConnect` instance to the action shortcut function. -const dataConnect = getDataConnect(connectorConfig); -const { data } = await listMovies(dataConnect); - -console.log(data.movies); - -// Or, you can use the `Promise` API. -listMovies().then((response) => { - const data = response.data; - console.log(data.movies); -}); -``` - -### Using `ListMovies`'s `QueryRef` function - -```javascript -import { getDataConnect, executeQuery } from 'firebase/data-connect'; -import { connectorConfig, listMoviesRef } from '@firebasegen/default-connector'; - - -// Call the `listMoviesRef()` function to get a reference to the query. -const ref = listMoviesRef(); - -// You can also pass in a `DataConnect` instance to the `QueryRef` function. -const dataConnect = getDataConnect(connectorConfig); -const ref = listMoviesRef(dataConnect); - -// Call `executeQuery()` on the reference to execute the query. -// You can use the `await` keyword to wait for the promise to resolve. -const { data } = await executeQuery(ref); - -console.log(data.movies); - -// Or, you can use the `Promise` API. -executeQuery(ref).then((response) => { - const data = response.data; - console.log(data.movies); -}); -``` - -# Mutations - -There are two ways to execute a Data Connect Mutation using the generated Web SDK: -- Using a Mutation Reference function, which returns a `MutationRef` - - The `MutationRef` can be used as an argument to `executeMutation()`, which will execute the Mutation and return a `MutationPromise` -- Using an action shortcut function, which returns a `MutationPromise` - - Calling the action shortcut function will execute the Mutation and return a `MutationPromise` - -The following is true for both the action shortcut function and the `MutationRef` function: -- The `MutationPromise` returned will resolve to the result of the Mutation once it has finished executing -- If the Mutation accepts arguments, both the action shortcut function and the `MutationRef` function accept a single argument: an object that contains all the required variables (and the optional variables) for the Mutation -- Both functions can be called with or without passing in a `DataConnect` instance as an argument. If no `DataConnect` argument is passed in, then the generated SDK will call `getDataConnect(connectorConfig)` behind the scenes for you. - -Below are examples of how to use the `default` connector's generated functions to execute each mutation. You can also follow the examples from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#using-mutations). - -## CreateMovie -You can execute the `CreateMovie` mutation using the following action shortcut function, or by calling `executeMutation()` after calling the following `MutationRef` function, both of which are defined in [default-connector/index.d.ts](./index.d.ts): -```javascript -createMovie(vars: CreateMovieVariables): MutationPromise; - -createMovieRef(vars: CreateMovieVariables): MutationRef; -``` -You can also pass in a `DataConnect` instance to the action shortcut function or `MutationRef` function. -```javascript -createMovie(dc: DataConnect, vars: CreateMovieVariables): MutationPromise; - -createMovieRef(dc: DataConnect, vars: CreateMovieVariables): MutationRef; -``` - -### Variables -The `CreateMovie` mutation requires an argument of type `CreateMovieVariables`, which is defined in [default-connector/index.d.ts](./index.d.ts). It has the following fields: - -```javascript -export interface CreateMovieVariables { - title: string; - genre: string; - imageUrl: string; -} -``` -### Return Type -Recall that executing the `CreateMovie` mutation returns a `MutationPromise` that resolves to an object with a `data` property. - -The `data` property is an object of type `CreateMovieData`, which is defined in [default-connector/index.d.ts](./index.d.ts). It has the following fields: -```javascript -export interface CreateMovieData { - movie_insert: Movie_Key; -} -``` -### Using `CreateMovie`'s action shortcut function - -```javascript -import { getDataConnect } from 'firebase/data-connect'; -import { connectorConfig, createMovie, CreateMovieVariables } from '@firebasegen/default-connector'; - -// The `CreateMovie` mutation requires an argument of type `CreateMovieVariables`: -const createMovieVars: CreateMovieVariables = { - title: ..., - genre: ..., - imageUrl: ..., -}; - -// Call the `createMovie()` function to execute the mutation. -// You can use the `await` keyword to wait for the promise to resolve. -const { data } = await createMovie(createMovieVars); -// Variables can be defined inline as well. -const { data } = await createMovie({ title: ..., genre: ..., imageUrl: ..., }); - -// You can also pass in a `DataConnect` instance to the action shortcut function. -const dataConnect = getDataConnect(connectorConfig); -const { data } = await createMovie(dataConnect, createMovieVars); - -console.log(data.movie_insert); - -// Or, you can use the `Promise` API. -createMovie(createMovieVars).then((response) => { - const data = response.data; - console.log(data.movie_insert); -}); -``` - -### Using `CreateMovie`'s `MutationRef` function - -```javascript -import { getDataConnect, executeMutation } from 'firebase/data-connect'; -import { connectorConfig, createMovieRef, CreateMovieVariables } from '@firebasegen/default-connector'; - -// The `CreateMovie` mutation requires an argument of type `CreateMovieVariables`: -const createMovieVars: CreateMovieVariables = { - title: ..., - genre: ..., - imageUrl: ..., -}; - -// Call the `createMovieRef()` function to get a reference to the mutation. -const ref = createMovieRef(createMovieVars); -// Variables can be defined inline as well. -const ref = createMovieRef({ title: ..., genre: ..., imageUrl: ..., }); - -// You can also pass in a `DataConnect` instance to the `MutationRef` function. -const dataConnect = getDataConnect(connectorConfig); -const ref = createMovieRef(dataConnect, createMovieVars); - -// Call `executeMutation()` on the reference to execute the mutation. -// You can use the `await` keyword to wait for the promise to resolve. -const { data } = await executeMutation(ref); - -console.log(data.movie_insert); - -// Or, you can use the `Promise` API. -executeMutation(ref).then((response) => { - const data = response.data; - console.log(data.movie_insert); -}); -``` - diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js deleted file mode 100644 index e88d2d56d35..00000000000 --- a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/index.esm.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - queryRef, - executeQuery, - mutationRef, - executeMutation, - validateArgs -} from 'firebase/data-connect'; - -export const connectorConfig = { - connector: 'default', - service: 'fdc-test', - location: 'us-central1' -}; - -export function createMovieRef(dcOrVars, vars) { - const { dc: dcInstance, vars: inputVars } = validateArgs( - connectorConfig, - dcOrVars, - vars, - true - ); - dcInstance._useGeneratedSdk(); - return mutationRef(dcInstance, 'CreateMovie', inputVars); -} - -export function createMovie(dcOrVars, vars) { - return executeMutation(createMovieRef(dcOrVars, vars)); -} - -export function listMoviesRef(dc) { - const { dc: dcInstance } = validateArgs(connectorConfig, dc, undefined); - dcInstance._useGeneratedSdk(); - return queryRef(dcInstance, 'ListMovies'); -} - -export function listMovies(dc) { - return executeQuery(listMoviesRef(dc)); -} diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/package.json b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/package.json deleted file mode 100644 index 7c34deb5837..00000000000 --- a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/esm/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"module"} \ No newline at end of file diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js deleted file mode 100644 index 814406ff090..00000000000 --- a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.cjs.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const { - queryRef, - executeQuery, - mutationRef, - executeMutation, - validateArgs -} = require('firebase/data-connect'); - -const connectorConfig = { - connector: 'default', - service: 'fdc-test', - location: 'us-central1' -}; -exports.connectorConfig = connectorConfig; - -exports.createMovieRef = function createMovieRef(dcOrVars, vars) { - const { dc: dcInstance, vars: inputVars } = validateArgs( - connectorConfig, - dcOrVars, - vars, - true - ); - dcInstance._useGeneratedSdk(); - return mutationRef(dcInstance, 'CreateMovie', inputVars); -}; - -exports.createMovie = function createMovie(dcOrVars, vars) { - return executeMutation(createMovieRef(dcOrVars, vars)); -}; - -exports.listMoviesRef = function listMoviesRef(dc) { - const { dc: dcInstance } = validateArgs(connectorConfig, dc, undefined); - dcInstance._useGeneratedSdk(); - return queryRef(dcInstance, 'ListMovies'); -}; - -exports.listMovies = function listMovies(dc) { - return executeQuery(listMoviesRef(dc)); -}; diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts deleted file mode 100644 index 474fefd0f4b..00000000000 --- a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/index.d.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - ConnectorConfig, - DataConnect, - QueryRef, - QueryPromise, - MutationRef, - MutationPromise -} from 'firebase/data-connect'; - -export const connectorConfig: ConnectorConfig; - -export type TimestampString = string; -export type UUIDString = string; -export type Int64String = string; -export type DateString = string; - -export interface CreateMovieData { - movie_insert: Movie_Key; -} - -export interface CreateMovieVariables { - title: string; - genre: string; - imageUrl: string; -} - -export interface ListMoviesData { - movies: ({ - id: UUIDString; - title: string; - imageUrl: string; - genre?: string | null; - } & Movie_Key)[]; -} - -export interface Movie_Key { - id: UUIDString; - __typename?: 'Movie_Key'; -} - -/* Allow users to create refs without passing in DataConnect */ -export function createMovieRef( - vars: CreateMovieVariables -): MutationRef; -/* Allow users to pass in custom DataConnect instances */ -export function createMovieRef( - dc: DataConnect, - vars: CreateMovieVariables -): MutationRef; - -export function createMovie( - vars: CreateMovieVariables -): MutationPromise; -export function createMovie( - dc: DataConnect, - vars: CreateMovieVariables -): MutationPromise; - -/* Allow users to create refs without passing in DataConnect */ -export function listMoviesRef(): QueryRef; -/* Allow users to pass in custom DataConnect instances */ -export function listMoviesRef( - dc: DataConnect -): QueryRef; - -export function listMovies(): QueryPromise; -export function listMovies( - dc: DataConnect -): QueryPromise; diff --git a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/package.json b/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/package.json deleted file mode 100644 index d0c9852ce3e..00000000000 --- a/packages/data-connect/example-integration/dataconnect-generated/js/default-connector/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "@firebasegen/default-connector", - "version": "1.0.0", - "author": "Firebase (https://firebase.google.com/)", - "description": "Generated SDK For default", - "license": "Apache-2.0", - "engines": { - "node": " >=18.0" - }, - "typings": "index.d.ts", - "module": "esm/index.esm.js", - "main": "index.cjs.js", - "browser": "esm/index.esm.js", - "exports": { - ".": { - "types": "./index.d.ts", - "require": "./index.cjs.js", - "default": "./esm/index.esm.js" - }, - "./package.json": "./package.json" - }, - "peerDependencies": { - "firebase": "^10.14.0 || ^11.3.0" - } -} \ No newline at end of file diff --git a/packages/data-connect/example-integration/dataconnect/connector/connector.yaml b/packages/data-connect/example-integration/dataconnect/connector/connector.yaml deleted file mode 100644 index b698515fe9f..00000000000 --- a/packages/data-connect/example-integration/dataconnect/connector/connector.yaml +++ /dev/null @@ -1,6 +0,0 @@ -connectorId: default -generate: - javascriptSdk: - outputDir: ../../dataconnect-generated/js/default-connector - package: "@firebasegen/default-connector" -# packageJsonDir: ../.. diff --git a/packages/data-connect/example-integration/dataconnect/connector/mutations.gql b/packages/data-connect/example-integration/dataconnect/connector/mutations.gql deleted file mode 100644 index 2379afeb89c..00000000000 --- a/packages/data-connect/example-integration/dataconnect/connector/mutations.gql +++ /dev/null @@ -1,33 +0,0 @@ -# # Example mutations for a simple movie app - -# # Create a movie based on user input -mutation CreateMovie($title: String!, $genre: String!, $imageUrl: String!) -@auth(level: USER_EMAIL_VERIFIED) { - movie_insert(data: { title: $title, genre: $genre, imageUrl: $imageUrl }) -} - -# # Upsert (update or insert) a user's username based on their auth.uid -# mutation UpsertUser($username: String!) @auth(level: USER) { -# # The "auth.uid" server value ensures that users can only register their own user. -# user_upsert(data: { id_expr: "auth.uid", username: $username }) -# } - -# # Add a review for a movie -# mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!) -# @auth(level: USER) { -# review_upsert( -# data: { -# userId_expr: "auth.uid" -# movieId: $movieId -# rating: $rating -# reviewText: $reviewText -# # reviewDate defaults to today in the schema. No need to set it manually. -# } -# ) -# } - -# # Logged in user can delete their review for a movie -# mutation DeleteReview($movieId: UUID!) @auth(level: USER) { -# # The "auth.uid" server value ensures that users can only delete their own reviews. -# review_delete(key: { userId_expr: "auth.uid", movieId: $movieId }) -# } diff --git a/packages/data-connect/example-integration/dataconnect/connector/queries.gql b/packages/data-connect/example-integration/dataconnect/connector/queries.gql deleted file mode 100644 index cb1a6f630bc..00000000000 --- a/packages/data-connect/example-integration/dataconnect/connector/queries.gql +++ /dev/null @@ -1,78 +0,0 @@ -# # Example queries for a simple movie app. - -# # @auth() directives control who can call each operation. -# # Anyone should be able to list all movies, so the auth level is set to PUBLIC -query ListMovies @auth(level: PUBLIC) { - movies { - id - title - imageUrl - genre - } -} - -# # List all users, only admins should be able to list all users, so we use NO_ACCESS -# query ListUsers @auth(level: NO_ACCESS) { -# users { -# id -# username -# } -# } - -# # Logged in users can list all their reviews and movie titles associated with the review -# # Since the query uses the uid of the current authenticated user, we set auth level to USER -# query ListUserReviews @auth(level: USER) { -# user(key: { id_expr: "auth.uid" }) { -# id -# username -# # _on_ makes it easy to grab info from another table -# # Here, we use it to grab all the reviews written by the user. -# reviews: reviews_on_user { -# rating -# reviewDate -# reviewText -# movie { -# id -# title -# } -# } -# } -# } - -# # Get movie by id -# query GetMovieById($id: UUID!) @auth(level: PUBLIC) { -# movie(id: $id) { -# id -# title -# imageUrl -# genre -# metadata: movieMetadata_on_movie { -# rating -# releaseYear -# description -# } -# reviews: reviews_on_movie { -# reviewText -# reviewDate -# rating -# user { -# id -# username -# } -# } -# } -# } - -# # Search for movies, actors, and reviews -# query SearchMovie($titleInput: String, $genre: String) @auth(level: PUBLIC) { -# movies( -# where: { -# _and: [{ genre: { eq: $genre } }, { title: { contains: $titleInput } }] -# } -# ) { -# id -# title -# genre -# imageUrl -# } -# } diff --git a/packages/data-connect/example-integration/dataconnect/dataconnect.yaml b/packages/data-connect/example-integration/dataconnect/dataconnect.yaml deleted file mode 100644 index 623fad3e209..00000000000 --- a/packages/data-connect/example-integration/dataconnect/dataconnect.yaml +++ /dev/null @@ -1,12 +0,0 @@ -specVersion: "v1beta" -serviceId: "fdc-test" -location: "us-central1" -schema: - source: "./schema" - datasource: - postgresql: - database: "fdcdb" - cloudSql: - instanceId: "fdc-test-fdc" - # schemaValidation: "COMPATIBLE" -connectorDirs: ["./connector"] diff --git a/packages/data-connect/example-integration/dataconnect/schema/schema.gql b/packages/data-connect/example-integration/dataconnect/schema/schema.gql deleted file mode 100644 index f114d9a678a..00000000000 --- a/packages/data-connect/example-integration/dataconnect/schema/schema.gql +++ /dev/null @@ -1,52 +0,0 @@ -# # Example schema for simple movie review app - -# # User table is keyed by Firebase Auth UID. -# type User @table { -# # `@default(expr: "auth.uid")` sets it to Firebase Auth UID during insert and upsert. -# id: String! @default(expr: "auth.uid") -# username: String! @col(dataType: "varchar(50)") -# # The `user: User!` field in the Review table generates the following one-to-many query field. -# # reviews_on_user: [Review!]! -# # The `Review` join table the following many-to-many query field. -# # movies_via_Review: [Movie!]! -# } - -# # Movie is keyed by a randomly generated UUID. -type Movie @table { - # If you do not pass a 'key' to `@table`, Data Connect automatically adds the following 'id' column. - # Feel free to uncomment and customize it. - # id: UUID! @default(expr: "uuidV4()") - title: String! - imageUrl: String! - genre: String -} - -# # MovieMetadata is a metadata attached to a Movie. -# # Movie <-> MovieMetadata is a one-to-one relationship -# type MovieMetadata @table { -# # @unique ensures each Movie can only one MovieMetadata. -# movie: Movie! @unique -# # The movie field adds the following foreign key field. Feel free to uncomment and customize it. -# # movieId: UUID! -# rating: Float -# releaseYear: Int -# description: String -# } - -# # Reviews is a join table between User and Movie. -# # It has a composite primary keys `userUid` and `movieId`. -# # A user can leave reviews for many movies. A movie can have reviews from many users. -# # User <-> Review is a one-to-many relationship -# # Movie <-> Review is a one-to-many relationship -# # Movie <-> User is a many-to-many relationship -# type Review @table(name: "Reviews", key: ["movie", "user"]) { -# user: User! -# # The user field adds the following foreign key field. Feel free to uncomment and customize it. -# # userUid: String! -# movie: Movie! -# # The movie field adds the following foreign key field. Feel free to uncomment and customize it. -# # movieId: UUID! -# rating: Int -# reviewText: String -# reviewDate: Date! @default(expr: "request.time") -# } diff --git a/packages/data-connect/example-integration/dataconnect/test b/packages/data-connect/example-integration/dataconnect/test deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/data-connect/example-integration/firebase-js-config.json b/packages/data-connect/example-integration/firebase-js-config.json deleted file mode 100644 index 0e0dcd235c4..00000000000 --- a/packages/data-connect/example-integration/firebase-js-config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - -} \ No newline at end of file diff --git a/packages/data-connect/example-integration/firebase.json b/packages/data-connect/example-integration/firebase.json deleted file mode 100644 index 6c9ad90b440..00000000000 --- a/packages/data-connect/example-integration/firebase.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "emulators": { - "dataconnect": { - "dataDir": "dataconnect/.dataconnect/pgliteData" - } - }, - "dataconnect": { - "source": "dataconnect" - } -} diff --git a/packages/data-connect/example-integration/package.json b/packages/data-connect/example-integration/package.json deleted file mode 100644 index 4cfd55079dc..00000000000 --- a/packages/data-connect/example-integration/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "fdc-test", - "version": "1.0.0", - "description": "", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "build": "tsc" - }, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "@types/node": "^22.13.14", - "ts-node": "^10.9.2", - "tslib": "^2.8.1", - "typescript": "^5.8.2" - }, - "dependencies": { - "firebase": "11.5.0" - } -} diff --git a/packages/data-connect/example-integration/test.ts b/packages/data-connect/example-integration/test.ts deleted file mode 100644 index cc177b8e47c..00000000000 --- a/packages/data-connect/example-integration/test.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { listMovies } from './dataconnect-generated/js/default-connector'; -import * as json from './firebase-js-config.json'; -import { initializeApp } from 'firebase/app'; - -initializeApp(json); -listMovies(); diff --git a/packages/data-connect/example-integration/testscript.sh b/packages/data-connect/example-integration/testscript.sh deleted file mode 100755 index 6a56cb4d536..00000000000 --- a/packages/data-connect/example-integration/testscript.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -statusResult=$(git status --porcelain | wc -l) -if [[ statusResult -eq "0" ]] -then - echo 'no changes found' -else - echo 'The workspace is modified:' - echo "$statusResult" -fi - diff --git a/packages/data-connect/example-integration/tsconfig.json b/packages/data-connect/example-integration/tsconfig.json deleted file mode 100644 index e3c427a3163..00000000000 --- a/packages/data-connect/example-integration/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "ES5", - "module": "CommonJS", - "resolveJsonModule": true, - "sourceMap": true, - "noEmit": true, - "skipLibCheck": false - } - } diff --git a/packages/data-connect/example-integration/yarn.lock b/packages/data-connect/example-integration/yarn.lock deleted file mode 100644 index cb23e2383e1..00000000000 --- a/packages/data-connect/example-integration/yarn.lock +++ /dev/null @@ -1,802 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - -"@firebase/analytics-compat@0.2.18": - version "0.2.18" - resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.2.18.tgz#5ea9bdea188d4c91938f539af4c4414813ddc5c9" - integrity sha512-Hw9mzsSMZaQu6wrTbi3kYYwGw9nBqOHr47pVLxfr5v8CalsdrG5gfs9XUlPOZjHRVISp3oQrh1j7d3E+ulHPjQ== - dependencies: - "@firebase/analytics" "0.10.12" - "@firebase/analytics-types" "0.8.3" - "@firebase/component" "0.6.13" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/analytics-types@0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.8.3.tgz#d08cd39a6209693ca2039ba7a81570dfa6c1518f" - integrity sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg== - -"@firebase/analytics@0.10.12": - version "0.10.12" - resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.10.12.tgz#b49b9351b8cb19da007320a52932b953fff90d71" - integrity sha512-iDCGnw6qdFqwI5ywkgece99WADJNoymu+nLIQI4fZM/vCZ3bEo4wlpEetW71s1HqGpI0hQStiPhqVjFxDb2yyw== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/installations" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/app-check-compat@0.3.20": - version "0.3.20" - resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.3.20.tgz#0dfce42699402f3b621be98857a8109b9397a37b" - integrity sha512-/twgmlnNAaZ/wbz3kcQrL/26b+X+zUX+lBmu5LwwEcWcpnb+mrVEAKhD7/ttm52dxYiSWtLDeuXy3FXBhqBC5A== - dependencies: - "@firebase/app-check" "0.8.13" - "@firebase/app-check-types" "0.5.3" - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/app-check-interop-types@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz#ed9c4a4f48d1395ef378f007476db3940aa5351a" - integrity sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A== - -"@firebase/app-check-types@0.5.3": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@firebase/app-check-types/-/app-check-types-0.5.3.tgz#38ba954acf4bffe451581a32fffa20337f11d8e5" - integrity sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng== - -"@firebase/app-check@0.8.13": - version "0.8.13" - resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.8.13.tgz#20b212d0ea5b79c9492f434abc276d4f28b19371" - integrity sha512-ONsgml8/dplUOAP42JQO6hhiWDEwR9+RUTLenxAN9S8N6gel/sDQ9Ci721Py1oASMGdDU8v9R7xAZxzvOX5lPg== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/app-compat@0.2.52": - version "0.2.52" - resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.52.tgz#71ac4334c2dc841be3f101ab1f7d00412568a885" - integrity sha512-0p/l1KiwhwwYTcPWoleFQHftOnYzeXvyVf3WNZyKFBAoQMpCVW6bVm/uO1bXF91AwU1JN0og888Y6Sc8avqZ+A== - dependencies: - "@firebase/app" "0.11.3" - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/app-types@0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.3.tgz#8408219eae9b1fb74f86c24e7150a148460414ad" - integrity sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw== - -"@firebase/app@0.11.3": - version "0.11.3" - resolved "https://registry.npmjs.org/@firebase/app/-/app-0.11.3.tgz#80abcb65a1dce743d081022d2934fe69e60c1d41" - integrity sha512-QlTZl/RcqPSonYxB87n8KgAUW2L6ZZz0W4D91PVmQ1tJPsKsKPrWAFHL0ii2cQW6FxTxfNjbZ7kucuIcKXk3tw== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - idb "7.1.1" - tslib "^2.1.0" - -"@firebase/auth-compat@0.5.19": - version "0.5.19" - resolved "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.19.tgz#6f393e85496754bfc4f31758bc0718a88f9c2f30" - integrity sha512-v898POphOIBJliKF76SiGOXh4EdhO5fM6S9a2ZKf/8wHdBea/qwxwZoVVya4DW6Mi7vWyp1lIzHbFgwRz8G9TA== - dependencies: - "@firebase/auth" "1.9.1" - "@firebase/auth-types" "0.13.0" - "@firebase/component" "0.6.13" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/auth-interop-types@0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz#176a08686b0685596ff03d7879b7e4115af53de0" - integrity sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA== - -"@firebase/auth-types@0.13.0": - version "0.13.0" - resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.13.0.tgz#ae6e0015e3bd4bfe18edd0942b48a0a118a098d9" - integrity sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg== - -"@firebase/auth@1.9.1": - version "1.9.1" - resolved "https://registry.npmjs.org/@firebase/auth/-/auth-1.9.1.tgz#5fca654e003a7fa0b3bbb247782633c3aab67ce4" - integrity sha512-9KKo5SNVkyJzftsW+daS+PGDbeJ+MFJWXQFHDqqPPH3acWHtiNnGHH5HGpIJErEELrsm9xMPie5zfZ0XpGU8+w== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/component@0.6.13": - version "0.6.13" - resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.6.13.tgz#6513379f1c09264133969d87282ce0d5bbbb2cd9" - integrity sha512-I/Eg1NpAtZ8AAfq8mpdfXnuUpcLxIDdCDtTzWSh+FXnp/9eCKJ3SNbOCKrUCyhLzNa2SiPJYruei0sxVjaOTeg== - dependencies: - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/data-connect@0.3.2": - version "0.3.2" - resolved "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.2.tgz#8a74af2e111fe1a36d7bf37c55a7c2469e8a051f" - integrity sha512-PYG55JRTmvYrUuXXmYBsZexwKVP9aR3mIRRHxB9V2bQeRDZky6JtRZnH3GLhf4ZsxZy5Ewd8ul/jTOYR4gpD9w== - dependencies: - "@firebase/auth-interop-types" "0.2.4" - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/database-compat@2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-2.0.5.tgz#110f612901995f9800f2435f58686e0c6f3d2544" - integrity sha512-CNf1UbvWh6qIaSf4sn6sx2DTDz/em/D7QxULH1LTxxDQHr9+CeYGvlAqrKnk4ZH0P0eIHyQFQU7RwkUJI0B9gQ== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/database" "1.0.14" - "@firebase/database-types" "1.0.10" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/database-types@1.0.10": - version "1.0.10" - resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-1.0.10.tgz#14cfed45bb06394cf1641e19265cbf90e4f6fb51" - integrity sha512-mH6RC1E9/Pv8jf1/p+M8YFTX+iu+iHDN89hecvyO7wHrI4R1V0TXjxOHvX3nLJN1sfh0CWG6CHZ0VlrSmK/cwg== - dependencies: - "@firebase/app-types" "0.9.3" - "@firebase/util" "1.11.0" - -"@firebase/database@1.0.14": - version "1.0.14" - resolved "https://registry.yarnpkg.com/@firebase/database/-/database-1.0.14.tgz#1d579b345c0f926eaddb7703051999489300c3bd" - integrity sha512-9nxYtkHAG02/Nh2Ssms1T4BbWPPjiwohCvkHDUl4hNxnki1kPgsLo5xe9kXNzbacOStmVys+RUXvwzynQSKmUQ== - dependencies: - "@firebase/app-check-interop-types" "0.3.3" - "@firebase/auth-interop-types" "0.2.4" - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - faye-websocket "0.11.4" - tslib "^2.1.0" - -"@firebase/firestore-compat@0.3.45": - version "0.3.45" - resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.3.45.tgz#93061f7d3644cd511749c9268d146e8c8c49a5de" - integrity sha512-uRvi7AYPmsDl7UZwPyV7jgDGYusEZ2+U2g7MndbQHKIA8fNHpYC6QrzMs58+/IjX+kF/lkUn67Vrr0AkVjlY+Q== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/firestore" "4.7.10" - "@firebase/firestore-types" "3.0.3" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/firestore-types@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-3.0.3.tgz#7d0c3dd8850c0193d8f5ee0cc8f11961407742c1" - integrity sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q== - -"@firebase/firestore@4.7.10": - version "4.7.10" - resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-4.7.10.tgz#6fe0cd31fcd7f4a8e13f9585f53e9300cf3114c0" - integrity sha512-6nKsyo2U+jYSCcSE5sjMdDNA23DMUvYPUvsYGg09CNvcTO8GGKsPs7SpOhspsB91mbacq+u627CDAx3FUhPSSQ== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - "@firebase/webchannel-wrapper" "1.0.3" - "@grpc/grpc-js" "~1.9.0" - "@grpc/proto-loader" "^0.7.8" - tslib "^2.1.0" - -"@firebase/functions-compat@0.3.20": - version "0.3.20" - resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.3.20.tgz#addf89242be8b4d63feacb15ef27785e16c5e220" - integrity sha512-iIudmYDAML6n3c7uXO2YTlzra2/J6lnMzmJTXNthvrKVMgNMaseNoQP1wKfchK84hMuSF8EkM4AvufwbJ+Juew== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/functions" "0.12.3" - "@firebase/functions-types" "0.6.3" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/functions-types@0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.6.3.tgz#f5faf770248b13f45d256f614230da6a11bfb654" - integrity sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg== - -"@firebase/functions@0.12.3": - version "0.12.3" - resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.12.3.tgz#b3e395aed1641d0d7169a22698c684a2745e02dd" - integrity sha512-Wv7JZMUkKLb1goOWRtsu3t7m97uK6XQvjQLPvn8rncY91+VgdU72crqnaYCDI/ophNuBEmuK8mn0/pAnjUeA6A== - dependencies: - "@firebase/app-check-interop-types" "0.3.3" - "@firebase/auth-interop-types" "0.2.4" - "@firebase/component" "0.6.13" - "@firebase/messaging-interop-types" "0.2.3" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/installations-compat@0.2.13": - version "0.2.13" - resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.13.tgz#0db0867ed58b782f7e2d142d9289a9eef1da24d5" - integrity sha512-f/o6MqCI7LD/ulY9gvgkv6w5k6diaReD8BFHd/y/fEdpsXmFWYS/g28GXCB72bRVBOgPpkOUNl+VsMvDwlRKmw== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/installations" "0.6.13" - "@firebase/installations-types" "0.5.3" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/installations-types@0.5.3": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.5.3.tgz#cac8a14dd49f09174da9df8ae453f9b359c3ef2f" - integrity sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA== - -"@firebase/installations@0.6.13": - version "0.6.13" - resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.13.tgz#a2a00aebb5dfb74fae08600ea98cd2681211dd3c" - integrity sha512-6ZpkUiaygPFwgVneYxuuOuHnSPnTA4KefLEaw/sKk/rNYgC7X6twaGfYb0sYLpbi9xV4i5jXsqZ3WO+yaguNgg== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/util" "1.11.0" - idb "7.1.1" - tslib "^2.1.0" - -"@firebase/logger@0.4.4": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.4.4.tgz#29e8379d20fd1149349a195ee6deee4573a86f48" - integrity sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g== - dependencies: - tslib "^2.1.0" - -"@firebase/messaging-compat@0.2.17": - version "0.2.17" - resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.17.tgz#fc223495319fe3784347dea77094b6e03548647d" - integrity sha512-5Q+9IG7FuedusdWHVQRjpA3OVD9KUWp/IPegcv0s5qSqRLBjib7FlAeWxN+VL0Ew43tuPJBY2HKhEecuizmO1Q== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/messaging" "0.12.17" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/messaging-interop-types@0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz#e647c9cd1beecfe6a6e82018a6eec37555e4da3e" - integrity sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q== - -"@firebase/messaging@0.12.17": - version "0.12.17" - resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.17.tgz#41eaeee70a89136715a4f7cb2b1a602423fc44ec" - integrity sha512-W3CnGhTm6Nx8XGb6E5/+jZTuxX/EK8Vur4QXvO1DwZta/t0xqWMRgO9vNsZFMYBqFV4o3j4F9qK/iddGYwWS6g== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/installations" "0.6.13" - "@firebase/messaging-interop-types" "0.2.3" - "@firebase/util" "1.11.0" - idb "7.1.1" - tslib "^2.1.0" - -"@firebase/performance-compat@0.2.15": - version "0.2.15" - resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.15.tgz#4e5034add63917cb6357938126e9e6562d0e7208" - integrity sha512-wUxsw7hGBEMN6XfvYQqwPIQp5LcJXawWM5tmYp6L7ClCoTQuEiCKHWWVurJgN8Q1YHzoHVgjNfPQAOVu29iMVg== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/performance" "0.7.2" - "@firebase/performance-types" "0.2.3" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/performance-types@0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.2.3.tgz#5ce64e90fa20ab5561f8b62a305010cf9fab86fb" - integrity sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ== - -"@firebase/performance@0.7.2": - version "0.7.2" - resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.7.2.tgz#e30ee3e3c120c53f48bde7bdd915687f1e3b27e1" - integrity sha512-DXLLp0R0jdxH/yTmv+WTkOzsLl8YYecXh4lGZE0dzqC0IV8k+AxpLSSWvOTCkAETze8yEU/iF+PtgYVlGjfMMQ== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/installations" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - web-vitals "^4.2.4" - -"@firebase/remote-config-compat@0.2.13": - version "0.2.13" - resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.13.tgz#4a35c2c6bb582d96aecc45da18f5094359cb5361" - integrity sha512-UmHoO7TxAEJPIZf8e1Hy6CeFGMeyjqSCpgoBkQZYXFI2JHhzxIyDpr8jVKJJN1dmAePKZ5EX7dC13CmcdTOl7Q== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/remote-config" "0.6.0" - "@firebase/remote-config-types" "0.4.0" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/remote-config-types@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz#91b9a836d5ca30ced68c1516163b281fbb544537" - integrity sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg== - -"@firebase/remote-config@0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.6.0.tgz#24a6966a4d092260983ba8597cc039f5795cd35f" - integrity sha512-Yrk4l5+6FJLPHC6irNHMzgTtJ3NfHXlAXVChCBdNFtgmzyGmufNs/sr8oA0auEfIJ5VpXCaThRh3P4OdQxiAlQ== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/installations" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/storage-compat@0.3.17": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.3.17.tgz#67f6bbc498971e6e404e0ea660fa5df81c5ba5ea" - integrity sha512-CBlODWEZ5b6MJWVh21VZioxwxNwVfPA9CAdsk+ZgVocJQQbE2oDW1XJoRcgthRY1HOitgbn4cVrM+NlQtuUYhw== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/storage" "0.13.7" - "@firebase/storage-types" "0.8.3" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/storage-types@0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.8.3.tgz#2531ef593a3452fc12c59117195d6485c6632d3d" - integrity sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg== - -"@firebase/storage@0.13.7": - version "0.13.7" - resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.13.7.tgz#809fc23685ad9ba8fdfb3bc758e3353867c9e796" - integrity sha512-FkRyc24rK+Y6EaQ1tYFm3TevBnnfSNA0VyTfew2hrYyL/aYfatBg7HOgktUdB4kWMHNA9VoTotzZTGoLuK92wg== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/util@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.11.0.tgz#e74ee2dc260ec4f9e75fe5d52bc4b0254d9872a9" - integrity sha512-PzSrhIr++KI6y4P6C/IdgBNMkEx0Ex6554/cYd0Hm+ovyFSJtJXqb/3OSIdnBoa2cpwZT1/GW56EmRc5qEc5fQ== - dependencies: - tslib "^2.1.0" - -"@firebase/vertexai@1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.2.0.tgz#8f8a4ae75284c3067c0a06c7d0bef922571e6dd7" - integrity sha512-WUYIzFpOipjFXT2i0hT26wivJoIximizQptVs3KAxFAqbVlO8sjKPsMkgz0bh+tdKlqP4SUDda71fMUZXUKHgA== - dependencies: - "@firebase/app-check-interop-types" "0.3.3" - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - -"@firebase/webchannel-wrapper@1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz#a73bab8eb491d7b8b7be2f0e6c310647835afe83" - integrity sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ== - -"@grpc/grpc-js@~1.9.0": - version "1.9.15" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.15.tgz#433d7ac19b1754af690ea650ab72190bd700739b" - integrity sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ== - dependencies: - "@grpc/proto-loader" "^0.7.8" - "@types/node" ">=12.12.47" - -"@grpc/proto-loader@^0.7.8": - version "0.7.13" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" - integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== - dependencies: - lodash.camelcase "^4.3.0" - long "^5.0.0" - protobufjs "^7.2.5" - yargs "^17.7.2" - -"@jridgewell/resolve-uri@^3.0.3": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" - integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== - -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" - integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== - -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== - -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" - integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== - -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" - integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== - -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== - -"@tsconfig/node10@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" - integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - -"@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@^22.13.14": - version "22.14.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.14.0.tgz#d3bfa3936fef0dbacd79ea3eb17d521c628bb47e" - integrity sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA== - dependencies: - undici-types "~6.21.0" - -acorn-walk@^8.1.1: - version "8.3.4" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" - integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== - dependencies: - acorn "^8.11.0" - -acorn@^8.11.0, acorn@^8.4.1: - version "8.14.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" - integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -escalade@^3.1.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -faye-websocket@0.11.4: - version "0.11.4" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" - integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== - dependencies: - websocket-driver ">=0.5.1" - -firebase@11.5.0: - version "11.5.0" - resolved "https://registry.npmjs.org/firebase/-/firebase-11.5.0.tgz#9a358ed8c7e805de8df64061840b2593ae706165" - integrity sha512-ZTpO/zD5nYqY02bGpXCg1dRNLggTXPQZdLQeSeur3jYH270p1QkAZZJsm/lrKZ2W4ZjBlafTxxs4OwN38Vyocw== - dependencies: - "@firebase/analytics" "0.10.12" - "@firebase/analytics-compat" "0.2.18" - "@firebase/app" "0.11.3" - "@firebase/app-check" "0.8.13" - "@firebase/app-check-compat" "0.3.20" - "@firebase/app-compat" "0.2.52" - "@firebase/app-types" "0.9.3" - "@firebase/auth" "1.9.1" - "@firebase/auth-compat" "0.5.19" - "@firebase/data-connect" "0.3.2" - "@firebase/database" "1.0.14" - "@firebase/database-compat" "2.0.5" - "@firebase/firestore" "4.7.10" - "@firebase/firestore-compat" "0.3.45" - "@firebase/functions" "0.12.3" - "@firebase/functions-compat" "0.3.20" - "@firebase/installations" "0.6.13" - "@firebase/installations-compat" "0.2.13" - "@firebase/messaging" "0.12.17" - "@firebase/messaging-compat" "0.2.17" - "@firebase/performance" "0.7.2" - "@firebase/performance-compat" "0.2.15" - "@firebase/remote-config" "0.6.0" - "@firebase/remote-config-compat" "0.2.13" - "@firebase/storage" "0.13.7" - "@firebase/storage-compat" "0.3.17" - "@firebase/util" "1.11.0" - "@firebase/vertexai" "1.2.0" - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -http-parser-js@>=0.5.1: - version "0.5.9" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.9.tgz#b817b3ca0edea6236225000d795378707c169cec" - integrity sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw== - -idb@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" - integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== - -long@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/long/-/long-5.3.1.tgz#9d4222d3213f38a5ec809674834e0f0ab21abe96" - integrity sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng== - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -protobufjs@^7.2.5: - version "7.4.0" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.4.0.tgz#7efe324ce9b3b61c82aae5de810d287bc08a248a" - integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -safe-buffer@>=5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -ts-node@^10.9.2: - version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tslib@^2.1.0, tslib@^2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - -typescript@^5.8.2: - version "5.8.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4" - integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ== - -undici-types@~6.21.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" - integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -web-vitals@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.4.tgz#1d20bc8590a37769bd0902b289550936069184b7" - integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw== - -websocket-driver@>=0.5.1: - version "0.7.4" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" - integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== - dependencies: - http-parser-js ">=0.5.1" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" - integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs@^17.7.2: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== From f867d3b2a8363896c098d27e4229e36f9175a2c7 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 23 Apr 2025 11:12:13 -0700 Subject: [PATCH 09/67] Removed unnecessary data connect changes --- packages/data-connect/.eslintrc.js | 2 +- packages/data-connect/tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/data-connect/.eslintrc.js b/packages/data-connect/.eslintrc.js index a6d8d8c7c84..faef63a0395 100644 --- a/packages/data-connect/.eslintrc.js +++ b/packages/data-connect/.eslintrc.js @@ -24,7 +24,7 @@ module.exports = { tsconfigRootDir: __dirname }, plugins: ['import'], - ignorePatterns: ['compat/*', 'example-integration/*'], + ignorePatterns: ['compat/*'], rules: { 'no-console': ['error', { allow: ['warn', 'error'] }], '@typescript-eslint/no-unused-vars': [ diff --git a/packages/data-connect/tsconfig.json b/packages/data-connect/tsconfig.json index ba35aaa2516..58561f50f5d 100644 --- a/packages/data-connect/tsconfig.json +++ b/packages/data-connect/tsconfig.json @@ -4,5 +4,5 @@ "outDir": "dist", "strict": false }, - "exclude": ["dist/**/*", "test/**/*", "example-integration/**/*"] + "exclude": ["dist/**/*", "test/**/*"] } From 4f23f3343146f15ea27fcba85ba9e22e1e96117c Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 23 Apr 2025 11:15:53 -0700 Subject: [PATCH 10/67] Create gentle-laws-kneel.md --- .changeset/gentle-laws-kneel.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/gentle-laws-kneel.md diff --git a/.changeset/gentle-laws-kneel.md b/.changeset/gentle-laws-kneel.md new file mode 100644 index 00000000000..46dc7d25ecf --- /dev/null +++ b/.changeset/gentle-laws-kneel.md @@ -0,0 +1,7 @@ +--- +"@firebase/database-compat": patch +"@firebase/database": patch +"@firebase/firestore": patch +--- + +Add SSL checks to `connectDatabaseEmulator` and `connectFirestoreEmulator` From 55b1c0ae12e91fb82b9d12dd752aa19c58e653cb Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 23 Apr 2025 15:37:44 -0700 Subject: [PATCH 11/67] Added code to pass on credentials if using a cloud workstation --- common/api-review/util.api.md | 5 ++++ packages/app-check/src/client.ts | 4 +++ packages/auth/src/api/index.ts | 12 +++++++- packages/data-connect/src/network/fetch.ts | 13 +++++--- .../platform/browser/webchannel_connection.ts | 1 + .../platform/browser_lite/fetch_connection.ts | 9 ++++-- .../storage/src/platform/node/connection.ts | 30 ++++++++++++------- packages/util/index.ts | 1 + packages/util/src/url.ts | 3 ++ 9 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 packages/util/src/url.ts diff --git a/common/api-review/util.api.md b/common/api-review/util.api.md index 8c62ff229ac..f9da0226c94 100644 --- a/common/api-review/util.api.md +++ b/common/api-review/util.api.md @@ -269,6 +269,11 @@ export function isBrowserExtension(): boolean; // @public export function isCloudflareWorker(): boolean; +// Warning: (ae-missing-release-tag) "isCloudWorkstation" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function isCloudWorkstation(url: string): boolean; + // Warning: (ae-missing-release-tag) "isElectron" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/packages/app-check/src/client.ts b/packages/app-check/src/client.ts index 1861383174d..e8223675ae3 100644 --- a/packages/app-check/src/client.ts +++ b/packages/app-check/src/client.ts @@ -25,6 +25,7 @@ import { FirebaseApp } from '@firebase/app'; import { ERROR_FACTORY, AppCheckError } from './errors'; import { Provider } from '@firebase/component'; import { AppCheckTokenInternal } from './types'; +import { isCloudWorkstation } from '@firebase/util'; /** * Response JSON returned from AppCheck server endpoint. @@ -62,6 +63,9 @@ export async function exchangeToken( body: JSON.stringify(body), headers }; + if (isCloudWorkstation(url)) { + options.credentials = 'include'; + } let response; try { response = await fetch(url, options); diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index 769a1b6accc..682a37f2303 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -15,7 +15,12 @@ * limitations under the License. */ -import { FirebaseError, isCloudflareWorker, querystring } from '@firebase/util'; +import { + FirebaseError, + isCloudflareWorker, + isCloudWorkstation, + querystring +} from '@firebase/util'; import { AuthErrorCode, NamedErrorParams } from '../core/errors'; import { @@ -33,6 +38,7 @@ import { IdTokenMfaResponse } from './authentication/mfa'; import { SERVER_ERROR_MAP, ServerError, ServerErrorMap } from './errors'; import { PersistenceType } from '../core/persistence'; import { CookiePersistence } from '../platform_browser/persistence/cookie_storage'; +import { FirebaseAuth } from '@firebase/auth-types'; export const enum HttpMethod { POST = 'POST', @@ -177,6 +183,10 @@ export async function _performApiRequest( fetchArgs.referrerPolicy = 'no-referrer'; } + if (auth.emulatorConfig && isCloudWorkstation(auth.emulatorConfig.host)) { + fetchArgs.credentials = 'include'; + } + return FetchProvider.fetch()( await _getFinalTarget(auth, auth.config.apiHost, path, query), fetchArgs diff --git a/packages/data-connect/src/network/fetch.ts b/packages/data-connect/src/network/fetch.ts index 8353c6b99ab..2488287b611 100644 --- a/packages/data-connect/src/network/fetch.ts +++ b/packages/data-connect/src/network/fetch.ts @@ -25,6 +25,7 @@ import { SDK_VERSION } from '../core/version'; import { logDebug, logError } from '../logger'; import { CallerSdkType, CallerSdkTypeEnum } from './transport'; +import { isCloudWorkstation } from '@firebase/util'; let connectFetch: typeof fetch | null = globalThis.fetch; export function initializeFetch(fetchImpl: typeof fetch): void { @@ -77,14 +78,18 @@ export function dcFetch( headers['X-Firebase-AppCheck'] = appCheckToken; } const bodyStr = JSON.stringify(body); - logDebug(`Making request out to ${url} with body: ${bodyStr}`); - - return connectFetch(url, { + const fetchOptions: RequestInit = { body: bodyStr, method: 'POST', headers, signal - }) + }; + if (isCloudWorkstation(url)) { + fetchOptions.credentials = 'include'; + } + logDebug(`Making request out to ${url} with body: ${bodyStr}`); + + return connectFetch(url, fetchOptions) .catch(err => { throw new DataConnectError( Code.OTHER, diff --git a/packages/firestore/src/platform/browser/webchannel_connection.ts b/packages/firestore/src/platform/browser/webchannel_connection.ts index 5223285c5a4..b5224eac117 100644 --- a/packages/firestore/src/platform/browser/webchannel_connection.ts +++ b/packages/firestore/src/platform/browser/webchannel_connection.ts @@ -46,6 +46,7 @@ import { Code, FirestoreError } from '../../util/error'; import { logDebug, logWarn } from '../../util/log'; import { Rejecter, Resolver } from '../../util/promise'; import { StringMap } from '../../util/types'; +import { isCloudWorkstation } from '@firebase/util'; const LOG_TAG = 'WebChannelConnection'; diff --git a/packages/firestore/src/platform/browser_lite/fetch_connection.ts b/packages/firestore/src/platform/browser_lite/fetch_connection.ts index d11247c8019..f3b2b9dbb21 100644 --- a/packages/firestore/src/platform/browser_lite/fetch_connection.ts +++ b/packages/firestore/src/platform/browser_lite/fetch_connection.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { isCloudWorkstation } from '@firebase/util'; import { Token } from '../../api/credentials'; import { Stream } from '../../remote/connection'; import { RestConnection } from '../../remote/rest_connection'; @@ -44,11 +45,15 @@ export class FetchConnection extends RestConnection { let response: Response; try { - response = await fetch(url, { + const fetchArgs: RequestInit = { method: 'POST', headers, body: requestJson - }); + }; + if (isCloudWorkstation(url)) { + fetchArgs.credentials = 'include'; + } + response = await fetch(url, fetchArgs); } catch (e) { const err = e as { status: number | undefined; statusText: string }; throw new FirestoreError( diff --git a/packages/storage/src/platform/node/connection.ts b/packages/storage/src/platform/node/connection.ts index c90f664c3b2..00371ff2bc5 100644 --- a/packages/storage/src/platform/node/connection.ts +++ b/packages/storage/src/platform/node/connection.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { isCloudWorkstation } from '@firebase/util'; import { Connection, ConnectionType, @@ -57,11 +58,7 @@ abstract class FetchConnection this.sent_ = true; try { - const response = await fetch(url, { - method, - headers: headers || {}, - body: body as NodeJS.ArrayBufferView | string - }); + const response = await newFetch(url, method, headers, body); this.headers_ = response.headers; this.statusCode_ = response.status; this.errorCode_ = ErrorCode.NO_ERROR; @@ -161,11 +158,7 @@ export class FetchStreamConnection extends FetchConnection< this.sent_ = true; try { - const response = await fetch(url, { - method, - headers: headers || {}, - body: body as NodeJS.ArrayBufferView | string - }); + const response = await newFetch(url, method, headers, body); this.headers_ = response.headers; this.statusCode_ = response.status; this.errorCode_ = ErrorCode.NO_ERROR; @@ -186,6 +179,23 @@ export class FetchStreamConnection extends FetchConnection< } } +function newFetch( + url: string, + method: string, + headers?: Record, + body?: NodeJS.ArrayBufferView | Blob | string +) { + const fetchArgs: RequestInit = { + method, + headers: headers || {}, + body: body as NodeJS.ArrayBufferView | string + }; + if (isCloudWorkstation(url)) { + fetchArgs.credentials = 'include'; + } + return fetch(url, fetchArgs); +} + export function newStreamConnection(): Connection> { return new FetchStreamConnection(); } diff --git a/packages/util/index.ts b/packages/util/index.ts index 51c27c31099..1829c32a420 100644 --- a/packages/util/index.ts +++ b/packages/util/index.ts @@ -37,3 +37,4 @@ export * from './src/exponential_backoff'; export * from './src/formatters'; export * from './src/compat'; export * from './src/global'; +export * from './src/url'; diff --git a/packages/util/src/url.ts b/packages/util/src/url.ts new file mode 100644 index 00000000000..d733bbd2b7f --- /dev/null +++ b/packages/util/src/url.ts @@ -0,0 +1,3 @@ +export function isCloudWorkstation(url: string) { + return url.endsWith('cloudworkstations.dev'); +} \ No newline at end of file From e0a59c59c9fc77b138ee78e14742acc487e2e99d Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Wed, 23 Apr 2025 15:42:43 -0700 Subject: [PATCH 12/67] Create nine-pugs-crash.md --- .changeset/nine-pugs-crash.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .changeset/nine-pugs-crash.md diff --git a/.changeset/nine-pugs-crash.md b/.changeset/nine-pugs-crash.md new file mode 100644 index 00000000000..c3542b35d54 --- /dev/null +++ b/.changeset/nine-pugs-crash.md @@ -0,0 +1,12 @@ +--- +"@firebase/app-check": patch +"@firebase/auth": patch +"@firebase/data-connect": patch +"@firebase/database-compat": patch +"@firebase/database": patch +"@firebase/firestore": patch +"@firebase/storage": patch +"@firebase/util": patch +--- + +Fix Auth Redirects on Firebase Studio From 8d93780ca041063293a731a3686c784200a5c89d Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 24 Apr 2025 09:29:35 -0700 Subject: [PATCH 13/67] Addressed comments --- packages/data-connect/src/network/fetch.ts | 6 ++--- .../src/network/transport/rest.ts | 8 +++++-- packages/database/src/api/Database.ts | 12 +++++----- packages/util/src/url.ts | 23 ++++++++++++++++--- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/data-connect/src/network/fetch.ts b/packages/data-connect/src/network/fetch.ts index 2488287b611..cc71844cac1 100644 --- a/packages/data-connect/src/network/fetch.ts +++ b/packages/data-connect/src/network/fetch.ts @@ -59,7 +59,8 @@ export function dcFetch( accessToken: string | null, appCheckToken: string | null, _isUsingGen: boolean, - _callerSdkType: CallerSdkType + _callerSdkType: CallerSdkType, + _isUsingEmulator: boolean ): Promise<{ data: T; errors: Error[] }> { if (!connectFetch) { throw new DataConnectError(Code.OTHER, 'No Fetch Implementation detected!'); @@ -84,10 +85,9 @@ export function dcFetch( headers, signal }; - if (isCloudWorkstation(url)) { + if (isCloudWorkstation(url) && _isUsingEmulator) { fetchOptions.credentials = 'include'; } - logDebug(`Making request out to ${url} with body: ${bodyStr}`); return connectFetch(url, fetchOptions) .catch(err => { diff --git a/packages/data-connect/src/network/transport/rest.ts b/packages/data-connect/src/network/transport/rest.ts index 0663bc026db..f16154dcb2a 100644 --- a/packages/data-connect/src/network/transport/rest.ts +++ b/packages/data-connect/src/network/transport/rest.ts @@ -36,6 +36,7 @@ export class RESTTransport implements DataConnectTransport { private _accessToken: string | null = null; private _appCheckToken: string | null = null; private _lastToken: string | null = null; + private _isUsingEmulator = false; constructor( options: DataConnectOptions, private apiKey?: string | undefined, @@ -93,6 +94,7 @@ export class RESTTransport implements DataConnectTransport { } useEmulator(host: string, port?: number, isSecure?: boolean): void { this._host = host; + this._isUsingEmulator = true; if (typeof port === 'number') { this._port = port; } @@ -182,7 +184,8 @@ export class RESTTransport implements DataConnectTransport { this._accessToken, this._appCheckToken, this._isUsingGen, - this._callerSdkType + this._callerSdkType, + this._isUsingEmulator ) ); return withAuth; @@ -208,7 +211,8 @@ export class RESTTransport implements DataConnectTransport { this._accessToken, this._appCheckToken, this._isUsingGen, - this._callerSdkType + this._callerSdkType, + this._isUsingEmulator ); }); return taskResult; diff --git a/packages/database/src/api/Database.ts b/packages/database/src/api/Database.ts index 60c6148f77e..c169bd44e1a 100644 --- a/packages/database/src/api/Database.ts +++ b/packages/database/src/api/Database.ts @@ -90,17 +90,17 @@ function repoManagerApplyEmulatorSettings( tokenProvider?: AuthTokenProvider ): void { let ssl = false; - let finalHost = hostAndPort; - if (/^https:\/\//.test(finalHost)) { + let host = hostAndPort; + if (/^https:\/\//.test(host)) { ssl = true; - finalHost = finalHost.substring(8); + host = host.substring(8); } - if (/^wss:\/\//.test(finalHost)) { + if (/^wss:\/\//.test(host)) { ssl = true; - finalHost = finalHost.substring(6); + host = host.substring(6); } repo.repoInfo_ = new RepoInfo( - finalHost, + host, /* secure= */ ssl, repo.repoInfo_.namespace, repo.repoInfo_.webSocketOnly, diff --git a/packages/util/src/url.ts b/packages/util/src/url.ts index d733bbd2b7f..d8de8d06cc7 100644 --- a/packages/util/src/url.ts +++ b/packages/util/src/url.ts @@ -1,3 +1,20 @@ -export function isCloudWorkstation(url: string) { - return url.endsWith('cloudworkstations.dev'); -} \ No newline at end of file +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function isCloudWorkstation(url: string): boolean { + return url.endsWith('.cloudworkstations.dev'); +} From 5e76a0aade2e3cae68c3af592cc8b6615d4cdcf9 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 24 Apr 2025 09:32:50 -0700 Subject: [PATCH 14/67] Removed unused import --- packages/auth/src/api/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index 682a37f2303..af9b3c63bf1 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -38,7 +38,6 @@ import { IdTokenMfaResponse } from './authentication/mfa'; import { SERVER_ERROR_MAP, ServerError, ServerErrorMap } from './errors'; import { PersistenceType } from '../core/persistence'; import { CookiePersistence } from '../platform_browser/persistence/cookie_storage'; -import { FirebaseAuth } from '@firebase/auth-types'; export const enum HttpMethod { POST = 'POST', From b8b485d47c32e969f5b1bf9f7bf324b8308c95f6 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 24 Apr 2025 15:45:33 -0700 Subject: [PATCH 15/67] include storage changes --- .../storage/src/implementation/connection.ts | 3 ++- packages/storage/src/implementation/request.ts | 17 +++++++++++++---- .../storage/src/platform/browser/connection.ts | 7 ++++++- .../storage/src/platform/node/connection.ts | 18 +++++++++++++----- packages/storage/src/service.ts | 6 ++++-- 5 files changed, 38 insertions(+), 13 deletions(-) diff --git a/packages/storage/src/implementation/connection.ts b/packages/storage/src/implementation/connection.ts index 80e29c9cd2f..ec65ace3c00 100644 --- a/packages/storage/src/implementation/connection.ts +++ b/packages/storage/src/implementation/connection.ts @@ -43,7 +43,8 @@ export interface Connection { url: string, method: string, body?: ArrayBufferView | Blob | string | null, - headers?: Headers + headers?: Headers, + isUsingEmulator?: boolean ): Promise; getErrorCode(): ErrorCode; diff --git a/packages/storage/src/implementation/request.ts b/packages/storage/src/implementation/request.ts index fae46d7a5ab..7433cd53955 100644 --- a/packages/storage/src/implementation/request.ts +++ b/packages/storage/src/implementation/request.ts @@ -71,7 +71,8 @@ class NetworkRequest implements Request { private timeout_: number, private progressCallback_: ((p1: number, p2: number) => void) | null, private connectionFactory_: () => Connection, - private retry = true + private retry = true, + private isUsingEmulator = false ) { this.promise_ = new Promise((resolve, reject) => { this.resolve_ = resolve as (value?: O | PromiseLike) => void; @@ -111,7 +112,13 @@ class NetworkRequest implements Request { // connection.send() never rejects, so we don't need to have a error handler or use catch on the returned promise. // eslint-disable-next-line @typescript-eslint/no-floating-promises connection - .send(this.url_, this.method_, this.body_, this.headers_) + .send( + this.url_, + this.method_, + this.body_, + this.headers_, + this.isUsingEmulator + ) .then(() => { if (this.progressCallback_ !== null) { connection.removeUploadProgressListener(progressListener); @@ -261,7 +268,8 @@ export function makeRequest( appCheckToken: string | null, requestFactory: () => Connection, firebaseVersion?: string, - retry = true + retry = true, + isUsingEmulator = false ): Request { const queryPart = makeQueryString(requestInfo.urlParams); const url = requestInfo.url + queryPart; @@ -282,6 +290,7 @@ export function makeRequest( requestInfo.timeout, requestInfo.progressCallback, requestFactory, - retry + retry, + isUsingEmulator ); } diff --git a/packages/storage/src/platform/browser/connection.ts b/packages/storage/src/platform/browser/connection.ts index fdd9b496242..fcbd5db0c2a 100644 --- a/packages/storage/src/platform/browser/connection.ts +++ b/packages/storage/src/platform/browser/connection.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { isCloudWorkstation } from '@firebase/util'; import { Connection, ConnectionType, @@ -63,11 +64,15 @@ abstract class XhrConnection url: string, method: string, body?: ArrayBufferView | Blob | string, - headers?: Headers + headers?: Headers, + isUsingEmulator?: boolean ): Promise { if (this.sent_) { throw internalError('cannot .send() more than once'); } + if (isCloudWorkstation(url) && isUsingEmulator) { + this.xhr_.withCredentials = true; + } this.sent_ = true; this.xhr_.open(method, url, true); if (headers !== undefined) { diff --git a/packages/storage/src/platform/node/connection.ts b/packages/storage/src/platform/node/connection.ts index 00371ff2bc5..e201ce8ffba 100644 --- a/packages/storage/src/platform/node/connection.ts +++ b/packages/storage/src/platform/node/connection.ts @@ -50,7 +50,8 @@ abstract class FetchConnection url: string, method: string, body?: NodeJS.ArrayBufferView | Blob | string, - headers?: Record + headers?: Record, + isUsingEmulator?: boolean ): Promise { if (this.sent_) { throw internalError('cannot .send() more than once'); @@ -58,7 +59,13 @@ abstract class FetchConnection this.sent_ = true; try { - const response = await newFetch(url, method, headers, body); + const response = await newFetch( + url, + method, + headers, + body, + isUsingEmulator + ); this.headers_ = response.headers; this.statusCode_ = response.status; this.errorCode_ = ErrorCode.NO_ERROR; @@ -183,14 +190,15 @@ function newFetch( url: string, method: string, headers?: Record, - body?: NodeJS.ArrayBufferView | Blob | string -) { + body?: NodeJS.ArrayBufferView | Blob | string, + isUsingEmulator?: boolean +): Promise { const fetchArgs: RequestInit = { method, headers: headers || {}, body: body as NodeJS.ArrayBufferView | string }; - if (isCloudWorkstation(url)) { + if (isCloudWorkstation(url) && isUsingEmulator) { fetchArgs.credentials = 'include'; } return fetch(url, fetchArgs); diff --git a/packages/storage/src/service.ts b/packages/storage/src/service.ts index 422e3e1a188..52afd3f2bfb 100644 --- a/packages/storage/src/service.ts +++ b/packages/storage/src/service.ts @@ -187,7 +187,8 @@ export class FirebaseStorageImpl implements FirebaseStorage { * @internal */ readonly _url?: string, - readonly _firebaseVersion?: string + readonly _firebaseVersion?: string, + readonly _isUsingEmulator = false ) { this._maxOperationRetryTime = DEFAULT_MAX_OPERATION_RETRY_TIME; this._maxUploadRetryTime = DEFAULT_MAX_UPLOAD_RETRY_TIME; @@ -320,7 +321,8 @@ export class FirebaseStorageImpl implements FirebaseStorage { appCheckToken, requestFactory, this._firebaseVersion, - retry + retry, + this._isUsingEmulator ); this._requests.add(request); // Request removes itself from set when complete. From 21ecf958848477cc524cfc95d04f79aa316d995d Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 24 Apr 2025 15:47:50 -0700 Subject: [PATCH 16/67] Updated api review --- common/api-review/util.api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/api-review/util.api.md b/common/api-review/util.api.md index f9da0226c94..bb3aaaea84e 100644 --- a/common/api-review/util.api.md +++ b/common/api-review/util.api.md @@ -271,7 +271,7 @@ export function isCloudflareWorker(): boolean; // Warning: (ae-missing-release-tag) "isCloudWorkstation" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) +// @public export function isCloudWorkstation(url: string): boolean; // Warning: (ae-missing-release-tag) "isElectron" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) From 24c157523238c291ecd05e84822f283268e146f0 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 09:05:35 -0700 Subject: [PATCH 17/67] Removed unnecessary import --- packages/firestore/src/platform/browser/webchannel_connection.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/firestore/src/platform/browser/webchannel_connection.ts b/packages/firestore/src/platform/browser/webchannel_connection.ts index b5224eac117..5223285c5a4 100644 --- a/packages/firestore/src/platform/browser/webchannel_connection.ts +++ b/packages/firestore/src/platform/browser/webchannel_connection.ts @@ -46,7 +46,6 @@ import { Code, FirestoreError } from '../../util/error'; import { logDebug, logWarn } from '../../util/log'; import { Rejecter, Resolver } from '../../util/promise'; import { StringMap } from '../../util/types'; -import { isCloudWorkstation } from '@firebase/util'; const LOG_TAG = 'WebChannelConnection'; From 7c7f3ae13f667688e9716ef049e862097d9660a6 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 09:09:52 -0700 Subject: [PATCH 18/67] Fix formatting --- packages/firestore/src/platform/browser_lite/fetch_connection.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/firestore/src/platform/browser_lite/fetch_connection.ts b/packages/firestore/src/platform/browser_lite/fetch_connection.ts index f3b2b9dbb21..690a9435dd5 100644 --- a/packages/firestore/src/platform/browser_lite/fetch_connection.ts +++ b/packages/firestore/src/platform/browser_lite/fetch_connection.ts @@ -16,6 +16,7 @@ */ import { isCloudWorkstation } from '@firebase/util'; + import { Token } from '../../api/credentials'; import { Stream } from '../../remote/connection'; import { RestConnection } from '../../remote/rest_connection'; From d62409a3929a7e0d33430ffc640c4482a4595a09 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 09:17:44 -0700 Subject: [PATCH 19/67] Fixed data connect test --- packages/data-connect/test/unit/fetch.test.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/data-connect/test/unit/fetch.test.ts b/packages/data-connect/test/unit/fetch.test.ts index 6cf2750d50d..11bc8d03818 100644 --- a/packages/data-connect/test/unit/fetch.test.ts +++ b/packages/data-connect/test/unit/fetch.test.ts @@ -57,7 +57,8 @@ describe('fetch', () => { null, null, false, - CallerSdkTypeEnum.Base + CallerSdkTypeEnum.Base, + false ) ).to.eventually.be.rejectedWith(message); }); @@ -81,7 +82,8 @@ describe('fetch', () => { null, null, false, - CallerSdkTypeEnum.Base + CallerSdkTypeEnum.Base, + false ) ).to.eventually.be.rejectedWith(JSON.stringify(json)); }); @@ -112,7 +114,8 @@ describe('fetch', () => { null, null, false, - CallerSdkTypeEnum.Base + CallerSdkTypeEnum.Base, + false ) ).to.eventually.be.rejected.then(error => { expect(error.response.data).to.eq(json.data); @@ -143,7 +146,8 @@ describe('fetch', () => { null, null, false, // _isUsingGen is false - callerSdkType as CallerSdkType + callerSdkType as CallerSdkType, + false ); let expectedHeaderRegex: RegExp; @@ -191,7 +195,8 @@ describe('fetch', () => { null, null, true, // _isUsingGen is true - callerSdkType as CallerSdkType + callerSdkType as CallerSdkType, + false ); let expectedHeaderRegex: RegExp; From 82faa082811f3292fdf9f871879dae37d7923590 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 10:57:29 -0700 Subject: [PATCH 20/67] Included extra url in externs --- packages/firestore/externs.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/firestore/externs.json b/packages/firestore/externs.json index 03d19ee8e83..60ced481279 100644 --- a/packages/firestore/externs.json +++ b/packages/firestore/externs.json @@ -30,6 +30,7 @@ "packages/util/dist/src/defaults.d.ts", "packages/util/dist/src/emulator.d.ts", "packages/util/dist/src/environment.d.ts", + "packages/util/dist/src/url.d.ts", "packages/util/dist/src/compat.d.ts", "packages/util/dist/src/global.d.ts", "packages/util/dist/src/obj.d.ts", From 32c461a7906ae1f4b851ed508253f4874402aad3 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 11:29:48 -0700 Subject: [PATCH 21/67] Fixed fdc tests --- packages/data-connect/src/network/fetch.ts | 5 +++-- packages/util/index.node.ts | 1 + packages/util/src/url.ts | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/data-connect/src/network/fetch.ts b/packages/data-connect/src/network/fetch.ts index cc71844cac1..3e8e2cab476 100644 --- a/packages/data-connect/src/network/fetch.ts +++ b/packages/data-connect/src/network/fetch.ts @@ -15,6 +15,8 @@ * limitations under the License. */ +import { isCloudWorkstation } from '@firebase/util'; + import { Code, DataConnectError, @@ -22,10 +24,9 @@ import { DataConnectOperationFailureResponse } from '../core/error'; import { SDK_VERSION } from '../core/version'; -import { logDebug, logError } from '../logger'; +import { logError } from '../logger'; import { CallerSdkType, CallerSdkTypeEnum } from './transport'; -import { isCloudWorkstation } from '@firebase/util'; let connectFetch: typeof fetch | null = globalThis.fetch; export function initializeFetch(fetchImpl: typeof fetch): void { diff --git a/packages/util/index.node.ts b/packages/util/index.node.ts index d839460713c..12fcf8a6de5 100644 --- a/packages/util/index.node.ts +++ b/packages/util/index.node.ts @@ -42,3 +42,4 @@ export * from './src/exponential_backoff'; export * from './src/formatters'; export * from './src/compat'; export * from './src/global'; +export * from './src/url'; diff --git a/packages/util/src/url.ts b/packages/util/src/url.ts index d8de8d06cc7..e51bef1e91c 100644 --- a/packages/util/src/url.ts +++ b/packages/util/src/url.ts @@ -15,6 +15,9 @@ * limitations under the License. */ +/** + * Checks whether a host url is a cloud workstation. + */ export function isCloudWorkstation(url: string): boolean { return url.endsWith('.cloudworkstations.dev'); } From da5b7bf4cb56b31d92809e209b5169bf6e641e5c Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 11:43:41 -0700 Subject: [PATCH 22/67] Passed in emulator information --- packages/firestore/src/core/database_info.ts | 3 ++- packages/firestore/src/lite-api/components.ts | 6 ++++-- .../firestore/src/platform/browser/webchannel_connection.ts | 3 ++- .../firestore/src/platform/browser_lite/fetch_connection.ts | 5 +++-- packages/firestore/src/remote/rest_connection.ts | 5 +++-- .../firestore/test/integration/util/internal_helpers.ts | 3 ++- packages/firestore/test/unit/remote/rest_connection.test.ts | 3 ++- packages/firestore/test/unit/specs/spec_test_runner.ts | 3 ++- 8 files changed, 20 insertions(+), 11 deletions(-) diff --git a/packages/firestore/src/core/database_info.ts b/packages/firestore/src/core/database_info.ts index 0325f8166b6..a057516763f 100644 --- a/packages/firestore/src/core/database_info.ts +++ b/packages/firestore/src/core/database_info.ts @@ -48,7 +48,8 @@ export class DatabaseInfo { readonly forceLongPolling: boolean, readonly autoDetectLongPolling: boolean, readonly longPollingOptions: ExperimentalLongPollingOptions, - readonly useFetchStreams: boolean + readonly useFetchStreams: boolean, + readonly isUsingEmulator: boolean ) {} } diff --git a/packages/firestore/src/lite-api/components.ts b/packages/firestore/src/lite-api/components.ts index 436d2b5d4d8..a51e451dcac 100644 --- a/packages/firestore/src/lite-api/components.ts +++ b/packages/firestore/src/lite-api/components.ts @@ -28,7 +28,7 @@ import { Datastore, newDatastore } from '../remote/datastore'; import { Code, FirestoreError } from '../util/error'; import { logDebug } from '../util/log'; -import { FirestoreSettingsImpl } from './settings'; +import { FirestoreSettingsImpl, PrivateSettings } from './settings'; export const LOG_TAG = 'ComponentProvider'; @@ -110,6 +110,7 @@ export function makeDatabaseInfo( persistenceKey: string, settings: FirestoreSettingsImpl ): DatabaseInfo { + const privateSettings = settings as PrivateSettings; return new DatabaseInfo( databaseId, appId, @@ -119,6 +120,7 @@ export function makeDatabaseInfo( settings.experimentalForceLongPolling, settings.experimentalAutoDetectLongPolling, cloneLongPollingOptions(settings.experimentalLongPollingOptions), - settings.useFetchStreams + settings.useFetchStreams, + privateSettings.emulatorOptions !== undefined ); } diff --git a/packages/firestore/src/platform/browser/webchannel_connection.ts b/packages/firestore/src/platform/browser/webchannel_connection.ts index 5223285c5a4..a2d540b0e85 100644 --- a/packages/firestore/src/platform/browser/webchannel_connection.ts +++ b/packages/firestore/src/platform/browser/webchannel_connection.ts @@ -71,7 +71,8 @@ export class WebChannelConnection extends RestConnection { rpcName: string, url: string, headers: StringMap, - body: Req + body: Req, + _isUsingEmulator: boolean ): Promise { const streamId = generateUniqueDebugId(); return new Promise((resolve: Resolver, reject: Rejecter) => { diff --git a/packages/firestore/src/platform/browser_lite/fetch_connection.ts b/packages/firestore/src/platform/browser_lite/fetch_connection.ts index 690a9435dd5..580c83c99ff 100644 --- a/packages/firestore/src/platform/browser_lite/fetch_connection.ts +++ b/packages/firestore/src/platform/browser_lite/fetch_connection.ts @@ -40,7 +40,8 @@ export class FetchConnection extends RestConnection { rpcName: string, url: string, headers: StringMap, - body: Req + body: Req, + isUsingEmulator: boolean ): Promise { const requestJson = JSON.stringify(body); let response: Response; @@ -51,7 +52,7 @@ export class FetchConnection extends RestConnection { headers, body: requestJson }; - if (isCloudWorkstation(url)) { + if (isCloudWorkstation(url) && isUsingEmulator) { fetchArgs.credentials = 'include'; } response = await fetch(url, fetchArgs); diff --git a/packages/firestore/src/remote/rest_connection.ts b/packages/firestore/src/remote/rest_connection.ts index 470cb332ce2..f80c075a06b 100644 --- a/packages/firestore/src/remote/rest_connection.ts +++ b/packages/firestore/src/remote/rest_connection.ts @@ -98,7 +98,7 @@ export abstract class RestConnection implements Connection { }; this.modifyHeadersForRequest(headers, authToken, appCheckToken); - return this.performRPCRequest(rpcName, url, headers, req).then( + return this.performRPCRequest(rpcName, url, headers, req, this.databaseInfo.isUsingEmulator).then( response => { logDebug(LOG_TAG, `Received RPC '${rpcName}' ${streamId}: `, response); return response; @@ -179,7 +179,8 @@ export abstract class RestConnection implements Connection { rpcName: string, url: string, headers: StringMap, - body: Req + body: Req, + isUsingEmulator: boolean ): Promise; private makeUrl(rpcName: string, path: string): string { diff --git a/packages/firestore/test/integration/util/internal_helpers.ts b/packages/firestore/test/integration/util/internal_helpers.ts index 86ded6af3c1..768b85df816 100644 --- a/packages/firestore/test/integration/util/internal_helpers.ts +++ b/packages/firestore/test/integration/util/internal_helpers.ts @@ -61,7 +61,8 @@ export function getDefaultDatabaseInfo(): DatabaseInfo { cloneLongPollingOptions( DEFAULT_SETTINGS.experimentalLongPollingOptions ?? {} ), - /*use FetchStreams= */ false + /*use FetchStreams= */ false, + /*isUsingEmulator=*/false ); } diff --git a/packages/firestore/test/unit/remote/rest_connection.test.ts b/packages/firestore/test/unit/remote/rest_connection.test.ts index d45a75ce67b..100b8b8368e 100644 --- a/packages/firestore/test/unit/remote/rest_connection.test.ts +++ b/packages/firestore/test/unit/remote/rest_connection.test.ts @@ -67,7 +67,8 @@ describe('RestConnection', () => { /*forceLongPolling=*/ false, /*autoDetectLongPolling=*/ false, /*longPollingOptions=*/ {}, - /*useFetchStreams=*/ false + /*useFetchStreams=*/ false, + /*isUsingEmulator=*/ false ); const connection = new TestRestConnection(testDatabaseInfo); diff --git a/packages/firestore/test/unit/specs/spec_test_runner.ts b/packages/firestore/test/unit/specs/spec_test_runner.ts index ee0af0b8bf8..51d2229b8a1 100644 --- a/packages/firestore/test/unit/specs/spec_test_runner.ts +++ b/packages/firestore/test/unit/specs/spec_test_runner.ts @@ -282,7 +282,8 @@ abstract class TestRunner { /*forceLongPolling=*/ false, /*autoDetectLongPolling=*/ false, /*longPollingOptions=*/ {}, - /*useFetchStreams=*/ false + /*useFetchStreams=*/ false, + /*isUsingEmulator=*/ false ); // TODO(mrschmidt): During client startup in `firestore_client`, we block From b424e58977381cc1f8e24ea4cda48ccc9b48d0e3 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 11:47:14 -0700 Subject: [PATCH 23/67] Fixed formattign --- packages/firestore/src/remote/rest_connection.ts | 8 +++++++- .../firestore/test/integration/util/internal_helpers.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/firestore/src/remote/rest_connection.ts b/packages/firestore/src/remote/rest_connection.ts index f80c075a06b..60d4af5c1af 100644 --- a/packages/firestore/src/remote/rest_connection.ts +++ b/packages/firestore/src/remote/rest_connection.ts @@ -98,7 +98,13 @@ export abstract class RestConnection implements Connection { }; this.modifyHeadersForRequest(headers, authToken, appCheckToken); - return this.performRPCRequest(rpcName, url, headers, req, this.databaseInfo.isUsingEmulator).then( + return this.performRPCRequest( + rpcName, + url, + headers, + req, + this.databaseInfo.isUsingEmulator + ).then( response => { logDebug(LOG_TAG, `Received RPC '${rpcName}' ${streamId}: `, response); return response; diff --git a/packages/firestore/test/integration/util/internal_helpers.ts b/packages/firestore/test/integration/util/internal_helpers.ts index 768b85df816..e5e64b5fbf4 100644 --- a/packages/firestore/test/integration/util/internal_helpers.ts +++ b/packages/firestore/test/integration/util/internal_helpers.ts @@ -62,7 +62,7 @@ export function getDefaultDatabaseInfo(): DatabaseInfo { DEFAULT_SETTINGS.experimentalLongPollingOptions ?? {} ), /*use FetchStreams= */ false, - /*isUsingEmulator=*/false + /*isUsingEmulator=*/ false ); } From 7d2313fa6aafb99a374a96ee714306ad89404188 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 13:40:30 -0700 Subject: [PATCH 24/67] WIP --- config/.eslintrc.js | 16 +++++----- packages/auth/src/core/auth/emulator.test.ts | 32 ++++++++++++++++++- packages/auth/src/core/util/fetch_provider.ts | 1 + 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/config/.eslintrc.js b/config/.eslintrc.js index 57243a3e2a4..589dbf4cccd 100644 --- a/config/.eslintrc.js +++ b/config/.eslintrc.js @@ -98,18 +98,18 @@ module.exports = { 'object': 'it', 'property': 'skip' }, - { - 'object': 'it', - 'property': 'only' - }, + // { + // 'object': 'it', + // 'property': 'only' + // }, { 'object': 'describe', 'property': 'skip' }, - { - 'object': 'describe', - 'property': 'only' - }, + // { + // 'object': 'describe', + // 'property': 'only' + // }, { 'object': 'xit' } diff --git a/packages/auth/src/core/auth/emulator.test.ts b/packages/auth/src/core/auth/emulator.test.ts index 47c5d927c44..35f82249ab2 100644 --- a/packages/auth/src/core/auth/emulator.test.ts +++ b/packages/auth/src/core/auth/emulator.test.ts @@ -29,18 +29,21 @@ import { Endpoint } from '../../api'; import { UserInternal } from '../../model/user'; import { _castAuth } from './auth_impl'; import { connectAuthEmulator } from './emulator'; +import { FetchProvider } from '../util/fetch_provider'; use(sinonChai); use(chaiAsPromised); -describe('core/auth/emulator', () => { +describe.only('core/auth/emulator', () => { let auth: TestAuth; let user: UserInternal; let normalEndpoint: fetch.Route; let emulatorEndpoint: fetch.Route; + let spy: sinon.SinonSpy; beforeEach(async () => { auth = await testAuth(); + spy = sinon.spy(FetchProvider.fetch()); user = testUser(_castAuth(auth), 'uid', 'email', true); fetch.setUp(); normalEndpoint = mockEndpoint(Endpoint.DELETE_ACCOUNT, {}); @@ -93,6 +96,16 @@ describe('core/auth/emulator', () => { 'auth/emulator-config-failed' ); }); + it.only('sends the proper value', async () => { + expect(() => connectAuthEmulator(auth, 'http://127.0.0.1:2020')).to.not + .throw; + await user.delete(); + expect(spy).to.have.been.called; + expect(() => connectAuthEmulator(auth, 'http://127.0.0.1:2021')).to.throw( + FirebaseError, + 'auth/emulator-config-failed' + ); + }); it('subsequent calls update the endpoint appropriately', async () => { connectAuthEmulator(auth, 'http://127.0.0.1:2021'); @@ -111,6 +124,23 @@ describe('core/auth/emulator', () => { }); }); + it('subsequent calls update the endpoint appropriately', async () => { + connectAuthEmulator(auth, 'http://127.0.0.1:2021'); + expect(auth.emulatorConfig).to.eql({ + protocol: 'http', + host: '127.0.0.1', + port: 2021, + options: { disableWarnings: false } + }); + connectAuthEmulator(auth, 'http://127.0.0.1:2020'); + expect(auth.emulatorConfig).to.eql({ + protocol: 'http', + host: '127.0.0.1', + port: 2020, + options: { disableWarnings: false } + }); + }); + it('updates the endpoint appropriately', async () => { connectAuthEmulator(auth, 'http://127.0.0.1:2020'); await user.delete(); diff --git a/packages/auth/src/core/util/fetch_provider.ts b/packages/auth/src/core/util/fetch_provider.ts index 14433d6eacb..6a481630eed 100644 --- a/packages/auth/src/core/util/fetch_provider.ts +++ b/packages/auth/src/core/util/fetch_provider.ts @@ -37,6 +37,7 @@ export class FetchProvider { } static fetch(): typeof fetch { + console.log('fetch!'); if (this.fetchImpl) { return this.fetchImpl; } From 6e0761d920c6794aec55d86867ce19ee0e3f4a7e Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 16:27:06 -0700 Subject: [PATCH 25/67] Added emulator status --- common/api-review/util.api.md | 15 +++++ packages/auth/src/api/index.ts | 14 ++++- packages/auth/src/core/auth/emulator.test.ts | 2 +- packages/auth/src/core/auth/emulator.ts | 46 +++------------ packages/firestore/src/lite-api/database.ts | 16 ++++- packages/firestore/src/lite-api/settings.ts | 4 ++ packages/util/src/emulator.ts | 62 ++++++++++++++++++++ 7 files changed, 116 insertions(+), 43 deletions(-) diff --git a/common/api-review/util.api.md b/common/api-review/util.api.md index bb3aaaea84e..0ade0d17371 100644 --- a/common/api-review/util.api.md +++ b/common/api-review/util.api.md @@ -140,6 +140,16 @@ export type EmulatorMockTokenOptions = ({ sub: string; }) & Partial; +// Warning: (ae-missing-release-tag) "EmulatorStatus" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface EmulatorStatus { + // (undocumented) + isRunningEmulator: boolean; + // (undocumented) + name: string; +} + // Warning: (ae-missing-release-tag) "ErrorData" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -481,6 +491,11 @@ export interface Subscribe { // @public (undocumented) export type Unsubscribe = () => void; +// Warning: (ae-missing-release-tag) "updateStatus" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function updateStatus(emulatorStatus: EmulatorStatus, isCloudWorkstation: boolean): void; + // Warning: (ae-missing-release-tag) "validateArgCount" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index af9b3c63bf1..f5083b3ddae 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -19,7 +19,8 @@ import { FirebaseError, isCloudflareWorker, isCloudWorkstation, - querystring + querystring, + updateStatus } from '@firebase/util'; import { AuthErrorCode, NamedErrorParams } from '../core/errors'; @@ -198,7 +199,16 @@ export async function _performFetchWithErrorHandling( customErrorMap: Partial>, fetchFn: () => Promise ): Promise { - (auth as AuthInternal)._canInitEmulator = false; + const authInternal = auth as AuthInternal; + updateStatus( + { + name: 'Auth', + isRunningEmulator: authInternal.emulatorConfig !== undefined + }, + authInternal.emulatorConfig!! && + isCloudWorkstation(authInternal.emulatorConfig.host) + ); + authInternal._canInitEmulator = false; const errorMap = { ...SERVER_ERROR_MAP, ...customErrorMap }; try { const networkTimeout = new NetworkTimeout(auth); diff --git a/packages/auth/src/core/auth/emulator.test.ts b/packages/auth/src/core/auth/emulator.test.ts index 35f82249ab2..e1996dafd2d 100644 --- a/packages/auth/src/core/auth/emulator.test.ts +++ b/packages/auth/src/core/auth/emulator.test.ts @@ -124,7 +124,7 @@ describe.only('core/auth/emulator', () => { }); }); - it('subsequent calls update the endpoint appropriately', async () => { + it('subsequent calls update the endpoint appropriately', async () => { connectAuthEmulator(auth, 'http://127.0.0.1:2021'); expect(auth.emulatorConfig).to.eql({ protocol: 'http', diff --git a/packages/auth/src/core/auth/emulator.ts b/packages/auth/src/core/auth/emulator.ts index 60cc9403d3d..fb78b72e0b8 100644 --- a/packages/auth/src/core/auth/emulator.ts +++ b/packages/auth/src/core/auth/emulator.ts @@ -18,7 +18,7 @@ import { Auth } from '../../model/public_types'; import { AuthErrorCode } from '../errors'; import { _assert } from '../util/assert'; import { _castAuth } from './auth_impl'; -import { deepEqual } from '@firebase/util'; +import { deepEqual, isCloudWorkstation, updateStatus } from '@firebase/util'; /** * Changes the {@link Auth} instance to communicate with the Firebase Auth Emulator, instead of production @@ -98,7 +98,13 @@ export function connectAuthEmulator( authInternal.settings.appVerificationDisabledForTesting = true; if (!disableWarnings) { - emitEmulatorWarning(); + updateStatus( + { + name: 'Auth', + isRunningEmulator: true + }, + isCloudWorkstation(emulatorConfig.host) + ); } } @@ -137,39 +143,3 @@ function parsePort(portStr: string): number | null { } return port; } - -function emitEmulatorWarning(): void { - function attachBanner(): void { - const el = document.createElement('p'); - const sty = el.style; - el.innerText = - 'Running in emulator mode. Do not use with production credentials.'; - sty.position = 'fixed'; - sty.width = '100%'; - sty.backgroundColor = '#ffffff'; - sty.border = '.1em solid #000000'; - sty.color = '#b50000'; - sty.bottom = '0px'; - sty.left = '0px'; - sty.margin = '0px'; - sty.zIndex = '10000'; - sty.textAlign = 'center'; - el.classList.add('firebase-emulator-warning'); - document.body.appendChild(el); - } - - if (typeof console !== 'undefined' && typeof console.info === 'function') { - console.info( - 'WARNING: You are using the Auth Emulator,' + - ' which is intended for local testing only. Do not use with' + - ' production credentials.' - ); - } - if (typeof window !== 'undefined' && typeof document !== 'undefined') { - if (document.readyState === 'loading') { - window.addEventListener('DOMContentLoaded', attachBanner); - } else { - attachBanner(); - } - } -} diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index 5c344fb72c6..a7c78710c1f 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -26,7 +26,9 @@ import { createMockUserToken, deepEqual, EmulatorMockTokenOptions, - getDefaultEmulatorHostnameAndPort + getDefaultEmulatorHostnameAndPort, + isCloudWorkstation, + updateStatus } from '@firebase/util'; import { @@ -140,6 +142,13 @@ export class Firestore implements FirestoreService { _freezeSettings(): FirestoreSettingsImpl { this._settingsFrozen = true; + updateStatus( + { + name: 'Firestore', + isRunningEmulator: (this._settings as PrivateSettings).emulator!! + }, + isCloudWorkstation(this._settings.host) + ); return this._settings; } @@ -297,6 +306,7 @@ export function getFirestore( if (!db._initialized) { const emulator = getDefaultEmulatorHostnameAndPort('firestore'); if (emulator) { + console.log('emulator'); connectFirestoreEmulator(db, ...emulator); } } @@ -346,8 +356,10 @@ export function connectFirestoreEmulator( ...settings, host: newHostSetting, ssl, - emulatorOptions: options + emulatorOptions: options, + emulator: true }; + console.log(newConfig); // No-op if the new configuration matches the current configuration. This supports SSR // enviornments which might call `connectFirestoreEmulator` multiple times as a standard practice. if (deepEqual(newConfig, existingConfig)) { diff --git a/packages/firestore/src/lite-api/settings.ts b/packages/firestore/src/lite-api/settings.ts index a1bba373d13..036b02a3f53 100644 --- a/packages/firestore/src/lite-api/settings.ts +++ b/packages/firestore/src/lite-api/settings.ts @@ -83,6 +83,7 @@ export interface PrivateSettings extends FirestoreSettings { experimentalLongPollingOptions?: ExperimentalLongPollingOptions; useFetchStreams?: boolean; emulatorOptions?: { mockUserToken?: EmulatorMockTokenOptions | string }; + emulator?: boolean; localCache?: FirestoreLocalCache; } @@ -112,6 +113,8 @@ export class FirestoreSettingsImpl { readonly useFetchStreams: boolean; readonly localCache?: FirestoreLocalCache; + readonly emulator?: boolean; + // Can be a google-auth-library or gapi client. // eslint-disable-next-line @typescript-eslint/no-explicit-any credentials?: any; @@ -130,6 +133,7 @@ export class FirestoreSettingsImpl { this.host = settings.host; this.ssl = settings.ssl ?? DEFAULT_SSL; } + this.emulator = settings.emulator; this.credentials = settings.credentials; this.ignoreUndefinedProperties = !!settings.ignoreUndefinedProperties; diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 2850b5be378..af4b3a85734 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -16,6 +16,7 @@ */ import { base64urlEncodeWithoutPadding } from './crypt'; +import { FirebaseApp } from '@firebase/app'; // Firebase Auth tokens contain snake_case claims following the JWT standard / convention. /* eslint-disable camelcase */ @@ -140,3 +141,64 @@ export function createMockUserToken( signature ].join('.'); } + +function getOrCreate(id: string): { created: boolean; element: HTMLElement } { + let parentDiv = document.getElementById(id); + let created = false; + if (!parentDiv) { + parentDiv = document.createElement('div'); + parentDiv.setAttribute('id', id); + created = true; + } + return { created, element: parentDiv }; +} + +export interface EmulatorStatus { + name: string; + isRunningEmulator: boolean; +} +export function updateStatus( + emulatorStatus: EmulatorStatus, + isCloudWorkstation: boolean +) { + function setupDom() { + const parentDivId = `__firebase_status`; + + let { element: parentDiv, created } = getOrCreate(parentDivId); + + if (created) { + parentDiv.style.position = 'fixed'; + parentDiv.style.bottom = '0px'; + parentDiv.style.border = 'solid 1px'; + parentDiv.style.width = '100%'; + parentDiv.style.borderRadius = '10px'; + parentDiv.style.padding = '.5em'; + parentDiv.style.textAlign = 'center'; + document.body.appendChild(parentDiv); + } + + const { name, isRunningEmulator } = emulatorStatus; + const { element, created: productDivCreated } = getOrCreate( + `${parentDivId}_${name}` + ); + // If in prod, and not using a cloud workstation, we should remove the node, as the banner can be distracting. + if (!isRunningEmulator && !isCloudWorkstation) { + element.remove(); + return; + } + if (productDivCreated) { + parentDiv.appendChild(element); + } + element.style.color = isRunningEmulator ? 'green' : 'red'; + element.innerHTML = `${name} is running in ${ + isRunningEmulator ? 'emulator' : 'prod' + } mode`; + } + if (typeof window !== 'undefined' && typeof document !== 'undefined') { + if (document.readyState === 'loading') { + window.addEventListener('DOMContentLoaded', setupDom); + } else { + setupDom(); + } + } +} From e7b292db7e8e74369592319b93ab0e1249e938dd Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 25 Apr 2025 16:33:18 -0700 Subject: [PATCH 26/67] Removed firebaseapp import --- packages/util/src/emulator.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index af4b3a85734..cb797fd6987 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -16,7 +16,6 @@ */ import { base64urlEncodeWithoutPadding } from './crypt'; -import { FirebaseApp } from '@firebase/app'; // Firebase Auth tokens contain snake_case claims following the JWT standard / convention. /* eslint-disable camelcase */ From 6ca5c2460901086cd81ecf593a34601c89c086d3 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 1 May 2025 12:06:07 -0700 Subject: [PATCH 27/67] Removed app check change --- packages/app-check/src/client.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/app-check/src/client.ts b/packages/app-check/src/client.ts index e8223675ae3..1861383174d 100644 --- a/packages/app-check/src/client.ts +++ b/packages/app-check/src/client.ts @@ -25,7 +25,6 @@ import { FirebaseApp } from '@firebase/app'; import { ERROR_FACTORY, AppCheckError } from './errors'; import { Provider } from '@firebase/component'; import { AppCheckTokenInternal } from './types'; -import { isCloudWorkstation } from '@firebase/util'; /** * Response JSON returned from AppCheck server endpoint. @@ -63,9 +62,6 @@ export async function exchangeToken( body: JSON.stringify(body), headers }; - if (isCloudWorkstation(url)) { - options.credentials = 'include'; - } let response; try { response = await fetch(url, options); From 6d0af9d43cb3ea398950859b80c7f731ed91cd89 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 1 May 2025 12:07:27 -0700 Subject: [PATCH 28/67] Removed eslintrc change --- config/.eslintrc.js | 16 ++++++++-------- packages/firestore/src/lite-api/database.ts | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/config/.eslintrc.js b/config/.eslintrc.js index 589dbf4cccd..57243a3e2a4 100644 --- a/config/.eslintrc.js +++ b/config/.eslintrc.js @@ -98,18 +98,18 @@ module.exports = { 'object': 'it', 'property': 'skip' }, - // { - // 'object': 'it', - // 'property': 'only' - // }, + { + 'object': 'it', + 'property': 'only' + }, { 'object': 'describe', 'property': 'skip' }, - // { - // 'object': 'describe', - // 'property': 'only' - // }, + { + 'object': 'describe', + 'property': 'only' + }, { 'object': 'xit' } diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index a7b55d5c7da..a32cf6a484c 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -307,7 +307,6 @@ export function getFirestore( if (!db._initialized) { const emulator = getDefaultEmulatorHostnameAndPort('firestore'); if (emulator) { - console.log('emulator'); connectFirestoreEmulator(db, ...emulator); } } From 445c490b0a2268c6f7a80a56d1ac2e7472de1f90 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 1 May 2025 12:08:07 -0700 Subject: [PATCH 29/67] Removed unnecessary test --- packages/auth/src/core/auth/emulator.test.ts | 32 +------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/packages/auth/src/core/auth/emulator.test.ts b/packages/auth/src/core/auth/emulator.test.ts index e1996dafd2d..47c5d927c44 100644 --- a/packages/auth/src/core/auth/emulator.test.ts +++ b/packages/auth/src/core/auth/emulator.test.ts @@ -29,21 +29,18 @@ import { Endpoint } from '../../api'; import { UserInternal } from '../../model/user'; import { _castAuth } from './auth_impl'; import { connectAuthEmulator } from './emulator'; -import { FetchProvider } from '../util/fetch_provider'; use(sinonChai); use(chaiAsPromised); -describe.only('core/auth/emulator', () => { +describe('core/auth/emulator', () => { let auth: TestAuth; let user: UserInternal; let normalEndpoint: fetch.Route; let emulatorEndpoint: fetch.Route; - let spy: sinon.SinonSpy; beforeEach(async () => { auth = await testAuth(); - spy = sinon.spy(FetchProvider.fetch()); user = testUser(_castAuth(auth), 'uid', 'email', true); fetch.setUp(); normalEndpoint = mockEndpoint(Endpoint.DELETE_ACCOUNT, {}); @@ -96,33 +93,6 @@ describe.only('core/auth/emulator', () => { 'auth/emulator-config-failed' ); }); - it.only('sends the proper value', async () => { - expect(() => connectAuthEmulator(auth, 'http://127.0.0.1:2020')).to.not - .throw; - await user.delete(); - expect(spy).to.have.been.called; - expect(() => connectAuthEmulator(auth, 'http://127.0.0.1:2021')).to.throw( - FirebaseError, - 'auth/emulator-config-failed' - ); - }); - - it('subsequent calls update the endpoint appropriately', async () => { - connectAuthEmulator(auth, 'http://127.0.0.1:2021'); - expect(auth.emulatorConfig).to.eql({ - protocol: 'http', - host: '127.0.0.1', - port: 2021, - options: { disableWarnings: false } - }); - connectAuthEmulator(auth, 'http://127.0.0.1:2020'); - expect(auth.emulatorConfig).to.eql({ - protocol: 'http', - host: '127.0.0.1', - port: 2020, - options: { disableWarnings: false } - }); - }); it('subsequent calls update the endpoint appropriately', async () => { connectAuthEmulator(auth, 'http://127.0.0.1:2021'); From d97337fb9e4e5aa7437f61d64dd38725bd783e90 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 1 May 2025 12:17:25 -0700 Subject: [PATCH 30/67] Fixed failing tests --- packages/auth/src/core/auth/emulator.ts | 32 ++++++++++++++----- packages/auth/src/core/util/fetch_provider.ts | 1 - .../storage/src/platform/node/connection.ts | 2 +- packages/util/src/emulator.ts | 1 + 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/packages/auth/src/core/auth/emulator.ts b/packages/auth/src/core/auth/emulator.ts index 6ca54051818..648128f9fb0 100644 --- a/packages/auth/src/core/auth/emulator.ts +++ b/packages/auth/src/core/auth/emulator.ts @@ -18,7 +18,12 @@ import { Auth } from '../../model/public_types'; import { AuthErrorCode } from '../errors'; import { _assert } from '../util/assert'; import { _castAuth } from './auth_impl'; -import { deepEqual, isCloudWorkstation, pingServer, updateStatus } from '@firebase/util'; +import { + deepEqual, + isCloudWorkstation, + pingServer, + updateStatus +} from '@firebase/util'; /** * Changes the {@link Auth} instance to communicate with the Firebase Auth Emulator, instead of production @@ -98,13 +103,7 @@ export function connectAuthEmulator( authInternal.settings.appVerificationDisabledForTesting = true; if (!disableWarnings) { - updateStatus( - { - name: 'Auth', - isRunningEmulator: true - }, - isCloudWorkstation(emulatorConfig.host) - ); + emitEmulatorWarning(isCloudWorkstation(emulatorConfig.host)); } // Workaround to get cookies in Firebase Studio @@ -148,3 +147,20 @@ function parsePort(portStr: string): number | null { } return port; } + +function emitEmulatorWarning(isCloudWorkstation: boolean): void { + updateStatus( + { + name: 'Auth', + isRunningEmulator: true + }, + isCloudWorkstation + ); + if (typeof console !== 'undefined' && typeof console.info === 'function') { + console.info( + 'WARNING: You are using the Auth Emulator,' + + ' which is intended for local testing only. Do not use with' + + ' production credentials.' + ); + } +} diff --git a/packages/auth/src/core/util/fetch_provider.ts b/packages/auth/src/core/util/fetch_provider.ts index 6a481630eed..14433d6eacb 100644 --- a/packages/auth/src/core/util/fetch_provider.ts +++ b/packages/auth/src/core/util/fetch_provider.ts @@ -37,7 +37,6 @@ export class FetchProvider { } static fetch(): typeof fetch { - console.log('fetch!'); if (this.fetchImpl) { return this.fetchImpl; } diff --git a/packages/storage/src/platform/node/connection.ts b/packages/storage/src/platform/node/connection.ts index d79e4d73254..2dd869eb2f0 100644 --- a/packages/storage/src/platform/node/connection.ts +++ b/packages/storage/src/platform/node/connection.ts @@ -51,7 +51,7 @@ abstract class FetchConnection method: string, isUsingEmulator: boolean, body?: NodeJS.ArrayBufferView | Blob | string, - headers?: Record, + headers?: Record ): Promise { if (this.sent_) { throw internalError('cannot .send() more than once'); diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index cb797fd6987..ba089bc14a3 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -173,6 +173,7 @@ export function updateStatus( parentDiv.style.borderRadius = '10px'; parentDiv.style.padding = '.5em'; parentDiv.style.textAlign = 'center'; + parentDiv.classList.add('firebase-emulator-warning'); document.body.appendChild(parentDiv); } From 8f6167e250af21f21034bcb40300e556345d437a Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 11:17:08 -0700 Subject: [PATCH 31/67] WIP --- common/api-review/util.api.md | 4 +- packages/auth/src/api/index.ts | 8 +- packages/auth/src/core/auth/emulator.ts | 7 +- packages/firestore/src/lite-api/database.ts | 7 +- packages/util/src/emulator.ts | 136 ++++++++++++++++---- 5 files changed, 117 insertions(+), 45 deletions(-) diff --git a/common/api-review/util.api.md b/common/api-review/util.api.md index 30e797152bb..9fb61715a36 100644 --- a/common/api-review/util.api.md +++ b/common/api-review/util.api.md @@ -146,8 +146,6 @@ export type EmulatorMockTokenOptions = ({ export interface EmulatorStatus { // (undocumented) isRunningEmulator: boolean; - // (undocumented) - name: string; } // Warning: (ae-missing-release-tag) "ErrorData" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -495,7 +493,7 @@ export type Unsubscribe = () => void; // Warning: (ae-missing-release-tag) "updateStatus" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function updateStatus(emulatorStatus: EmulatorStatus, isCloudWorkstation: boolean): void; +export function updateStatus(name: string, isRunningEmulator: boolean): void; // Warning: (ae-missing-release-tag) "validateArgCount" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index f5083b3ddae..6d640c236b7 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -201,12 +201,8 @@ export async function _performFetchWithErrorHandling( ): Promise { const authInternal = auth as AuthInternal; updateStatus( - { - name: 'Auth', - isRunningEmulator: authInternal.emulatorConfig !== undefined - }, - authInternal.emulatorConfig!! && - isCloudWorkstation(authInternal.emulatorConfig.host) + 'Auth', + authInternal.emulatorConfig !== null ); authInternal._canInitEmulator = false; const errorMap = { ...SERVER_ERROR_MAP, ...customErrorMap }; diff --git a/packages/auth/src/core/auth/emulator.ts b/packages/auth/src/core/auth/emulator.ts index 648128f9fb0..1c4fb4b0fbd 100644 --- a/packages/auth/src/core/auth/emulator.ts +++ b/packages/auth/src/core/auth/emulator.ts @@ -150,11 +150,8 @@ function parsePort(portStr: string): number | null { function emitEmulatorWarning(isCloudWorkstation: boolean): void { updateStatus( - { - name: 'Auth', - isRunningEmulator: true - }, - isCloudWorkstation + 'Auth', + true ); if (typeof console !== 'undefined' && typeof console.info === 'function') { console.info( diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index a32cf6a484c..cde362df93b 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -144,11 +144,8 @@ export class Firestore implements FirestoreService { _freezeSettings(): FirestoreSettingsImpl { this._settingsFrozen = true; updateStatus( - { - name: 'Firestore', - isRunningEmulator: (this._settings as PrivateSettings).emulator!! - }, - isCloudWorkstation(this._settings.host) + 'Firestore', + (this._settings as PrivateSettings).emulator!! ); return this._settings; } diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index ba089bc14a3..896750f2133 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -152,47 +152,117 @@ function getOrCreate(id: string): { created: boolean; element: HTMLElement } { return { created, element: parentDiv }; } +interface EmulatorStatuses { + [name: string]: boolean; +} +const emulatorStatus: EmulatorStatuses = {}; + export interface EmulatorStatus { - name: string; isRunningEmulator: boolean; } -export function updateStatus( - emulatorStatus: EmulatorStatus, - isCloudWorkstation: boolean -) { + +function createPopover() { + const popover = document.createElement('div'); + popover.setAttribute('id', 'firebase__popover'); + popover.innerText = "I'm a popover!"; + popover.style.padding = '1em'; + popover.style.display = 'none'; + popover.style.position = 'absolute'; + popover.style.top = '50px'; + return popover; +} + +function createFirebaseEl() { + const firebaseIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + firebaseIcon.setAttribute('width', '25'); + firebaseIcon.setAttribute('height', '25'); + firebaseIcon.setAttribute('viewBox', '0 0 600 600'); + firebaseIcon.setAttribute('fill', 'none'); + + firebaseIcon.setAttribute('xlmns', 'http://www.w3.org/2000/svg'); + firebaseIcon.innerHTML = + ''; + return firebaseIcon; +} +export function updateStatus(name: string, isRunningEmulator: boolean) { + if (emulatorStatus[name] === isRunningEmulator) { + // No rerendering required + return; + } + emulatorStatus[name] = isRunningEmulator; + + function setDarkMode(el: HTMLElement) { + el.setAttribute( + 'style', + 'position: fixed; bottom: 0px; border: solid 1px; width: 100%; border-radius: 10px; padding: .5em; text-align: center; background: black; color: white;' + ); + } + function setLightMode(el: HTMLElement) { + el.setAttribute( + 'style', + 'position: fixed; bottom: 0px; border: solid 1px; width: 100%; border-radius: 10px; padding: .5em; text-align: center; background: #e9f1fe; color: black;' + ); + } function setupDom() { const parentDivId = `__firebase_status`; let { element: parentDiv, created } = getOrCreate(parentDivId); if (created) { - parentDiv.style.position = 'fixed'; - parentDiv.style.bottom = '0px'; - parentDiv.style.border = 'solid 1px'; - parentDiv.style.width = '100%'; - parentDiv.style.borderRadius = '10px'; - parentDiv.style.padding = '.5em'; - parentDiv.style.textAlign = 'center'; parentDiv.classList.add('firebase-emulator-warning'); document.body.appendChild(parentDiv); } + window + .matchMedia('(prefers-color-scheme: dark)') + .addEventListener('change', event => { + event.matches ? setDarkMode(parentDiv) : setLightMode(parentDiv); + }); - const { name, isRunningEmulator } = emulatorStatus; - const { element, created: productDivCreated } = getOrCreate( - `${parentDivId}_${name}` - ); - // If in prod, and not using a cloud workstation, we should remove the node, as the banner can be distracting. - if (!isRunningEmulator && !isCloudWorkstation) { - element.remove(); - return; + const paragraph = document.createElement('p'); + const anchor = document.createElement('a'); + if (isRunningEmulator) { + paragraph.innerHTML = 'Running in local emulator'; + const firstDashIdx = window.location.host.indexOf('-'); + const emulatorHostPort = '4000'; + anchor.href = `${emulatorHostPort}-${window.location.host.substring( + firstDashIdx + )}`; + } else { + paragraph.innerHTML = 'Emulator disconnected'; + anchor.innerHTML = 'Learn more'; } - if (productDivCreated) { - parentDiv.appendChild(element); + const banner = getOrCreate('firebase__banner'); + if (banner.created) { + // update styles + const bannerEl = banner.element; + bannerEl.style.display = 'flex'; + bannerEl.style.background = '#7faaf0'; + bannerEl.style.position = 'absolute'; + bannerEl.style.bottom = '0'; + const popOver = createPopover(); + // TODO(mtewani): Light vs dark mode + const firebaseIcon = createFirebaseEl(); + const firebaseText = document.createElement('span'); + firebaseText.setAttribute('style', 'align-content: center'); + firebaseText.innerText = 'Firebase: '; + const statusEl = document.createElement('span'); + updateStatusCount(statusEl); + bannerEl.appendChild(firebaseIcon); + bannerEl.appendChild(firebaseText); + bannerEl.appendChild(popOver); + bannerEl.appendChild(statusEl); + banner.element.onclick = () => { + const popover = document.getElementById('firebase__popover'); + if (popover) { + if (popover?.style.display === 'none') { + popover.style.display = 'flex'; + } else { + popover.style.display = 'none'; + } + } + }; + document.body.appendChild(banner.element); } - element.style.color = isRunningEmulator ? 'green' : 'red'; - element.innerHTML = `${name} is running in ${ - isRunningEmulator ? 'emulator' : 'prod' - } mode`; } if (typeof window !== 'undefined' && typeof document !== 'undefined') { if (document.readyState === 'loading') { @@ -202,3 +272,17 @@ export function updateStatus( } } } + +function updateStatusCount(element: HTMLElement) { + const products = Object.keys(emulatorStatus); + let prodCount = 0; + let localCount = 0; + for(let product in products) { + if(emulatorStatus[product]) { + localCount++; + } else { + prodCount++; + } + } + element.innerText = `Prod (${prodCount}) Local (${localCount})`; +} From 0aede90247c7e6b494b283afb3e313f3cfe98bbd Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 13:08:38 -0700 Subject: [PATCH 32/67] Implemented emulator overlay --- common/api-review/util.api.md | 6 +- packages/auth/src/api/index.ts | 7 +- packages/auth/src/core/auth/emulator.ts | 39 ++++- packages/firestore/src/lite-api/database.ts | 17 ++- packages/util/src/emulator.ts | 155 +++++++------------- 5 files changed, 97 insertions(+), 127 deletions(-) diff --git a/common/api-review/util.api.md b/common/api-review/util.api.md index 9fb61715a36..7c31eb0aa46 100644 --- a/common/api-review/util.api.md +++ b/common/api-review/util.api.md @@ -490,10 +490,8 @@ export interface Subscribe { // @public (undocumented) export type Unsubscribe = () => void; -// Warning: (ae-missing-release-tag) "updateStatus" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export function updateStatus(name: string, isRunningEmulator: boolean): void; +// @public +export function updateEmulatorBanner(name: string, isRunningEmulator: boolean): void; // Warning: (ae-missing-release-tag) "validateArgCount" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index 6d640c236b7..3b280e64245 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -20,7 +20,7 @@ import { isCloudflareWorker, isCloudWorkstation, querystring, - updateStatus + updateEmulatorBanner } from '@firebase/util'; import { AuthErrorCode, NamedErrorParams } from '../core/errors'; @@ -200,10 +200,7 @@ export async function _performFetchWithErrorHandling( fetchFn: () => Promise ): Promise { const authInternal = auth as AuthInternal; - updateStatus( - 'Auth', - authInternal.emulatorConfig !== null - ); + updateEmulatorBanner('Auth', authInternal.emulatorConfig !== null); authInternal._canInitEmulator = false; const errorMap = { ...SERVER_ERROR_MAP, ...customErrorMap }; try { diff --git a/packages/auth/src/core/auth/emulator.ts b/packages/auth/src/core/auth/emulator.ts index 1c4fb4b0fbd..62e512d0a07 100644 --- a/packages/auth/src/core/auth/emulator.ts +++ b/packages/auth/src/core/auth/emulator.ts @@ -22,7 +22,7 @@ import { deepEqual, isCloudWorkstation, pingServer, - updateStatus + updateEmulatorBanner } from '@firebase/util'; /** @@ -102,13 +102,14 @@ export function connectAuthEmulator( authInternal.emulatorConfig = emulatorConfig; authInternal.settings.appVerificationDisabledForTesting = true; - if (!disableWarnings) { - emitEmulatorWarning(isCloudWorkstation(emulatorConfig.host)); + if (!disableWarnings && !isCloudWorkstation(host)) { + emitEmulatorWarning(); } // Workaround to get cookies in Firebase Studio if (isCloudWorkstation(host)) { void pingServer(`${protocol}//${host}:${port}`); + updateEmulatorBanner('Auth', true); } } @@ -148,11 +149,26 @@ function parsePort(portStr: string): number | null { return port; } -function emitEmulatorWarning(isCloudWorkstation: boolean): void { - updateStatus( - 'Auth', - true - ); +function emitEmulatorWarning(): void { + function attachBanner(): void { + const el = document.createElement('p'); + const sty = el.style; + el.innerText = + 'Running in emulator mode. Do not use with production credentials.'; + sty.position = 'fixed'; + sty.width = '100%'; + sty.backgroundColor = '#ffffff'; + sty.border = '.1em solid #000000'; + sty.color = '#b50000'; + sty.bottom = '0px'; + sty.left = '0px'; + sty.margin = '0px'; + sty.zIndex = '10000'; + sty.textAlign = 'center'; + el.classList.add('firebase-emulator-warning'); + document.body.appendChild(el); + } + if (typeof console !== 'undefined' && typeof console.info === 'function') { console.info( 'WARNING: You are using the Auth Emulator,' + @@ -160,4 +176,11 @@ function emitEmulatorWarning(isCloudWorkstation: boolean): void { ' production credentials.' ); } + if (typeof window !== 'undefined' && typeof document !== 'undefined') { + if (document.readyState === 'loading') { + window.addEventListener('DOMContentLoaded', attachBanner); + } else { + attachBanner(); + } + } } diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index cde362df93b..87c12debf98 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -28,7 +28,7 @@ import { EmulatorMockTokenOptions, getDefaultEmulatorHostnameAndPort, isCloudWorkstation, - updateStatus, + updateEmulatorBanner, pingServer } from '@firebase/util'; @@ -143,9 +143,9 @@ export class Firestore implements FirestoreService { _freezeSettings(): FirestoreSettingsImpl { this._settingsFrozen = true; - updateStatus( - 'Firestore', - (this._settings as PrivateSettings).emulator!! + updateEmulatorBanner( + 'Firestore', + (this._settings as PrivateSettings).emulator!! ); return this._settings; } @@ -339,9 +339,7 @@ export function connectFirestoreEmulator( emulatorOptions: firestore._getEmulatorOptions() }; const newHostSetting = `${host}:${port}`; - if (useSsl) { - void pingServer(`https://${newHostSetting}`); - } + if (settings.host !== DEFAULT_HOST && settings.host !== newHostSetting) { logWarn( 'Host has been set in both settings() and connectFirestoreEmulator(), emulator host ' + @@ -362,6 +360,11 @@ export function connectFirestoreEmulator( firestore._setSettings(newConfig); + if (useSsl) { + void pingServer(`https://${newHostSetting}`); + updateEmulatorBanner('firestore', true); + } + if (options.mockUserToken) { let token: string; let user: User; diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 896750f2133..e8346752479 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -141,17 +141,6 @@ export function createMockUserToken( ].join('.'); } -function getOrCreate(id: string): { created: boolean; element: HTMLElement } { - let parentDiv = document.getElementById(id); - let created = false; - if (!parentDiv) { - parentDiv = document.createElement('div'); - parentDiv.setAttribute('id', id); - created = true; - } - return { created, element: parentDiv }; -} - interface EmulatorStatuses { [name: string]: boolean; } @@ -161,108 +150,82 @@ export interface EmulatorStatus { isRunningEmulator: boolean; } -function createPopover() { - const popover = document.createElement('div'); - popover.setAttribute('id', 'firebase__popover'); - popover.innerText = "I'm a popover!"; - popover.style.padding = '1em'; - popover.style.display = 'none'; - popover.style.position = 'absolute'; - popover.style.top = '50px'; - return popover; +// Checks whether any products are running on an emulator +function areRunningEmulator() { + let runningEmulator = false; + for (let key of Object.keys(emulatorStatus)) { + if (emulatorStatus[key]) { + runningEmulator = true; + } + } + return runningEmulator; } -function createFirebaseEl() { - const firebaseIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - firebaseIcon.setAttribute('width', '25'); - firebaseIcon.setAttribute('height', '25'); - firebaseIcon.setAttribute('viewBox', '0 0 600 600'); - firebaseIcon.setAttribute('fill', 'none'); - - firebaseIcon.setAttribute('xlmns', 'http://www.w3.org/2000/svg'); - firebaseIcon.innerHTML = - ''; - return firebaseIcon; +function getOrCreateEl(id: string): { created: boolean; element: HTMLElement } { + let parentDiv = document.getElementById(id); + let created = false; + if (!parentDiv) { + parentDiv = document.createElement('div'); + parentDiv.setAttribute('id', id); + created = true; + } + return { created, element: parentDiv }; } -export function updateStatus(name: string, isRunningEmulator: boolean) { + +/** + * Updates Emulator Banner. Primarily used for Firebase Studio + * @param name + * @param isRunningEmulator + * @public + */ +export function updateEmulatorBanner(name: string, isRunningEmulator: boolean) { if (emulatorStatus[name] === isRunningEmulator) { // No rerendering required return; } emulatorStatus[name] = isRunningEmulator; - - function setDarkMode(el: HTMLElement) { - el.setAttribute( - 'style', - 'position: fixed; bottom: 0px; border: solid 1px; width: 100%; border-radius: 10px; padding: .5em; text-align: center; background: black; color: white;' - ); - } - function setLightMode(el: HTMLElement) { - el.setAttribute( - 'style', - 'position: fixed; bottom: 0px; border: solid 1px; width: 100%; border-radius: 10px; padding: .5em; text-align: center; background: #e9f1fe; color: black;' - ); + if (!areRunningEmulator()) { + tearDown(); + return; } - function setupDom() { - const parentDivId = `__firebase_status`; - let { element: parentDiv, created } = getOrCreate(parentDivId); + function tearDown() { + const divId = `__firebase_status`; + if (typeof document !== 'undefined') { + const element = document.getElementById(divId); + if (element) { + element.remove(); + } + } + } + function setupDom() { + const parentDivId = `__firebase__status`; + let { element: parentDiv, created } = getOrCreateEl(parentDivId); if (created) { parentDiv.classList.add('firebase-emulator-warning'); document.body.appendChild(parentDiv); } - window - .matchMedia('(prefers-color-scheme: dark)') - .addEventListener('change', event => { - event.matches ? setDarkMode(parentDiv) : setLightMode(parentDiv); - }); - - const paragraph = document.createElement('p'); - const anchor = document.createElement('a'); - if (isRunningEmulator) { - paragraph.innerHTML = 'Running in local emulator'; - const firstDashIdx = window.location.host.indexOf('-'); - const emulatorHostPort = '4000'; - anchor.href = `${emulatorHostPort}-${window.location.host.substring( - firstDashIdx - )}`; - } else { - paragraph.innerHTML = 'Emulator disconnected'; - anchor.innerHTML = 'Learn more'; - } - const banner = getOrCreate('firebase__banner'); + const banner = getOrCreateEl('__firebase__banner'); + let firebaseText: HTMLSpanElement = + document.getElementById('__firebase__text') || + document.createElement('span'); if (banner.created) { // update styles const bannerEl = banner.element; bannerEl.style.display = 'flex'; bannerEl.style.background = '#7faaf0'; bannerEl.style.position = 'absolute'; - bannerEl.style.bottom = '0'; - const popOver = createPopover(); - // TODO(mtewani): Light vs dark mode - const firebaseIcon = createFirebaseEl(); - const firebaseText = document.createElement('span'); - firebaseText.setAttribute('style', 'align-content: center'); - firebaseText.innerText = 'Firebase: '; - const statusEl = document.createElement('span'); - updateStatusCount(statusEl); - bannerEl.appendChild(firebaseIcon); + bannerEl.style.bottom = '5px'; + bannerEl.style.left = '5px'; + bannerEl.style.padding = '.5em'; + bannerEl.style.borderRadius = '5px'; bannerEl.appendChild(firebaseText); - bannerEl.appendChild(popOver); - bannerEl.appendChild(statusEl); - banner.element.onclick = () => { - const popover = document.getElementById('firebase__popover'); - if (popover) { - if (popover?.style.display === 'none') { - popover.style.display = 'flex'; - } else { - popover.style.display = 'none'; - } - } - }; document.body.appendChild(banner.element); } + firebaseText.setAttribute('id', '__firebase__text'); + firebaseText.setAttribute('style', 'align-content: center'); + firebaseText.innerText = 'Running in this workspace'; } if (typeof window !== 'undefined' && typeof document !== 'undefined') { if (document.readyState === 'loading') { @@ -272,17 +235,3 @@ export function updateStatus(name: string, isRunningEmulator: boolean) { } } } - -function updateStatusCount(element: HTMLElement) { - const products = Object.keys(emulatorStatus); - let prodCount = 0; - let localCount = 0; - for(let product in products) { - if(emulatorStatus[product]) { - localCount++; - } else { - prodCount++; - } - } - element.innerText = `Prod (${prodCount}) Local (${localCount})`; -} From fa3a56fa98e0526510050adfa3c2cf76bbe9ff1f Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 13:10:56 -0700 Subject: [PATCH 33/67] Removed changeset --- .changeset/gentle-laws-kneel.md | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .changeset/gentle-laws-kneel.md diff --git a/.changeset/gentle-laws-kneel.md b/.changeset/gentle-laws-kneel.md deleted file mode 100644 index 46dc7d25ecf..00000000000 --- a/.changeset/gentle-laws-kneel.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@firebase/database-compat": patch -"@firebase/database": patch -"@firebase/firestore": patch ---- - -Add SSL checks to `connectDatabaseEmulator` and `connectFirestoreEmulator` From 6cff61f03c3b025ba87e472ca9c48b13e558ec26 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 13:11:15 -0700 Subject: [PATCH 34/67] Create three-singers-wonder.md --- .changeset/three-singers-wonder.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/three-singers-wonder.md diff --git a/.changeset/three-singers-wonder.md b/.changeset/three-singers-wonder.md new file mode 100644 index 00000000000..8f3efa16725 --- /dev/null +++ b/.changeset/three-singers-wonder.md @@ -0,0 +1,8 @@ +--- +"@firebase/auth": patch +"@firebase/firestore": patch +"@firebase/storage": patch +"@firebase/util": patch +--- + +Add Emulator Overlay From eeebee1898bd185d52a0b95cf928b8ad7ba0520c Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 13:12:30 -0700 Subject: [PATCH 35/67] Removed unused line --- packages/firestore/src/lite-api/components.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/firestore/src/lite-api/components.ts b/packages/firestore/src/lite-api/components.ts index 7ab8fc6aa40..6d4a161259f 100644 --- a/packages/firestore/src/lite-api/components.ts +++ b/packages/firestore/src/lite-api/components.ts @@ -110,7 +110,6 @@ export function makeDatabaseInfo( persistenceKey: string, settings: FirestoreSettingsImpl ): DatabaseInfo { - const privateSettings = settings as PrivateSettings; return new DatabaseInfo( databaseId, appId, From c439abea51778735901b846a3c7837441c598537 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 13:26:08 -0700 Subject: [PATCH 36/67] Removed unnecessary changes --- packages/firestore/src/lite-api/components.ts | 2 +- packages/firestore/src/lite-api/database.ts | 3 ++- packages/firestore/src/lite-api/settings.ts | 1 - .../firestore/src/platform/browser_lite/fetch_connection.ts | 2 -- packages/storage/src/implementation/connection.ts | 3 +-- packages/storage/src/platform/browser/connection.ts | 3 +-- 6 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/firestore/src/lite-api/components.ts b/packages/firestore/src/lite-api/components.ts index 6d4a161259f..52c3b3729ee 100644 --- a/packages/firestore/src/lite-api/components.ts +++ b/packages/firestore/src/lite-api/components.ts @@ -28,7 +28,7 @@ import { Datastore, newDatastore } from '../remote/datastore'; import { Code, FirestoreError } from '../util/error'; import { logDebug } from '../util/log'; -import { FirestoreSettingsImpl, PrivateSettings } from './settings'; +import { FirestoreSettingsImpl } from './settings'; export const LOG_TAG = 'ComponentProvider'; diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index 87c12debf98..5f35d3c9b6f 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -145,7 +145,8 @@ export class Firestore implements FirestoreService { this._settingsFrozen = true; updateEmulatorBanner( 'Firestore', - (this._settings as PrivateSettings).emulator!! + (this._settings as PrivateSettings).emulatorOptions !== null && + (this._settings as PrivateSettings).emulatorOptions !== undefined ); return this._settings; } diff --git a/packages/firestore/src/lite-api/settings.ts b/packages/firestore/src/lite-api/settings.ts index e6f4229e802..56c99e7ccea 100644 --- a/packages/firestore/src/lite-api/settings.ts +++ b/packages/firestore/src/lite-api/settings.ts @@ -83,7 +83,6 @@ export interface PrivateSettings extends FirestoreSettings { experimentalLongPollingOptions?: ExperimentalLongPollingOptions; useFetchStreams?: boolean; emulatorOptions?: { mockUserToken?: EmulatorMockTokenOptions | string }; - emulator?: boolean; localCache?: FirestoreLocalCache; } diff --git a/packages/firestore/src/platform/browser_lite/fetch_connection.ts b/packages/firestore/src/platform/browser_lite/fetch_connection.ts index 6d36490f926..227322153e9 100644 --- a/packages/firestore/src/platform/browser_lite/fetch_connection.ts +++ b/packages/firestore/src/platform/browser_lite/fetch_connection.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -import { isCloudWorkstation } from '@firebase/util'; - import { Token } from '../../api/credentials'; import { Stream } from '../../remote/connection'; import { RestConnection } from '../../remote/rest_connection'; diff --git a/packages/storage/src/implementation/connection.ts b/packages/storage/src/implementation/connection.ts index 0e9c8de3773..f7630e59708 100644 --- a/packages/storage/src/implementation/connection.ts +++ b/packages/storage/src/implementation/connection.ts @@ -44,8 +44,7 @@ export interface Connection { method: string, isUsingEmulator: boolean, body?: ArrayBufferView | Blob | string | null, - headers?: Headers, - isUsingEmulator?: boolean + headers?: Headers ): Promise; getErrorCode(): ErrorCode; diff --git a/packages/storage/src/platform/browser/connection.ts b/packages/storage/src/platform/browser/connection.ts index 254ba2289c4..77a2e42809b 100644 --- a/packages/storage/src/platform/browser/connection.ts +++ b/packages/storage/src/platform/browser/connection.ts @@ -65,8 +65,7 @@ abstract class XhrConnection method: string, isUsingEmulator: boolean, body?: ArrayBufferView | Blob | string, - headers?: Headers, - isUsingEmulator?: boolean + headers?: Headers ): Promise { if (this.sent_) { throw internalError('cannot .send() more than once'); From adb9c763661d91fa376f0b19d5c2776ca3b6fdbb Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 13:27:11 -0700 Subject: [PATCH 37/67] Updated storage changeset --- .changeset/three-singers-wonder.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/three-singers-wonder.md b/.changeset/three-singers-wonder.md index 8f3efa16725..c663605e970 100644 --- a/.changeset/three-singers-wonder.md +++ b/.changeset/three-singers-wonder.md @@ -1,7 +1,6 @@ --- "@firebase/auth": patch "@firebase/firestore": patch -"@firebase/storage": patch "@firebase/util": patch --- From 32433f3ea363b4181ae7e890b8b7dd9517312273 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 13:59:55 -0700 Subject: [PATCH 38/67] Fixed button click --- packages/util/src/emulator.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index e8346752479..c7d911756b7 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -184,15 +184,15 @@ export function updateEmulatorBanner(name: string, isRunningEmulator: boolean) { return; } emulatorStatus[name] = isRunningEmulator; + const bannerId = '__firebase__banner'; if (!areRunningEmulator()) { tearDown(); return; } function tearDown() { - const divId = `__firebase_status`; if (typeof document !== 'undefined') { - const element = document.getElementById(divId); + const element = document.getElementById(bannerId); if (element) { element.remove(); } @@ -200,13 +200,7 @@ export function updateEmulatorBanner(name: string, isRunningEmulator: boolean) { } function setupDom() { - const parentDivId = `__firebase__status`; - let { element: parentDiv, created } = getOrCreateEl(parentDivId); - if (created) { - parentDiv.classList.add('firebase-emulator-warning'); - document.body.appendChild(parentDiv); - } - const banner = getOrCreateEl('__firebase__banner'); + const banner = getOrCreateEl(bannerId); let firebaseText: HTMLSpanElement = document.getElementById('__firebase__text') || document.createElement('span'); @@ -220,11 +214,19 @@ export function updateEmulatorBanner(name: string, isRunningEmulator: boolean) { bannerEl.style.left = '5px'; bannerEl.style.padding = '.5em'; bannerEl.style.borderRadius = '5px'; + bannerEl.style.alignContent = 'center'; + const closeBtn = document.createElement('span'); + closeBtn.style.cursor = 'pointer'; + closeBtn.style.paddingLeft = '5px'; + closeBtn.innerHTML = ' ×'; + closeBtn.onclick = () => { + tearDown(); + }; bannerEl.appendChild(firebaseText); + bannerEl.appendChild(closeBtn); document.body.appendChild(banner.element); } firebaseText.setAttribute('id', '__firebase__text'); - firebaseText.setAttribute('style', 'align-content: center'); firebaseText.innerText = 'Running in this workspace'; } if (typeof window !== 'undefined' && typeof document !== 'undefined') { From 1db0a4061946166c18996079810271ad3df6de11 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 14:02:05 -0700 Subject: [PATCH 39/67] Fixed linting errors --- packages/util/src/emulator.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index c7d911756b7..a29fcd6cea0 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -151,9 +151,9 @@ export interface EmulatorStatus { } // Checks whether any products are running on an emulator -function areRunningEmulator() { +function areRunningEmulator(): boolean { let runningEmulator = false; - for (let key of Object.keys(emulatorStatus)) { + for (const key of Object.keys(emulatorStatus)) { if (emulatorStatus[key]) { runningEmulator = true; } @@ -178,7 +178,7 @@ function getOrCreateEl(id: string): { created: boolean; element: HTMLElement } { * @param isRunningEmulator * @public */ -export function updateEmulatorBanner(name: string, isRunningEmulator: boolean) { +export function updateEmulatorBanner(name: string, isRunningEmulator: boolean): void { if (emulatorStatus[name] === isRunningEmulator) { // No rerendering required return; @@ -190,7 +190,7 @@ export function updateEmulatorBanner(name: string, isRunningEmulator: boolean) { return; } - function tearDown() { + function tearDown(): void { if (typeof document !== 'undefined') { const element = document.getElementById(bannerId); if (element) { @@ -199,9 +199,9 @@ export function updateEmulatorBanner(name: string, isRunningEmulator: boolean) { } } - function setupDom() { + function setupDom(): void { const banner = getOrCreateEl(bannerId); - let firebaseText: HTMLSpanElement = + const firebaseText: HTMLSpanElement = document.getElementById('__firebase__text') || document.createElement('span'); if (banner.created) { From 25f3a210f2068092bd9a5b7d3b2c00476d7b12eb Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 14:03:57 -0700 Subject: [PATCH 40/67] fixed formatting --- packages/util/src/emulator.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index a29fcd6cea0..2ab0eb143a4 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -178,7 +178,10 @@ function getOrCreateEl(id: string): { created: boolean; element: HTMLElement } { * @param isRunningEmulator * @public */ -export function updateEmulatorBanner(name: string, isRunningEmulator: boolean): void { +export function updateEmulatorBanner( + name: string, + isRunningEmulator: boolean +): void { if (emulatorStatus[name] === isRunningEmulator) { // No rerendering required return; From b0e7566d6fbccccdcf44927ece5f7884f4f24587 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 14:13:54 -0700 Subject: [PATCH 41/67] Addressed comments --- packages/util/src/emulator.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 2ab0eb143a4..30210f8503a 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -146,10 +146,6 @@ interface EmulatorStatuses { } const emulatorStatus: EmulatorStatuses = {}; -export interface EmulatorStatus { - isRunningEmulator: boolean; -} - // Checks whether any products are running on an emulator function areRunningEmulator(): boolean { let runningEmulator = false; @@ -182,10 +178,14 @@ export function updateEmulatorBanner( name: string, isRunningEmulator: boolean ): void { - if (emulatorStatus[name] === isRunningEmulator) { - // No rerendering required + if ( + typeof window === 'undefined' || + typeof document === 'undefined' || + emulatorStatus[name] === isRunningEmulator + ) { return; } + emulatorStatus[name] = isRunningEmulator; const bannerId = '__firebase__banner'; if (!areRunningEmulator()) { @@ -232,11 +232,9 @@ export function updateEmulatorBanner( firebaseText.setAttribute('id', '__firebase__text'); firebaseText.innerText = 'Running in this workspace'; } - if (typeof window !== 'undefined' && typeof document !== 'undefined') { - if (document.readyState === 'loading') { - window.addEventListener('DOMContentLoaded', setupDom); - } else { - setupDom(); - } + if (document.readyState === 'loading') { + window.addEventListener('DOMContentLoaded', setupDom); + } else { + setupDom(); } } From 8d70b121a8fdc4582f9975b96adea34817b5a2df Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 14:14:37 -0700 Subject: [PATCH 42/67] Removed extra document check --- packages/util/src/emulator.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 30210f8503a..6cbd5446a79 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -194,11 +194,9 @@ export function updateEmulatorBanner( } function tearDown(): void { - if (typeof document !== 'undefined') { - const element = document.getElementById(bannerId); - if (element) { - element.remove(); - } + const element = document.getElementById(bannerId); + if (element) { + element.remove(); } } From bffdabd700d789a6ebab56c149c31332ecc3f3ff Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 14:17:00 -0700 Subject: [PATCH 43/67] Removed extra export --- common/api-review/util.api.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/common/api-review/util.api.md b/common/api-review/util.api.md index 7c31eb0aa46..98f8657fd5d 100644 --- a/common/api-review/util.api.md +++ b/common/api-review/util.api.md @@ -140,14 +140,6 @@ export type EmulatorMockTokenOptions = ({ sub: string; }) & Partial; -// Warning: (ae-missing-release-tag) "EmulatorStatus" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface EmulatorStatus { - // (undocumented) - isRunningEmulator: boolean; -} - // Warning: (ae-missing-release-tag) "ErrorData" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) From cdbf66329db30e14b9e614a47bec4cdf6f7ac328 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 16:13:19 -0700 Subject: [PATCH 44/67] Trigger Build From 927daddb8b4460bef3a2d026074c53ed3b0032bd Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 5 May 2025 16:52:13 -0700 Subject: [PATCH 45/67] Fixed formatting --- packages/firestore/src/lite-api/database.ts | 5 ++- packages/util/src/emulator.ts | 35 +++++++++++++++------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index 5f35d3c9b6f..aae875d2955 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -145,8 +145,7 @@ export class Firestore implements FirestoreService { this._settingsFrozen = true; updateEmulatorBanner( 'Firestore', - (this._settings as PrivateSettings).emulatorOptions !== null && - (this._settings as PrivateSettings).emulatorOptions !== undefined + this._settings.isUsingEmulator || isCloudWorkstation(this._settings.host) ); return this._settings; } @@ -363,7 +362,7 @@ export function connectFirestoreEmulator( if (useSsl) { void pingServer(`https://${newHostSetting}`); - updateEmulatorBanner('firestore', true); + updateEmulatorBanner('Firestore', true); } if (options.mockUserToken) { diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 6cbd5446a79..eb4465c05b5 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -146,15 +146,25 @@ interface EmulatorStatuses { } const emulatorStatus: EmulatorStatuses = {}; +interface EmulatorSummary { + prod: string[]; + emulator: string[]; +} + // Checks whether any products are running on an emulator -function areRunningEmulator(): boolean { - let runningEmulator = false; +function getEmulatorSummary(): EmulatorSummary { + const summary: EmulatorSummary = { + prod: [], + emulator: [] + }; for (const key of Object.keys(emulatorStatus)) { if (emulatorStatus[key]) { - runningEmulator = true; + summary.emulator.push(key); + } else { + summary.prod.push(key); } } - return runningEmulator; + return summary; } function getOrCreateEl(id: string): { created: boolean; element: HTMLElement } { @@ -188,10 +198,8 @@ export function updateEmulatorBanner( emulatorStatus[name] = isRunningEmulator; const bannerId = '__firebase__banner'; - if (!areRunningEmulator()) { - tearDown(); - return; - } + const summary = getEmulatorSummary(); + const showError = summary.prod.length > 0; function tearDown(): void { const element = document.getElementById(bannerId); @@ -225,10 +233,17 @@ export function updateEmulatorBanner( }; bannerEl.appendChild(firebaseText); bannerEl.appendChild(closeBtn); - document.body.appendChild(banner.element); + document.body.appendChild(bannerEl); + } + if (showError) { + banner.element.style.background = '#cd5c5c'; + firebaseText.innerText = `Product${ + summary.prod.length > 0 ? 's' : '' + } Running in Production: ${summary.prod.join(', ')}`; + } else { + firebaseText.innerText = 'Running in this workspace'; } firebaseText.setAttribute('id', '__firebase__text'); - firebaseText.innerText = 'Running in this workspace'; } if (document.readyState === 'loading') { window.addEventListener('DOMContentLoaded', setupDom); From 83b84f0d27a9df51b23b224263ab2e94474bb49b Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 13:31:44 -0700 Subject: [PATCH 46/67] Addressed comments --- packages/database/src/api/Database.ts | 5 ++- packages/database/src/core/Repo.ts | 7 +++- packages/functions/src/service.ts | 9 ++++- packages/storage/src/service.ts | 6 ++- packages/util/src/emulator.ts | 58 ++++++++++++++++++++++----- 5 files changed, 71 insertions(+), 14 deletions(-) diff --git a/packages/database/src/api/Database.ts b/packages/database/src/api/Database.ts index 515e278b5c5..405f70fd867 100644 --- a/packages/database/src/api/Database.ts +++ b/packages/database/src/api/Database.ts @@ -31,7 +31,8 @@ import { EmulatorMockTokenOptions, getDefaultEmulatorHostnameAndPort, isCloudWorkstation, - pingServer + pingServer, + updateEmulatorBanner } from '@firebase/util'; import { AppCheckTokenProvider } from '../core/AppCheckTokenProvider'; @@ -56,6 +57,7 @@ import { TransportManager } from '../realtime/TransportManager'; import { WebSocketConnection } from '../realtime/WebSocketConnection'; import { ReferenceImpl } from './Reference_impl'; +import { updateStrings } from 'yargs'; export { EmulatorMockTokenOptions } from '@firebase/util'; /** @@ -393,6 +395,7 @@ export function connectDatabaseEmulator( // Workaround to get cookies in Firebase Studio if (isCloudWorkstation(host)) { void pingServer(host); + updateEmulatorBanner('Database', true); } // Modify the repo to apply emulator settings diff --git a/packages/database/src/core/Repo.ts b/packages/database/src/core/Repo.ts index 2d76af39a08..1256dc40b30 100644 --- a/packages/database/src/core/Repo.ts +++ b/packages/database/src/core/Repo.ts @@ -18,10 +18,12 @@ import { assert, contains, + isCloudWorkstation, isEmpty, map, safeGet, - stringify + stringify, + updateEmulatorBanner } from '@firebase/util'; import { ValueEventRegistration } from '../api/Reference_impl'; @@ -328,6 +330,9 @@ export function repoStart( repo.server_.unlisten(query, tag); } }); + if (isCloudWorkstation(repo.repoInfo_.host)) { + updateEmulatorBanner('Database', repo.repoInfo_.isUsingEmulator); + } } /** diff --git a/packages/functions/src/service.ts b/packages/functions/src/service.ts index af9d8898d2e..000420e381c 100644 --- a/packages/functions/src/service.ts +++ b/packages/functions/src/service.ts @@ -30,7 +30,11 @@ import { Provider } from '@firebase/component'; import { FirebaseAuthInternalName } from '@firebase/auth-interop-types'; import { MessagingInternalComponentName } from '@firebase/messaging-interop-types'; import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types'; -import { isCloudWorkstation, pingServer } from '@firebase/util'; +import { + isCloudWorkstation, + pingServer, + updateEmulatorBanner +} from '@firebase/util'; export const DEFAULT_REGION = 'us-central1'; @@ -182,6 +186,7 @@ export function connectFunctionsEmulator( // Workaround to get cookies in Firebase Studio if (useSsl) { void pingServer(functionsInstance.emulatorOrigin); + updateEmulatorBanner('Functions', true); } } @@ -195,6 +200,7 @@ export function httpsCallable( name: string, options?: HttpsCallableOptions ): HttpsCallable { + updateEmulatorBanner('Functions', functionsInstance.emulatorOrigin !== null); const callable = ( data?: RequestData | null ): Promise => { @@ -225,6 +231,7 @@ export function httpsCallableFromURL< url: string, options?: HttpsCallableOptions ): HttpsCallable { + updateEmulatorBanner('Functions', functionsInstance.emulatorOrigin !== null); const callable = ( data?: RequestData | null ): Promise => { diff --git a/packages/storage/src/service.ts b/packages/storage/src/service.ts index 741dd6eaa1a..0e1da121d62 100644 --- a/packages/storage/src/service.ts +++ b/packages/storage/src/service.ts @@ -46,9 +46,11 @@ import { createMockUserToken, EmulatorMockTokenOptions, isCloudWorkstation, - pingServer + pingServer, + updateEmulatorBanner } from '@firebase/util'; import { Connection, ConnectionType } from './implementation/connection'; +import { updateEmail } from '@firebase/auth'; export function isUrl(path?: string): boolean { return /^[A-Za-z]+:\/\//.test(path as string); @@ -150,6 +152,7 @@ export function connectStorageEmulator( // Workaround to get cookies in Firebase Studio if (useSsl) { void pingServer(`https://${storage.host}`); + updateEmulatorBanner('Storage', true); } storage._isUsingEmulator = true; storage._protocol = useSsl ? 'https' : 'http'; @@ -324,6 +327,7 @@ export class FirebaseStorageImpl implements FirebaseStorage { appCheckToken: string | null, retry = true ): Request { + updateEmulatorBanner('Service', this._isUsingEmulator); if (!this._deleted) { const request = makeRequest( requestInfo, diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index eb4465c05b5..72cd7c3c6b2 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -141,10 +141,10 @@ export function createMockUserToken( ].join('.'); } -interface EmulatorStatuses { +interface EmulatorStatusMap { [name: string]: boolean; } -const emulatorStatus: EmulatorStatuses = {}; +const emulatorStatus: EmulatorStatusMap = {}; interface EmulatorSummary { prod: string[]; @@ -197,6 +197,10 @@ export function updateEmulatorBanner( } emulatorStatus[name] = isRunningEmulator; + + function prefixedId(id: string) { + return `__firebase__banner__${id}`; + } const bannerId = '__firebase__banner'; const summary = getEmulatorSummary(); const showError = summary.prod.length > 0; @@ -210,9 +214,17 @@ export function updateEmulatorBanner( function setupDom(): void { const banner = getOrCreateEl(bannerId); + const firebaseTextId = prefixedId('text'); const firebaseText: HTMLSpanElement = - document.getElementById('__firebase__text') || - document.createElement('span'); + document.getElementById(firebaseTextId) || document.createElement('span'); + const learnMoreId = prefixedId('learnmore'); + const learnMoreLink: HTMLAnchorElement = + (document.getElementById(learnMoreId) as HTMLAnchorElement) || + document.createElement('a'); + const prependIconId = prefixedId('preprendIcon'); + const prependIcon = + document.getElementById(prependIconId) || + document.createElementNS('http://www.w3.org/2000/svg', 'svg'); if (banner.created) { // update styles const bannerEl = banner.element; @@ -231,19 +243,45 @@ export function updateEmulatorBanner( closeBtn.onclick = () => { tearDown(); }; + learnMoreLink.setAttribute('id', learnMoreId); + learnMoreLink.href = + 'http://firebase.google.com/docs/studio/deploy-app#emulator '; + bannerEl.appendChild(prependIcon); bannerEl.appendChild(firebaseText); + bannerEl.appendChild(learnMoreLink); bannerEl.appendChild(closeBtn); + prependIcon.setAttribute('width', '24'); + prependIcon.setAttribute('id', prependIconId); + prependIcon.setAttribute('height', '24'); + prependIcon.setAttribute('viewBox', '0 0 24 24'); + prependIcon.setAttribute('fill', 'none'); document.body.appendChild(bannerEl); } + if (showError) { - banner.element.style.background = '#cd5c5c'; - firebaseText.innerText = `Product${ - summary.prod.length > 0 ? 's' : '' - } Running in Production: ${summary.prod.join(', ')}`; + firebaseText.innerText = `Running in Production`; + prependIcon.innerHTML = ` + + + + + + +`; } else { - firebaseText.innerText = 'Running in this workspace'; + prependIcon.innerHTML = ` + + + + + + +`; + firebaseText.innerText = 'Using emulated backend'; + learnMoreLink.href = + 'https://firebase.google.com/docs/studio/solution-build-with-ai'; } - firebaseText.setAttribute('id', '__firebase__text'); + firebaseText.setAttribute('id', firebaseTextId); } if (document.readyState === 'loading') { window.addEventListener('DOMContentLoaded', setupDom); From c824b35e5ffa830a6069cc0d2456b607a44dff11 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 13:36:20 -0700 Subject: [PATCH 47/67] Fixed linting --- .changeset/three-singers-wonder.md | 3 +++ packages/util/src/emulator.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.changeset/three-singers-wonder.md b/.changeset/three-singers-wonder.md index c663605e970..72dea9d7aa5 100644 --- a/.changeset/three-singers-wonder.md +++ b/.changeset/three-singers-wonder.md @@ -2,6 +2,9 @@ "@firebase/auth": patch "@firebase/firestore": patch "@firebase/util": patch +"@firebase/database": patch +"@firebase/storage": patch +"@firebase/functions": patch --- Add Emulator Overlay diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 72cd7c3c6b2..53a931d53b1 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -198,7 +198,7 @@ export function updateEmulatorBanner( emulatorStatus[name] = isRunningEmulator; - function prefixedId(id: string) { + function prefixedId(id: string): string { return `__firebase__banner__${id}`; } const bannerId = '__firebase__banner'; From 9ee4aa02eb6c729661499e824d2fd10430aefe46 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 13:39:16 -0700 Subject: [PATCH 48/67] Fixed linting --- packages/database/src/api/Database.ts | 1 - packages/storage/src/service.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/database/src/api/Database.ts b/packages/database/src/api/Database.ts index 405f70fd867..338255be46f 100644 --- a/packages/database/src/api/Database.ts +++ b/packages/database/src/api/Database.ts @@ -57,7 +57,6 @@ import { TransportManager } from '../realtime/TransportManager'; import { WebSocketConnection } from '../realtime/WebSocketConnection'; import { ReferenceImpl } from './Reference_impl'; -import { updateStrings } from 'yargs'; export { EmulatorMockTokenOptions } from '@firebase/util'; /** diff --git a/packages/storage/src/service.ts b/packages/storage/src/service.ts index 0e1da121d62..60369279ff2 100644 --- a/packages/storage/src/service.ts +++ b/packages/storage/src/service.ts @@ -50,7 +50,6 @@ import { updateEmulatorBanner } from '@firebase/util'; import { Connection, ConnectionType } from './implementation/connection'; -import { updateEmail } from '@firebase/auth'; export function isUrl(path?: string): boolean { return /^[A-Za-z]+:\/\//.test(path as string); From 1e7039ae821c84fa3658f22641660de97d6fedd9 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 13:54:45 -0700 Subject: [PATCH 49/67] Updated to only trigger on Studio --- packages/database/src/core/Repo.ts | 4 +--- packages/firestore/src/lite-api/database.ts | 7 +++---- packages/util/src/emulator.ts | 2 ++ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/database/src/core/Repo.ts b/packages/database/src/core/Repo.ts index 1256dc40b30..f642a37ae55 100644 --- a/packages/database/src/core/Repo.ts +++ b/packages/database/src/core/Repo.ts @@ -330,9 +330,7 @@ export function repoStart( repo.server_.unlisten(query, tag); } }); - if (isCloudWorkstation(repo.repoInfo_.host)) { - updateEmulatorBanner('Database', repo.repoInfo_.isUsingEmulator); - } + updateEmulatorBanner('Database', repo.repoInfo_.isUsingEmulator); } /** diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index aae875d2955..5530fc8d8e1 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -143,10 +143,9 @@ export class Firestore implements FirestoreService { _freezeSettings(): FirestoreSettingsImpl { this._settingsFrozen = true; - updateEmulatorBanner( - 'Firestore', - this._settings.isUsingEmulator || isCloudWorkstation(this._settings.host) - ); + if (isCloudWorkstation(this._settings.host)) { + updateEmulatorBanner('Firestore', this._settings.isUsingEmulator); + } return this._settings; } diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 53a931d53b1..56c7c5c0a52 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -16,6 +16,7 @@ */ import { base64urlEncodeWithoutPadding } from './crypt'; +import { isCloudWorkstation } from './url'; // Firebase Auth tokens contain snake_case claims following the JWT standard / convention. /* eslint-disable camelcase */ @@ -191,6 +192,7 @@ export function updateEmulatorBanner( if ( typeof window === 'undefined' || typeof document === 'undefined' || + !isCloudWorkstation(window.location.host) || emulatorStatus[name] === isRunningEmulator ) { return; From 2e57ab70a14f0d192923996d2ebe388424d4a246 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 13:59:03 -0700 Subject: [PATCH 50/67] Fixed linting --- packages/database/src/core/Repo.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/database/src/core/Repo.ts b/packages/database/src/core/Repo.ts index f642a37ae55..79d1d2437d0 100644 --- a/packages/database/src/core/Repo.ts +++ b/packages/database/src/core/Repo.ts @@ -18,7 +18,6 @@ import { assert, contains, - isCloudWorkstation, isEmpty, map, safeGet, From c2246ca0b9755b5b0e8043e18fef3775b256831b Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 14:42:58 -0700 Subject: [PATCH 51/67] Trigger Build From fe1264c00e0985baa624c1eba2d18088ac089005 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 14:53:21 -0700 Subject: [PATCH 52/67] Persisted dismiss --- packages/util/src/emulator.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 56c7c5c0a52..02b3f9a21c1 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -179,6 +179,7 @@ function getOrCreateEl(id: string): { created: boolean; element: HTMLElement } { return { created, element: parentDiv }; } +let previouslyDismissed = false; /** * Updates Emulator Banner. Primarily used for Firebase Studio * @param name @@ -193,7 +194,8 @@ export function updateEmulatorBanner( typeof window === 'undefined' || typeof document === 'undefined' || !isCloudWorkstation(window.location.host) || - emulatorStatus[name] === isRunningEmulator + emulatorStatus[name] === isRunningEmulator || + previouslyDismissed ) { return; } @@ -243,6 +245,7 @@ export function updateEmulatorBanner( closeBtn.style.paddingLeft = '5px'; closeBtn.innerHTML = ' ×'; closeBtn.onclick = () => { + previouslyDismissed = true; tearDown(); }; learnMoreLink.setAttribute('id', learnMoreId); From a3edf835eb9791c393aa929f6a889848541e5b5e Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 17:22:37 -0700 Subject: [PATCH 53/67] Removed change to check every request --- packages/auth/src/api/index.ts | 1 - packages/auth/src/platform_browser/index.ts | 8 ++- packages/database/src/api/Database.ts | 5 ++ packages/database/src/core/Repo.ts | 1 - packages/firestore/src/lite-api/database.ts | 4 +- packages/functions/src/api.ts | 4 +- packages/storage/src/api.ts | 4 +- packages/util/src/emulator.ts | 72 ++++++++++++--------- 8 files changed, 61 insertions(+), 38 deletions(-) diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index 3b280e64245..9e25d241345 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -200,7 +200,6 @@ export async function _performFetchWithErrorHandling( fetchFn: () => Promise ): Promise { const authInternal = auth as AuthInternal; - updateEmulatorBanner('Auth', authInternal.emulatorConfig !== null); authInternal._canInitEmulator = false; const errorMap = { ...SERVER_ERROR_MAP, ...customErrorMap }; try { diff --git a/packages/auth/src/platform_browser/index.ts b/packages/auth/src/platform_browser/index.ts index f94525bfeb7..025bd50869f 100644 --- a/packages/auth/src/platform_browser/index.ts +++ b/packages/auth/src/platform_browser/index.ts @@ -30,7 +30,11 @@ import { browserSessionPersistence } from './persistence/session_storage'; import { indexedDBLocalPersistence } from './persistence/indexed_db'; import { browserPopupRedirectResolver } from './popup_redirect'; import { Auth, User } from '../model/public_types'; -import { getDefaultEmulatorHost, getExperimentalSetting } from '@firebase/util'; +import { + getDefaultEmulatorHost, + getExperimentalSetting, + updateEmulatorBanner +} from '@firebase/util'; import { _setExternalJSProvider } from './load_js'; import { _createError } from '../core/util/assert'; import { AuthErrorCode } from '../core/errors'; @@ -107,6 +111,8 @@ export function getAuth(app: FirebaseApp = getApp()): Auth { } } + updateEmulatorBanner('Auth', false); + const authEmulatorHost = getDefaultEmulatorHost('auth'); if (authEmulatorHost) { connectAuthEmulator(auth, `http://${authEmulatorHost}`); diff --git a/packages/database/src/api/Database.ts b/packages/database/src/api/Database.ts index 338255be46f..e1652467a60 100644 --- a/packages/database/src/api/Database.ts +++ b/packages/database/src/api/Database.ts @@ -258,6 +258,10 @@ export class Database implements _FirebaseService { this.app.options['databaseAuthVariableOverride'] ); this._instanceStarted = true; + updateEmulatorBanner( + 'Database', + this._repo.repoInfo_.emulatorOptions !== null + ); } return this._repoInternal; } @@ -329,6 +333,7 @@ export function getDatabase( identifier: url }) as Database; if (!db._instanceStarted) { + updateEmulatorBanner('Database', false); const emulator = getDefaultEmulatorHostnameAndPort('database'); if (emulator) { connectDatabaseEmulator(db, ...emulator); diff --git a/packages/database/src/core/Repo.ts b/packages/database/src/core/Repo.ts index 79d1d2437d0..7fb62a6955e 100644 --- a/packages/database/src/core/Repo.ts +++ b/packages/database/src/core/Repo.ts @@ -329,7 +329,6 @@ export function repoStart( repo.server_.unlisten(query, tag); } }); - updateEmulatorBanner('Database', repo.repoInfo_.isUsingEmulator); } /** diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index 5530fc8d8e1..fce6d5843b7 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -143,9 +143,7 @@ export class Firestore implements FirestoreService { _freezeSettings(): FirestoreSettingsImpl { this._settingsFrozen = true; - if (isCloudWorkstation(this._settings.host)) { - updateEmulatorBanner('Firestore', this._settings.isUsingEmulator); - } + updateEmulatorBanner('Firestore', this._settings.isUsingEmulator); return this._settings; } diff --git a/packages/functions/src/api.ts b/packages/functions/src/api.ts index 7f92cba8343..cb987035145 100644 --- a/packages/functions/src/api.ts +++ b/packages/functions/src/api.ts @@ -29,7 +29,8 @@ import { } from './service'; import { getModularInstance, - getDefaultEmulatorHostnameAndPort + getDefaultEmulatorHostnameAndPort, + updateEmulatorBanner } from '@firebase/util'; export { FunctionsError } from './error'; @@ -47,6 +48,7 @@ export function getFunctions( app: FirebaseApp = getApp(), regionOrCustomDomain: string = DEFAULT_REGION ): Functions { + updateEmulatorBanner('Functions', false); // Dependencies const functionsProvider: Provider<'functions'> = _getProvider( getModularInstance(app), diff --git a/packages/storage/src/api.ts b/packages/storage/src/api.ts index 84c77ea0c8c..b164a1324c3 100644 --- a/packages/storage/src/api.ts +++ b/packages/storage/src/api.ts @@ -53,7 +53,8 @@ import { STORAGE_TYPE } from './constants'; import { EmulatorMockTokenOptions, getModularInstance, - getDefaultEmulatorHostnameAndPort + getDefaultEmulatorHostnameAndPort, + updateEmulatorBanner } from '@firebase/util'; import { StringFormat } from './implementation/string'; @@ -332,6 +333,7 @@ export function getStorage( bucketUrl?: string ): FirebaseStorage { app = getModularInstance(app); + updateEmulatorBanner('Storage', false); const storageProvider: Provider<'storage'> = _getProvider(app, STORAGE_TYPE); const storageInstance = storageProvider.getImmediate({ identifier: bucketUrl diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 02b3f9a21c1..a8f3181f62e 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -193,8 +193,9 @@ export function updateEmulatorBanner( if ( typeof window === 'undefined' || typeof document === 'undefined' || - !isCloudWorkstation(window.location.host) || + // !isCloudWorkstation(window.location.host) || emulatorStatus[name] === isRunningEmulator || + emulatorStatus[name] || // If already set to use emulator, can't go back to prod. previouslyDismissed ) { return; @@ -216,6 +217,38 @@ export function updateEmulatorBanner( } } + function setupBannerStyles(bannerEl: HTMLElement) { + bannerEl.style.display = 'flex'; + bannerEl.style.background = '#7faaf0'; + bannerEl.style.position = 'absolute'; + bannerEl.style.bottom = '5px'; + bannerEl.style.left = '5px'; + bannerEl.style.padding = '.5em'; + bannerEl.style.borderRadius = '5px'; + bannerEl.style.alignContent = 'center'; + } + + function setupIconStyles(prependIcon: SVGElement, iconId: string) { + prependIcon.setAttribute('width', '24'); + prependIcon.setAttribute('id', iconId); + prependIcon.setAttribute('height', '24'); + prependIcon.setAttribute('viewBox', '0 0 24 24'); + prependIcon.setAttribute('fill', 'none'); + prependIcon.style.marginLeft = '-6px'; + } + + function setupCloseBtn() { + const closeBtn = document.createElement('span'); + closeBtn.style.cursor = 'pointer'; + closeBtn.style.paddingLeft = '5px'; + closeBtn.innerHTML = ' ×'; + closeBtn.onclick = () => { + previouslyDismissed = true; + tearDown(); + }; + return closeBtn; + } + function setupDom(): void { const banner = getOrCreateEl(bannerId); const firebaseTextId = prefixedId('text'); @@ -226,40 +259,21 @@ export function updateEmulatorBanner( (document.getElementById(learnMoreId) as HTMLAnchorElement) || document.createElement('a'); const prependIconId = prefixedId('preprendIcon'); - const prependIcon = - document.getElementById(prependIconId) || + const prependIcon: SVGElement = + (document.getElementById( + prependIconId + ) as HTMLOrSVGElement as SVGElement) || document.createElementNS('http://www.w3.org/2000/svg', 'svg'); if (banner.created) { // update styles const bannerEl = banner.element; - bannerEl.style.display = 'flex'; - bannerEl.style.background = '#7faaf0'; - bannerEl.style.position = 'absolute'; - bannerEl.style.bottom = '5px'; - bannerEl.style.left = '5px'; - bannerEl.style.padding = '.5em'; - bannerEl.style.borderRadius = '5px'; - bannerEl.style.alignContent = 'center'; - const closeBtn = document.createElement('span'); - closeBtn.style.cursor = 'pointer'; - closeBtn.style.paddingLeft = '5px'; - closeBtn.innerHTML = ' ×'; - closeBtn.onclick = () => { - previouslyDismissed = true; - tearDown(); - }; + setupBannerStyles(bannerEl); + const closeBtn = setupCloseBtn(); learnMoreLink.setAttribute('id', learnMoreId); learnMoreLink.href = 'http://firebase.google.com/docs/studio/deploy-app#emulator '; - bannerEl.appendChild(prependIcon); - bannerEl.appendChild(firebaseText); - bannerEl.appendChild(learnMoreLink); - bannerEl.appendChild(closeBtn); - prependIcon.setAttribute('width', '24'); - prependIcon.setAttribute('id', prependIconId); - prependIcon.setAttribute('height', '24'); - prependIcon.setAttribute('viewBox', '0 0 24 24'); - prependIcon.setAttribute('fill', 'none'); + setupIconStyles(prependIcon, prependIconId); + bannerEl.append(prependIcon, firebaseText, learnMoreLink, closeBtn); document.body.appendChild(bannerEl); } @@ -283,8 +297,6 @@ export function updateEmulatorBanner( `; firebaseText.innerText = 'Using emulated backend'; - learnMoreLink.href = - 'https://firebase.google.com/docs/studio/solution-build-with-ai'; } firebaseText.setAttribute('id', firebaseTextId); } From db73a9614a30fc314e390fd8507b78e4c8e68eec Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 17:26:24 -0700 Subject: [PATCH 54/67] Used disableWarnings in auth --- packages/auth/src/core/auth/emulator.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/auth/src/core/auth/emulator.ts b/packages/auth/src/core/auth/emulator.ts index 305cfcd5064..aa7f13ed9ff 100644 --- a/packages/auth/src/core/auth/emulator.ts +++ b/packages/auth/src/core/auth/emulator.ts @@ -102,14 +102,17 @@ export function connectAuthEmulator( authInternal.emulatorConfig = emulatorConfig; authInternal.settings.appVerificationDisabledForTesting = true; - if (!disableWarnings && !isCloudWorkstation(host)) { - emitEmulatorWarning(); + if (!disableWarnings) { + if (isCloudWorkstation(host)) { + updateEmulatorBanner('Auth', true); + } else { + emitEmulatorWarning(); + } } // Workaround to get cookies in Firebase Studio if (isCloudWorkstation(host)) { void pingServer(`${protocol}//${host}${portStr}`); - updateEmulatorBanner('Auth', true); } } From 1c4c6eebd7ba306ad51d21bdc8533d3b2af9e32c Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Tue, 6 May 2025 17:35:53 -0700 Subject: [PATCH 55/67] Fixed linting --- packages/database/src/core/Repo.ts | 3 +-- packages/util/src/emulator.ts | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/database/src/core/Repo.ts b/packages/database/src/core/Repo.ts index 7fb62a6955e..2d76af39a08 100644 --- a/packages/database/src/core/Repo.ts +++ b/packages/database/src/core/Repo.ts @@ -21,8 +21,7 @@ import { isEmpty, map, safeGet, - stringify, - updateEmulatorBanner + stringify } from '@firebase/util'; import { ValueEventRegistration } from '../api/Reference_impl'; diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index a8f3181f62e..6dba618de3a 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -193,7 +193,7 @@ export function updateEmulatorBanner( if ( typeof window === 'undefined' || typeof document === 'undefined' || - // !isCloudWorkstation(window.location.host) || + !isCloudWorkstation(window.location.host) || emulatorStatus[name] === isRunningEmulator || emulatorStatus[name] || // If already set to use emulator, can't go back to prod. previouslyDismissed @@ -217,7 +217,7 @@ export function updateEmulatorBanner( } } - function setupBannerStyles(bannerEl: HTMLElement) { + function setupBannerStyles(bannerEl: HTMLElement): void { bannerEl.style.display = 'flex'; bannerEl.style.background = '#7faaf0'; bannerEl.style.position = 'absolute'; @@ -228,7 +228,7 @@ export function updateEmulatorBanner( bannerEl.style.alignContent = 'center'; } - function setupIconStyles(prependIcon: SVGElement, iconId: string) { + function setupIconStyles(prependIcon: SVGElement, iconId: string): void { prependIcon.setAttribute('width', '24'); prependIcon.setAttribute('id', iconId); prependIcon.setAttribute('height', '24'); @@ -237,7 +237,7 @@ export function updateEmulatorBanner( prependIcon.style.marginLeft = '-6px'; } - function setupCloseBtn() { + function setupCloseBtn(): HTMLSpanElement { const closeBtn = document.createElement('span'); closeBtn.style.cursor = 'pointer'; closeBtn.style.paddingLeft = '5px'; From 3a4ba477a0d65d678da5e8a5ff9e0f1d72a7cf92 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 8 May 2025 10:19:38 -0700 Subject: [PATCH 56/67] Fixed linting --- packages/auth/src/api/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index 9e25d241345..cd013cadf4a 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -19,8 +19,7 @@ import { FirebaseError, isCloudflareWorker, isCloudWorkstation, - querystring, - updateEmulatorBanner + querystring } from '@firebase/util'; import { AuthErrorCode, NamedErrorParams } from '../core/errors'; From 613bd0496c85c50380ae9c7c5cc2ddff55a8286d Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 8 May 2025 10:24:55 -0700 Subject: [PATCH 57/67] Updated for copy --- packages/util/src/emulator.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 6dba618de3a..4a2f4a1dd9f 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -270,6 +270,7 @@ export function updateEmulatorBanner( setupBannerStyles(bannerEl); const closeBtn = setupCloseBtn(); learnMoreLink.setAttribute('id', learnMoreId); + learnMoreLink.innerText = 'Learn more'; learnMoreLink.href = 'http://firebase.google.com/docs/studio/deploy-app#emulator '; setupIconStyles(prependIcon, prependIconId); @@ -278,7 +279,7 @@ export function updateEmulatorBanner( } if (showError) { - firebaseText.innerText = `Running in Production`; + firebaseText.innerText = `Not using emulated backend.`; prependIcon.innerHTML = ` From 243d24da1d3441c76532ecc308006ed64e428007 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 8 May 2025 10:43:48 -0700 Subject: [PATCH 58/67] Removed testing changed --- packages/util/src/emulator.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 4a2f4a1dd9f..f30628335e1 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -249,6 +249,18 @@ export function updateEmulatorBanner( return closeBtn; } + function setupLinkStyles( + learnMoreLink: HTMLAnchorElement, + learnMoreId: string + ): void { + learnMoreLink.setAttribute('id', learnMoreId); + learnMoreLink.innerText = 'Learn more'; + learnMoreLink.href = + 'http://firebase.google.com/docs/studio/deploy-app#emulator '; + learnMoreLink.setAttribute('target', '__blank'); + learnMoreLink.style.paddingLeft = '5px'; + } + function setupDom(): void { const banner = getOrCreateEl(bannerId); const firebaseTextId = prefixedId('text'); @@ -268,11 +280,8 @@ export function updateEmulatorBanner( // update styles const bannerEl = banner.element; setupBannerStyles(bannerEl); + setupLinkStyles(learnMoreLink, learnMoreId); const closeBtn = setupCloseBtn(); - learnMoreLink.setAttribute('id', learnMoreId); - learnMoreLink.innerText = 'Learn more'; - learnMoreLink.href = - 'http://firebase.google.com/docs/studio/deploy-app#emulator '; setupIconStyles(prependIcon, prependIconId); bannerEl.append(prependIcon, firebaseText, learnMoreLink, closeBtn); document.body.appendChild(bannerEl); From 0da1b9fcd569c70435044ec0fa675cb1ff8ed625 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 8 May 2025 14:42:14 -0700 Subject: [PATCH 59/67] Updated to include external link --- packages/auth/src/api/index.ts | 3 +-- packages/auth/src/core/auth/emulator.ts | 13 ++++------ packages/auth/src/platform_browser/index.ts | 2 -- packages/database/src/api/Database.ts | 1 - .../firestore/src/util/async_queue_impl.ts | 1 + packages/functions/src/api.ts | 1 - packages/functions/src/service.ts | 2 -- packages/storage/src/api.ts | 1 - packages/storage/src/service.ts | 1 - packages/util/src/emulator.ts | 24 ++++++++++++++++++- 10 files changed, 29 insertions(+), 20 deletions(-) diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index cd013cadf4a..af9b3c63bf1 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -198,8 +198,7 @@ export async function _performFetchWithErrorHandling( customErrorMap: Partial>, fetchFn: () => Promise ): Promise { - const authInternal = auth as AuthInternal; - authInternal._canInitEmulator = false; + (auth as AuthInternal)._canInitEmulator = false; const errorMap = { ...SERVER_ERROR_MAP, ...customErrorMap }; try { const networkTimeout = new NetworkTimeout(auth); diff --git a/packages/auth/src/core/auth/emulator.ts b/packages/auth/src/core/auth/emulator.ts index aa7f13ed9ff..42fbda3f095 100644 --- a/packages/auth/src/core/auth/emulator.ts +++ b/packages/auth/src/core/auth/emulator.ts @@ -102,17 +102,12 @@ export function connectAuthEmulator( authInternal.emulatorConfig = emulatorConfig; authInternal.settings.appVerificationDisabledForTesting = true; - if (!disableWarnings) { - if (isCloudWorkstation(host)) { - updateEmulatorBanner('Auth', true); - } else { - emitEmulatorWarning(); - } - } - - // Workaround to get cookies in Firebase Studio if (isCloudWorkstation(host)) { + updateEmulatorBanner('Auth', true); + // Workaround to get cookies in Firebase Studio void pingServer(`${protocol}//${host}${portStr}`); + } else if (!disableWarnings) { + emitEmulatorWarning(); } } diff --git a/packages/auth/src/platform_browser/index.ts b/packages/auth/src/platform_browser/index.ts index 025bd50869f..f0e5039a070 100644 --- a/packages/auth/src/platform_browser/index.ts +++ b/packages/auth/src/platform_browser/index.ts @@ -111,8 +111,6 @@ export function getAuth(app: FirebaseApp = getApp()): Auth { } } - updateEmulatorBanner('Auth', false); - const authEmulatorHost = getDefaultEmulatorHost('auth'); if (authEmulatorHost) { connectAuthEmulator(auth, `http://${authEmulatorHost}`); diff --git a/packages/database/src/api/Database.ts b/packages/database/src/api/Database.ts index e1652467a60..a94b04518d7 100644 --- a/packages/database/src/api/Database.ts +++ b/packages/database/src/api/Database.ts @@ -333,7 +333,6 @@ export function getDatabase( identifier: url }) as Database; if (!db._instanceStarted) { - updateEmulatorBanner('Database', false); const emulator = getDefaultEmulatorHostnameAndPort('database'); if (emulator) { connectDatabaseEmulator(db, ...emulator); diff --git a/packages/firestore/src/util/async_queue_impl.ts b/packages/firestore/src/util/async_queue_impl.ts index f8c7a995761..f0d003e0b7d 100644 --- a/packages/firestore/src/util/async_queue_impl.ts +++ b/packages/firestore/src/util/async_queue_impl.ts @@ -182,6 +182,7 @@ export class AsyncQueueImpl implements AsyncQueue { } private enqueueInternal(op: () => Promise): Promise { + console.trace(); const newTail = this.tail.then(() => { this.operationInProgress = true; return op() diff --git a/packages/functions/src/api.ts b/packages/functions/src/api.ts index cb987035145..e07d7608678 100644 --- a/packages/functions/src/api.ts +++ b/packages/functions/src/api.ts @@ -48,7 +48,6 @@ export function getFunctions( app: FirebaseApp = getApp(), regionOrCustomDomain: string = DEFAULT_REGION ): Functions { - updateEmulatorBanner('Functions', false); // Dependencies const functionsProvider: Provider<'functions'> = _getProvider( getModularInstance(app), diff --git a/packages/functions/src/service.ts b/packages/functions/src/service.ts index 000420e381c..57504a4c7a4 100644 --- a/packages/functions/src/service.ts +++ b/packages/functions/src/service.ts @@ -200,7 +200,6 @@ export function httpsCallable( name: string, options?: HttpsCallableOptions ): HttpsCallable { - updateEmulatorBanner('Functions', functionsInstance.emulatorOrigin !== null); const callable = ( data?: RequestData | null ): Promise => { @@ -231,7 +230,6 @@ export function httpsCallableFromURL< url: string, options?: HttpsCallableOptions ): HttpsCallable { - updateEmulatorBanner('Functions', functionsInstance.emulatorOrigin !== null); const callable = ( data?: RequestData | null ): Promise => { diff --git a/packages/storage/src/api.ts b/packages/storage/src/api.ts index b164a1324c3..7149e8388dd 100644 --- a/packages/storage/src/api.ts +++ b/packages/storage/src/api.ts @@ -333,7 +333,6 @@ export function getStorage( bucketUrl?: string ): FirebaseStorage { app = getModularInstance(app); - updateEmulatorBanner('Storage', false); const storageProvider: Provider<'storage'> = _getProvider(app, STORAGE_TYPE); const storageInstance = storageProvider.getImmediate({ identifier: bucketUrl diff --git a/packages/storage/src/service.ts b/packages/storage/src/service.ts index 60369279ff2..97d1407bb52 100644 --- a/packages/storage/src/service.ts +++ b/packages/storage/src/service.ts @@ -326,7 +326,6 @@ export class FirebaseStorageImpl implements FirebaseStorage { appCheckToken: string | null, retry = true ): Request { - updateEmulatorBanner('Service', this._isUsingEmulator); if (!this._deleted) { const request = makeRequest( requestInfo, diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index f30628335e1..1aa20ec2f44 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -261,6 +261,15 @@ export function updateEmulatorBanner( learnMoreLink.style.paddingLeft = '5px'; } + function setupOpenExternal(svgElement: SVGElement, id: string): void { + svgElement.setAttribute('viewBox', '0 0 16 16'); + svgElement.setAttribute('fill', 'none'); + svgElement.setAttribute('id', id); + svgElement.style.width = '16px'; + svgElement.style.marginLeft = '4px'; + svgElement.innerHTML = ``; + } + function setupDom(): void { const banner = getOrCreateEl(bannerId); const firebaseTextId = prefixedId('text'); @@ -276,14 +285,27 @@ export function updateEmulatorBanner( prependIconId ) as HTMLOrSVGElement as SVGElement) || document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + const openExternalIconId = prefixedId('openexternal'); + const openExternalIcon: SVGElement = + (document.getElementById( + openExternalIconId + ) as HTMLOrSVGElement as SVGElement) || + document.createElementNS('http://www.w3.org/2000/svg', 'svg'); if (banner.created) { // update styles const bannerEl = banner.element; setupBannerStyles(bannerEl); setupLinkStyles(learnMoreLink, learnMoreId); + setupOpenExternal(openExternalIcon, openExternalIconId); const closeBtn = setupCloseBtn(); setupIconStyles(prependIcon, prependIconId); - bannerEl.append(prependIcon, firebaseText, learnMoreLink, closeBtn); + bannerEl.append( + prependIcon, + firebaseText, + learnMoreLink, + openExternalIcon, + closeBtn + ); document.body.appendChild(bannerEl); } From 3d0a24f7b56aef0b7d35e44c94f3b2d89befc04b Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 8 May 2025 14:44:56 -0700 Subject: [PATCH 60/67] Added back emulator banner change --- packages/functions/src/api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/functions/src/api.ts b/packages/functions/src/api.ts index e07d7608678..cb987035145 100644 --- a/packages/functions/src/api.ts +++ b/packages/functions/src/api.ts @@ -48,6 +48,7 @@ export function getFunctions( app: FirebaseApp = getApp(), regionOrCustomDomain: string = DEFAULT_REGION ): Functions { + updateEmulatorBanner('Functions', false); // Dependencies const functionsProvider: Provider<'functions'> = _getProvider( getModularInstance(app), From c553d9946cfc6122dc6fbc9f240e2743263b1f60 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 8 May 2025 14:48:08 -0700 Subject: [PATCH 61/67] Added back emulator banner change --- packages/auth/src/platform_browser/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/auth/src/platform_browser/index.ts b/packages/auth/src/platform_browser/index.ts index f0e5039a070..99ab834cbdb 100644 --- a/packages/auth/src/platform_browser/index.ts +++ b/packages/auth/src/platform_browser/index.ts @@ -114,6 +114,8 @@ export function getAuth(app: FirebaseApp = getApp()): Auth { const authEmulatorHost = getDefaultEmulatorHost('auth'); if (authEmulatorHost) { connectAuthEmulator(auth, `http://${authEmulatorHost}`); + } else { + updateEmulatorBanner('Auth', false); } return auth; From e5a945c8fcd9a174576e398ad3e710a1c267034d Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 8 May 2025 15:13:29 -0700 Subject: [PATCH 62/67] Fixed linting --- packages/storage/src/api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/storage/src/api.ts b/packages/storage/src/api.ts index 7149e8388dd..b164a1324c3 100644 --- a/packages/storage/src/api.ts +++ b/packages/storage/src/api.ts @@ -333,6 +333,7 @@ export function getStorage( bucketUrl?: string ): FirebaseStorage { app = getModularInstance(app); + updateEmulatorBanner('Storage', false); const storageProvider: Provider<'storage'> = _getProvider(app, STORAGE_TYPE); const storageInstance = storageProvider.getImmediate({ identifier: bucketUrl From a528caf5fd1b62a1094fbdec630583f7b483d916 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Thu, 8 May 2025 15:14:01 -0700 Subject: [PATCH 63/67] Removed trace --- packages/firestore/src/util/async_queue_impl.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/firestore/src/util/async_queue_impl.ts b/packages/firestore/src/util/async_queue_impl.ts index f0d003e0b7d..f8c7a995761 100644 --- a/packages/firestore/src/util/async_queue_impl.ts +++ b/packages/firestore/src/util/async_queue_impl.ts @@ -182,7 +182,6 @@ export class AsyncQueueImpl implements AsyncQueue { } private enqueueInternal(op: () => Promise): Promise { - console.trace(); const newTail = this.tail.then(() => { this.operationInProgress = true; return op() From dbac496fa75fda342321d1e6dbe6719bef886f1e Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 12 May 2025 10:56:18 -0700 Subject: [PATCH 64/67] Addressed comments --- packages/util/src/emulator.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 1aa20ec2f44..0e94ce51f04 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -241,6 +241,7 @@ export function updateEmulatorBanner( const closeBtn = document.createElement('span'); closeBtn.style.cursor = 'pointer'; closeBtn.style.paddingLeft = '5px'; + closeBtn.style.width = '10px'; closeBtn.innerHTML = ' ×'; closeBtn.onclick = () => { previouslyDismissed = true; @@ -251,7 +252,8 @@ export function updateEmulatorBanner( function setupLinkStyles( learnMoreLink: HTMLAnchorElement, - learnMoreId: string + learnMoreId: string, + svgElement: SVGElement ): void { learnMoreLink.setAttribute('id', learnMoreId); learnMoreLink.innerText = 'Learn more'; @@ -259,6 +261,8 @@ export function updateEmulatorBanner( 'http://firebase.google.com/docs/studio/deploy-app#emulator '; learnMoreLink.setAttribute('target', '__blank'); learnMoreLink.style.paddingLeft = '5px'; + learnMoreLink.style.textDecoration = 'underline'; + learnMoreLink.appendChild(svgElement); } function setupOpenExternal(svgElement: SVGElement, id: string): void { @@ -295,8 +299,8 @@ export function updateEmulatorBanner( // update styles const bannerEl = banner.element; setupBannerStyles(bannerEl); - setupLinkStyles(learnMoreLink, learnMoreId); setupOpenExternal(openExternalIcon, openExternalIconId); + setupLinkStyles(learnMoreLink, learnMoreId, openExternalIcon); const closeBtn = setupCloseBtn(); setupIconStyles(prependIcon, prependIconId); bannerEl.append( From 16cd277a225ffadde80e389c64515b541558ca7c Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 12 May 2025 11:29:56 -0700 Subject: [PATCH 65/67] Removed out link --- packages/util/src/emulator.ts | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 0e94ce51f04..182cd409594 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -252,8 +252,7 @@ export function updateEmulatorBanner( function setupLinkStyles( learnMoreLink: HTMLAnchorElement, - learnMoreId: string, - svgElement: SVGElement + learnMoreId: string ): void { learnMoreLink.setAttribute('id', learnMoreId); learnMoreLink.innerText = 'Learn more'; @@ -262,16 +261,6 @@ export function updateEmulatorBanner( learnMoreLink.setAttribute('target', '__blank'); learnMoreLink.style.paddingLeft = '5px'; learnMoreLink.style.textDecoration = 'underline'; - learnMoreLink.appendChild(svgElement); - } - - function setupOpenExternal(svgElement: SVGElement, id: string): void { - svgElement.setAttribute('viewBox', '0 0 16 16'); - svgElement.setAttribute('fill', 'none'); - svgElement.setAttribute('id', id); - svgElement.style.width = '16px'; - svgElement.style.marginLeft = '4px'; - svgElement.innerHTML = ``; } function setupDom(): void { @@ -289,25 +278,17 @@ export function updateEmulatorBanner( prependIconId ) as HTMLOrSVGElement as SVGElement) || document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - const openExternalIconId = prefixedId('openexternal'); - const openExternalIcon: SVGElement = - (document.getElementById( - openExternalIconId - ) as HTMLOrSVGElement as SVGElement) || - document.createElementNS('http://www.w3.org/2000/svg', 'svg'); if (banner.created) { // update styles const bannerEl = banner.element; setupBannerStyles(bannerEl); - setupOpenExternal(openExternalIcon, openExternalIconId); - setupLinkStyles(learnMoreLink, learnMoreId, openExternalIcon); + setupLinkStyles(learnMoreLink, learnMoreId); const closeBtn = setupCloseBtn(); setupIconStyles(prependIcon, prependIconId); bannerEl.append( prependIcon, firebaseText, learnMoreLink, - openExternalIcon, closeBtn ); document.body.appendChild(bannerEl); From ecd0deb81617aff6ea48ca2a29413c327fb4b7f9 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 12 May 2025 11:55:49 -0700 Subject: [PATCH 66/67] Addressed comments' --- packages/util/src/emulator.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 182cd409594..f8a88e3365e 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -225,7 +225,7 @@ export function updateEmulatorBanner( bannerEl.style.left = '5px'; bannerEl.style.padding = '.5em'; bannerEl.style.borderRadius = '5px'; - bannerEl.style.alignContent = 'center'; + bannerEl.style.alignItems = 'center'; } function setupIconStyles(prependIcon: SVGElement, iconId: string): void { @@ -240,8 +240,8 @@ export function updateEmulatorBanner( function setupCloseBtn(): HTMLSpanElement { const closeBtn = document.createElement('span'); closeBtn.style.cursor = 'pointer'; - closeBtn.style.paddingLeft = '5px'; - closeBtn.style.width = '10px'; + closeBtn.style.marginLeft = '16px'; + closeBtn.style.fontSize = '24px'; closeBtn.innerHTML = ' ×'; closeBtn.onclick = () => { previouslyDismissed = true; @@ -285,12 +285,7 @@ export function updateEmulatorBanner( setupLinkStyles(learnMoreLink, learnMoreId); const closeBtn = setupCloseBtn(); setupIconStyles(prependIcon, prependIconId); - bannerEl.append( - prependIcon, - firebaseText, - learnMoreLink, - closeBtn - ); + bannerEl.append(prependIcon, firebaseText, learnMoreLink, closeBtn); document.body.appendChild(bannerEl); } From 0615f555aa2f37bf3c94bfd95d50857c5dbec55a Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Mon, 12 May 2025 11:59:55 -0700 Subject: [PATCH 67/67] Finalized changes --- packages/util/src/emulator.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index f8a88e3365e..ff09940d88f 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -257,7 +257,7 @@ export function updateEmulatorBanner( learnMoreLink.setAttribute('id', learnMoreId); learnMoreLink.innerText = 'Learn more'; learnMoreLink.href = - 'http://firebase.google.com/docs/studio/deploy-app#emulator '; + 'https://firebase.google.com/docs/studio/preview-apps#preview-backend'; learnMoreLink.setAttribute('target', '__blank'); learnMoreLink.style.paddingLeft = '5px'; learnMoreLink.style.textDecoration = 'underline'; @@ -290,7 +290,7 @@ export function updateEmulatorBanner( } if (showError) { - firebaseText.innerText = `Not using emulated backend.`; + firebaseText.innerText = `Preview backend disconnected.`; prependIcon.innerHTML = ` @@ -308,7 +308,7 @@ export function updateEmulatorBanner( `; - firebaseText.innerText = 'Using emulated backend'; + firebaseText.innerText = 'Preview backend running in this workspace.'; } firebaseText.setAttribute('id', firebaseTextId); }