firebase-tools 12.4.4 → 12.4.6

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.
package/lib/apiv2.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Client = exports.setAccessToken = exports.setRefreshToken = void 0;
4
4
  const url_1 = require("url");
5
5
  const stream_1 = require("stream");
6
- const ProxyAgent = require("proxy-agent");
6
+ const proxy_agent_1 = require("proxy-agent");
7
7
  const retry = require("retry");
8
8
  const abort_controller_1 = require("abort-controller");
9
9
  const node_fetch_1 = require("node-fetch");
@@ -146,7 +146,7 @@ class Client {
146
146
  if (accessToken) {
147
147
  return accessToken;
148
148
  }
149
- const data = (await auth.getAccessToken(refreshToken, []));
149
+ const data = await auth.getAccessToken(refreshToken, []);
150
150
  return data.access_token;
151
151
  }
152
152
  requestURL(options) {
@@ -179,12 +179,8 @@ class Client {
179
179
  redirect: options.redirect,
180
180
  compress: options.compress,
181
181
  };
182
- if (this.opts.proxy) {
183
- fetchOptions.agent = new ProxyAgent(this.opts.proxy);
184
- }
185
- const envProxy = proxyURIFromEnv();
186
- if (envProxy) {
187
- fetchOptions.agent = new ProxyAgent(envProxy);
182
+ if (proxyURIFromEnv()) {
183
+ fetchOptions.agent = new proxy_agent_1.ProxyAgent();
188
184
  }
189
185
  if (options.signal) {
190
186
  fetchOptions.signal = options.signal;
package/lib/auth.js CHANGED
@@ -509,7 +509,7 @@ async function refreshTokens(refreshToken, authScopes) {
509
509
  }
510
510
  }
511
511
  async function getAccessToken(refreshToken, authScopes) {
512
- if (haveValidTokens(refreshToken, authScopes)) {
512
+ if (haveValidTokens(refreshToken, authScopes) && lastAccessToken) {
513
513
  return lastAccessToken;
514
514
  }
515
515
  return refreshTokens(refreshToken, authScopes);
@@ -12,9 +12,9 @@ const prompt_1 = require("../prompt");
12
12
  const utils_1 = require("../utils");
13
13
  const projectUtils_1 = require("../projectUtils");
14
14
  const secretManager_1 = require("../gcp/secretManager");
15
+ const ensureApiEnabled_1 = require("../ensureApiEnabled");
15
16
  const secrets = require("../functions/secrets");
16
17
  const backend = require("../deploy/functions/backend");
17
- const ensureApiEnabled_1 = require("../ensureApiEnabled");
18
18
  exports.command = new command_1.Command("functions:secrets:set <KEY>")
19
19
  .description("Create or update a secret for use in Cloud Functions for Firebase.")
20
20
  .withForce("Automatically updates functions to use the new secret.")
@@ -58,7 +58,7 @@ exports.command = new command_1.Command("functions:secrets:set <KEY>")
58
58
  logger_1.logger.debug("Customer set secrets before enabling functions. Exiting");
59
59
  return;
60
60
  }
61
- const haveBackend = await backend.existingBackend({ projectId });
61
+ let haveBackend = await backend.existingBackend({ projectId });
62
62
  const endpointsToUpdate = backend
63
63
  .allEndpoints(haveBackend)
64
64
  .filter((e) => secrets.inUse({ projectId, projectNumber }, secret, e));
@@ -87,4 +87,20 @@ exports.command = new command_1.Command("functions:secrets:set <KEY>")
87
87
  return updated;
88
88
  });
89
89
  await Promise.all(updateOps);
90
+ haveBackend = await backend.existingBackend({ projectId }, true);
91
+ const staleEndpoints = backend.allEndpoints(backend.matchingBackend(haveBackend, (e) => {
92
+ const pInfo = { projectId, projectNumber };
93
+ return secrets.inUse(pInfo, secret, e) && !secrets.versionInUse(pInfo, secretVersion, e);
94
+ }));
95
+ if (staleEndpoints.length !== 0) {
96
+ (0, utils_1.logWarning)(`${staleEndpoints.length} functions are unexpectedly using old version of secret ${secret.name} still:\n\t` +
97
+ staleEndpoints.map((e) => `${e.id}(${e.region})`).join("\n\t"));
98
+ (0, utils_1.logBullet)("Please deploy your functions manually for the change to take effect by running:\n\t" +
99
+ clc.bold("firebase deploy --only functions"));
100
+ }
101
+ const secretsToPrune = (await secrets.pruneSecrets({ projectId, projectNumber }, backend.allEndpoints(haveBackend))).filter((sv) => sv.key === key);
102
+ (0, utils_1.logBullet)(`Removing secret versions: ${secretsToPrune
103
+ .map((sv) => sv.key + "[" + sv.version + "]")
104
+ .join(", ")}`);
105
+ await Promise.all(secretsToPrune.map((sv) => (0, secretManager_1.destroySecretVersion)(projectId, sv.secret, sv.version)));
90
106
  });
@@ -25,11 +25,11 @@ function prepareIndexes(context, options, databaseId, indexesFileName) {
25
25
  async function default_1(context, options) {
26
26
  if (options.only) {
27
27
  const targets = options.only.split(",");
28
- const onlyIndexes = targets.indexOf("firestore:indexes") >= 0;
29
- const onlyRules = targets.indexOf("firestore:rules") >= 0;
28
+ const excludeRules = targets.indexOf("firestore:indexes") >= 0;
29
+ const excludeIndexes = targets.indexOf("firestore:rules") >= 0;
30
30
  const onlyFirestore = targets.indexOf("firestore") >= 0;
31
- context.firestoreIndexes = onlyIndexes || onlyFirestore;
32
- context.firestoreRules = onlyRules || onlyFirestore;
31
+ context.firestoreIndexes = !excludeIndexes || onlyFirestore;
32
+ context.firestoreRules = !excludeRules || onlyFirestore;
33
33
  }
34
34
  else {
35
35
  context.firestoreIndexes = true;
@@ -223,12 +223,12 @@ class Fabricator {
223
223
  }
224
224
  async createV2Function(endpoint) {
225
225
  var _a, _b, _c, _d, _e;
226
- const storage = (_a = this.sources[endpoint.codebase]) === null || _a === void 0 ? void 0 : _a.storage;
227
- if (!storage) {
226
+ const storageSource = (_a = this.sources[endpoint.codebase]) === null || _a === void 0 ? void 0 : _a.storage;
227
+ if (!storageSource) {
228
228
  logger_1.logger.debug("Precondition failed. Cannot create a GCFv2 function without storage");
229
229
  throw new Error("Precondition failed");
230
230
  }
231
- const apiFunction = gcfV2.functionFromEndpoint(endpoint, storage);
231
+ const apiFunction = gcfV2.functionFromEndpoint(Object.assign(Object.assign({}, endpoint), { source: { storageSource } }));
232
232
  const topic = (_b = apiFunction.eventTrigger) === null || _b === void 0 ? void 0 : _b.pubsubTopic;
233
233
  if (topic) {
234
234
  await this.executor
@@ -368,12 +368,12 @@ class Fabricator {
368
368
  }
369
369
  async updateV2Function(endpoint) {
370
370
  var _a, _b, _c, _d;
371
- const storage = (_a = this.sources[endpoint.codebase]) === null || _a === void 0 ? void 0 : _a.storage;
372
- if (!storage) {
371
+ const storageSource = (_a = this.sources[endpoint.codebase]) === null || _a === void 0 ? void 0 : _a.storage;
372
+ if (!storageSource) {
373
373
  logger_1.logger.debug("Precondition failed. Cannot update a GCFv2 function without storage");
374
374
  throw new Error("Precondition failed");
375
375
  }
376
- const apiFunction = gcfV2.functionFromEndpoint(endpoint, storage);
376
+ const apiFunction = gcfV2.functionFromEndpoint(Object.assign(Object.assign({}, endpoint), { source: { storageSource } }));
377
377
  if ((_b = apiFunction.eventTrigger) === null || _b === void 0 ? void 0 : _b.pubsubTopic) {
378
378
  delete apiFunction.eventTrigger.pubsubTopic;
379
379
  }
@@ -146,13 +146,13 @@ async function signUp(state, reqBody, ctx) {
146
146
  (0, errors_1.assert)(state.enableAnonymousUser, "ADMIN_ONLY_OPERATION");
147
147
  }
148
148
  }
149
- if (typeof reqBody.email === "string") {
149
+ if (reqBody.email || (reqBody.email === "" && provider)) {
150
150
  (0, errors_1.assert)((0, utils_1.isValidEmailAddress)(reqBody.email), "INVALID_EMAIL");
151
151
  const email = (0, utils_1.canonicalizeEmailAddress)(reqBody.email);
152
152
  (0, errors_1.assert)(!state.getUserByEmail(email), "EMAIL_EXISTS");
153
153
  updates.email = email;
154
154
  }
155
- if (typeof reqBody.password === "string") {
155
+ if (reqBody.password) {
156
156
  (0, errors_1.assert)(reqBody.password.length >= PASSWORD_MIN_LENGTH, `WEAK_PASSWORD : Password should be at least ${PASSWORD_MIN_LENGTH} characters`);
157
157
  updates.salt = "fakeSalt" + (0, utils_1.randomId)(20);
158
158
  updates.passwordHash = hashPassword(reqBody.password, updates.salt);
@@ -88,6 +88,7 @@ exports.Constants = Constants;
88
88
  Constants.FAKE_PROJECT_ID_PREFIX = "demo-";
89
89
  Constants.FAKE_PROJECT_NUMBER = "0";
90
90
  Constants.DEFAULT_DATABASE_EMULATOR_NAMESPACE = "fake-server";
91
+ Constants.FIREBASE_ENABLED_EXPERIMENTS = "FIREBASE_ENABLED_EXPERIMENTS";
91
92
  Constants.FIRESTORE_EMULATOR_HOST = "FIRESTORE_EMULATOR_HOST";
92
93
  Constants.FIRESTORE_EMULATOR_ENV_ALT = "FIREBASE_FIRESTORE_EMULATOR_ADDRESS";
93
94
  Constants.FIREBASE_DATABASE_EMULATOR_HOST = "FIREBASE_DATABASE_EMULATOR_HOST";
@@ -8,6 +8,7 @@ const error_1 = require("../error");
8
8
  const constants_1 = require("./constants");
9
9
  const track_1 = require("../track");
10
10
  const ExpressBasedEmulator_1 = require("./ExpressBasedEmulator");
11
+ const experiments_1 = require("../experiments");
11
12
  class EmulatorUI {
12
13
  constructor(args) {
13
14
  this.args = args;
@@ -26,6 +27,8 @@ class EmulatorUI {
26
27
  if (session) {
27
28
  env[constants_1.Constants.FIREBASE_GA_SESSION] = JSON.stringify(session);
28
29
  }
30
+ const enabledExperiments = Object.keys(experiments_1.ALL_EXPERIMENTS).filter((experimentName) => (0, experiments_1.isEnabled)(experimentName));
31
+ env[constants_1.Constants.FIREBASE_ENABLED_EXPERIMENTS] = JSON.stringify(enabledExperiments);
29
32
  return downloadableEmulators.start(types_1.Emulators.UI, { auto_download: autoDownload }, env);
30
33
  }
31
34
  connect() {
@@ -27,6 +27,10 @@ async function check(projectId, apiName, prefix, silent = false) {
27
27
  return isEnabled;
28
28
  }
29
29
  exports.check = check;
30
+ function isPermissionError(e) {
31
+ var _a, _b, _c;
32
+ return ((_c = (_b = (_a = e.context) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.status) === "PERMISSION_DENIED";
33
+ }
30
34
  async function enable(projectId, apiName) {
31
35
  try {
32
36
  await apiClient.post(`/projects/${projectId}/services/${apiName}:enable`, undefined, {
@@ -40,7 +44,24 @@ async function enable(projectId, apiName) {
40
44
 
41
45
  https://console.firebase.google.com/project/${projectId}/usage/details`);
42
46
  }
43
- throw err;
47
+ else if (isPermissionError(err)) {
48
+ const apiPermissionDeniedRegex = new RegExp(/Permission denied to enable service \[([.a-zA-Z]+)\]/);
49
+ const permissionsError = apiPermissionDeniedRegex.exec(err.message);
50
+ if (permissionsError && permissionsError[1]) {
51
+ const serviceUrl = permissionsError[1];
52
+ err.message = `Permissions denied enabling ${serviceUrl}.
53
+ Please ask a project owner to visit the following URL to enable this service:
54
+
55
+ https://console.cloud.google.com/apis/library/${serviceUrl}?project=${projectId}`;
56
+ throw err;
57
+ }
58
+ else {
59
+ throw err;
60
+ }
61
+ }
62
+ else {
63
+ throw err;
64
+ }
44
65
  }
45
66
  }
46
67
  async function pollCheckEnabled(projectId, apiName, prefix, silent, enablementRetries, pollRetries = 0) {
@@ -39,36 +39,48 @@ async function acceptPublisherTOS(projectId, tosVersion) {
39
39
  }
40
40
  exports.acceptPublisherTOS = acceptPublisherTOS;
41
41
  async function acceptLatestPublisherTOS(options, projectId) {
42
- logger_1.logger.debug(`Checking if latest publisher TOS has been accepted by ${projectId}...`);
43
- const currentAcceptance = await getPublisherTOSStatus(projectId);
44
- if (currentAcceptance.lastAcceptedVersion) {
45
- logger_1.logger.debug(`Already accepted version ${currentAcceptance.lastAcceptedVersion} of Extensions publisher TOS.`);
46
- return currentAcceptance;
47
- }
48
- else {
49
- const tosLink = extensionsTosUrl("publisher");
50
- logger_1.logger.info(`To continue, you must accept the Firebase Extensions Publisher Terms of Service: ${tosLink}`);
51
- if (await (0, prompt_1.confirm)(Object.assign(Object.assign({}, options), { message: "Do you accept the Firebase Extensions Publisher Terms of Service?" }))) {
52
- return acceptPublisherTOS(projectId, currentAcceptance.latestTosVersion);
42
+ try {
43
+ logger_1.logger.debug(`Checking if latest publisher TOS has been accepted by ${projectId}...`);
44
+ const currentAcceptance = await getPublisherTOSStatus(projectId);
45
+ if (currentAcceptance.lastAcceptedVersion) {
46
+ logger_1.logger.debug(`Already accepted version ${currentAcceptance.lastAcceptedVersion} of Extensions publisher TOS.`);
47
+ return currentAcceptance;
48
+ }
49
+ else {
50
+ const tosLink = extensionsTosUrl("publisher");
51
+ logger_1.logger.info(`To continue, you must accept the Firebase Extensions Publisher Terms of Service: ${tosLink}`);
52
+ if (await (0, prompt_1.confirm)(Object.assign(Object.assign({}, options), { message: "Do you accept the Firebase Extensions Publisher Terms of Service?" }))) {
53
+ return acceptPublisherTOS(projectId, currentAcceptance.latestTosVersion);
54
+ }
53
55
  }
54
- throw new error_1.FirebaseError("You must accept the terms of service to continue.");
55
56
  }
57
+ catch (err) {
58
+ logger_1.logger.debug(`Error when checking Publisher TOS for ${projectId}. This is expected if authenticated via a service account: ${err}`);
59
+ return;
60
+ }
61
+ throw new error_1.FirebaseError("You must accept the terms of service to continue.");
56
62
  }
57
63
  exports.acceptLatestPublisherTOS = acceptLatestPublisherTOS;
58
64
  async function acceptLatestAppDeveloperTOS(options, projectId, instanceIds) {
59
- logger_1.logger.debug(`Checking if latest AppDeveloper TOS has been accepted by ${projectId}...`);
60
- displayDeveloperTOSWarning();
61
- const currentAcceptance = await getAppDeveloperTOSStatus(projectId);
62
- if (currentAcceptance.lastAcceptedVersion) {
63
- logger_1.logger.debug(`User Terms of Service aready accepted on project ${projectId}.`);
65
+ try {
66
+ logger_1.logger.debug(`Checking if latest AppDeveloper TOS has been accepted by ${projectId}...`);
67
+ displayDeveloperTOSWarning();
68
+ const currentAcceptance = await getAppDeveloperTOSStatus(projectId);
69
+ if (currentAcceptance.lastAcceptedVersion) {
70
+ logger_1.logger.debug(`User Terms of Service aready accepted on project ${projectId}.`);
71
+ }
72
+ else if (!(await (0, prompt_1.confirm)(Object.assign(Object.assign({}, options), { message: "Do you accept the Firebase Extensions User Terms of Service?" })))) {
73
+ throw new error_1.FirebaseError("You must accept the terms of service to continue.");
74
+ }
75
+ const tosPromises = instanceIds.map((instanceId) => {
76
+ return acceptAppDeveloperTOS(projectId, currentAcceptance.latestTosVersion, instanceId);
77
+ });
78
+ return Promise.all(tosPromises);
64
79
  }
65
- else if (!(await (0, prompt_1.confirm)(Object.assign(Object.assign({}, options), { message: "Do you accept the Firebase Extensions User Terms of Service?" })))) {
66
- throw new error_1.FirebaseError("You must accept the terms of service to continue.");
80
+ catch (err) {
81
+ logger_1.logger.debug(`Error when checking App Developer TOS for ${projectId}. This is expected if authenticated via a service account: ${err}`);
82
+ return [];
67
83
  }
68
- const tosPromises = instanceIds.map((instanceId) => {
69
- return acceptAppDeveloperTOS(projectId, currentAcceptance.latestTosVersion, instanceId);
70
- });
71
- return Promise.all(tosPromises);
72
84
  }
73
85
  exports.acceptLatestAppDeveloperTOS = acceptLatestAppDeveloperTOS;
74
86
  function displayDeveloperTOSWarning() {
@@ -49,14 +49,21 @@ function getFirestoreConfig(projectId, options) {
49
49
  }
50
50
  }
51
51
  else if (database) {
52
- if (allDatabases) {
52
+ if (allDatabases || onlyDatabases.has(database)) {
53
53
  results.push(c);
54
+ onlyDatabases.delete(database);
54
55
  }
55
56
  }
56
57
  else {
57
58
  throw new error_1.FirebaseError('Must supply either "target" or "databaseId" in firestore config');
58
59
  }
59
60
  }
61
+ if (onlyDatabases.has("rules")) {
62
+ onlyDatabases.delete("rules");
63
+ }
64
+ if (onlyDatabases.has("indexes")) {
65
+ onlyDatabases.delete("indexes");
66
+ }
60
67
  if (!allDatabases && onlyDatabases.size !== 0) {
61
68
  throw new error_1.FirebaseError(`Could not find configurations in firebase.json for the following database targets: ${[
62
69
  ...onlyDatabases,
@@ -13,6 +13,7 @@ const svelte = require("./svelte");
13
13
  const svelekit = require("./sveltekit");
14
14
  const react = require("./react");
15
15
  const vite = require("./vite");
16
+ const flutter = require("./flutter");
16
17
  exports.WebFrameworks = {
17
18
  angular,
18
19
  astro,
@@ -26,4 +27,5 @@ exports.WebFrameworks = {
26
27
  svelekit,
27
28
  react,
28
29
  vite,
30
+ flutter,
29
31
  };
@@ -30,10 +30,6 @@ exports.support = "preview";
30
30
  exports.type = 2;
31
31
  exports.docsUrl = "https://firebase.google.com/docs/hosting/frameworks/nextjs";
32
32
  const DEFAULT_NUMBER_OF_REASONS_TO_LIST = 5;
33
- function getNextVersion(cwd) {
34
- var _a;
35
- return (_a = (0, utils_1.findDependency)("next", { cwd, depth: 0, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
36
- }
37
33
  function getReactVersion(cwd) {
38
34
  var _a;
39
35
  return (_a = (0, utils_1.findDependency)("react-dom", { cwd, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
@@ -41,7 +37,7 @@ function getReactVersion(cwd) {
41
37
  async function discover(dir) {
42
38
  if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "package.json"))))
43
39
  return;
44
- if (!(await (0, fs_extra_1.pathExists)("next.config.js")) && !getNextVersion(dir))
40
+ if (!(await (0, fs_extra_1.pathExists)("next.config.js")) && !(0, utils_2.getNextVersion)(dir))
45
41
  return;
46
42
  return { mayWantBackend: true, publicDirectory: (0, path_1.join)(dir, PUBLIC_DIR) };
47
43
  }
@@ -72,7 +68,7 @@ async function build(dir) {
72
68
  if (await (0, utils_2.isUsingMiddleware)((0, path_1.join)(dir, distDir), false)) {
73
69
  reasonsForBackend.add("middleware");
74
70
  }
75
- if (await (0, utils_2.isUsingImageOptimization)((0, path_1.join)(dir, distDir))) {
71
+ if (await (0, utils_2.isUsingImageOptimization)(dir, distDir)) {
76
72
  reasonsForBackend.add(`Image Optimization`);
77
73
  }
78
74
  const prerenderManifest = await (0, utils_1.readJSON)((0, path_1.join)(dir, distDir, constants_2.PRERENDER_MANIFEST));
@@ -349,8 +345,7 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
349
345
  await (0, promises_1.mkdir)((0, path_1.join)(destDir, "public"));
350
346
  await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, "public"), (0, path_1.join)(destDir, "public"));
351
347
  }
352
- if (!(await (0, utils_2.hasUnoptimizedImage)(sourceDir, distDir)) &&
353
- ((0, utils_2.usesAppDirRouter)(sourceDir) || (await (0, utils_2.usesNextImage)(sourceDir, distDir)))) {
348
+ if (await (0, utils_2.isUsingImageOptimization)(sourceDir, distDir)) {
354
349
  packageJson.dependencies["sharp"] = constants_1.SHARP_VERSION;
355
350
  }
356
351
  await (0, fs_extra_1.mkdirp)((0, path_1.join)(destDir, distDir));
@@ -386,7 +381,7 @@ async function getConfig(dir) {
386
381
  var _b;
387
382
  let config = {};
388
383
  if ((0, fs_1.existsSync)((0, path_1.join)(dir, "next.config.js"))) {
389
- const version = getNextVersion(dir);
384
+ const version = (0, utils_2.getNextVersion)(dir);
390
385
  if (!version)
391
386
  throw new Error("Unable to find the next dep, try NPM installing?");
392
387
  if ((0, semver_1.gte)(version, "12.0.0")) {
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getBuildId = exports.getHeadersFromMetaFiles = exports.getNonStaticServerComponents = exports.getNonStaticRoutes = exports.getMiddlewareMatcherRegexes = exports.allDependencyNames = exports.isUsingAppDirectory = exports.isUsingImageOptimization = exports.isUsingMiddleware = exports.hasUnoptimizedImage = exports.usesNextImage = exports.usesAppDirRouter = exports.getNextjsRewritesToUse = exports.isHeaderSupportedByHosting = exports.isRedirectSupportedByHosting = exports.isRewriteSupportedByHosting = exports.cleanI18n = exports.cleanCustomRouteI18n = exports.cleanEscapedChars = exports.I18N_SOURCE = void 0;
3
+ exports.getNextVersion = exports.getBuildId = exports.getHeadersFromMetaFiles = exports.getNonStaticServerComponents = exports.getNonStaticRoutes = exports.getMiddlewareMatcherRegexes = exports.allDependencyNames = exports.isUsingAppDirectory = exports.isUsingNextImageInAppDirectory = exports.isUsingImageOptimization = exports.isUsingMiddleware = exports.hasUnoptimizedImage = exports.usesNextImage = exports.usesAppDirRouter = exports.getNextjsRewritesToUse = exports.isHeaderSupportedByHosting = exports.isRedirectSupportedByHosting = exports.isRewriteSupportedByHosting = exports.cleanI18n = exports.cleanCustomRouteI18n = exports.cleanEscapedChars = exports.I18N_SOURCE = void 0;
4
4
  const fs_1 = require("fs");
5
5
  const fs_extra_1 = require("fs-extra");
6
6
  const path_1 = require("path");
7
+ const promises_1 = require("fs/promises");
8
+ const glob_1 = require("glob");
9
+ const semver_1 = require("semver");
7
10
  const utils_1 = require("../utils");
8
11
  const constants_1 = require("./constants");
9
12
  const fsutils_1 = require("../../fsutils");
10
- const promises_1 = require("fs/promises");
11
13
  exports.I18N_SOURCE = /\/:nextInternalLocale(\([^\)]+\))?/;
12
14
  function cleanEscapedChars(path) {
13
15
  return path.replace(/\\([(){}:+?*])/g, (a, b) => b);
@@ -84,20 +86,31 @@ async function isUsingMiddleware(dir, isDevMode) {
84
86
  }
85
87
  }
86
88
  exports.isUsingMiddleware = isUsingMiddleware;
87
- async function isUsingImageOptimization(dir) {
88
- let { isNextImageImported } = await (0, utils_1.readJSON)((0, path_1.join)(dir, constants_1.EXPORT_MARKER));
89
- if (!isNextImageImported && isUsingAppDirectory(dir)) {
90
- isNextImageImported = (await (0, promises_1.readFile)((0, path_1.join)(dir, "server", "client-reference-manifest.js")))
91
- .toString()
92
- .includes("node_modules/next/dist/client/image.js");
89
+ async function isUsingImageOptimization(projectDir, distDir) {
90
+ let isNextImageImported = await usesNextImage(projectDir, distDir);
91
+ if (!isNextImageImported && isUsingAppDirectory((0, path_1.join)(projectDir, distDir))) {
92
+ if (await isUsingNextImageInAppDirectory(projectDir, distDir)) {
93
+ isNextImageImported = true;
94
+ }
93
95
  }
94
96
  if (isNextImageImported) {
95
- const imagesManifest = await (0, utils_1.readJSON)((0, path_1.join)(dir, constants_1.IMAGES_MANIFEST));
97
+ const imagesManifest = await (0, utils_1.readJSON)((0, path_1.join)(projectDir, distDir, constants_1.IMAGES_MANIFEST));
96
98
  return !imagesManifest.images.unoptimized;
97
99
  }
98
100
  return false;
99
101
  }
100
102
  exports.isUsingImageOptimization = isUsingImageOptimization;
103
+ async function isUsingNextImageInAppDirectory(projectDir, nextDir) {
104
+ const files = (0, glob_1.sync)((0, path_1.join)(projectDir, nextDir, "server", "**", "*client-reference-manifest.js"));
105
+ for (const filepath of files) {
106
+ const fileContents = await (0, promises_1.readFile)(filepath);
107
+ if (fileContents.includes("node_modules/next/dist/client/image")) {
108
+ return true;
109
+ }
110
+ }
111
+ return false;
112
+ }
113
+ exports.isUsingNextImageInAppDirectory = isUsingNextImageInAppDirectory;
101
114
  function isUsingAppDirectory(dir) {
102
115
  const appPathRoutesManifestPath = (0, path_1.join)(dir, constants_1.APP_PATH_ROUTES_MANIFEST);
103
116
  return (0, fsutils_1.fileExistsSync)(appPathRoutesManifestPath);
@@ -172,3 +185,13 @@ async function getBuildId(distDir) {
172
185
  return buildId.toString();
173
186
  }
174
187
  exports.getBuildId = getBuildId;
188
+ function getNextVersion(cwd) {
189
+ const dependency = (0, utils_1.findDependency)("next", { cwd, depth: 0, omitDev: false });
190
+ if (!dependency)
191
+ return undefined;
192
+ const nextVersionSemver = (0, semver_1.coerce)(dependency.version);
193
+ if (!nextVersionSemver)
194
+ return dependency.version;
195
+ return nextVersionSemver.toString();
196
+ }
197
+ exports.getNextVersion = getNextVersion;
@@ -1,20 +1,33 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateEndpointSecret = exports.pruneAndDestroySecrets = exports.pruneSecrets = exports.inUse = exports.getSecretVersions = exports.of = exports.ensureSecret = exports.ensureValidKey = exports.ensureApi = exports.labels = exports.isFirebaseManaged = void 0;
3
+ exports.updateEndpointSecret = exports.pruneAndDestroySecrets = exports.pruneSecrets = exports.versionInUse = exports.inUse = exports.getSecretVersions = exports.of = exports.ensureSecret = exports.ensureValidKey = exports.ensureApi = exports.labels = exports.isFirebaseManaged = void 0;
4
4
  const utils = require("../utils");
5
5
  const poller = require("../operation-poller");
6
- const gcf = require("../gcp/cloudfunctions");
6
+ const gcfV1 = require("../gcp/cloudfunctions");
7
+ const gcfV2 = require("../gcp/cloudfunctionsv2");
7
8
  const ensureApiEnabled = require("../ensureApiEnabled");
9
+ const api_1 = require("../api");
8
10
  const secretManager_1 = require("../gcp/secretManager");
9
11
  const error_1 = require("../error");
10
12
  const utils_1 = require("../utils");
11
13
  const prompt_1 = require("../prompt");
12
14
  const env_1 = require("./env");
13
15
  const logger_1 = require("../logger");
14
- const api_1 = require("../api");
15
16
  const functional_1 = require("../functional");
16
17
  const projectUtils_1 = require("../projectUtils");
17
18
  const FIREBASE_MANAGED = "firebase-managed";
19
+ const gcfV1PollerOptions = {
20
+ apiOrigin: api_1.functionsOrigin,
21
+ apiVersion: "v1",
22
+ masterTimeout: 25 * 60 * 1000,
23
+ maxBackoff: 10000,
24
+ };
25
+ const gcfV2PollerOptions = {
26
+ apiOrigin: api_1.functionsV2Origin,
27
+ apiVersion: "v2",
28
+ masterTimeout: 25 * 60 * 1000,
29
+ maxBackoff: 10000,
30
+ };
18
31
  function isFirebaseManaged(secret) {
19
32
  return Object.keys(secret.labels || []).includes(FIREBASE_MANAGED);
20
33
  }
@@ -110,6 +123,18 @@ function inUse(projectInfo, secret, endpoint) {
110
123
  return false;
111
124
  }
112
125
  exports.inUse = inUse;
126
+ function versionInUse(projectInfo, sv, endpoint) {
127
+ const { projectId, projectNumber } = projectInfo;
128
+ for (const sev of of([endpoint])) {
129
+ if ((sev.projectId === projectId || sev.projectId === projectNumber) &&
130
+ sev.secret === sv.secret.name &&
131
+ sev.version === sv.versionId) {
132
+ return true;
133
+ }
134
+ }
135
+ return false;
136
+ }
137
+ exports.versionInUse = versionInUse;
113
138
  async function pruneSecrets(projectInfo, endpoints) {
114
139
  const { projectId, projectNumber } = projectInfo;
115
140
  const pruneKey = (name, version) => `${name}@${version}`;
@@ -191,26 +216,21 @@ async function updateEndpointSecret(projectInfo, secretVersion, endpoint) {
191
216
  updatedSevs.push(updatedSev);
192
217
  }
193
218
  if (endpoint.platform === "gcfv1") {
194
- const fn = gcf.functionFromEndpoint(endpoint, "");
195
- const op = await gcf.updateFunction({
219
+ const fn = gcfV1.functionFromEndpoint(endpoint, "");
220
+ const op = await gcfV1.updateFunction({
196
221
  name: fn.name,
197
222
  runtime: fn.runtime,
198
223
  entryPoint: fn.entryPoint,
199
224
  secretEnvironmentVariables: updatedSevs,
200
225
  });
201
- const gcfV1PollerOptions = {
202
- apiOrigin: api_1.functionsOrigin,
203
- apiVersion: gcf.API_VERSION,
204
- masterTimeout: 25 * 60 * 1000,
205
- maxBackoff: 10000,
206
- pollerName: `update-${endpoint.region}-${endpoint.id}`,
207
- operationResourceName: op.name,
208
- };
209
- const cfn = await poller.pollOperation(gcfV1PollerOptions);
210
- return gcf.endpointFromFunction(cfn);
226
+ const cfn = await poller.pollOperation(Object.assign(Object.assign({}, gcfV1PollerOptions), { operationResourceName: op.name }));
227
+ return gcfV1.endpointFromFunction(cfn);
211
228
  }
212
229
  else if (endpoint.platform === "gcfv2") {
213
- throw new error_1.FirebaseError(`Unsupported platform ${endpoint.platform}`);
230
+ const fn = gcfV2.functionFromEndpoint(endpoint);
231
+ const op = await gcfV2.updateFunction(Object.assign(Object.assign({}, fn), { serviceConfig: Object.assign(Object.assign({}, fn.serviceConfig), { secretEnvironmentVariables: updatedSevs }) }));
232
+ const cfn = await poller.pollOperation(Object.assign(Object.assign({}, gcfV2PollerOptions), { operationResourceName: op.name }));
233
+ return gcfV2.endpointFromFunction(cfn);
214
234
  }
215
235
  else {
216
236
  (0, functional_1.assertExhaustive)(endpoint.platform);
@@ -6,16 +6,17 @@ const repl = require("repl");
6
6
  const _ = require("lodash");
7
7
  const request = require("request");
8
8
  const util = require("util");
9
+ const shell = require("./emulator/functionsEmulatorShell");
10
+ const commandUtils = require("./emulator/commandUtils");
9
11
  const functions_1 = require("./serve/functions");
10
12
  const localFunction_1 = require("./localFunction");
11
13
  const utils = require("./utils");
12
14
  const logger_1 = require("./logger");
13
- const shell = require("./emulator/functionsEmulatorShell");
14
- const commandUtils = require("./emulator/commandUtils");
15
15
  const types_1 = require("./emulator/types");
16
16
  const hubClient_1 = require("./emulator/hubClient");
17
17
  const portUtils_1 = require("./emulator/portUtils");
18
18
  const constants_1 = require("./emulator/constants");
19
+ const projectUtils_1 = require("./projectUtils");
19
20
  const serveFunctions = new functions_1.FunctionsServer();
20
21
  const actionFunction = async (options) => {
21
22
  var _a, _b, _c, _d, _e, _f;
@@ -26,7 +27,7 @@ const actionFunction = async (options) => {
26
27
  if (options.inspectFunctions) {
27
28
  debugPort = commandUtils.parseInspectionPort(options);
28
29
  }
29
- utils.assertDefined(options.project);
30
+ (0, projectUtils_1.needProjectId)(options);
30
31
  const hubClient = new hubClient_1.EmulatorHubClient(options.project);
31
32
  let remoteEmulators = {};
32
33
  if (hubClient.foundHub()) {
@@ -168,8 +168,8 @@ async function deleteFunction(cloudFunction) {
168
168
  }
169
169
  }
170
170
  exports.deleteFunction = deleteFunction;
171
- function functionFromEndpoint(endpoint, source) {
172
- var _a, _b;
171
+ function functionFromEndpoint(endpoint) {
172
+ var _a, _b, _c;
173
173
  if (endpoint.platform !== "gcfv2") {
174
174
  throw new error_1.FirebaseError("Trying to create a v2 CloudFunction with v1 API. This should never happen");
175
175
  }
@@ -183,7 +183,7 @@ function functionFromEndpoint(endpoint, source) {
183
183
  runtime: endpoint.runtime,
184
184
  entryPoint: endpoint.entryPoint,
185
185
  source: {
186
- storageSource: source,
186
+ storageSource: (_a = endpoint.source) === null || _a === void 0 ? void 0 : _a.storageSource,
187
187
  },
188
188
  environmentVariables: {},
189
189
  },
@@ -213,7 +213,7 @@ function functionFromEndpoint(endpoint, source) {
213
213
  eventType: endpoint.eventTrigger.eventType,
214
214
  };
215
215
  if (gcfFunction.eventTrigger.eventType === v2_1.PUBSUB_PUBLISH_EVENT) {
216
- if (!((_a = endpoint.eventTrigger.eventFilters) === null || _a === void 0 ? void 0 : _a.topic)) {
216
+ if (!((_b = endpoint.eventTrigger.eventFilters) === null || _b === void 0 ? void 0 : _b.topic)) {
217
217
  throw new error_1.FirebaseError("Error: Pub/Sub event trigger is missing topic: " +
218
218
  JSON.stringify(endpoint.eventTrigger, null, 2));
219
219
  }
@@ -262,7 +262,7 @@ function functionFromEndpoint(endpoint, source) {
262
262
  gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { [constants_1.CODEBASE_LABEL]: codebase });
263
263
  }
264
264
  else {
265
- (_b = gcfFunction.labels) === null || _b === void 0 ? true : delete _b[constants_1.CODEBASE_LABEL];
265
+ (_c = gcfFunction.labels) === null || _c === void 0 ? true : delete _c[constants_1.CODEBASE_LABEL];
266
266
  }
267
267
  if (endpoint.hash) {
268
268
  gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { [constants_1.HASH_LABEL]: endpoint.hash });
@@ -335,7 +335,7 @@ function endpointFromFunction(gcfFunction) {
335
335
  }
336
336
  const endpoint = Object.assign(Object.assign({ platform: "gcfv2", id,
337
337
  project,
338
- region }, trigger), { entryPoint: gcfFunction.buildConfig.entryPoint, runtime: gcfFunction.buildConfig.runtime });
338
+ region }, trigger), { entryPoint: gcfFunction.buildConfig.entryPoint, runtime: gcfFunction.buildConfig.runtime, source: gcfFunction.buildConfig.source });
339
339
  if (gcfFunction.serviceConfig) {
340
340
  proto.copyIfPresent(endpoint, gcfFunction.serviceConfig, "ingressSettings", "environmentVariables", "secretEnvironmentVariables", "timeoutSeconds", "uri");
341
341
  proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "serviceAccount", "serviceAccountEmail");
@@ -346,7 +346,7 @@ function endpointFromFunction(gcfFunction) {
346
346
  }
347
347
  const mem = mebibytes(prod);
348
348
  if (!backend.isValidMemoryOption(mem)) {
349
- logger_1.logger.warn("Converting a function to an endpoint with an invalid memory option", mem);
349
+ logger_1.logger.debug("Converting a function to an endpoint with an invalid memory option", mem);
350
350
  }
351
351
  return mem;
352
352
  });
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.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.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");
@@ -375,14 +375,6 @@ function thirtyDaysFromNow() {
375
375
  return new Date(Date.now() + THIRTY_DAYS_IN_MILLISECONDS);
376
376
  }
377
377
  exports.thirtyDaysFromNow = thirtyDaysFromNow;
378
- function assertDefined(val, message) {
379
- if (val === undefined || val === null) {
380
- throw new assert_1.AssertionError({
381
- message: message || `expected value to be defined but got "${val}"`,
382
- });
383
- }
384
- }
385
- exports.assertDefined = assertDefined;
386
378
  function assertIsString(val, message) {
387
379
  if (typeof val !== "string") {
388
380
  throw new assert_1.AssertionError({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "12.4.4",
3
+ "version": "12.4.6",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
@@ -99,7 +99,7 @@
99
99
  "p-limit": "^3.0.1",
100
100
  "portfinder": "^1.0.32",
101
101
  "progress": "^2.0.3",
102
- "proxy-agent": "^5.0.0",
102
+ "proxy-agent": "^6.3.0",
103
103
  "request": "^2.87.0",
104
104
  "retry": "^0.13.1",
105
105
  "rimraf": "^3.0.0",