firebase-tools 14.27.0 → 15.0.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.
Files changed (55) hide show
  1. package/lib/archiveDirectory.js +7 -45
  2. package/lib/bin/cli.js +35 -8
  3. package/lib/command.js +5 -1
  4. package/lib/commands/dataconnect-execute.js +1 -1
  5. package/lib/commands/dataconnect-sdk-generate.js +7 -5
  6. package/lib/commands/dataconnect-sql-diff.js +7 -5
  7. package/lib/commands/dataconnect-sql-grant.js +12 -12
  8. package/lib/commands/dataconnect-sql-migrate.js +6 -4
  9. package/lib/commands/dataconnect-sql-setup.js +6 -4
  10. package/lib/commands/dataconnect-sql-shell.js +6 -4
  11. package/lib/commands/firestore-backups-list.js +1 -1
  12. package/lib/commands/functions-config-clone.js +2 -2
  13. package/lib/commands/functions-config-export.js +137 -92
  14. package/lib/commands/functions-config-get.js +1 -2
  15. package/lib/commands/functions-config-set.js +2 -2
  16. package/lib/commands/functions-config-unset.js +2 -2
  17. package/lib/commands/help.js +1 -1
  18. package/lib/commands/index.js +15 -10
  19. package/lib/commands/init.js +8 -0
  20. package/lib/config.js +1 -5
  21. package/lib/dataconnect/load.js +18 -21
  22. package/lib/deploy/database/prepare.js +1 -3
  23. package/lib/deploy/functions/prepare.js +5 -1
  24. package/lib/deploy/functions/prepareFunctionsUpload.js +1 -2
  25. package/lib/deploy/functions/runtimes/node/index.js +11 -12
  26. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  27. package/lib/deploy/functions/validate.js +49 -2
  28. package/lib/emulator/commandUtils.js +1 -1
  29. package/lib/emulator/controller.js +1 -2
  30. package/lib/emulator/databaseEmulator.js +1 -5
  31. package/lib/emulator/downloadableEmulatorInfo.json +30 -30
  32. package/lib/emulator/functionsEmulator.js +0 -40
  33. package/lib/emulator/functionsEmulatorRuntime.js +1 -118
  34. package/lib/emulator/functionsEmulatorShared.js +1 -6
  35. package/lib/experiments.js +8 -1
  36. package/lib/extensions/extensionsHelper.js +0 -1
  37. package/lib/frameworks/constants.js +1 -1
  38. package/lib/fsAsync.js +11 -3
  39. package/lib/functionsConfig.js +39 -1
  40. package/lib/index.js +44 -1
  41. package/lib/init/features/dataconnect/resolver.js +111 -0
  42. package/lib/init/features/index.js +4 -1
  43. package/lib/init/features/project.js +1 -0
  44. package/lib/init/index.js +5 -0
  45. package/lib/mcp/tools/dataconnect/compile.js +13 -7
  46. package/lib/mcp/tools/dataconnect/execute.js +10 -7
  47. package/lib/mcp/tools/dataconnect/generate_operation.js +7 -3
  48. package/package.json +1 -2
  49. package/lib/deploy/functions/runtimes/node/extractTriggers.js +0 -23
  50. package/lib/deploy/functions/runtimes/node/parseTriggers.js +0 -332
  51. package/lib/deploy/functions/runtimes/node/triggerParser.js +0 -72
  52. package/lib/functions/deprecationWarnings.js +0 -21
  53. package/lib/functions/runtimeConfigExport.js +0 -141
  54. package/lib/handlePreviewToggles.js +0 -38
  55. package/lib/parseBoltRules.js +0 -29
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addSchemaToDataConnectYaml = exports.actuate = exports.askQuestions = void 0;
4
+ const clc = require("colorette");
5
+ const fs = require("fs-extra");
6
+ const path_1 = require("path");
7
+ const yaml = require("yaml");
8
+ const prompt_1 = require("../../../prompt");
9
+ const utils_1 = require("../../../utils");
10
+ const load_1 = require("../../../dataconnect/load");
11
+ const names_1 = require("../../../dataconnect/names");
12
+ const experiments = require("../../../experiments");
13
+ const cloudbilling_1 = require("../../../gcp/cloudbilling");
14
+ const track_1 = require("../../../track");
15
+ async function askQuestions(setup, config) {
16
+ var _a;
17
+ const resolverInfo = {
18
+ id: "",
19
+ uri: "",
20
+ serviceInfo: {},
21
+ };
22
+ const serviceInfos = await (0, load_1.loadAll)(setup.projectId || "", config);
23
+ if (!serviceInfos.length) {
24
+ throw new Error(`No Firebase Data Connect workspace found. Run ${clc.bold("firebase init dataconnect")} to set up a service and main schema.`);
25
+ }
26
+ else if (serviceInfos.length === 1) {
27
+ resolverInfo.serviceInfo = serviceInfos[0];
28
+ }
29
+ else {
30
+ const choices = serviceInfos.map((si) => {
31
+ const serviceName = (0, names_1.parseServiceName)(si.serviceName);
32
+ return {
33
+ name: `${serviceName.location}/${serviceName.serviceId}`,
34
+ value: si,
35
+ };
36
+ });
37
+ resolverInfo.serviceInfo = await (0, prompt_1.select)({
38
+ message: "Which service would you like to set up a custom resolver for?",
39
+ choices,
40
+ });
41
+ }
42
+ resolverInfo.id = await (0, prompt_1.input)({
43
+ message: `What ID would you like to use for your custom resolver?`,
44
+ default: (0, utils_1.newUniqueId)(`resolver`, ((_a = resolverInfo.serviceInfo.dataConnectYaml.schemas) === null || _a === void 0 ? void 0 : _a.map((sch) => sch.id || "")) || []),
45
+ });
46
+ resolverInfo.uri = `https://${resolverInfo.id}-${setup.projectNumber || "PROJECT_NUMBER"}.${resolverInfo.serviceInfo.dataConnectYaml.location}.run.app/graphql`;
47
+ (0, utils_1.logBullet)("Setting " +
48
+ clc.bold(resolverInfo.uri) +
49
+ " as the custom resolver URL. To change this, update your " +
50
+ clc.bold(`dataconnect.yaml`) +
51
+ " later.");
52
+ setup.featureInfo = setup.featureInfo || {};
53
+ setup.featureInfo.dataconnectResolver = resolverInfo;
54
+ }
55
+ exports.askQuestions = askQuestions;
56
+ async function actuate(setup, config) {
57
+ var _a;
58
+ if (!experiments.isEnabled("fdcwebhooks")) {
59
+ return;
60
+ }
61
+ const resolverInfo = (_a = setup.featureInfo) === null || _a === void 0 ? void 0 : _a.dataconnectResolver;
62
+ if (!resolverInfo) {
63
+ throw new Error("Data Connect resolver feature ResolverRequiredInfo not provided");
64
+ }
65
+ const startTime = Date.now();
66
+ try {
67
+ actuateWithInfo(config, resolverInfo);
68
+ }
69
+ finally {
70
+ const source = "init_resolver";
71
+ void (0, track_1.trackGA4)("dataconnect_init", {
72
+ source,
73
+ project_status: setup.projectId
74
+ ? (await (0, cloudbilling_1.isBillingEnabled)(setup))
75
+ ? "blaze"
76
+ : "spark"
77
+ : "missing",
78
+ }, Date.now() - startTime);
79
+ }
80
+ }
81
+ exports.actuate = actuate;
82
+ function actuateWithInfo(config, info) {
83
+ var _a;
84
+ const dataConnectYaml = JSON.parse(JSON.stringify((_a = info.serviceInfo) === null || _a === void 0 ? void 0 : _a.dataConnectYaml));
85
+ addSchemaToDataConnectYaml(dataConnectYaml, info);
86
+ info.serviceInfo.dataConnectYaml = dataConnectYaml;
87
+ const dataConnectYamlContents = yaml.stringify(dataConnectYaml);
88
+ const dataConnectYamlPath = (0, path_1.join)(info.serviceInfo.sourceDirectory, "dataconnect.yaml");
89
+ config.writeProjectFile((0, path_1.relative)(config.projectDir, dataConnectYamlPath), dataConnectYamlContents);
90
+ fs.ensureFileSync((0, path_1.join)(info.serviceInfo.sourceDirectory, `schema_${info.id}`, "schema.gql"));
91
+ }
92
+ function addSchemaToDataConnectYaml(dataConnectYaml, info) {
93
+ const secondarySchema = {
94
+ source: `./schema_${info.id}`,
95
+ id: info.id,
96
+ datasource: {
97
+ httpGraphql: {
98
+ uri: info.uri,
99
+ },
100
+ },
101
+ };
102
+ if (!dataConnectYaml.schemas) {
103
+ dataConnectYaml.schemas = [];
104
+ if (dataConnectYaml.schema) {
105
+ dataConnectYaml.schemas.push(dataConnectYaml.schema);
106
+ dataConnectYaml.schema = undefined;
107
+ }
108
+ }
109
+ dataConnectYaml.schemas.push(secondarySchema);
110
+ }
111
+ exports.addSchemaToDataConnectYaml = addSchemaToDataConnectYaml;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.aiLogicActuate = exports.aiLogicAskQuestions = exports.aitools = exports.apptestingAcutate = exports.apptestingAskQuestions = exports.genkit = exports.apphosting = exports.dataconnectSdkActuate = exports.dataconnectSdkAskQuestions = exports.dataconnectActuate = exports.dataconnectAskQuestions = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storageActuate = exports.storageAskQuestions = exports.hostingActuate = exports.hostingAskQuestions = exports.functions = exports.firestoreActuate = exports.firestoreAskQuestions = exports.databaseActuate = exports.databaseAskQuestions = exports.account = void 0;
3
+ exports.aiLogicActuate = exports.aiLogicAskQuestions = exports.aitools = exports.apptestingAcutate = exports.apptestingAskQuestions = exports.genkit = exports.apphosting = exports.dataconnectResolverActuate = exports.dataconnectResolverAskQuestions = exports.dataconnectSdkActuate = exports.dataconnectSdkAskQuestions = exports.dataconnectActuate = exports.dataconnectAskQuestions = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storageActuate = exports.storageAskQuestions = exports.hostingActuate = exports.hostingAskQuestions = exports.functions = exports.firestoreActuate = exports.firestoreAskQuestions = exports.databaseActuate = exports.databaseAskQuestions = exports.account = void 0;
4
4
  var account_1 = require("./account");
5
5
  Object.defineProperty(exports, "account", { enumerable: true, get: function () { return account_1.doSetup; } });
6
6
  var database_1 = require("./database");
@@ -33,6 +33,9 @@ Object.defineProperty(exports, "dataconnectActuate", { enumerable: true, get: fu
33
33
  var sdk_1 = require("./dataconnect/sdk");
34
34
  Object.defineProperty(exports, "dataconnectSdkAskQuestions", { enumerable: true, get: function () { return sdk_1.askQuestions; } });
35
35
  Object.defineProperty(exports, "dataconnectSdkActuate", { enumerable: true, get: function () { return sdk_1.actuate; } });
36
+ var resolver_1 = require("./dataconnect/resolver");
37
+ Object.defineProperty(exports, "dataconnectResolverAskQuestions", { enumerable: true, get: function () { return resolver_1.askQuestions; } });
38
+ Object.defineProperty(exports, "dataconnectResolverActuate", { enumerable: true, get: function () { return resolver_1.actuate; } });
36
39
  var apphosting_1 = require("./apphosting");
37
40
  Object.defineProperty(exports, "apphosting", { enumerable: true, get: function () { return apphosting_1.doSetup; } });
38
41
  var genkit_1 = require("./genkit");
@@ -88,6 +88,7 @@ async function usingProjectMetadata(setup, config, pm) {
88
88
  }
89
89
  _.set(setup.rcfile, "projects.default", pm.projectId);
90
90
  setup.projectId = pm.projectId;
91
+ setup.projectNumber = pm.projectNumber;
91
92
  setup.instance = (_a = pm.resources) === null || _a === void 0 ? void 0 : _a.realtimeDatabaseInstance;
92
93
  setup.projectLocation = (_b = pm.resources) === null || _b === void 0 ? void 0 : _b.locationId;
93
94
  utils.makeActiveProject(config.projectDir, pm.projectId);
package/lib/init/index.js CHANGED
@@ -29,6 +29,11 @@ const featuresList = [
29
29
  askQuestions: features.dataconnectSdkAskQuestions,
30
30
  actuate: features.dataconnectSdkActuate,
31
31
  },
32
+ {
33
+ name: "dataconnect:resolver",
34
+ askQuestions: features.dataconnectResolverAskQuestions,
35
+ actuate: features.dataconnectResolverActuate,
36
+ },
32
37
  { name: "functions", doSetup: features.functions },
33
38
  {
34
39
  name: "hosting",
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.compile = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const tool_1 = require("../../tool");
6
- const load_1 = require("../../../dataconnect/load");
7
6
  const compile_1 = require("../../util/dataconnect/compile");
7
+ const load_1 = require("../../../dataconnect/load");
8
8
  exports.compile = (0, tool_1.tool)("dataconnect", {
9
9
  name: "build",
10
10
  description: "Use this to compile Firebase Data Connect schema, operations, and/or connectors and check for build errors.",
@@ -16,7 +16,11 @@ exports.compile = (0, tool_1.tool)("dataconnect", {
16
16
  service_id: zod_1.z
17
17
  .string()
18
18
  .optional()
19
- .describe("The Firebase Data Connect service ID to look for. If omitted, builds all services defined in `firebase.json`."),
19
+ .describe(`Service ID of the Data Connect service to compile. Used to disambiguate when there are multiple Data Connect services in firebase.json.`),
20
+ location_id: zod_1.z
21
+ .string()
22
+ .optional()
23
+ .describe(`Data Connect Service location ID to disambiguate among multiple Data Connect services.`),
20
24
  }),
21
25
  annotations: {
22
26
  title: "Compile Data Connect",
@@ -26,15 +30,17 @@ exports.compile = (0, tool_1.tool)("dataconnect", {
26
30
  requiresProject: false,
27
31
  requiresAuth: false,
28
32
  },
29
- }, async ({ service_id, error_filter }, { projectId, config }) => {
30
- const serviceInfo = await (0, load_1.pickService)(projectId, config, service_id || undefined);
31
- const errors = await (0, compile_1.compileErrors)(serviceInfo.sourceDirectory, error_filter);
32
- if (errors)
33
+ }, async ({ service_id, location_id, error_filter }, { projectId, config }) => {
34
+ const serviceInfos = await (0, load_1.pickServices)(projectId, config, service_id || undefined, location_id || undefined);
35
+ const errors = (await Promise.all(serviceInfos.map(async (serviceInfo) => {
36
+ return await (0, compile_1.compileErrors)(serviceInfo.sourceDirectory, error_filter);
37
+ }))).flat();
38
+ if (errors.length > 0)
33
39
  return {
34
40
  content: [
35
41
  {
36
42
  type: "text",
37
- text: `The following errors were encountered while compiling Data Connect from directory \`${serviceInfo.sourceDirectory}\`:\n\n${errors}`,
43
+ text: `The following errors were encountered while compiling Data Connect:\n\n${errors.join("\n")}`,
38
44
  },
39
45
  ],
40
46
  isError: true,
@@ -15,11 +15,14 @@ exports.execute = (0, tool_1.tool)("dataconnect", {
15
15
  You can use the \`dataconnect_generate_operation\` tool to generate a query.
16
16
  Example Data Connect schema and example queries can be found in files ending in \`.graphql\` or \`.gql\`.
17
17
  `),
18
- service_id: zod_1.z.string().optional()
19
- .describe(`Data Connect Service ID to dis-ambulate if there are multiple.
20
- It's only necessary if there are multiple dataconnect sources in \`firebase.json\`.
21
- You can find candidate service_id in \`dataconnect.yaml\`
22
- `),
18
+ service_id: zod_1.z
19
+ .string()
20
+ .optional()
21
+ .describe(`Service ID of the Data Connect service to compile. Used to disambiguate when there are multiple Data Connect services in firebase.json.`),
22
+ location_id: zod_1.z
23
+ .string()
24
+ .optional()
25
+ .describe(`Data Connect Service location ID to disambiguate among multiple Data Connect services.`),
23
26
  variables_json: zod_1.z
24
27
  .string()
25
28
  .optional()
@@ -42,8 +45,8 @@ You can find candidate service_id in \`dataconnect.yaml\`
42
45
  requiresProject: true,
43
46
  requiresAuth: true,
44
47
  },
45
- }, async ({ query, service_id, variables_json: unparsedVariables, use_emulator, auth_token_json: unparsedAuthToken, }, { projectId, config, host }) => {
46
- const serviceInfo = await (0, load_1.pickService)(projectId, config, service_id || undefined);
48
+ }, async ({ query, service_id, location_id, variables_json: unparsedVariables, use_emulator, auth_token_json: unparsedAuthToken, }, { projectId, config, host }) => {
49
+ const serviceInfo = await (0, load_1.pickOneService)(projectId, config, service_id || undefined, location_id || undefined);
47
50
  let apiClient;
48
51
  if (use_emulator) {
49
52
  apiClient = await (0, emulator_1.getDataConnectEmulatorClient)(host);
@@ -16,7 +16,11 @@ exports.generate_operation = (0, tool_1.tool)("dataconnect", {
16
16
  service_id: zod_1.z
17
17
  .string()
18
18
  .optional()
19
- .describe("Optional: Uses the service ID from the firebase.json file if nothing provided. The service ID of the deployed Firebase resource."),
19
+ .describe(`Service ID of the Data Connect service to compile. Used to disambiguate when there are multiple Data Connect services in firebase.json.`),
20
+ location_id: zod_1.z
21
+ .string()
22
+ .optional()
23
+ .describe(`Data Connect Service location ID to disambiguate among multiple Data Connect services.`),
20
24
  }),
21
25
  annotations: {
22
26
  title: "Generate Data Connect Operation",
@@ -27,8 +31,8 @@ exports.generate_operation = (0, tool_1.tool)("dataconnect", {
27
31
  requiresAuth: true,
28
32
  requiresGemini: true,
29
33
  },
30
- }, async ({ prompt, service_id }, { projectId, config }) => {
31
- const serviceInfo = await (0, load_1.pickService)(projectId, config, service_id || undefined);
34
+ }, async ({ prompt, service_id, location_id }, { projectId, config }) => {
35
+ const serviceInfo = await (0, load_1.pickOneService)(projectId, config, service_id || undefined, location_id || undefined);
32
36
  const schema = await (0, fdcExperience_1.generateOperation)(prompt, serviceInfo.serviceName, projectId);
33
37
  return (0, util_1.toContent)(schema);
34
38
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "14.27.0",
3
+ "version": "15.0.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "mcpName": "io.github.firebase/firebase-mcp",
@@ -125,7 +125,6 @@
125
125
  "stream-chain": "^2.2.4",
126
126
  "stream-json": "^1.7.3",
127
127
  "superstatic": "^10.0.0",
128
- "tar": "^6.1.11",
129
128
  "tcp-port-used": "^1.0.2",
130
129
  "tmp": "^0.2.3",
131
130
  "triple-beam": "^1.3.0",
@@ -1,23 +0,0 @@
1
- "use strict";
2
- var extractTriggers = function (mod, triggers, prefix) {
3
- prefix = prefix || "";
4
- for (var funcName of Object.keys(mod)) {
5
- var child = mod[funcName];
6
- if (typeof child === "function" && child.__trigger && typeof child.__trigger === "object") {
7
- if (funcName.indexOf("-") >= 0) {
8
- throw new Error('Function name "' + funcName + '" is invalid. Function names cannot contain dashes.');
9
- }
10
- var trigger = {};
11
- for (var key of Object.keys(child.__trigger)) {
12
- trigger[key] = child.__trigger[key];
13
- }
14
- trigger.name = prefix + funcName;
15
- trigger.entryPoint = trigger.name.replace(/-/g, ".");
16
- triggers.push(trigger);
17
- }
18
- else if (typeof child === "object" && child !== null) {
19
- extractTriggers(child, triggers, prefix + funcName + "-");
20
- }
21
- }
22
- };
23
- module.exports = extractTriggers;
@@ -1,332 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addResourcesToBackend = exports.addResourcesToBuild = exports.mergeRequiredAPIs = exports.discoverBackend = exports.discoverBuild = exports.useStrategy = void 0;
4
- const path = require("path");
5
- const _ = require("lodash");
6
- const child_process_1 = require("child_process");
7
- const error_1 = require("../../../../error");
8
- const logger_1 = require("../../../../logger");
9
- const backend = require("../../backend");
10
- const api = require("../../../../api");
11
- const proto = require("../../../../gcp/proto");
12
- const events = require("../../../../functions/events");
13
- const functional_1 = require("../../../../functional");
14
- const TRIGGER_PARSER = path.resolve(__dirname, "./triggerParser.js");
15
- function removeInspectOptions(options) {
16
- return options.filter((opt) => !opt.startsWith("--inspect"));
17
- }
18
- function parseTriggers(projectId, sourceDir, configValues, envs) {
19
- return new Promise((resolve, reject) => {
20
- const env = Object.assign({}, envs);
21
- env.GCLOUD_PROJECT = projectId;
22
- if (!_.isEmpty(configValues)) {
23
- env.CLOUD_RUNTIME_CONFIG = JSON.stringify(configValues);
24
- }
25
- const execArgv = removeInspectOptions(process.execArgv);
26
- if (env.NODE_OPTIONS) {
27
- env.NODE_OPTIONS = removeInspectOptions(env.NODE_OPTIONS.split(" ")).join(" ");
28
- }
29
- const parser = (0, child_process_1.fork)(TRIGGER_PARSER, [sourceDir], {
30
- silent: true,
31
- env: env,
32
- execArgv: execArgv,
33
- });
34
- parser.on("message", (message) => {
35
- if (message.triggers) {
36
- resolve(message.triggers);
37
- }
38
- else if (message.error) {
39
- reject(new error_1.FirebaseError(message.error, { exit: 1 }));
40
- }
41
- });
42
- parser.on("exit", (code) => {
43
- if (code !== 0) {
44
- reject(new error_1.FirebaseError("There was an unknown problem while trying to parse function triggers.", { exit: 2 }));
45
- }
46
- });
47
- });
48
- }
49
- function useStrategy() {
50
- return Promise.resolve(true);
51
- }
52
- exports.useStrategy = useStrategy;
53
- async function discoverBuild(projectId, sourceDir, runtime, configValues, envs) {
54
- const triggerAnnotations = await parseTriggers(projectId, sourceDir, configValues, envs);
55
- const want = {
56
- requiredAPIs: [],
57
- endpoints: {},
58
- params: [],
59
- };
60
- for (const annotation of triggerAnnotations) {
61
- addResourcesToBuild(projectId, runtime, annotation, want);
62
- }
63
- return want;
64
- }
65
- exports.discoverBuild = discoverBuild;
66
- async function discoverBackend(projectId, sourceDir, runtime, configValues, envs) {
67
- const triggerAnnotations = await parseTriggers(projectId, sourceDir, configValues, envs);
68
- const want = Object.assign(Object.assign({}, backend.empty()), { environmentVariables: envs });
69
- for (const annotation of triggerAnnotations) {
70
- addResourcesToBackend(projectId, runtime, annotation, want);
71
- }
72
- return want;
73
- }
74
- exports.discoverBackend = discoverBackend;
75
- function mergeRequiredAPIs(backend) {
76
- const apiToReasons = {};
77
- for (const { api, reason } of backend.requiredAPIs) {
78
- const reasons = apiToReasons[api] || new Set();
79
- if (reason) {
80
- reasons.add(reason);
81
- }
82
- apiToReasons[api] = reasons;
83
- }
84
- const merged = [];
85
- for (const [api, reasons] of Object.entries(apiToReasons)) {
86
- merged.push({ api, reason: Array.from(reasons).join(" ") });
87
- }
88
- backend.requiredAPIs = merged;
89
- }
90
- exports.mergeRequiredAPIs = mergeRequiredAPIs;
91
- function addResourcesToBuild(projectId, runtime, annotation, want) {
92
- var _a, _b;
93
- Object.freeze(annotation);
94
- const toSeconds = (0, functional_1.nullsafeVisitor)(proto.secondsFromDuration);
95
- const regions = annotation.regions || [api.functionsDefaultRegion()];
96
- let triggered;
97
- const triggerCount = +!!annotation.httpsTrigger +
98
- +!!annotation.eventTrigger +
99
- +!!annotation.taskQueueTrigger +
100
- +!!annotation.blockingTrigger;
101
- if (triggerCount !== 1) {
102
- throw new error_1.FirebaseError("Unexpected annotation generated by the Firebase Functions SDK. This should never happen.");
103
- }
104
- if (annotation.taskQueueTrigger) {
105
- want.requiredAPIs.push({
106
- api: "cloudtasks.googleapis.com",
107
- reason: "Needed for task queue functions.",
108
- });
109
- triggered = {
110
- taskQueueTrigger: {},
111
- };
112
- proto.copyIfPresent(triggered.taskQueueTrigger, annotation.taskQueueTrigger, "invoker");
113
- proto.copyIfPresent(triggered.taskQueueTrigger, annotation.taskQueueTrigger, "rateLimits");
114
- if (annotation.taskQueueTrigger.retryConfig) {
115
- triggered.taskQueueTrigger.retryConfig = {};
116
- proto.copyIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxAttempts", "maxDoublings");
117
- proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "minBackoffSeconds", "minBackoff", toSeconds);
118
- proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxBackoffSeconds", "maxBackoff", toSeconds);
119
- proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxRetrySeconds", "maxRetryDuration", toSeconds);
120
- }
121
- }
122
- else if (annotation.httpsTrigger) {
123
- if ((_a = annotation.labels) === null || _a === void 0 ? void 0 : _a["deployment-callable"]) {
124
- delete annotation.labels["deployment-callable"];
125
- triggered = { callableTrigger: {} };
126
- }
127
- else {
128
- const trigger = {};
129
- if (annotation.failurePolicy) {
130
- logger_1.logger.warn(`Ignoring retry policy for HTTPS function ${annotation.name}`);
131
- }
132
- if (annotation.httpsTrigger.invoker) {
133
- trigger.invoker = annotation.httpsTrigger.invoker;
134
- }
135
- triggered = { httpsTrigger: trigger };
136
- }
137
- }
138
- else if (annotation.schedule) {
139
- want.requiredAPIs.push({
140
- api: "cloudscheduler.googleapis.com",
141
- reason: "Needed for scheduled functions.",
142
- });
143
- triggered = {
144
- scheduleTrigger: {
145
- schedule: annotation.schedule.schedule,
146
- timeZone: (_b = annotation.schedule.timeZone) !== null && _b !== void 0 ? _b : null,
147
- retryConfig: {},
148
- },
149
- };
150
- if (annotation.schedule.retryConfig) {
151
- triggered.scheduleTrigger.retryConfig = {};
152
- proto.copyIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "retryCount", "maxDoublings");
153
- proto.convertIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "maxRetrySeconds", "maxRetryDuration", toSeconds);
154
- proto.convertIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "minBackoffSeconds", "minBackoffDuration", toSeconds);
155
- proto.convertIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "maxBackoffSeconds", "maxBackoffDuration", toSeconds);
156
- }
157
- }
158
- else if (annotation.blockingTrigger) {
159
- if (events.v1.AUTH_BLOCKING_EVENTS.includes(annotation.blockingTrigger.eventType)) {
160
- want.requiredAPIs.push({
161
- api: "identitytoolkit.googleapis.com",
162
- reason: "Needed for auth blocking functions.",
163
- });
164
- }
165
- triggered = {
166
- blockingTrigger: {
167
- eventType: annotation.blockingTrigger.eventType,
168
- },
169
- };
170
- }
171
- else if (annotation.eventTrigger) {
172
- triggered = {
173
- eventTrigger: {
174
- eventType: annotation.eventTrigger.eventType,
175
- eventFilters: { resource: annotation.eventTrigger.resource },
176
- retry: !!annotation.failurePolicy,
177
- },
178
- };
179
- }
180
- else {
181
- throw new error_1.FirebaseError("Do not understand Cloud Function annotation without a trigger" +
182
- JSON.stringify(annotation, null, 2));
183
- }
184
- const endpointId = annotation.name;
185
- const endpoint = Object.assign({ platform: annotation.platform || "gcfv1", region: regions, project: projectId, entryPoint: annotation.entryPoint, runtime: runtime }, triggered);
186
- proto.renameIfPresent(endpoint, annotation, "serviceAccount", "serviceAccountEmail");
187
- if (annotation.vpcConnector != null) {
188
- endpoint.vpc = { connector: annotation.vpcConnector };
189
- proto.renameIfPresent(endpoint.vpc, annotation, "egressSettings", "vpcConnectorEgressSettings");
190
- }
191
- proto.copyIfPresent(endpoint, annotation, "concurrency", "labels", "maxInstances", "minInstances", "availableMemoryMb");
192
- proto.convertIfPresent(endpoint, annotation, "ingressSettings", (str) => {
193
- if (str === null) {
194
- return null;
195
- }
196
- if (!backend.AllIngressSettings.includes(str)) {
197
- throw new Error(`Invalid ingress setting ${str}`);
198
- }
199
- return str;
200
- });
201
- proto.convertIfPresent(endpoint, annotation, "timeoutSeconds", "timeout", proto.secondsFromDuration);
202
- if (annotation.secrets) {
203
- endpoint.secretEnvironmentVariables = annotation.secrets.map((secret) => {
204
- return {
205
- secret,
206
- projectId,
207
- key: secret,
208
- };
209
- });
210
- }
211
- want.endpoints[endpointId] = endpoint;
212
- }
213
- exports.addResourcesToBuild = addResourcesToBuild;
214
- function addResourcesToBackend(projectId, runtime, annotation, want) {
215
- var _a;
216
- Object.freeze(annotation);
217
- for (const region of annotation.regions || [api.functionsDefaultRegion()]) {
218
- let triggered;
219
- const triggerCount = +!!annotation.httpsTrigger +
220
- +!!annotation.eventTrigger +
221
- +!!annotation.taskQueueTrigger +
222
- +!!annotation.blockingTrigger;
223
- if (triggerCount !== 1) {
224
- throw new error_1.FirebaseError("Unexpected annotation generated by the Firebase Functions SDK. This should never happen.");
225
- }
226
- if (annotation.taskQueueTrigger) {
227
- triggered = { taskQueueTrigger: annotation.taskQueueTrigger };
228
- want.requiredAPIs.push({
229
- api: "cloudtasks.googleapis.com",
230
- reason: "Needed for task queue functions.",
231
- });
232
- }
233
- else if (annotation.httpsTrigger) {
234
- if ((_a = annotation.labels) === null || _a === void 0 ? void 0 : _a["deployment-callable"]) {
235
- delete annotation.labels["deployment-callable"];
236
- triggered = { callableTrigger: {} };
237
- }
238
- else {
239
- const trigger = {};
240
- if (annotation.failurePolicy) {
241
- logger_1.logger.warn(`Ignoring retry policy for HTTPS function ${annotation.name}`);
242
- }
243
- proto.copyIfPresent(trigger, annotation.httpsTrigger, "invoker");
244
- triggered = { httpsTrigger: trigger };
245
- }
246
- }
247
- else if (annotation.schedule) {
248
- want.requiredAPIs.push({
249
- api: "cloudscheduler.googleapis.com",
250
- reason: "Needed for scheduled functions.",
251
- });
252
- triggered = { scheduleTrigger: annotation.schedule };
253
- }
254
- else if (annotation.blockingTrigger) {
255
- if (events.v1.AUTH_BLOCKING_EVENTS.includes(annotation.blockingTrigger.eventType)) {
256
- want.requiredAPIs.push({
257
- api: "identitytoolkit.googleapis.com",
258
- reason: "Needed for auth blocking functions.",
259
- });
260
- }
261
- triggered = {
262
- blockingTrigger: {
263
- eventType: annotation.blockingTrigger.eventType,
264
- options: annotation.blockingTrigger.options,
265
- },
266
- };
267
- }
268
- else {
269
- triggered = {
270
- eventTrigger: {
271
- eventType: annotation.eventTrigger.eventType,
272
- eventFilters: { resource: annotation.eventTrigger.resource },
273
- retry: !!annotation.failurePolicy,
274
- },
275
- };
276
- if (annotation.platform === "gcfv2") {
277
- if (annotation.eventTrigger.eventType === events.v2.PUBSUB_PUBLISH_EVENT) {
278
- triggered.eventTrigger.eventFilters = { topic: annotation.eventTrigger.resource };
279
- }
280
- if (events.v2.STORAGE_EVENTS.find((event) => { var _a; return event === (((_a = annotation.eventTrigger) === null || _a === void 0 ? void 0 : _a.eventType) || ""); })) {
281
- triggered.eventTrigger.eventFilters = { bucket: annotation.eventTrigger.resource };
282
- }
283
- }
284
- }
285
- const endpoint = Object.assign({ platform: annotation.platform || "gcfv1", id: annotation.name, region: region, project: projectId, entryPoint: annotation.entryPoint, runtime: runtime }, triggered);
286
- if (annotation.vpcConnector != null) {
287
- let maybeId = annotation.vpcConnector;
288
- if (maybeId && !maybeId.includes("/")) {
289
- maybeId = `projects/${projectId}/locations/${region}/connectors/${maybeId}`;
290
- }
291
- endpoint.vpc = { connector: maybeId };
292
- proto.renameIfPresent(endpoint.vpc, annotation, "egressSettings", "vpcConnectorEgressSettings");
293
- }
294
- if (annotation.secrets) {
295
- const secretEnvs = [];
296
- for (const secret of annotation.secrets) {
297
- const secretEnv = {
298
- secret,
299
- projectId,
300
- key: secret,
301
- };
302
- secretEnvs.push(secretEnv);
303
- }
304
- endpoint.secretEnvironmentVariables = secretEnvs;
305
- }
306
- proto.copyIfPresent(endpoint, annotation, "concurrency", "labels", "maxInstances", "minInstances");
307
- proto.renameIfPresent(endpoint, annotation, "serviceAccount", "serviceAccountEmail");
308
- proto.convertIfPresent(endpoint, annotation, "ingressSettings", (ingress) => {
309
- if (ingress == null) {
310
- return null;
311
- }
312
- if (!backend.AllIngressSettings.includes(ingress)) {
313
- throw new error_1.FirebaseError(`Invalid ingress setting ${ingress}`);
314
- }
315
- return ingress;
316
- });
317
- proto.convertIfPresent(endpoint, annotation, "availableMemoryMb", (mem) => {
318
- if (mem === null) {
319
- return null;
320
- }
321
- if (!backend.isValidMemoryOption(mem)) {
322
- throw new error_1.FirebaseError(`This version of firebase-tools does not know about the memory option ${mem}. Is an upgrade necessary?`);
323
- }
324
- return mem;
325
- });
326
- proto.convertIfPresent(endpoint, annotation, "timeoutSeconds", "timeout", proto.secondsFromDuration);
327
- want.endpoints[region] = want.endpoints[region] || {};
328
- want.endpoints[region][endpoint.id] = endpoint;
329
- mergeRequiredAPIs(want);
330
- }
331
- }
332
- exports.addResourcesToBackend = addResourcesToBackend;