firebase-tools 12.3.1 → 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 (62) hide show
  1. package/lib/api/frameworks.js +21 -0
  2. package/lib/api.js +4 -3
  3. package/lib/appdistribution/client.js +52 -0
  4. package/lib/auth.js +3 -3
  5. package/lib/command.js +15 -4
  6. package/lib/commands/appdistribution-group-create.js +19 -0
  7. package/lib/commands/appdistribution-group-delete.js +24 -0
  8. package/lib/commands/appdistribution-testers-add.js +6 -1
  9. package/lib/commands/appdistribution-testers-remove.js +20 -13
  10. package/lib/commands/experiments-describe.js +1 -1
  11. package/lib/commands/ext-install.js +10 -4
  12. package/lib/commands/index.js +5 -0
  13. package/lib/commands/init.js +8 -0
  14. package/lib/commands/internaltesting-frameworks-init.js +14 -0
  15. package/lib/config.js +1 -0
  16. package/lib/deploy/extensions/prepare.js +1 -0
  17. package/lib/deploy/extensions/release.js +11 -1
  18. package/lib/deploy/functions/checkIam.js +4 -1
  19. package/lib/deploy/functions/prepare.js +2 -1
  20. package/lib/deploy/functions/runtimes/discovery/index.js +6 -0
  21. package/lib/deploy/functions/runtimes/node/index.js +12 -4
  22. package/lib/deploy/functions/runtimes/python/index.js +19 -25
  23. package/lib/deploy/hosting/deploy.js +0 -6
  24. package/lib/deploy/hosting/prepare.js +7 -1
  25. package/lib/deploy/index.js +11 -4
  26. package/lib/deploy/lifecycleHooks.js +3 -0
  27. package/lib/deploy/storage/prepare.js +1 -1
  28. package/lib/detectProjectRoot.js +4 -1
  29. package/lib/dynamicImport.js +11 -1
  30. package/lib/emulator/commandUtils.js +4 -4
  31. package/lib/emulator/controller.js +9 -7
  32. package/lib/emulator/downloadableEmulators.js +3 -3
  33. package/lib/emulator/functionsEmulator.js +1 -2
  34. package/lib/emulator/storage/index.js +6 -0
  35. package/lib/emulator/storage/rules/manager.js +0 -4
  36. package/lib/emulator/storage/server.js +52 -0
  37. package/lib/ensureApiEnabled.js +3 -1
  38. package/lib/experiments.js +5 -0
  39. package/lib/extensions/paramHelper.js +0 -5
  40. package/lib/frameworks/compose/discover/filesystem.js +52 -0
  41. package/lib/frameworks/compose/discover/frameworkMatcher.js +76 -0
  42. package/lib/frameworks/compose/discover/frameworkSpec.js +39 -0
  43. package/lib/frameworks/compose/discover/types.js +2 -0
  44. package/lib/frameworks/constants.js +2 -15
  45. package/lib/frameworks/index.js +13 -8
  46. package/lib/frameworks/utils.js +50 -20
  47. package/lib/functionsConfig.js +2 -2
  48. package/lib/gcp/cloudbuild.js +50 -0
  49. package/lib/gcp/storage.js +6 -5
  50. package/lib/init/features/composer/repo.js +121 -0
  51. package/lib/init/features/frameworks/constants.js +7 -0
  52. package/lib/init/features/frameworks/index.js +36 -0
  53. package/lib/init/features/index.js +3 -1
  54. package/lib/init/index.js +4 -0
  55. package/lib/management/projects.js +5 -1
  56. package/lib/monospace/index.js +82 -0
  57. package/lib/monospace/interfaces.js +2 -0
  58. package/lib/requireAuth.js +8 -0
  59. package/lib/track.js +91 -52
  60. package/lib/utils.js +6 -1
  61. package/package.json +1 -1
  62. package/schema/extension-yaml.json +432 -0
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.prepareFrameworks = exports.discover = exports.WebFrameworks = void 0;
3
+ exports.prepareFrameworks = exports.generateSSRCodebaseId = exports.discover = exports.WebFrameworks = void 0;
4
4
  const path_1 = require("path");
5
5
  const process_1 = require("process");
6
6
  const child_process_1 = require("child_process");
@@ -25,21 +25,22 @@ const experiments = require("../experiments");
25
25
  const implicitInit_1 = require("../hosting/implicitInit");
26
26
  const utils_1 = require("./utils");
27
27
  const constants_2 = require("./constants");
28
- Object.defineProperty(exports, "WebFrameworks", { enumerable: true, get: function () { return constants_2.WebFrameworks; } });
29
28
  const utils_2 = require("../utils");
30
29
  const ensureTargeted_1 = require("../functions/ensureTargeted");
31
30
  const util_1 = require("util");
32
31
  const projectPath_1 = require("../projectPath");
33
32
  const logger_1 = require("../logger");
33
+ const frameworks_1 = require("./frameworks");
34
+ Object.defineProperty(exports, "WebFrameworks", { enumerable: true, get: function () { return frameworks_1.WebFrameworks; } });
34
35
  async function discover(dir, warn = true) {
35
36
  const allFrameworkTypes = [
36
- ...new Set(Object.values(constants_2.WebFrameworks).map(({ type }) => type)),
37
+ ...new Set(Object.values(frameworks_1.WebFrameworks).map(({ type }) => type)),
37
38
  ].sort();
38
39
  for (const discoveryType of allFrameworkTypes) {
39
40
  const frameworksDiscovered = [];
40
- for (const framework in constants_2.WebFrameworks) {
41
- if (constants_2.WebFrameworks[framework]) {
42
- const { discover, type } = constants_2.WebFrameworks[framework];
41
+ for (const framework in frameworks_1.WebFrameworks) {
42
+ if (frameworks_1.WebFrameworks[framework]) {
43
+ const { discover, type } = frameworks_1.WebFrameworks[framework];
43
44
  if (type !== discoveryType)
44
45
  continue;
45
46
  const result = await discover(dir);
@@ -72,6 +73,10 @@ function memoizeBuild(dir, build, deps, target) {
72
73
  BUILD_MEMO.set(key, value);
73
74
  return value;
74
75
  }
76
+ function generateSSRCodebaseId(site) {
77
+ return `firebase-frameworks-${site}`;
78
+ }
79
+ exports.generateSSRCodebaseId = generateSSRCodebaseId;
75
80
  async function prepareFrameworks(purpose, targetNames, context, options, emulators = []) {
76
81
  var _a, _b, _c, _d, _e, _f;
77
82
  var _g, _h, _j, _k, _l;
@@ -185,7 +190,7 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
185
190
  throw new error_1.FirebaseError((0, utils_1.frameworksCallToAction)("Unable to detect the web framework in use, check firebase-debug.log for more info."));
186
191
  }
187
192
  const { framework, mayWantBackend, publicDirectory } = results;
188
- const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, docsUrl, getValidBuildTargets = constants_2.GET_DEFAULT_BUILD_TARGETS, shouldUseDevModeHandle = constants_2.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, } = constants_2.WebFrameworks[framework];
193
+ const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, docsUrl, getValidBuildTargets = constants_2.GET_DEFAULT_BUILD_TARGETS, shouldUseDevModeHandle = constants_2.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, } = frameworks_1.WebFrameworks[framework];
189
194
  logger_1.logger.info(`\n${(0, utils_1.frameworksCallToAction)(constants_2.SupportLevelWarnings[support](name), docsUrl, " ")}\n`);
190
195
  const hostingEmulatorInfo = emulators.find((e) => e.name === types_1.Emulators.HOSTING);
191
196
  const validBuildTargets = await getValidBuildTargets(purpose, getProjectPath());
@@ -242,7 +247,7 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
242
247
  if (context === null || context === void 0 ? void 0 : context.hostingChannel) {
243
248
  experiments.assertEnabled("pintags", "deploy an app that requires a backend to a preview channel");
244
249
  }
245
- const codebase = `firebase-frameworks-${site}`;
250
+ const codebase = generateSSRCodebaseId(site);
246
251
  const existingFunctionsConfig = options.config.get("functions")
247
252
  ? [].concat(options.config.get("functions"))
248
253
  : [];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getFrameworksBuildTarget = exports.validateLocales = exports.frameworksCallToAction = exports.conjoinOptions = exports.relativeRequire = exports.findDependency = exports.getNodeModuleBin = exports.getNpmRoot = exports.simpleProxy = exports.warnIfCustomBuildScript = exports.readJSON = exports.isUrl = void 0;
3
+ exports.getFrameworksBuildTarget = exports.validateLocales = exports.frameworksCallToAction = exports.conjoinOptions = exports.relativeRequire = exports.findDependency = exports.getNodeModuleBin = exports.getNpmRoot = exports.simpleProxy = exports.proxyResponse = exports.warnIfCustomBuildScript = exports.readJSON = exports.isUrl = void 0;
4
4
  const fs_extra_1 = require("fs-extra");
5
5
  const path_1 = require("path");
6
6
  const promises_1 = require("fs/promises");
@@ -32,21 +32,51 @@ async function warnIfCustomBuildScript(dir, framework, defaultBuildScripts) {
32
32
  }
33
33
  }
34
34
  exports.warnIfCustomBuildScript = warnIfCustomBuildScript;
35
- function proxyResponse(original, next) {
36
- return (response) => {
37
- const { statusCode, statusMessage } = response;
38
- if (!statusCode) {
39
- original.end();
40
- return;
41
- }
42
- if (statusCode === 404) {
43
- return next();
44
- }
45
- const headers = "getHeaders" in response ? response.getHeaders() : response.headers;
46
- original.writeHead(statusCode, statusMessage, headers);
47
- response.pipe(original);
48
- };
35
+ function proxyResponse(req, res, next) {
36
+ const proxiedRes = new http_1.ServerResponse(req);
37
+ const buffer = [];
38
+ proxiedRes.write = new Proxy(proxiedRes.write.bind(proxiedRes), {
39
+ apply: (target, thisArg, args) => {
40
+ target.call(thisArg, ...args);
41
+ buffer.push(["write", args]);
42
+ },
43
+ });
44
+ proxiedRes.setHeader = new Proxy(proxiedRes.setHeader.bind(proxiedRes), {
45
+ apply: (target, thisArg, args) => {
46
+ target.call(thisArg, ...args);
47
+ buffer.push(["setHeader", args]);
48
+ },
49
+ });
50
+ proxiedRes.removeHeader = new Proxy(proxiedRes.removeHeader.bind(proxiedRes), {
51
+ apply: (target, thisArg, args) => {
52
+ target.call(thisArg, ...args);
53
+ buffer.push(["removeHeader", args]);
54
+ },
55
+ });
56
+ proxiedRes.writeHead = new Proxy(proxiedRes.writeHead.bind(proxiedRes), {
57
+ apply: (target, thisArg, args) => {
58
+ target.call(thisArg, ...args);
59
+ buffer.push(["writeHead", args]);
60
+ },
61
+ });
62
+ proxiedRes.end = new Proxy(proxiedRes.end.bind(proxiedRes), {
63
+ apply: (target, thisArg, args) => {
64
+ target.call(thisArg, ...args);
65
+ if (proxiedRes.statusCode === 404) {
66
+ next();
67
+ }
68
+ else {
69
+ for (const [fn, args] of buffer) {
70
+ res[fn](...args);
71
+ }
72
+ res.end(...args);
73
+ buffer.length = 0;
74
+ }
75
+ },
76
+ });
77
+ return proxiedRes;
49
78
  }
79
+ exports.proxyResponse = proxyResponse;
50
80
  function simpleProxy(hostOrRequestHandler) {
51
81
  const agent = new http_1.Agent({ keepAlive: true });
52
82
  const firebaseDefaultsJSON = process.env.__FIREBASE_DEFAULTS__;
@@ -91,9 +121,8 @@ function simpleProxy(hostOrRequestHandler) {
91
121
  });
92
122
  }
93
123
  else {
94
- await Promise.resolve(hostOrRequestHandler(originalReq, originalRes, next));
95
- const proxiedRes = new http_1.ServerResponse(originalReq);
96
- proxyResponse(originalRes, next)(proxiedRes);
124
+ const proxiedRes = proxyResponse(originalReq, originalRes, next);
125
+ await hostOrRequestHandler(originalReq, proxiedRes, next);
97
126
  }
98
127
  };
99
128
  }
@@ -153,12 +182,13 @@ function findDependency(name, options = {}) {
153
182
  exports.findDependency = findDependency;
154
183
  function relativeRequire(dir, mod) {
155
184
  try {
156
- const path = require.resolve(mod, { paths: [dir] });
185
+ const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
186
+ const path = requireFunc.resolve(mod, { paths: [dir] });
157
187
  if ((0, path_1.extname)(path) === ".mjs") {
158
188
  return dynamicImport((0, url_1.pathToFileURL)(path).toString());
159
189
  }
160
190
  else {
161
- return require(path);
191
+ return requireFunc(path);
162
192
  }
163
193
  }
164
194
  catch (e) {
@@ -82,7 +82,7 @@ exports.setVariablesRecursive = setVariablesRecursive;
82
82
  async function materializeConfig(configName, output) {
83
83
  const materializeVariable = async function (varName) {
84
84
  const variable = await runtimeconfig.variables.get(varName);
85
- const id = exports.varNameToIds(variable.name);
85
+ const id = varNameToIds(variable.name);
86
86
  const key = id.config + "." + id.variable.split("/").join(".");
87
87
  _.set(output, key, variable.text);
88
88
  };
@@ -106,7 +106,7 @@ async function materializeAll(projectId) {
106
106
  if (config.name.match(new RegExp("configs/firebase"))) {
107
107
  return;
108
108
  }
109
- return exports.materializeConfig(config.name, output);
109
+ return materializeConfig(config.name, output);
110
110
  }));
111
111
  return output;
112
112
  }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteRepository = exports.getRepository = exports.createRepository = exports.fetchLinkableRepositories = exports.deleteConnection = exports.getConnection = exports.createConnection = void 0;
4
+ const apiv2_1 = require("../apiv2");
5
+ const api_1 = require("../api");
6
+ const client = new apiv2_1.Client({
7
+ urlPrefix: api_1.cloudbuildOrigin,
8
+ auth: true,
9
+ apiVersion: "v2",
10
+ });
11
+ async function createConnection(projectId, location, connectionId) {
12
+ const res = await client.post(`projects/${projectId}/locations/${location}/connections`, { githubConfig: {} }, { queryParams: { connectionId } });
13
+ return res.body;
14
+ }
15
+ exports.createConnection = createConnection;
16
+ async function getConnection(projectId, location, connectionId) {
17
+ const name = `projects/${projectId}/locations/${location}/connections/${connectionId}`;
18
+ const res = await client.get(name);
19
+ return res.body;
20
+ }
21
+ exports.getConnection = getConnection;
22
+ async function deleteConnection(projectId, location, connectionId) {
23
+ const name = `projects/${projectId}/locations/${location}/connections/${connectionId}`;
24
+ const res = await client.delete(name);
25
+ return res.body;
26
+ }
27
+ exports.deleteConnection = deleteConnection;
28
+ async function fetchLinkableRepositories(projectId, location, connectionId) {
29
+ const name = `projects/${projectId}/locations/${location}/connections/${connectionId}:fetchLinkableRepositories`;
30
+ const res = await client.get(name);
31
+ return res.body;
32
+ }
33
+ exports.fetchLinkableRepositories = fetchLinkableRepositories;
34
+ async function createRepository(projectId, location, connectionId, repositoryId, remoteUri) {
35
+ const res = await client.post(`projects/${projectId}/locations/${location}/connections/${connectionId}/repositories`, { remoteUri }, { queryParams: { repositoryId } });
36
+ return res.body;
37
+ }
38
+ exports.createRepository = createRepository;
39
+ async function getRepository(projectId, location, connectionId, repositoryId) {
40
+ const name = `projects/${projectId}/locations/${location}/connections/${connectionId}/repositories/${repositoryId}`;
41
+ const res = await client.get(name);
42
+ return res.body;
43
+ }
44
+ exports.getRepository = getRepository;
45
+ async function deleteRepository(projectId, location, connectionId, repositoryId) {
46
+ const name = `projects/${projectId}/locations/${location}/connections/${connectionId}/repositories/${repositoryId}`;
47
+ const res = await client.delete(name);
48
+ return res.body;
49
+ }
50
+ exports.deleteRepository = deleteRepository;
@@ -4,17 +4,18 @@ exports.getServiceAccount = exports.listBuckets = exports.getBucket = exports.de
4
4
  const path = require("path");
5
5
  const api_1 = require("../api");
6
6
  const apiv2_1 = require("../apiv2");
7
- const logger_1 = require("../logger");
8
7
  const error_1 = require("../error");
8
+ const logger_1 = require("../logger");
9
+ const projects_1 = require("../management/projects");
9
10
  async function getDefaultBucket(projectId) {
11
+ var _a;
10
12
  try {
11
- const appengineClient = new apiv2_1.Client({ urlPrefix: api_1.appengineOrigin, apiVersion: "v1" });
12
- const resp = await appengineClient.get(`/apps/${projectId}`);
13
- if (resp.body.defaultBucket === "undefined") {
13
+ const metadata = await (0, projects_1.getFirebaseProject)(projectId);
14
+ if (!((_a = metadata.resources) === null || _a === void 0 ? void 0 : _a.storageBucket)) {
14
15
  logger_1.logger.debug("Default storage bucket is undefined.");
15
16
  throw new error_1.FirebaseError("Your project is being set up. Please wait a minute before deploying again.");
16
17
  }
17
- return resp.body.defaultBucket;
18
+ return metadata.resources.storageBucket;
18
19
  }
19
20
  catch (err) {
20
21
  logger_1.logger.info("\n\nThere was an issue deploying your functions. Verify that your project has a Google App Engine instance setup at https://console.cloud.google.com/appengine and try again. If this issue persists, please contact support.");
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getOrCreateRepository = exports.getOrCreateConnection = exports.linkGitHubRepository = void 0;
4
+ const api_1 = require("../../../api");
5
+ const error_1 = require("../../../error");
6
+ const gcb = require("../../../gcp/cloudbuild");
7
+ const logger_1 = require("../../../logger");
8
+ const poller = require("../../../operation-poller");
9
+ const utils = require("../../../utils");
10
+ const prompt_1 = require("../../../prompt");
11
+ const gcbPollerOptions = {
12
+ apiOrigin: api_1.cloudbuildOrigin,
13
+ apiVersion: "v2",
14
+ masterTimeout: 25 * 60 * 1000,
15
+ maxBackoff: 10000,
16
+ };
17
+ function extractRepoSlugFromURI(remoteUri) {
18
+ const match = /github.com\/(.+).git/.exec(remoteUri);
19
+ if (!match) {
20
+ return undefined;
21
+ }
22
+ return match[1];
23
+ }
24
+ function generateConnectionId(stackId) {
25
+ return `composer-${stackId}-conn`;
26
+ }
27
+ function generateRepositoryId() {
28
+ return `composer-repo`;
29
+ }
30
+ async function linkGitHubRepository(projectId, location, stackId) {
31
+ const connectionId = generateConnectionId(stackId);
32
+ await getOrCreateConnection(projectId, location, connectionId);
33
+ let remoteUri = await promptRepositoryURI(projectId, location, connectionId);
34
+ while (remoteUri === "") {
35
+ await utils.openInBrowser("https://github.com/apps/google-cloud-build/installations/new");
36
+ await (0, prompt_1.promptOnce)({
37
+ type: "input",
38
+ message: "Press any key once you have finished configuring your installation's access settings.",
39
+ });
40
+ remoteUri = await promptRepositoryURI(projectId, location, connectionId);
41
+ }
42
+ const repo = await getOrCreateRepository(projectId, location, connectionId, remoteUri);
43
+ logger_1.logger.info(`Successfully linked GitHub repository at remote URI ${remoteUri}.`);
44
+ return repo;
45
+ }
46
+ exports.linkGitHubRepository = linkGitHubRepository;
47
+ async function promptRepositoryURI(projectId, location, connectionId) {
48
+ const resp = await gcb.fetchLinkableRepositories(projectId, location, connectionId);
49
+ if (!resp.repositories || resp.repositories.length === 0) {
50
+ throw new error_1.FirebaseError("The GitHub App does not have access to any repositories. Please configure " +
51
+ "your app installation permissions at https://github.com/settings/installations.");
52
+ }
53
+ const choices = resp.repositories.map((repo) => ({
54
+ name: extractRepoSlugFromURI(repo.remoteUri) || repo.remoteUri,
55
+ value: repo.remoteUri,
56
+ }));
57
+ choices.push({
58
+ name: "Missing a repo? Select this option to configure your installation's access settings",
59
+ value: "",
60
+ });
61
+ return await (0, prompt_1.promptOnce)({
62
+ type: "list",
63
+ message: "Which of the following repositories would you like to link?",
64
+ choices,
65
+ });
66
+ }
67
+ async function promptConnectionAuth(conn, projectId, location, connectionId) {
68
+ logger_1.logger.info(conn.installationState.message);
69
+ logger_1.logger.info(conn.installationState.actionUri);
70
+ await utils.openInBrowser(conn.installationState.actionUri);
71
+ await (0, prompt_1.promptOnce)({
72
+ type: "input",
73
+ message: "Press any key once you have authorized the app (Cloud Build) to access your GitHub repo.",
74
+ });
75
+ return await gcb.getConnection(projectId, location, connectionId);
76
+ }
77
+ async function getOrCreateConnection(projectId, location, connectionId) {
78
+ let conn;
79
+ try {
80
+ conn = await gcb.getConnection(projectId, location, connectionId);
81
+ }
82
+ catch (err) {
83
+ if (err.status === 404) {
84
+ const op = await gcb.createConnection(projectId, location, connectionId);
85
+ conn = await poller.pollOperation(Object.assign(Object.assign({}, gcbPollerOptions), { pollerName: `create-${location}-${connectionId}`, operationResourceName: op.name }));
86
+ }
87
+ else {
88
+ throw err;
89
+ }
90
+ }
91
+ while (conn.installationState.stage !== "COMPLETE") {
92
+ conn = await promptConnectionAuth(conn, projectId, location, connectionId);
93
+ }
94
+ return conn;
95
+ }
96
+ exports.getOrCreateConnection = getOrCreateConnection;
97
+ async function getOrCreateRepository(projectId, location, connectionId, remoteUri) {
98
+ const repositoryId = generateRepositoryId();
99
+ if (!repositoryId) {
100
+ throw new error_1.FirebaseError(`Failed to generate repositoryId for URI "${remoteUri}".`);
101
+ }
102
+ let repo;
103
+ try {
104
+ repo = await gcb.getRepository(projectId, location, connectionId, repositoryId);
105
+ const repoSlug = extractRepoSlugFromURI(repo.remoteUri);
106
+ if (repoSlug) {
107
+ throw new error_1.FirebaseError(`${repoSlug} has already been linked.`);
108
+ }
109
+ }
110
+ catch (err) {
111
+ if (err.status === 404) {
112
+ const op = await gcb.createRepository(projectId, location, connectionId, repositoryId, remoteUri);
113
+ repo = await poller.pollOperation(Object.assign(Object.assign({}, gcbPollerOptions), { pollerName: `create-${location}-${connectionId}-${repositoryId}`, operationResourceName: op.name }));
114
+ }
115
+ else {
116
+ throw err;
117
+ }
118
+ }
119
+ return repo;
120
+ }
121
+ exports.getOrCreateRepository = getOrCreateRepository;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ALLOWED_DEPLOY_METHODS = exports.DEFAULT_DEPLOY_METHOD = exports.ALLOWED_REGIONS = exports.DEFAULT_REGION = void 0;
4
+ exports.DEFAULT_REGION = "us-central1";
5
+ exports.ALLOWED_REGIONS = [{ name: "us-central1 (Iowa)", value: "us-central1" }];
6
+ exports.DEFAULT_DEPLOY_METHOD = "github";
7
+ exports.ALLOWED_DEPLOY_METHODS = [{ name: "Deploy using github", value: "github" }];
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doSetup = void 0;
4
+ const clc = require("colorette");
5
+ const utils = require("../../../utils");
6
+ const logger_1 = require("../../../logger");
7
+ const prompt_1 = require("../../../prompt");
8
+ const constants_1 = require("./constants");
9
+ async function doSetup(setup) {
10
+ setup.frameworks = {};
11
+ utils.logBullet("First we need a few details to create your service.");
12
+ await (0, prompt_1.promptOnce)({
13
+ name: "serviceName",
14
+ type: "input",
15
+ default: "acme-inc-web",
16
+ message: "Create a name for your service [6-32 characters]",
17
+ }, setup.frameworks);
18
+ await (0, prompt_1.promptOnce)({
19
+ name: "region",
20
+ type: "list",
21
+ default: constants_1.DEFAULT_REGION,
22
+ message: "Please select a region " +
23
+ `(${clc.yellow("info")}: Your region determines where your backend is located):\n`,
24
+ choices: constants_1.ALLOWED_REGIONS,
25
+ }, setup.frameworks);
26
+ utils.logSuccess(`Region set to ${setup.frameworks.region}.`);
27
+ logger_1.logger.info(clc.bold(`\n${clc.white("===")} Deploy Setup`));
28
+ await (0, prompt_1.promptOnce)({
29
+ name: "deployMethod",
30
+ type: "list",
31
+ default: constants_1.DEFAULT_DEPLOY_METHOD,
32
+ message: "How do you want to deploy",
33
+ choices: constants_1.ALLOWED_DEPLOY_METHODS,
34
+ }, setup.frameworks);
35
+ }
36
+ exports.doSetup = doSetup;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storage = exports.hosting = exports.functions = exports.firestore = exports.database = exports.account = void 0;
3
+ exports.frameworks = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storage = exports.hosting = exports.functions = exports.firestore = exports.database = exports.account = void 0;
4
4
  var account_1 = require("./account");
5
5
  Object.defineProperty(exports, "account", { enumerable: true, get: function () { return account_1.doSetup; } });
6
6
  var database_1 = require("./database");
@@ -23,3 +23,5 @@ var remoteconfig_1 = require("./remoteconfig");
23
23
  Object.defineProperty(exports, "remoteconfig", { enumerable: true, get: function () { return remoteconfig_1.doSetup; } });
24
24
  var github_1 = require("./hosting/github");
25
25
  Object.defineProperty(exports, "hostingGithub", { enumerable: true, get: function () { return github_1.initGitHub; } });
26
+ var frameworks_1 = require("./frameworks");
27
+ Object.defineProperty(exports, "frameworks", { enumerable: true, get: function () { return frameworks_1.doSetup; } });
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
  }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isMonospaceEnv = exports.selectProjectInMonospace = void 0;
4
+ const node_fetch_1 = require("node-fetch");
5
+ const error_1 = require("../error");
6
+ const logger_1 = require("../logger");
7
+ const rc_1 = require("../rc");
8
+ const POLL_USER_RESPONSE_MILLIS = 2000;
9
+ async function selectProjectInMonospace({ projectRoot, project, isVSCE, }) {
10
+ const initFirebaseResponse = await initFirebase(project);
11
+ if (initFirebaseResponse.success === false) {
12
+ throw new Error(String(initFirebaseResponse.error));
13
+ }
14
+ const { rid } = initFirebaseResponse;
15
+ const authorizedProject = await pollAuthorizedProject(rid);
16
+ if (!authorizedProject)
17
+ return null;
18
+ if (isVSCE)
19
+ return authorizedProject;
20
+ if (projectRoot)
21
+ createFirebaseRc(projectRoot, authorizedProject);
22
+ }
23
+ exports.selectProjectInMonospace = selectProjectInMonospace;
24
+ async function pollAuthorizedProject(rid) {
25
+ const getInitFirebaseRes = await getInitFirebaseResponse(rid);
26
+ if ("userResponse" in getInitFirebaseRes) {
27
+ if (getInitFirebaseRes.userResponse.success) {
28
+ return getInitFirebaseRes.userResponse.projectId;
29
+ }
30
+ return null;
31
+ }
32
+ const { error } = getInitFirebaseRes;
33
+ if (error === "WAITING_FOR_RESPONSE") {
34
+ await new Promise((res) => setTimeout(res, POLL_USER_RESPONSE_MILLIS));
35
+ return pollAuthorizedProject(rid);
36
+ }
37
+ if (error === "USER_CANCELED") {
38
+ throw new error_1.FirebaseError("User canceled without authorizing any project");
39
+ }
40
+ throw new error_1.FirebaseError(`Unhandled /get-init-firebase-response error`, {
41
+ original: new Error(error),
42
+ });
43
+ }
44
+ async function initFirebase(project) {
45
+ const port = getMonospaceDaemonPort();
46
+ if (!port)
47
+ throw new error_1.FirebaseError("Undefined MONOSPACE_DAEMON_PORT");
48
+ const initFirebaseURL = new URL(`http://localhost:${port}/init-firebase`);
49
+ if (project) {
50
+ initFirebaseURL.searchParams.set("known_project", project);
51
+ }
52
+ const initFirebaseRes = await (0, node_fetch_1.default)(initFirebaseURL.toString(), {
53
+ method: "POST",
54
+ headers: {
55
+ "Content-Type": "application/json",
56
+ },
57
+ });
58
+ const initFirebaseResponse = (await initFirebaseRes.json());
59
+ return initFirebaseResponse;
60
+ }
61
+ async function getInitFirebaseResponse(rid) {
62
+ const port = getMonospaceDaemonPort();
63
+ if (!port)
64
+ throw new error_1.FirebaseError("Undefined MONOSPACE_DAEMON_PORT");
65
+ const getInitFirebaseRes = await (0, node_fetch_1.default)(`http://localhost:${port}/get-init-firebase-response?rid=${rid}`);
66
+ const getInitFirebaseJson = (await getInitFirebaseRes.json());
67
+ logger_1.logger.debug(`/get-init-firebase-response?rid=${rid} response:`);
68
+ logger_1.logger.debug(getInitFirebaseJson);
69
+ return getInitFirebaseJson;
70
+ }
71
+ function createFirebaseRc(projectDir, authorizedProject) {
72
+ const firebaseRc = (0, rc_1.loadRC)({ cwd: projectDir });
73
+ firebaseRc.addProjectAlias("default", authorizedProject);
74
+ return firebaseRc.save();
75
+ }
76
+ function isMonospaceEnv() {
77
+ return getMonospaceDaemonPort() !== undefined;
78
+ }
79
+ exports.isMonospaceEnv = isMonospaceEnv;
80
+ function getMonospaceDaemonPort() {
81
+ return process.env.MONOSPACE_DAEMON_PORT;
82
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -10,6 +10,7 @@ const logger_1 = require("./logger");
10
10
  const utils = require("./utils");
11
11
  const scopes = require("./scopes");
12
12
  const auth_1 = require("./auth");
13
+ const monospace_1 = require("./monospace");
13
14
  const AUTH_ERROR_MESSAGE = `Command requires authentication, please run ${clc.bold("firebase login")}`;
14
15
  let authClient;
15
16
  function getAuthClient(config) {
@@ -23,6 +24,13 @@ async function autoAuth(options, authScopes) {
23
24
  const client = getAuthClient({ scopes: authScopes, projectId: options.project });
24
25
  const token = await client.getAccessToken();
25
26
  token !== null ? apiv2.setAccessToken(token) : false;
27
+ if (!options.isVSCE && (0, monospace_1.isMonospaceEnv)()) {
28
+ await (0, monospace_1.selectProjectInMonospace)({
29
+ projectRoot: options.config.projectDir,
30
+ project: options.project,
31
+ isVSCE: options.isVSCE,
32
+ });
33
+ }
26
34
  }
27
35
  async function requireAuth(options) {
28
36
  api.setScopes([scopes.CLOUD_PLATFORM, scopes.FIREBASE_PLATFORM]);