firebase-tools 13.4.1 → 13.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -330,7 +330,9 @@ class Fabricator {
330
330
  .catch(rethrowAs(endpoint, "set invoker"));
331
331
  }
332
332
  else if (backend.isScheduleTriggered(endpoint)) {
333
- const invoker = [(0, checkIam_1.getDefaultComputeServiceAgent)(this.projectNumber)];
333
+ const invoker = endpoint.serviceAccount
334
+ ? [endpoint.serviceAccount]
335
+ : [(0, checkIam_1.getDefaultComputeServiceAgent)(this.projectNumber)];
334
336
  await this.executor
335
337
  .run(() => run.setInvokerCreate(endpoint.project, serviceName, invoker))
336
338
  .catch(rethrowAs(endpoint, "set invoker"));
@@ -411,7 +413,9 @@ class Fabricator {
411
413
  invoker = ["public"];
412
414
  }
413
415
  else if (backend.isScheduleTriggered(endpoint)) {
414
- invoker = [(0, checkIam_1.getDefaultComputeServiceAgent)(this.projectNumber)];
416
+ invoker = endpoint.serviceAccount
417
+ ? [endpoint.serviceAccount]
418
+ : [(0, checkIam_1.getDefaultComputeServiceAgent)(this.projectNumber)];
415
419
  }
416
420
  if (invoker) {
417
421
  await this.executor
@@ -117,13 +117,16 @@ async function beforeEmulatorCommand(options) {
117
117
  }
118
118
  exports.beforeEmulatorCommand = beforeEmulatorCommand;
119
119
  function parseInspectionPort(options) {
120
- let port = options.inspectFunctions;
121
- if (port === true) {
122
- port = "9229";
120
+ const port = options.inspectFunctions;
121
+ if (typeof port === "undefined") {
122
+ return false;
123
+ }
124
+ else if (typeof port === "boolean") {
125
+ return port;
123
126
  }
124
127
  const parsed = Number(port);
125
128
  if (isNaN(parsed) || parsed < 1024 || parsed > 65535) {
126
- throw new error_1.FirebaseError(`"${port}" is not a valid port for debugging, please pass an integer between 1024 and 65535.`);
129
+ throw new error_1.FirebaseError(`"${port}" is not a valid port for debugging, please pass an integer between 1024 and 65535 or true for a dynamic port.`);
127
130
  }
128
131
  return parsed;
129
132
  }
@@ -332,10 +332,9 @@ async function startAll(options, showUI = true, runningTestScript = false) {
332
332
  const functionsLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS);
333
333
  const functionsAddr = legacyGetFirstAddr(types_1.Emulators.FUNCTIONS);
334
334
  const projectId = (0, projectUtils_1.needProjectId)(options);
335
- let inspectFunctions;
336
- if (options.inspectFunctions) {
337
- inspectFunctions = commandUtils.parseInspectionPort(options);
338
- functionsLogger.logLabeled("WARN", "functions", `You are running the Functions emulator in debug mode (port=${inspectFunctions}). This means that functions will execute in sequence rather than in parallel.`);
335
+ const inspectFunctions = commandUtils.parseInspectionPort(options);
336
+ if (inspectFunctions) {
337
+ functionsLogger.logLabeled("WARN", "functions", `You are running the Functions emulator in debug mode. This means that functions will execute in sequence rather than in parallel.`);
339
338
  }
340
339
  const emulatorsNotRunning = types_1.ALL_SERVICE_EMULATORS.filter((e) => {
341
340
  return e !== types_1.Emulators.FUNCTIONS && !listenForEmulator[e];
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
23
23
  expectedChecksum: "2fd771101c0e1f7898c04c9204f2ce63",
24
24
  },
25
25
  firestore: {
26
- version: "1.19.2",
27
- expectedSize: 67203281,
28
- expectedChecksum: "167205aea99351c08ef293f35009a63c",
26
+ version: "1.19.3",
27
+ expectedSize: 67296394,
28
+ expectedChecksum: "08a9b882a5c38570b6333f3931b1e52b",
29
29
  },
30
30
  storage: {
31
31
  version: "1.1.3",
@@ -35,9 +35,9 @@ const EMULATOR_UPDATE_DETAILS = {
35
35
  ui: experiments.isEnabled("emulatoruisnapshot")
36
36
  ? { version: "SNAPSHOT", expectedSize: -1, expectedChecksum: "" }
37
37
  : {
38
- version: "1.11.7",
39
- expectedSize: 3064105,
40
- expectedChecksum: "bd2bcc331cbf613a5b3b55a1ce08998b",
38
+ version: "1.11.8",
39
+ expectedSize: 3523907,
40
+ expectedChecksum: "49f6dc1911dda9d10df62a6c09aaf9a0",
41
41
  },
42
42
  pubsub: {
43
43
  version: "0.7.1",
@@ -83,7 +83,7 @@ exports.DownloadDetails = {
83
83
  version: EMULATOR_UPDATE_DETAILS.ui.version,
84
84
  downloadPath: path.join(CACHE_DIR, `ui-v${EMULATOR_UPDATE_DETAILS.ui.version}.zip`),
85
85
  unzipDir: path.join(CACHE_DIR, `ui-v${EMULATOR_UPDATE_DETAILS.ui.version}`),
86
- binaryPath: path.join(CACHE_DIR, `ui-v${EMULATOR_UPDATE_DETAILS.ui.version}`, "server", "server.js"),
86
+ binaryPath: path.join(CACHE_DIR, `ui-v${EMULATOR_UPDATE_DETAILS.ui.version}`, "server", "server.mjs"),
87
87
  opts: {
88
88
  cacheDir: CACHE_DIR,
89
89
  remoteUrl: `https://storage.googleapis.com/firebase-preview-drop/emulator/ui-v${EMULATOR_UPDATE_DETAILS.ui.version}.zip`,
@@ -84,6 +84,11 @@ class FunctionsEmulator {
84
84
  this.debugMode = false;
85
85
  emulatorLogger_1.EmulatorLogger.setVerbosity(this.args.verbosity ? emulatorLogger_1.Verbosity[this.args.verbosity] : emulatorLogger_1.Verbosity["DEBUG"]);
86
86
  if (this.args.debugPort) {
87
+ const maybeNodeCodebases = this.args.emulatableBackends.filter((b) => !b.runtime || b.runtime.startsWith("node"));
88
+ if (maybeNodeCodebases.length > 1 && typeof this.args.debugPort === "number") {
89
+ throw new error_1.FirebaseError("Cannot debug on a single port with multiple codebases. " +
90
+ "Use --inspect-functions=true to assign dynamic ports to each codebase");
91
+ }
87
92
  this.args.disabledRuntimeFeatures = this.args.disabledRuntimeFeatures || {};
88
93
  this.args.disabledRuntimeFeatures.timeout = true;
89
94
  this.debugMode = true;
@@ -847,8 +852,22 @@ class FunctionsEmulator {
847
852
  this.logger.log("WARN", `To enable function inspection, please run "npm i node@${semver.coerce(backend.runtime || "18.0.0")} --save-dev" in your functions directory`);
848
853
  }
849
854
  else {
855
+ let port;
856
+ if (typeof this.args.debugPort === "number") {
857
+ port = this.args.debugPort;
858
+ }
859
+ else {
860
+ port = await portfinder.getPortPromise({ port: 9229 });
861
+ if (port === 9229) {
862
+ this.logger.logLabeled("SUCCESS", "functions", `Using debug port 9229 for functions codebase ${backend.codebase}`);
863
+ }
864
+ else {
865
+ this.logger.logLabeled("SUCCESS", "functions", `Using debug port ${port} for functions codebase ${backend.codebase}. ` +
866
+ "You may need to add manually add this port to your inspector.");
867
+ }
868
+ }
850
869
  const { host } = this.getInfo();
851
- args.unshift(`--inspect=${(0, utils_1.connectableHostname)(host)}:${this.args.debugPort}`);
870
+ args.unshift(`--inspect=${(0, utils_1.connectableHostname)(host)}:${port}`);
852
871
  }
853
872
  }
854
873
  const pnpPath = path.join(backend.functionsDir, ".pnp.js");
@@ -865,7 +884,7 @@ class FunctionsEmulator {
865
884
  const socketPath = (0, functionsEmulatorShared_1.getTemporarySocketPath)();
866
885
  const childProcess = spawn(bin, args, {
867
886
  cwd: backend.functionsDir,
868
- env: Object.assign(Object.assign(Object.assign({ node: backend.bin }, process.env), envs), { PORT: socketPath }),
887
+ env: Object.assign(Object.assign(Object.assign({ node: backend.bin, METADATA_SERVER_DETECTION: "none" }, process.env), envs), { PORT: socketPath }),
869
888
  stdio: ["pipe", "pipe", "pipe", "ipc"],
870
889
  });
871
890
  return Promise.resolve({
@@ -129,7 +129,7 @@ async function ensureApiEnabled(options) {
129
129
  }
130
130
  exports.ensureApiEnabled = ensureApiEnabled;
131
131
  async function getNextRolloutId(projectId, location, backendId, counter) {
132
- var _a;
132
+ var _a, _b;
133
133
  const date = new Date();
134
134
  const year = date.getUTCFullYear();
135
135
  const month = String(date.getUTCMonth() + 1).padStart(2, "0");
@@ -137,22 +137,28 @@ async function getNextRolloutId(projectId, location, backendId, counter) {
137
137
  if (counter) {
138
138
  return `build-${year}-${month}-${day}-${String(counter).padStart(3, "0")}`;
139
139
  }
140
- const builds = await exports.listRollouts(projectId, location, backendId);
141
- if ((_a = builds.unreachable) === null || _a === void 0 ? void 0 : _a.includes(location)) {
140
+ const rolloutsPromise = exports.listRollouts(projectId, location, backendId);
141
+ const buildsPromise = exports.listBuilds(projectId, location, backendId);
142
+ const [rollouts, builds] = await Promise.all([rolloutsPromise, buildsPromise]);
143
+ if (((_a = builds.unreachable) === null || _a === void 0 ? void 0 : _a.includes(location)) || ((_b = rollouts.unreachable) === null || _b === void 0 ? void 0 : _b.includes(location))) {
142
144
  throw new error_1.FirebaseError(`Firebase App Hosting is currently unreachable in location ${location}`);
143
145
  }
144
- let highest = 0;
145
- const test = new RegExp(`projects/${projectId}/locations/${location}/backends/${backendId}/rollouts/build-${year}-${month}-${day}-(\\d+)`);
146
- for (const rollout of builds.rollouts) {
147
- const match = rollout.name.match(test);
148
- if (!match) {
149
- continue;
150
- }
151
- const n = Number(match[1]);
152
- if (n > highest) {
153
- highest = n;
146
+ const test = new RegExp(`projects/${projectId}/locations/${location}/backends/${backendId}/(rollouts|builds)/build-${year}-${month}-${day}-(\\d+)`);
147
+ const highestId = (input) => {
148
+ let highest = 0;
149
+ for (const i of input) {
150
+ const match = i.name.match(test);
151
+ if (!match) {
152
+ continue;
153
+ }
154
+ const n = Number(match[2]);
155
+ if (n > highest) {
156
+ highest = n;
157
+ }
154
158
  }
155
- }
159
+ return highest;
160
+ };
161
+ const highest = Math.max(highestId(builds.builds), highestId(rollouts.rollouts));
156
162
  return `build-${year}-${month}-${day}-${String(highest + 1).padStart(3, "0")}`;
157
163
  }
158
164
  exports.getNextRolloutId = getNextRolloutId;
@@ -215,6 +215,9 @@ function functionFromEndpoint(endpoint) {
215
215
  eventType: endpoint.eventTrigger.eventType,
216
216
  retryPolicy: "RETRY_POLICY_UNSPECIFIED",
217
217
  };
218
+ if (endpoint.serviceAccount) {
219
+ gcfFunction.eventTrigger.serviceAccountEmail = endpoint.serviceAccount;
220
+ }
218
221
  if (gcfFunction.eventTrigger.eventType === v2_1.PUBSUB_PUBLISH_EVENT) {
219
222
  if (!((_b = endpoint.eventTrigger.eventFilters) === null || _b === void 0 ? void 0 : _b.topic)) {
220
223
  throw new error_1.FirebaseError("Error: Pub/Sub event trigger is missing topic: " +
@@ -112,6 +112,7 @@ function topicNameForEndpoint(endpoint) {
112
112
  }
113
113
  exports.topicNameForEndpoint = topicNameForEndpoint;
114
114
  function jobFromEndpoint(endpoint, location, projectNumber) {
115
+ var _a;
115
116
  const job = {};
116
117
  job.name = jobNameForEndpoint(endpoint, location);
117
118
  if (endpoint.platform === "gcfv1") {
@@ -129,7 +130,7 @@ function jobFromEndpoint(endpoint, location, projectNumber) {
129
130
  uri: endpoint.uri,
130
131
  httpMethod: "POST",
131
132
  oidcToken: {
132
- serviceAccountEmail: (0, checkIam_1.getDefaultComputeServiceAgent)(projectNumber),
133
+ serviceAccountEmail: (_a = endpoint.serviceAccount) !== null && _a !== void 0 ? _a : (0, checkIam_1.getDefaultComputeServiceAgent)(projectNumber),
133
134
  },
134
135
  };
135
136
  }
@@ -172,31 +172,9 @@ async function orchestrateRollout(projectId, location, backendId, buildInput) {
172
172
  (0, utils_1.logBullet)("Starting a new rollout... this may take a few minutes.");
173
173
  const buildId = await apphosting.getNextRolloutId(projectId, location, backendId, 1);
174
174
  const buildOp = await apphosting.createBuild(projectId, location, backendId, buildId, buildInput);
175
- const rolloutBody = {
175
+ const rolloutOp = await apphosting.createRollout(projectId, location, backendId, buildId, {
176
176
  build: `projects/${projectId}/locations/${location}/backends/${backendId}/builds/${buildId}`,
177
- };
178
- let tries = 0;
179
- let done = false;
180
- while (!done) {
181
- tries++;
182
- try {
183
- const validateOnly = true;
184
- await apphosting.createRollout(projectId, location, backendId, buildId, rolloutBody, validateOnly);
185
- done = true;
186
- }
187
- catch (err) {
188
- if (err instanceof error_1.FirebaseError && err.status === 400) {
189
- if (tries >= 5) {
190
- throw err;
191
- }
192
- await new Promise((resolve) => setTimeout(resolve, 1000));
193
- }
194
- else {
195
- throw err;
196
- }
197
- }
198
- }
199
- const rolloutOp = await apphosting.createRollout(projectId, location, backendId, buildId, rolloutBody);
177
+ });
200
178
  const rolloutPoll = poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `create-${projectId}-${location}-backend-${backendId}-rollout-${buildId}`, operationResourceName: rolloutOp.name }));
201
179
  const buildPoll = poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `create-${projectId}-${location}-backend-${backendId}-build-${buildId}`, operationResourceName: buildOp.name }));
202
180
  const [rollout, build] = await Promise.all([rolloutPoll, buildPoll]);
@@ -8,6 +8,7 @@ const auth_1 = require("../auth");
8
8
  const projectConfig = require("../functions/projectConfig");
9
9
  const utils = require("../utils");
10
10
  const registry_1 = require("../emulator/registry");
11
+ const commandUtils_1 = require("../emulator/commandUtils");
11
12
  class FunctionsServer {
12
13
  assertServer() {
13
14
  if (!this.emulator || !this.backends) {
@@ -31,7 +32,7 @@ class FunctionsServer {
31
32
  }
32
33
  this.backends = backends;
33
34
  const account = (0, auth_1.getProjectDefaultAccount)(options.config.projectDir);
34
- const args = Object.assign({ projectId, projectDir: options.config.projectDir, emulatableBackends: this.backends, projectAlias: options.projectAlias, account }, partialArgs);
35
+ const args = Object.assign(Object.assign({ projectId, projectDir: options.config.projectDir, emulatableBackends: this.backends, projectAlias: options.projectAlias, account }, partialArgs), { debugPort: (0, commandUtils_1.parseInspectionPort)(options) });
35
36
  if (options.host) {
36
37
  utils.assertIsStringOrUndefined(options.host);
37
38
  args.host = options.host;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "13.4.1",
3
+ "version": "13.5.1",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {