firebase-tools 13.20.1 → 13.21.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 (36) hide show
  1. package/lib/apphosting/githubConnections.js +19 -1
  2. package/lib/apphosting/index.js +12 -46
  3. package/lib/apphosting/rollout.js +127 -0
  4. package/lib/command.js +10 -3
  5. package/lib/commands/apphosting-rollouts-create.js +13 -13
  6. package/lib/commands/emulators-start.js +1 -1
  7. package/lib/config.js +14 -4
  8. package/lib/dataconnect/fileUtils.js +7 -43
  9. package/lib/dataconnect/freeTrial.js +44 -10
  10. package/lib/dataconnect/provisionCloudSql.js +4 -4
  11. package/lib/dataconnect/types.js +3 -2
  12. package/lib/dataconnect/webhook.js +2 -1
  13. package/lib/deploy/dataconnect/prepare.js +5 -0
  14. package/lib/emulator/apphosting/config.js +45 -0
  15. package/lib/emulator/apphosting/index.js +9 -11
  16. package/lib/emulator/apphosting/serve.js +16 -10
  17. package/lib/emulator/apphosting/utils.js +18 -0
  18. package/lib/emulator/controller.js +6 -1
  19. package/lib/emulator/downloadableEmulators.js +12 -12
  20. package/lib/emulator/eventarcEmulator.js +1 -1
  21. package/lib/emulator/extensionsEmulator.js +38 -6
  22. package/lib/emulator/functionsEmulator.js +85 -41
  23. package/lib/emulator/functionsEmulatorShared.js +2 -1
  24. package/lib/error.js +24 -1
  25. package/lib/extensions/emulator/triggerHelper.js +1 -1
  26. package/lib/extensions/extensionsApi.js +11 -8
  27. package/lib/extensions/runtimes/common.js +11 -19
  28. package/lib/extensions/runtimes/node.js +25 -22
  29. package/lib/extensions/types.js +16 -1
  30. package/lib/gcp/cloudmonitoring.js +3 -3
  31. package/lib/gcp/cloudsql/cloudsqladmin.js +32 -20
  32. package/lib/gcp/devConnect.js +38 -1
  33. package/lib/init/features/dataconnect/index.js +69 -85
  34. package/lib/init/features/dataconnect/sdk.js +69 -86
  35. package/lib/init/spawn.js +2 -1
  36. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.longestCommonPrefix = exports.snakeToCamelCase = exports.lowercaseFirstLetter = exports.capitalizeFirstLetter = exports.toTitleCase = exports.getInstallPathPrefix = exports.getCodebaseDir = exports.writeSDK = exports.getCodebaseRuntime = exports.copyDirectory = exports.writeFile = exports.isTypescriptCodebase = exports.extensionMatchesAnyFilter = exports.extractExtensionsFromBuilds = exports.getErrorMessage = exports.fixDarkBlueText = void 0;
3
+ exports.longestCommonPrefix = exports.snakeToCamelCase = exports.lowercaseFirstLetter = exports.capitalizeFirstLetter = exports.toTitleCase = exports.getInstallPathPrefix = exports.getCodebaseDir = exports.writeSDK = exports.getCodebaseRuntime = exports.copyDirectory = exports.writeFile = exports.isTypescriptCodebase = exports.extensionMatchesAnyFilter = exports.extractExtensionsFromBuilds = exports.fixDarkBlueText = void 0;
4
4
  const fs = require("fs");
5
5
  const path = require("path");
6
6
  const prompt_1 = require("../../prompt");
@@ -8,7 +8,6 @@ const fsutils = require("../../fsutils");
8
8
  const utils_1 = require("../../utils");
9
9
  const error_1 = require("../../error");
10
10
  const projectConfig_1 = require("../../functions/projectConfig");
11
- const types_1 = require("../types");
12
11
  const functionRuntimes = require("../../deploy/functions/runtimes");
13
12
  const nodeRuntime = require("./node");
14
13
  function fixDarkBlueText(txt) {
@@ -17,15 +16,6 @@ function fixDarkBlueText(txt) {
17
16
  return txt.replaceAll(DARK_BLUE, BRIGHT_CYAN);
18
17
  }
19
18
  exports.fixDarkBlueText = fixDarkBlueText;
20
- function getErrorMessage(err, defaultMsg) {
21
- if ((0, types_1.isObject)(err) && err.message && typeof err.message === "string") {
22
- return err.message;
23
- }
24
- else {
25
- return defaultMsg;
26
- }
27
- }
28
- exports.getErrorMessage = getErrorMessage;
29
19
  function extractExtensionsFromBuilds(builds, filters) {
30
20
  const extRecords = {};
31
21
  for (const [codebase, build] of Object.entries(builds)) {
@@ -80,7 +70,7 @@ async function writeFile(filePath, data, options) {
80
70
  (0, utils_1.logLabeledBullet)("extensions", `successfully wrote ${shortFilePath}`);
81
71
  }
82
72
  catch (err) {
83
- throw new error_1.FirebaseError(`Failed to write ${shortFilePath}:\n ${err}`);
73
+ throw new error_1.FirebaseError(`Failed to write ${shortFilePath}:\n ${(0, error_1.getErrMsg)(err)}`);
84
74
  }
85
75
  }
86
76
  else {
@@ -95,11 +85,11 @@ async function writeFile(filePath, data, options) {
95
85
  (0, utils_1.logLabeledBullet)("extensions", `successfully created ${shortFilePath}`);
96
86
  }
97
87
  catch (err) {
98
- throw new error_1.FirebaseError(`Failed to create ${shortFilePath}:\n ${err}`);
88
+ throw new error_1.FirebaseError(`Failed to create ${shortFilePath}:\n ${(0, error_1.getErrMsg)(err)}`);
99
89
  }
100
90
  }
101
91
  catch (err) {
102
- throw new error_1.FirebaseError(`Error during SDK file creation:\n ${err}`);
92
+ throw new error_1.FirebaseError(`Error during SDK file creation:\n ${(0, error_1.getErrMsg)(err)}`);
103
93
  }
104
94
  }
105
95
  }
@@ -121,14 +111,14 @@ async function copyDirectory(src, dest, options) {
121
111
  if (srcPath.includes("node_modules")) {
122
112
  continue;
123
113
  }
124
- await copyDirectory(srcPath, destPath, { force: true });
114
+ await copyDirectory(srcPath, destPath, Object.assign(Object.assign({}, options), { force: true }));
125
115
  }
126
116
  else if (entry.isFile())
127
117
  try {
128
118
  await fs.promises.copyFile(srcPath, destPath);
129
119
  }
130
120
  catch (err) {
131
- throw new error_1.FirebaseError(`Failed to copy ${destPath.replace(process.cwd(), ".")}:\n ${err}`);
121
+ throw new error_1.FirebaseError(`Failed to copy ${destPath.replace(process.cwd(), ".")}:\n ${(0, error_1.getErrMsg)(err)}`);
132
122
  }
133
123
  }
134
124
  }
@@ -137,9 +127,8 @@ async function copyDirectory(src, dest, options) {
137
127
  }
138
128
  }
139
129
  else {
140
- await fs.promises.mkdir(dest, { recursive: true }).then(async () => {
141
- await copyDirectory(src, dest, { force: true });
142
- });
130
+ await fs.promises.mkdir(dest, { recursive: true });
131
+ await copyDirectory(src, dest, Object.assign(Object.assign({}, options), { force: true }));
143
132
  }
144
133
  }
145
134
  exports.copyDirectory = copyDirectory;
@@ -177,6 +166,9 @@ async function writeSDK(extensionRef, localPath, spec, options) {
177
166
  }
178
167
  exports.writeSDK = writeSDK;
179
168
  function getCodebaseDir(options) {
169
+ if (!options.projectRoot) {
170
+ throw new error_1.FirebaseError("Unable to determine root directory of project");
171
+ }
180
172
  const config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
181
173
  const codebaseConfig = (0, projectConfig_1.configForCodebase)(config, options.codebase || projectConfig_1.DEFAULT_CODEBASE);
182
174
  return `${options.projectRoot}/${codebaseConfig.source}/`;
@@ -1,18 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.writeSDK = exports.TYPESCRIPT_VERSION = exports.FIREBASE_FUNCTIONS_VERSION = exports.SDK_GENERATION_VERSION = void 0;
4
+ const path = require("path");
5
+ const child_process_1 = require("child_process");
6
+ const marked_terminal_1 = require("marked-terminal");
7
+ const marked_1 = require("marked");
4
8
  const types_1 = require("../types");
5
9
  const prompt_1 = require("../../prompt");
6
10
  const secretsUtils = require("../secretsUtils");
7
- const child_process_1 = require("child_process");
8
11
  const utils_1 = require("../../utils");
9
- const path = require("path");
10
12
  const common_1 = require("./common");
11
13
  const askUserForEventsConfig_1 = require("../askUserForEventsConfig");
12
14
  const extensionsHelper_1 = require("../extensionsHelper");
13
15
  const error_1 = require("../../error");
14
- const marked_terminal_1 = require("marked-terminal");
15
- const marked_1 = require("marked");
16
16
  marked_1.marked.use((0, marked_terminal_1.markedTerminal)());
17
17
  exports.SDK_GENERATION_VERSION = "1.0.0";
18
18
  exports.FIREBASE_FUNCTIONS_VERSION = ">=5.1.0";
@@ -67,7 +67,7 @@ function makeClassName(name) {
67
67
  function makeEventName(name, prefix) {
68
68
  let eventName;
69
69
  const versionedEvent = /^(?:[^.]+[.])+(?:[vV]\d+[.])(?<event>.*)$/;
70
- const match = name.match(versionedEvent);
70
+ const match = versionedEvent.exec(name);
71
71
  if (match) {
72
72
  eventName = match[1];
73
73
  }
@@ -79,7 +79,7 @@ function makeEventName(name, prefix) {
79
79
  eventName = parts[parts.length - 1];
80
80
  }
81
81
  const allCaps = /^[A-Z._-]+$/;
82
- eventName = eventName.match(allCaps) ? eventName : eventName.replace(/([A-Z])/g, " $1").trim();
82
+ eventName = allCaps.exec(eventName) ? eventName : eventName.replace(/([A-Z])/g, " $1").trim();
83
83
  eventName = eventName.replace(/[._-]/g, " ");
84
84
  eventName = eventName.toLowerCase().startsWith("on") ? eventName : "on " + eventName;
85
85
  eventName = eventName.replace(/\w\S*/g, common_1.toTitleCase);
@@ -87,6 +87,15 @@ function makeEventName(name, prefix) {
87
87
  eventName = eventName.charAt(0).toLowerCase() + eventName.substring(1);
88
88
  return eventName;
89
89
  }
90
+ function addPeerDependency(pkgJson, dependency, version) {
91
+ if (!pkgJson.peerDependencies) {
92
+ pkgJson.peerDependencies = {};
93
+ }
94
+ if (!(0, types_1.isObject)(pkgJson.peerDependencies)) {
95
+ throw new error_1.FirebaseError("Internal error generating peer dependencies.");
96
+ }
97
+ pkgJson.peerDependencies[dependency] = version;
98
+ }
90
99
  async function writeSDK(extensionRef, localPath, spec, options) {
91
100
  var _a, _b, _c;
92
101
  const sdkLines = [];
@@ -105,7 +114,7 @@ async function writeSDK(extensionRef, localPath, spec, options) {
105
114
  })) {
106
115
  const newLocalPath = path.join(dirPath, "src");
107
116
  await (0, common_1.copyDirectory)(localPath, newLocalPath, options);
108
- localPath = newLocalPath.replace(options.projectRoot, ".");
117
+ localPath = newLocalPath.replace(options.projectRoot || ".", ".");
109
118
  }
110
119
  }
111
120
  if (!dirPath) {
@@ -115,7 +124,7 @@ async function writeSDK(extensionRef, localPath, spec, options) {
115
124
  const pkgJson = {
116
125
  name: packageName,
117
126
  version: `${exports.SDK_GENERATION_VERSION}`,
118
- description: `Generated SDK for ${spec.displayName}@${spec.version}`,
127
+ description: `Generated SDK for ${spec.displayName || spec.name}@${spec.version}`,
119
128
  main: "./output/index.js",
120
129
  private: true,
121
130
  scripts: {
@@ -138,7 +147,7 @@ async function writeSDK(extensionRef, localPath, spec, options) {
138
147
  },
139
148
  };
140
149
  sdkLines.push("/**");
141
- sdkLines.push(` * ${spec.displayName} SDK for ${spec.name}@${spec.version}`);
150
+ sdkLines.push(` * ${spec.displayName || spec.name} SDK for ${spec.name}@${spec.version}`);
142
151
  sdkLines.push(" *");
143
152
  sdkLines.push(" * When filing bugs or feature requests please specify:");
144
153
  if (extensionRef) {
@@ -155,18 +164,12 @@ async function writeSDK(extensionRef, localPath, spec, options) {
155
164
  if (hasEvents) {
156
165
  sdkLines.push(`import { CloudEvent } from "firebase-functions/v2";`);
157
166
  sdkLines.push(`import { onCustomEventPublished, EventarcTriggerOptions } from "firebase-functions/v2/eventarc";`);
158
- if (!pkgJson.peerDependencies) {
159
- pkgJson.peerDependencies = {};
160
- }
161
- pkgJson.peerDependencies["firebase-functions"] = exports.FIREBASE_FUNCTIONS_VERSION;
167
+ addPeerDependency(pkgJson, "firebase-functions", exports.FIREBASE_FUNCTIONS_VERSION);
162
168
  }
163
169
  const usesSecrets = secretsUtils.usesSecrets(spec);
164
170
  if (usesSecrets) {
165
171
  sdkLines.push(`import { defineSecret } from "firebase-functions/params";`);
166
- if (!pkgJson.peerDependencies) {
167
- pkgJson.peerDependencies = {};
168
- }
169
- pkgJson.peerDependencies["firebase-functions"] = exports.FIREBASE_FUNCTIONS_VERSION;
172
+ addPeerDependency(pkgJson, "firebase-functions", exports.FIREBASE_FUNCTIONS_VERSION);
170
173
  }
171
174
  if (hasEvents || usesSecrets) {
172
175
  sdkLines.push("");
@@ -289,7 +292,7 @@ async function writeSDK(extensionRef, localPath, spec, options) {
289
292
  sdkLines.push(` ${sysParam.param}${opt}: string;`);
290
293
  break;
291
294
  default:
292
- throw new error_1.FirebaseError(`Error: Unknown systemParam type: ${sysParam.type}.`);
295
+ throw new error_1.FirebaseError(`Error: Unknown systemParam type: ${sysParam.type || "undefined"}.`);
293
296
  }
294
297
  sdkLines.push("");
295
298
  }
@@ -299,7 +302,7 @@ async function writeSDK(extensionRef, localPath, spec, options) {
299
302
  sdkLines.push(` return new ${className}(instanceId, params);`);
300
303
  sdkLines.push("}\n");
301
304
  sdkLines.push(`/**`);
302
- sdkLines.push(` * ${spec.displayName}`);
305
+ sdkLines.push(` * ${spec.displayName || spec.name}`);
303
306
  (_c = spec.description) === null || _c === void 0 ? void 0 : _c.split("\n").forEach((val) => {
304
307
  sdkLines.push(` * ${val.replace(/\*\//g, "* /")}`);
305
308
  });
@@ -347,7 +350,7 @@ async function writeSDK(extensionRef, localPath, spec, options) {
347
350
  (0, child_process_1.execFileSync)("npm", ["--prefix", dirPath, "install"]);
348
351
  }
349
352
  catch (err) {
350
- const errMsg = (0, common_1.getErrorMessage)(err, "unknown error");
353
+ const errMsg = (0, error_1.getErrMsg)(err, "unknown error");
351
354
  throw new error_1.FirebaseError(`Error during npm install in ${shortDirPath}: ${errMsg}`);
352
355
  }
353
356
  (0, utils_1.logLabeledBullet)("extensions", `running 'npm --prefix ${shortDirPath} run build'`);
@@ -355,7 +358,7 @@ async function writeSDK(extensionRef, localPath, spec, options) {
355
358
  (0, child_process_1.execFileSync)("npm", ["--prefix", dirPath, "run", "build"]);
356
359
  }
357
360
  catch (err) {
358
- const errMsg = (0, common_1.getErrorMessage)(err, "unknown error");
361
+ const errMsg = (0, error_1.getErrMsg)(err, "unknown error");
359
362
  throw new error_1.FirebaseError(`Error during npm run build in ${shortDirPath}: ${errMsg}`);
360
363
  }
361
364
  const codebaseDir = (0, common_1.getCodebaseDir)(options);
@@ -372,7 +375,7 @@ async function writeSDK(extensionRef, localPath, spec, options) {
372
375
  (0, child_process_1.execFileSync)("npm", ["--prefix", codebaseDir, "install", "--save", dirPath]);
373
376
  }
374
377
  catch (err) {
375
- const errMsg = (0, common_1.getErrorMessage)(err, "unknown error");
378
+ const errMsg = (0, error_1.getErrMsg)(err, "unknown error");
376
379
  throw new error_1.FirebaseError(`Error during npm install in ${codebaseDir}: ${errMsg}`);
377
380
  }
378
381
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isExtensionSpec = exports.isResource = exports.isParam = exports.isObject = exports.ParamType = exports.FUNCTIONS_V2_RESOURCE_TYPE = exports.FUNCTIONS_RESOURCE_TYPE = exports.Visibility = exports.RegistryLaunchStage = void 0;
3
+ exports.isExtensionSpec = exports.isResource = exports.isParam = exports.isObject = exports.ParamType = exports.FUNCTIONS_V2_RESOURCE_TYPE = exports.FUNCTIONS_RESOURCE_TYPE = exports.isExtensionInstance = exports.Visibility = exports.RegistryLaunchStage = void 0;
4
4
  var RegistryLaunchStage;
5
5
  (function (RegistryLaunchStage) {
6
6
  RegistryLaunchStage["EXPERIMENTAL"] = "EXPERIMENTAL";
@@ -14,6 +14,21 @@ var Visibility;
14
14
  Visibility["UNLISTED"] = "unlisted";
15
15
  Visibility["PUBLIC"] = "public";
16
16
  })(Visibility = exports.Visibility || (exports.Visibility = {}));
17
+ const extensionInstanceState = [
18
+ "STATE_UNSPECIFIED",
19
+ "DEPLOYING",
20
+ "UNINSTALLING",
21
+ "ACTIVE",
22
+ "ERRORED",
23
+ "PAUSED",
24
+ ];
25
+ const isExtensionInstance = (value) => {
26
+ if (!isObject(value) || typeof value.name !== "string") {
27
+ return false;
28
+ }
29
+ return true;
30
+ };
31
+ exports.isExtensionInstance = isExtensionInstance;
17
32
  const lifecycleStages = ["STAGE_UNSPECIFIED", "ON_INSTALL", "ON_UPDATE", "ON_CONFIGURE"];
18
33
  exports.FUNCTIONS_RESOURCE_TYPE = "firebaseextensions.v1beta.function";
19
34
  exports.FUNCTIONS_V2_RESOURCE_TYPE = "firebaseextensions.v1beta.v2function";
@@ -57,19 +57,19 @@ var ValueType;
57
57
  ValueType["DOUBLE"] = "DOUBLE";
58
58
  ValueType["STRING"] = "STRING";
59
59
  })(ValueType = exports.ValueType || (exports.ValueType = {}));
60
- async function queryTimeSeries(query, projectNumber) {
60
+ async function queryTimeSeries(query, project) {
61
61
  const client = new apiv2_1.Client({
62
62
  urlPrefix: (0, api_1.cloudMonitoringOrigin)(),
63
63
  apiVersion: exports.CLOUD_MONITORING_VERSION,
64
64
  });
65
65
  try {
66
- const res = await client.get(`/projects/${projectNumber}/timeSeries/`, {
66
+ const res = await client.get(`/projects/${project}/timeSeries/`, {
67
67
  queryParams: query,
68
68
  });
69
69
  return res.body.timeSeries;
70
70
  }
71
71
  catch (err) {
72
- throw new error_1.FirebaseError(`Failed to get extension usage: ${err}`, {
72
+ throw new error_1.FirebaseError(`Failed to get Cloud Monitoring metric: ${err}`, {
73
73
  status: err.status,
74
74
  });
75
75
  }
@@ -34,27 +34,34 @@ async function createInstance(projectId, location, instanceId, enableGoogleMlInt
34
34
  if (enableGoogleMlIntegration) {
35
35
  databaseFlags.push({ name: "cloudsql.enable_google_ml_integration", value: "on" });
36
36
  }
37
- const op = await client.post(`projects/${projectId}/instances`, {
38
- name: instanceId,
39
- region: location,
40
- databaseVersion: "POSTGRES_15",
41
- settings: {
42
- tier: "db-f1-micro",
43
- edition: "ENTERPRISE",
44
- ipConfiguration: {
45
- authorizedNetworks: [],
46
- },
47
- enableGoogleMlIntegration,
48
- databaseFlags,
49
- storageAutoResize: false,
50
- userLabels: { "firebase-data-connect": "ft" },
51
- insightsConfig: {
52
- queryInsightsEnabled: true,
53
- queryPlansPerMinute: 5,
54
- queryStringLength: 1024,
37
+ let op;
38
+ try {
39
+ op = await client.post(`projects/${projectId}/instances`, {
40
+ name: instanceId,
41
+ region: location,
42
+ databaseVersion: "POSTGRES_15",
43
+ settings: {
44
+ tier: "db-f1-micro",
45
+ edition: "ENTERPRISE",
46
+ ipConfiguration: {
47
+ authorizedNetworks: [],
48
+ },
49
+ enableGoogleMlIntegration,
50
+ databaseFlags,
51
+ storageAutoResize: false,
52
+ userLabels: { "firebase-data-connect": "ft" },
53
+ insightsConfig: {
54
+ queryInsightsEnabled: true,
55
+ queryPlansPerMinute: 5,
56
+ queryStringLength: 1024,
57
+ },
55
58
  },
56
- },
57
- });
59
+ });
60
+ }
61
+ catch (err) {
62
+ handleAllowlistError(err, location);
63
+ throw err;
64
+ }
58
65
  if (!waitForCreation) {
59
66
  return;
60
67
  }
@@ -94,6 +101,11 @@ async function updateInstanceForDataConnect(instance, enableGoogleMlIntegration)
94
101
  return pollRes;
95
102
  }
96
103
  exports.updateInstanceForDataConnect = updateInstanceForDataConnect;
104
+ function handleAllowlistError(err, region) {
105
+ if (err.message.includes("Not allowed to set system label: firebase-data-connect")) {
106
+ throw new error_1.FirebaseError(`Cloud SQL free trial instances are not yet available in ${region}. Please check https://firebase.google.com/docs/data-connect/ for a full list of available regions.`);
107
+ }
108
+ }
97
109
  function setDatabaseFlag(flag, flags = []) {
98
110
  const temp = flags.filter((f) => f.name !== flag.name);
99
111
  temp.push(flag);
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateP4SA = exports.serviceAgentEmail = exports.sortConnectionsByCreateTime = exports.getGitRepositoryLink = exports.createGitRepositoryLink = exports.fetchGitHubInstallations = exports.listAllBranches = exports.listAllLinkableGitRepositories = exports.listAllConnections = exports.getConnection = exports.deleteConnection = exports.createConnection = exports.client = void 0;
3
+ exports.getRepoDetailsFromBackend = exports.extractGitRepositoryLinkComponents = exports.generateP4SA = exports.serviceAgentEmail = exports.sortConnectionsByCreateTime = exports.fetchGitRepositoryLinkReadToken = exports.getGitRepositoryLink = exports.createGitRepositoryLink = exports.fetchGitHubInstallations = exports.listAllBranches = exports.listAllLinkableGitRepositories = exports.listAllConnections = exports.getConnection = exports.deleteConnection = exports.createConnection = exports.client = void 0;
4
4
  const apiv2_1 = require("../apiv2");
5
5
  const api_1 = require("../api");
6
6
  const serviceusage_1 = require("./serviceusage");
7
+ const error_1 = require("../error");
8
+ const githubConnections_1 = require("../apphosting/githubConnections");
7
9
  const PAGE_SIZE_MAX = 1000;
8
10
  const LOCATION_OVERRIDE = process.env.FIREBASE_DEVELOPERCONNECT_LOCATION_OVERRIDE;
9
11
  exports.client = new apiv2_1.Client({
@@ -112,6 +114,12 @@ async function getGitRepositoryLink(projectId, location, connectionId, gitReposi
112
114
  return res.body;
113
115
  }
114
116
  exports.getGitRepositoryLink = getGitRepositoryLink;
117
+ async function fetchGitRepositoryLinkReadToken(projectId, location, connectionId, gitRepositoryLinkId) {
118
+ const name = `projects/${projectId}/locations/${LOCATION_OVERRIDE !== null && LOCATION_OVERRIDE !== void 0 ? LOCATION_OVERRIDE : location}/connections/${connectionId}/gitRepositoryLinks/${gitRepositoryLinkId}:fetchReadToken`;
119
+ const res = await exports.client.post(name);
120
+ return res.body;
121
+ }
122
+ exports.fetchGitRepositoryLinkReadToken = fetchGitRepositoryLinkReadToken;
115
123
  function sortConnectionsByCreateTime(connections) {
116
124
  return connections.sort((a, b) => {
117
125
  return Date.parse(a.createTime) - Date.parse(b.createTime);
@@ -127,3 +135,32 @@ async function generateP4SA(projectNumber) {
127
135
  await (0, serviceusage_1.generateServiceIdentityAndPoll)(projectNumber, new URL(devConnectOrigin).hostname, "apphosting");
128
136
  }
129
137
  exports.generateP4SA = generateP4SA;
138
+ function extractGitRepositoryLinkComponents(path) {
139
+ const connectionMatch = /connections\/([^\/]+)/.exec(path);
140
+ const repositoryMatch = /gitRepositoryLinks\/([^\/]+)/.exec(path);
141
+ const connection = connectionMatch ? connectionMatch[1] : null;
142
+ const gitRepoLink = repositoryMatch ? repositoryMatch[1] : null;
143
+ return { connection, gitRepoLink };
144
+ }
145
+ exports.extractGitRepositoryLinkComponents = extractGitRepositoryLinkComponents;
146
+ async function getRepoDetailsFromBackend(projectId, location, gitRepoLinkPath) {
147
+ const { connection, gitRepoLink } = extractGitRepositoryLinkComponents(gitRepoLinkPath);
148
+ if (!connection || !gitRepoLink) {
149
+ throw new error_1.FirebaseError(`Failed to extract connection or repository resource names from backend repository name.`);
150
+ }
151
+ const repoLink = await getGitRepositoryLink(projectId, location, connection, gitRepoLink);
152
+ const repoSlug = (0, githubConnections_1.extractRepoSlugFromUri)(repoLink.cloneUri);
153
+ const owner = repoSlug === null || repoSlug === void 0 ? void 0 : repoSlug.split("/")[0];
154
+ const repo = repoSlug === null || repoSlug === void 0 ? void 0 : repoSlug.split("/")[1];
155
+ if (!owner || !repo) {
156
+ throw new error_1.FirebaseError("Failed to parse owner and repo from git repository link");
157
+ }
158
+ const readToken = await fetchGitRepositoryLinkReadToken(projectId, location, connection, gitRepoLink);
159
+ return {
160
+ repoLink,
161
+ owner,
162
+ repo,
163
+ readToken,
164
+ };
165
+ }
166
+ exports.getRepoDetailsFromBackend = getRepoDetailsFromBackend;