firebase-tools 13.0.0-canary.0 → 13.0.0

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 (72) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +0 -0
  3. package/lib/dynamicImport.js +0 -0
  4. package/lib/frameworks/angular/utils.js +8 -0
  5. package/lib/frameworks/constants.js +5 -2
  6. package/lib/gcp/cloudbuild.js +24 -3
  7. package/lib/gcp/storage.js +5 -1
  8. package/lib/init/features/frameworks/index.js +4 -4
  9. package/lib/init/features/frameworks/repo.js +105 -36
  10. package/lib/utils.js +28 -1
  11. package/package.json +1 -1
  12. package/schema/extension-yaml.json +0 -0
  13. package/schema/firebase-config.json +0 -0
  14. package/standalone/check.js +0 -0
  15. package/standalone/config.template.js +0 -0
  16. package/standalone/firepit.js +0 -0
  17. package/standalone/package.json +0 -0
  18. package/standalone/runtime.js +0 -0
  19. package/standalone/welcome.js +0 -0
  20. package/templates/_gitignore +0 -0
  21. package/templates/banner.txt +0 -0
  22. package/templates/emulators/default_storage.rules +0 -0
  23. package/templates/extensions/CL-template.md +0 -0
  24. package/templates/extensions/POSTINSTALL.md +0 -0
  25. package/templates/extensions/PREINSTALL.md +0 -0
  26. package/templates/extensions/extension.yaml +0 -0
  27. package/templates/extensions/integration-test.env +0 -0
  28. package/templates/extensions/integration-test.json +0 -0
  29. package/templates/extensions/javascript/WELCOME.md +0 -0
  30. package/templates/extensions/javascript/_gitignore +0 -0
  31. package/templates/extensions/javascript/index.js +0 -0
  32. package/templates/extensions/javascript/integration-test.js +0 -0
  33. package/templates/extensions/javascript/package.lint.json +0 -0
  34. package/templates/extensions/javascript/package.nolint.json +0 -0
  35. package/templates/extensions/typescript/WELCOME.md +0 -0
  36. package/templates/extensions/typescript/_gitignore +0 -0
  37. package/templates/extensions/typescript/_mocharc +0 -0
  38. package/templates/extensions/typescript/index.ts +0 -0
  39. package/templates/extensions/typescript/integration-test.ts +0 -0
  40. package/templates/extensions/typescript/package.lint.json +0 -0
  41. package/templates/extensions/typescript/package.nolint.json +0 -0
  42. package/templates/extensions/typescript/tsconfig.dev.json +0 -0
  43. package/templates/extensions/typescript/tsconfig.json +0 -0
  44. package/templates/firebase.json +0 -0
  45. package/templates/hosting/init.js +0 -0
  46. package/templates/init/firestore/firestore.indexes.json +0 -0
  47. package/templates/init/firestore/firestore.rules +0 -0
  48. package/templates/init/functions/javascript/_eslintrc +0 -0
  49. package/templates/init/functions/javascript/_gitignore +0 -0
  50. package/templates/init/functions/javascript/index.js +0 -0
  51. package/templates/init/functions/javascript/package.lint.json +0 -0
  52. package/templates/init/functions/javascript/package.nolint.json +0 -0
  53. package/templates/init/functions/python/_gitignore +0 -0
  54. package/templates/init/functions/python/main.py +0 -0
  55. package/templates/init/functions/python/requirements.txt +0 -0
  56. package/templates/init/functions/typescript/_eslintrc +0 -0
  57. package/templates/init/functions/typescript/_gitignore +0 -0
  58. package/templates/init/functions/typescript/index.ts +0 -0
  59. package/templates/init/functions/typescript/package.lint.json +0 -0
  60. package/templates/init/functions/typescript/package.nolint.json +0 -0
  61. package/templates/init/functions/typescript/tsconfig.dev.json +0 -0
  62. package/templates/init/functions/typescript/tsconfig.json +0 -0
  63. package/templates/init/hosting/404.html +0 -0
  64. package/templates/init/hosting/index.html +0 -0
  65. package/templates/init/storage/storage.rules +0 -0
  66. package/templates/loginFailure.html +0 -0
  67. package/templates/loginSuccess.html +0 -0
  68. package/templates/loginSuccessGithub.html +0 -0
  69. package/templates/popup.html +64 -0
  70. package/templates/setup/web.js +0 -0
  71. package/standalone/config.js +0 -19
  72. package/standalone/firepit-log.txt +0 -4
package/LICENSE CHANGED
File without changes
package/README.md CHANGED
File without changes
File without changes
@@ -56,6 +56,7 @@ async function localesForTarget(dir, architectHost, target, workspaceProject) {
56
56
  const DEV_SERVER_TARGETS = [
57
57
  "@angular-devkit/build-angular:dev-server",
58
58
  "@nguniversal/builders:ssr-dev-server",
59
+ "@angular-devkit/build-angular:ssr-dev-server",
59
60
  ];
60
61
  function getValidBuilders(purpose) {
61
62
  return [
@@ -63,6 +64,7 @@ function getValidBuilders(purpose) {
63
64
  "@angular-devkit/build-angular:browser-esbuild",
64
65
  "@angular/fire:deploy",
65
66
  "@angular-devkit/build-angular:browser",
67
+ "@angular-devkit/build-angular:prerender",
66
68
  "@nguniversal/builders:prerender",
67
69
  ...(purpose === "deploy" ? [] : DEV_SERVER_TARGETS),
68
70
  ];
@@ -156,11 +158,13 @@ async function getContext(dir, targetOrConfiguration) {
156
158
  case "@angular-devkit/build-angular:browser":
157
159
  browserTarget = overrideTarget;
158
160
  break;
161
+ case "@angular-devkit/build-angular:prerender":
159
162
  case "@nguniversal/builders:prerender":
160
163
  prerenderTarget = overrideTarget;
161
164
  break;
162
165
  case "@angular-devkit/build-angular:dev-server":
163
166
  case "@nguniversal/builders:ssr-dev-server":
167
+ case "@angular-devkit/build-angular:ssr-dev-server":
164
168
  serveTarget = overrideTarget;
165
169
  break;
166
170
  default:
@@ -299,12 +303,16 @@ async function getContext(dir, targetOrConfiguration) {
299
303
  continue;
300
304
  if (target === browserTarget && builder === "@angular-devkit/build-angular:browser")
301
305
  continue;
306
+ if (target === prerenderTarget && builder === "@angular-devkit/build-angular:prerender")
307
+ continue;
302
308
  if (target === prerenderTarget && builder === "@nguniversal/builders:prerender")
303
309
  continue;
304
310
  if (target === serverTarget && builder === "@angular-devkit/build-angular:server")
305
311
  continue;
306
312
  if (target === serveTarget && builder === "@nguniversal/builders:ssr-dev-server")
307
313
  continue;
314
+ if (target === serveTarget && builder === "@angular-devkit/build-angular:ssr-dev-server")
315
+ continue;
308
316
  if (target === serveTarget && builder === "@angular-devkit/build-angular:dev-server")
309
317
  continue;
310
318
  throw new error_1.FirebaseError(`${definition.builder} (${targetString}) is not a recognized builder. Please check your angular.json`);
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE = exports.GET_DEFAULT_BUILD_TARGETS = exports.I18N_ROOT = exports.ALLOWED_SSR_REGIONS = exports.DEFAULT_REGION = exports.VALID_LOCALE_FORMATS = exports.VALID_ENGINES = exports.NODE_VERSION = exports.SHARP_VERSION = exports.FIREBASE_ADMIN_VERSION = exports.FIREBASE_FUNCTIONS_VERSION = exports.FIREBASE_FRAMEWORKS_VERSION = exports.MAILING_LIST_URL = exports.FEATURE_REQUEST_URL = exports.FILE_BUG_URL = exports.DEFAULT_DOCS_URL = exports.SupportLevelWarnings = exports.NPM_COMMAND_TIMEOUT_MILLIES = void 0;
4
4
  const clc = require("colorette");
5
+ const experiments = require("../experiments");
5
6
  exports.NPM_COMMAND_TIMEOUT_MILLIES = 10000;
6
7
  exports.SupportLevelWarnings = {
7
8
  ["experimental"]: (framework) => `Thank you for trying our ${clc.italic("experimental")} support for ${framework} on Firebase Hosting.
@@ -14,10 +15,12 @@ exports.DEFAULT_DOCS_URL = "https://firebase.google.com/docs/hosting/frameworks/
14
15
  exports.FILE_BUG_URL = "https://github.com/firebase/firebase-tools/issues/new?template=bug_report.md";
15
16
  exports.FEATURE_REQUEST_URL = "https://github.com/firebase/firebase-tools/issues/new?template=feature_request.md";
16
17
  exports.MAILING_LIST_URL = "https://goo.gle/41enW5X";
17
- exports.FIREBASE_FRAMEWORKS_VERSION = "^0.11.0";
18
+ const DEFAULT_FIREBASE_FRAMEWORKS_VERSION = "^0.11.0";
19
+ exports.FIREBASE_FRAMEWORKS_VERSION = (experiments.isEnabled("internaltesting") && process.env.FIREBASE_FRAMEWORKS_VERSION) ||
20
+ DEFAULT_FIREBASE_FRAMEWORKS_VERSION;
18
21
  exports.FIREBASE_FUNCTIONS_VERSION = "^4.5.0";
19
22
  exports.FIREBASE_ADMIN_VERSION = "^11.11.1";
20
- exports.SHARP_VERSION = "^0.33.0";
23
+ exports.SHARP_VERSION = "^0.32.1";
21
24
  exports.NODE_VERSION = parseInt(process.versions.node, 10);
22
25
  exports.VALID_ENGINES = { node: [16, 18, 20] };
23
26
  exports.VALID_LOCALE_FORMATS = [/^ALL_[a-z]+$/, /^[a-z]+_ALL$/, /^[a-z]+(_[a-z]+)?$/];
@@ -1,15 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteRepository = exports.getRepository = exports.createRepository = exports.fetchLinkableRepositories = exports.deleteConnection = exports.getConnection = exports.createConnection = void 0;
3
+ exports.deleteRepository = exports.getRepository = exports.createRepository = exports.fetchLinkableRepositories = exports.deleteConnection = exports.listConnections = exports.getConnection = exports.createConnection = void 0;
4
4
  const apiv2_1 = require("../apiv2");
5
5
  const api_1 = require("../api");
6
+ const PAGE_SIZE_MAX = 100;
6
7
  const client = new apiv2_1.Client({
7
8
  urlPrefix: api_1.cloudbuildOrigin,
8
9
  auth: true,
9
10
  apiVersion: "v2",
10
11
  });
11
- async function createConnection(projectId, location, connectionId) {
12
- const res = await client.post(`projects/${projectId}/locations/${location}/connections`, { githubConfig: {} }, { queryParams: { connectionId } });
12
+ async function createConnection(projectId, location, connectionId, githubConfig = {}) {
13
+ const res = await client.post(`projects/${projectId}/locations/${location}/connections`, { githubConfig }, { queryParams: { connectionId } });
13
14
  return res.body;
14
15
  }
15
16
  exports.createConnection = createConnection;
@@ -19,6 +20,26 @@ async function getConnection(projectId, location, connectionId) {
19
20
  return res.body;
20
21
  }
21
22
  exports.getConnection = getConnection;
23
+ async function listConnections(projectId, location) {
24
+ const conns = [];
25
+ const getNextPage = async (pageToken = "") => {
26
+ const res = await client.get(`/projects/${projectId}/locations/${location}/connections`, {
27
+ queryParams: {
28
+ pageSize: PAGE_SIZE_MAX,
29
+ pageToken,
30
+ },
31
+ });
32
+ if (Array.isArray(res.body.connections)) {
33
+ conns.push(...res.body.connections);
34
+ }
35
+ if (res.body.nextPageToken) {
36
+ await getNextPage(res.body.nextPageToken);
37
+ }
38
+ };
39
+ await getNextPage();
40
+ return conns;
41
+ }
42
+ exports.listConnections = listConnections;
22
43
  async function deleteConnection(projectId, location, connectionId) {
23
44
  const name = `projects/${projectId}/locations/${location}/connections/${connectionId}`;
24
45
  const res = await client.delete(name);
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getServiceAccount = exports.listBuckets = exports.getBucket = exports.deleteObject = exports.uploadObject = exports.upload = exports.getDefaultBucket = void 0;
4
4
  const path = require("path");
5
+ const clc = require("colorette");
5
6
  const api_1 = require("../api");
6
7
  const apiv2_1 = require("../apiv2");
7
8
  const error_1 = require("../error");
@@ -20,7 +21,10 @@ async function getDefaultBucket(projectId) {
20
21
  return response.body.bucket.name.split("/").pop();
21
22
  }
22
23
  catch (err) {
23
- 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.");
24
+ if ((err === null || err === void 0 ? void 0 : err.status) === 404) {
25
+ throw new error_1.FirebaseError(`Firebase Storage has not been set up on project '${clc.bold(projectId)}'. Go to https://console.firebase.google.com/project/${projectId}/storage and click 'Get Started' to set up Firebase Storage.`);
26
+ }
27
+ logger_1.logger.info("\n\nUnexpected error when fetching default storage bucket.");
24
28
  throw err;
25
29
  }
26
30
  }
@@ -3,15 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createBackend = exports.getOrCreateBackend = exports.doSetup = void 0;
4
4
  const clc = require("colorette");
5
5
  const utils = require("../../../utils");
6
- const logger_1 = require("../../../logger");
7
- const prompt_1 = require("../../../prompt");
8
- const constants_1 = require("./constants");
9
6
  const repo = require("./repo");
10
7
  const poller = require("../../../operation-poller");
11
- const api_1 = require("../../../api");
12
8
  const gcp = require("../../../gcp/frameworks");
9
+ const api_1 = require("../../../api");
13
10
  const frameworks_1 = require("../../../gcp/frameworks");
14
11
  const error_1 = require("../../../error");
12
+ const logger_1 = require("../../../logger");
13
+ const prompt_1 = require("../../../prompt");
14
+ const constants_1 = require("./constants");
15
15
  const frameworksPollerOptions = {
16
16
  apiOrigin: api_1.frameworksOrigin,
17
17
  apiVersion: frameworks_1.API_VERSION,
@@ -1,21 +1,37 @@
1
1
  "use strict";
2
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");
3
+ exports.listFrameworksConnections = exports.getOrCreateRepository = exports.getOrCreateConnection = exports.createConnection = exports.linkGitHubRepository = exports.parseConnectionName = void 0;
4
+ const clc = require("colorette");
6
5
  const gcb = require("../../../gcp/cloudbuild");
7
- const logger_1 = require("../../../logger");
8
6
  const poller = require("../../../operation-poller");
9
7
  const utils = require("../../../utils");
8
+ const api_1 = require("../../../api");
9
+ const error_1 = require("../../../error");
10
+ const logger_1 = require("../../../logger");
10
11
  const prompt_1 = require("../../../prompt");
11
- const clc = require("colorette");
12
+ const FRAMEWORKS_CONN_PATTERN = /.+\/frameworks-github-conn-.+$/;
13
+ const FRAMEWORKS_OAUTH_CONN_NAME = "frameworks-github-oauth";
14
+ const CONNECTION_NAME_REGEX = /^projects\/(?<projectId>[^\/]+)\/locations\/(?<location>[^\/]+)\/connections\/(?<id>[^\/]+)$/;
15
+ function parseConnectionName(name) {
16
+ const match = name.match(CONNECTION_NAME_REGEX);
17
+ if (!match || typeof match.groups === undefined) {
18
+ return;
19
+ }
20
+ const { projectId, location, id } = match.groups;
21
+ return {
22
+ projectId,
23
+ location,
24
+ id,
25
+ };
26
+ }
27
+ exports.parseConnectionName = parseConnectionName;
12
28
  const gcbPollerOptions = {
13
29
  apiOrigin: api_1.cloudbuildOrigin,
14
30
  apiVersion: "v2",
15
31
  masterTimeout: 25 * 60 * 1000,
16
32
  maxBackoff: 10000,
17
33
  };
18
- function extractRepoSlugFromURI(remoteUri) {
34
+ function extractRepoSlugFromUri(remoteUri) {
19
35
  const match = /github.com\/(.+).git/.exec(remoteUri);
20
36
  if (!match) {
21
37
  return undefined;
@@ -24,77 +40,123 @@ function extractRepoSlugFromURI(remoteUri) {
24
40
  }
25
41
  function generateRepositoryId(remoteUri) {
26
42
  var _a;
27
- return (_a = extractRepoSlugFromURI(remoteUri)) === null || _a === void 0 ? void 0 : _a.replaceAll("/", "-");
43
+ return (_a = extractRepoSlugFromUri(remoteUri)) === null || _a === void 0 ? void 0 : _a.replaceAll("/", "-");
28
44
  }
29
- function generateConnectionId(location) {
30
- return `frameworks-${location}`;
45
+ function generateConnectionId() {
46
+ const randomHash = Math.random().toString(36).slice(6);
47
+ return `frameworks-github-conn-${randomHash}`;
31
48
  }
32
49
  async function linkGitHubRepository(projectId, location) {
33
- logger_1.logger.info(clc.bold(`\n${clc.white("===")} Connect a github repository`));
34
- const connectionId = generateConnectionId(location);
35
- await getOrCreateConnection(projectId, location, connectionId);
36
- let remoteUri = await promptRepositoryURI(projectId, location, connectionId);
50
+ var _a, _b, _c;
51
+ logger_1.logger.info(clc.bold(`\n${clc.yellow("===")} Connect a GitHub repository`));
52
+ const existingConns = await listFrameworksConnections(projectId);
53
+ if (existingConns.length < 1) {
54
+ let oauthConn = await getOrCreateConnection(projectId, location, FRAMEWORKS_OAUTH_CONN_NAME);
55
+ while (oauthConn.installationState.stage === "PENDING_USER_OAUTH") {
56
+ oauthConn = await promptConnectionAuth(oauthConn);
57
+ }
58
+ const connectionId = generateConnectionId();
59
+ const conn = await createConnection(projectId, location, connectionId, {
60
+ authorizerCredential: (_a = oauthConn.githubConfig) === null || _a === void 0 ? void 0 : _a.authorizerCredential,
61
+ });
62
+ let refreshedConn = conn;
63
+ while (refreshedConn.installationState.stage !== "COMPLETE") {
64
+ refreshedConn = await promptAppInstall(conn);
65
+ }
66
+ existingConns.push(refreshedConn);
67
+ }
68
+ let { remoteUri, connection } = await promptRepositoryUri(projectId, location, existingConns);
37
69
  while (remoteUri === "") {
38
70
  await utils.openInBrowser("https://github.com/apps/google-cloud-build/installations/new");
39
71
  await (0, prompt_1.promptOnce)({
40
72
  type: "input",
41
73
  message: "Press ENTER once you have finished configuring your installation's access settings.",
42
74
  });
43
- remoteUri = await promptRepositoryURI(projectId, location, connectionId);
75
+ const selection = await promptRepositoryUri(projectId, location, existingConns);
76
+ remoteUri = selection.remoteUri;
77
+ connection = selection.connection;
44
78
  }
79
+ const { id: connectionId } = parseConnectionName(connection.name);
80
+ await getOrCreateConnection(projectId, location, connectionId, {
81
+ authorizerCredential: (_b = connection.githubConfig) === null || _b === void 0 ? void 0 : _b.authorizerCredential,
82
+ appInstallationId: (_c = connection.githubConfig) === null || _c === void 0 ? void 0 : _c.appInstallationId,
83
+ });
45
84
  const repo = await getOrCreateRepository(projectId, location, connectionId, remoteUri);
46
85
  logger_1.logger.info();
47
86
  utils.logSuccess(`Successfully linked GitHub repository at remote URI:\n ${remoteUri}`);
48
87
  return repo;
49
88
  }
50
89
  exports.linkGitHubRepository = linkGitHubRepository;
51
- async function promptRepositoryURI(projectId, location, connectionId) {
52
- const resp = await gcb.fetchLinkableRepositories(projectId, location, connectionId);
53
- if (!resp.repositories || resp.repositories.length === 0) {
54
- throw new error_1.FirebaseError("The GitHub App does not have access to any repositories. Please configure " +
55
- "your app installation permissions at https://github.com/settings/installations.");
90
+ async function promptRepositoryUri(projectId, location, connections) {
91
+ const remoteUriToConnection = {};
92
+ for (const conn of connections) {
93
+ const { id } = parseConnectionName(conn.name);
94
+ const resp = await gcb.fetchLinkableRepositories(projectId, location, id);
95
+ if (resp.repositories && resp.repositories.length > 1) {
96
+ for (const repo of resp.repositories) {
97
+ remoteUriToConnection[repo.remoteUri] = conn;
98
+ }
99
+ }
56
100
  }
57
- const choices = resp.repositories.map((repo) => ({
58
- name: extractRepoSlugFromURI(repo.remoteUri) || repo.remoteUri,
59
- value: repo.remoteUri,
101
+ const choices = Object.keys(remoteUriToConnection).map((remoteUri) => ({
102
+ name: extractRepoSlugFromUri(remoteUri) || remoteUri,
103
+ value: remoteUri,
60
104
  }));
61
105
  choices.push({
62
106
  name: "Missing a repo? Select this option to configure your installation's access settings",
63
107
  value: "",
64
108
  });
65
- return await (0, prompt_1.promptOnce)({
109
+ const remoteUri = await (0, prompt_1.promptOnce)({
66
110
  type: "list",
67
111
  message: "Which of the following repositories would you like to deploy?",
68
112
  choices,
69
113
  });
114
+ return { remoteUri, connection: remoteUriToConnection[remoteUri] };
115
+ }
116
+ async function promptConnectionAuth(conn) {
117
+ logger_1.logger.info("You must authorize the Cloud Build GitHub app.");
118
+ logger_1.logger.info();
119
+ logger_1.logger.info("First, sign in to GitHub and authorize Cloud Build GitHub app:");
120
+ const cleanup = await utils.openInBrowserPopup(conn.installationState.actionUri, "Authorize the GitHub app");
121
+ await (0, prompt_1.promptOnce)({
122
+ type: "input",
123
+ message: "Press Enter once you have authorized the app",
124
+ });
125
+ cleanup();
126
+ const { projectId, location, id } = parseConnectionName(conn.name);
127
+ return await gcb.getConnection(projectId, location, id);
70
128
  }
71
- async function promptConnectionAuth(conn, projectId, location, connectionId) {
72
- logger_1.logger.info("First, log in to GitHub, install and authorize Cloud Build app:");
73
- logger_1.logger.info(conn.installationState.actionUri);
74
- await utils.openInBrowser(conn.installationState.actionUri);
129
+ async function promptAppInstall(conn) {
130
+ logger_1.logger.info("Now, install the Cloud Build GitHub app:");
131
+ const targetUri = conn.installationState.actionUri.replace("install_v2", "direct_install_v2");
132
+ logger_1.logger.info(targetUri);
133
+ await utils.openInBrowser(targetUri);
75
134
  await (0, prompt_1.promptOnce)({
76
135
  type: "input",
77
- message: "Press Enter once you have authorized the app (Cloud Build) to access your GitHub repo.",
136
+ message: "Press Enter once you have installed or configured the Cloud Build GitHub app to access your GitHub repo.",
78
137
  });
79
- return await gcb.getConnection(projectId, location, connectionId);
138
+ const { projectId, location, id } = parseConnectionName(conn.name);
139
+ return await gcb.getConnection(projectId, location, id);
140
+ }
141
+ async function createConnection(projectId, location, connectionId, githubConfig) {
142
+ const op = await gcb.createConnection(projectId, location, connectionId, githubConfig);
143
+ const conn = await poller.pollOperation(Object.assign(Object.assign({}, gcbPollerOptions), { pollerName: `create-${location}-${connectionId}`, operationResourceName: op.name }));
144
+ return conn;
80
145
  }
81
- async function getOrCreateConnection(projectId, location, connectionId) {
146
+ exports.createConnection = createConnection;
147
+ async function getOrCreateConnection(projectId, location, connectionId, githubConfig) {
82
148
  let conn;
83
149
  try {
84
150
  conn = await gcb.getConnection(projectId, location, connectionId);
85
151
  }
86
152
  catch (err) {
87
153
  if (err.status === 404) {
88
- const op = await gcb.createConnection(projectId, location, connectionId);
89
- conn = await poller.pollOperation(Object.assign(Object.assign({}, gcbPollerOptions), { pollerName: `create-${location}-${connectionId}`, operationResourceName: op.name }));
154
+ conn = await createConnection(projectId, location, connectionId, githubConfig);
90
155
  }
91
156
  else {
92
157
  throw err;
93
158
  }
94
159
  }
95
- while (conn.installationState.stage !== "COMPLETE") {
96
- conn = await promptConnectionAuth(conn, projectId, location, connectionId);
97
- }
98
160
  return conn;
99
161
  }
100
162
  exports.getOrCreateConnection = getOrCreateConnection;
@@ -106,7 +168,7 @@ async function getOrCreateRepository(projectId, location, connectionId, remoteUr
106
168
  let repo;
107
169
  try {
108
170
  repo = await gcb.getRepository(projectId, location, connectionId, repositoryId);
109
- const repoSlug = extractRepoSlugFromURI(repo.remoteUri);
171
+ const repoSlug = extractRepoSlugFromUri(repo.remoteUri);
110
172
  if (repoSlug) {
111
173
  throw new error_1.FirebaseError(`${repoSlug} has already been linked.`);
112
174
  }
@@ -123,3 +185,10 @@ async function getOrCreateRepository(projectId, location, connectionId, remoteUr
123
185
  return repo;
124
186
  }
125
187
  exports.getOrCreateRepository = getOrCreateRepository;
188
+ async function listFrameworksConnections(projectId) {
189
+ const conns = await gcb.listConnections(projectId, "-");
190
+ return conns.filter((conn) => FRAMEWORKS_CONN_PATTERN.test(conn.name) &&
191
+ conn.installationState.stage === "COMPLETE" &&
192
+ !conn.disabled);
193
+ }
194
+ exports.listFrameworksConnections = listFrameworksConnections;
package/lib/utils.js CHANGED
@@ -1,8 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.openInBrowser = exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isVSCodeExtension = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.withTimeout = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
3
+ exports.openInBrowserPopup = exports.openInBrowser = exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isVSCodeExtension = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.withTimeout = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
4
6
  const _ = require("lodash");
5
7
  const url = require("url");
8
+ const http = require("http");
6
9
  const clc = require("colorette");
7
10
  const open = require("open");
8
11
  const ora = require("ora");
@@ -12,6 +15,7 @@ const winston = require("winston");
12
15
  const triple_beam_1 = require("triple-beam");
13
16
  const assert_1 = require("assert");
14
17
  const stripAnsi = require("strip-ansi");
18
+ const portfinder_1 = require("portfinder");
15
19
  const configstore_1 = require("./configstore");
16
20
  const error_1 = require("./error");
17
21
  const logger_1 = require("./logger");
@@ -486,3 +490,26 @@ async function openInBrowser(url) {
486
490
  await open(url);
487
491
  }
488
492
  exports.openInBrowser = openInBrowser;
493
+ async function openInBrowserPopup(url, buttonText) {
494
+ const popupPage = fs
495
+ .readFileSync(path.join(__dirname, "../templates/popup.html"), { encoding: "utf-8" })
496
+ .replace("${url}", url)
497
+ .replace("${buttonText}", buttonText);
498
+ const port = await (0, portfinder_1.getPortPromise)();
499
+ const server = http.createServer((req, res) => {
500
+ res.writeHead(200, {
501
+ "Content-Length": popupPage.length,
502
+ "Content-Type": "text/html",
503
+ });
504
+ res.end(popupPage);
505
+ req.socket.destroy();
506
+ });
507
+ server.listen(port);
508
+ const popupPageUri = `http://localhost:${port}`;
509
+ logger_1.logger.info(popupPageUri);
510
+ await openInBrowser(popupPageUri);
511
+ return () => {
512
+ server.close();
513
+ };
514
+ }
515
+ exports.openInBrowserPopup = openInBrowserPopup;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "13.0.0-canary.0",
3
+ "version": "13.0.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,64 @@
1
+ <head>
2
+ <style>
3
+ div {
4
+ font-family: sans-serif;
5
+ }
6
+ #popup {
7
+ display: flex;
8
+ flex-direction: column;
9
+ justify-content: center;
10
+ align-items: center;
11
+ height: 100vh;
12
+ width: 100vw;
13
+ text-align: center;
14
+ }
15
+ #popup button {
16
+ display: inline-flex;
17
+ align-items: center;
18
+ justify-content: center;
19
+ border-radius: 0.375rem;
20
+ font-size: 1.5rem;
21
+ font-weight: 500;
22
+ height: 2.5rem;
23
+ padding: 0.5rem 1rem;
24
+ background-color: black;
25
+ color: white;
26
+ outline: none;
27
+ transition: background-color 150ms ease-in-out;
28
+ margin-bottom: 20px;
29
+ }
30
+ #popup button:hover {
31
+ background-color: #333;
32
+ }
33
+ #popup button:disabled {
34
+ opacity: 0.5;
35
+ pointer-events: none;
36
+ }
37
+ #message {
38
+ height: 20px;
39
+ margin-bottom: 20px;
40
+ color: gray;
41
+ font-size: 1.5rem;
42
+ }
43
+ </style>
44
+ </head>
45
+ <body>
46
+ <div id="popup">
47
+ <button id="popupBtn" onclick="openPopup()">${buttonText}</button>
48
+ <div id="message">(Close this window after authorizing the app)</div>
49
+ </div>
50
+ <script>
51
+ function openPopup() {
52
+ var w = window.open("${url}", "newwindow", "popup=1");
53
+ var m = document.getElementById("message");
54
+ var d = document.getElementById("popupBtn");
55
+ var timer = setInterval(function () {
56
+ if (w.closed) {
57
+ m.innerText = "You can close this page now";
58
+ d.disabled = true;
59
+ clearInterval(timer);
60
+ }
61
+ }, 1000);
62
+ }
63
+ </script>
64
+ </body>
File without changes
@@ -1,19 +0,0 @@
1
- module.exports = {
2
- /*
3
- Headless mode forces the firepit builds to exactly imitate firebase-tools,
4
- so the resulting binary "firebase" is a drop in replacement for the script
5
- installed via npm. This is the behavior for CI / Cloud Shell / Docker etc.
6
-
7
- When headless mode is disabled, the "double click" experience is enabled
8
- which allows the binary to spawn a terminal on Windows and Mac. The is the
9
- behavior for desktop users.
10
- */
11
- headless: true,
12
-
13
- /*
14
- This is generally set to "firebase-tools@latest" however a custom value
15
- can be supplied for EAPs which would like to have builds pointed at
16
- specific tgz bundles.
17
- */
18
- firebase_tools_package: "firebase-tools@latest"
19
- };
@@ -1,4 +0,0 @@
1
- Welcome to firepit v1.1.0!
2
- Doing JSON parses for version checks at /snapshot/joehanley/Workspace/firebase-tools/standalone/vendor/node_modules/firebase-tools/package.json
3
-
4
- SyntaxError: Unexpected end of JSON input