firebase-tools 13.29.3 → 13.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -97,7 +97,7 @@ async function isStorageProvisioned(projectId) {
97
97
  return !!((_b = (_a = resp.body) === null || _a === void 0 ? void 0 : _a.buckets) === null || _b === void 0 ? void 0 : _b.find((bucket) => {
98
98
  const bucketResourceName = bucket.name;
99
99
  const bucketResourceNameTokens = bucketResourceName.split("/");
100
- const pattern = "^" + projectId + "(.[[a-z0-9]+)*.appspot.com$";
100
+ const pattern = "^" + projectId + "(.[[a-z0-9]+)*.(appspot.com|firebasestorage.app)$";
101
101
  return new RegExp(pattern).test(bucketResourceNameTokens[bucketResourceNameTokens.length - 1]);
102
102
  }));
103
103
  }
@@ -123,7 +123,9 @@ function simpleProxy(hostOrRequestHandler) {
123
123
  });
124
124
  }
125
125
  else {
126
- const proxiedRes = proxyResponse(originalReq, originalRes, next);
126
+ const proxiedRes = proxyResponse(originalReq, originalRes, () => {
127
+ void hostOrRequestHandler(originalReq, originalRes, next);
128
+ });
127
129
  await hostOrRequestHandler(originalReq, proxiedRes, next);
128
130
  }
129
131
  };
@@ -259,6 +259,9 @@ function functionFromEndpoint(endpoint) {
259
259
  }
260
260
  else if (backend.isCallableTriggered(endpoint)) {
261
261
  gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-callable": "true" });
262
+ if (endpoint.callableTrigger.genkitAction) {
263
+ gcfFunction.labels["genkit-action"] = "true";
264
+ }
262
265
  }
263
266
  else if (backend.isBlockingTriggered(endpoint)) {
264
267
  gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { [constants_1.BLOCKING_LABEL]: constants_1.BLOCKING_EVENT_TO_LABEL_KEY[endpoint.blockingTrigger.eventType] });
@@ -14,9 +14,11 @@ const ensureApiEnabled_1 = require("../../../ensureApiEnabled");
14
14
  const logger_1 = require("../../../logger");
15
15
  const error_1 = require("../../../error");
16
16
  const utils_1 = require("../../../utils");
17
+ const UNKNOWN_VERSION_TOO_HIGH = "2.0.0";
18
+ const LATEST_TEMPLATE = "1.0.0";
17
19
  async function getGenkitVersion() {
18
20
  let genkitVersion;
19
- let templateVersion = "0.9.0";
21
+ let templateVersion = LATEST_TEMPLATE;
20
22
  let useInit = false;
21
23
  let stopInstall = false;
22
24
  if (process.env.GENKIT_DEV_VERSION && typeof process.env.GENKIT_DEV_VERSION === "string") {
@@ -39,7 +41,7 @@ async function getGenkitVersion() {
39
41
  if (!genkitVersion) {
40
42
  throw new error_1.FirebaseError("Unable to determine genkit version to install");
41
43
  }
42
- if (semver.gte(genkitVersion, "1.0.0")) {
44
+ if (semver.gte(genkitVersion, UNKNOWN_VERSION_TOO_HIGH)) {
43
45
  const continueInstall = await (0, prompt_1.confirm)({
44
46
  message: clc.yellow(`WARNING: The latest version of Genkit (${genkitVersion}) isn't supported by this\n` +
45
47
  "version of firebase-tools. You can proceed, but the provided sample code may\n" +
@@ -51,7 +53,11 @@ async function getGenkitVersion() {
51
53
  stopInstall = true;
52
54
  }
53
55
  }
56
+ else if (semver.gte(genkitVersion, "1.0.0-rc.1")) {
57
+ templateVersion = "1.0.0";
58
+ }
54
59
  else if (semver.gte(genkitVersion, "0.6.0")) {
60
+ templateVersion = "0.9.0";
55
61
  }
56
62
  else {
57
63
  templateVersion = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "13.29.3",
3
+ "version": "13.30.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
@@ -0,0 +1,66 @@
1
+ // Import the Genkit core libraries and plugins.
2
+ import {genkit, z} from "genkit";
3
+ $GENKIT_CONFIG_IMPORTS
4
+ $GENKIT_MODEL_IMPORT
5
+
6
+ // Cloud Functions for Firebase supports Genkit natively. The onCallGenkit function creates a callable
7
+ // function from a Genkit action. It automatically implements streaming if your flow does.
8
+ // The https library also has other utility methods such as hasClaim, which verifies that
9
+ // a caller's token has a specific claim (optionally matching a specific value)
10
+ import { onCallGenkit, hasClaim } from "firebase-functions/https";
11
+
12
+ // Genkit models generally depend on an API key. APIs should be stored in Cloud Secret Manager so that
13
+ // access to these sensitive values can be controlled. defineSecret does this for you automatically.
14
+ // If you are using Google generative AI you can get an API key at https://aistudio.google.com/app/apikey
15
+ import { defineSecret } from "firebase-functions/params";
16
+ const apiKey = defineSecret("GOOGLE_GENAI_API_KEY");
17
+
18
+ const ai = genkit({
19
+ plugins: [
20
+ $GENKIT_CONFIG_PLUGINS
21
+ ],
22
+ });
23
+
24
+ // Define a simple flow that prompts an LLM to generate menu suggestions.
25
+ const menuSuggestionFlow = ai.defineFlow({
26
+ name: "menuSuggestionFlow",
27
+ inputSchema: z.string(),
28
+ outputSchema: z.string(),
29
+ streamSchema: z.string(),
30
+ }, async (subject, { sendChunk }) => {
31
+ // Construct a request and send it to the model API.
32
+ const prompt =
33
+ `Suggest an item for the menu of a ${subject} themed restaurant`;
34
+ const { response, stream } = ai.generateStream({
35
+ model: $GENKIT_MODEL,
36
+ prompt: prompt,
37
+ config: {
38
+ temperature: 1,
39
+ },
40
+ });
41
+
42
+ for await (const chunk of stream) {
43
+ sendChunk(chunk.text);
44
+ }
45
+
46
+ // Handle the response from the model API. In this sample, we just
47
+ // convert it to a string, but more complicated flows might coerce the
48
+ // response into structured output or chain the response into another
49
+ // LLM call, etc.
50
+ return (await response).text;
51
+ }
52
+ );
53
+
54
+ export const menuSuggestion = onCallGenkit({
55
+ // Uncomment to enable AppCheck. This can reduce costs by ensuring only your Verified
56
+ // app users can use your API. Read more at https://firebase.google.com/docs/app-check/cloud-functions
57
+ // enforceAppCheck: true,
58
+
59
+ // authPolicy can be any callback that accepts an AuthData (a uid and tokens dictionary) and the
60
+ // request data. The isSignedIn() and hasClaim() helpers can be used to simplify. The following
61
+ // will require the user to have the email_verified claim, for example.
62
+ // authPolicy: hasClaim("email_verified"),
63
+
64
+ // Grant access to the API key to this function:
65
+ secrets: [apiKey],
66
+ }, menuSuggestionFlow);
@@ -1,36 +1,20 @@
1
1
  # # Example mutations for a simple movie app
2
2
 
3
3
  # # Create a movie based on user input
4
- # mutation CreateMovie(
5
- # $title: String!
6
- # $genre: String!
7
- # $imageUrl: String!
8
- # ) @auth(level: USER_EMAIL_VERIFIED) {
9
- # movie_insert(
10
- # data: {
11
- # title: $title
12
- # genre: $genre
13
- # imageUrl: $imageUrl
14
- # }
15
- # )
4
+ # mutation CreateMovie($title: String!, $genre: String!, $imageUrl: String!)
5
+ # @auth(level: USER_EMAIL_VERIFIED) {
6
+ # movie_insert(data: { title: $title, genre: $genre, imageUrl: $imageUrl })
16
7
  # }
17
8
 
18
9
  # # Upsert (update or insert) a user's username based on their auth.uid
19
10
  # mutation UpsertUser($username: String!) @auth(level: USER) {
20
- # user_upsert(
21
- # data: {
22
- # id_expr: "auth.uid"
23
- # username: $username
24
- # }
25
- # )
11
+ # # The "auth.uid" server value ensures that users can only register their own user.
12
+ # user_upsert(data: { id_expr: "auth.uid", username: $username })
26
13
  # }
27
14
 
28
15
  # # Add a review for a movie
29
- # mutation AddReview(
30
- # $movieId: UUID!
31
- # $rating: Int!
32
- # $reviewText: String!
33
- # ) @auth(level: USER) {
16
+ # mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!)
17
+ # @auth(level: USER) {
34
18
  # review_upsert(
35
19
  # data: {
36
20
  # userId_expr: "auth.uid"
@@ -43,8 +27,7 @@
43
27
  # }
44
28
 
45
29
  # # Logged in user can delete their review for a movie
46
- # mutation DeleteReview(
47
- # $movieId: UUID!
48
- # ) @auth(level: USER) {
30
+ # mutation DeleteReview($movieId: UUID!) @auth(level: USER) {
31
+ # # The "auth.uid" server value ensures that users can only delete their own reviews.
49
32
  # review_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
50
33
  # }
@@ -13,19 +13,21 @@
13
13
 
14
14
  # # List all users, only admins should be able to list all users, so we use NO_ACCESS
15
15
  # query ListUsers @auth(level: NO_ACCESS) {
16
- # users { id, username }
16
+ # users {
17
+ # id
18
+ # username
19
+ # }
17
20
  # }
18
21
 
19
- # # Logged in user can list all their reviews and movie titles associated with the review
20
- # # Since the query requires the uid of the current authenticated user, the auth level is set to USER
22
+ # # Logged in users can list all their reviews and movie titles associated with the review
23
+ # # Since the query uses the uid of the current authenticated user, we set auth level to USER
21
24
  # query ListUserReviews @auth(level: USER) {
22
- # user(key: {id_expr: "auth.uid"}) {
25
+ # user(key: { id_expr: "auth.uid" }) {
23
26
  # id
24
27
  # username
25
28
  # # <field>_on_<foreign_key_field> makes it easy to grab info from another table
26
29
  # # Here, we use it to grab all the reviews written by the user.
27
30
  # reviews: reviews_on_user {
28
- # id
29
31
  # rating
30
32
  # reviewDate
31
33
  # reviewText
@@ -50,7 +52,6 @@
50
52
  # description
51
53
  # }
52
54
  # reviews: reviews_on_movie {
53
- # id
54
55
  # reviewText
55
56
  # reviewDate
56
57
  # rating
@@ -63,16 +64,10 @@
63
64
  # }
64
65
 
65
66
  # # Search for movies, actors, and reviews
66
- # query SearchMovie(
67
- # $titleInput: String
68
- # $genre: String
69
- # ) @auth(level: PUBLIC) {
67
+ # query SearchMovie($titleInput: String, $genre: String) @auth(level: PUBLIC) {
70
68
  # movies(
71
69
  # where: {
72
- # _and: [
73
- # { genre: { eq: $genre } }
74
- # { title: { contains: $titleInput } }
75
- # ]
70
+ # _and: [{ genre: { eq: $genre } }, { title: { contains: $titleInput } }]
76
71
  # }
77
72
  # ) {
78
73
  # id
@@ -1,44 +1,51 @@
1
1
  # # Example schema for simple movie review app
2
2
 
3
- # # Users
4
- # # Suppose a user can leave reviews for movies
5
- # # user -> reviews is a one to many relationship,
6
- # # movie -> reviews is a one to many relationship
7
- # # movie <-> user is a many to many relationship
3
+ # # User table is keyed by Firebase Auth UID.
8
4
  # type User @table {
9
- # id: String! @col(name: "user_auth")
10
- # username: String! @col(name: "username", dataType: "varchar(50)")
11
- # # The following are generated by the user: User! field in the Review table
12
- # # reviews_on_user
13
- # # movies_via_Review
5
+ # # `@default(expr: "auth.uid")` sets it to Firebase Auth UID during insert and upsert.
6
+ # id: String! @default(expr: "auth.uid")
7
+ # username: String! @col(dataType: "varchar(50)")
8
+ # # The `user: User!` field in the Review table generates the following one-to-many query field.
9
+ # # reviews_on_user: [Review!]!
10
+ # # The `Review` join table the following many-to-many query field.
11
+ # # movies_via_Review: [Movie!]!
14
12
  # }
15
13
 
16
- # # Movies
14
+ # # Movie is keyed by a randomly generated UUID.
17
15
  # type Movie @table {
18
- # # The below parameter values are generated by default with @table, and can be edited manually.
19
- # # implies directive `@col(name: "movie_id")`, generating a column name
20
- # id: UUID! @default(expr: "uuidV4()")
16
+ # # If you do not pass a 'key' to `@table`, Data Connect automatically adds the following 'id' column.
17
+ # # Feel free to uncomment and customize it.
18
+ # # id: UUID! @default(expr: "uuidV4()")
21
19
  # title: String!
22
20
  # imageUrl: String!
23
21
  # genre: String
24
22
  # }
25
23
 
26
- # # Movie Metadata
27
- # # Movie - MovieMetadata is a one-to-one relationship
24
+ # # MovieMetadata is a metadata attached to a Movie.
25
+ # # Movie <-> MovieMetadata is a one-to-one relationship
28
26
  # type MovieMetadata @table {
29
- # # @unique indicates a 1-1 relationship
30
- # movie: Movie! @unique
31
- # # movieId: UUID <- this is created by the above reference
27
+ # # @unique ensures each Movie can only one MovieMetadata.
28
+ # movie: Movie! @unique
29
+ # # The movie field adds the following foreign key field. Feel free to uncomment and customize it.
30
+ # # movieId: UUID!
32
31
  # rating: Float
33
32
  # releaseYear: Int
34
33
  # description: String
35
34
  # }
36
35
 
37
- # # Reviews
36
+ # # Reviews is a join table between User and Movie.
37
+ # # It has a composite primary keys `userUid` and `movieId`.
38
+ # # A user can leave reviews for many movies. A movie can have reviews from many users.
39
+ # # User <-> Review is a one-to-many relationship
40
+ # # Movie <-> Review is a one-to-many relationship
41
+ # # Movie <-> User is a many-to-many relationship
38
42
  # type Review @table(name: "Reviews", key: ["movie", "user"]) {
39
- # id: UUID! @default(expr: "uuidV4()")
40
43
  # user: User!
44
+ # # The user field adds the following foreign key field. Feel free to uncomment and customize it.
45
+ # # userUid: String!
41
46
  # movie: Movie!
47
+ # # The movie field adds the following foreign key field. Feel free to uncomment and customize it.
48
+ # # movieId: UUID!
42
49
  # rating: Int
43
50
  # reviewText: String
44
51
  # reviewDate: Date! @default(expr: "request.time")