firebase-tools 11.25.2 → 11.26.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.
@@ -17,7 +17,10 @@ marked_1.marked.setOptions({
17
17
  });
18
18
  exports.command = new command_1.Command("ext:dev:publish <extensionRef>")
19
19
  .description(`publish a new version of an extension`)
20
- .option(`-s, --stage <stage>`, `release stage (supports "rc", "alpha", "beta", and "stable")`)
20
+ .option(`-s, --stage <stage>`, `release stage (supports "alpha", "beta", "rc", and "stable")`)
21
+ .option(`--repo <repo>`, `Public Git repo URI (only required for first version from repo, cannot be changed)`)
22
+ .option(`--ref <ref>`, `commit hash, branch, or tag to build from the repo (defaults to HEAD)`)
23
+ .option(`--root <root>`, `root directory that contains this Extension (defaults to previous version's root or root of repo if none set)`)
21
24
  .withForce()
22
25
  .help("if you have not previously published a version of this extension, this will " +
23
26
  "create the extension. If you have previously published a version of this extension, this version must " +
@@ -32,15 +35,30 @@ exports.command = new command_1.Command("ext:dev:publish <extensionRef>")
32
35
  if (!publisherId || !extensionId) {
33
36
  throw new error_1.FirebaseError(`Error parsing publisher ID and extension ID from extension reference '${clc.bold(extensionRef)}'. Please use the format '${clc.bold("<publisherId>/<extensionId>")}'.`);
34
37
  }
35
- const extensionYamlDirectory = (0, localHelper_1.findExtensionYaml)(process.cwd());
36
- const res = await (0, extensionsHelper_1.publishExtensionVersionFromLocalSource)({
37
- publisherId,
38
- extensionId,
39
- rootDirectory: extensionYamlDirectory,
40
- nonInteractive: options.nonInteractive,
41
- force: options.force,
42
- stage: (_a = options.stage) !== null && _a !== void 0 ? _a : "stable",
43
- });
38
+ let res;
39
+ if (options.repo || options.root || options.ref) {
40
+ res = await (0, extensionsHelper_1.publishExtensionVersionFromRemoteRepo)({
41
+ publisherId,
42
+ extensionId,
43
+ repoUri: options.repo,
44
+ sourceRef: options.ref,
45
+ extensionRoot: options.root,
46
+ nonInteractive: options.nonInteractive,
47
+ force: options.force,
48
+ stage: options.stage,
49
+ });
50
+ }
51
+ else {
52
+ const extensionYamlDirectory = (0, localHelper_1.findExtensionYaml)(process.cwd());
53
+ res = await (0, extensionsHelper_1.publishExtensionVersionFromLocalSource)({
54
+ publisherId,
55
+ extensionId,
56
+ rootDirectory: extensionYamlDirectory,
57
+ nonInteractive: options.nonInteractive,
58
+ force: options.force,
59
+ stage: (_a = options.stage) !== null && _a !== void 0 ? _a : "stable",
60
+ });
61
+ }
44
62
  if (res) {
45
63
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, (0, marked_1.marked)(`[Install Link](${(0, publishHelpers_1.consoleInstallLink)(res.ref)})`));
46
64
  }
@@ -115,9 +115,8 @@ exports.command = new command_1.Command("ext:install [extensionName]")
115
115
  });
116
116
  async function infoExtensionVersion(args) {
117
117
  const ref = refs.parse(args.extensionName);
118
- const extension = await extensionsApi.getExtension(refs.toExtensionRef(ref));
119
118
  await (0, displayExtensionInfo_1.displayExtInfo)(args.extensionName, ref.publisherId, args.extensionVersion.spec, true);
120
- await (0, warnings_1.displayWarningPrompts)(ref.publisherId, extension.registryLaunchStage, args.extensionVersion);
119
+ await (0, warnings_1.displayWarningPrompts)(ref.publisherId, args.extensionVersion);
121
120
  }
122
121
  async function installToManifest(options) {
123
122
  var _a, _b;
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
23
23
  expectedChecksum: "311609538bd65666eb724ef47c2e6466",
24
24
  },
25
25
  firestore: {
26
- version: "1.16.1",
27
- expectedSize: 64213741,
28
- expectedChecksum: "befa5f6cbe258e787bf0bbb4eb9da2c8",
26
+ version: "1.16.2",
27
+ expectedSize: 64601019,
28
+ expectedChecksum: "83f379a5b3d367503a860497fea3a936",
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.4",
39
- expectedSize: 3062916,
40
- expectedChecksum: "1773926323b07fdb9602d882a7682882",
38
+ version: "1.11.5",
39
+ expectedSize: 3063444,
40
+ expectedChecksum: "4045fef65cf71fb9d83b01fb8b160141",
41
41
  },
42
42
  pubsub: {
43
43
  version: "0.7.1",
@@ -82,15 +82,15 @@ class FunctionsEmulator {
82
82
  this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS);
83
83
  this.multicastTriggers = {};
84
84
  this.blockingFunctionsConfig = {};
85
+ this.debugMode = false;
85
86
  emulatorLogger_1.EmulatorLogger.verbosity = this.args.quiet ? emulatorLogger_1.Verbosity.QUIET : emulatorLogger_1.Verbosity.DEBUG;
86
87
  if (this.args.debugPort) {
87
88
  this.args.disabledRuntimeFeatures = this.args.disabledRuntimeFeatures || {};
88
89
  this.args.disabledRuntimeFeatures.timeout = true;
90
+ this.debugMode = true;
89
91
  }
90
92
  this.adminSdkConfig = Object.assign(Object.assign({}, this.args.adminSdkConfig), { projectId: this.args.projectId });
91
- const mode = this.args.debugPort
92
- ? types_1.FunctionsExecutionMode.SEQUENTIAL
93
- : types_1.FunctionsExecutionMode.AUTO;
93
+ const mode = this.debugMode ? types_1.FunctionsExecutionMode.SEQUENTIAL : types_1.FunctionsExecutionMode.AUTO;
94
94
  this.workerPools = {};
95
95
  for (const backend of this.args.emulatableBackends) {
96
96
  const pool = new functionsRuntimeWorker_1.RuntimeWorkerPool(mode);
@@ -204,6 +204,12 @@ class FunctionsEmulator {
204
204
  }
205
205
  }
206
206
  const worker = pool.getIdleWorker(trigger.id);
207
+ if (this.debugMode) {
208
+ await worker.sendDebugMsg({
209
+ functionTarget: trigger.entryPoint,
210
+ functionSignature: (0, functionsEmulatorShared_1.getSignatureType)(trigger),
211
+ });
212
+ }
207
213
  const reqBody = JSON.stringify(body);
208
214
  const headers = {
209
215
  "Content-Type": "application/json",
@@ -406,7 +412,7 @@ class FunctionsEmulator {
406
412
  this.logger.logLabeled("SUCCESS", `functions[${definition.id}]`, msg);
407
413
  }
408
414
  }
409
- if (this.args.debugPort) {
415
+ if (this.debugMode) {
410
416
  if (!((_a = emulatableBackend.runtime) === null || _a === void 0 ? void 0 : _a.startsWith("node"))) {
411
417
  this.logger.log("WARN", "--inspect-functions only supported for Node.js runtimes.");
412
418
  }
@@ -722,7 +728,7 @@ class FunctionsEmulator {
722
728
  emulatorInfos = emulatorInfos.concat(Object.values(this.args.remoteEmulators));
723
729
  }
724
730
  (0, env_1.setEnvVarsForEmulators)(envs, emulatorInfos);
725
- if (this.args.debugPort) {
731
+ if (this.debugMode) {
726
732
  envs["FUNCTION_DEBUG_MODE"] = "true";
727
733
  }
728
734
  return envs;
@@ -789,7 +795,7 @@ class FunctionsEmulator {
789
795
  }
790
796
  async startNode(backend, envs) {
791
797
  const args = [path.join(__dirname, "functionsEmulatorRuntime")];
792
- if (this.args.debugPort) {
798
+ if (this.debugMode) {
793
799
  if (process.env.FIREPIT_VERSION) {
794
800
  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`);
795
801
  }
@@ -824,7 +830,7 @@ class FunctionsEmulator {
824
830
  }
825
831
  async startPython(backend, envs) {
826
832
  const args = ["functions-framework"];
827
- if (this.args.debugPort) {
833
+ if (this.debugMode) {
828
834
  this.logger.log("WARN", "--inspect-functions not supported for Python functions. Ignored.");
829
835
  }
830
836
  const port = await portfinder.getPortPromise({
@@ -961,12 +967,13 @@ class FunctionsEmulator {
961
967
  return;
962
968
  }
963
969
  }
964
- const debugBundle = this.args.debugPort
965
- ? {
970
+ let debugBundle;
971
+ if (this.debugMode) {
972
+ debugBundle = {
966
973
  functionTarget: trigger.entryPoint,
967
974
  functionSignature: (0, functionsEmulatorShared_1.getSignatureType)(trigger),
968
- }
969
- : undefined;
975
+ };
976
+ }
970
977
  await pool.submitRequest(trigger.id, {
971
978
  method,
972
979
  path,
@@ -135,7 +135,7 @@ function createCloudEndpoints(emulator) {
135
135
  items: (_a = listResponse.items) === null || _a === void 0 ? void 0 : _a.map((item) => new metadata_1.CloudStorageObjectMetadata(item)),
136
136
  });
137
137
  });
138
- gcloudStorageAPI.delete("/b/:bucketId/o/:objectId", async (req, res) => {
138
+ gcloudStorageAPI.delete(["/b/:bucketId/o/:objectId", "/storage/v1/b/:bucketId/o/:objectId"], async (req, res) => {
139
139
  try {
140
140
  await adminStorageLayer.deleteObject({
141
141
  bucketId: req.params.bucketId,
@@ -391,15 +391,18 @@ async function undeprecateExtensionVersion(extensionRef) {
391
391
  }
392
392
  }
393
393
  exports.undeprecateExtensionVersion = undeprecateExtensionVersion;
394
- async function publishExtensionVersion(extensionVersionRef, packageUri, extensionRoot) {
395
- const ref = refs.parse(extensionVersionRef);
394
+ async function publishExtensionVersion(args) {
395
+ var _a, _b, _c, _d;
396
+ const ref = refs.parse(args.extensionVersionRef);
396
397
  if (!ref.version) {
397
- throw new error_1.FirebaseError(`ExtensionVersion ref "${extensionVersionRef}" must supply a version.`);
398
+ throw new error_1.FirebaseError(`ExtensionVersion ref "${args.extensionVersionRef}" must supply a version.`);
398
399
  }
399
400
  const publishRes = await apiClient.post(`/${refs.toExtensionName(ref)}/versions:publish`, {
400
401
  versionId: ref.version,
401
- packageUri,
402
- extensionRoot: extensionRoot !== null && extensionRoot !== void 0 ? extensionRoot : "/",
402
+ packageUri: (_a = args.packageUri) !== null && _a !== void 0 ? _a : "",
403
+ extensionRoot: (_b = args.extensionRoot) !== null && _b !== void 0 ? _b : "/",
404
+ repoUri: (_c = args.repoUri) !== null && _c !== void 0 ? _c : "",
405
+ sourceRef: (_d = args.sourceRef) !== null && _d !== void 0 ? _d : "",
403
406
  });
404
407
  const pollRes = await operationPoller.pollOperation({
405
408
  apiOrigin: api_1.extensionsOrigin,
@@ -1,9 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.canonicalizeRefInput = exports.diagnoseAndFixProject = exports.confirm = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.publishExtensionVersionFromLocalSource = exports.incrementPrereleaseVersion = exports.ensureExtensionsApiEnabled = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.AUTOPOULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
3
+ exports.canonicalizeRefInput = exports.diagnoseAndFixProject = exports.confirm = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.publishExtensionVersionFromLocalSource = exports.publishExtensionVersionFromRemoteRepo = exports.incrementPrereleaseVersion = exports.ensureExtensionsApiEnabled = exports.promptForValidRepoURI = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.AUTOPOULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
4
4
  const clc = require("colorette");
5
5
  const ora = require("ora");
6
6
  const semver = require("semver");
7
+ const tmp = require("tmp");
8
+ const fs = require("fs-extra");
9
+ const unzipper = require("unzipper");
10
+ const node_fetch_1 = require("node-fetch");
11
+ const path = require("path");
7
12
  const marked_1 = require("marked");
8
13
  const TerminalRenderer = require("marked-terminal");
9
14
  marked_1.marked.setOptions({
@@ -66,6 +71,11 @@ exports.AUTOPOULATED_PARAM_PLACEHOLDERS = {
66
71
  DATABASE_INSTANCE: "project-id-default-rtdb",
67
72
  DATABASE_URL: "https://project-id-default-rtdb.firebaseio.com",
68
73
  };
74
+ exports.resourceTypeToNiceName = {
75
+ "firebaseextensions.v1beta.function": "Cloud Function",
76
+ };
77
+ const repoRegex = new RegExp(`^https:\/\/github\.com\/[^\/]+\/[^\/]+$`);
78
+ const stageOptions = ["alpha", "beta", "rc", "stable"];
69
79
  function getDBInstanceFromURL(databaseUrl = "") {
70
80
  const instanceRegex = new RegExp("(?:https://)(.*)(?:.firebaseio.com)");
71
81
  const matches = instanceRegex.exec(databaseUrl);
@@ -263,6 +273,24 @@ async function promptForValidInstanceId(instanceId) {
263
273
  return newInstanceId;
264
274
  }
265
275
  exports.promptForValidInstanceId = promptForValidInstanceId;
276
+ async function promptForValidRepoURI() {
277
+ let repoIsValid = false;
278
+ let extensionRoot = "";
279
+ while (!repoIsValid) {
280
+ extensionRoot = await (0, prompt_1.promptOnce)({
281
+ type: "input",
282
+ message: "Enter the GitHub repo URI where this Extension's source code is located:",
283
+ });
284
+ if (!repoRegex.test(extensionRoot)) {
285
+ logger_1.logger.info("Repo URI must follow this format: https://github.com/<user>/<repo>");
286
+ }
287
+ else {
288
+ repoIsValid = true;
289
+ }
290
+ }
291
+ return extensionRoot;
292
+ }
293
+ exports.promptForValidRepoURI = promptForValidRepoURI;
266
294
  async function ensureExtensionsApiEnabled(options) {
267
295
  const projectId = (0, projectUtils_1.getProjectId)(options);
268
296
  if (!projectId) {
@@ -281,7 +309,6 @@ async function archiveAndUploadSource(extPath, bucketName) {
281
309
  }
282
310
  async function incrementPrereleaseVersion(ref, extensionVersion, stage) {
283
311
  var _a;
284
- const stageOptions = ["stable", "alpha", "beta", "rc"];
285
312
  if (!stageOptions.includes(stage)) {
286
313
  throw new error_1.FirebaseError(`--stage flag only supports the following values: ${stageOptions}`);
287
314
  }
@@ -306,7 +333,8 @@ async function incrementPrereleaseVersion(ref, extensionVersion, stage) {
306
333
  return extensionVersion;
307
334
  }
308
335
  exports.incrementPrereleaseVersion = incrementPrereleaseVersion;
309
- async function publishExtensionVersionFromLocalSource(args) {
336
+ async function validateExtensionSpec(args) {
337
+ const extensionRef = `${args.publisherId}/${args.extensionId}`;
310
338
  const extensionSpec = await (0, localHelper_1.getLocalExtensionSpec)(args.rootDirectory);
311
339
  if (extensionSpec.name !== args.extensionId) {
312
340
  throw new error_1.FirebaseError(`Extension ID '${clc.bold(args.extensionId)}' does not match the name in extension.yaml '${clc.bold(extensionSpec.name)}'.`);
@@ -314,13 +342,7 @@ async function publishExtensionVersionFromLocalSource(args) {
314
342
  const subbedSpec = JSON.parse(JSON.stringify(extensionSpec));
315
343
  subbedSpec.params = substituteParams(extensionSpec.params || [], exports.AUTOPOULATED_PARAM_PLACEHOLDERS);
316
344
  validateSpec(subbedSpec);
317
- extensionSpec.version = await incrementPrereleaseVersion(`${args.publisherId}/${args.extensionId}`, extensionSpec.version, args.stage);
318
- let extension;
319
- try {
320
- extension = await (0, extensionsApi_1.getExtension)(`${args.publisherId}/${args.extensionId}`);
321
- }
322
- catch (err) {
323
- }
345
+ extensionSpec.version = await incrementPrereleaseVersion(extensionRef, extensionSpec.version, args.stage);
324
346
  let notes;
325
347
  try {
326
348
  const changes = (0, change_log_1.getLocalChangelog)(args.rootDirectory);
@@ -331,30 +353,197 @@ async function publishExtensionVersionFromLocalSource(args) {
331
353
  "Please create one and add an entry for this version. " +
332
354
  (0, marked_1.marked)("See https://firebase.google.com/docs/extensions/alpha/create-user-docs#writing-changelog for more details."));
333
355
  }
334
- if (!notes && !semver.prerelease(extensionSpec.version) && extension) {
356
+ if (!notes && !semver.prerelease(extensionSpec.version) && args.latestVersion) {
335
357
  throw new error_1.FirebaseError(`No entry for version ${extensionSpec.version} found in CHANGELOG.md. ` +
336
358
  "Please add one so users know what has changed in this version. " +
337
359
  (0, marked_1.marked)("See https://firebase.google.com/docs/extensions/alpha/create-user-docs#writing-changelog for more details."));
338
360
  }
339
- displayReleaseNotes(args.publisherId, args.extensionId, extensionSpec.version, notes);
340
- if (!(await confirm({
361
+ if (args.latestVersion) {
362
+ if (semver.lt(extensionSpec.version, args.latestVersion)) {
363
+ throw new error_1.FirebaseError(`The version you are trying to publish (${clc.bold(extensionSpec.version)}) is lower than the current version (${clc.bold(args.latestVersion)}) for the extension '${clc.bold(extensionRef)}'. Please make sure this version is greater than the current version (${clc.bold(args.latestVersion)}) inside of extension.yaml.\n`, { exit: 104 });
364
+ }
365
+ else if (semver.eq(extensionSpec.version, args.latestVersion)) {
366
+ throw new error_1.FirebaseError(`The version you are trying to publish (${clc.bold(extensionSpec.version)}) already exists for Extension '${clc.bold(extensionRef)}'. Please increment the version inside of extension.yaml.\n`, { exit: 103 });
367
+ }
368
+ }
369
+ return { extensionSpec, notes };
370
+ }
371
+ async function publishExtensionVersionFromRemoteRepo(args) {
372
+ const extensionRef = `${args.publisherId}/${args.extensionId}`;
373
+ let extension;
374
+ try {
375
+ extension = await (0, extensionsApi_1.getExtension)(extensionRef);
376
+ }
377
+ catch (err) {
378
+ }
379
+ if (args.repoUri && !repoRegex.test(args.repoUri)) {
380
+ throw new error_1.FirebaseError("Repo URI must follow this format: https://github.com/<user>/<repo>");
381
+ }
382
+ let repoUri = args.repoUri || (extension === null || extension === void 0 ? void 0 : extension.repoUri);
383
+ if (!repoUri) {
384
+ if (!args.nonInteractive) {
385
+ repoUri = await promptForValidRepoURI();
386
+ }
387
+ else {
388
+ throw new error_1.FirebaseError("Repo URI is required but not currently set.");
389
+ }
390
+ }
391
+ if ((extension === null || extension === void 0 ? void 0 : extension.repoUri) && extension.repoUri !== repoUri) {
392
+ throw new error_1.FirebaseError(`Repo URI '${clc.bold(args.repoUri)}' does not match repo URI '${clc.bold(extension.repoUri)}' already associated with Extension ${clc.bold(extensionRef)}. Repo URI cannot be changed.`);
393
+ }
394
+ if (!(extension === null || extension === void 0 ? void 0 : extension.repoUri)) {
395
+ logger_1.logger.info(`\n${clc.red("Warning:")} You are about to associate repo URI ${clc.bold(repoUri)} with Extension ${clc.bold(extensionRef)}. This cannot be changed. All future verifiable versions must be published from this repo. ` +
396
+ `You can continue publishing unverifiable versions from local source.`);
397
+ const confirmed = await confirm({
398
+ nonInteractive: args.nonInteractive,
399
+ force: args.force,
400
+ default: false,
401
+ });
402
+ if (!confirmed) {
403
+ return;
404
+ }
405
+ }
406
+ else {
407
+ logger_1.logger.info(`Extension ${clc.bold(extensionRef)} is published from ${clc.bold(extension === null || extension === void 0 ? void 0 : extension.repoUri)}.`);
408
+ }
409
+ let extensionRoot = args.extensionRoot;
410
+ let defaultRoot = "/";
411
+ if (!extensionRoot) {
412
+ if (extension) {
413
+ try {
414
+ const extensionVersionRef = `${extensionRef}@${extension.latestVersion}`;
415
+ const extensionVersion = await (0, extensionsApi_1.getExtensionVersion)(extensionVersionRef);
416
+ if (extensionVersion.extensionRoot) {
417
+ defaultRoot = extensionVersion.extensionRoot;
418
+ }
419
+ }
420
+ catch (err) {
421
+ }
422
+ }
423
+ extensionRoot = defaultRoot;
424
+ if (!args.nonInteractive) {
425
+ extensionRoot = await (0, prompt_1.promptOnce)({
426
+ type: "input",
427
+ message: "Enter this Extension's root directory in the repo (defaults to previous root if set):",
428
+ default: defaultRoot,
429
+ });
430
+ }
431
+ }
432
+ let sourceRef = args.sourceRef;
433
+ const defaultSourceRef = "HEAD";
434
+ if (!sourceRef) {
435
+ if (!args.nonInteractive) {
436
+ sourceRef = await (0, prompt_1.promptOnce)({
437
+ type: "input",
438
+ message: "Enter the commit hash, branch, or tag name to build from in the repo:",
439
+ default: defaultSourceRef,
440
+ });
441
+ }
442
+ else {
443
+ sourceRef = defaultSourceRef;
444
+ }
445
+ }
446
+ let stage = args.stage;
447
+ const defaultStage = "rc";
448
+ if (!stage) {
449
+ if (!args.nonInteractive) {
450
+ stage = await (0, prompt_1.promptOnce)({
451
+ type: "list",
452
+ message: "Choose the release stage (pre-release annotations will be auto-incremented):",
453
+ choices: stageOptions,
454
+ default: defaultStage,
455
+ });
456
+ }
457
+ else {
458
+ stage = defaultStage;
459
+ }
460
+ }
461
+ logger_1.logger.info("Downloading and validating source code...");
462
+ const archiveUri = `${repoUri}/archive/${sourceRef}.zip`;
463
+ const tempDirectory = tmp.dirSync({ unsafeCleanup: true });
464
+ try {
465
+ const response = await (0, node_fetch_1.default)(archiveUri);
466
+ if (response.ok) {
467
+ await response.body.pipe(unzipper.Extract({ path: tempDirectory.name })).promise();
468
+ }
469
+ }
470
+ catch (err) {
471
+ throw new error_1.FirebaseError(`Failed to fetch Extension archive ${archiveUri}. Please check the repo URI and source ref. ${err}`);
472
+ }
473
+ const archiveName = fs.readdirSync(tempDirectory.name)[0];
474
+ const rootDirectory = path.join(tempDirectory.name, archiveName, extensionRoot);
475
+ try {
476
+ (0, localHelper_1.readFile)(path.resolve(rootDirectory, localHelper_1.EXTENSIONS_SPEC_FILE));
477
+ }
478
+ catch (err) {
479
+ throw new error_1.FirebaseError(`Failed to find ${clc.bold(localHelper_1.EXTENSIONS_SPEC_FILE)} in directory ${clc.bold(extensionRoot)}. Please verify the root and try again.`);
480
+ }
481
+ const { extensionSpec, notes } = await validateExtensionSpec({
482
+ publisherId: args.publisherId,
483
+ extensionId: args.extensionId,
484
+ rootDirectory: rootDirectory,
485
+ latestVersion: extension === null || extension === void 0 ? void 0 : extension.latestVersion,
486
+ stage: stage,
487
+ });
488
+ const sourceUri = path.join(repoUri, "tree", sourceRef, extensionRoot);
489
+ displayReleaseNotes(extensionRef, extensionSpec.version, notes, sourceUri);
490
+ const confirmed = await confirm({
341
491
  nonInteractive: args.nonInteractive,
342
492
  force: args.force,
343
493
  default: false,
344
- }))) {
494
+ });
495
+ if (!confirmed) {
345
496
  return;
346
497
  }
347
- if (extension &&
348
- extension.latestVersion &&
349
- semver.lt(extensionSpec.version, extension.latestVersion)) {
350
- throw new error_1.FirebaseError(`The version you are trying to publish (${clc.bold(extensionSpec.version)}) is lower than the current version (${clc.bold(extension.latestVersion)}) for the extension '${clc.bold(`${args.publisherId}/${args.extensionId}`)}'. Please make sure this version is greater than the current version (${clc.bold(extension.latestVersion)}) inside of extension.yaml.\n`, { exit: 104 });
498
+ const extensionVersionRef = `${extensionRef}@${extensionSpec.version}`;
499
+ const publishSpinner = ora(`Publishing ${clc.bold(extensionVersionRef)}`);
500
+ let res;
501
+ try {
502
+ publishSpinner.start();
503
+ res = await (0, extensionsApi_1.publishExtensionVersion)({
504
+ extensionVersionRef,
505
+ packageUri: "",
506
+ extensionRoot,
507
+ repoUri,
508
+ sourceRef: args.sourceRef,
509
+ });
510
+ publishSpinner.succeed(` Successfully published ${clc.bold(extensionRef)}`);
351
511
  }
352
- else if (extension &&
353
- extension.latestVersion &&
354
- semver.eq(extensionSpec.version, extension.latestVersion)) {
355
- throw new error_1.FirebaseError(`The version you are trying to publish (${clc.bold(extensionSpec.version)}) already exists for the extension '${clc.bold(`${args.publisherId}/${args.extensionId}`)}'. Please increment the version inside of extension.yaml.\n`, { exit: 103 });
512
+ catch (err) {
513
+ publishSpinner.fail();
514
+ if (err.status === 404) {
515
+ throw getMissingPublisherError(args.publisherId);
516
+ }
517
+ throw err;
518
+ }
519
+ return res;
520
+ }
521
+ exports.publishExtensionVersionFromRemoteRepo = publishExtensionVersionFromRemoteRepo;
522
+ async function publishExtensionVersionFromLocalSource(args) {
523
+ let extension;
524
+ try {
525
+ extension = await (0, extensionsApi_1.getExtension)(`${args.publisherId}/${args.extensionId}`);
356
526
  }
357
- const ref = `${args.publisherId}/${args.extensionId}@${extensionSpec.version}`;
527
+ catch (err) {
528
+ }
529
+ const { extensionSpec, notes } = await validateExtensionSpec({
530
+ publisherId: args.publisherId,
531
+ extensionId: args.extensionId,
532
+ rootDirectory: args.rootDirectory,
533
+ latestVersion: extension === null || extension === void 0 ? void 0 : extension.latestVersion,
534
+ stage: args.stage,
535
+ });
536
+ const extensionRef = `${args.publisherId}/${args.extensionId}`;
537
+ displayReleaseNotes(extensionRef, extensionSpec.version, notes);
538
+ const confirmed = await confirm({
539
+ nonInteractive: args.nonInteractive,
540
+ force: args.force,
541
+ default: false,
542
+ });
543
+ if (!confirmed) {
544
+ return;
545
+ }
546
+ const extensionVersionRef = `${extensionRef}@${extensionSpec.version}`;
358
547
  let packageUri;
359
548
  let objectPath = "";
360
549
  const uploadSpinner = ora(" Archiving and uploading extension source code");
@@ -370,17 +559,17 @@ async function publishExtensionVersionFromLocalSource(args) {
370
559
  original: err,
371
560
  });
372
561
  }
373
- const publishSpinner = ora(`Publishing ${clc.bold(ref)}`);
562
+ const publishSpinner = ora(`Publishing ${clc.bold(extensionVersionRef)}`);
374
563
  let res;
375
564
  try {
376
565
  publishSpinner.start();
377
- res = await (0, extensionsApi_1.publishExtensionVersion)(ref, packageUri);
378
- publishSpinner.succeed(` Successfully published ${clc.bold(ref)}`);
566
+ res = await (0, extensionsApi_1.publishExtensionVersion)({ extensionVersionRef, packageUri });
567
+ publishSpinner.succeed(` Successfully published ${clc.bold(extensionVersionRef)}`);
379
568
  }
380
569
  catch (err) {
381
570
  publishSpinner.fail();
382
571
  if (err.status === 404) {
383
- throw new error_1.FirebaseError((0, marked_1.marked)(`Couldn't find publisher ID '${clc.bold(args.publisherId)}'. Please ensure that you have registered this ID. To register as a publisher, you can check out the [Firebase documentation](https://firebase.google.com/docs/extensions/alpha/share#register_as_an_extensions_publisher) for step-by-step instructions.`));
572
+ throw getMissingPublisherError(args.publisherId);
384
573
  }
385
574
  throw err;
386
575
  }
@@ -388,6 +577,9 @@ async function publishExtensionVersionFromLocalSource(args) {
388
577
  return res;
389
578
  }
390
579
  exports.publishExtensionVersionFromLocalSource = publishExtensionVersionFromLocalSource;
580
+ function getMissingPublisherError(publisherId) {
581
+ return new error_1.FirebaseError((0, marked_1.marked)(`Couldn't find publisher ID '${clc.bold(publisherId)}'. Please ensure that you have registered this ID. To register as a publisher, you can check out the [Firebase documentation](https://firebase.google.com/docs/extensions/alpha/share#register_as_an_extensions_publisher) for step-by-step instructions.`));
582
+ }
391
583
  async function createSourceFromLocation(projectId, sourceUri) {
392
584
  const extensionRoot = "/";
393
585
  let packageUri;
@@ -431,12 +623,18 @@ function getPublisherProjectFromName(publisherName) {
431
623
  throw new error_1.FirebaseError(`Could not find publisher with name '${publisherName}'.`);
432
624
  }
433
625
  exports.getPublisherProjectFromName = getPublisherProjectFromName;
434
- function displayReleaseNotes(publisherId, extensionId, versionId, releaseNotes) {
626
+ function displayReleaseNotes(extensionRef, versionId, releaseNotes, sourceUri) {
627
+ const source = sourceUri || "local source";
435
628
  const releaseNotesMessage = releaseNotes
436
- ? ` Release notes for this version:\n${(0, marked_1.marked)(releaseNotes)}\n`
437
- : "\n";
438
- const message = `You are about to publish version ${clc.green(versionId)} of ${clc.green(`${publisherId}/${extensionId}`)} to Firebase's registry of extensions.${releaseNotesMessage}` +
439
- "Once an extension version is published, it cannot be changed. If you wish to make changes after publishing, you will need to publish a new version.\n\n";
629
+ ? `${clc.bold("Release notes:")}\n${(0, marked_1.marked)(releaseNotes)}`
630
+ : "";
631
+ const metadataMessage = `${clc.bold("Extension:")} ${extensionRef}\n` +
632
+ `${clc.bold("Version:")} ${clc.bold(clc.green(versionId))}\n` +
633
+ `${clc.bold("Source:")} ${source}\n`;
634
+ const message = `\nYou are about to publish a new version to Firebase's registry of Extensions.\n\n` +
635
+ metadataMessage +
636
+ releaseNotesMessage +
637
+ `\nOnce an Extension version is published, it cannot be changed. If you wish to make changes after publishing, you will need to publish a new version.\n`;
440
638
  logger_1.logger.info(message);
441
639
  }
442
640
  exports.displayReleaseNotes = displayReleaseNotes;
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isLocalExtension = exports.readFile = exports.findExtensionYaml = exports.getLocalExtensionSpec = void 0;
3
+ exports.isLocalExtension = exports.readFile = exports.findExtensionYaml = exports.getLocalExtensionSpec = exports.EXTENSIONS_SPEC_FILE = void 0;
4
4
  const fs = require("fs-extra");
5
5
  const path = require("path");
6
6
  const yaml = require("js-yaml");
7
7
  const fsutils_1 = require("../fsutils");
8
8
  const error_1 = require("../error");
9
9
  const logger_1 = require("../logger");
10
- const EXTENSIONS_SPEC_FILE = "extension.yaml";
10
+ exports.EXTENSIONS_SPEC_FILE = "extension.yaml";
11
11
  const EXTENSIONS_PREINSTALL_FILE = "PREINSTALL.md";
12
12
  async function getLocalExtensionSpec(directory) {
13
- const spec = await parseYAML(readFile(path.resolve(directory, EXTENSIONS_SPEC_FILE)));
13
+ const spec = await parseYAML(readFile(path.resolve(directory, exports.EXTENSIONS_SPEC_FILE)));
14
14
  try {
15
15
  const preinstall = readFile(path.resolve(directory, EXTENSIONS_PREINSTALL_FILE));
16
16
  spec.preinstallContent = preinstall;
@@ -22,7 +22,7 @@ async function getLocalExtensionSpec(directory) {
22
22
  }
23
23
  exports.getLocalExtensionSpec = getLocalExtensionSpec;
24
24
  function findExtensionYaml(directory) {
25
- while (!(0, fsutils_1.fileExistsSync)(path.resolve(directory, EXTENSIONS_SPEC_FILE))) {
25
+ while (!(0, fsutils_1.fileExistsSync)(path.resolve(directory, exports.EXTENSIONS_SPEC_FILE))) {
26
26
  const parentDir = path.dirname(directory);
27
27
  if (parentDir === directory) {
28
28
  throw new error_1.FirebaseError("Couldn't find an extension.yaml file. Check that you are in the root directory of your extension.");
@@ -3,13 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.outOfBandChangesWarning = exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
4
4
  const marked_1 = require("marked");
5
5
  const clc = require("colorette");
6
- const types_1 = require("./types");
7
6
  const displayExtensionInfo_1 = require("./displayExtensionInfo");
8
7
  const extensionsHelper_1 = require("./extensionsHelper");
9
8
  const resolveSource_1 = require("./resolveSource");
10
9
  const deploymentSummary_1 = require("../deploy/extensions/deploymentSummary");
11
10
  const planner_1 = require("../deploy/extensions/planner");
12
- const functional_1 = require("../functional");
13
11
  const utils = require("../utils");
14
12
  const logger_1 = require("../logger");
15
13
  function displayEAPWarning({ publisherId, sourceDownloadUri, githubLink, }) {
@@ -19,10 +17,7 @@ function displayEAPWarning({ publisherId, sourceDownloadUri, githubLink, }) {
19
17
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, (0, marked_1.marked)(warningMsg + legalMsg));
20
18
  (0, displayExtensionInfo_1.printSourceDownloadLink)(sourceDownloadUri);
21
19
  }
22
- function displayExperimentalWarning() {
23
- utils.logLabeledBullet(extensionsHelper_1.logPrefix, (0, marked_1.marked)(`${clc.yellow(clc.bold("Important"))}: This extension is ${clc.bold("experimental")} and may not be production-ready. Its functionality might change in backward-incompatible ways before its official release, or it may be discontinued.`));
24
- }
25
- async function displayWarningPrompts(publisherId, launchStage, extensionVersion) {
20
+ async function displayWarningPrompts(publisherId, extensionVersion) {
26
21
  const trustedPublishers = await (0, resolveSource_1.getTrustedPublishers)();
27
22
  if (!trustedPublishers.includes(publisherId)) {
28
23
  displayEAPWarning({
@@ -31,9 +26,6 @@ async function displayWarningPrompts(publisherId, launchStage, extensionVersion)
31
26
  githubLink: extensionVersion.spec.sourceUrl,
32
27
  });
33
28
  }
34
- else if (launchStage === types_1.RegistryLaunchStage.EXPERIMENTAL) {
35
- displayExperimentalWarning();
36
- }
37
29
  else {
38
30
  return;
39
31
  }
@@ -54,19 +46,14 @@ async function displayWarningsForDeploy(instancesToCreate) {
54
46
  for (const i of publishedExtensionInstances) {
55
47
  await (0, planner_1.getExtension)(i);
56
48
  }
57
- const [eapExtensions, nonEapExtensions] = (0, functional_1.partition)(publishedExtensionInstances, (i) => { var _a, _b; return !trustedPublishers.includes((_b = (_a = i.ref) === null || _a === void 0 ? void 0 : _a.publisherId) !== null && _b !== void 0 ? _b : ""); });
58
- const experimental = nonEapExtensions.filter((i) => i.extension.registryLaunchStage === types_1.RegistryLaunchStage.EXPERIMENTAL);
59
- if (experimental.length) {
60
- const humanReadableList = experimental.map((i) => `\t${(0, deploymentSummary_1.humanReadable)(i)}`).join("\n");
61
- utils.logLabeledBullet(extensionsHelper_1.logPrefix, (0, marked_1.marked)(`The following are instances of ${clc.bold("experimental")} extensions.They may not be production-ready. Their functionality may change in backward-incompatible ways before their official release, or they may be discontinued.\n${humanReadableList}\n`, { gfm: false }));
62
- }
49
+ const eapExtensions = publishedExtensionInstances.filter((i) => { var _a, _b; return !trustedPublishers.includes((_b = (_a = i.ref) === null || _a === void 0 ? void 0 : _a.publisherId) !== null && _b !== void 0 ? _b : ""); });
63
50
  if (eapExtensions.length) {
64
51
  const humanReadableList = eapExtensions.map(toListEntry).join("\n");
65
52
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, (0, marked_1.marked)(`These extensions are in preview and are built by a developer in the Extensions Publisher Early Access Program (http://bit.ly/firex-provider). Their functionality might change in backwards-incompatible ways. Since these extensions aren't built by Firebase, reach out to their publisher with questions about them.` +
66
53
  ` They are provided “AS IS”, without any warranty, express or implied, from Google.` +
67
54
  ` Google disclaims all liability for any damages, direct or indirect, resulting from the use of these extensions\n${humanReadableList}`, { gfm: false }));
68
55
  }
69
- return experimental.length > 0 || eapExtensions.length > 0;
56
+ return eapExtensions.length > 0;
70
57
  }
71
58
  exports.displayWarningsForDeploy = displayWarningsForDeploy;
72
59
  function outOfBandChangesWarning(instanceIds) {
@@ -8,12 +8,10 @@ const fs_extra_1 = require("fs-extra");
8
8
  const promises_1 = require("fs/promises");
9
9
  const __1 = require("..");
10
10
  const prompt_1 = require("../../prompt");
11
- const proxy_1 = require("../../hosting/proxy");
12
11
  const utils_1 = require("../utils");
13
12
  exports.name = "Angular";
14
13
  exports.support = "experimental";
15
14
  exports.type = 3;
16
- const CLI_COMMAND = (0, path_1.join)("node_modules", ".bin", process.platform === "win32" ? "ng.cmd" : "ng");
17
15
  const DEFAULT_BUILD_SCRIPT = ["ng build"];
18
16
  async function discover(dir) {
19
17
  if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "package.json"))))
@@ -56,7 +54,8 @@ async function build(dir) {
56
54
  if (!browserTarget)
57
55
  throw new Error("No build target...");
58
56
  if (prerenderTarget) {
59
- (0, child_process_1.execSync)(`${CLI_COMMAND} run ${targetStringFromTarget(prerenderTarget)}`, {
57
+ const cli = (0, __1.getNodeModuleBin)("ng", dir);
58
+ (0, child_process_1.execSync)(`${cli} run ${targetStringFromTarget(prerenderTarget)}`, {
60
59
  cwd: dir,
61
60
  stdio: "inherit",
62
61
  });
@@ -76,7 +75,10 @@ async function getDevModeHandle(dir) {
76
75
  if (!serveTarget)
77
76
  return;
78
77
  const host = new Promise((resolve) => {
79
- const serve = (0, cross_spawn_1.spawn)(CLI_COMMAND, ["run", targetStringFromTarget(serveTarget), "--host", "localhost"], { cwd: dir });
78
+ const cli = (0, __1.getNodeModuleBin)("ng", dir);
79
+ const serve = (0, cross_spawn_1.spawn)(cli, ["run", targetStringFromTarget(serveTarget), "--host", "localhost"], {
80
+ cwd: dir,
81
+ });
80
82
  serve.stdout.on("data", (data) => {
81
83
  process.stdout.write(data);
82
84
  const match = data.toString().match(/(http:\/\/localhost:\d+)/);
@@ -87,7 +89,7 @@ async function getDevModeHandle(dir) {
87
89
  process.stderr.write(data);
88
90
  });
89
91
  });
90
- return (0, proxy_1.proxyRequestHandler)(await host, "Angular Live Development Server", { forceCascade: true });
92
+ return (0, utils_1.simpleProxy)(await host);
91
93
  }
92
94
  exports.getDevModeHandle = getDevModeHandle;
93
95
  async function ɵcodegenPublicDirectory(sourceDir, destDir) {
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,13 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createServerResponseProxy = exports.prepareFrameworks = exports.findDependency = exports.discover = exports.relativeRequire = exports.WebFrameworks = exports.ALLOWED_SSR_REGIONS = exports.DEFAULT_REGION = exports.NODE_VERSION = exports.FIREBASE_ADMIN_VERSION = exports.FIREBASE_FUNCTIONS_VERSION = exports.FIREBASE_FRAMEWORKS_VERSION = void 0;
3
+ exports.prepareFrameworks = exports.findDependency = exports.getNodeModuleBin = exports.discover = exports.relativeRequire = exports.WebFrameworks = exports.ALLOWED_SSR_REGIONS = exports.DEFAULT_REGION = exports.NODE_VERSION = exports.FIREBASE_ADMIN_VERSION = exports.FIREBASE_FUNCTIONS_VERSION = exports.FIREBASE_FRAMEWORKS_VERSION = void 0;
4
4
  const path_1 = require("path");
5
5
  const process_1 = require("process");
6
6
  const child_process_1 = require("child_process");
7
7
  const cross_spawn_1 = require("cross-spawn");
8
8
  const fs_1 = require("fs");
9
9
  const url_1 = require("url");
10
- const http_1 = require("http");
11
10
  const promises_1 = require("fs/promises");
12
11
  const fs_extra_1 = require("fs-extra");
13
12
  const clc = require("colorette");
@@ -29,12 +28,13 @@ const requireHostingSite_1 = require("../requireHostingSite");
29
28
  const experiments = require("../experiments");
30
29
  const ensureTargeted_1 = require("../functions/ensureTargeted");
31
30
  const implicitInit_1 = require("../hosting/implicitInit");
31
+ const fsutils_1 = require("../fsutils");
32
32
  const { dynamicImport } = require(true && "../dynamicImport");
33
33
  const SupportLevelWarnings = {
34
34
  ["experimental"]: clc.yellow(`This is an experimental integration, proceed with caution.`),
35
35
  ["community-supported"]: clc.yellow(`This is a community-supported integration, support is best effort.`),
36
36
  };
37
- exports.FIREBASE_FRAMEWORKS_VERSION = "^0.6.0";
37
+ exports.FIREBASE_FRAMEWORKS_VERSION = "^0.7.0";
38
38
  exports.FIREBASE_FUNCTIONS_VERSION = "^3.23.0";
39
39
  exports.FIREBASE_ADMIN_VERSION = "^11.0.1";
40
40
  exports.NODE_VERSION = parseInt(process.versions.node, 10).toString();
@@ -50,7 +50,6 @@ const DEFAULT_FIND_DEP_OPTIONS = {
50
50
  cwd: process.cwd(),
51
51
  omitDev: true,
52
52
  };
53
- const NPM_COMMAND = process.platform === "win32" ? "npm.cmd" : "npm";
54
53
  exports.WebFrameworks = Object.fromEntries((0, fs_1.readdirSync)(__dirname)
55
54
  .filter((path) => (0, fs_1.statSync)((0, path_1.join)(__dirname, path)).isDirectory())
56
55
  .map((path) => [path, require((0, path_1.join)(__dirname, path))])
@@ -111,11 +110,29 @@ function scanDependencyTree(searchingFor, dependencies = {}) {
111
110
  }
112
111
  return;
113
112
  }
113
+ function getNodeModuleBin(name, cwd) {
114
+ var _a;
115
+ const cantFindExecutable = new error_1.FirebaseError(`Could not find the ${name} executable.`);
116
+ const npmBin = (_a = (0, cross_spawn_1.sync)("npm", ["bin"], { cwd }).stdout) === null || _a === void 0 ? void 0 : _a.toString().trim();
117
+ if (!npmBin) {
118
+ throw cantFindExecutable;
119
+ }
120
+ const path = (0, path_1.join)(npmBin, name);
121
+ if (!(0, fsutils_1.fileExistsSync)(path)) {
122
+ throw cantFindExecutable;
123
+ }
124
+ return path;
125
+ }
126
+ exports.getNodeModuleBin = getNodeModuleBin;
114
127
  function findDependency(name, options = {}) {
115
- const { cwd, depth, omitDev } = Object.assign(Object.assign({}, DEFAULT_FIND_DEP_OPTIONS), options);
128
+ var _a;
129
+ const { cwd: dir, depth, omitDev } = Object.assign(Object.assign({}, DEFAULT_FIND_DEP_OPTIONS), options);
130
+ const cwd = (_a = (0, cross_spawn_1.sync)("npm", ["root"], { cwd: dir }).stdout) === null || _a === void 0 ? void 0 : _a.toString().trim();
131
+ if (!cwd)
132
+ return;
116
133
  const env = Object.assign({}, process.env);
117
134
  delete env.NODE_ENV;
118
- const result = (0, cross_spawn_1.sync)(NPM_COMMAND, [
135
+ const result = (0, cross_spawn_1.sync)("npm", [
119
136
  "list",
120
137
  name,
121
138
  "--json",
@@ -236,11 +253,12 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
236
253
  }
237
254
  }
238
255
  }
239
- if (firebaseDefaults)
256
+ if (firebaseDefaults) {
240
257
  process.env.__FIREBASE_DEFAULTS__ = JSON.stringify(firebaseDefaults);
258
+ }
241
259
  const results = await discover(getProjectPath());
242
260
  if (!results)
243
- throw new Error("Epic fail.");
261
+ throw new error_1.FirebaseError("Unable to detect the web framework in use, check firebase-debug.log for more info.");
244
262
  const { framework, mayWantBackend, publicDirectory } = results;
245
263
  const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, } = exports.WebFrameworks[framework];
246
264
  console.log(`Detected a ${name} codebase. ${SupportLevelWarnings[support] || ""}\n`);
@@ -273,8 +291,10 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
273
291
  }
274
292
  config.webFramework = `${framework}${codegenFunctionsDirectory ? "_ssr" : ""}`;
275
293
  if (codegenFunctionsDirectory) {
276
- if (firebaseDefaults)
294
+ if (firebaseDefaults) {
277
295
  firebaseDefaults._authTokenSyncURL = "/__session";
296
+ process.env.__FIREBASE_DEFAULTS__ = JSON.stringify(firebaseDefaults);
297
+ }
278
298
  const rewrite = {
279
299
  source: "**",
280
300
  function: {
@@ -369,7 +389,7 @@ ${firebaseDefaults ? `__FIREBASE_DEFAULTS__=${JSON.stringify(firebaseDefaults)}\
369
389
  resolve(matches);
370
390
  }));
371
391
  await Promise.all(envs.map((path) => (0, promises_1.copyFile)(path, (0, path_1.join)(functionsDist, (0, path_1.basename)(path)))));
372
- (0, child_process_1.execSync)(`${NPM_COMMAND} i --omit dev --no-audit`, {
392
+ (0, child_process_1.execSync)(`npm i --omit dev --no-audit`, {
373
393
  cwd: functionsDist,
374
394
  stdio: "inherit",
375
395
  });
@@ -416,47 +436,3 @@ function codegenDevModeFunctionsDirectory() {
416
436
  const packageJson = {};
417
437
  return Promise.resolve({ packageJson, frameworksEntry: "_devMode" });
418
438
  }
419
- function createServerResponseProxy(req, res, next) {
420
- const proxiedRes = new http_1.ServerResponse(req);
421
- const buffer = [];
422
- proxiedRes.write = new Proxy(proxiedRes.write.bind(proxiedRes), {
423
- apply: (target, thisArg, args) => {
424
- target.call(thisArg, ...args);
425
- buffer.push(["write", args]);
426
- },
427
- });
428
- proxiedRes.setHeader = new Proxy(proxiedRes.setHeader.bind(proxiedRes), {
429
- apply: (target, thisArg, args) => {
430
- target.call(thisArg, ...args);
431
- buffer.push(["setHeader", args]);
432
- },
433
- });
434
- proxiedRes.removeHeader = new Proxy(proxiedRes.removeHeader.bind(proxiedRes), {
435
- apply: (target, thisArg, args) => {
436
- target.call(thisArg, ...args);
437
- buffer.push(["removeHeader", args]);
438
- },
439
- });
440
- proxiedRes.writeHead = new Proxy(proxiedRes.writeHead.bind(proxiedRes), {
441
- apply: (target, thisArg, args) => {
442
- target.call(thisArg, ...args);
443
- buffer.push(["writeHead", args]);
444
- },
445
- });
446
- proxiedRes.end = new Proxy(proxiedRes.end.bind(proxiedRes), {
447
- apply: (target, thisArg, args) => {
448
- target.call(thisArg, ...args);
449
- if (proxiedRes.statusCode === 404) {
450
- next();
451
- }
452
- else {
453
- for (const [fn, args] of buffer) {
454
- res[fn](...args);
455
- }
456
- res.end(...args);
457
- }
458
- },
459
- });
460
- return proxiedRes;
461
- }
462
- exports.createServerResponseProxy = createServerResponseProxy;
@@ -284,11 +284,10 @@ async function getDevModeHandle(dir, hostingEmulatorInfo) {
284
284
  });
285
285
  const handler = nextApp.getRequestHandler();
286
286
  await nextApp.prepare();
287
- return (req, res, next) => {
287
+ return (0, utils_2.simpleProxy)(async (req, res) => {
288
288
  const parsedUrl = (0, url_1.parse)(req.url, true);
289
- const proxy = (0, __1.createServerResponseProxy)(req, res, next);
290
- handler(req, proxy, parsedUrl);
291
- };
289
+ await handler(req, res, parsedUrl);
290
+ });
292
291
  }
293
292
  exports.getDevModeHandle = getDevModeHandle;
294
293
  async function getConfig(dir) {
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.build = exports.getDevModeHandle = exports.discover = exports.type = exports.support = exports.name = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const path_1 = require("path");
6
+ const vite_1 = require("../vite");
7
+ const fsutils_1 = require("../../fsutils");
8
+ const { dynamicImport } = require(true && "../../dynamicImport");
9
+ exports.name = "SvelteKit";
10
+ exports.support = "experimental";
11
+ exports.type = 2;
12
+ exports.discover = (0, vite_1.viteDiscoverWithNpmDependency)("@sveltejs/kit");
13
+ var vite_2 = require("../vite");
14
+ Object.defineProperty(exports, "getDevModeHandle", { enumerable: true, get: function () { return vite_2.getDevModeHandle; } });
15
+ async function build(root) {
16
+ var _a;
17
+ const config = await getConfig(root);
18
+ const wantsBackend = ((_a = config.kit.adapter) === null || _a === void 0 ? void 0 : _a.name) !== "@sveltejs/adapter-static";
19
+ await (0, vite_1.build)(root);
20
+ return { wantsBackend };
21
+ }
22
+ exports.build = build;
23
+ async function ɵcodegenPublicDirectory(root, dest) {
24
+ const config = await getConfig(root);
25
+ const output = (0, path_1.join)(root, config.kit.outDir, "output");
26
+ await (0, fs_extra_1.copy)((0, path_1.join)(output, "client"), dest);
27
+ const prerenderedPath = (0, path_1.join)(output, "prerendered", "pages");
28
+ if (await (0, fs_extra_1.pathExists)(prerenderedPath)) {
29
+ await (0, fs_extra_1.copy)(prerenderedPath, dest);
30
+ }
31
+ }
32
+ exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
33
+ async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
34
+ var _a;
35
+ var _b;
36
+ const packageJsonBuffer = await (0, fs_extra_1.readFile)((0, path_1.join)(sourceDir, "package.json"));
37
+ const packageJson = JSON.parse(packageJsonBuffer.toString());
38
+ packageJson.dependencies || (packageJson.dependencies = {});
39
+ (_a = (_b = packageJson.dependencies)["@sveltejs/kit"]) !== null && _a !== void 0 ? _a : (_b["@sveltejs/kit"] = packageJson.devDependencies["@sveltejs/kit"]);
40
+ const config = await getConfig(sourceDir);
41
+ await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, config.kit.outDir, "output", "server"), destDir);
42
+ return { packageJson, frameworksEntry: "sveltekit" };
43
+ }
44
+ exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
45
+ async function getConfig(root) {
46
+ var _a;
47
+ const configPath = ["svelte.config.js", "svelte.config.mjs"]
48
+ .map((filename) => (0, path_1.join)(root, filename))
49
+ .find(fsutils_1.fileExistsSync);
50
+ const config = configPath ? (await dynamicImport(configPath)).default : {};
51
+ config.kit || (config.kit = {});
52
+ (_a = config.kit).outDir || (_a.outDir = ".svelte-kit");
53
+ return config;
54
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.warnIfCustomBuildScript = exports.readJSON = exports.isUrl = void 0;
3
+ exports.simpleProxy = exports.warnIfCustomBuildScript = exports.readJSON = exports.isUrl = void 0;
4
4
  const fs_extra_1 = require("fs-extra");
5
5
  const path_1 = require("path");
6
6
  const promises_1 = require("fs/promises");
7
+ const http_1 = require("http");
8
+ const logger_1 = require("../logger");
7
9
  function isUrl(url) {
8
10
  return /^https?:\/\//.test(url);
9
11
  }
@@ -22,3 +24,46 @@ async function warnIfCustomBuildScript(dir, framework, defaultBuildScripts) {
22
24
  }
23
25
  }
24
26
  exports.warnIfCustomBuildScript = warnIfCustomBuildScript;
27
+ function simpleProxy(hostOrRequestHandler) {
28
+ const agent = new http_1.Agent({ keepAlive: true });
29
+ return async (originalReq, originalRes, next) => {
30
+ const { method, headers, url: path } = originalReq;
31
+ if (!method || !path) {
32
+ return originalRes.end();
33
+ }
34
+ const firebaseDefaultsJSON = process.env.__FIREBASE_DEFAULTS__;
35
+ const authTokenSyncURL = firebaseDefaultsJSON && JSON.parse(firebaseDefaultsJSON)._authTokenSyncURL;
36
+ if (path === authTokenSyncURL) {
37
+ return next();
38
+ }
39
+ if (typeof hostOrRequestHandler === "string") {
40
+ const { hostname, port, protocol, username, password } = new URL(hostOrRequestHandler);
41
+ const host = `${hostname}:${port}`;
42
+ const auth = username || password ? `${username}:${password}` : undefined;
43
+ const opts = {
44
+ agent,
45
+ auth,
46
+ protocol,
47
+ hostname,
48
+ port,
49
+ path,
50
+ method,
51
+ headers: Object.assign(Object.assign({}, headers), { host, "X-Forwarded-Host": headers.host }),
52
+ };
53
+ const req = (0, http_1.request)(opts, (response) => {
54
+ const { statusCode, statusMessage, headers } = response;
55
+ originalRes.writeHead(statusCode, statusMessage, headers);
56
+ response.pipe(originalRes);
57
+ });
58
+ originalReq.pipe(req);
59
+ req.on("error", (err) => {
60
+ logger_1.logger.debug("Error encountered while proxying request:", method, path, err);
61
+ originalRes.end();
62
+ });
63
+ }
64
+ else {
65
+ await hostOrRequestHandler(originalReq, originalRes);
66
+ }
67
+ };
68
+ }
69
+ exports.simpleProxy = simpleProxy;
@@ -7,13 +7,11 @@ const fs_1 = require("fs");
7
7
  const fs_extra_1 = require("fs-extra");
8
8
  const path_1 = require("path");
9
9
  const __1 = require("..");
10
- const proxy_1 = require("../../hosting/proxy");
11
10
  const prompt_1 = require("../../prompt");
12
11
  const utils_1 = require("../utils");
13
12
  exports.name = "Vite";
14
13
  exports.support = "experimental";
15
14
  exports.type = 4;
16
- const CLI_COMMAND = (0, path_1.join)("node_modules", ".bin", process.platform === "win32" ? "vite.cmd" : "vite");
17
15
  exports.DEFAULT_BUILD_SCRIPT = ["vite build", "tsc && vite build"];
18
16
  const initViteTemplate = (template) => async (setup, config) => await init(setup, config, template);
19
17
  exports.initViteTemplate = initViteTemplate;
@@ -41,7 +39,7 @@ exports.vitePluginDiscover = vitePluginDiscover;
41
39
  async function discover(dir, plugin, npmDependency) {
42
40
  if (!(0, fs_1.existsSync)((0, path_1.join)(dir, "package.json")))
43
41
  return;
44
- const additionalDep = npmDependency && (0, __1.findDependency)(npmDependency, { cwd: dir, depth: 0, omitDev: true });
42
+ const additionalDep = npmDependency && (0, __1.findDependency)(npmDependency, { cwd: dir, depth: 0, omitDev: false });
45
43
  const depth = plugin ? undefined : 0;
46
44
  const configFilesExist = await Promise.all([
47
45
  (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "vite.config.js")),
@@ -61,7 +59,10 @@ exports.discover = discover;
61
59
  async function build(root) {
62
60
  const { build } = (0, __1.relativeRequire)(root, "vite");
63
61
  await (0, utils_1.warnIfCustomBuildScript)(root, exports.name, exports.DEFAULT_BUILD_SCRIPT);
64
- await build({ root });
62
+ const cwd = process.cwd();
63
+ process.chdir(root);
64
+ await build({ root, mode: "production" });
65
+ process.chdir(cwd);
65
66
  }
66
67
  exports.build = build;
67
68
  async function ɵcodegenPublicDirectory(root, dest) {
@@ -72,7 +73,8 @@ async function ɵcodegenPublicDirectory(root, dest) {
72
73
  exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
73
74
  async function getDevModeHandle(dir) {
74
75
  const host = new Promise((resolve) => {
75
- const serve = (0, cross_spawn_1.spawn)(CLI_COMMAND, [], { cwd: dir });
76
+ const cli = (0, __1.getNodeModuleBin)("vite", dir);
77
+ const serve = (0, cross_spawn_1.spawn)(cli, [], { cwd: dir });
76
78
  serve.stdout.on("data", (data) => {
77
79
  process.stdout.write(data);
78
80
  const match = data.toString().match(/(http:\/\/.+:\d+)/);
@@ -83,10 +85,14 @@ async function getDevModeHandle(dir) {
83
85
  process.stderr.write(data);
84
86
  });
85
87
  });
86
- return (0, proxy_1.proxyRequestHandler)(await host, "Vite Development Server", { forceCascade: true });
88
+ return (0, utils_1.simpleProxy)(await host);
87
89
  }
88
90
  exports.getDevModeHandle = getDevModeHandle;
89
91
  async function getConfig(root) {
90
92
  const { resolveConfig } = (0, __1.relativeRequire)(root, "vite");
91
- return await resolveConfig({ root }, "build", "production");
93
+ const cwd = process.cwd();
94
+ process.chdir(root);
95
+ const config = await resolveConfig({ root }, "build", "production");
96
+ process.chdir(cwd);
97
+ return config;
92
98
  }
@@ -247,7 +247,7 @@ async function promptForRepo(options, ghAccessToken) {
247
247
  keyId = body.key_id;
248
248
  }
249
249
  catch (e) {
250
- if (e.status === 403) {
250
+ if ([403, 404].includes(e.status)) {
251
251
  logger_1.logger.info();
252
252
  logger_1.logger.info();
253
253
  (0, utils_1.logWarning)("The provided authorization cannot be used with this repository. If this repository is in an organization, did you remember to grant access?", "error");
package/lib/track.js CHANGED
@@ -10,25 +10,31 @@ const logger_1 = require("./logger");
10
10
  const pkg = require("../package.json");
11
11
  exports.EMULATOR_GA4_MEASUREMENT_ID = process.env.FIREBASE_EMULATOR_GA4_MEASUREMENT_ID || "G-KYP2JMPFC0";
12
12
  function usageEnabled() {
13
- return !!configstore_1.configstore.get("usage");
13
+ return !!process.env.IS_FIREBASE_CLI && !!configstore_1.configstore.get("usage");
14
14
  }
15
15
  exports.usageEnabled = usageEnabled;
16
16
  const FIREBASE_ANALYTICS_UA = process.env.FIREBASE_ANALYTICS_UA || "UA-29174744-3";
17
- let anonId = configstore_1.configstore.get("analytics-uuid");
18
- if (!anonId) {
19
- anonId = (0, uuid_1.v4)();
20
- configstore_1.configstore.set("analytics-uuid", anonId);
17
+ let visitor;
18
+ function ensureUAVisitor() {
19
+ if (!visitor) {
20
+ let anonId = configstore_1.configstore.get("analytics-uuid");
21
+ if (!anonId) {
22
+ anonId = (0, uuid_1.v4)();
23
+ configstore_1.configstore.set("analytics-uuid", anonId);
24
+ }
25
+ visitor = ua(FIREBASE_ANALYTICS_UA, anonId, {
26
+ strictCidFormat: false,
27
+ https: true,
28
+ });
29
+ visitor.set("cd1", process.platform);
30
+ visitor.set("cd2", process.version);
31
+ visitor.set("cd3", process.env.FIREPIT_VERSION || "none");
32
+ }
21
33
  }
22
- const visitor = ua(FIREBASE_ANALYTICS_UA, anonId, {
23
- strictCidFormat: false,
24
- https: true,
25
- });
26
- visitor.set("cd1", process.platform);
27
- visitor.set("cd2", process.version);
28
- visitor.set("cd3", process.env.FIREPIT_VERSION || "none");
29
34
  function track(action, label, duration = 0) {
35
+ ensureUAVisitor();
30
36
  return new Promise((resolve) => {
31
- if (configstore_1.configstore.get("tokens") && usageEnabled()) {
37
+ if (usageEnabled() && configstore_1.configstore.get("tokens")) {
32
38
  visitor.event("Firebase CLI " + pkg.version, action, label, duration).send(() => {
33
39
  resolve();
34
40
  });
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "11.25.2",
3
+ "version": "11.26.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "firebase-tools",
9
- "version": "11.25.2",
9
+ "version": "11.26.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@google-cloud/pubsub": "^3.0.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "11.25.2",
3
+ "version": "11.26.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {