firebase-tools 11.21.0 → 11.23.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 (94) hide show
  1. package/lib/commands/ext-configure.js +3 -3
  2. package/lib/commands/ext-dev-init.js +16 -4
  3. package/lib/commands/ext-dev-publish.js +3 -3
  4. package/lib/commands/ext-dev-register.js +2 -2
  5. package/lib/commands/ext-info.js +3 -3
  6. package/lib/commands/ext-install.js +2 -2
  7. package/lib/commands/ext-uninstall.js +2 -2
  8. package/lib/commands/ext-update.js +2 -2
  9. package/lib/commands/hosting-channel-create.js +2 -2
  10. package/lib/commands/hosting-channel-delete.js +2 -2
  11. package/lib/commands/hosting-channel-deploy.js +2 -2
  12. package/lib/commands/hosting-clone.js +2 -2
  13. package/lib/deploy/functions/release/fabricator.js +3 -0
  14. package/lib/deploy/functions/runtimes/discovery/index.js +1 -1
  15. package/lib/deploy/functions/runtimes/index.js +5 -2
  16. package/lib/deploy/functions/runtimes/node/index.js +70 -27
  17. package/lib/deploy/functions/runtimes/node/versioning.js +4 -2
  18. package/lib/deploy/functions/runtimes/python/index.js +132 -0
  19. package/lib/deploy/hosting/convertConfig.js +2 -1
  20. package/lib/emulator/auth/apiSpec.js +21 -1
  21. package/lib/emulator/controller.js +5 -5
  22. package/lib/emulator/downloadableEmulators.js +6 -6
  23. package/lib/emulator/extensionsEmulator.js +3 -2
  24. package/lib/emulator/functionsEmulator.js +119 -87
  25. package/lib/emulator/functionsEmulatorRuntime.js +26 -42
  26. package/lib/emulator/functionsRuntimeWorker.js +51 -35
  27. package/lib/emulator/hub.js +6 -6
  28. package/lib/emulator/pubsubEmulator.js +12 -9
  29. package/lib/emulator/storage/apis/shared.js +2 -1
  30. package/lib/emulator/storage/cloudFunctions.js +1 -1
  31. package/lib/emulator/storage/files.js +18 -11
  32. package/lib/emulator/types.js +9 -9
  33. package/lib/extensions/askUserForConsent.js +4 -4
  34. package/lib/extensions/askUserForEventsConfig.js +2 -2
  35. package/lib/extensions/askUserForParam.js +34 -3
  36. package/lib/extensions/billingMigrationHelper.js +4 -4
  37. package/lib/extensions/change-log.js +4 -4
  38. package/lib/extensions/displayExtensionInfo.js +4 -4
  39. package/lib/extensions/emulator/optionsHelper.js +3 -3
  40. package/lib/extensions/emulator/specHelper.js +17 -16
  41. package/lib/extensions/extensionsApi.js +2 -2
  42. package/lib/extensions/extensionsHelper.js +6 -6
  43. package/lib/extensions/provisioningHelper.js +2 -2
  44. package/lib/extensions/updateHelper.js +2 -2
  45. package/lib/extensions/warnings.js +5 -5
  46. package/lib/firestore/checkDatabaseType.js +3 -3
  47. package/lib/frameworks/angular/index.js +6 -4
  48. package/lib/frameworks/index.js +47 -11
  49. package/lib/frameworks/lit/index.js +5 -1
  50. package/lib/frameworks/next/index.js +48 -20
  51. package/lib/frameworks/next/utils.js +1 -1
  52. package/lib/frameworks/nuxt/index.js +18 -26
  53. package/lib/frameworks/nuxt/interfaces.js +2 -0
  54. package/lib/frameworks/nuxt/utils.js +13 -0
  55. package/lib/frameworks/nuxt2/index.js +91 -0
  56. package/lib/frameworks/preact/index.js +5 -1
  57. package/lib/frameworks/react/index.js +5 -1
  58. package/lib/frameworks/svelte/index.js +5 -1
  59. package/lib/frameworks/vite/index.js +6 -4
  60. package/lib/functions/python.js +16 -0
  61. package/lib/gcp/cloudfunctionsv2.js +8 -0
  62. package/lib/getDefaultHostingSite.js +3 -1
  63. package/lib/init/features/firestore/index.js +1 -3
  64. package/lib/init/features/functions/index.js +10 -0
  65. package/lib/init/features/functions/python.js +48 -0
  66. package/lib/init/features/hosting/index.js +3 -2
  67. package/lib/projectUtils.js +2 -2
  68. package/lib/rc.js +4 -4
  69. package/lib/serve/functions.js +1 -3
  70. package/npm-shrinkwrap.json +1295 -276
  71. package/package.json +2 -2
  72. package/templates/extensions/extension.yaml +1 -1
  73. package/templates/extensions/integration-test.env +2 -0
  74. package/templates/extensions/integration-test.json +14 -0
  75. package/templates/extensions/javascript/WELCOME.md +14 -5
  76. package/templates/extensions/javascript/index.js +10 -10
  77. package/templates/extensions/javascript/integration-test.js +13 -0
  78. package/templates/extensions/javascript/package.lint.json +12 -4
  79. package/templates/extensions/javascript/package.nolint.json +11 -2
  80. package/templates/extensions/typescript/WELCOME.md +18 -5
  81. package/templates/extensions/typescript/_mocharc +10 -0
  82. package/templates/extensions/typescript/index.ts +16 -15
  83. package/templates/extensions/typescript/integration-test.ts +13 -0
  84. package/templates/extensions/typescript/package.lint.json +16 -4
  85. package/templates/extensions/typescript/package.nolint.json +12 -4
  86. package/templates/init/functions/javascript/_eslintrc +16 -2
  87. package/templates/init/functions/javascript/package.lint.json +4 -4
  88. package/templates/init/functions/javascript/package.nolint.json +3 -3
  89. package/templates/init/functions/python/_gitignore +0 -0
  90. package/templates/init/functions/python/main.py +13 -0
  91. package/templates/init/functions/python/requirements.txt +1 -0
  92. package/templates/init/functions/typescript/_eslintrc +1 -0
  93. package/templates/init/functions/typescript/package.lint.json +4 -4
  94. package/templates/init/functions/typescript/package.nolint.json +4 -3
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseChangelog = exports.getLocalChangelog = exports.breakingChangesInUpdate = exports.displayReleaseNotes = exports.getReleaseNotesForUpdate = void 0;
4
4
  const clc = require("colorette");
5
- const { marked } = require("marked");
5
+ const marked_1 = require("marked");
6
6
  const path = require("path");
7
7
  const semver = require("semver");
8
8
  const TerminalRenderer = require("marked-terminal");
@@ -12,7 +12,7 @@ const localHelper_1 = require("./localHelper");
12
12
  const logger_1 = require("../logger");
13
13
  const refs = require("./refs");
14
14
  const utils_1 = require("../utils");
15
- marked.setOptions({
15
+ marked_1.marked.setOptions({
16
16
  renderer: new TerminalRenderer(),
17
17
  });
18
18
  const EXTENSIONS_CHANGELOG = "CHANGELOG.md";
@@ -39,10 +39,10 @@ function displayReleaseNotes(releaseNotes, fromVersion) {
39
39
  const table = new Table({ head: ["Version", "What's New"], style: { head: ["yellow", "bold"] } });
40
40
  for (const [version, note] of Object.entries(releaseNotes)) {
41
41
  if (breakingVersions.includes(version)) {
42
- table.push([clc.yellow(clc.bold(version)), marked(note)]);
42
+ table.push([clc.yellow(clc.bold(version)), (0, marked_1.marked)(note)]);
43
43
  }
44
44
  else {
45
- table.push([version, marked(note)]);
45
+ table.push([version, (0, marked_1.marked)(note)]);
46
46
  }
47
47
  }
48
48
  logger_1.logger.info(clc.bold("What's new with this update:"));
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.retrieveRoleInfo = exports.printSourceDownloadLink = exports.displayExtInfo = void 0;
4
4
  const clc = require("colorette");
5
- const { marked } = require("marked");
5
+ const marked_1 = require("marked");
6
6
  const TerminalRenderer = require("marked-terminal");
7
7
  const utils = require("../utils");
8
8
  const extensionsHelper_1 = require("./extensionsHelper");
@@ -11,7 +11,7 @@ const error_1 = require("../error");
11
11
  const types_1 = require("./types");
12
12
  const iam = require("../gcp/iam");
13
13
  const secretsUtils_1 = require("./secretsUtils");
14
- marked.setOptions({
14
+ marked_1.marked.setOptions({
15
15
  renderer: new TerminalRenderer(),
16
16
  });
17
17
  const TASKS_ROLE = "cloudtasks.enqueuer";
@@ -44,7 +44,7 @@ async function displayExtInfo(extensionName, publisher, spec, published = false)
44
44
  if (lines.length > 0) {
45
45
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, `information about '${clc.bold(extensionName)}':`);
46
46
  const infoStr = lines.join("\n");
47
- const formatted = marked(infoStr).replace(/\n+$/, "\n");
47
+ const formatted = (0, marked_1.marked)(infoStr).replace(/\n+$/, "\n");
48
48
  logger_1.logger.info(formatted);
49
49
  return lines;
50
50
  }
@@ -60,7 +60,7 @@ async function displayExtInfo(extensionName, publisher, spec, published = false)
60
60
  exports.displayExtInfo = displayExtInfo;
61
61
  function printSourceDownloadLink(sourceDownloadUri) {
62
62
  const sourceDownloadMsg = `Want to review the source code that will be installed? Download it here: ${sourceDownloadUri}`;
63
- utils.logBullet(marked(sourceDownloadMsg));
63
+ utils.logBullet((0, marked_1.marked)(sourceDownloadMsg));
64
64
  }
65
65
  exports.printSourceDownloadLink = printSourceDownloadLink;
66
66
  async function retrieveRoleInfo(role) {
@@ -32,7 +32,7 @@ async function buildOptions(options) {
32
32
  options.extDevEnv = params;
33
33
  const functionEmuTriggerDefs = functionResources.map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r));
34
34
  options.extDevTriggers = functionEmuTriggerDefs;
35
- options.extDevNodeVersion = specHelper.getNodeVersion(functionResources);
35
+ options.extDevRuntime = specHelper.getRuntime(functionResources);
36
36
  return options;
37
37
  }
38
38
  exports.buildOptions = buildOptions;
@@ -45,12 +45,12 @@ async function getExtensionFunctionInfo(instance, paramValues) {
45
45
  trigger.name = `ext-${instance.instanceId}-${trigger.name}`;
46
46
  return trigger;
47
47
  });
48
- const nodeMajorVersion = specHelper.getNodeVersion(functionResources);
48
+ const runtime = specHelper.getRuntime(functionResources);
49
49
  const nonSecretEnv = getNonSecretEnv(spec.params, paramValues);
50
50
  const secretEnvVariables = getSecretEnvVars(spec.params, paramValues);
51
51
  return {
52
52
  extensionTriggers,
53
- nodeMajorVersion,
53
+ runtime,
54
54
  nonSecretEnv,
55
55
  secretEnvVariables,
56
56
  };
@@ -1,13 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getNodeVersion = exports.getFunctionProperties = exports.getFunctionResourcesWithParamSubstitution = exports.readFileFromDirectory = exports.readPostinstall = exports.readExtensionYaml = void 0;
3
+ exports.getRuntime = exports.DEFAULT_RUNTIME = exports.getFunctionProperties = exports.getFunctionResourcesWithParamSubstitution = exports.readFileFromDirectory = exports.readPostinstall = exports.readExtensionYaml = void 0;
4
4
  const yaml = require("js-yaml");
5
5
  const path = require("path");
6
6
  const fs = require("fs-extra");
7
7
  const error_1 = require("../../error");
8
8
  const extensionsHelper_1 = require("../extensionsHelper");
9
9
  const utils_1 = require("../utils");
10
- const functionsEmulatorUtils_1 = require("../../emulator/functionsEmulatorUtils");
11
10
  const SPEC_FILE = "extension.yaml";
12
11
  const POSTINSTALL_FILE = "POSTINSTALL.md";
13
12
  const validFunctionTypes = [
@@ -67,24 +66,26 @@ function getFunctionProperties(resources) {
67
66
  return resources.map((r) => r.properties);
68
67
  }
69
68
  exports.getFunctionProperties = getFunctionProperties;
70
- function getNodeVersion(resources) {
69
+ exports.DEFAULT_RUNTIME = "nodejs14";
70
+ function getRuntime(resources) {
71
+ if (resources.length === 0) {
72
+ return exports.DEFAULT_RUNTIME;
73
+ }
71
74
  const invalidRuntimes = [];
72
- const versions = resources.map((r) => {
73
- if ((0, utils_1.getResourceRuntime)(r)) {
74
- const runtimeName = (0, utils_1.getResourceRuntime)(r);
75
- const runtime = (0, functionsEmulatorUtils_1.parseRuntimeVersion)(runtimeName);
76
- if (!runtime) {
77
- invalidRuntimes.push(runtimeName);
78
- }
79
- else {
80
- return runtime;
81
- }
75
+ const runtimes = resources.map((r) => {
76
+ const runtime = (0, utils_1.getResourceRuntime)(r);
77
+ if (!runtime) {
78
+ return exports.DEFAULT_RUNTIME;
79
+ }
80
+ if (!/^(nodejs)?([0-9]+)/.test(runtime)) {
81
+ invalidRuntimes.push(runtime);
82
+ return exports.DEFAULT_RUNTIME;
82
83
  }
83
- return 14;
84
+ return runtime;
84
85
  });
85
86
  if (invalidRuntimes.length) {
86
87
  throw new error_1.FirebaseError(`The following runtimes are not supported by the Emulator Suite: ${invalidRuntimes.join(", ")}. \n Only Node runtimes are supported.`);
87
88
  }
88
- return Math.max(...versions);
89
+ return runtimes.sort()[runtimes.length - 1];
89
90
  }
90
- exports.getNodeVersion = getNodeVersion;
91
+ exports.getRuntime = getRuntime;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getExtension = exports.deleteExtension = exports.unpublishExtension = exports.publishExtensionVersion = exports.undeprecateExtensionVersion = exports.deprecateExtensionVersion = exports.registerPublisherProfile = exports.getPublisherProfile = exports.listExtensionVersions = exports.listExtensions = exports.getExtensionVersion = exports.getSource = exports.createSource = exports.updateInstanceFromRegistry = exports.updateInstance = exports.configureInstance = exports.listInstances = exports.getInstance = exports.deleteInstance = exports.createInstance = void 0;
4
4
  const yaml = require("js-yaml");
5
5
  const clc = require("colorette");
6
- const { marked } = require("marked");
6
+ const marked_1 = require("marked");
7
7
  const apiv2_1 = require("../apiv2");
8
8
  const api_1 = require("../api");
9
9
  const error_1 = require("../error");
@@ -478,5 +478,5 @@ function refNotFoundError(ref) {
478
478
  return new error_1.FirebaseError(`The extension reference '${clc.bold(ref.version ? refs.toExtensionVersionRef(ref) : refs.toExtensionRef(ref))}' doesn't exist. This could happen for two reasons:\n` +
479
479
  ` -The publisher ID '${clc.bold(ref.publisherId)}' doesn't exist or could be misspelled\n` +
480
480
  ` -The name of the ${ref.version ? "extension version" : "extension"} '${clc.bold(ref.version ? `${ref.extensionId}@${ref.version}` : ref.extensionId)}' doesn't exist or could be misspelled\n\n` +
481
- `Please correct the extension reference and try again. If you meant to install an extension from a local source, please provide a relative path prefixed with '${clc.bold("./")}', '${clc.bold("../")}', or '${clc.bold("~/")}'. Learn more about local extension installation at ${marked("[https://firebase.google.com/docs/extensions/alpha/install-extensions_community#install](https://firebase.google.com/docs/extensions/alpha/install-extensions_community#install).")}`, { status: 404 });
481
+ `Please correct the extension reference and try again. If you meant to install an extension from a local source, please provide a relative path prefixed with '${clc.bold("./")}', '${clc.bold("../")}', or '${clc.bold("~/")}'. Learn more about local extension installation at ${(0, marked_1.marked)("[https://firebase.google.com/docs/extensions/alpha/install-extensions_community#install](https://firebase.google.com/docs/extensions/alpha/install-extensions_community#install).")}`, { status: 404 });
482
482
  }
@@ -4,9 +4,9 @@ exports.canonicalizeRefInput = exports.diagnoseAndFixProject = exports.confirm =
4
4
  const clc = require("colorette");
5
5
  const ora = require("ora");
6
6
  const semver = require("semver");
7
- const { marked } = require("marked");
7
+ const marked_1 = require("marked");
8
8
  const TerminalRenderer = require("marked-terminal");
9
- marked.setOptions({
9
+ marked_1.marked.setOptions({
10
10
  renderer: new TerminalRenderer(),
11
11
  });
12
12
  const api_1 = require("../api");
@@ -329,12 +329,12 @@ async function publishExtensionVersionFromLocalSource(args) {
329
329
  catch (err) {
330
330
  throw new error_1.FirebaseError("No CHANGELOG.md file found. " +
331
331
  "Please create one and add an entry for this version. " +
332
- marked("See https://firebase.google.com/docs/extensions/alpha/create-user-docs#writing-changelog for more details."));
332
+ (0, marked_1.marked)("See https://firebase.google.com/docs/extensions/alpha/create-user-docs#writing-changelog for more details."));
333
333
  }
334
334
  if (!notes && !semver.prerelease(extensionSpec.version) && extension) {
335
335
  throw new error_1.FirebaseError(`No entry for version ${extensionSpec.version} found in CHANGELOG.md. ` +
336
336
  "Please add one so users know what has changed in this version. " +
337
- marked("See https://firebase.google.com/docs/extensions/alpha/create-user-docs#writing-changelog for more details."));
337
+ (0, marked_1.marked)("See https://firebase.google.com/docs/extensions/alpha/create-user-docs#writing-changelog for more details."));
338
338
  }
339
339
  displayReleaseNotes(args.publisherId, args.extensionId, extensionSpec.version, notes);
340
340
  if (!(await confirm({
@@ -380,7 +380,7 @@ async function publishExtensionVersionFromLocalSource(args) {
380
380
  catch (err) {
381
381
  publishSpinner.fail();
382
382
  if (err.status === 404) {
383
- throw new error_1.FirebaseError(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.`));
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.`));
384
384
  }
385
385
  throw err;
386
386
  }
@@ -433,7 +433,7 @@ function getPublisherProjectFromName(publisherName) {
433
433
  exports.getPublisherProjectFromName = getPublisherProjectFromName;
434
434
  function displayReleaseNotes(publisherId, extensionId, versionId, releaseNotes) {
435
435
  const releaseNotesMessage = releaseNotes
436
- ? ` Release notes for this version:\n${marked(releaseNotes)}\n`
436
+ ? ` Release notes for this version:\n${(0, marked_1.marked)(releaseNotes)}\n`
437
437
  : "\n";
438
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
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";
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getUsedProducts = exports.bulkCheckProductsProvisioned = exports.checkProductsProvisioned = exports.DeferredProduct = void 0;
4
- const { marked } = require("marked");
4
+ const marked_1 = require("marked");
5
5
  const api_1 = require("../api");
6
6
  const apiv2_1 = require("../apiv2");
7
7
  const functional_1 = require("../functional");
@@ -64,7 +64,7 @@ async function checkProducts(projectId, usedProducts) {
64
64
  "without server-side code.\n";
65
65
  errorMessage += ` https://console.firebase.google.com/project/${projectId}/authentication/users`;
66
66
  }
67
- throw new error_1.FirebaseError(marked(errorMessage), { exit: 2 });
67
+ throw new error_1.FirebaseError((0, marked_1.marked)(errorMessage), { exit: 2 });
68
68
  }
69
69
  }
70
70
  function getUsedProducts(spec) {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.inferUpdateSource = exports.updateFromUrlSource = exports.updateFromLocalSource = exports.update = exports.warningUpdateToOtherSource = exports.getExistingSourceOrigin = void 0;
4
4
  const clc = require("colorette");
5
5
  const semver = require("semver");
6
- const { marked } = require("marked");
6
+ const marked_1 = require("marked");
7
7
  const error_1 = require("../error");
8
8
  const logger_1 = require("../logger");
9
9
  const extensionsApi = require("./extensionsApi");
@@ -47,7 +47,7 @@ function warningUpdateToOtherSource(sourceOrigin) {
47
47
  targetText = "URL";
48
48
  }
49
49
  const warning = `All the instance's resources and logic will be overwritten to use the source code and files from the ${targetText}.\n`;
50
- logger_1.logger.info(marked(warning));
50
+ logger_1.logger.info((0, marked_1.marked)(warning));
51
51
  }
52
52
  exports.warningUpdateToOtherSource = warningUpdateToOtherSource;
53
53
  async function update(updateOptions) {
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.outOfBandChangesWarning = exports.paramsFlagDeprecationWarning = exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
4
- const { marked } = require("marked");
4
+ const marked_1 = require("marked");
5
5
  const clc = require("colorette");
6
6
  const types_1 = require("./types");
7
7
  const displayExtensionInfo_1 = require("./displayExtensionInfo");
@@ -16,11 +16,11 @@ function displayEAPWarning({ publisherId, sourceDownloadUri, githubLink, }) {
16
16
  const publisherNameLink = githubLink ? `[${publisherId}](${githubLink})` : publisherId;
17
17
  const warningMsg = `This extension is in preview and is built by a developer in the [Extensions Publisher Early Access Program](http://bit.ly/firex-provider). Its functionality might change in backward-incompatible ways. Since this extension isn't built by Firebase, reach out to ${publisherNameLink} with questions about this extension.`;
18
18
  const legalMsg = "\n\nIt is provided “AS IS”, without any warranty, express or implied, from Google. Google disclaims all liability for any damages, direct or indirect, resulting from the use of the extension, and its functionality might change in backward - incompatible ways.";
19
- utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(warningMsg + legalMsg));
19
+ utils.logLabeledBullet(extensionsHelper_1.logPrefix, (0, marked_1.marked)(warningMsg + legalMsg));
20
20
  (0, displayExtensionInfo_1.printSourceDownloadLink)(sourceDownloadUri);
21
21
  }
22
22
  function displayExperimentalWarning() {
23
- utils.logLabeledBullet(extensionsHelper_1.logPrefix, 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.`));
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
24
  }
25
25
  async function displayWarningPrompts(publisherId, launchStage, extensionVersion) {
26
26
  const trustedPublishers = await (0, resolveSource_1.getTrustedPublishers)();
@@ -58,11 +58,11 @@ async function displayWarningsForDeploy(instancesToCreate) {
58
58
  const experimental = nonEapExtensions.filter((i) => i.extension.registryLaunchStage === types_1.RegistryLaunchStage.EXPERIMENTAL);
59
59
  if (experimental.length) {
60
60
  const humanReadableList = experimental.map((i) => `\t${(0, deploymentSummary_1.humanReadable)(i)}`).join("\n");
61
- utils.logLabeledBullet(extensionsHelper_1.logPrefix, 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 }));
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
62
  }
63
63
  if (eapExtensions.length) {
64
64
  const humanReadableList = eapExtensions.map(toListEntry).join("\n");
65
- utils.logLabeledBullet(extensionsHelper_1.logPrefix, 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.` +
65
+ 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
66
  ` They are provided “AS IS”, without any warranty, express or implied, from Google.` +
67
67
  ` Google disclaims all liability for any damages, direct or indirect, resulting from the use of these extensions\n${humanReadableList}`, { gfm: false }));
68
68
  }
@@ -6,9 +6,9 @@ const apiv2_1 = require("../apiv2");
6
6
  const logger_1 = require("../logger");
7
7
  async function checkDatabaseType(projectId) {
8
8
  try {
9
- const client = new apiv2_1.Client({ urlPrefix: api_1.appengineOrigin, apiVersion: "v1" });
10
- const resp = await client.get(`/apps/${projectId}`);
11
- return resp.body.databaseType;
9
+ const client = new apiv2_1.Client({ urlPrefix: api_1.firestoreOrigin, apiVersion: "v1" });
10
+ const resp = await client.get(`/projects/${projectId}/databases/(default)`);
11
+ return resp.body.type;
12
12
  }
13
13
  catch (err) {
14
14
  logger_1.logger.debug("error getting database type", err);
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.getDevModeHandle = exports.build = exports.init = exports.discover = exports.type = exports.support = exports.name = void 0;
4
4
  const path_1 = require("path");
5
5
  const child_process_1 = require("child_process");
6
+ const cross_spawn_1 = require("cross-spawn");
6
7
  const fs_extra_1 = require("fs-extra");
7
8
  const promises_1 = require("fs/promises");
8
9
  const __1 = require("..");
@@ -23,9 +24,10 @@ async function discover(dir) {
23
24
  return { mayWantBackend: !!serverTarget, publicDirectory: (0, path_1.join)(dir, "src", "assets") };
24
25
  }
25
26
  exports.discover = discover;
26
- async function init(setup) {
27
- (0, child_process_1.execSync)(`npx --yes -p @angular/cli@latest ng new ${setup.hosting.source} --skip-git`, {
27
+ async function init(setup, config) {
28
+ (0, child_process_1.execSync)(`npx --yes -p @angular/cli@latest ng new ${setup.projectId} --directory ${setup.hosting.source} --skip-git`, {
28
29
  stdio: "inherit",
30
+ cwd: config.projectDir,
29
31
  });
30
32
  const useAngularUniversal = await (0, prompt_1.promptOnce)({
31
33
  name: "useAngularUniversal",
@@ -36,7 +38,7 @@ async function init(setup) {
36
38
  if (useAngularUniversal) {
37
39
  (0, child_process_1.execSync)("ng add @nguniversal/express-engine --skip-confirmation", {
38
40
  stdio: "inherit",
39
- cwd: setup.hosting.source,
41
+ cwd: (0, path_1.join)(config.projectDir, setup.hosting.source),
40
42
  });
41
43
  }
42
44
  }
@@ -74,7 +76,7 @@ async function getDevModeHandle(dir) {
74
76
  if (!serveTarget)
75
77
  return;
76
78
  const host = new Promise((resolve) => {
77
- const serve = (0, child_process_1.spawn)(CLI_COMMAND, ["run", targetStringFromTarget(serveTarget), "--host", "localhost"], { cwd: dir });
79
+ const serve = (0, cross_spawn_1.spawn)(CLI_COMMAND, ["run", targetStringFromTarget(serveTarget), "--host", "localhost"], { cwd: dir });
78
80
  serve.stdout.on("data", (data) => {
79
81
  process.stdout.write(data);
80
82
  const match = data.toString().match(/(http:\/\/localhost:\d+)/);
@@ -4,6 +4,7 @@ exports.createServerResponseProxy = exports.prepareFrameworks = exports.findDepe
4
4
  const path_1 = require("path");
5
5
  const process_1 = require("process");
6
6
  const child_process_1 = require("child_process");
7
+ const cross_spawn_1 = require("cross-spawn");
7
8
  const fs_1 = require("fs");
8
9
  const url_1 = require("url");
9
10
  const http_1 = require("http");
@@ -12,6 +13,7 @@ const fs_extra_1 = require("fs-extra");
12
13
  const clc = require("colorette");
13
14
  const process = require("node:process");
14
15
  const semver = require("semver");
16
+ const glob = require("glob");
15
17
  const projectUtils_1 = require("../projectUtils");
16
18
  const config_1 = require("../hosting/config");
17
19
  const api_1 = require("../hosting/api");
@@ -106,7 +108,7 @@ function findDependency(name, options = {}) {
106
108
  const { cwd, depth, omitDev } = Object.assign(Object.assign({}, DEFAULT_FIND_DEP_OPTIONS), options);
107
109
  const env = Object.assign({}, process.env);
108
110
  delete env.NODE_ENV;
109
- const result = (0, child_process_1.spawnSync)(NPM_COMMAND, [
111
+ const result = (0, cross_spawn_1.sync)(NPM_COMMAND, [
110
112
  "list",
111
113
  name,
112
114
  "--json",
@@ -120,8 +122,8 @@ function findDependency(name, options = {}) {
120
122
  }
121
123
  exports.findDependency = findDependency;
122
124
  async function prepareFrameworks(targetNames, context, options, emulators = []) {
123
- var _a;
124
- var _b, _c, _d, _e;
125
+ var _a, _b;
126
+ var _c, _d, _e, _f;
125
127
  const nodeVersion = process.version;
126
128
  if (!semver.satisfies(nodeVersion, ">=16.0.0")) {
127
129
  throw new error_1.FirebaseError(`The frameworks awareness feature requires Node.JS >= 16 and npm >= 8 in order to work correctly, due to some of the downstream dependencies. Please upgrade your version of Node.JS, reinstall firebase-tools, and give it another go.`);
@@ -133,7 +135,7 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
133
135
  try {
134
136
  await (0, requireHostingSite_1.requireHostingSite)(options);
135
137
  }
136
- catch (_f) {
138
+ catch (_g) {
137
139
  options.site = project;
138
140
  }
139
141
  }
@@ -243,10 +245,11 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
243
245
  }
244
246
  }
245
247
  else {
246
- const { wantsBackend = false, rewrites = [], redirects = [], headers = [], } = (await build(getProjectPath())) || {};
248
+ const { wantsBackend = false, rewrites = [], redirects = [], headers = [], trailingSlash, } = (await build(getProjectPath())) || {};
247
249
  config.rewrites.push(...rewrites);
248
250
  config.redirects.push(...redirects);
249
251
  config.headers.push(...headers);
252
+ (_b = config.trailingSlash) !== null && _b !== void 0 ? _b : (config.trailingSlash = trailingSlash);
250
253
  if (await (0, fs_extra_1.pathExists)(hostingDist))
251
254
  await (0, promises_1.rm)(hostingDist, { recursive: true });
252
255
  await (0, fs_extra_1.mkdirp)(hostingDist);
@@ -319,19 +322,52 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
319
322
  packageJson.main = "server.js";
320
323
  delete packageJson.devDependencies;
321
324
  packageJson.dependencies || (packageJson.dependencies = {});
322
- (_b = packageJson.dependencies)["firebase-frameworks"] || (_b["firebase-frameworks"] = exports.FIREBASE_FRAMEWORKS_VERSION);
323
- (_c = packageJson.dependencies)["firebase-functions"] || (_c["firebase-functions"] = exports.FIREBASE_FUNCTIONS_VERSION);
324
- (_d = packageJson.dependencies)["firebase-admin"] || (_d["firebase-admin"] = exports.FIREBASE_ADMIN_VERSION);
325
+ (_c = packageJson.dependencies)["firebase-frameworks"] || (_c["firebase-frameworks"] = exports.FIREBASE_FRAMEWORKS_VERSION);
326
+ (_d = packageJson.dependencies)["firebase-functions"] || (_d["firebase-functions"] = exports.FIREBASE_FUNCTIONS_VERSION);
327
+ (_e = packageJson.dependencies)["firebase-admin"] || (_e["firebase-admin"] = exports.FIREBASE_ADMIN_VERSION);
325
328
  packageJson.engines || (packageJson.engines = {});
326
- (_e = packageJson.engines).node || (_e.node = exports.NODE_VERSION);
329
+ (_f = packageJson.engines).node || (_f.node = exports.NODE_VERSION);
330
+ for (const [name, version] of Object.entries(packageJson.dependencies)) {
331
+ if (version.startsWith("file:")) {
332
+ const path = version.replace(/^file:/, "");
333
+ if (!(await (0, fs_extra_1.pathExists)(path)))
334
+ continue;
335
+ const stats = await (0, fs_extra_1.stat)(path);
336
+ if (stats.isDirectory()) {
337
+ const result = (0, cross_spawn_1.sync)("npm", ["pack", (0, path_1.relative)(functionsDist, path)], {
338
+ cwd: functionsDist,
339
+ });
340
+ if (!result.stdout)
341
+ throw new Error(`Error running \`npm pack\` at ${path}`);
342
+ const filename = result.stdout.toString().trim();
343
+ packageJson.dependencies[name] = `file:${filename}`;
344
+ }
345
+ else {
346
+ const filename = (0, path_1.basename)(path);
347
+ await (0, promises_1.copyFile)(path, (0, path_1.join)(functionsDist, filename));
348
+ packageJson.dependencies[name] = `file:${filename}`;
349
+ }
350
+ }
351
+ }
327
352
  await (0, promises_1.writeFile)((0, path_1.join)(functionsDist, "package.json"), JSON.stringify(packageJson, null, 2));
328
- await (0, promises_1.writeFile)((0, path_1.join)(functionsDist, ".env"), `__FIREBASE_FRAMEWORKS_ENTRY__=${frameworksEntry}
329
- ${firebaseDefaults ? `__FIREBASE_DEFAULTS__=${JSON.stringify(firebaseDefaults)}\n` : ""}`);
330
353
  await (0, promises_1.copyFile)(getProjectPath("package-lock.json"), (0, path_1.join)(functionsDist, "package-lock.json")).catch(() => {
331
354
  });
332
355
  if (await (0, fs_extra_1.pathExists)(getProjectPath(".npmrc"))) {
333
356
  await (0, promises_1.copyFile)(getProjectPath(".npmrc"), (0, path_1.join)(functionsDist, ".npmrc"));
334
357
  }
358
+ let existingDotEnvContents = "";
359
+ if (await (0, fs_extra_1.pathExists)(getProjectPath(".env"))) {
360
+ existingDotEnvContents = (await (0, promises_1.readFile)(getProjectPath(".env"))).toString();
361
+ }
362
+ await (0, promises_1.writeFile)((0, path_1.join)(functionsDist, ".env"), `${existingDotEnvContents}
363
+ __FIREBASE_FRAMEWORKS_ENTRY__=${frameworksEntry}
364
+ ${firebaseDefaults ? `__FIREBASE_DEFAULTS__=${JSON.stringify(firebaseDefaults)}\n` : ""}`);
365
+ const envs = await new Promise((resolve, reject) => glob(getProjectPath(".env.*"), (err, matches) => {
366
+ if (err)
367
+ reject(err);
368
+ resolve(matches);
369
+ }));
370
+ await Promise.all(envs.map((path) => (0, promises_1.copyFile)(path, (0, path_1.join)(functionsDist, (0, path_1.basename)(path)))));
335
371
  (0, child_process_1.execSync)(`${NPM_COMMAND} i --omit dev --no-audit`, {
336
372
  cwd: functionsDist,
337
373
  stdio: "inherit",
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDevModeHandle = exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.init = exports.build = exports.discover = exports.type = exports.support = exports.name = void 0;
4
4
  const child_process_1 = require("child_process");
5
+ const cross_spawn_1 = require("cross-spawn");
5
6
  const promises_1 = require("fs/promises");
6
7
  const path_1 = require("path");
7
8
  const fs_extra_1 = require("fs-extra");
@@ -9,6 +10,10 @@ const url_1 = require("url");
9
10
  const fs_1 = require("fs");
10
11
  const semver_1 = require("semver");
11
12
  const clc = require("colorette");
13
+ const stream_chain_1 = require("stream-chain");
14
+ const stream_json_1 = require("stream-json");
15
+ const Pick_1 = require("stream-json/filters/Pick");
16
+ const StreamObject_1 = require("stream-json/streamers/StreamObject");
12
17
  const __1 = require("..");
13
18
  const prompt_1 = require("../../prompt");
14
19
  const error_1 = require("../../error");
@@ -52,7 +57,7 @@ async function build(dir) {
52
57
  throw e;
53
58
  });
54
59
  const reasonsForBackend = [];
55
- const { distDir } = await getConfig(dir);
60
+ const { distDir, trailingSlash } = await getConfig(dir);
56
61
  if (await (0, utils_1.isUsingMiddleware)((0, path_1.join)(dir, distDir), false)) {
57
62
  reasonsForBackend.push("middleware");
58
63
  }
@@ -96,7 +101,9 @@ async function build(dir) {
96
101
  source: (0, utils_1.cleanEscapedChars)(source),
97
102
  headers,
98
103
  }));
99
- const isEveryRedirectSupported = nextJsRedirects.every(utils_1.isRedirectSupportedByHosting);
104
+ const isEveryRedirectSupported = nextJsRedirects
105
+ .filter((it) => !it.internal)
106
+ .every(utils_1.isRedirectSupportedByHosting);
100
107
  if (!isEveryRedirectSupported) {
101
108
  reasonsForBackend.push("advanced redirects");
102
109
  }
@@ -134,17 +141,17 @@ async function build(dir) {
134
141
  }
135
142
  console.log("");
136
143
  }
137
- return { wantsBackend, headers, redirects, rewrites };
144
+ return { wantsBackend, headers, redirects, rewrites, trailingSlash };
138
145
  }
139
146
  exports.build = build;
140
- async function init(setup) {
147
+ async function init(setup, config) {
141
148
  const language = await (0, prompt_1.promptOnce)({
142
149
  type: "list",
143
- default: "JavaScript",
150
+ default: "TypeScript",
144
151
  message: "What language would you like to use?",
145
152
  choices: ["JavaScript", "TypeScript"],
146
153
  });
147
- (0, child_process_1.execSync)(`npx --yes create-next-app@latest -e hello-world ${setup.hosting.source} --use-npm ${language === "TypeScript" ? "--ts" : ""}`, { stdio: "inherit" });
154
+ (0, child_process_1.execSync)(`npx --yes create-next-app@latest -e hello-world ${setup.hosting.source} --use-npm ${language === "TypeScript" ? "--ts" : "--js"}`, { stdio: "inherit", cwd: config.projectDir });
148
155
  }
149
156
  exports.init = init;
150
157
  async function ɵcodegenPublicDirectory(sourceDir, destDir) {
@@ -215,18 +222,38 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
215
222
  const { distDir } = await getConfig(sourceDir);
216
223
  const packageJson = await (0, utils_2.readJSON)((0, path_1.join)(sourceDir, "package.json"));
217
224
  if ((0, fs_1.existsSync)((0, path_1.join)(sourceDir, "next.config.js"))) {
218
- const dependencyTree = JSON.parse((0, child_process_1.spawnSync)("npm", ["ls", "--omit=dev", "--all", "--json"], {
219
- cwd: sourceDir,
220
- }).stdout.toString());
221
- const esbuildArgs = (0, utils_1.allDependencyNames)(dependencyTree)
222
- .map((it) => `--external:${it}`)
223
- .concat("--bundle", "--platform=node", `--target=node${__1.NODE_VERSION}`, `--outdir=${destDir}`, "--log-level=error");
224
- const bundle = (0, child_process_1.spawnSync)("npx", ["--yes", "esbuild", "next.config.js", ...esbuildArgs], {
225
- cwd: sourceDir,
226
- });
227
- if (bundle.status) {
228
- console.error(bundle.stderr.toString());
229
- throw new error_1.FirebaseError("Unable to bundle next.config.js for use in Cloud Functions");
225
+ try {
226
+ const productionDeps = await new Promise((resolve) => {
227
+ const dependencies = [];
228
+ const pipeline = (0, stream_chain_1.chain)([
229
+ (0, cross_spawn_1.spawn)("npm", ["ls", "--omit=dev", "--all", "--json"], { cwd: sourceDir }).stdout,
230
+ (0, stream_json_1.parser)({ packValues: false, packKeys: true, streamValues: false }),
231
+ (0, Pick_1.pick)({ filter: "dependencies" }),
232
+ (0, StreamObject_1.streamObject)(),
233
+ ({ key, value }) => [
234
+ key,
235
+ ...(0, utils_1.allDependencyNames)(value),
236
+ ],
237
+ ]);
238
+ pipeline.on("data", (it) => dependencies.push(it));
239
+ pipeline.on("end", () => {
240
+ resolve([...new Set(dependencies)]);
241
+ });
242
+ });
243
+ const esbuildArgs = productionDeps
244
+ .map((it) => `--external:${it}`)
245
+ .concat("--bundle", "--platform=node", `--target=node${__1.NODE_VERSION}`, `--outdir=${destDir}`, "--log-level=error");
246
+ const bundle = (0, cross_spawn_1.sync)("npx", ["--yes", "esbuild", "next.config.js", ...esbuildArgs], {
247
+ cwd: sourceDir,
248
+ });
249
+ if (bundle.status) {
250
+ throw new error_1.FirebaseError(bundle.stderr.toString());
251
+ }
252
+ }
253
+ catch (e) {
254
+ console.warn("Unable to bundle next.config.js for use in Cloud Functions, proceeding with deploy but problems may be enountered.");
255
+ console.error(e.message);
256
+ (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, "next.config.js"), (0, path_1.join)(destDir, "next.config.js"));
230
257
  }
231
258
  }
232
259
  if (await (0, fs_extra_1.pathExists)((0, path_1.join)(sourceDir, "public"))) {
@@ -265,6 +292,7 @@ async function getDevModeHandle(dir, hostingEmulatorInfo) {
265
292
  }
266
293
  exports.getDevModeHandle = getDevModeHandle;
267
294
  async function getConfig(dir) {
295
+ var _a;
268
296
  let config = {};
269
297
  if ((0, fs_1.existsSync)((0, path_1.join)(dir, "next.config.js"))) {
270
298
  const version = getNextVersion(dir);
@@ -277,12 +305,12 @@ async function getConfig(dir) {
277
305
  }
278
306
  else {
279
307
  try {
280
- config = await Promise.resolve().then(() => require((0, url_1.pathToFileURL)((0, path_1.join)(dir, "next.config.js")).toString()));
308
+ config = await (_a = (0, url_1.pathToFileURL)((0, path_1.join)(dir, "next.config.js")).toString(), Promise.resolve().then(() => require(_a)));
281
309
  }
282
310
  catch (e) {
283
311
  throw new Error("Unable to load next.config.js.");
284
312
  }
285
313
  }
286
314
  }
287
- return Object.assign({ distDir: ".next" }, config);
315
+ return Object.assign({ distDir: ".next", trailingSlash: false }, config);
288
316
  }
@@ -87,6 +87,6 @@ function allDependencyNames(mod) {
87
87
  if (!mod.dependencies)
88
88
  return [];
89
89
  const dependencyNames = Object.keys(mod.dependencies).reduce((acc, it) => [...acc, it, ...allDependencyNames(mod.dependencies[it])], []);
90
- return [...new Set(dependencyNames)];
90
+ return dependencyNames;
91
91
  }
92
92
  exports.allDependencyNames = allDependencyNames;