firebase-tools 13.7.3 → 13.7.5

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/api.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.githubOrigin = exports.apphostingOrigin = exports.serviceUsageOrigin = exports.cloudRunApiOrigin = exports.hostingApiOrigin = exports.firebaseStorageOrigin = exports.storageOrigin = exports.runtimeconfigOrigin = exports.rulesOrigin = exports.resourceManagerOrigin = exports.remoteConfigApiOrigin = exports.rtdbMetadataOrigin = exports.rtdbManagementOrigin = exports.realtimeOrigin = exports.extensionsTOSOrigin = exports.extensionsPublisherOrigin = exports.extensionsOrigin = exports.iamOrigin = exports.identityOrigin = exports.hostingOrigin = exports.googleOrigin = exports.pubsubOrigin = exports.cloudTasksOrigin = exports.cloudschedulerOrigin = exports.developerConnectP4SAOrigin = exports.developerConnectOrigin = exports.cloudbuildOrigin = exports.functionsDefaultRegion = exports.runOrigin = exports.functionsV2Origin = exports.functionsOrigin = exports.firestoreOrigin = exports.firestoreOriginOrEmulator = exports.firedataOrigin = exports.firebaseExtensionsRegistryOrigin = exports.firebaseApiOrigin = exports.eventarcOrigin = exports.dynamicLinksKey = exports.dynamicLinksOrigin = exports.consoleOrigin = exports.authOrigin = exports.appDistributionOrigin = exports.artifactRegistryDomain = exports.containerRegistryDomain = exports.cloudMonitoringOrigin = exports.cloudloggingOrigin = exports.cloudbillingOrigin = exports.clientSecret = exports.clientId = exports.authProxyOrigin = void 0;
4
- exports.setScopes = exports.getScopes = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = void 0;
3
+ exports.serviceUsageOrigin = exports.cloudRunApiOrigin = exports.hostingApiOrigin = exports.firebaseStorageOrigin = exports.storageOrigin = exports.runtimeconfigOrigin = exports.rulesOrigin = exports.resourceManagerOrigin = exports.remoteConfigApiOrigin = exports.rtdbMetadataOrigin = exports.rtdbManagementOrigin = exports.realtimeOrigin = exports.extensionsTOSOrigin = exports.extensionsPublisherOrigin = exports.extensionsOrigin = exports.iamOrigin = exports.identityOrigin = exports.hostingOrigin = exports.googleOrigin = exports.pubsubOrigin = exports.cloudTasksOrigin = exports.cloudschedulerOrigin = exports.cloudbuildOrigin = exports.functionsDefaultRegion = exports.runOrigin = exports.functionsV2Origin = exports.functionsOrigin = exports.firestoreOrigin = exports.firestoreOriginOrEmulator = exports.firedataOrigin = exports.firebaseExtensionsRegistryOrigin = exports.firebaseApiOrigin = exports.eventarcOrigin = exports.dynamicLinksKey = exports.dynamicLinksOrigin = exports.consoleOrigin = exports.authOrigin = exports.apphostingP4SADomain = exports.apphostingOrigin = exports.appDistributionOrigin = exports.artifactRegistryDomain = exports.developerConnectP4SADomain = exports.developerConnectOrigin = exports.containerRegistryDomain = exports.cloudMonitoringOrigin = exports.cloudloggingOrigin = exports.cloudbillingOrigin = exports.clientSecret = exports.clientId = exports.authProxyOrigin = void 0;
4
+ exports.setScopes = exports.getScopes = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = void 0;
5
5
  const constants_1 = require("./emulator/constants");
6
6
  const logger_1 = require("./logger");
7
7
  const scopes = require("./scopes");
@@ -21,10 +21,18 @@ const cloudMonitoringOrigin = () => utils.envOverride("CLOUD_MONITORING_URL", "h
21
21
  exports.cloudMonitoringOrigin = cloudMonitoringOrigin;
22
22
  const containerRegistryDomain = () => utils.envOverride("CONTAINER_REGISTRY_DOMAIN", "gcr.io");
23
23
  exports.containerRegistryDomain = containerRegistryDomain;
24
+ const developerConnectOrigin = () => utils.envOverride("DEVELOPERCONNECT_URL", "https://developerconnect.googleapis.com");
25
+ exports.developerConnectOrigin = developerConnectOrigin;
26
+ const developerConnectP4SADomain = () => utils.envOverride("DEVELOPERCONNECT_P4SA_DOMAIN", "gcp-sa-devconnect.iam.gserviceaccount.com");
27
+ exports.developerConnectP4SADomain = developerConnectP4SADomain;
24
28
  const artifactRegistryDomain = () => utils.envOverride("ARTIFACT_REGISTRY_DOMAIN", "https://artifactregistry.googleapis.com");
25
29
  exports.artifactRegistryDomain = artifactRegistryDomain;
26
30
  const appDistributionOrigin = () => utils.envOverride("FIREBASE_APP_DISTRIBUTION_URL", "https://firebaseappdistribution.googleapis.com");
27
31
  exports.appDistributionOrigin = appDistributionOrigin;
32
+ const apphostingOrigin = () => utils.envOverride("FIREBASE_APPHOSTING_URL", "https://firebaseapphosting.googleapis.com");
33
+ exports.apphostingOrigin = apphostingOrigin;
34
+ const apphostingP4SADomain = () => utils.envOverride("FIREBASE_APPHOSTING_P4SA_DOMAIN", "gcp-sa-firebaseapphosting.iam.gserviceaccount.com");
35
+ exports.apphostingP4SADomain = apphostingP4SADomain;
28
36
  const authOrigin = () => utils.envOverride("FIREBASE_AUTH_URL", "https://accounts.google.com");
29
37
  exports.authOrigin = authOrigin;
30
38
  const consoleOrigin = () => utils.envOverride("FIREBASE_CONSOLE_URL", "https://console.firebase.google.com");
@@ -60,10 +68,6 @@ const functionsDefaultRegion = () => utils.envOverride("FIREBASE_FUNCTIONS_DEFAU
60
68
  exports.functionsDefaultRegion = functionsDefaultRegion;
61
69
  const cloudbuildOrigin = () => utils.envOverride("FIREBASE_CLOUDBUILD_URL", "https://cloudbuild.googleapis.com");
62
70
  exports.cloudbuildOrigin = cloudbuildOrigin;
63
- const developerConnectOrigin = () => utils.envOverride("FIREBASE_DEVELOPERCONNECT_URL", "https://developerconnect.googleapis.com");
64
- exports.developerConnectOrigin = developerConnectOrigin;
65
- const developerConnectP4SAOrigin = () => utils.envOverride("FIREBASE_DEVELOPERCONNECT_P4SA_URL", "gcp-sa-devconnect.iam.gserviceaccount.com");
66
- exports.developerConnectP4SAOrigin = developerConnectP4SAOrigin;
67
71
  const cloudschedulerOrigin = () => utils.envOverride("FIREBASE_CLOUDSCHEDULER_URL", "https://cloudscheduler.googleapis.com");
68
72
  exports.cloudschedulerOrigin = cloudschedulerOrigin;
69
73
  const cloudTasksOrigin = () => utils.envOverride("FIREBASE_CLOUD_TAKS_URL", "https://cloudtasks.googleapis.com");
@@ -108,8 +112,6 @@ const cloudRunApiOrigin = () => utils.envOverride("CLOUD_RUN_API_URL", "https://
108
112
  exports.cloudRunApiOrigin = cloudRunApiOrigin;
109
113
  const serviceUsageOrigin = () => utils.envOverride("FIREBASE_SERVICE_USAGE_URL", "https://serviceusage.googleapis.com");
110
114
  exports.serviceUsageOrigin = serviceUsageOrigin;
111
- const apphostingOrigin = () => utils.envOverride("APPHOSTING_URL", "https://firebaseapphosting.googleapis.com");
112
- exports.apphostingOrigin = apphostingOrigin;
113
115
  const githubOrigin = () => utils.envOverride("GITHUB_URL", "https://github.com");
114
116
  exports.githubOrigin = githubOrigin;
115
117
  const githubApiOrigin = () => utils.envOverride("GITHUB_API_URL", "https://api.github.com");
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ALLOWED_DEPLOY_METHODS = exports.DEFAULT_DEPLOY_METHOD = exports.DEFAULT_REGION = void 0;
4
- exports.DEFAULT_REGION = "us-central1";
3
+ exports.ALLOWED_DEPLOY_METHODS = exports.DEFAULT_DEPLOY_METHOD = exports.DEFAULT_LOCATION = void 0;
4
+ exports.DEFAULT_LOCATION = "us-central1";
5
5
  exports.DEFAULT_DEPLOY_METHOD = "github";
6
6
  exports.ALLOWED_DEPLOY_METHODS = [{ name: "Deploy using github", value: "github" }];
@@ -89,7 +89,7 @@ async function createFullyInstalledConnection(projectId, location, connectionId,
89
89
  });
90
90
  while (conn.installationState.stage !== "COMPLETE") {
91
91
  utils.logBullet("Install the Firebase GitHub app to enable access to GitHub repositories");
92
- const targetUri = conn.installationState.actionUri.replace("install_v2", "direct_install_v2");
92
+ const targetUri = conn.installationState.actionUri;
93
93
  utils.logBullet(targetUri);
94
94
  await utils.openInBrowser(targetUri);
95
95
  await (0, prompt_1.promptOnce)({
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteBackendAndPoll = exports.orchestrateRollout = exports.setDefaultTrafficPolicy = exports.createBackend = exports.doSetup = void 0;
3
+ exports.promptLocation = exports.deleteBackendAndPoll = exports.orchestrateRollout = exports.setDefaultTrafficPolicy = exports.createBackend = exports.ensureAppHostingComputeServiceAccount = exports.doSetup = void 0;
4
4
  const repo = require("./repo");
5
5
  const poller = require("../operation-poller");
6
6
  const apphosting = require("../gcp/apphosting");
@@ -30,24 +30,19 @@ async function doSetup(projectId, webAppName, location, serviceAccount, withDevC
30
30
  (0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.secretManagerOrigin)(), "apphosting", true),
31
31
  (0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.cloudRunApiOrigin)(), "apphosting", true),
32
32
  (0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.artifactRegistryDomain)(), "apphosting", true),
33
+ (0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.iamOrigin)(), "apphosting", true),
33
34
  ]);
35
+ (0, utils_1.logBullet)("First we need a few details to create your backend.\n");
36
+ await ensureAppHostingComputeServiceAccount(projectId, serviceAccount);
34
37
  const allowedLocations = (await apphosting.listLocations(projectId)).map((loc) => loc.locationId);
35
38
  if (location) {
36
39
  if (!allowedLocations.includes(location)) {
37
40
  throw new error_1.FirebaseError(`Invalid location ${location}. Valid choices are ${allowedLocations.join(", ")}`);
38
41
  }
39
42
  }
40
- (0, utils_1.logBullet)("First we need a few details to create your backend.\n");
41
43
  location =
42
- location ||
43
- (await (0, prompt_1.promptOnce)({
44
- name: "region",
45
- type: "list",
46
- default: constants_1.DEFAULT_REGION,
47
- message: "Select a region to host your backend:\n",
48
- choices: allowedLocations.map((loc) => ({ value: loc })),
49
- }));
50
- (0, utils_1.logSuccess)(`Region set to ${location}.\n`);
44
+ location || (await promptLocation(projectId, "Select a location to host your backend:\n"));
45
+ (0, utils_1.logSuccess)(`Location set to ${location}.\n`);
51
46
  const backendId = await promptNewBackendId(projectId, location, {
52
47
  name: "backendId",
53
48
  type: "input",
@@ -100,6 +95,25 @@ async function doSetup(projectId, webAppName, location, serviceAccount, withDevC
100
95
  (0, utils_1.logSuccess)(`Your backend is now deployed at:\n\thttps://${backend.uri}`);
101
96
  }
102
97
  exports.doSetup = doSetup;
98
+ async function ensureAppHostingComputeServiceAccount(projectId, serviceAccount) {
99
+ const sa = serviceAccount || defaultComputeServiceAccountEmail(projectId);
100
+ const name = `projects/${projectId}/serviceAccounts/${sa}`;
101
+ try {
102
+ await iam.testResourceIamPermissions((0, api_1.iamOrigin)(), "v1", name, ["iam.serviceAccounts.actAs"], `projects/${projectId}`);
103
+ }
104
+ catch (err) {
105
+ if (!(err instanceof error_1.FirebaseError)) {
106
+ throw err;
107
+ }
108
+ if (err.status === 404) {
109
+ await provisionDefaultComputeServiceAccount(projectId);
110
+ }
111
+ else if (err.status === 403) {
112
+ throw new error_1.FirebaseError(`Failed to create backend due to missing delegation permissions for ${sa}. Make sure you have the iam.serviceAccounts.actAs permission.`, { original: err });
113
+ }
114
+ }
115
+ }
116
+ exports.ensureAppHostingComputeServiceAccount = ensureAppHostingComputeServiceAccount;
103
117
  async function promptNewBackendId(projectId, location, prompt) {
104
118
  while (true) {
105
119
  const backendId = await (0, prompt_1.promptOnce)(prompt);
@@ -130,31 +144,16 @@ async function createBackend(projectId, location, backendId, repository, service
130
144
  serviceAccount: serviceAccount || defaultServiceAccount,
131
145
  appId: webAppId,
132
146
  };
133
- delete backendReqBody.serviceAccount;
134
147
  async function createBackendAndPoll() {
135
148
  const op = await apphosting.createBackend(projectId, location, backendReqBody, backendId);
136
149
  return await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `create-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
137
150
  }
138
- try {
139
- return await createBackendAndPoll();
140
- }
141
- catch (err) {
142
- if (err.status === 403) {
143
- if (err.message.includes(defaultServiceAccount)) {
144
- await provisionDefaultComputeServiceAccount(projectId);
145
- return await createBackendAndPoll();
146
- }
147
- else if (serviceAccount && err.message.includes(serviceAccount)) {
148
- throw new error_1.FirebaseError(`Failed to create backend due to missing delegation permissions for ${serviceAccount}. Make sure you have the iam.serviceAccounts.actAs permission.`, { children: [err] });
149
- }
150
- }
151
- throw err;
152
- }
151
+ return await createBackendAndPoll();
153
152
  }
154
153
  exports.createBackend = createBackend;
155
154
  async function provisionDefaultComputeServiceAccount(projectId) {
156
155
  try {
157
- await iam.createServiceAccount(projectId, DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME, "Firebase App Hosting compute service account", "Default service account used to run builds and deploys for Firebase App Hosting");
156
+ await iam.createServiceAccount(projectId, DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME, "Default service account used to run builds and deploys for Firebase App Hosting", "Firebase App Hosting compute service account");
158
157
  }
159
158
  catch (err) {
160
159
  if (err.status !== 409) {
@@ -162,11 +161,9 @@ async function provisionDefaultComputeServiceAccount(projectId) {
162
161
  }
163
162
  }
164
163
  await (0, resourceManager_1.addServiceAccountToRoles)(projectId, defaultComputeServiceAccountEmail(projectId), [
165
- "roles/firebaseapphosting.viewer",
166
- "roles/artifactregistry.createOnPushWriter",
167
- "roles/logging.logWriter",
168
- "roles/storage.objectAdmin",
164
+ "roles/firebaseapphosting.computeRunner",
169
165
  "roles/firebase.sdkAdminServiceAgent",
166
+ "roles/developerconnect.tokenAccessor",
170
167
  ], true);
171
168
  }
172
169
  async function setDefaultTrafficPolicy(projectId, location, backendId, codebaseBranch) {
@@ -185,8 +182,12 @@ async function setDefaultTrafficPolicy(projectId, location, backendId, codebaseB
185
182
  await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `updateTraffic-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
186
183
  }
187
184
  exports.setDefaultTrafficPolicy = setDefaultTrafficPolicy;
185
+ function delay(ms) {
186
+ return new Promise((resolve) => setTimeout(resolve, ms));
187
+ }
188
188
  async function orchestrateRollout(projectId, location, backendId, buildInput) {
189
189
  (0, utils_1.logBullet)("Starting a new rollout... this may take a few minutes.");
190
+ await delay(45 * 1000);
190
191
  const buildId = await apphosting.getNextRolloutId(projectId, location, backendId, 1);
191
192
  const buildOp = await apphosting.createBuild(projectId, location, backendId, buildId, buildInput);
192
193
  const rolloutBody = {
@@ -233,3 +234,14 @@ async function deleteBackendAndPoll(projectId, location, backendId) {
233
234
  await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `delete-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
234
235
  }
235
236
  exports.deleteBackendAndPoll = deleteBackendAndPoll;
237
+ async function promptLocation(projectId, prompt = "Please select a location:") {
238
+ const allowedLocations = (await apphosting.listLocations(projectId)).map((loc) => loc.locationId);
239
+ return (await (0, prompt_1.promptOnce)({
240
+ name: "location",
241
+ type: "list",
242
+ default: constants_1.DEFAULT_LOCATION,
243
+ message: prompt,
244
+ choices: allowedLocations,
245
+ }));
246
+ }
247
+ exports.promptLocation = promptLocation;
@@ -86,7 +86,7 @@ async function createFullyInstalledConnection(projectId, location, connectionId,
86
86
  });
87
87
  while (conn.installationState.stage !== "COMPLETE") {
88
88
  utils.logBullet("Install the Cloud Build GitHub app to enable access to GitHub repositories");
89
- const targetUri = conn.installationState.actionUri.replace("install_v2", "direct_install_v2");
89
+ const targetUri = conn.installationState.actionUri;
90
90
  utils.logBullet(targetUri);
91
91
  await utils.openInBrowser(targetUri);
92
92
  await (0, prompt_1.promptOnce)({
@@ -5,6 +5,7 @@ const error_1 = require("../../error");
5
5
  const gcsm = require("../../gcp/secretManager");
6
6
  const gcb = require("../../gcp/cloudbuild");
7
7
  const gce = require("../../gcp/computeEngine");
8
+ const apphosting = require("../../gcp/apphosting");
8
9
  const secretManager_1 = require("../../gcp/secretManager");
9
10
  const secretManager_2 = require("../../gcp/secretManager");
10
11
  const utils = require("../../utils");
@@ -33,7 +34,8 @@ function serviceAccountsForBackend(projectNumber, backend) {
33
34
  };
34
35
  }
35
36
  exports.serviceAccountsForBackend = serviceAccountsForBackend;
36
- async function grantSecretAccess(projectId, secretName, accounts) {
37
+ async function grantSecretAccess(projectId, projectNumber, secretName, accounts) {
38
+ const p4saEmail = apphosting.serviceAgentEmail(projectNumber);
37
39
  const newBindings = [
38
40
  {
39
41
  role: "roles/secretmanager.secretAccessor",
@@ -43,6 +45,10 @@ async function grantSecretAccess(projectId, secretName, accounts) {
43
45
  role: "roles/secretmanager.viewer",
44
46
  members: accounts.buildServiceAccounts.map((sa) => `serviceAccount:${sa}`),
45
47
  },
48
+ {
49
+ role: "roles/secretmanager.secretVersionManager",
50
+ members: [`serviceAccount:${p4saEmail}`],
51
+ },
46
52
  ];
47
53
  let existingBindings;
48
54
  try {
@@ -9,9 +9,9 @@ const apphosting_2 = require("../gcp/apphosting");
9
9
  exports.command = new command_1.Command("apphosting:backends:create")
10
10
  .description("create a Firebase App Hosting backend")
11
11
  .option("-a, --app <webApp>", "specify an existing Firebase web app to associate your App Hosting backend with")
12
- .option("-l, --location <location>", "specify the region of the backend", "")
12
+ .option("-l, --location <location>", "specify the location of the backend", "")
13
13
  .option("-s, --service-account <serviceAccount>", "specify the service account used to run the server", "")
14
- .option("-w, --with-dev-connect", "use the Developer Connect flow insetad of Cloud Build Repositories (testing)", false)
14
+ .option("-w, --with-dev-connect", "use the Developer Connect flow instead of Cloud Build Repositories (testing)", true)
15
15
  .before(apphosting_2.ensureApiEnabled)
16
16
  .before(requireInteractive_1.default)
17
17
  .action(async (options) => {
@@ -5,32 +5,21 @@ const command_1 = require("../command");
5
5
  const projectUtils_1 = require("../projectUtils");
6
6
  const error_1 = require("../error");
7
7
  const prompt_1 = require("../prompt");
8
- const constants_1 = require("../apphosting/constants");
9
8
  const utils = require("../utils");
10
9
  const apphosting = require("../gcp/apphosting");
11
10
  const apphosting_backends_list_1 = require("./apphosting-backends-list");
12
11
  const apphosting_1 = require("../apphosting");
13
12
  exports.command = new command_1.Command("apphosting:backends:delete <backend>")
14
13
  .description("delete a Firebase App Hosting backend")
15
- .option("-l, --location <location>", "specify the region of the backend", "")
14
+ .option("-l, --location <location>", "specify the location of the backend", "")
16
15
  .withForce()
17
16
  .before(apphosting.ensureApiEnabled)
18
17
  .action(async (backendId, options) => {
19
18
  const projectId = (0, projectUtils_1.needProjectId)(options);
20
19
  let location = options.location;
21
- if (!backendId) {
22
- throw new error_1.FirebaseError("Backend id can't be empty.");
23
- }
24
- if (!location) {
25
- const allowedLocations = (await apphosting.listLocations(projectId)).map((loc) => loc.locationId);
26
- location = await (0, prompt_1.promptOnce)({
27
- name: "region",
28
- type: "list",
29
- default: constants_1.DEFAULT_REGION,
30
- message: "Please select the region of the backend you'd like to delete:",
31
- choices: allowedLocations,
32
- });
33
- }
20
+ location =
21
+ location ||
22
+ (await (0, apphosting_1.promptLocation)(projectId, "Please select the location of the backend you'd like to delete:"));
34
23
  let backend;
35
24
  try {
36
25
  backend = await apphosting.getBackend(projectId, location, backendId);
@@ -8,7 +8,7 @@ const logger_1 = require("../logger");
8
8
  const projectUtils_1 = require("../projectUtils");
9
9
  const apphosting = require("../gcp/apphosting");
10
10
  const Table = require("cli-table");
11
- const TABLE_HEAD = ["Backend ID", "Repository", "Location", "URL", "Created Date", "Updated Date"];
11
+ const TABLE_HEAD = ["Backend", "Repository", "URL", "Location", "Updated Date"];
12
12
  exports.command = new command_1.Command("apphosting:backends:list")
13
13
  .description("list Firebase App Hosting backends")
14
14
  .option("-l, --location <location>", "list backends in the specified location", "-")
@@ -39,9 +39,8 @@ function printBackendsTable(backends) {
39
39
  table.push([
40
40
  backendId,
41
41
  (_c = (_b = (_a = backend.codebase) === null || _a === void 0 ? void 0 : _a.repository) === null || _b === void 0 ? void 0 : _b.split("/").pop()) !== null && _c !== void 0 ? _c : "",
42
- backendLocation,
43
42
  backend.uri.startsWith("https:") ? backend.uri : "https://" + backend.uri,
44
- (0, utils_1.datetimeString)(new Date(backend.createTime)),
43
+ backendLocation,
45
44
  (0, utils_1.datetimeString)(new Date(backend.updateTime)),
46
45
  ]);
47
46
  }
@@ -8,7 +8,7 @@ const secretManager_1 = require("../gcp/secretManager");
8
8
  const requireAuth_1 = require("../requireAuth");
9
9
  const secretManager = require("../gcp/secretManager");
10
10
  const requirePermissions_1 = require("../requirePermissions");
11
- exports.command = new command_1.Command("apphosting:secrets:access <secretName>[@version]")
11
+ exports.command = new command_1.Command("apphosting:secrets:access <secretName[@version]>")
12
12
  .description("Access secret value given secret and its version. Defaults to accessing the latest version.")
13
13
  .before(requireAuth_1.requireAuth)
14
14
  .before(secretManager.ensureApi)
@@ -9,6 +9,7 @@ const secretManager = require("../gcp/secretManager");
9
9
  const requirePermissions_1 = require("../requirePermissions");
10
10
  const apphosting = require("../gcp/apphosting");
11
11
  const secrets = require("../apphosting/secrets");
12
+ const apphosting_1 = require("../apphosting");
12
13
  exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretName>")
13
14
  .description("grant service accounts permissions to the provided secret")
14
15
  .option("-l, --location <location>", "backend location")
@@ -27,13 +28,12 @@ exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretN
27
28
  .action(async (secretName, options) => {
28
29
  const projectId = (0, projectUtils_1.needProjectId)(options);
29
30
  const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
30
- if (!options.location) {
31
- throw new error_1.FirebaseError("Missing required flag --location. See firebase apphosting:secrets:grantaccess --help for more info");
32
- }
33
- const location = options.location;
34
31
  if (!options.backend) {
35
32
  throw new error_1.FirebaseError("Missing required flag --backend. See firebase apphosting:secrets:grantaccess --help for more info");
36
33
  }
34
+ let location = options.location;
35
+ location =
36
+ location || (await (0, apphosting_1.promptLocation)(projectId, "Please select the location of your backend"));
37
37
  const exists = await secretManager.secretExists(projectId, secretName);
38
38
  if (!exists) {
39
39
  throw new error_1.FirebaseError(`Cannot find secret ${secretName}`);
@@ -41,5 +41,5 @@ exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretN
41
41
  const backendId = options.backend;
42
42
  const backend = await apphosting.getBackend(projectId, location, backendId);
43
43
  const accounts = secrets.toMulti(secrets.serviceAccountsForBackend(projectNumber, backend));
44
- await secrets.grantSecretAccess(projectId, secretName, accounts);
44
+ await secrets.grantSecretAccess(projectId, projectNumber, secretName, accounts);
45
45
  });
@@ -50,7 +50,7 @@ exports.command = new command_1.Command("apphosting:secrets:set <secretName>")
50
50
  utils.logWarning(`To use this secret in your backend, you must grant access. You can do so in the future with ${clc.bold("firebase apphosting:secrets:grantaccess")}`);
51
51
  }
52
52
  else {
53
- await secrets.grantSecretAccess(projectId, secretName, accounts);
53
+ await secrets.grantSecretAccess(projectId, projectNumber, secretName, accounts);
54
54
  }
55
55
  await config.maybeAddSecretToYaml(secretName);
56
56
  });
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
23
23
  expectedChecksum: "2fd771101c0e1f7898c04c9204f2ce63",
24
24
  },
25
25
  firestore: {
26
- version: "1.19.4",
27
- expectedSize: 65913000,
28
- expectedChecksum: "a861bfa9d12ef69645b41e2f3bd8db8d",
26
+ version: "1.19.5",
27
+ expectedSize: 66204670,
28
+ expectedChecksum: "6d9fb826605701668af722f25048ad95",
29
29
  },
30
30
  storage: {
31
31
  version: "1.1.3",
@@ -147,6 +147,7 @@ const Commands = {
147
147
  "single_project_mode",
148
148
  ],
149
149
  joinArgs: false,
150
+ shell: false,
150
151
  },
151
152
  firestore: {
152
153
  binary: "java",
@@ -168,6 +169,7 @@ const Commands = {
168
169
  "single_project_mode",
169
170
  ],
170
171
  joinArgs: false,
172
+ shell: false,
171
173
  },
172
174
  storage: {
173
175
  binary: "java",
@@ -179,18 +181,21 @@ const Commands = {
179
181
  ],
180
182
  optionalArgs: [],
181
183
  joinArgs: false,
184
+ shell: false,
182
185
  },
183
186
  pubsub: {
184
187
  binary: getExecPath(types_1.Emulators.PUBSUB),
185
188
  args: [],
186
189
  optionalArgs: ["port", "host"],
187
190
  joinArgs: true,
191
+ shell: true,
188
192
  },
189
193
  ui: {
190
194
  binary: "node",
191
195
  args: [getExecPath(types_1.Emulators.UI)],
192
196
  optionalArgs: [],
193
197
  joinArgs: false,
198
+ shell: false,
194
199
  },
195
200
  };
196
201
  function getExecPath(name) {
@@ -237,6 +242,7 @@ function _getCommand(emulator, args) {
237
242
  args: cmdLineArgs,
238
243
  optionalArgs: baseCmd.optionalArgs,
239
244
  joinArgs: baseCmd.joinArgs,
245
+ shell: baseCmd.shell,
240
246
  };
241
247
  }
242
248
  exports._getCommand = _getCommand;
@@ -273,11 +279,15 @@ async function _runBinary(emulator, command, extraEnv) {
273
279
  const logger = emulatorLogger_1.EmulatorLogger.forEmulator(emulator.name);
274
280
  emulator.stdout = fs.createWriteStream(getLogFileName(emulator.name));
275
281
  try {
276
- emulator.instance = childProcess.spawn(command.binary, command.args, {
282
+ const opts = {
277
283
  env: Object.assign(Object.assign({}, process.env), extraEnv),
278
284
  detached: true,
279
285
  stdio: ["inherit", "pipe", "pipe"],
280
- });
286
+ };
287
+ if (command.shell && utils.IS_WINDOWS) {
288
+ opts.shell = true;
289
+ }
290
+ emulator.instance = childProcess.spawn(command.binary, command.args, opts);
281
291
  }
282
292
  catch (e) {
283
293
  if (e.code === "EACCES") {
@@ -123,9 +123,9 @@ async function build(dir, target, context) {
123
123
  headers.push(...headersFromMetaFiles);
124
124
  if (appPathsManifest) {
125
125
  const unrenderedServerComponents = (0, utils_2.getNonStaticServerComponents)(appPathsManifest, appPathRoutesManifest, prerenderedRoutes, dynamicRoutes);
126
- if (unrenderedServerComponents.has("/_not-found") &&
127
- (await (0, utils_2.hasStaticAppNotFoundComponent)(dir, distDir))) {
128
- unrenderedServerComponents.delete("/_not-found");
126
+ const notFoundPageKey = ["/_not-found", "/_not-found/page"].find((key) => unrenderedServerComponents.has(key));
127
+ if (notFoundPageKey && (await (0, utils_2.hasStaticAppNotFoundComponent)(dir, distDir))) {
128
+ unrenderedServerComponents.delete(notFoundPageKey);
129
129
  }
130
130
  for (const key of unrenderedServerComponents) {
131
131
  reasonsForBackend.add(`non-static component ${key}`);
@@ -231,6 +231,7 @@ async function getProductionDistDirFiles(sourceDir, distDir) {
231
231
  cwd: (0, path_1.join)(sourceDir, distDir),
232
232
  nodir: true,
233
233
  absolute: true,
234
+ realpath: utils_2.IS_WINDOWS,
234
235
  }, (err, matches) => {
235
236
  if (err)
236
237
  reject(err);
@@ -4,13 +4,14 @@ exports.runWithVirtualEnv = exports.virtualEnvCmd = exports.DEFAULT_VENV_DIR = v
4
4
  const path = require("path");
5
5
  const spawn = require("cross-spawn");
6
6
  const logger_1 = require("../logger");
7
+ const utils_1 = require("../utils");
7
8
  exports.DEFAULT_VENV_DIR = "venv";
8
9
  function virtualEnvCmd(cwd, venvDir) {
9
- const activateScriptPath = process.platform === "win32" ? ["Scripts", "activate.bat"] : ["bin", "activate"];
10
+ const activateScriptPath = utils_1.IS_WINDOWS ? ["Scripts", "activate.bat"] : ["bin", "activate"];
10
11
  const venvActivate = `"${path.join(cwd, venvDir, ...activateScriptPath)}"`;
11
12
  return {
12
- command: process.platform === "win32" ? venvActivate : ".",
13
- args: [process.platform === "win32" ? "" : venvActivate],
13
+ command: utils_1.IS_WINDOWS ? venvActivate : ".",
14
+ args: [utils_1.IS_WINDOWS ? "" : venvActivate],
14
15
  };
15
16
  }
16
17
  exports.virtualEnvCmd = virtualEnvCmd;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getNextRolloutId = exports.ensureApiEnabled = exports.listLocations = exports.updateTraffic = exports.listRollouts = exports.createRollout = exports.createBuild = exports.listBuilds = exports.getBuild = exports.deleteBackend = exports.listBackends = exports.getBackend = exports.createBackend = exports.client = exports.API_VERSION = void 0;
3
+ exports.getNextRolloutId = exports.ensureApiEnabled = exports.listLocations = exports.updateTraffic = exports.listRollouts = exports.createRollout = exports.createBuild = exports.listBuilds = exports.getBuild = exports.deleteBackend = exports.listBackends = exports.getBackend = exports.createBackend = exports.serviceAgentEmail = exports.client = exports.API_VERSION = void 0;
4
4
  const proto = require("../gcp/proto");
5
5
  const apiv2_1 = require("../apiv2");
6
6
  const projectUtils_1 = require("../projectUtils");
@@ -19,6 +19,11 @@ exports.client = new apiv2_1.Client({
19
19
  (0, metaprogramming_1.assertImplements)();
20
20
  (0, metaprogramming_1.assertImplements)();
21
21
  (0, metaprogramming_1.assertImplements)();
22
+ const P4SA_DOMAIN = (0, api_1.apphostingP4SADomain)();
23
+ function serviceAgentEmail(projectNumber) {
24
+ return `service-${projectNumber}@${P4SA_DOMAIN}`;
25
+ }
26
+ exports.serviceAgentEmail = serviceAgentEmail;
22
27
  async function createBackend(projectId, location, backendReqBoby, backendId) {
23
28
  const res = await exports.client.post(`projects/${projectId}/locations/${location}/backends`, Object.assign(Object.assign({}, backendReqBoby), { labels: Object.assign(Object.assign({}, backendReqBoby.labels), deploymentTool.labels()) }), { queryParams: { backendId } });
24
29
  return res.body;
@@ -84,7 +84,7 @@ async function getGitRepositoryLink(projectId, location, connectionId, gitReposi
84
84
  }
85
85
  exports.getGitRepositoryLink = getGitRepositoryLink;
86
86
  function serviceAgentEmail(projectNumber) {
87
- return `service-${projectNumber}@${(0, api_1.developerConnectP4SAOrigin)()}`;
87
+ return `service-${projectNumber}@${(0, api_1.developerConnectP4SADomain)()}`;
88
88
  }
89
89
  exports.serviceAgentEmail = serviceAgentEmail;
90
90
  async function generateP4SA(projectNumber) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "13.7.3",
3
+ "version": "13.7.5",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {