firebase-tools 11.29.1 → 12.0.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 (95) hide show
  1. package/lib/api.js +4 -2
  2. package/lib/commands/database-import.js +2 -2
  3. package/lib/commands/ext-configure.js +2 -1
  4. package/lib/commands/ext-dev-deprecate.js +24 -20
  5. package/lib/commands/ext-dev-list.js +12 -11
  6. package/lib/commands/ext-dev-publish.js +13 -47
  7. package/lib/commands/ext-dev-register.js +8 -5
  8. package/lib/commands/ext-dev-undeprecate.js +4 -4
  9. package/lib/commands/ext-dev-upload.js +88 -0
  10. package/lib/commands/ext-dev-usage.js +3 -3
  11. package/lib/commands/ext-install.js +5 -10
  12. package/lib/commands/ext-uninstall.js +0 -1
  13. package/lib/commands/ext-update.js +4 -10
  14. package/lib/commands/hosting-channel-deploy.js +3 -0
  15. package/lib/commands/index.js +9 -19
  16. package/lib/database/import.js +113 -18
  17. package/lib/deploy/extensions/planner.js +13 -7
  18. package/lib/deploy/extensions/prepare.js +16 -32
  19. package/lib/deploy/functions/ensure.js +7 -1
  20. package/lib/deploy/functions/release/fabricator.js +2 -0
  21. package/lib/deploy/functions/runtimes/discovery/index.js +1 -1
  22. package/lib/deploy/functions/runtimes/index.js +11 -3
  23. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +3 -3
  24. package/lib/deploy/functions/runtimes/python/index.js +41 -13
  25. package/lib/deploy/hosting/convertConfig.js +8 -4
  26. package/lib/deploy/hosting/prepare.js +64 -6
  27. package/lib/deploy/index.js +24 -8
  28. package/lib/emulator/adminSdkConfig.js +8 -0
  29. package/lib/emulator/controller.js +7 -9
  30. package/lib/emulator/download.js +3 -12
  31. package/lib/emulator/downloadableEmulators.js +5 -5
  32. package/lib/emulator/functionsEmulator.js +57 -7
  33. package/lib/emulator/functionsEmulatorRuntime.js +4 -1
  34. package/lib/emulator/functionsEmulatorShared.js +1 -0
  35. package/lib/emulator/functionsRuntimeWorker.js +12 -4
  36. package/lib/emulator/storage/rules/config.js +17 -7
  37. package/lib/experiments.js +22 -8
  38. package/lib/extensions/extensionsApi.js +24 -151
  39. package/lib/extensions/extensionsHelper.js +283 -146
  40. package/lib/extensions/manifest.js +1 -8
  41. package/lib/extensions/publisherApi.js +215 -0
  42. package/lib/extensions/refs.js +1 -1
  43. package/lib/extensions/resolveSource.js +1 -18
  44. package/lib/extensions/tos.js +78 -0
  45. package/lib/extensions/warnings.js +21 -41
  46. package/lib/frameworks/angular/index.js +74 -192
  47. package/lib/frameworks/angular/interfaces.js +2 -0
  48. package/lib/frameworks/angular/utils.js +274 -0
  49. package/lib/frameworks/astro/index.js +3 -4
  50. package/lib/frameworks/constants.js +45 -0
  51. package/lib/frameworks/express/index.js +3 -2
  52. package/lib/frameworks/flutter/index.js +39 -0
  53. package/lib/frameworks/flutter/utils.js +11 -0
  54. package/lib/frameworks/index.js +104 -145
  55. package/lib/frameworks/interfaces.js +2 -0
  56. package/lib/frameworks/next/constants.js +2 -1
  57. package/lib/frameworks/next/index.js +197 -114
  58. package/lib/frameworks/next/utils.js +97 -15
  59. package/lib/frameworks/nuxt/index.js +4 -5
  60. package/lib/frameworks/nuxt/utils.js +2 -2
  61. package/lib/frameworks/nuxt2/index.js +5 -5
  62. package/lib/frameworks/utils.js +108 -1
  63. package/lib/frameworks/vite/index.js +5 -6
  64. package/lib/functions/ensureTargeted.js +4 -4
  65. package/lib/functions/python.js +12 -5
  66. package/lib/gcp/resourceManager.js +1 -0
  67. package/lib/hosting/api.js +32 -1
  68. package/lib/hosting/config.js +4 -8
  69. package/lib/init/features/functions/index.js +4 -7
  70. package/lib/init/features/hosting/github.js +7 -2
  71. package/lib/init/features/hosting/index.js +3 -2
  72. package/lib/serve/index.js +2 -1
  73. package/lib/unzip.js +126 -0
  74. package/package.json +2 -3
  75. package/schema/firebase-config.json +1 -1
  76. package/templates/extensions/POSTINSTALL.md +2 -2
  77. package/templates/extensions/PREINSTALL.md +1 -1
  78. package/templates/extensions/extension.yaml +10 -6
  79. package/templates/extensions/javascript/WELCOME.md +1 -1
  80. package/templates/extensions/typescript/WELCOME.md +1 -1
  81. package/templates/extensions/typescript/index.ts +1 -1
  82. package/templates/init/functions/javascript/index.js +16 -6
  83. package/templates/init/functions/javascript/package.lint.json +4 -4
  84. package/templates/init/functions/javascript/package.nolint.json +4 -4
  85. package/templates/init/functions/python/requirements.txt +1 -1
  86. package/templates/init/functions/typescript/index.ts +16 -6
  87. package/templates/init/functions/typescript/package.lint.json +4 -4
  88. package/templates/init/functions/typescript/package.nolint.json +4 -4
  89. package/lib/commands/ext-dev-emulators-exec.js +0 -27
  90. package/lib/commands/ext-dev-emulators-start.js +0 -24
  91. package/lib/commands/ext-dev-extension-delete.js +0 -45
  92. package/lib/commands/ext-dev-unpublish.js +0 -49
  93. package/lib/commands/ext-sources-create.js +0 -24
  94. package/lib/extensions/askUserForConsent.js +0 -33
  95. package/npm-shrinkwrap.json +0 -12649
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deploy = void 0;
4
+ const clc = require("colorette");
4
5
  const logger_1 = require("../logger");
5
6
  const api_1 = require("../api");
6
7
  const colorette_1 = require("colorette");
@@ -19,8 +20,10 @@ const StorageTarget = require("./storage");
19
20
  const RemoteConfigTarget = require("./remoteconfig");
20
21
  const ExtensionsTarget = require("./extensions");
21
22
  const frameworks_1 = require("../frameworks");
22
- const requirePermissions_1 = require("../requirePermissions");
23
+ const prepare_1 = require("./hosting/prepare");
24
+ const github_1 = require("../init/features/hosting/github");
23
25
  const deploy_1 = require("../commands/deploy");
26
+ const requirePermissions_1 = require("../requirePermissions");
24
27
  const TARGETS = {
25
28
  hosting: HostingTarget,
26
29
  database: DatabaseTarget,
@@ -48,17 +51,30 @@ const deploy = async function (targetNames, options, customContext = {}) {
48
51
  if (targetNames.includes("hosting")) {
49
52
  const config = options.config.get("hosting");
50
53
  if (Array.isArray(config) ? config.some((it) => it.source) : config.source) {
51
- experiments.assertEnabled("webframeworks", "deploy a web framework to hosting");
52
- const usedToTargetFunctions = targetNames.includes("functions");
54
+ experiments.assertEnabled("webframeworks", "deploy a web framework from source");
53
55
  await (0, frameworks_1.prepareFrameworks)(targetNames, context, options);
54
- const nowTargetsFunctions = targetNames.includes("functions");
55
- if (nowTargetsFunctions && !usedToTargetFunctions) {
56
- if (context.hostingChannel && !experiments.isEnabled("pintags")) {
57
- throw new error_1.FirebaseError("Web frameworks with dynamic content do not yet support deploying to preview channels");
56
+ }
57
+ }
58
+ if (targetNames.includes("hosting") && (0, prepare_1.hasPinnedFunctions)(options)) {
59
+ experiments.assertEnabled("pintags", "deploy a tagged function as a hosting rewrite");
60
+ if (!targetNames.includes("functions")) {
61
+ targetNames.unshift("functions");
62
+ try {
63
+ await (0, requirePermissions_1.requirePermissions)(options, deploy_1.TARGET_PERMISSIONS["functions"]);
64
+ }
65
+ catch (e) {
66
+ if ((0, github_1.isRunningInGithubAction)()) {
67
+ throw new error_1.FirebaseError("It looks like you are deploying a Hosting site along with Cloud Functions " +
68
+ "using a GitHub action version that did not include Cloud Functions " +
69
+ "permissions. Please reinstall the GitHub action with" +
70
+ clc.bold("firebase init hosting:github"), { original: e });
71
+ }
72
+ else {
73
+ throw e;
58
74
  }
59
- await (0, requirePermissions_1.requirePermissions)(deploy_1.TARGET_PERMISSIONS["functions"]);
60
75
  }
61
76
  }
77
+ await (0, prepare_1.addPinnedFunctionsToOnlyString)(context, options);
62
78
  }
63
79
  for (const targetName of targetNames) {
64
80
  const target = TARGETS[targetName];
@@ -37,6 +37,14 @@ async function getProjectAdminSdkConfig(projectId) {
37
37
  apiVersion: "v1beta1",
38
38
  urlPrefix: api_1.firebaseApiOrigin,
39
39
  });
40
+ if (projectId.startsWith("demo-")) {
41
+ logger_1.logger.debug(`Detected demo- project: ${projectId}. Using default adminSdkConfig instead of calling firebase API.`);
42
+ return {
43
+ projectId,
44
+ databaseURL: `${projectId}-default-rtdb.firebaseio.com`,
45
+ storageBucket: `${projectId}.appspot.com`,
46
+ };
47
+ }
40
48
  try {
41
49
  const res = await apiClient.get(`projects/${projectId}/adminSdkConfig`);
42
50
  return res.body;
@@ -282,15 +282,13 @@ async function startAll(options, showUI = true) {
282
282
  if (Array.isArray(hostingConfig) ? hostingConfig.some((it) => it.source) : hostingConfig === null || hostingConfig === void 0 ? void 0 : hostingConfig.source) {
283
283
  experiments.assertEnabled("webframeworks", "emulate a web framework");
284
284
  const emulators = [];
285
- if (experiments.isEnabled("webframeworks")) {
286
- for (const e of types_1.ALL_SERVICE_EMULATORS) {
287
- if (listenForEmulator[e]) {
288
- emulators.push({
289
- name: e,
290
- host: utils.connectableHostname(listenForEmulator[e][0].address),
291
- port: listenForEmulator[e][0].port,
292
- });
293
- }
285
+ for (const e of types_1.ALL_SERVICE_EMULATORS) {
286
+ if (listenForEmulator[e]) {
287
+ emulators.push({
288
+ name: e,
289
+ host: utils.connectableHostname(listenForEmulator[e][0].address),
290
+ port: listenForEmulator[e][0].port,
291
+ });
294
292
  }
295
293
  }
296
294
  await (0, frameworks_1.prepareFrameworks)(targets, options, options, emulators);
@@ -5,9 +5,9 @@ const crypto = require("crypto");
5
5
  const fs = require("fs-extra");
6
6
  const path = require("path");
7
7
  const tmp = require("tmp");
8
- const unzipper = require("unzipper");
9
8
  const emulatorLogger_1 = require("./emulatorLogger");
10
9
  const error_1 = require("../error");
10
+ const unzip_1 = require("../unzip");
11
11
  const downloadableEmulators = require("./downloadableEmulators");
12
12
  const downloadUtils = require("../downloadUtils");
13
13
  tmp.setGracefulCleanup();
@@ -25,9 +25,8 @@ async function downloadEmulator(name) {
25
25
  }
26
26
  fs.copySync(tmpfile, emulator.downloadPath);
27
27
  if (emulator.unzipDir) {
28
- await unzip(emulator.downloadPath, emulator.unzipDir);
28
+ await (0, unzip_1.unzip)(emulator.downloadPath, emulator.unzipDir);
29
29
  }
30
- await new Promise((f) => setTimeout(f, 2000));
31
30
  const executablePath = emulator.binaryPath || emulator.downloadPath;
32
31
  fs.chmodSync(executablePath, 0o755);
33
32
  removeOldFiles(name, emulator);
@@ -44,20 +43,12 @@ async function downloadExtensionVersion(extensionVersionRef, sourceDownloadUri,
44
43
  }
45
44
  emulatorLogger.logLabeled("BULLET", "extensions", `downloading ${sourceDownloadUri}...`);
46
45
  const sourceCodeZip = await downloadUtils.downloadToTmp(sourceDownloadUri);
47
- await unzip(sourceCodeZip, targetDir);
46
+ await (0, unzip_1.unzip)(sourceCodeZip, targetDir);
48
47
  fs.chmodSync(targetDir, 0o755);
49
48
  emulatorLogger.logLabeled("BULLET", "extensions", `Downloaded to ${targetDir}...`);
50
49
  await new Promise((resolve) => setTimeout(resolve, 1000));
51
50
  }
52
51
  exports.downloadExtensionVersion = downloadExtensionVersion;
53
- function unzip(zipPath, unzipDir) {
54
- return new Promise((resolve, reject) => {
55
- fs.createReadStream(zipPath)
56
- .pipe(unzipper.Extract({ path: unzipDir }))
57
- .on("error", reject)
58
- .on("close", resolve);
59
- });
60
- }
61
52
  function removeOldFiles(name, emulator, removeAllVersions = false) {
62
53
  const currentLocalPath = emulator.downloadPath;
63
54
  const currentUnzipPath = emulator.unzipDir;
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
23
23
  expectedChecksum: "311609538bd65666eb724ef47c2e6466",
24
24
  },
25
25
  firestore: {
26
- version: "1.17.3",
27
- expectedSize: 64970588,
28
- expectedChecksum: "75beb285dc404176b974fec9e3032712",
26
+ version: "1.17.4",
27
+ expectedSize: 64969580,
28
+ expectedChecksum: "9d580b58e55e57b0cdc3ca8888098d43",
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.5",
38
+ version: "1.11.6",
39
39
  expectedSize: 3063444,
40
- expectedChecksum: "4045fef65cf71fb9d83b01fb8b160141",
40
+ expectedChecksum: "14b971f4ed4909f348e647db7114d62b",
41
41
  },
42
42
  pubsub: {
43
43
  version: "0.7.1",
@@ -367,7 +367,7 @@ class FunctionsEmulator {
367
367
  const signature = (0, functionsEmulatorShared_1.getSignatureType)(definition);
368
368
  switch (service) {
369
369
  case constants_1.Constants.SERVICE_FIRESTORE:
370
- added = await this.addFirestoreTrigger(this.args.projectId, key, definition.eventTrigger);
370
+ added = await this.addFirestoreTrigger(this.args.projectId, key, definition.eventTrigger, signature);
371
371
  break;
372
372
  case constants_1.Constants.SERVICE_REALTIME_DATABASE:
373
373
  added = await this.addRealtimeDatabaseTrigger(this.args.projectId, definition.id, key, definition.eventTrigger, signature, definition.region);
@@ -531,17 +531,60 @@ class FunctionsEmulator {
531
531
  }
532
532
  return true;
533
533
  }
534
- async addFirestoreTrigger(projectId, key, eventTrigger) {
535
- if (!registry_1.EmulatorRegistry.isRunning(types_1.Emulators.FIRESTORE)) {
536
- return Promise.resolve(false);
537
- }
534
+ getV1FirestoreAttributes(projectId, key, eventTrigger) {
538
535
  const bundle = JSON.stringify({
539
536
  eventTrigger: Object.assign(Object.assign({}, eventTrigger), { service: "firestore.googleapis.com" }),
540
537
  });
538
+ const path = `/emulator/v1/projects/${projectId}/triggers/${key}`;
539
+ return { bundle, path };
540
+ }
541
+ getV2FirestoreAttributes(projectId, key, eventTrigger) {
542
+ var _a, _b, _c, _d, _e, _f;
543
+ logger_1.logger.debug("Found a v2 firestore trigger.");
544
+ const database = (_a = eventTrigger.eventFilters) === null || _a === void 0 ? void 0 : _a.database;
545
+ if (!database) {
546
+ throw new error_1.FirebaseError("A database must be supplied.");
547
+ }
548
+ const namespace = (_b = eventTrigger.eventFilters) === null || _b === void 0 ? void 0 : _b.namespace;
549
+ if (!namespace) {
550
+ throw new error_1.FirebaseError("A namespace must be supplied.");
551
+ }
552
+ let doc;
553
+ let match;
554
+ if ((_c = eventTrigger.eventFilters) === null || _c === void 0 ? void 0 : _c.document) {
555
+ doc = (_d = eventTrigger.eventFilters) === null || _d === void 0 ? void 0 : _d.document;
556
+ match = "EXACT";
557
+ }
558
+ if ((_e = eventTrigger.eventFilterPathPatterns) === null || _e === void 0 ? void 0 : _e.document) {
559
+ doc = (_f = eventTrigger.eventFilterPathPatterns) === null || _f === void 0 ? void 0 : _f.document;
560
+ match = "PATH_PATTERN";
561
+ }
562
+ if (!doc) {
563
+ throw new error_1.FirebaseError("A document must be supplied.");
564
+ }
565
+ const bundle = JSON.stringify({
566
+ eventType: eventTrigger.eventType,
567
+ database,
568
+ namespace,
569
+ document: {
570
+ value: doc,
571
+ matchType: match,
572
+ },
573
+ });
574
+ const path = `/emulator/v1/projects/${projectId}/eventarcTrigger?eventarcTriggerId=${key}`;
575
+ return { bundle, path };
576
+ }
577
+ async addFirestoreTrigger(projectId, key, eventTrigger, signature) {
578
+ if (!registry_1.EmulatorRegistry.isRunning(types_1.Emulators.FIRESTORE)) {
579
+ return Promise.resolve(false);
580
+ }
581
+ const { bundle, path } = signature === "cloudevent"
582
+ ? this.getV2FirestoreAttributes(projectId, key, eventTrigger)
583
+ : this.getV1FirestoreAttributes(projectId, key, eventTrigger);
541
584
  logger_1.logger.debug(`addFirestoreTrigger`, JSON.stringify(bundle));
542
585
  const client = registry_1.EmulatorRegistry.client(types_1.Emulators.FIRESTORE);
543
586
  try {
544
- await client.put(`/emulator/v1/projects/${projectId}/triggers/${key}`, bundle);
587
+ signature === "cloudevent" ? await client.post(path, bundle) : await client.put(path, bundle);
545
588
  }
546
589
  catch (err) {
547
590
  this.logger.log("WARN", "Error adding firestore function: " + err);
@@ -915,6 +958,7 @@ class FunctionsEmulator {
915
958
  }
916
959
  }
917
960
  async handleHttpsTrigger(req, res) {
961
+ var _a;
918
962
  const method = req.method;
919
963
  let triggerId = req.params.trigger_name;
920
964
  if (req.params.region) {
@@ -933,7 +977,13 @@ class FunctionsEmulator {
933
977
  }
934
978
  const trigger = record.def;
935
979
  logger_1.logger.debug(`Accepted request ${method} ${req.url} --> ${triggerId}`);
936
- const reqBody = req.rawBody;
980
+ let reqBody = req.rawBody;
981
+ if ((0, functionsEmulatorShared_1.getSignatureType)(trigger) === "cloudevent") {
982
+ if ((_a = req.headers["content-type"]) === null || _a === void 0 ? void 0 : _a.includes("application/protobuf")) {
983
+ reqBody = Uint8Array.from(atob(reqBody.toString()), (c) => c.charCodeAt(0));
984
+ req.headers["content-length"] = reqBody.length.toString();
985
+ }
986
+ }
937
987
  const isCallable = trigger.labels && trigger.labels["deployment-callable"] === "true";
938
988
  const authHeader = req.header("Authorization");
939
989
  if (authHeader && isCallable && trigger.platform !== "gcfv2") {
@@ -677,12 +677,15 @@ async function main() {
677
677
  switch (FUNCTION_SIGNATURE) {
678
678
  case "event":
679
679
  case "cloudevent":
680
+ let reqBody;
680
681
  const rawBody = req.rawBody;
681
- let reqBody = JSON.parse(rawBody.toString());
682
682
  if (types_2.EventUtils.isBinaryCloudEvent(req)) {
683
683
  reqBody = types_2.EventUtils.extractBinaryCloudEventContext(req);
684
684
  reqBody.data = req.body;
685
685
  }
686
+ else {
687
+ reqBody = JSON.parse(rawBody.toString());
688
+ }
686
689
  await processBackground(trigger, reqBody, FUNCTION_SIGNATURE);
687
690
  res.send({ status: "acknowledged" });
688
691
  break;
@@ -19,6 +19,7 @@ const V2_EVENTS = [
19
19
  events.v2.PUBSUB_PUBLISH_EVENT,
20
20
  ...events.v2.STORAGE_EVENTS,
21
21
  ...events.v2.DATABASE_EVENTS,
22
+ ...events.v2.FIRESTORE_EVENTS,
22
23
  ];
23
24
  exports.EVENTARC_SOURCE_ENV = "EVENTARC_CLOUD_EVENT_SOURCE";
24
25
  class HttpConstants {
@@ -110,11 +110,19 @@ class RuntimeWorker {
110
110
  }
111
111
  const proxy = http.request(reqOpts, (_resp) => {
112
112
  resp.writeHead(_resp.statusCode || 200, _resp.headers);
113
+ let finished = false;
114
+ const finishReq = (event) => {
115
+ this.logger.log("DEBUG", `Finishing up request with event=${event}`);
116
+ if (!finished) {
117
+ finished = true;
118
+ onFinish();
119
+ resolve();
120
+ }
121
+ };
122
+ _resp.on("pause", () => finishReq("pause"));
123
+ _resp.on("close", () => finishReq("close"));
113
124
  const piped = _resp.pipe(resp);
114
- piped.on("finish", () => {
115
- onFinish();
116
- resolve();
117
- });
125
+ piped.on("finish", () => finishReq("finish"));
118
126
  });
119
127
  proxy.on("timeout", () => {
120
128
  this.logger.log("ERROR", `Your function timed out after ~${this.timeoutSeconds}s. To configure this timeout, see
@@ -12,12 +12,11 @@ function getSourceFile(rules, options) {
12
12
  }
13
13
  function getStorageRulesConfig(projectId, options) {
14
14
  const storageConfig = options.config.data.storage;
15
+ const storageLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.STORAGE);
15
16
  if (!storageConfig) {
16
17
  if (constants_1.Constants.isDemoProject(projectId)) {
17
- const storageLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.STORAGE);
18
18
  storageLogger.logLabeled("BULLET", "storage", `Detected demo project ID "${projectId}", using a default (open) rules configuration.`);
19
- const path = __dirname + "/../../../../templates/emulators/default_storage.rules";
20
- return { name: path, content: (0, fsutils_1.readFile)(path) };
19
+ return defaultStorageRules();
21
20
  }
22
21
  throw new error_1.FirebaseError("Cannot start the Storage emulator without rules file specified in firebase.json: run 'firebase init' and set up your Storage configuration");
23
22
  }
@@ -33,11 +32,22 @@ function getStorageRulesConfig(projectId, options) {
33
32
  if (!targetConfig.target) {
34
33
  throw new error_1.FirebaseError("Must supply 'target' in Storage configuration");
35
34
  }
36
- rc.requireTarget(projectId, "storage", targetConfig.target);
37
- rc.target(projectId, "storage", targetConfig.target).forEach((resource) => {
38
- results.push({ resource, rules: getSourceFile(targetConfig.rules, options) });
39
- });
35
+ const targets = rc.target(projectId, "storage", targetConfig.target);
36
+ if (targets.length === 0) {
37
+ if (constants_1.Constants.isDemoProject(projectId)) {
38
+ storageLogger.logLabeled("BULLET", "storage", `Detected demo project ID "${projectId}", using a default (open) rules configuration. Storage targets in firebase.json will be ignored.`);
39
+ return defaultStorageRules();
40
+ }
41
+ rc.requireTarget(projectId, "storage", targetConfig.target);
42
+ }
43
+ results.push(...rc.target(projectId, "storage", targetConfig.target).map((resource) => {
44
+ return { resource, rules: getSourceFile(targetConfig.rules, options) };
45
+ }));
40
46
  }
41
47
  return results;
42
48
  }
43
49
  exports.getStorageRulesConfig = getStorageRulesConfig;
50
+ function defaultStorageRules() {
51
+ const path = __dirname + "/../../../../templates/emulators/default_storage.rules";
52
+ return { name: path, content: (0, fsutils_1.readFile)(path) };
53
+ }
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.flushToDisk = exports.assertEnabled = exports.enableExperimentsFromCliEnvVariable = exports.setEnabled = exports.isEnabled = exports.experimentNameAutocorrect = exports.isValidExperiment = exports.ALL_EXPERIMENTS = void 0;
4
4
  const colorette_1 = require("colorette");
5
5
  const leven = require("leven");
6
+ const path_1 = require("path");
6
7
  const configstore_1 = require("./configstore");
7
8
  const error_1 = require("./error");
9
+ const github_1 = require("./init/features/hosting/github");
8
10
  function experiments(exp) {
9
11
  return Object.freeze(exp);
10
12
  }
@@ -18,13 +20,6 @@ exports.ALL_EXPERIMENTS = experiments({
18
20
  rtdbmanagement: {
19
21
  shortDescription: "Use new endpoint to administer realtime database instances",
20
22
  },
21
- ext: {
22
- shortDescription: `Enables the ${(0, colorette_1.bold)("ext:sources:create")} command`,
23
- },
24
- extdev: {
25
- shortDescription: `Enables the ${(0, colorette_1.bold)("ext:dev")} family of commands`,
26
- docsUri: "https://firebase.google.com/docs/extensions/alpha/overview-build-extensions",
27
- },
28
23
  pythonfunctions: {
29
24
  shortDescription: "Python support for Cloud Functions for Firebase",
30
25
  fullDescription: "Adds the ability to initializea and deploy Cloud " +
@@ -65,6 +60,8 @@ exports.ALL_EXPERIMENTS = experiments({
65
60
  "exist per region. firebase-tools aggressively garbage collects tags it creates " +
66
61
  "if any service exceeds 500 tags, but it is theoretically possible that a project " +
67
62
  "exceeds the region-wide limit of tags and an old site version fails",
63
+ public: true,
64
+ default: true,
68
65
  },
69
66
  crossservicerules: {
70
67
  shortDescription: "Allow Firebase Rules to reference resources in other services",
@@ -123,8 +120,25 @@ function enableExperimentsFromCliEnvVariable() {
123
120
  }
124
121
  exports.enableExperimentsFromCliEnvVariable = enableExperimentsFromCliEnvVariable;
125
122
  function assertEnabled(name, task) {
123
+ var _a;
126
124
  if (!isEnabled(name)) {
127
- throw new error_1.FirebaseError(`Cannot ${task} because the experiment ${(0, colorette_1.bold)(name)} is not enabled. To enable ${(0, colorette_1.bold)(name)} run ${(0, colorette_1.bold)(`firebase experiments:enable ${name}`)}`);
125
+ const prefix = `Cannot ${task} because the experiment ${(0, colorette_1.bold)(name)} is not enabled.`;
126
+ if ((0, github_1.isRunningInGithubAction)()) {
127
+ const path = (_a = process.env.GITHUB_WORKFLOW_REF) === null || _a === void 0 ? void 0 : _a.split("@")[0];
128
+ const filename = path ? `.github/workflows/${(0, path_1.basename)(path)}` : "your action's yml";
129
+ const newValue = [process.env.FIREBASE_CLI_EXPERIMENTS, name].filter((it) => !!it).join(",");
130
+ throw new error_1.FirebaseError(`${prefix} To enable add a ${(0, colorette_1.bold)("FIREBASE_CLI_EXPERIMENTS")} environment variable to ${filename}, like so: ${(0, colorette_1.italic)(`
131
+
132
+ - uses: FirebaseExtended/action-hosting-deploy@v0
133
+ with:
134
+ ...
135
+ env:
136
+ FIREBASE_CLI_EXPERIMENTS: ${newValue}
137
+ `)}`);
138
+ }
139
+ else {
140
+ throw new error_1.FirebaseError(`${prefix} To enable ${(0, colorette_1.bold)(name)} run ${(0, colorette_1.bold)(`firebase experiments:enable ${name}`)}`);
141
+ }
128
142
  }
129
143
  }
130
144
  exports.assertEnabled = assertEnabled;