firebase-tools 12.4.6 → 12.4.8

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.
@@ -642,22 +642,23 @@ async function main() {
642
642
  }
643
643
  const app = express();
644
644
  app.enable("trust proxy");
645
+ const bodyParserLimit = "32mb";
645
646
  app.use(bodyParser.json({
646
- limit: "10mb",
647
+ limit: bodyParserLimit,
647
648
  verify: rawBodySaver,
648
649
  }));
649
650
  app.use(bodyParser.text({
650
- limit: "10mb",
651
+ limit: bodyParserLimit,
651
652
  verify: rawBodySaver,
652
653
  }));
653
654
  app.use(bodyParser.urlencoded({
654
655
  extended: true,
655
- limit: "10mb",
656
+ limit: bodyParserLimit,
656
657
  verify: rawBodySaver,
657
658
  }));
658
659
  app.use(bodyParser.raw({
659
660
  type: "*/*",
660
- limit: "10mb",
661
+ limit: bodyParserLimit,
661
662
  verify: rawBodySaver,
662
663
  }));
663
664
  app.get("/__/health", (req, res) => {
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FunctionsEmulatorShell = void 0;
4
4
  const uuid = require("uuid");
5
- const functionsEmulator_1 = require("./functionsEmulator");
6
5
  const utils = require("../utils");
6
+ const functionsEmulator_1 = require("./functionsEmulator");
7
7
  const logger_1 = require("../logger");
8
8
  const error_1 = require("../error");
9
9
  class FunctionsEmulatorShell {
@@ -20,37 +20,69 @@ class FunctionsEmulatorShell {
20
20
  }
21
21
  }
22
22
  }
23
- call(name, data, opts) {
24
- const trigger = this.getTrigger(name);
25
- logger_1.logger.debug(`shell:${name}: trigger=${JSON.stringify(trigger)}`);
26
- logger_1.logger.debug(`shell:${name}: opts=${JSON.stringify(opts)}, data=${JSON.stringify(data)}`);
27
- if (!trigger.eventTrigger) {
28
- throw new error_1.FirebaseError(`Function ${name} is not a background function`);
29
- }
30
- const eventType = trigger.eventTrigger.eventType;
23
+ createLegacyEvent(eventTrigger, data, opts) {
24
+ var _a, _b;
31
25
  let resource = opts.resource;
32
26
  if (typeof resource === "object" && resource.name) {
33
27
  resource = resource.name;
34
28
  }
35
- const proto = {
29
+ return {
36
30
  eventId: uuid.v4(),
37
31
  timestamp: new Date().toISOString(),
38
- eventType,
39
- resource,
32
+ eventType: eventTrigger.eventType,
33
+ resource: resource,
40
34
  params: opts.params,
41
- auth: opts.auth,
35
+ auth: { admin: ((_a = opts.auth) === null || _a === void 0 ? void 0 : _a.admin) || false, variable: (_b = opts.auth) === null || _b === void 0 ? void 0 : _b.variable },
42
36
  data,
43
37
  };
44
- this.emu.sendRequest(trigger, proto);
45
38
  }
46
- getTrigger(name) {
47
- const result = this.triggers.find((trigger) => {
48
- return trigger.name === name;
49
- });
50
- if (!result) {
51
- throw new error_1.FirebaseError(`Could not find trigger ${name}`);
52
- }
53
- return result;
39
+ createCloudEvent(eventTrigger, data, opts) {
40
+ var _a, _b;
41
+ const ce = {
42
+ specversion: "1.0",
43
+ datacontenttype: "application/json",
44
+ id: uuid.v4(),
45
+ type: eventTrigger.eventType,
46
+ time: new Date().toISOString(),
47
+ source: "",
48
+ data,
49
+ };
50
+ if (eventTrigger.eventType.startsWith("google.cloud.storage")) {
51
+ ce.source = `projects/_/buckets/${(_a = eventTrigger.eventFilters) === null || _a === void 0 ? void 0 : _a.bucket}`;
52
+ }
53
+ else if (eventTrigger.eventType.startsWith("google.cloud.pubsub")) {
54
+ ce.source = eventTrigger.eventFilters.topic;
55
+ data = Object.assign(Object.assign({}, data), { messageId: uuid.v4() });
56
+ }
57
+ else if (eventTrigger.eventType.startsWith("google.cloud.firestore")) {
58
+ ce.source = `projects/_/databases/(default)`;
59
+ if (opts.resource) {
60
+ ce.document = opts.resource;
61
+ }
62
+ }
63
+ else if (eventTrigger.eventType.startsWith("google.firebase.database")) {
64
+ ce.source = `projects/_/locations/_/instances/${(_b = eventTrigger.eventFilterPathPatterns) === null || _b === void 0 ? void 0 : _b.instance}`;
65
+ if (opts.resource) {
66
+ ce.ref = opts.resource;
67
+ }
68
+ }
69
+ return ce;
70
+ }
71
+ call(trigger, data, opts) {
72
+ logger_1.logger.debug(`shell:${trigger.name}: trigger=${JSON.stringify(trigger)}`);
73
+ logger_1.logger.debug(`shell:${trigger.name}: opts=${JSON.stringify(opts)}, data=${JSON.stringify(data)}`);
74
+ const eventTrigger = trigger.eventTrigger;
75
+ if (!eventTrigger) {
76
+ throw new error_1.FirebaseError(`Function ${trigger.name} is not a background function`);
77
+ }
78
+ let body;
79
+ if (trigger.platform === "gcfv1") {
80
+ body = this.createLegacyEvent(eventTrigger, data, opts);
81
+ }
82
+ else {
83
+ body = this.createCloudEvent(eventTrigger, data, opts);
84
+ }
85
+ this.emu.sendRequest(trigger, body);
54
86
  }
55
87
  }
56
88
  exports.FunctionsEmulatorShell = FunctionsEmulatorShell;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isSystemParam = exports.readEnvFile = exports.promptForNewParams = exports.getParamsForUpdate = exports.getParams = exports.getParamsWithCurrentValuesAsDefaults = exports.setNewDefaults = exports.buildBindingOptionsWithBaseValue = exports.getBaseParamBindings = void 0;
3
+ exports.isSystemParam = exports.readEnvFile = exports.promptForNewParams = exports.getParamsForUpdate = exports.getParams = exports.setNewDefaults = exports.buildBindingOptionsWithBaseValue = exports.getBaseParamBindings = void 0;
4
4
  const path = require("path");
5
5
  const clc = require("colorette");
6
6
  const fs = require("fs-extra");
@@ -9,7 +9,6 @@ const logger_1 = require("../logger");
9
9
  const extensionsHelper_1 = require("./extensionsHelper");
10
10
  const askUserForParam = require("./askUserForParam");
11
11
  const env = require("../functions/env");
12
- const utils_1 = require("../utils");
13
12
  const NONINTERACTIVE_ERROR_MESSAGE = "As of firebase-tools@11, `ext:install`, `ext:update` and `ext:configure` are interactive only commands. " +
14
13
  "To deploy an extension noninteractively, use an extensions manifest and `firebase deploy --only extensions`. " +
15
14
  "See https://firebase.google.com/docs/extensions/manifest for more details";
@@ -30,21 +29,17 @@ function buildBindingOptionsWithBaseValue(baseParams) {
30
29
  }
31
30
  exports.buildBindingOptionsWithBaseValue = buildBindingOptionsWithBaseValue;
32
31
  function setNewDefaults(params, newDefaults) {
33
- params.forEach((param) => {
34
- if (newDefaults[param.param.toUpperCase()]) {
35
- param.default = newDefaults[param.param.toUpperCase()];
32
+ for (const param of params) {
33
+ if (newDefaults[param.param]) {
34
+ param.default = newDefaults[param.param];
36
35
  }
37
- });
36
+ else if ((param.param = `firebaseextensions.v1beta.function/location` && newDefaults["LOCATION"])) {
37
+ param.default = newDefaults["LOCATION"];
38
+ }
39
+ }
38
40
  return params;
39
41
  }
40
42
  exports.setNewDefaults = setNewDefaults;
41
- function getParamsWithCurrentValuesAsDefaults(extensionInstance) {
42
- var _a, _b, _c, _d;
43
- const specParams = (0, utils_1.cloneDeep)(((_c = (_b = (_a = extensionInstance === null || extensionInstance === void 0 ? void 0 : extensionInstance.config) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.spec) === null || _c === void 0 ? void 0 : _c.params) || []);
44
- const currentParams = (0, utils_1.cloneDeep)(((_d = extensionInstance === null || extensionInstance === void 0 ? void 0 : extensionInstance.config) === null || _d === void 0 ? void 0 : _d.params) || {});
45
- return setNewDefaults(specParams, currentParams);
46
- }
47
- exports.getParamsWithCurrentValuesAsDefaults = getParamsWithCurrentValuesAsDefaults;
48
43
  async function getParams(args) {
49
44
  let params;
50
45
  if (args.nonInteractive) {
@@ -81,6 +76,7 @@ async function getParamsForUpdate(args) {
81
76
  }
82
77
  exports.getParamsForUpdate = getParamsForUpdate;
83
78
  async function promptForNewParams(args) {
79
+ var _a, _b;
84
80
  const newParamBindingOptions = buildBindingOptionsWithBaseValue(args.currentParams);
85
81
  const firebaseProjectParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
86
82
  const sameParam = (param1) => (param2) => {
@@ -89,10 +85,22 @@ async function promptForNewParams(args) {
89
85
  const paramDiff = (left, right) => {
90
86
  return left.filter((aLeft) => !right.find(sameParam(aLeft)));
91
87
  };
92
- const oldParams = args.spec.params.filter((p) => Object.keys(args.currentParams).includes(p.param));
93
- let paramsDiffDeletions = paramDiff(oldParams, args.newSpec.params);
88
+ let combinedOldParams = args.spec.params.concat((_a = args.spec.systemParams.filter((p) => !p.advanced)) !== null && _a !== void 0 ? _a : []);
89
+ let combinedNewParams = args.newSpec.params.concat((_b = args.newSpec.systemParams.filter((p) => !p.advanced)) !== null && _b !== void 0 ? _b : []);
90
+ if (combinedOldParams.some((p) => p.param === "LOCATION") &&
91
+ combinedNewParams.some((p) => p.param === "firebaseextensions.v1beta.function/location") &&
92
+ !!args.currentParams["LOCATION"]) {
93
+ newParamBindingOptions["firebaseextensions.v1beta.function/location"] = {
94
+ baseValue: args.currentParams["LOCATION"],
95
+ };
96
+ delete newParamBindingOptions["LOCATION"];
97
+ combinedOldParams = combinedOldParams.filter((p) => p.param !== "LOCATION");
98
+ combinedNewParams = combinedNewParams.filter((p) => p.param !== "firebaseextensions.v1beta.function/location");
99
+ }
100
+ const oldParams = combinedOldParams.filter((p) => Object.keys(args.currentParams).includes(p.param));
101
+ let paramsDiffDeletions = paramDiff(oldParams, combinedNewParams);
94
102
  paramsDiffDeletions = (0, extensionsHelper_1.substituteParams)(paramsDiffDeletions, firebaseProjectParams);
95
- let paramsDiffAdditions = paramDiff(args.newSpec.params, oldParams);
103
+ let paramsDiffAdditions = paramDiff(combinedNewParams, oldParams);
96
104
  paramsDiffAdditions = (0, extensionsHelper_1.substituteParams)(paramsDiffAdditions, firebaseProjectParams);
97
105
  if (paramsDiffDeletions.length) {
98
106
  logger_1.logger.info("The following params will no longer be used:");
@@ -10,14 +10,10 @@ const utils_2 = require("./utils");
10
10
  exports.name = "Astro";
11
11
  exports.support = "experimental";
12
12
  exports.type = 2;
13
- function getAstroVersion(cwd) {
14
- var _a;
15
- return (_a = (0, utils_1.findDependency)("astro", { cwd, depth: 0, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
16
- }
17
13
  async function discover(dir) {
18
14
  if (!(0, fs_extra_1.existsSync)((0, path_1.join)(dir, "package.json")))
19
15
  return;
20
- if (!getAstroVersion(dir))
16
+ if (!(0, utils_2.getAstroVersion)(dir))
21
17
  return;
22
18
  const { output, publicDir: publicDirectory } = await (0, utils_2.getConfig)(dir);
23
19
  return {
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getConfig = exports.getBootstrapScript = void 0;
3
+ exports.getAstroVersion = exports.getConfig = exports.getBootstrapScript = void 0;
4
4
  const path_1 = require("path");
5
+ const utils_1 = require("../utils");
6
+ const semver_1 = require("semver");
5
7
  const { dynamicImport } = require(true && "../../dynamicImport");
6
8
  function getBootstrapScript() {
7
9
  return `const entry = import('./entry.mjs');\nexport const handle = async (req, res) => (await entry).handler(req, res)`;
@@ -9,9 +11,20 @@ function getBootstrapScript() {
9
11
  exports.getBootstrapScript = getBootstrapScript;
10
12
  async function getConfig(cwd) {
11
13
  const astroDirectory = (0, path_1.dirname)(require.resolve("astro/package.json", { paths: [cwd] }));
12
- const { openConfig } = await dynamicImport((0, path_1.join)(astroDirectory, "dist", "core", "config", "config.js"));
13
- const logging = undefined;
14
- const { astroConfig: config } = await openConfig({ cmd: "build", cwd, logging });
14
+ const version = getAstroVersion(cwd);
15
+ let config;
16
+ const configPath = (0, path_1.join)(astroDirectory, "dist", "core", "config", "config.js");
17
+ if ((0, semver_1.gte)(version, "2.9.7")) {
18
+ const { resolveConfig } = await dynamicImport(configPath);
19
+ const { astroConfig } = await resolveConfig({ root: cwd }, "build");
20
+ config = astroConfig;
21
+ }
22
+ else {
23
+ const { openConfig } = await dynamicImport(configPath);
24
+ const logging = undefined;
25
+ const { astroConfig } = await openConfig({ cmd: "build", cwd, logging });
26
+ config = astroConfig;
27
+ }
15
28
  return {
16
29
  outDir: (0, path_1.relative)(cwd, config.outDir.pathname),
17
30
  publicDir: (0, path_1.relative)(cwd, config.publicDir.pathname),
@@ -20,3 +33,8 @@ async function getConfig(cwd) {
20
33
  };
21
34
  }
22
35
  exports.getConfig = getConfig;
36
+ function getAstroVersion(cwd) {
37
+ var _a;
38
+ return (_a = (0, utils_1.findDependency)("astro", { cwd, depth: 0, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
39
+ }
40
+ exports.getAstroVersion = getAstroVersion;
@@ -29,6 +29,7 @@ exports.name = "Next.js";
29
29
  exports.support = "preview";
30
30
  exports.type = 2;
31
31
  exports.docsUrl = "https://firebase.google.com/docs/hosting/frameworks/nextjs";
32
+ const BUNDLE_NEXT_CONFIG_TIMEOUT = 60000;
32
33
  const DEFAULT_NUMBER_OF_REASONS_TO_LIST = 5;
33
34
  function getReactVersion(cwd) {
34
35
  var _a;
@@ -297,7 +298,6 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
297
298
  }));
298
299
  }
299
300
  exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
300
- const BUNDLE_NEXT_CONFIG_TIMEOUT = 10000;
301
301
  async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
302
302
  const { distDir } = await getConfig(sourceDir);
303
303
  const packageJson = await (0, utils_1.readJSON)((0, path_1.join)(sourceDir, "package.json"));
@@ -144,14 +144,13 @@ function getNpmRoot(cwd) {
144
144
  }
145
145
  exports.getNpmRoot = getNpmRoot;
146
146
  function getNodeModuleBin(name, cwd) {
147
- const cantFindExecutable = new error_1.FirebaseError(`Could not find the ${name} executable.`);
148
147
  const npmRoot = getNpmRoot(cwd);
149
148
  if (!npmRoot) {
150
- throw cantFindExecutable;
149
+ throw new error_1.FirebaseError(`Error finding ${name} executable: failed to spawn 'npm'`);
151
150
  }
152
151
  const path = (0, path_1.join)(npmRoot, ".bin", name);
153
152
  if (!(0, fsutils_1.fileExistsSync)(path)) {
154
- throw cantFindExecutable;
153
+ throw new error_1.FirebaseError(`Could not find the ${name} executable.`);
155
154
  }
156
155
  return path;
157
156
  }
@@ -44,7 +44,7 @@ function toUpperSnakeCase(key) {
44
44
  }
45
45
  function ensureApi(options) {
46
46
  const projectId = (0, projectUtils_1.needProjectId)(options);
47
- return ensureApiEnabled.ensure(projectId, "secretmanager.googleapis.com", "runtimeconfig", true);
47
+ return ensureApiEnabled.ensure(projectId, "secretmanager.googleapis.com", "secretmanager", true);
48
48
  }
49
49
  exports.ensureApi = ensureApi;
50
50
  async function ensureValidKey(key, options) {
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createBuild = exports.createStack = exports.API_VERSION = void 0;
3
+ exports.createBuild = exports.getStack = exports.createStack = exports.API_VERSION = void 0;
4
4
  const apiv2_1 = require("../apiv2");
5
5
  const api_1 = require("../api");
6
- exports.API_VERSION = "v2";
6
+ exports.API_VERSION = "v1alpha";
7
7
  const client = new apiv2_1.Client({
8
8
  urlPrefix: api_1.frameworksOrigin,
9
9
  auth: true,
@@ -15,6 +15,12 @@ async function createStack(projectId, location, stackInput) {
15
15
  return res.body;
16
16
  }
17
17
  exports.createStack = createStack;
18
+ async function getStack(projectId, location, stackId) {
19
+ const name = `projects/${projectId}/locations/${location}/stacks/${stackId}`;
20
+ const res = await client.get(name);
21
+ return res.body;
22
+ }
23
+ exports.getStack = getStack;
18
24
  async function createBuild(projectId, location, stackId, buildInput) {
19
25
  const buildId = buildInput.name;
20
26
  const res = await client.post(`projects/${projectId}/locations/${location}/stacks/${stackId}/builds`, buildInput, { queryParams: { buildId } });
package/lib/gcp/iam.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.testIamPermissions = exports.testResourceIamPermissions = exports.getRole = exports.deleteServiceAccount = exports.createServiceAccountKey = exports.getServiceAccount = exports.createServiceAccount = void 0;
3
+ exports.testIamPermissions = exports.testResourceIamPermissions = exports.getRole = exports.listServiceAccountKeys = exports.deleteServiceAccount = exports.createServiceAccountKey = exports.getServiceAccount = exports.createServiceAccount = void 0;
4
4
  const api_1 = require("../api");
5
5
  const logger_1 = require("../logger");
6
6
  const apiv2_1 = require("../apiv2");
@@ -35,6 +35,11 @@ async function deleteServiceAccount(projectId, accountEmail) {
35
35
  });
36
36
  }
37
37
  exports.deleteServiceAccount = deleteServiceAccount;
38
+ async function listServiceAccountKeys(projectId, serviceAccountName) {
39
+ const response = await apiClient.get(`/projects/${projectId}/serviceAccounts/${serviceAccountName}@${projectId}.iam.gserviceaccount.com/keys`);
40
+ return response.body.keys;
41
+ }
42
+ exports.listServiceAccountKeys = listServiceAccountKeys;
38
43
  async function getRole(role) {
39
44
  const response = await apiClient.get(`/roles/${role}`, {
40
45
  retryCodes: [500, 503],
@@ -1,16 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createStack = exports.doSetup = void 0;
3
+ exports.createStack = exports.getOrCreateStack = exports.doSetup = void 0;
4
4
  const clc = require("colorette");
5
5
  const utils = require("../../../utils");
6
6
  const logger_1 = require("../../../logger");
7
7
  const prompt_1 = require("../../../prompt");
8
8
  const constants_1 = require("./constants");
9
- const repo_1 = require("./repo");
9
+ const repo = require("./repo");
10
10
  const poller = require("../../../operation-poller");
11
11
  const api_1 = require("../../../api");
12
12
  const gcp = require("../../../gcp/frameworks");
13
13
  const frameworks_1 = require("../../../gcp/frameworks");
14
+ const error_1 = require("../../../error");
14
15
  const frameworksPollerOptions = {
15
16
  apiOrigin: api_1.frameworksOrigin,
16
17
  apiVersion: frameworks_1.API_VERSION,
@@ -26,7 +27,7 @@ async function doSetup(setup) {
26
27
  name: "serviceName",
27
28
  type: "input",
28
29
  default: "acme-inc-web",
29
- message: "Create a name for your service [6-32 characters]",
30
+ message: "Create a name for your service [1-30 characters]",
30
31
  }, setup.frameworks);
31
32
  await (0, prompt_1.promptOnce)({
32
33
  name: "region",
@@ -45,19 +46,62 @@ async function doSetup(setup) {
45
46
  message: "How do you want to deploy",
46
47
  choices: constants_1.ALLOWED_DEPLOY_METHODS,
47
48
  }, setup.frameworks);
48
- if (setup.frameworks.deployMethod === "github") {
49
- const cloudBuildConnRepo = await (0, repo_1.linkGitHubRepository)(projectId, setup.frameworks.region, setup.frameworks.serviceName);
50
- toStack(cloudBuildConnRepo, setup.frameworks.serviceName);
51
- }
49
+ await getOrCreateStack(projectId, setup);
52
50
  }
53
51
  exports.doSetup = doSetup;
54
52
  function toStack(cloudBuildConnRepo, stackId) {
55
53
  return {
56
54
  name: stackId,
57
- codebase: { repository: cloudBuildConnRepo.name, rootDirectory: "/" },
58
55
  labels: {},
59
56
  };
60
57
  }
58
+ async function getOrCreateStack(projectId, setup) {
59
+ const location = setup.frameworks.region;
60
+ const deployMethod = setup.frameworks.deployMethod;
61
+ try {
62
+ return await getExistingStack(projectId, setup, location);
63
+ }
64
+ catch (err) {
65
+ if (err.status === 404) {
66
+ logger_1.logger.info("Creating new stack.");
67
+ if (deployMethod === "github") {
68
+ const cloudBuildConnRepo = await repo.linkGitHubRepository(projectId, location, setup.frameworks.serviceName);
69
+ const stackDetails = toStack(cloudBuildConnRepo, setup.frameworks.serviceName);
70
+ return await createStack(projectId, location, stackDetails);
71
+ }
72
+ }
73
+ else {
74
+ throw new error_1.FirebaseError(`Failed to get or create a stack using the given initialization details: ${err}`);
75
+ }
76
+ }
77
+ return undefined;
78
+ }
79
+ exports.getOrCreateStack = getOrCreateStack;
80
+ async function getExistingStack(projectId, setup, location) {
81
+ let stack = await gcp.getStack(projectId, location, setup.frameworks.serviceName);
82
+ while (stack) {
83
+ setup.frameworks.serviceName = undefined;
84
+ await (0, prompt_1.promptOnce)({
85
+ name: "existingStack",
86
+ type: "confirm",
87
+ default: true,
88
+ message: "A stack already exists for the given serviceName, do you want to use existing stack? (yes/no)",
89
+ }, setup.frameworks);
90
+ if (setup.frameworks.existingStack) {
91
+ logger_1.logger.info("Using the existing stack.");
92
+ return stack;
93
+ }
94
+ await (0, prompt_1.promptOnce)({
95
+ name: "serviceName",
96
+ type: "input",
97
+ default: "acme-inc-web",
98
+ message: "Please enter a new service name [1-30 characters]",
99
+ }, setup.frameworks);
100
+ stack = await gcp.getStack(projectId, location, setup.frameworks.serviceName);
101
+ setup.frameworks.existingStack = undefined;
102
+ }
103
+ return stack;
104
+ }
61
105
  async function createStack(projectId, location, stackInput) {
62
106
  const op = await gcp.createStack(projectId, location, stackInput);
63
107
  const stack = await poller.pollOperation(Object.assign(Object.assign({}, frameworksPollerOptions), { pollerName: `create-${projectId}-${location}-${stackInput.name}`, operationResourceName: op.name }));
@@ -32,7 +32,7 @@ async function linkGitHubRepository(projectId, location, stackId) {
32
32
  await utils.openInBrowser("https://github.com/apps/google-cloud-build/installations/new");
33
33
  await (0, prompt_1.promptOnce)({
34
34
  type: "input",
35
- message: "Press any key once you have finished configuring your installation's access settings.",
35
+ message: "Press ENTER once you have finished configuring your installation's access settings.",
36
36
  });
37
37
  remoteUri = await promptRepositoryURI(projectId, location, connectionId);
38
38
  }
@@ -17,6 +17,7 @@ const prompt_1 = require("../../../prompt");
17
17
  const utils_1 = require("../../../utils");
18
18
  const api_1 = require("../../../api");
19
19
  const apiv2_1 = require("../../../apiv2");
20
+ const error_1 = require("../../../error");
20
21
  let GIT_DIR;
21
22
  let GITHUB_DIR;
22
23
  let WORKFLOW_DIR;
@@ -26,6 +27,7 @@ const YML_PULL_REQUEST_FILENAME = "firebase-hosting-pull-request.yml";
26
27
  const YML_MERGE_FILENAME = "firebase-hosting-merge.yml";
27
28
  const CHECKOUT_GITHUB_ACTION_NAME = "actions/checkout@v3";
28
29
  const HOSTING_GITHUB_ACTION_NAME = "FirebaseExtended/action-hosting-deploy@v0";
30
+ const SERVICE_ACCOUNT_MAX_KEY_NUMBER = 10;
29
31
  const githubApiClient = new apiv2_1.Client({ urlPrefix: api_1.githubApiOrigin, auth: false });
30
32
  async function initGitHub(setup) {
31
33
  if (!setup.projectId) {
@@ -344,6 +346,13 @@ async function createServiceAccountAndKeyWithRetry(options, repo, accountId) {
344
346
  catch (e) {
345
347
  spinnerServiceAccount.stop();
346
348
  if (!e.message.includes("429")) {
349
+ const serviceAccountKeys = await (0, iam_1.listServiceAccountKeys)(options.projectId, accountId);
350
+ if (serviceAccountKeys.length >= SERVICE_ACCOUNT_MAX_KEY_NUMBER) {
351
+ throw new error_1.FirebaseError(`You cannot add another key because the service account ${(0, colorette_1.bold)(accountId)} already contains the max number of keys: ${SERVICE_ACCOUNT_MAX_KEY_NUMBER}.`, {
352
+ original: e,
353
+ exit: 1,
354
+ });
355
+ }
347
356
  throw e;
348
357
  }
349
358
  spinnerServiceAccount.start();
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const uuid = require("uuid");
3
4
  const request = require("request");
4
- const utils = require("./utils");
5
5
  const encodeFirestoreValue_1 = require("./firestore/encodeFirestoreValue");
6
+ const utils = require("./utils");
6
7
  class LocalFunction {
7
8
  constructor(trigger, urls, controller) {
8
9
  this.trigger = trigger;
@@ -17,7 +18,7 @@ class LocalFunction {
17
18
  return resource.replace(this.paramWildcardRegex, (wildcard) => {
18
19
  const wildcardNoBraces = wildcard.slice(1, -1);
19
20
  const sub = params === null || params === void 0 ? void 0 : params[wildcardNoBraces];
20
- return sub || `${wildcardNoBraces}${utils.randomInt(1, 9)}`;
21
+ return sub || wildcardNoBraces + utils.randomInt(1, 9);
21
22
  });
22
23
  }
23
24
  constructCallableFunc(data, opts) {
@@ -118,24 +119,30 @@ class LocalFunction {
118
119
  isFirestoreFunc(eventTrigger) {
119
120
  return utils.getFunctionsEventProvider(eventTrigger.eventType) === "Firestore";
120
121
  }
122
+ isPubsubFunc(eventTrigger) {
123
+ return utils.getFunctionsEventProvider(eventTrigger.eventType) === "PubSub";
124
+ }
121
125
  triggerEvent(data, opts) {
126
+ var _a, _b, _c, _d;
122
127
  opts = opts || {};
123
128
  let operationType;
124
129
  let dataPayload;
125
130
  if (this.trigger.httpsTrigger) {
126
- this.controller.call(this.trigger.name, data || {}, opts);
131
+ this.controller.call(this.trigger, data || {}, opts);
127
132
  }
128
133
  else if (this.trigger.eventTrigger) {
129
134
  if (this.isDatabaseFn(this.trigger.eventTrigger)) {
130
135
  operationType = utils.last(this.trigger.eventTrigger.eventType.split("."));
131
136
  switch (operationType) {
132
137
  case "create":
138
+ case "created":
133
139
  dataPayload = {
134
140
  data: null,
135
141
  delta: data,
136
142
  };
137
143
  break;
138
144
  case "delete":
145
+ case "deleted":
139
146
  dataPayload = {
140
147
  data: data,
141
148
  delta: null,
@@ -147,20 +154,23 @@ class LocalFunction {
147
154
  delta: data.after,
148
155
  };
149
156
  }
150
- opts.resource = this.substituteParams(this.trigger.eventTrigger.resource, opts.params);
157
+ const resource = (_a = this.trigger.eventTrigger.resource) !== null && _a !== void 0 ? _a : (_b = this.trigger.eventTrigger.eventFilterPathPatterns) === null || _b === void 0 ? void 0 : _b.ref;
158
+ opts.resource = this.substituteParams(resource, opts.params);
151
159
  opts.auth = this.constructAuth(opts.auth, opts.authType);
152
- this.controller.call(this.trigger.name, dataPayload, opts);
160
+ this.controller.call(this.trigger, dataPayload, opts);
153
161
  }
154
162
  else if (this.isFirestoreFunc(this.trigger.eventTrigger)) {
155
163
  operationType = utils.last(this.trigger.eventTrigger.eventType.split("."));
156
164
  switch (operationType) {
157
165
  case "create":
166
+ case "created":
158
167
  dataPayload = {
159
168
  value: this.makeFirestoreValue(data),
160
169
  oldValue: {},
161
170
  };
162
171
  break;
163
172
  case "delete":
173
+ case "deleted":
164
174
  dataPayload = {
165
175
  value: {},
166
176
  oldValue: this.makeFirestoreValue(data),
@@ -172,14 +182,22 @@ class LocalFunction {
172
182
  oldValue: this.makeFirestoreValue(data.before),
173
183
  };
174
184
  }
175
- opts.resource = this.substituteParams(this.trigger.eventTrigger.resource, opts.params);
176
- this.controller.call(this.trigger.name, dataPayload, opts);
185
+ const resource = (_c = this.trigger.eventTrigger.resource) !== null && _c !== void 0 ? _c : (_d = this.trigger.eventTrigger.eventFilterPathPatterns) === null || _d === void 0 ? void 0 : _d.document;
186
+ opts.resource = this.substituteParams(resource, opts.params);
187
+ this.controller.call(this.trigger, dataPayload, opts);
188
+ }
189
+ else if (this.isPubsubFunc(this.trigger.eventTrigger)) {
190
+ dataPayload = data;
191
+ if (this.trigger.platform === "gcfv2") {
192
+ dataPayload = { message: Object.assign(Object.assign({}, data), { messageId: uuid.v4() }) };
193
+ }
194
+ this.controller.call(this.trigger, dataPayload || {}, opts);
177
195
  }
178
196
  else {
179
- this.controller.call(this.trigger.name, data || {}, opts);
197
+ this.controller.call(this.trigger, data || {}, opts);
180
198
  }
181
199
  }
182
- return console.log("Successfully invoked function.");
200
+ return "Successfully invoked function.";
183
201
  }
184
202
  makeFn() {
185
203
  var _a;
package/lib/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.openInBrowser = exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.withTimeout = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
3
+ exports.openInBrowser = exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isVSCodeExtension = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.withTimeout = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
4
4
  const _ = require("lodash");
5
5
  const url = require("url");
6
6
  const clc = require("colorette");
@@ -194,7 +194,7 @@ function getFunctionsEventProvider(eventType) {
194
194
  const provider = last(parts[1].split("."));
195
195
  return _.capitalize(provider);
196
196
  }
197
- if (/google.pubsub/.exec(eventType)) {
197
+ if (/google.*pubsub/.exec(eventType)) {
198
198
  return "PubSub";
199
199
  }
200
200
  else if (/google.storage/.exec(eventType)) {
@@ -212,7 +212,7 @@ function getFunctionsEventProvider(eventType) {
212
212
  else if (/google.firebase.crashlytics/.exec(eventType)) {
213
213
  return "Crashlytics";
214
214
  }
215
- else if (/google.firestore/.exec(eventType)) {
215
+ else if (/google.*firestore/.exec(eventType)) {
216
216
  return "Firestore";
217
217
  }
218
218
  return _.capitalize(eventType.split(".")[1]);
@@ -367,6 +367,10 @@ function isCloudEnvironment() {
367
367
  return !!process.env.CODESPACES || !!process.env.GOOGLE_CLOUD_WORKSTATIONS;
368
368
  }
369
369
  exports.isCloudEnvironment = isCloudEnvironment;
370
+ function isVSCodeExtension() {
371
+ return !!process.env.VSCODE_CWD;
372
+ }
373
+ exports.isVSCodeExtension = isVSCodeExtension;
370
374
  function isRunningInWSL() {
371
375
  return !!process.env.WSL_DISTRO_NAME;
372
376
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "12.4.6",
3
+ "version": "12.4.8",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {