firebase-tools 10.7.0 → 10.8.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 (64) hide show
  1. package/lib/commands/ext-configure.js +26 -15
  2. package/lib/commands/ext-export.js +14 -5
  3. package/lib/commands/ext-install.js +31 -2
  4. package/lib/commands/ext-update.js +17 -10
  5. package/lib/commands/functions-delete.js +9 -2
  6. package/lib/commands/functions-secrets-set.js +1 -13
  7. package/lib/deploy/extensions/planner.js +12 -0
  8. package/lib/deploy/extensions/tasks.js +13 -0
  9. package/lib/deploy/functions/backend.js +67 -10
  10. package/lib/deploy/functions/build.js +28 -9
  11. package/lib/deploy/functions/checkIam.js +71 -56
  12. package/lib/deploy/functions/containerCleaner.js +8 -7
  13. package/lib/deploy/functions/deploy.js +49 -27
  14. package/lib/deploy/functions/functionsDeployHelper.js +48 -4
  15. package/lib/deploy/functions/prepare.js +125 -74
  16. package/lib/deploy/functions/pricing.js +2 -2
  17. package/lib/deploy/functions/release/executor.js +1 -1
  18. package/lib/deploy/functions/release/fabricator.js +94 -36
  19. package/lib/deploy/functions/release/index.js +16 -27
  20. package/lib/deploy/functions/release/planner.js +12 -7
  21. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +13 -1
  22. package/lib/deploy/functions/runtimes/golang/index.js +3 -0
  23. package/lib/deploy/functions/runtimes/node/index.js +7 -0
  24. package/lib/deploy/functions/runtimes/node/parseTriggers.js +108 -1
  25. package/lib/deploy/functions/services/storage.js +6 -12
  26. package/lib/deploy/functions/validate.js +58 -8
  27. package/lib/deploy/hosting/convertConfig.js +6 -4
  28. package/lib/emulator/auth/cloudFunctions.js +6 -2
  29. package/lib/emulator/auth/operations.js +0 -1
  30. package/lib/emulator/auth/server.js +8 -1
  31. package/lib/emulator/auth/state.js +27 -24
  32. package/lib/emulator/controller.js +12 -9
  33. package/lib/emulator/databaseEmulator.js +36 -3
  34. package/lib/emulator/downloadableEmulators.js +7 -7
  35. package/lib/emulator/extensionsEmulator.js +3 -0
  36. package/lib/emulator/functionsEmulator.js +11 -9
  37. package/lib/emulator/functionsEmulatorRuntime.js +1 -1
  38. package/lib/emulator/functionsEmulatorShared.js +5 -1
  39. package/lib/emulator/functionsEmulatorShell.js +2 -3
  40. package/lib/emulator/functionsEmulatorUtils.js +5 -1
  41. package/lib/emulator/pubsubEmulator.js +13 -9
  42. package/lib/emulator/storage/apis/firebase.js +26 -4
  43. package/lib/ensureApiEnabled.js +1 -1
  44. package/lib/extensions/askUserForEventsConfig.js +97 -0
  45. package/lib/extensions/export.js +7 -0
  46. package/lib/extensions/extensionsApi.js +47 -7
  47. package/lib/extensions/manifest.js +1 -1
  48. package/lib/extensions/paramHelper.js +2 -0
  49. package/lib/extensions/updateHelper.js +7 -1
  50. package/lib/extensions/warnings.js +11 -4
  51. package/lib/functions/projectConfig.js +13 -8
  52. package/lib/functionsShellCommandAction.js +1 -1
  53. package/lib/gcp/cloudfunctions.js +9 -2
  54. package/lib/gcp/cloudfunctionsv2.js +28 -10
  55. package/lib/gcp/serviceusage.js +24 -0
  56. package/lib/previews.js +1 -1
  57. package/lib/serve/functions.js +16 -19
  58. package/lib/throttler/throttler.js +2 -1
  59. package/npm-shrinkwrap.json +214 -527
  60. package/package.json +3 -3
  61. package/templates/extensions/typescript/package.lint.json +2 -1
  62. package/templates/extensions/typescript/package.nolint.json +2 -1
  63. package/templates/init/functions/typescript/package.lint.json +1 -0
  64. package/templates/init/functions/typescript/package.nolint.json +1 -0
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ensureServiceAgentRoles = exports.mergeBindings = exports.obtainEventarcServiceAgentBindings = exports.obtainDefaultComputeServiceAgentBindings = exports.obtainPubSubServiceAgentBindings = exports.obtainBinding = exports.checkHttpIam = exports.checkServiceAccountIam = exports.EVENTARC_SERVICE_AGENT_ROLE = exports.EVENTARC_EVENT_RECEIVER_ROLE = exports.RUN_INVOKER_ROLE = exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE = void 0;
3
+ exports.ensureServiceAgentRoles = exports.mergeBindings = exports.obtainDefaultComputeServiceAgentBindings = exports.obtainPubSubServiceAgentBindings = exports.checkHttpIam = exports.checkServiceAccountIam = exports.EVENTARC_EVENT_RECEIVER_ROLE = exports.RUN_INVOKER_ROLE = exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE = void 0;
4
4
  const cli_color_1 = require("cli-color");
5
5
  const logger_1 = require("../../logger");
6
6
  const functionsDeployHelper_1 = require("./functionsDeployHelper");
7
7
  const error_1 = require("../../error");
8
+ const functional_1 = require("../../functional");
8
9
  const iam = require("../../gcp/iam");
9
10
  const backend = require("./backend");
10
11
  const track_1 = require("../../track");
@@ -15,7 +16,6 @@ const PERMISSION = "cloudfunctions.functions.setIamPolicy";
15
16
  exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE = "roles/iam.serviceAccountTokenCreator";
16
17
  exports.RUN_INVOKER_ROLE = "roles/run.invoker";
17
18
  exports.EVENTARC_EVENT_RECEIVER_ROLE = "roles/eventarc.eventReceiver";
18
- exports.EVENTARC_SERVICE_AGENT_ROLE = "roles/eventarc.serviceAgent";
19
19
  async function checkServiceAccountIam(projectId) {
20
20
  const saEmail = `${projectId}@appspot.gserviceaccount.com`;
21
21
  let passed = false;
@@ -35,10 +35,12 @@ async function checkServiceAccountIam(projectId) {
35
35
  }
36
36
  exports.checkServiceAccountIam = checkServiceAccountIam;
37
37
  async function checkHttpIam(context, options, payload) {
38
+ if (!payload.functions) {
39
+ return;
40
+ }
38
41
  const filters = context.filters || (0, functionsDeployHelper_1.getEndpointFilters)(options);
39
- const wantBackend = payload.functions.wantBackend;
40
- const httpEndpoints = backend
41
- .allEndpoints(wantBackend)
42
+ const wantBackends = Object.values(payload.functions).map(({ wantBackend }) => wantBackend);
43
+ const httpEndpoints = [...(0, functional_1.flattenArray)(wantBackends.map((b) => backend.allEndpoints(b)))]
42
44
  .filter(backend.isHttpsTriggered)
43
45
  .filter((f) => (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(f, filters));
44
46
  const existing = await backend.existingBackend(context);
@@ -65,6 +67,12 @@ async function checkHttpIam(context, options, payload) {
65
67
  logger_1.logger.debug("[functions] found setIamPolicy permission, proceeding with deploy");
66
68
  }
67
69
  exports.checkHttpIam = checkHttpIam;
70
+ function getPubsubServiceAgent(projectNumber) {
71
+ return `serviceAccount:service-${projectNumber}@gcp-sa-pubsub.iam.gserviceaccount.com`;
72
+ }
73
+ function getDefaultComputeServiceAgent(projectNumber) {
74
+ return `serviceAccount:${projectNumber}-compute@developer.gserviceaccount.com`;
75
+ }
68
76
  function reduceEventsToServices(services, endpoint) {
69
77
  const service = (0, services_1.serviceForEndpoint)(endpoint);
70
78
  if (service.requiredProjectBindings && !services.find((s) => s.name === service.name)) {
@@ -72,90 +80,97 @@ function reduceEventsToServices(services, endpoint) {
72
80
  }
73
81
  return services;
74
82
  }
75
- function obtainBinding(existingPolicy, serviceAccount, role) {
76
- let binding = existingPolicy.bindings.find((b) => b.role === role);
77
- if (!binding) {
78
- binding = {
79
- role,
80
- members: [],
81
- };
82
- }
83
- if (!binding.members.find((m) => m === serviceAccount)) {
84
- binding.members.push(serviceAccount);
85
- }
86
- return binding;
87
- }
88
- exports.obtainBinding = obtainBinding;
89
- function obtainPubSubServiceAgentBindings(projectNumber, existingPolicy) {
90
- const pubsubServiceAgent = `serviceAccount:service-${projectNumber}@gcp-sa-pubsub.iam.gserviceaccount.com`;
91
- return [obtainBinding(existingPolicy, pubsubServiceAgent, exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE)];
83
+ function obtainPubSubServiceAgentBindings(projectNumber) {
84
+ const serviceAccountTokenCreatorBinding = {
85
+ role: exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE,
86
+ members: [getPubsubServiceAgent(projectNumber)],
87
+ };
88
+ return [serviceAccountTokenCreatorBinding];
92
89
  }
93
90
  exports.obtainPubSubServiceAgentBindings = obtainPubSubServiceAgentBindings;
94
- function obtainDefaultComputeServiceAgentBindings(projectNumber, existingPolicy) {
95
- const defaultComputeServiceAgent = `serviceAccount:${projectNumber}-compute@developer.gserviceaccount.com`;
96
- const invokerBinding = obtainBinding(existingPolicy, defaultComputeServiceAgent, exports.RUN_INVOKER_ROLE);
97
- const eventReceiverBinding = obtainBinding(existingPolicy, defaultComputeServiceAgent, exports.EVENTARC_EVENT_RECEIVER_ROLE);
98
- return [invokerBinding, eventReceiverBinding];
91
+ function obtainDefaultComputeServiceAgentBindings(projectNumber) {
92
+ const defaultComputeServiceAgent = getDefaultComputeServiceAgent(projectNumber);
93
+ const runInvokerBinding = {
94
+ role: exports.RUN_INVOKER_ROLE,
95
+ members: [defaultComputeServiceAgent],
96
+ };
97
+ const eventarcEventReceiverBinding = {
98
+ role: exports.EVENTARC_EVENT_RECEIVER_ROLE,
99
+ members: [defaultComputeServiceAgent],
100
+ };
101
+ return [runInvokerBinding, eventarcEventReceiverBinding];
99
102
  }
100
103
  exports.obtainDefaultComputeServiceAgentBindings = obtainDefaultComputeServiceAgentBindings;
101
- function obtainEventarcServiceAgentBindings(projectNumber, existingPolicy) {
102
- const eventarcServiceAgent = `serviceAccount:service-${projectNumber}@gcp-sa-eventarc.iam.gserviceaccount.com`;
103
- return [obtainBinding(existingPolicy, eventarcServiceAgent, exports.EVENTARC_SERVICE_AGENT_ROLE)];
104
- }
105
- exports.obtainEventarcServiceAgentBindings = obtainEventarcServiceAgentBindings;
106
- function mergeBindings(policy, allRequiredBindings) {
107
- for (const requiredBindings of allRequiredBindings) {
108
- if (requiredBindings.length === 0) {
104
+ function mergeBindings(policy, requiredBindings) {
105
+ let updated = false;
106
+ for (const requiredBinding of requiredBindings) {
107
+ const match = policy.bindings.find((b) => b.role === requiredBinding.role);
108
+ if (!match) {
109
+ updated = true;
110
+ policy.bindings.push(requiredBinding);
109
111
  continue;
110
112
  }
111
- for (const requiredBinding of requiredBindings) {
112
- const ndx = policy.bindings.findIndex((policyBinding) => policyBinding.role === requiredBinding.role);
113
- if (ndx === -1) {
114
- policy.bindings.push(requiredBinding);
115
- continue;
113
+ for (const requiredMember of requiredBinding.members) {
114
+ if (!match.members.find((m) => m === requiredMember)) {
115
+ updated = true;
116
+ match.members.push(requiredMember);
116
117
  }
117
- requiredBinding.members.forEach((updatedMember) => {
118
- if (!policy.bindings[ndx].members.find((member) => member === updatedMember)) {
119
- policy.bindings[ndx].members.push(updatedMember);
120
- }
121
- });
122
118
  }
123
119
  }
120
+ return updated;
124
121
  }
125
122
  exports.mergeBindings = mergeBindings;
126
- async function ensureServiceAgentRoles(projectNumber, want, have) {
123
+ function printManualIamConfig(requiredBindings, projectId) {
124
+ utils.logLabeledBullet("functions", "Failed to verify the project has the correct IAM bindings for a successful deployment.", "warn");
125
+ utils.logLabeledBullet("functions", "You can either re-run `firebase deploy` as a project owner or manually run the following set of `gcloud` commands:", "warn");
126
+ for (const binding of requiredBindings) {
127
+ for (const member of binding.members) {
128
+ utils.logLabeledBullet("functions", `\`gcloud projects add-iam-policy-binding ${projectId} ` +
129
+ `--member=${member} ` +
130
+ `--role=${binding.role}\``, "warn");
131
+ }
132
+ }
133
+ }
134
+ async function ensureServiceAgentRoles(projectId, projectNumber, want, have) {
127
135
  const wantServices = backend.allEndpoints(want).reduce(reduceEventsToServices, []);
128
136
  const haveServices = backend.allEndpoints(have).reduce(reduceEventsToServices, []);
129
137
  const newServices = wantServices.filter((wantS) => !haveServices.find((haveS) => wantS.name === haveS.name));
130
138
  if (newServices.length === 0) {
131
139
  return;
132
140
  }
141
+ const requiredBindingsPromises = [];
142
+ for (const service of newServices) {
143
+ requiredBindingsPromises.push(service.requiredProjectBindings(projectNumber));
144
+ }
145
+ const nestedRequiredBindings = await Promise.all(requiredBindingsPromises);
146
+ const requiredBindings = [...(0, functional_1.flattenArray)(nestedRequiredBindings)];
147
+ if (haveServices.length === 0) {
148
+ requiredBindings.push(...obtainPubSubServiceAgentBindings(projectNumber));
149
+ requiredBindings.push(...obtainDefaultComputeServiceAgentBindings(projectNumber));
150
+ }
151
+ if (requiredBindings.length === 0) {
152
+ return;
153
+ }
133
154
  let policy;
134
155
  try {
135
156
  policy = await (0, resourceManager_1.getIamPolicy)(projectNumber);
136
157
  }
137
158
  catch (err) {
159
+ printManualIamConfig(requiredBindings, projectId);
138
160
  utils.logLabeledBullet("functions", "Could not verify the necessary IAM configuration for the following newly-integrated services: " +
139
161
  `${newServices.map((service) => service.api).join(", ")}` +
140
162
  ". Deployment may fail.", "warn");
141
163
  return;
142
164
  }
143
- const findRequiredBindings = [];
144
- newServices.forEach((service) => findRequiredBindings.push(service.requiredProjectBindings(projectNumber, policy)));
145
- const allRequiredBindings = await Promise.all(findRequiredBindings);
146
- if (haveServices.length === 0) {
147
- allRequiredBindings.push(obtainPubSubServiceAgentBindings(projectNumber, policy));
148
- allRequiredBindings.push(obtainDefaultComputeServiceAgentBindings(projectNumber, policy));
149
- allRequiredBindings.push(obtainEventarcServiceAgentBindings(projectNumber, policy));
150
- }
151
- if (!allRequiredBindings.find((bindings) => bindings.length > 0)) {
165
+ const hasUpdatedBindings = mergeBindings(policy, requiredBindings);
166
+ if (!hasUpdatedBindings) {
152
167
  return;
153
168
  }
154
- mergeBindings(policy, allRequiredBindings);
155
169
  try {
156
170
  await (0, resourceManager_1.setIamPolicy)(projectNumber, policy, "bindings");
157
171
  }
158
172
  catch (err) {
173
+ printManualIamConfig(requiredBindings, projectId);
159
174
  throw new error_1.FirebaseError("We failed to modify the IAM policy for the project. The functions " +
160
175
  "deployment requires specific roles to be granted to service agents," +
161
176
  " otherwise the deployment will fail.", { original: err });
@@ -251,13 +251,14 @@ class DockerHelper {
251
251
  this.client = new docker.Client(origin);
252
252
  }
253
253
  async ls(path) {
254
- if (!this.cache[path]) {
255
- const raw = await retry(() => this.client.listTags(path));
256
- this.cache[path] = {
257
- tags: raw.tags,
258
- digests: Object.keys(raw.manifest),
259
- children: raw.child,
260
- };
254
+ if (!(path in this.cache)) {
255
+ this.cache[path] = retry(() => this.client.listTags(path)).then((res) => {
256
+ return {
257
+ tags: res.tags,
258
+ digests: Object.keys(res.manifest),
259
+ children: res.child,
260
+ };
261
+ });
261
262
  }
262
263
  return this.cache[path];
263
264
  }
@@ -6,54 +6,62 @@ const clc = require("cli-color");
6
6
  const fs = require("fs");
7
7
  const checkIam_1 = require("./checkIam");
8
8
  const utils_1 = require("../../utils");
9
+ const projectConfig_1 = require("../../functions/projectConfig");
9
10
  const gcs = require("../../gcp/storage");
10
11
  const gcf = require("../../gcp/cloudfunctions");
11
12
  const gcfv2 = require("../../gcp/cloudfunctionsv2");
12
13
  const backend = require("./backend");
13
14
  (0, tmp_1.setGracefulCleanup)();
14
- async function uploadSourceV1(context, region) {
15
- const uploadUrl = await gcf.generateUploadUrl(context.projectId, region);
16
- context.source.sourceUrl = uploadUrl;
15
+ async function uploadSourceV1(projectId, source, wantBackend) {
16
+ const v1Endpoints = backend.allEndpoints(wantBackend).filter((e) => e.platform === "gcfv1");
17
+ if (v1Endpoints.length === 0) {
18
+ return;
19
+ }
20
+ const region = v1Endpoints[0].region;
21
+ const uploadUrl = await gcf.generateUploadUrl(projectId, region);
17
22
  const uploadOpts = {
18
- file: context.source.functionsSourceV1,
19
- stream: fs.createReadStream(context.source.functionsSourceV1),
23
+ file: source.functionsSourceV1,
24
+ stream: fs.createReadStream(source.functionsSourceV1),
20
25
  };
21
26
  await gcs.upload(uploadOpts, uploadUrl, {
22
27
  "x-goog-content-length-range": "0,104857600",
23
28
  });
29
+ return uploadUrl;
24
30
  }
25
- async function uploadSourceV2(context, region) {
26
- const res = await gcfv2.generateUploadUrl(context.projectId, region);
31
+ async function uploadSourceV2(projectId, source, wantBackend) {
32
+ const v2Endpoints = backend.allEndpoints(wantBackend).filter((e) => e.platform === "gcfv2");
33
+ if (v2Endpoints.length === 0) {
34
+ return;
35
+ }
36
+ const region = v2Endpoints[0].region;
37
+ const res = await gcfv2.generateUploadUrl(projectId, region);
27
38
  const uploadOpts = {
28
- file: context.source.functionsSourceV2,
29
- stream: fs.createReadStream(context.source.functionsSourceV2),
39
+ file: source.functionsSourceV2,
40
+ stream: fs.createReadStream(source.functionsSourceV2),
30
41
  };
31
42
  await gcs.upload(uploadOpts, res.uploadUrl);
32
- context.source.storage = res.storageSource;
43
+ return res.storageSource;
33
44
  }
34
- async function deploy(context, options, payload) {
35
- var _a, _b, _c, _d;
36
- if (!context.config) {
37
- return;
38
- }
39
- if (!((_a = context.source) === null || _a === void 0 ? void 0 : _a.functionsSourceV1) && !((_b = context.source) === null || _b === void 0 ? void 0 : _b.functionsSourceV2)) {
45
+ async function uploadCodebase(context, codebase, wantBackend) {
46
+ var _a;
47
+ const source = (_a = context.sources) === null || _a === void 0 ? void 0 : _a[codebase];
48
+ if (!source || (!source.functionsSourceV1 && !source.functionsSourceV2)) {
40
49
  return;
41
50
  }
42
- await (0, checkIam_1.checkHttpIam)(context, options, payload);
51
+ const uploads = [];
43
52
  try {
44
- const want = payload.functions.wantBackend;
45
- const uploads = [];
46
- const byPlatform = (0, utils_1.groupBy)(backend.allEndpoints(want), (e) => e.platform);
47
- if (((_c = byPlatform.gcfv1) === null || _c === void 0 ? void 0 : _c.length) > 0) {
48
- uploads.push(uploadSourceV1(context, byPlatform.gcfv1[0].region));
53
+ uploads.push(uploadSourceV1(context.projectId, source, wantBackend));
54
+ uploads.push(uploadSourceV2(context.projectId, source, wantBackend));
55
+ const [sourceUrl, storage] = await Promise.all(uploads);
56
+ if (sourceUrl) {
57
+ source.sourceUrl = sourceUrl;
49
58
  }
50
- if (((_d = byPlatform.gcfv2) === null || _d === void 0 ? void 0 : _d.length) > 0) {
51
- uploads.push(uploadSourceV2(context, byPlatform.gcfv2[0].region));
59
+ if (storage) {
60
+ source.storage = storage;
52
61
  }
53
- await Promise.all(uploads);
54
- const source = context.config.source;
62
+ const sourceDir = (0, projectConfig_1.configForCodebase)(context.config, codebase).source;
55
63
  if (uploads.length) {
56
- (0, utils_1.logSuccess)(`${clc.green.bold("functions:")} ${clc.bold(source)} folder uploaded successfully`);
64
+ (0, utils_1.logSuccess)(`${clc.green.bold("functions:")} ${clc.bold(sourceDir)} folder uploaded successfully`);
57
65
  }
58
66
  }
59
67
  catch (err) {
@@ -61,4 +69,18 @@ async function deploy(context, options, payload) {
61
69
  throw err;
62
70
  }
63
71
  }
72
+ async function deploy(context, options, payload) {
73
+ if (!context.config) {
74
+ return;
75
+ }
76
+ if (!payload.functions) {
77
+ return;
78
+ }
79
+ await (0, checkIam_1.checkHttpIam)(context, options, payload);
80
+ const uploads = [];
81
+ for (const [codebase, { wantBackend }] of Object.entries(payload.functions)) {
82
+ uploads.push(uploadCodebase(context, codebase, wantBackend));
83
+ }
84
+ await Promise.all(uploads);
85
+ }
64
86
  exports.deploy = deploy;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getFunctionLabel = exports.getEndpointFilters = exports.parseFunctionSelector = exports.endpointMatchesFilter = exports.endpointMatchesAnyFilter = void 0;
4
- const projectConfig = require("../../functions/projectConfig");
3
+ exports.groupEndpointsByCodebase = exports.targetCodebases = exports.getFunctionLabel = exports.getEndpointFilters = exports.parseFunctionSelector = exports.endpointMatchesFilter = exports.endpointMatchesAnyFilter = void 0;
4
+ const backend = require("./backend");
5
+ const projectConfig_1 = require("../../functions/projectConfig");
5
6
  function endpointMatchesAnyFilter(endpoint, filters) {
6
7
  if (!filters) {
7
8
  return true;
@@ -35,7 +36,7 @@ function parseFunctionSelector(selector) {
35
36
  if (fragments.length < 2) {
36
37
  return [
37
38
  { codebase: fragments[0] },
38
- { codebase: projectConfig.DEFAULT_CODEBASE, idChunks: fragments[0].split(/[-.]/) },
39
+ { codebase: projectConfig_1.DEFAULT_CODEBASE, idChunks: fragments[0].split(/[-.]/) },
39
40
  ];
40
41
  }
41
42
  return [
@@ -67,6 +68,49 @@ function getEndpointFilters(options) {
67
68
  }
68
69
  exports.getEndpointFilters = getEndpointFilters;
69
70
  function getFunctionLabel(fn) {
70
- return `${fn.id}(${fn.region})`;
71
+ let id = `${fn.id}(${fn.region})`;
72
+ if (fn.codebase && fn.codebase !== projectConfig_1.DEFAULT_CODEBASE) {
73
+ id = `${fn.codebase}:${id}`;
74
+ }
75
+ return id;
71
76
  }
72
77
  exports.getFunctionLabel = getFunctionLabel;
78
+ function targetCodebases(config, filters) {
79
+ const codebasesFromConfig = [...new Set(Object.values(config).map((c) => c.codebase))];
80
+ if (!filters) {
81
+ return [...codebasesFromConfig];
82
+ }
83
+ const codebasesFromFilters = [
84
+ ...new Set(filters.map((f) => f.codebase).filter((c) => c !== undefined)),
85
+ ];
86
+ if (codebasesFromFilters.length === 0) {
87
+ return [...codebasesFromConfig];
88
+ }
89
+ const intersections = [];
90
+ for (const codebase of codebasesFromConfig) {
91
+ if (codebasesFromFilters.includes(codebase)) {
92
+ intersections.push(codebase);
93
+ }
94
+ }
95
+ return intersections;
96
+ }
97
+ exports.targetCodebases = targetCodebases;
98
+ function groupEndpointsByCodebase(wantBackends, haveEndpoints) {
99
+ const grouped = {};
100
+ let endpointsToAssign = haveEndpoints;
101
+ for (const codebase of Object.keys(wantBackends)) {
102
+ const names = backend.allEndpoints(wantBackends[codebase]).map((e) => backend.functionName(e));
103
+ grouped[codebase] = backend.of(...endpointsToAssign.filter((e) => names.includes(backend.functionName(e))));
104
+ endpointsToAssign = endpointsToAssign.filter((e) => !names.includes(backend.functionName(e)));
105
+ }
106
+ for (const codebase of Object.keys(wantBackends)) {
107
+ const matchedEndpoints = endpointsToAssign.filter((e) => e.codebase === codebase);
108
+ grouped[codebase] = backend.merge(grouped[codebase], backend.of(...matchedEndpoints));
109
+ const matchedNames = matchedEndpoints.map((e) => backend.functionName(e));
110
+ endpointsToAssign = endpointsToAssign.filter((e) => {
111
+ return !matchedNames.includes(backend.functionName(e));
112
+ });
113
+ }
114
+ return grouped;
115
+ }
116
+ exports.groupEndpointsByCodebase = groupEndpointsByCodebase;