firebase-tools 12.4.0 → 12.4.1

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 (49) hide show
  1. package/lib/api/frameworks.js +21 -0
  2. package/lib/api.js +4 -2
  3. package/lib/auth.js +3 -3
  4. package/lib/command.js +15 -4
  5. package/lib/commands/ext-install.js +10 -4
  6. package/lib/commands/index.js +2 -0
  7. package/lib/commands/init.js +8 -0
  8. package/lib/commands/internaltesting-frameworks-init.js +14 -0
  9. package/lib/config.js +1 -0
  10. package/lib/deploy/extensions/prepare.js +1 -0
  11. package/lib/deploy/extensions/release.js +11 -1
  12. package/lib/deploy/functions/checkIam.js +4 -1
  13. package/lib/deploy/functions/prepare.js +2 -1
  14. package/lib/deploy/functions/runtimes/discovery/index.js +6 -0
  15. package/lib/deploy/functions/runtimes/node/index.js +12 -4
  16. package/lib/deploy/functions/runtimes/python/index.js +19 -25
  17. package/lib/deploy/hosting/deploy.js +0 -6
  18. package/lib/deploy/hosting/prepare.js +7 -1
  19. package/lib/deploy/index.js +11 -4
  20. package/lib/deploy/lifecycleHooks.js +3 -0
  21. package/lib/detectProjectRoot.js +4 -1
  22. package/lib/dynamicImport.js +11 -1
  23. package/lib/emulator/commandUtils.js +4 -4
  24. package/lib/emulator/controller.js +9 -7
  25. package/lib/emulator/downloadableEmulators.js +3 -3
  26. package/lib/emulator/functionsEmulator.js +1 -2
  27. package/lib/emulator/storage/index.js +6 -0
  28. package/lib/emulator/storage/rules/manager.js +0 -4
  29. package/lib/emulator/storage/server.js +52 -0
  30. package/lib/ensureApiEnabled.js +3 -1
  31. package/lib/experiments.js +5 -0
  32. package/lib/extensions/paramHelper.js +0 -5
  33. package/lib/frameworks/constants.js +2 -15
  34. package/lib/frameworks/index.js +13 -8
  35. package/lib/frameworks/utils.js +50 -20
  36. package/lib/functionsConfig.js +2 -2
  37. package/lib/gcp/cloudbuild.js +50 -0
  38. package/lib/init/features/composer/repo.js +121 -0
  39. package/lib/init/features/frameworks/constants.js +7 -0
  40. package/lib/init/features/frameworks/index.js +36 -0
  41. package/lib/init/features/index.js +3 -1
  42. package/lib/init/index.js +4 -0
  43. package/lib/management/projects.js +5 -1
  44. package/lib/monospace/index.js +7 -7
  45. package/lib/requireAuth.js +1 -1
  46. package/lib/track.js +91 -52
  47. package/lib/utils.js +6 -1
  48. package/package.json +1 -1
  49. package/schema/extension-yaml.json +432 -0
package/lib/init/index.js CHANGED
@@ -6,6 +6,7 @@ const clc = require("colorette");
6
6
  const error_1 = require("../error");
7
7
  const logger_1 = require("../logger");
8
8
  const features = require("./features");
9
+ const experiments_1 = require("../experiments");
9
10
  const featureFns = new Map([
10
11
  ["account", features.account],
11
12
  ["database", features.database],
@@ -19,6 +20,9 @@ const featureFns = new Map([
19
20
  ["remoteconfig", features.remoteconfig],
20
21
  ["hosting:github", features.hostingGithub],
21
22
  ]);
23
+ if ((0, experiments_1.isEnabled)("frameworks")) {
24
+ featureFns.set("frameworks", features.frameworks);
25
+ }
22
26
  async function init(setup, config, options) {
23
27
  var _a;
24
28
  const nextFeature = (_a = setup.features) === null || _a === void 0 ? void 0 : _a.shift();
@@ -300,7 +300,11 @@ async function getFirebaseProject(projectId) {
300
300
  return res.body;
301
301
  }
302
302
  catch (err) {
303
- logger_1.logger.debug(err.message);
303
+ let message = err.message;
304
+ if (err.original) {
305
+ message += ` (original: ${err.original.message})`;
306
+ }
307
+ logger_1.logger.debug(message);
304
308
  throw new error_1.FirebaseError(`Failed to get Firebase project ${projectId}. ` +
305
309
  "Please make sure the project exists and your account has permission to access it.", { exit: 2, original: err });
306
310
  }
@@ -5,7 +5,7 @@ const node_fetch_1 = require("node-fetch");
5
5
  const error_1 = require("../error");
6
6
  const logger_1 = require("../logger");
7
7
  const rc_1 = require("../rc");
8
- const POLL_USER_RESPONSE_MILLIS = 5000;
8
+ const POLL_USER_RESPONSE_MILLIS = 2000;
9
9
  async function selectProjectInMonospace({ projectRoot, project, isVSCE, }) {
10
10
  const initFirebaseResponse = await initFirebase(project);
11
11
  if (initFirebaseResponse.success === false) {
@@ -27,9 +27,7 @@ async function pollAuthorizedProject(rid) {
27
27
  if (getInitFirebaseRes.userResponse.success) {
28
28
  return getInitFirebaseRes.userResponse.projectId;
29
29
  }
30
- else {
31
- return null;
32
- }
30
+ return null;
33
31
  }
34
32
  const { error } = getInitFirebaseRes;
35
33
  if (error === "WAITING_FOR_RESPONSE") {
@@ -39,7 +37,9 @@ async function pollAuthorizedProject(rid) {
39
37
  if (error === "USER_CANCELED") {
40
38
  throw new error_1.FirebaseError("User canceled without authorizing any project");
41
39
  }
42
- throw new error_1.FirebaseError(`Unhandled /get-init-firebase-response error: ${error}`);
40
+ throw new error_1.FirebaseError(`Unhandled /get-init-firebase-response error`, {
41
+ original: new Error(error),
42
+ });
43
43
  }
44
44
  async function initFirebase(project) {
45
45
  const port = getMonospaceDaemonPort();
@@ -73,8 +73,8 @@ function createFirebaseRc(projectDir, authorizedProject) {
73
73
  firebaseRc.addProjectAlias("default", authorizedProject);
74
74
  return firebaseRc.save();
75
75
  }
76
- async function isMonospaceEnv() {
77
- return Promise.resolve(Boolean(getMonospaceDaemonPort()));
76
+ function isMonospaceEnv() {
77
+ return getMonospaceDaemonPort() !== undefined;
78
78
  }
79
79
  exports.isMonospaceEnv = isMonospaceEnv;
80
80
  function getMonospaceDaemonPort() {
@@ -24,7 +24,7 @@ async function autoAuth(options, authScopes) {
24
24
  const client = getAuthClient({ scopes: authScopes, projectId: options.project });
25
25
  const token = await client.getAccessToken();
26
26
  token !== null ? apiv2.setAccessToken(token) : false;
27
- if (!options.isVSCE && (await (0, monospace_1.isMonospaceEnv)())) {
27
+ if (!options.isVSCE && (0, monospace_1.isMonospaceEnv)()) {
28
28
  await (0, monospace_1.selectProjectInMonospace)({
29
29
  projectRoot: options.config.projectDir,
30
30
  project: options.project,
package/lib/track.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.emulatorSession = exports.trackEmulator = exports.track = exports.usageEnabled = exports.EMULATOR_GA4_MEASUREMENT_ID = void 0;
3
+ exports.track = exports.cliSession = exports.emulatorSession = exports.trackEmulator = exports.trackGA4 = exports.usageEnabled = exports.GA4_PROPERTIES = void 0;
4
4
  const node_fetch_1 = require("node-fetch");
5
5
  const ua = require("universal-analytics");
6
6
  const uuid_1 = require("uuid");
@@ -8,45 +8,23 @@ const auth_1 = require("./auth");
8
8
  const configstore_1 = require("./configstore");
9
9
  const logger_1 = require("./logger");
10
10
  const pkg = require("../package.json");
11
- exports.EMULATOR_GA4_MEASUREMENT_ID = process.env.FIREBASE_EMULATOR_GA4_MEASUREMENT_ID || "G-KYP2JMPFC0";
11
+ exports.GA4_PROPERTIES = {
12
+ cli: {
13
+ measurementId: process.env.FIREBASE_CLI_GA4_MEASUREMENT_ID || "G-PDN0QWHQJR",
14
+ apiSecret: process.env.FIREBASE_CLI_GA4_API_SECRET || "LSw5lNxhSFSWeB6aIzJS2w",
15
+ clientIdKey: "analytics-uuid",
16
+ },
17
+ emulator: {
18
+ measurementId: process.env.FIREBASE_EMULATOR_GA4_MEASUREMENT_ID || "G-KYP2JMPFC0",
19
+ apiSecret: process.env.FIREBASE_EMULATOR_GA4_API_SECRET || "2V_zBYc4TdeoppzDaIu0zw",
20
+ clientIdKey: "emulator-analytics-clientId",
21
+ },
22
+ };
12
23
  function usageEnabled() {
13
24
  return !!process.env.IS_FIREBASE_CLI && !!configstore_1.configstore.get("usage");
14
25
  }
15
26
  exports.usageEnabled = usageEnabled;
16
- const FIREBASE_ANALYTICS_UA = process.env.FIREBASE_ANALYTICS_UA || "UA-29174744-3";
17
- let visitor;
18
- function ensureUAVisitor() {
19
- if (!visitor) {
20
- let anonId = configstore_1.configstore.get("analytics-uuid");
21
- if (!anonId) {
22
- anonId = (0, uuid_1.v4)();
23
- configstore_1.configstore.set("analytics-uuid", anonId);
24
- }
25
- visitor = ua(FIREBASE_ANALYTICS_UA, anonId, {
26
- strictCidFormat: false,
27
- https: true,
28
- });
29
- visitor.set("cd1", process.platform);
30
- visitor.set("cd2", process.version);
31
- visitor.set("cd3", process.env.FIREPIT_VERSION || "none");
32
- }
33
- }
34
- function track(action, label, duration = 0) {
35
- ensureUAVisitor();
36
- return new Promise((resolve) => {
37
- if (usageEnabled() && configstore_1.configstore.get("tokens")) {
38
- visitor.event("Firebase CLI " + pkg.version, action, label, duration).send(() => {
39
- resolve();
40
- });
41
- }
42
- else {
43
- resolve();
44
- }
45
- });
46
- }
47
- exports.track = track;
48
- const EMULATOR_GA4_API_SECRET = process.env.FIREBASE_EMULATOR_GA4_API_SECRET || "2V_zBYc4TdeoppzDaIu0zw";
49
- const EMULATOR_GA4_USER_PROPS = {
27
+ const GA4_USER_PROPS = {
50
28
  node_platform: {
51
29
  value: process.platform,
52
30
  },
@@ -60,6 +38,20 @@ const EMULATOR_GA4_USER_PROPS = {
60
38
  value: process.env.FIREPIT_VERSION || "none",
61
39
  },
62
40
  };
41
+ async function trackGA4(eventName, params, duration = 1) {
42
+ const session = cliSession();
43
+ if (!session) {
44
+ return;
45
+ }
46
+ return _ga4Track({
47
+ session,
48
+ apiSecret: exports.GA4_PROPERTIES.cli.apiSecret,
49
+ eventName,
50
+ params,
51
+ duration,
52
+ });
53
+ }
54
+ exports.trackGA4 = trackGA4;
63
55
  async function trackEmulator(eventName, params) {
64
56
  const session = emulatorSession();
65
57
  if (!session) {
@@ -67,29 +59,38 @@ async function trackEmulator(eventName, params) {
67
59
  }
68
60
  const oldTotalEngagementSeconds = session.totalEngagementSeconds;
69
61
  session.totalEngagementSeconds = process.uptime();
62
+ const duration = session.totalEngagementSeconds - oldTotalEngagementSeconds;
63
+ return _ga4Track({
64
+ session,
65
+ apiSecret: exports.GA4_PROPERTIES.emulator.apiSecret,
66
+ eventName,
67
+ params,
68
+ duration,
69
+ });
70
+ }
71
+ exports.trackEmulator = trackEmulator;
72
+ async function _ga4Track(args) {
73
+ const { session, apiSecret, eventName, params, duration } = args;
70
74
  session.commandName = (params === null || params === void 0 ? void 0 : params.command_name) || session.commandName;
71
- const search = `?api_secret=${EMULATOR_GA4_API_SECRET}&measurement_id=${session.measurementId}`;
75
+ const search = `?api_secret=${apiSecret}&measurement_id=${session.measurementId}`;
72
76
  const validate = session.validateOnly ? "debug/" : "";
73
77
  const url = `https://www.google-analytics.com/${validate}mp/collect${search}`;
74
78
  const body = {
75
79
  timestamp_micros: `${Date.now()}000`,
76
80
  client_id: session.clientId,
77
- user_properties: Object.assign(Object.assign({}, EMULATOR_GA4_USER_PROPS), { java_major_version: session.javaMajorVersion
81
+ user_properties: Object.assign(Object.assign({}, GA4_USER_PROPS), { java_major_version: session.javaMajorVersion
78
82
  ? { value: session.javaMajorVersion }
79
83
  : undefined }),
80
84
  validationBehavior: session.validateOnly ? "ENFORCE_RECOMMENDATIONS" : undefined,
81
85
  events: [
82
86
  {
83
87
  name: eventName,
84
- params: Object.assign({ session_id: session.sessionId, engagement_time_msec: (session.totalEngagementSeconds - oldTotalEngagementSeconds)
85
- .toFixed(3)
86
- .replace(".", "")
87
- .replace(/^0+/, ""), debug_mode: session.debugMode ? true : undefined, command_name: session.commandName }, params),
88
+ params: Object.assign({ session_id: session.sessionId, engagement_time_msec: (duration !== null && duration !== void 0 ? duration : 0).toFixed(3).replace(".", "").replace(/^0+/, ""), debug_mode: session.debugMode ? true : undefined, command_name: session.commandName }, params),
88
89
  },
89
90
  ],
90
91
  };
91
92
  if (session.validateOnly) {
92
- logger_1.logger.info(`Sending Analytics for event ${eventName}`, params, body);
93
+ logger_1.logger.info(`Sending Analytics for event ${eventName} to property ${session.measurementId}`, params, body);
93
94
  }
94
95
  try {
95
96
  const response = await (0, node_fetch_1.default)(url, {
@@ -114,8 +115,15 @@ async function trackEmulator(eventName, params) {
114
115
  return;
115
116
  }
116
117
  }
117
- exports.trackEmulator = trackEmulator;
118
118
  function emulatorSession() {
119
+ return session("emulator");
120
+ }
121
+ exports.emulatorSession = emulatorSession;
122
+ function cliSession() {
123
+ return session("cli");
124
+ }
125
+ exports.cliSession = cliSession;
126
+ function session(propertyName) {
119
127
  const validateOnly = !!process.env.FIREBASE_CLI_MP_VALIDATE;
120
128
  if (!usageEnabled()) {
121
129
  if (validateOnly) {
@@ -123,14 +131,15 @@ function emulatorSession() {
123
131
  }
124
132
  return;
125
133
  }
126
- if (!currentEmulatorSession) {
127
- let clientId = configstore_1.configstore.get("emulator-analytics-clientId");
134
+ const property = exports.GA4_PROPERTIES[propertyName];
135
+ if (!property.currentSession) {
136
+ let clientId = configstore_1.configstore.get(property.clientIdKey);
128
137
  if (!clientId) {
129
138
  clientId = (0, uuid_1.v4)();
130
- configstore_1.configstore.set("emulator-analytics-clientId", clientId);
139
+ configstore_1.configstore.set(property.clientIdKey, clientId);
131
140
  }
132
- currentEmulatorSession = {
133
- measurementId: exports.EMULATOR_GA4_MEASUREMENT_ID,
141
+ property.currentSession = {
142
+ measurementId: property.measurementId,
134
143
  clientId,
135
144
  sessionId: (Math.random() * Number.MAX_SAFE_INTEGER).toFixed(0),
136
145
  totalEngagementSeconds: 0,
@@ -138,10 +147,8 @@ function emulatorSession() {
138
147
  validateOnly,
139
148
  };
140
149
  }
141
- return currentEmulatorSession;
150
+ return property.currentSession;
142
151
  }
143
- exports.emulatorSession = emulatorSession;
144
- let currentEmulatorSession = undefined;
145
152
  function isDebugMode() {
146
153
  const account = (0, auth_1.getGlobalDefaultAccount)();
147
154
  if (account === null || account === void 0 ? void 0 : account.user.email.endsWith("@google.com")) {
@@ -155,3 +162,35 @@ function isDebugMode() {
155
162
  }
156
163
  return false;
157
164
  }
165
+ const FIREBASE_ANALYTICS_UA = process.env.FIREBASE_ANALYTICS_UA || "UA-29174744-3";
166
+ let visitor;
167
+ function ensureUAVisitor() {
168
+ if (!visitor) {
169
+ let anonId = configstore_1.configstore.get("analytics-uuid");
170
+ if (!anonId) {
171
+ anonId = (0, uuid_1.v4)();
172
+ configstore_1.configstore.set("analytics-uuid", anonId);
173
+ }
174
+ visitor = ua(FIREBASE_ANALYTICS_UA, anonId, {
175
+ strictCidFormat: false,
176
+ https: true,
177
+ });
178
+ visitor.set("cd1", process.platform);
179
+ visitor.set("cd2", process.version);
180
+ visitor.set("cd3", process.env.FIREPIT_VERSION || "none");
181
+ }
182
+ }
183
+ function track(action, label, duration = 0) {
184
+ ensureUAVisitor();
185
+ return new Promise((resolve) => {
186
+ if (usageEnabled() && configstore_1.configstore.get("tokens")) {
187
+ visitor.event("Firebase CLI " + pkg.version, action, label, duration).send(() => {
188
+ resolve();
189
+ });
190
+ }
191
+ else {
192
+ resolve();
193
+ }
194
+ });
195
+ }
196
+ exports.track = track;
package/lib/utils.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.assertDefined = 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.assertDefined = 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;
4
4
  const _ = require("lodash");
5
5
  const url = require("url");
6
6
  const clc = require("colorette");
7
+ const open = require("open");
7
8
  const ora = require("ora");
8
9
  const process = require("process");
9
10
  const stream_1 = require("stream");
@@ -485,3 +486,7 @@ function connectableHostname(hostname) {
485
486
  return hostname;
486
487
  }
487
488
  exports.connectableHostname = connectableHostname;
489
+ async function openInBrowser(url) {
490
+ await open(url);
491
+ }
492
+ exports.openInBrowser = openInBrowser;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "12.4.0",
3
+ "version": "12.4.1",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {