firebase-tools 10.1.2 → 10.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/apiv2.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Client = exports.setAccessToken = exports.setRefreshToken = void 0;
4
- const stream_1 = require("stream");
5
4
  const url_1 = require("url");
5
+ const stream_1 = require("stream");
6
6
  const ProxyAgent = require("proxy-agent");
7
+ const retry = require("retry");
7
8
  const abort_controller_1 = require("abort-controller");
8
9
  const node_fetch_1 = require("node-fetch");
9
10
  const util_1 = require("util");
@@ -151,6 +152,7 @@ class Client {
151
152
  return `${this.opts.urlPrefix}${versionPath}${options.path}`;
152
153
  }
153
154
  async doRequest(options) {
155
+ var _a;
154
156
  if (!options.path.startsWith("/")) {
155
157
  options.path = "/" + options.path;
156
158
  }
@@ -199,53 +201,94 @@ class Client {
199
201
  else if (options.body !== undefined) {
200
202
  fetchOptions.body = JSON.stringify(options.body);
201
203
  }
202
- this.logRequest(options);
203
- let res;
204
- try {
205
- res = await (0, node_fetch_1.default)(fetchURL, fetchOptions);
206
- }
207
- catch (thrown) {
208
- const err = thrown instanceof Error ? thrown : new Error(thrown);
209
- const isAbortError = err.name.includes("AbortError");
210
- if (isAbortError) {
211
- throw new error_1.FirebaseError(`Timeout reached making request to ${fetchURL}`, { original: err });
212
- }
213
- throw new error_1.FirebaseError(`Failed to make request to ${fetchURL}`, { original: err });
214
- }
215
- finally {
216
- if (reqTimeout) {
217
- clearTimeout(reqTimeout);
218
- }
219
- }
220
- let body;
221
- if (options.responseType === "json") {
222
- const text = await res.text();
223
- if (!text.length) {
224
- body = undefined;
225
- }
226
- else {
227
- body = JSON.parse(text);
228
- }
229
- }
230
- else if (options.responseType === "stream") {
231
- body = res.body;
232
- }
233
- else {
234
- throw new error_1.FirebaseError(`Unable to interpret response. Please set responseType.`, {
235
- exit: 2,
236
- });
237
- }
238
- this.logResponse(res, body, options);
239
- if (res.status >= 400) {
240
- if (!options.resolveOnHTTPError) {
241
- throw responseToError({ statusCode: res.status }, body);
242
- }
243
- }
244
- return {
245
- status: res.status,
246
- response: res,
247
- body,
204
+ const operationOptions = {
205
+ retries: ((_a = options.retryCodes) === null || _a === void 0 ? void 0 : _a.length) ? 1 : 2,
206
+ minTimeout: 1 * 1000,
207
+ maxTimeout: 5 * 1000,
248
208
  };
209
+ if (typeof options.retries === "number") {
210
+ operationOptions.retries = options.retries;
211
+ }
212
+ if (typeof options.retryMinTimeout === "number") {
213
+ operationOptions.minTimeout = options.retryMinTimeout;
214
+ }
215
+ if (typeof options.retryMaxTimeout === "number") {
216
+ operationOptions.maxTimeout = options.retryMaxTimeout;
217
+ }
218
+ const operation = retry.operation(operationOptions);
219
+ return await new Promise((resolve, reject) => {
220
+ operation.attempt(async (currentAttempt) => {
221
+ var _a;
222
+ let res;
223
+ let body;
224
+ try {
225
+ if (currentAttempt > 1) {
226
+ logger_1.logger.debug(`*** [apiv2] Attempting the request again. Attempt number ${currentAttempt}`);
227
+ }
228
+ this.logRequest(options);
229
+ try {
230
+ res = await (0, node_fetch_1.default)(fetchURL, fetchOptions);
231
+ }
232
+ catch (thrown) {
233
+ const err = thrown instanceof Error ? thrown : new Error(thrown);
234
+ const isAbortError = err.name.includes("AbortError");
235
+ if (isAbortError) {
236
+ throw new error_1.FirebaseError(`Timeout reached making request to ${fetchURL}`, {
237
+ original: err,
238
+ });
239
+ }
240
+ throw new error_1.FirebaseError(`Failed to make request to ${fetchURL}`, { original: err });
241
+ }
242
+ finally {
243
+ if (reqTimeout) {
244
+ clearTimeout(reqTimeout);
245
+ }
246
+ }
247
+ if (options.responseType === "json") {
248
+ const text = await res.text();
249
+ if (!text.length) {
250
+ body = undefined;
251
+ }
252
+ else {
253
+ try {
254
+ body = JSON.parse(text);
255
+ }
256
+ catch (err) {
257
+ throw new error_1.FirebaseError(`Unable to parse JSON: ${err}`);
258
+ }
259
+ }
260
+ }
261
+ else if (options.responseType === "stream") {
262
+ body = res.body;
263
+ }
264
+ else {
265
+ throw new error_1.FirebaseError(`Unable to interpret response. Please set responseType.`, {
266
+ exit: 2,
267
+ });
268
+ }
269
+ }
270
+ catch (err) {
271
+ return err instanceof error_1.FirebaseError ? reject(err) : reject(new error_1.FirebaseError(`${err}`));
272
+ }
273
+ this.logResponse(res, body, options);
274
+ if (res.status >= 400) {
275
+ if ((_a = options.retryCodes) === null || _a === void 0 ? void 0 : _a.includes(res.status)) {
276
+ const err = responseToError({ statusCode: res.status }, body) || undefined;
277
+ if (operation.retry(err)) {
278
+ return;
279
+ }
280
+ }
281
+ if (!options.resolveOnHTTPError) {
282
+ return reject(responseToError({ statusCode: res.status }, body));
283
+ }
284
+ }
285
+ resolve({
286
+ status: res.status,
287
+ response: res,
288
+ body,
289
+ });
290
+ });
291
+ });
249
292
  }
250
293
  logRequest(options) {
251
294
  var _a, _b;
@@ -282,7 +325,7 @@ class Client {
282
325
  }
283
326
  exports.Client = Client;
284
327
  function isLocalInsecureRequest(urlPrefix) {
285
- const u = (0, url_1.parse)(urlPrefix);
328
+ const u = new url_1.URL(urlPrefix);
286
329
  return u.protocol === "http:";
287
330
  }
288
331
  function bodyToString(body) {
@@ -1,18 +1,17 @@
1
1
  "use strict";
2
- const _ = require("lodash");
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.archiveDirectory = void 0;
3
4
  const archiver = require("archiver");
4
5
  const filesize = require("filesize");
5
6
  const fs = require("fs");
6
7
  const path = require("path");
7
8
  const tar = require("tar");
8
9
  const tmp = require("tmp");
9
- const { listFiles } = require("./listFiles");
10
- const { FirebaseError } = require("./error");
10
+ const error_1 = require("./error");
11
+ const listFiles_1 = require("./listFiles");
12
+ const logger_1 = require("./logger");
11
13
  const fsAsync = require("./fsAsync");
12
- const { logger } = require("./logger");
13
- const utils = require("./utils");
14
- const archiveDirectory = (sourceDirectory, options) => {
15
- options = options || {};
14
+ async function archiveDirectory(sourceDirectory, options = {}) {
16
15
  let postfix = ".tar.gz";
17
16
  if (options.type === "zip") {
18
17
  postfix = ".zip";
@@ -26,105 +25,96 @@ const archiveDirectory = (sourceDirectory, options) => {
26
25
  }
27
26
  let makeArchive;
28
27
  if (options.type === "zip") {
29
- makeArchive = _zipDirectory(sourceDirectory, tempFile, options);
28
+ makeArchive = zipDirectory(sourceDirectory, tempFile, options);
30
29
  }
31
30
  else {
32
- makeArchive = _tarDirectory(sourceDirectory, tempFile, options);
31
+ makeArchive = tarDirectory(sourceDirectory, tempFile, options);
33
32
  }
34
- return makeArchive
35
- .then((archive) => {
36
- logger.debug(`Archived ${filesize(archive.size)} in ${sourceDirectory}.`);
33
+ try {
34
+ const archive = await makeArchive;
35
+ logger_1.logger.debug(`Archived ${filesize(archive.size)} in ${sourceDirectory}.`);
37
36
  return archive;
38
- })
39
- .catch((err) => {
40
- if (err instanceof FirebaseError) {
37
+ }
38
+ catch (err) {
39
+ if (err instanceof error_1.FirebaseError) {
41
40
  throw err;
42
41
  }
43
- return utils.reject("Failed to create archive.", {
44
- original: err,
45
- });
46
- });
47
- };
48
- const _tarDirectory = (sourceDirectory, tempFile, options) => {
49
- const allFiles = listFiles(sourceDirectory, options.ignore);
42
+ throw new error_1.FirebaseError("Failed to create archive.", { original: err });
43
+ }
44
+ }
45
+ exports.archiveDirectory = archiveDirectory;
46
+ async function tarDirectory(sourceDirectory, tempFile, options) {
47
+ const allFiles = (0, listFiles_1.listFiles)(sourceDirectory, options.ignore);
50
48
  try {
51
49
  fs.statSync(sourceDirectory);
52
50
  }
53
51
  catch (err) {
54
52
  if (err.code === "ENOENT") {
55
- return utils.reject(`Could not read directory "${sourceDirectory}"`);
53
+ throw new error_1.FirebaseError(`Could not read directory "${sourceDirectory}"`);
56
54
  }
57
55
  throw err;
58
56
  }
59
57
  if (!allFiles.length) {
60
- return utils.reject(`Cannot create a tar archive with 0 files from directory "${sourceDirectory}"`);
58
+ throw new error_1.FirebaseError(`Cannot create a tar archive with 0 files from directory "${sourceDirectory}"`);
61
59
  }
62
- return tar
63
- .create({
60
+ await tar.create({
64
61
  gzip: true,
65
62
  file: tempFile.name,
66
63
  cwd: sourceDirectory,
67
64
  follow: true,
68
65
  noDirRecurse: true,
69
66
  portable: true,
70
- }, allFiles)
71
- .then(() => {
72
- const stats = fs.statSync(tempFile.name);
73
- return {
74
- file: tempFile.name,
75
- stream: fs.createReadStream(tempFile.name),
76
- manifest: allFiles,
77
- size: stats.size,
78
- source: sourceDirectory,
79
- };
80
- });
81
- };
82
- const _zipDirectory = (sourceDirectory, tempFile, options) => {
67
+ }, allFiles);
68
+ const stats = fs.statSync(tempFile.name);
69
+ return {
70
+ file: tempFile.name,
71
+ stream: fs.createReadStream(tempFile.name),
72
+ manifest: allFiles,
73
+ size: stats.size,
74
+ source: sourceDirectory,
75
+ };
76
+ }
77
+ async function zipDirectory(sourceDirectory, tempFile, options) {
83
78
  const archiveFileStream = fs.createWriteStream(tempFile.name, {
84
79
  flags: "w",
85
80
  encoding: "binary",
86
81
  });
87
82
  const archive = archiver("zip");
88
- const archiveDone = _pipeAsync(archive, archiveFileStream);
83
+ const archiveDone = pipeAsync(archive, archiveFileStream);
89
84
  const allFiles = [];
90
- return fsAsync
91
- .readdirRecursive({ path: sourceDirectory, ignore: options.ignore })
92
- .catch((err) => {
85
+ let files;
86
+ try {
87
+ files = await fsAsync.readdirRecursive({ path: sourceDirectory, ignore: options.ignore });
88
+ }
89
+ catch (err) {
93
90
  if (err.code === "ENOENT") {
94
- return utils.reject(`Could not read directory "${sourceDirectory}"`, { original: err });
91
+ throw new error_1.FirebaseError(`Could not read directory "${sourceDirectory}"`, { original: err });
95
92
  }
96
93
  throw err;
97
- })
98
- .then(function (files) {
99
- _.forEach(files, function (file) {
100
- const name = path.relative(sourceDirectory, file.name);
101
- allFiles.push(name);
102
- archive.file(file.name, {
103
- name,
104
- mode: file.mode,
105
- });
94
+ }
95
+ for (const file of files) {
96
+ const name = path.relative(sourceDirectory, file.name);
97
+ allFiles.push(name);
98
+ archive.file(file.name, {
99
+ name,
100
+ mode: file.mode,
106
101
  });
107
- archive.finalize();
108
- return archiveDone;
109
- })
110
- .then(() => {
111
- const stats = fs.statSync(tempFile.name);
112
- return {
113
- file: tempFile.name,
114
- stream: fs.createReadStream(tempFile.name),
115
- manifest: allFiles,
116
- size: stats.size,
117
- source: sourceDirectory,
118
- };
119
- });
120
- };
121
- const _pipeAsync = function (from, to) {
122
- return new Promise(function (resolve, reject) {
102
+ }
103
+ void archive.finalize();
104
+ await archiveDone;
105
+ const stats = fs.statSync(tempFile.name);
106
+ return {
107
+ file: tempFile.name,
108
+ stream: fs.createReadStream(tempFile.name),
109
+ manifest: allFiles,
110
+ size: stats.size,
111
+ source: sourceDirectory,
112
+ };
113
+ }
114
+ async function pipeAsync(from, to) {
115
+ return new Promise((resolve, reject) => {
123
116
  to.on("finish", resolve);
124
117
  to.on("error", reject);
125
118
  from.pipe(to);
126
119
  });
127
- };
128
- module.exports = {
129
- archiveDirectory,
130
- };
120
+ }
@@ -58,14 +58,14 @@ module.exports = new command_1.Command("ext:dev:usage <publisherId>")
58
58
  }
59
59
  const profile = await (0, extensionsApi_1.getPublisherProfile)("-", publisherId);
60
60
  const projectNumber = (0, extensionsHelper_1.getPublisherProjectFromName)(profile.name);
61
- const past30d = new Date();
62
- past30d.setDate(past30d.getDate() - 30);
61
+ const past45d = new Date();
62
+ past45d.setDate(past45d.getDate() - 45);
63
63
  const query = {
64
64
  filter: `metric.type="firebaseextensions.googleapis.com/extension/version/active_instances" ` +
65
65
  `resource.type="firebaseextensions.googleapis.com/ExtensionVersion" ` +
66
66
  `resource.labels.extension="${extensionName}"`,
67
67
  "interval.endTime": new Date().toJSON(),
68
- "interval.startTime": past30d.toJSON(),
68
+ "interval.startTime": past45d.toJSON(),
69
69
  view: cloudmonitoring_1.TimeSeriesView.FULL,
70
70
  "aggregation.alignmentPeriod": (60 * 60 * 24).toString() + "s",
71
71
  "aggregation.perSeriesAligner": cloudmonitoring_1.Aligner.ALIGN_MAX,
@@ -95,15 +95,10 @@ module.exports = new command_1.Command("ext:dev:usage <publisherId>")
95
95
  });
96
96
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, `showing usage stats for ${clc.bold(extensionName)}:`);
97
97
  logger_1.logger.info(table.toString());
98
- const link = await buildCloudMonitoringLink({
99
- projectNumber: projectNumber,
100
- extensionName,
101
- });
102
98
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, `How to read this table:`);
103
99
  logger_1.logger.info(`* Due to privacy considerations, numbers are reported as ranges.`);
104
100
  logger_1.logger.info(`* In the absence of significant changes, we will render a '-' symbol.`);
105
101
  logger_1.logger.info(`* You will need more than 10 installs over a period of more than 28 days to render sufficient data.`);
106
- logger_1.logger.info(`For more detail, visit: ${link}`);
107
102
  });
108
103
  async function buildCloudMonitoringLink(args) {
109
104
  const pageState = {
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.setRulesetLabels = exports.createRuleset = exports.getRulesetLabels = exports.getRuleset = exports.listAllRulesets = void 0;
4
- const api = require("../api");
4
+ const api_1 = require("../api");
5
+ const apiv2_1 = require("../apiv2");
5
6
  const logger_1 = require("../logger");
6
7
  const utils = require("../utils");
7
8
  function handleErrorResponse(response) {
@@ -13,12 +14,9 @@ function handleErrorResponse(response) {
13
14
  code: 2,
14
15
  });
15
16
  }
17
+ const apiClient = new apiv2_1.Client({ urlPrefix: api_1.rtdbMetadataOrigin });
16
18
  async function listAllRulesets(databaseName) {
17
- const response = await api.request("GET", `/namespaces/${databaseName}/rulesets`, {
18
- auth: true,
19
- origin: api.rtdbMetadataOrigin,
20
- json: true,
21
- });
19
+ const response = await apiClient.get(`/namespaces/${databaseName}/rulesets`, { resolveOnHTTPError: true });
22
20
  if (response.status === 200) {
23
21
  return response.body.rulesets;
24
22
  }
@@ -26,11 +24,7 @@ async function listAllRulesets(databaseName) {
26
24
  }
27
25
  exports.listAllRulesets = listAllRulesets;
28
26
  async function getRuleset(databaseName, rulesetId) {
29
- const response = await api.request("GET", `/namespaces/${databaseName}/rulesets/${rulesetId}`, {
30
- auth: true,
31
- origin: api.rtdbMetadataOrigin,
32
- json: true,
33
- });
27
+ const response = await apiClient.get(`/namespaces/${databaseName}/rulesets/${rulesetId}`, { resolveOnHTTPError: true });
34
28
  if (response.status === 200) {
35
29
  return response.body;
36
30
  }
@@ -38,9 +32,8 @@ async function getRuleset(databaseName, rulesetId) {
38
32
  }
39
33
  exports.getRuleset = getRuleset;
40
34
  async function getRulesetLabels(databaseName) {
41
- const response = await api.request("GET", `/namespaces/${databaseName}/ruleset_labels`, {
42
- auth: true,
43
- origin: api.rtdbMetadataOrigin,
35
+ const response = await apiClient.get(`/namespaces/${databaseName}/ruleset_labels`, {
36
+ resolveOnHTTPError: true,
44
37
  });
45
38
  if (response.status === 200) {
46
39
  return response.body;
@@ -49,23 +42,22 @@ async function getRulesetLabels(databaseName) {
49
42
  }
50
43
  exports.getRulesetLabels = getRulesetLabels;
51
44
  async function createRuleset(databaseName, source) {
52
- const response = await api.request("POST", `/.settings/rulesets.json`, {
53
- auth: true,
54
- origin: utils.addSubdomain(api.realtimeOrigin, databaseName),
55
- json: false,
56
- data: source,
45
+ const localApiClient = new apiv2_1.Client({
46
+ urlPrefix: utils.addSubdomain(api_1.realtimeOrigin, databaseName),
57
47
  });
48
+ const response = await localApiClient.post(`/.settings/rulesets.json`, source, { resolveOnHTTPError: true });
58
49
  if (response.status === 200) {
59
- return JSON.parse(response.body).id;
50
+ return response.body.id;
60
51
  }
61
52
  return handleErrorResponse(response);
62
53
  }
63
54
  exports.createRuleset = createRuleset;
64
55
  async function setRulesetLabels(databaseName, labels) {
65
- const response = await api.request("PUT", `/.settings/ruleset_labels.json`, {
66
- auth: true,
67
- origin: utils.addSubdomain(api.realtimeOrigin, databaseName),
68
- data: labels,
56
+ const localApiClient = new apiv2_1.Client({
57
+ urlPrefix: utils.addSubdomain(api_1.realtimeOrigin, databaseName),
58
+ });
59
+ const response = await localApiClient.put(`/.settings/ruleset_labels.json`, labels, {
60
+ resolveOnHTTPError: true,
69
61
  });
70
62
  if (response.status === 200) {
71
63
  return response.body;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.compareFunctions = exports.missingEndpoint = exports.hasEndpoint = exports.regionalEndpoints = exports.matchingBackend = exports.someEndpoint = exports.allEndpoints = exports.checkAvailability = exports.existingBackend = exports.scheduleIdForFunction = exports.functionName = exports.isEmptyBackend = exports.of = exports.empty = exports.isTaskQueueTriggered = exports.isScheduleTriggered = exports.isEventTriggered = exports.isHttpsTriggered = exports.SCHEDULED_FUNCTION_LABEL = exports.memoryOptionDisplayName = exports.endpointTriggerType = void 0;
3
+ exports.compareFunctions = exports.missingEndpoint = exports.hasEndpoint = exports.regionalEndpoints = exports.matchingBackend = exports.someEndpoint = exports.allEndpoints = exports.checkAvailability = exports.existingBackend = exports.scheduleIdForFunction = exports.functionName = exports.isEmptyBackend = exports.of = exports.empty = exports.isTaskQueueTriggered = exports.isScheduleTriggered = exports.isEventTriggered = exports.isHttpsTriggered = exports.SCHEDULED_FUNCTION_LABEL = exports.MIN_MEMORY_FOR_CONCURRENCY = exports.DEFAULT_MEMORY = exports.memoryOptionDisplayName = exports.endpointTriggerType = void 0;
4
4
  const gcf = require("../../gcp/cloudfunctions");
5
5
  const gcfV2 = require("../../gcp/cloudfunctionsv2");
6
6
  const utils = require("../../utils");
@@ -36,6 +36,8 @@ function memoryOptionDisplayName(option) {
36
36
  }[option];
37
37
  }
38
38
  exports.memoryOptionDisplayName = memoryOptionDisplayName;
39
+ exports.DEFAULT_MEMORY = 256;
40
+ exports.MIN_MEMORY_FOR_CONCURRENCY = 2048;
39
41
  exports.SCHEDULED_FUNCTION_LABEL = Object.freeze({ deployment: "firebase-schedule" });
40
42
  function isHttpsTriggered(triggered) {
41
43
  return {}.hasOwnProperty.call(triggered, "httpsTrigger");
@@ -27,7 +27,7 @@ function hasDotenv(opts) {
27
27
  return previews_1.previews.dotenv && functionsEnv.hasUserEnvs(opts);
28
28
  }
29
29
  async function maybeEnableAR(projectId) {
30
- if (previews_1.previews.artifactregistry) {
30
+ if (!previews_1.previews.artifactregistry) {
31
31
  return ensureApiEnabled.check(projectId, "artifactregistry.googleapis.com", "functions", true);
32
32
  }
33
33
  await ensureApiEnabled.ensure(projectId, "artifactregistry.googleapis.com", "functions");
@@ -113,7 +113,7 @@ async function prepare(context, options, payload) {
113
113
  await Promise.all(Object.values(wantBackend.requiredAPIs).map((api) => {
114
114
  return ensureApiEnabled.ensure(projectId, api, "functions", false);
115
115
  }));
116
- validate.functionIdsAreValid(backend.allEndpoints(wantBackend));
116
+ validate.endpointsAreValid(wantBackend);
117
117
  context.filters = (0, functionsDeployHelper_1.getFilterGroups)(options);
118
118
  const matchingBackend = backend.matchingBackend(wantBackend, (endpoint) => {
119
119
  return (0, functionsDeployHelper_1.functionMatchesAnyGroup)(endpoint, context.filters);
@@ -242,7 +242,10 @@ class Fabricator {
242
242
  .catch(rethrowAs(endpoint, "set invoker"));
243
243
  }
244
244
  }
245
- await this.setConcurrency(endpoint, serviceName, endpoint.concurrency || DEFAULT_GCFV2_CONCURRENCY);
245
+ const mem = endpoint.availableMemoryMb || backend.DEFAULT_MEMORY;
246
+ if (mem >= backend.MIN_MEMORY_FOR_CONCURRENCY && endpoint.concurrency != 1) {
247
+ await this.setConcurrency(endpoint, serviceName, endpoint.concurrency || DEFAULT_GCFV2_CONCURRENCY);
248
+ }
246
249
  }
247
250
  async updateV1Function(endpoint, scraper) {
248
251
  var _a;
@@ -1,10 +1,37 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.functionIdsAreValid = exports.functionsDirectoryExists = void 0;
3
+ exports.functionIdsAreValid = exports.functionsDirectoryExists = exports.endpointsAreValid = void 0;
4
4
  const path = require("path");
5
5
  const clc = require("cli-color");
6
6
  const error_1 = require("../../error");
7
7
  const fsutils = require("../../fsutils");
8
+ const backend = require("./backend");
9
+ function endpointsAreValid(wantBackend) {
10
+ functionIdsAreValid(backend.allEndpoints(wantBackend));
11
+ const gcfV1WithConcurrency = backend
12
+ .allEndpoints(wantBackend)
13
+ .filter((endpoint) => (endpoint.concurrency || 1) != 1 && endpoint.platform == "gcfv1")
14
+ .map((endpoint) => endpoint.id);
15
+ if (gcfV1WithConcurrency.length) {
16
+ const msg = `Cannot set concurrency on the functions ${gcfV1WithConcurrency.join(",")} because they are GCF gen 1`;
17
+ throw new error_1.FirebaseError(msg);
18
+ }
19
+ const tooSmallForConcurrency = backend
20
+ .allEndpoints(wantBackend)
21
+ .filter((endpoint) => {
22
+ if ((endpoint.concurrency || 1) == 1) {
23
+ return false;
24
+ }
25
+ const mem = endpoint.availableMemoryMb || backend.DEFAULT_MEMORY;
26
+ return mem < backend.MIN_MEMORY_FOR_CONCURRENCY;
27
+ })
28
+ .map((endpoint) => endpoint.id);
29
+ if (tooSmallForConcurrency.length) {
30
+ const msg = `Cannot set concurency on the functions ${tooSmallForConcurrency.join(",")} because they have fewer than 2GB memory`;
31
+ throw new error_1.FirebaseError(msg);
32
+ }
33
+ }
34
+ exports.endpointsAreValid = endpointsAreValid;
8
35
  function functionsDirectoryExists(sourceDir, projectDir) {
9
36
  if (!fsutils.dirExistsSync(sourceDir)) {
10
37
  const sourceDirName = path.relative(projectDir, sourceDir);