firebase-tools 12.3.1 → 12.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/frameworks.js +21 -0
- package/lib/api.js +4 -3
- package/lib/appdistribution/client.js +52 -0
- package/lib/auth.js +3 -3
- package/lib/command.js +15 -4
- package/lib/commands/appdistribution-group-create.js +19 -0
- package/lib/commands/appdistribution-group-delete.js +24 -0
- package/lib/commands/appdistribution-testers-add.js +6 -1
- package/lib/commands/appdistribution-testers-remove.js +20 -13
- package/lib/commands/experiments-describe.js +1 -1
- package/lib/commands/ext-install.js +10 -4
- package/lib/commands/index.js +5 -0
- package/lib/commands/init.js +8 -0
- package/lib/commands/internaltesting-frameworks-init.js +14 -0
- package/lib/config.js +1 -0
- package/lib/deploy/extensions/prepare.js +1 -0
- package/lib/deploy/extensions/release.js +11 -1
- package/lib/deploy/functions/checkIam.js +4 -1
- package/lib/deploy/functions/prepare.js +2 -1
- package/lib/deploy/functions/runtimes/discovery/index.js +6 -0
- package/lib/deploy/functions/runtimes/node/index.js +12 -4
- package/lib/deploy/functions/runtimes/python/index.js +19 -25
- package/lib/deploy/hosting/deploy.js +0 -6
- package/lib/deploy/hosting/prepare.js +7 -1
- package/lib/deploy/index.js +11 -4
- package/lib/deploy/lifecycleHooks.js +3 -0
- package/lib/deploy/storage/prepare.js +1 -1
- package/lib/detectProjectRoot.js +4 -1
- package/lib/dynamicImport.js +11 -1
- package/lib/emulator/commandUtils.js +4 -4
- package/lib/emulator/controller.js +9 -7
- package/lib/emulator/downloadableEmulators.js +3 -3
- package/lib/emulator/functionsEmulator.js +1 -2
- package/lib/emulator/storage/index.js +6 -0
- package/lib/emulator/storage/rules/manager.js +0 -4
- package/lib/emulator/storage/server.js +52 -0
- package/lib/ensureApiEnabled.js +3 -1
- package/lib/experiments.js +5 -0
- package/lib/extensions/paramHelper.js +0 -5
- package/lib/frameworks/compose/discover/filesystem.js +52 -0
- package/lib/frameworks/compose/discover/frameworkMatcher.js +76 -0
- package/lib/frameworks/compose/discover/frameworkSpec.js +39 -0
- package/lib/frameworks/compose/discover/types.js +2 -0
- package/lib/frameworks/constants.js +2 -15
- package/lib/frameworks/index.js +13 -8
- package/lib/frameworks/utils.js +50 -20
- package/lib/functionsConfig.js +2 -2
- package/lib/gcp/cloudbuild.js +50 -0
- package/lib/gcp/storage.js +6 -5
- package/lib/init/features/composer/repo.js +121 -0
- package/lib/init/features/frameworks/constants.js +7 -0
- package/lib/init/features/frameworks/index.js +36 -0
- package/lib/init/features/index.js +3 -1
- package/lib/init/index.js +4 -0
- package/lib/management/projects.js +5 -1
- package/lib/monospace/index.js +82 -0
- package/lib/monospace/interfaces.js +2 -0
- package/lib/requireAuth.js +8 -0
- package/lib/track.js +91 -52
- package/lib/utils.js +6 -1
- package/package.json +1 -1
- package/schema/extension-yaml.json +432 -0
|
@@ -11,6 +11,7 @@ const track_1 = require("../../track");
|
|
|
11
11
|
const utils = require("../../utils");
|
|
12
12
|
const backend = require("../functions/backend");
|
|
13
13
|
const ensureTargeted_1 = require("../../functions/ensureTargeted");
|
|
14
|
+
const frameworks_1 = require("../../frameworks");
|
|
14
15
|
function handlePublicDirectoryFlag(options) {
|
|
15
16
|
if (options.public) {
|
|
16
17
|
if (Array.isArray(options.config.get("hosting"))) {
|
|
@@ -48,6 +49,9 @@ async function addPinnedFunctionsToOnlyString(context, options) {
|
|
|
48
49
|
if (endpoint) {
|
|
49
50
|
options.only = (0, ensureTargeted_1.ensureTargeted)(options.only, endpoint.codebase || "default", endpoint.id);
|
|
50
51
|
}
|
|
52
|
+
else if (c.webFramework) {
|
|
53
|
+
options.only = (0, ensureTargeted_1.ensureTargeted)(options.only, (0, frameworks_1.generateSSRCodebaseId)(c.site), r.function.functionId);
|
|
54
|
+
}
|
|
51
55
|
else {
|
|
52
56
|
options.only = (0, ensureTargeted_1.ensureTargeted)(options.only, r.function.functionId);
|
|
53
57
|
}
|
|
@@ -94,7 +98,9 @@ async function prepare(context, options) {
|
|
|
94
98
|
labels,
|
|
95
99
|
};
|
|
96
100
|
const [, versionName] = await Promise.all([
|
|
97
|
-
(0, track_1.
|
|
101
|
+
(0, track_1.trackGA4)("hosting_version", {
|
|
102
|
+
framework: config.webFramework || "classic",
|
|
103
|
+
}),
|
|
98
104
|
api.createVersion(config.site, version),
|
|
99
105
|
]);
|
|
100
106
|
return versionName;
|
package/lib/deploy/index.js
CHANGED
|
@@ -96,11 +96,18 @@ const deploy = async function (targetNames, options, customContext = {}) {
|
|
|
96
96
|
await chain(deploys, context, options, payload);
|
|
97
97
|
await chain(releases, context, options, payload);
|
|
98
98
|
await chain(postdeploys, context, options, payload);
|
|
99
|
-
if ((0, lodash_1.has)(options, "config.notes.databaseRules")) {
|
|
100
|
-
await (0, track_1.track)("Rules Deploy", options.config.notes.databaseRules);
|
|
101
|
-
}
|
|
102
99
|
const duration = Date.now() - startTime;
|
|
103
|
-
|
|
100
|
+
const analyticsParams = {
|
|
101
|
+
interactive: options.nonInteractive ? "false" : "true",
|
|
102
|
+
};
|
|
103
|
+
Object.keys(TARGETS).reduce((accum, t) => {
|
|
104
|
+
accum[t] = "false";
|
|
105
|
+
return accum;
|
|
106
|
+
}, analyticsParams);
|
|
107
|
+
for (const t of targetNames) {
|
|
108
|
+
analyticsParams[t] = "true";
|
|
109
|
+
}
|
|
110
|
+
await (0, track_1.trackGA4)("product_deploy", analyticsParams, duration);
|
|
104
111
|
logger_1.logger.info();
|
|
105
112
|
(0, utils_1.logSuccess)((0, colorette_1.bold)((0, colorette_1.underline)("Deploy complete!")));
|
|
106
113
|
logger_1.logger.info();
|
|
@@ -115,6 +115,9 @@ function getReleventConfigs(target, options) {
|
|
|
115
115
|
return individualOnly.replace(`${target}:`, "");
|
|
116
116
|
});
|
|
117
117
|
return targetConfigs.filter((config) => {
|
|
118
|
+
if (target === "functions") {
|
|
119
|
+
return onlyTargets.includes(config.codebase);
|
|
120
|
+
}
|
|
118
121
|
return !config.target || onlyTargets.includes(config.target);
|
|
119
122
|
});
|
|
120
123
|
}
|
|
@@ -26,7 +26,7 @@ async function default_1(context, options) {
|
|
|
26
26
|
}
|
|
27
27
|
const rulesDeploy = new rulesDeploy_1.RulesDeploy(options, rulesDeploy_1.RulesetServiceType.FIREBASE_STORAGE);
|
|
28
28
|
const rulesConfigsToDeploy = [];
|
|
29
|
-
if (!Array.isArray(rulesConfig)) {
|
|
29
|
+
if (!Array.isArray(rulesConfig) && options.project) {
|
|
30
30
|
const defaultBucket = await gcp.storage.getDefaultBucket(options.project);
|
|
31
31
|
rulesConfig = [Object.assign(rulesConfig, { bucket: defaultBucket })];
|
|
32
32
|
}
|
package/lib/detectProjectRoot.js
CHANGED
|
@@ -9,7 +9,10 @@ function detectProjectRoot(options) {
|
|
|
9
9
|
if (options.configPath) {
|
|
10
10
|
const fullPath = (0, path_1.resolve)(projectRootDir, options.configPath);
|
|
11
11
|
if (!(0, fsutils_1.fileExistsSync)(fullPath)) {
|
|
12
|
-
throw new error_1.FirebaseError(`Could not load config file ${options.configPath}.`, {
|
|
12
|
+
throw new error_1.FirebaseError(`Could not load config file ${options.configPath}.`, {
|
|
13
|
+
exit: 1,
|
|
14
|
+
status: 404,
|
|
15
|
+
});
|
|
13
16
|
}
|
|
14
17
|
return (0, path_1.dirname)(fullPath);
|
|
15
18
|
}
|
package/lib/dynamicImport.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
const { pathToFileURL } = require("url");
|
|
2
2
|
|
|
3
|
+
// If being compiled with webpack, use non webpack require for these calls.
|
|
4
|
+
// (VSCode plugin uses webpack which by default replaces require calls
|
|
5
|
+
// with its own require, which doesn't work on files)
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
7
|
+
const requireFunc =
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
9
|
+
// @ts-ignore prevent VSCE webpack from erroring on non_webpack_require
|
|
10
|
+
// eslint-disable-next-line camelcase
|
|
11
|
+
typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
|
|
12
|
+
|
|
3
13
|
exports.dynamicImport = function(mod) {
|
|
4
14
|
if (mod.startsWith("file://")) return import(mod);
|
|
5
15
|
if (mod.startsWith("/")) return import(pathToFileURL(mod).toString());
|
|
6
16
|
try {
|
|
7
|
-
const path =
|
|
17
|
+
const path = requireFunc.resolve(mod);
|
|
8
18
|
return import(pathToFileURL(path).toString());
|
|
9
19
|
} catch(e) {
|
|
10
20
|
return Promise.reject(e);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.JAVA_DEPRECATION_WARNING = exports.MIN_SUPPORTED_JAVA_MAJOR_VERSION = exports.checkJavaMajorVersion = exports.emulatorExec = exports.getListenOverview = exports.shutdownWhenKilled = exports.setExportOnExitOptions = exports.parseInspectionPort = exports.beforeEmulatorCommand = exports.warnEmulatorNotSupported = exports.printNoticeIfEmulated = exports.DESC_TEST_PARAMS = exports.FLAG_TEST_PARAMS = exports.DESC_TEST_CONFIG = exports.FLAG_TEST_CONFIG = exports.DESC_UI = exports.FLAG_UI = exports.EXPORT_ON_EXIT_CWD_DANGER = exports.EXPORT_ON_EXIT_USAGE_ERROR = exports.DESC_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT_NAME = exports.DESC_IMPORT = exports.FLAG_IMPORT = exports.DESC_INSPECT_FUNCTIONS = exports.FLAG_INSPECT_FUNCTIONS = exports.DESC_ONLY = exports.FLAG_ONLY = void 0;
|
|
3
|
+
exports.JAVA_DEPRECATION_WARNING = exports.MIN_SUPPORTED_JAVA_MAJOR_VERSION = exports.checkJavaMajorVersion = exports.emulatorExec = exports.getListenOverview = exports.shutdownWhenKilled = exports.setExportOnExitOptions = exports.parseInspectionPort = exports.beforeEmulatorCommand = exports.warnEmulatorNotSupported = exports.printNoticeIfEmulated = exports.DEFAULT_CONFIG = exports.DESC_TEST_PARAMS = exports.FLAG_TEST_PARAMS = exports.DESC_TEST_CONFIG = exports.FLAG_TEST_CONFIG = exports.DESC_UI = exports.FLAG_UI = exports.EXPORT_ON_EXIT_CWD_DANGER = exports.EXPORT_ON_EXIT_USAGE_ERROR = exports.DESC_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT_NAME = exports.DESC_IMPORT = exports.FLAG_IMPORT = exports.DESC_INSPECT_FUNCTIONS = exports.FLAG_INSPECT_FUNCTIONS = exports.DESC_ONLY = exports.FLAG_ONLY = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const childProcess = require("child_process");
|
|
6
6
|
const controller = require("../emulator/controller");
|
|
@@ -43,7 +43,7 @@ exports.FLAG_TEST_CONFIG = "--test-config <firebase.json file>";
|
|
|
43
43
|
exports.DESC_TEST_CONFIG = "A firebase.json style file. Used to configure the Firestore and Realtime Database emulators.";
|
|
44
44
|
exports.FLAG_TEST_PARAMS = "--test-params <params.env file>";
|
|
45
45
|
exports.DESC_TEST_PARAMS = "A .env file containing test param values for your emulated extension.";
|
|
46
|
-
|
|
46
|
+
exports.DEFAULT_CONFIG = new config_1.Config({
|
|
47
47
|
eventarc: {},
|
|
48
48
|
database: {},
|
|
49
49
|
firestore: {},
|
|
@@ -92,7 +92,7 @@ function warnEmulatorNotSupported(options, emulator) {
|
|
|
92
92
|
}
|
|
93
93
|
exports.warnEmulatorNotSupported = warnEmulatorNotSupported;
|
|
94
94
|
async function beforeEmulatorCommand(options) {
|
|
95
|
-
const optionsWithDefaultConfig = Object.assign(Object.assign({}, options), { config: DEFAULT_CONFIG });
|
|
95
|
+
const optionsWithDefaultConfig = Object.assign(Object.assign({}, options), { config: exports.DEFAULT_CONFIG });
|
|
96
96
|
const optionsWithConfig = options.config ? options : optionsWithDefaultConfig;
|
|
97
97
|
const canStartWithoutConfig = options.only &&
|
|
98
98
|
!controller.shouldStart(optionsWithConfig, types_1.Emulators.FUNCTIONS) &&
|
|
@@ -106,7 +106,7 @@ async function beforeEmulatorCommand(options) {
|
|
|
106
106
|
}
|
|
107
107
|
if (canStartWithoutConfig && !options.config) {
|
|
108
108
|
utils.logWarning("Could not find config (firebase.json) so using defaults.");
|
|
109
|
-
options.config = DEFAULT_CONFIG;
|
|
109
|
+
options.config = exports.DEFAULT_CONFIG;
|
|
110
110
|
}
|
|
111
111
|
else {
|
|
112
112
|
await (0, requireConfig_1.requireConfig)(options);
|
|
@@ -209,6 +209,10 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
209
209
|
const extensionsBackends = await extensionEmulator.getExtensionBackends();
|
|
210
210
|
const filteredExtensionsBackends = extensionEmulator.filterUnemulatedTriggers(options, extensionsBackends);
|
|
211
211
|
emulatableBackends.push(...filteredExtensionsBackends);
|
|
212
|
+
(0, track_1.trackGA4)("extensions_emulated", {
|
|
213
|
+
number_of_extensions_emulated: filteredExtensionsBackends.length,
|
|
214
|
+
number_of_extensions_ignored: extensionsBackends.length - filteredExtensionsBackends.length,
|
|
215
|
+
});
|
|
212
216
|
}
|
|
213
217
|
const listenConfig = {};
|
|
214
218
|
if (emulatableBackends.length) {
|
|
@@ -248,7 +252,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
248
252
|
}
|
|
249
253
|
function startEmulator(instance) {
|
|
250
254
|
const name = instance.getName();
|
|
251
|
-
void (0, track_1.track)("Emulator Run", name);
|
|
252
255
|
void (0, track_1.trackEmulator)("emulator_run", {
|
|
253
256
|
emulator_name: name,
|
|
254
257
|
is_demo_project: String(isDemoProject),
|
|
@@ -261,7 +264,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
261
264
|
listen: listenForEmulator[types_1.Emulators.HUB],
|
|
262
265
|
listenForEmulator,
|
|
263
266
|
});
|
|
264
|
-
void (0, track_1.track)("emulators:start", "hub");
|
|
265
267
|
await startEmulator(hub);
|
|
266
268
|
}
|
|
267
269
|
let exportMetadata = {
|
|
@@ -531,11 +533,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
531
533
|
});
|
|
532
534
|
await startEmulator(hostingEmulator);
|
|
533
535
|
}
|
|
534
|
-
if (showUI && !shouldStart(options, types_1.Emulators.UI)) {
|
|
535
|
-
hubLogger.logLabeled("WARN", "emulators", "The Emulator UI is not starting, either because none of the emulated " +
|
|
536
|
-
"products have an interaction layer in Emulator UI or it cannot " +
|
|
537
|
-
"determine the Project ID. Pass the --project flag to specify a project.");
|
|
538
|
-
}
|
|
539
536
|
if (listenForEmulator.logging) {
|
|
540
537
|
const loggingAddr = legacyGetFirstAddr(types_1.Emulators.LOGGING);
|
|
541
538
|
const loggingEmulator = new loggingEmulator_1.LoggingEmulator({
|
|
@@ -544,6 +541,11 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
544
541
|
});
|
|
545
542
|
await startEmulator(loggingEmulator);
|
|
546
543
|
}
|
|
544
|
+
if (showUI && !shouldStart(options, types_1.Emulators.UI)) {
|
|
545
|
+
hubLogger.logLabeled("WARN", "emulators", "The Emulator UI is not starting, either because none of the running " +
|
|
546
|
+
"emulators have a UI component or the Emulator UI cannot " +
|
|
547
|
+
"determine the Project ID. Pass the --project flag to specify a project.");
|
|
548
|
+
}
|
|
547
549
|
if (listenForEmulator.ui) {
|
|
548
550
|
const ui = new ui_1.EmulatorUI({
|
|
549
551
|
projectId: projectId,
|
|
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
23
23
|
expectedChecksum: "2fd771101c0e1f7898c04c9204f2ce63",
|
|
24
24
|
},
|
|
25
25
|
firestore: {
|
|
26
|
-
version: "1.
|
|
27
|
-
expectedSize:
|
|
28
|
-
expectedChecksum: "
|
|
26
|
+
version: "1.18.1",
|
|
27
|
+
expectedSize: 64866257,
|
|
28
|
+
expectedChecksum: "743211a3e33217fe71dc20aff1fa26a5",
|
|
29
29
|
},
|
|
30
30
|
storage: {
|
|
31
31
|
version: "1.1.3",
|
|
@@ -36,7 +36,6 @@ const v1_1 = require("../functions/events/v1");
|
|
|
36
36
|
const build_1 = require("../deploy/functions/build");
|
|
37
37
|
const env_1 = require("./env");
|
|
38
38
|
const python_1 = require("../functions/python");
|
|
39
|
-
const EVENT_INVOKE = "functions:invoke";
|
|
40
39
|
const EVENT_INVOKE_GA4 = "functions_invoke";
|
|
41
40
|
const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
|
|
42
41
|
class IPCConn {
|
|
@@ -754,6 +753,7 @@ class FunctionsEmulator {
|
|
|
754
753
|
envs.GCLOUD_PROJECT = this.args.projectId;
|
|
755
754
|
envs.K_REVISION = "1";
|
|
756
755
|
envs.PORT = "80";
|
|
756
|
+
envs.GOOGLE_CLOUD_QUOTA_PROJECT = this.args.projectId;
|
|
757
757
|
if (trigger) {
|
|
758
758
|
const target = trigger.entryPoint;
|
|
759
759
|
envs.FUNCTION_TARGET = target;
|
|
@@ -1003,7 +1003,6 @@ class FunctionsEmulator {
|
|
|
1003
1003
|
req.headers[functionsEmulatorShared_1.HttpConstants.CALLABLE_AUTH_HEADER] = encodeURIComponent(JSON.stringify(contextAuth));
|
|
1004
1004
|
}
|
|
1005
1005
|
}
|
|
1006
|
-
void (0, track_1.track)(EVENT_INVOKE, (0, functionsEmulatorShared_1.getFunctionService)(trigger));
|
|
1007
1006
|
void (0, track_1.trackEmulator)(EVENT_INVOKE_GA4, {
|
|
1008
1007
|
function_service: (0, functionsEmulatorShared_1.getFunctionService)(trigger),
|
|
1009
1008
|
});
|
|
@@ -64,6 +64,7 @@ class StorageEmulator {
|
|
|
64
64
|
}
|
|
65
65
|
async stop() {
|
|
66
66
|
await this._persistence.deleteAll();
|
|
67
|
+
await this._rulesRuntime.stop();
|
|
67
68
|
await this._rulesManager.stop();
|
|
68
69
|
return this.destroyServer ? this.destroyServer() : Promise.resolve();
|
|
69
70
|
}
|
|
@@ -85,6 +86,11 @@ class StorageEmulator {
|
|
|
85
86
|
createRulesManager(rules) {
|
|
86
87
|
return (0, manager_1.createStorageRulesManager)(rules, this._rulesRuntime);
|
|
87
88
|
}
|
|
89
|
+
async replaceRules(rules) {
|
|
90
|
+
await this._rulesManager.stop();
|
|
91
|
+
this._rulesManager = this.createRulesManager(rules);
|
|
92
|
+
return this._rulesManager.start();
|
|
93
|
+
}
|
|
88
94
|
getPersistenceTmpDir() {
|
|
89
95
|
return `${(0, os_1.tmpdir)()}/firebase/storage/blobs`;
|
|
90
96
|
}
|
|
@@ -20,7 +20,6 @@ class DefaultStorageRulesManager {
|
|
|
20
20
|
this._rules = _rules;
|
|
21
21
|
}
|
|
22
22
|
async start() {
|
|
23
|
-
this._runtime.start();
|
|
24
23
|
const issues = await this.loadRuleset();
|
|
25
24
|
this.updateWatcher(this._rules.name);
|
|
26
25
|
return issues;
|
|
@@ -30,9 +29,6 @@ class DefaultStorageRulesManager {
|
|
|
30
29
|
}
|
|
31
30
|
async stop() {
|
|
32
31
|
await this._watcher.close();
|
|
33
|
-
if (this._runtime.alive) {
|
|
34
|
-
await this._runtime.stop();
|
|
35
|
-
}
|
|
36
32
|
}
|
|
37
33
|
updateWatcher(rulesFile) {
|
|
38
34
|
this._watcher = chokidar
|
|
@@ -8,6 +8,7 @@ const types_1 = require("../types");
|
|
|
8
8
|
const bodyParser = require("body-parser");
|
|
9
9
|
const gcloud_1 = require("./apis/gcloud");
|
|
10
10
|
const firebase_1 = require("./apis/firebase");
|
|
11
|
+
const errors_1 = require("../auth/errors");
|
|
11
12
|
function createApp(defaultProjectId, emulator) {
|
|
12
13
|
const { storageLayer } = emulator;
|
|
13
14
|
const app = express();
|
|
@@ -50,6 +51,54 @@ function createApp(defaultProjectId, emulator) {
|
|
|
50
51
|
await storageLayer.export(path, { initiatedBy });
|
|
51
52
|
res.sendStatus(200);
|
|
52
53
|
});
|
|
54
|
+
app.put("/internal/setRules", async (req, res) => {
|
|
55
|
+
const rulesRaw = req.body.rules;
|
|
56
|
+
if (!(rulesRaw && Array.isArray(rulesRaw.files) && rulesRaw.files.length > 0)) {
|
|
57
|
+
res.status(400).json({
|
|
58
|
+
message: "Request body must include 'rules.files' array",
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const { files } = rulesRaw;
|
|
63
|
+
function parseRulesFromFiles(files) {
|
|
64
|
+
if (files.length === 1) {
|
|
65
|
+
const file = files[0];
|
|
66
|
+
if (!isRulesFile(file)) {
|
|
67
|
+
throw new errors_1.InvalidArgumentError("Each member of 'rules.files' array must contain 'name' and 'content'");
|
|
68
|
+
}
|
|
69
|
+
return { name: file.name, content: file.content };
|
|
70
|
+
}
|
|
71
|
+
const rules = [];
|
|
72
|
+
for (const file of files) {
|
|
73
|
+
if (!isRulesFile(file) || !file.resource) {
|
|
74
|
+
throw new errors_1.InvalidArgumentError("Each member of 'rules.files' array must contain 'name', 'content', and 'resource'");
|
|
75
|
+
}
|
|
76
|
+
rules.push({ resource: file.resource, rules: { name: file.name, content: file.content } });
|
|
77
|
+
}
|
|
78
|
+
return rules;
|
|
79
|
+
}
|
|
80
|
+
let rules;
|
|
81
|
+
try {
|
|
82
|
+
rules = parseRulesFromFiles(files);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if (err instanceof errors_1.InvalidArgumentError) {
|
|
86
|
+
res.status(400).json({ message: err.message });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
const issues = await emulator.replaceRules(rules);
|
|
92
|
+
if (issues.errors.length > 0) {
|
|
93
|
+
res.status(400).json({
|
|
94
|
+
message: "There was an error updating rules, see logs for more details",
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
res.status(200).json({
|
|
99
|
+
message: "Rules updated successfully",
|
|
100
|
+
});
|
|
101
|
+
});
|
|
53
102
|
app.post("/internal/reset", (req, res) => {
|
|
54
103
|
emulator.reset();
|
|
55
104
|
res.sendStatus(200);
|
|
@@ -59,3 +108,6 @@ function createApp(defaultProjectId, emulator) {
|
|
|
59
108
|
return Promise.resolve(app);
|
|
60
109
|
}
|
|
61
110
|
exports.createApp = createApp;
|
|
111
|
+
function isRulesFile(file) {
|
|
112
|
+
return (typeof file.name === "string" && typeof file.content === "string");
|
|
113
|
+
}
|
package/lib/ensureApiEnabled.js
CHANGED
|
@@ -52,7 +52,9 @@ async function pollCheckEnabled(projectId, apiName, prefix, silent, enablementRe
|
|
|
52
52
|
});
|
|
53
53
|
const isEnabled = await check(projectId, apiName, prefix, silent);
|
|
54
54
|
if (isEnabled) {
|
|
55
|
-
void (0, track_1.
|
|
55
|
+
void (0, track_1.trackGA4)("api_enabled", {
|
|
56
|
+
api_name: apiName,
|
|
57
|
+
});
|
|
56
58
|
return;
|
|
57
59
|
}
|
|
58
60
|
if (!silent) {
|
package/lib/experiments.js
CHANGED
|
@@ -72,6 +72,11 @@ exports.ALL_EXPERIMENTS = experiments({
|
|
|
72
72
|
"These commands are not meant for public consumption and may break or disappear " +
|
|
73
73
|
"without a notice.",
|
|
74
74
|
},
|
|
75
|
+
frameworks: {
|
|
76
|
+
shortDescription: "Allow CLI option for Frameworks",
|
|
77
|
+
default: true,
|
|
78
|
+
public: false,
|
|
79
|
+
},
|
|
75
80
|
});
|
|
76
81
|
function isValidExperiment(name) {
|
|
77
82
|
return Object.keys(exports.ALL_EXPERIMENTS).includes(name);
|
|
@@ -8,7 +8,6 @@ const error_1 = require("../error");
|
|
|
8
8
|
const logger_1 = require("../logger");
|
|
9
9
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
10
10
|
const askUserForParam = require("./askUserForParam");
|
|
11
|
-
const track_1 = require("../track");
|
|
12
11
|
const env = require("../functions/env");
|
|
13
12
|
const utils_1 = require("../utils");
|
|
14
13
|
const NONINTERACTIVE_ERROR_MESSAGE = "As of firebase-tools@11, `ext:install`, `ext:update` and `ext:configure` are interactive only commands. " +
|
|
@@ -61,8 +60,6 @@ async function getParams(args) {
|
|
|
61
60
|
reconfiguring: !!args.reconfiguring,
|
|
62
61
|
});
|
|
63
62
|
}
|
|
64
|
-
const paramNames = Object.keys(params);
|
|
65
|
-
void (0, track_1.track)("Extension Params", paramNames.length ? "Not Present" : "Present", paramNames.length);
|
|
66
63
|
return params;
|
|
67
64
|
}
|
|
68
65
|
exports.getParams = getParams;
|
|
@@ -80,8 +77,6 @@ async function getParamsForUpdate(args) {
|
|
|
80
77
|
instanceId: args.instanceId,
|
|
81
78
|
});
|
|
82
79
|
}
|
|
83
|
-
const paramNames = Object.keys(params);
|
|
84
|
-
void (0, track_1.track)("Extension Params", paramNames.length ? "Not Present" : "Present", paramNames.length);
|
|
85
80
|
return params;
|
|
86
81
|
}
|
|
87
82
|
exports.getParamsForUpdate = getParamsForUpdate;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readOrNull = exports.LocalFileSystem = void 0;
|
|
4
|
+
const fs_extra_1 = require("fs-extra");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const error_1 = require("../../../error");
|
|
7
|
+
const logger_1 = require("../../../../src/logger");
|
|
8
|
+
class LocalFileSystem {
|
|
9
|
+
constructor(cwd) {
|
|
10
|
+
this.cwd = cwd;
|
|
11
|
+
this.existsCache = {};
|
|
12
|
+
this.contentCache = {};
|
|
13
|
+
}
|
|
14
|
+
async exists(file) {
|
|
15
|
+
try {
|
|
16
|
+
if (!(file in this.contentCache)) {
|
|
17
|
+
this.existsCache[file] = await (0, fs_extra_1.pathExists)(path.resolve(this.cwd, file));
|
|
18
|
+
}
|
|
19
|
+
return this.existsCache[file];
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
throw new error_1.FirebaseError(`Error occured while searching for file: ${error}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async read(file) {
|
|
26
|
+
try {
|
|
27
|
+
if (!(file in this.contentCache)) {
|
|
28
|
+
const fileContents = await (0, fs_extra_1.readFile)(path.resolve(this.cwd, file), "utf-8");
|
|
29
|
+
this.contentCache[file] = fileContents;
|
|
30
|
+
}
|
|
31
|
+
return this.contentCache[file];
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
logger_1.logger.error("Error occured while reading file contents.");
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.LocalFileSystem = LocalFileSystem;
|
|
40
|
+
async function readOrNull(fs, path) {
|
|
41
|
+
try {
|
|
42
|
+
return fs.read(path);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
if (err && typeof err === "object" && (err === null || err === void 0 ? void 0 : err.code) === "ENOENT") {
|
|
46
|
+
logger_1.logger.debug("ENOENT error occured while reading file.");
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`Unknown error occured while reading file: ${err}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.readOrNull = readOrNull;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.frameworkMatcher = exports.removeEmbededFrameworks = exports.filterFrameworksWithFiles = exports.filterFrameworksWithDependencies = void 0;
|
|
4
|
+
const error_1 = require("../../../error");
|
|
5
|
+
const logger_1 = require("../../../logger");
|
|
6
|
+
function filterFrameworksWithDependencies(allFrameworkSpecs, dependencies) {
|
|
7
|
+
return allFrameworkSpecs.filter((framework) => {
|
|
8
|
+
return framework.requiredDependencies.every((dependency) => {
|
|
9
|
+
return dependency.name in dependencies;
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
exports.filterFrameworksWithDependencies = filterFrameworksWithDependencies;
|
|
14
|
+
async function filterFrameworksWithFiles(allFrameworkSpecs, fs) {
|
|
15
|
+
try {
|
|
16
|
+
const filteredFrameworks = [];
|
|
17
|
+
for (const framework of allFrameworkSpecs) {
|
|
18
|
+
if (!framework.requiredFiles) {
|
|
19
|
+
filteredFrameworks.push(framework);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
let isRequired = true;
|
|
23
|
+
for (let files of framework.requiredFiles) {
|
|
24
|
+
files = Array.isArray(files) ? files : [files];
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
isRequired = isRequired && (await fs.exists(file));
|
|
27
|
+
if (!isRequired) {
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (isRequired) {
|
|
33
|
+
filteredFrameworks.push(framework);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return filteredFrameworks;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
logger_1.logger.error("Error: Unable to filter frameworks based on required files", error);
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.filterFrameworksWithFiles = filterFrameworksWithFiles;
|
|
44
|
+
function removeEmbededFrameworks(allFrameworkSpecs) {
|
|
45
|
+
const embededFrameworkSet = new Set();
|
|
46
|
+
for (const framework of allFrameworkSpecs) {
|
|
47
|
+
if (!framework.embedsFrameworks) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
for (const item of framework.embedsFrameworks) {
|
|
51
|
+
embededFrameworkSet.add(item);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return allFrameworkSpecs.filter((item) => !embededFrameworkSet.has(item.id));
|
|
55
|
+
}
|
|
56
|
+
exports.removeEmbededFrameworks = removeEmbededFrameworks;
|
|
57
|
+
async function frameworkMatcher(runtime, fs, frameworks, dependencies) {
|
|
58
|
+
try {
|
|
59
|
+
const filterRuntimeFramework = frameworks.filter((framework) => framework.runtime === runtime);
|
|
60
|
+
const frameworksWithDependencies = filterFrameworksWithDependencies(filterRuntimeFramework, dependencies);
|
|
61
|
+
const frameworkWithFiles = await filterFrameworksWithFiles(frameworksWithDependencies, fs);
|
|
62
|
+
const allMatches = removeEmbededFrameworks(frameworkWithFiles);
|
|
63
|
+
if (allMatches.length === 0) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
if (allMatches.length > 1) {
|
|
67
|
+
const frameworkNames = allMatches.map((framework) => framework.id);
|
|
68
|
+
throw new error_1.FirebaseError(`Multiple Frameworks are matched: ${frameworkNames.join(", ")} Manually set up override commands in firebase.json`);
|
|
69
|
+
}
|
|
70
|
+
return allMatches[0];
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw new error_1.FirebaseError(`Failed to match the correct framework: ${error}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.frameworkMatcher = frameworkMatcher;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.frameworkSpecs = void 0;
|
|
4
|
+
exports.frameworkSpecs = [
|
|
5
|
+
{
|
|
6
|
+
id: "express",
|
|
7
|
+
runtime: "nodejs",
|
|
8
|
+
webFrameworkId: "Express.js",
|
|
9
|
+
requiredDependencies: [
|
|
10
|
+
{
|
|
11
|
+
name: "express",
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "nextjs",
|
|
17
|
+
runtime: "nodejs",
|
|
18
|
+
webFrameworkId: "Next.js",
|
|
19
|
+
requiredFiles: ["next.config.js", "next.config.ts"],
|
|
20
|
+
requiredDependencies: [
|
|
21
|
+
{
|
|
22
|
+
name: "next",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
commands: {
|
|
26
|
+
build: {
|
|
27
|
+
cmd: "next build",
|
|
28
|
+
},
|
|
29
|
+
dev: {
|
|
30
|
+
cmd: "next dev",
|
|
31
|
+
env: { NODE_ENV: "dev" },
|
|
32
|
+
},
|
|
33
|
+
run: {
|
|
34
|
+
cmd: "next run",
|
|
35
|
+
env: { NODE_ENV: "production" },
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
];
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE = exports.GET_DEFAULT_BUILD_TARGETS = exports.
|
|
4
|
-
const fs_1 = require("fs");
|
|
5
|
-
const path_1 = require("path");
|
|
3
|
+
exports.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE = exports.GET_DEFAULT_BUILD_TARGETS = exports.I18N_ROOT = exports.ALLOWED_SSR_REGIONS = exports.DEFAULT_REGION = exports.VALID_LOCALE_FORMATS = exports.VALID_ENGINES = exports.NODE_VERSION = exports.SHARP_VERSION = exports.FIREBASE_ADMIN_VERSION = exports.FIREBASE_FUNCTIONS_VERSION = exports.FIREBASE_FRAMEWORKS_VERSION = exports.MAILING_LIST_URL = exports.FEATURE_REQUEST_URL = exports.FILE_BUG_URL = exports.DEFAULT_DOCS_URL = exports.SupportLevelWarnings = exports.NPM_COMMAND_TIMEOUT_MILLIES = void 0;
|
|
6
4
|
const clc = require("colorette");
|
|
7
5
|
exports.NPM_COMMAND_TIMEOUT_MILLIES = 10000;
|
|
8
6
|
exports.SupportLevelWarnings = {
|
|
@@ -16,7 +14,7 @@ exports.DEFAULT_DOCS_URL = "https://firebase.google.com/docs/hosting/frameworks/
|
|
|
16
14
|
exports.FILE_BUG_URL = "https://github.com/firebase/firebase-tools/issues/new?template=bug_report.md";
|
|
17
15
|
exports.FEATURE_REQUEST_URL = "https://github.com/firebase/firebase-tools/issues/new?template=feature_request.md";
|
|
18
16
|
exports.MAILING_LIST_URL = "https://goo.gle/41enW5X";
|
|
19
|
-
exports.FIREBASE_FRAMEWORKS_VERSION = "^0.10.
|
|
17
|
+
exports.FIREBASE_FRAMEWORKS_VERSION = "^0.10.4";
|
|
20
18
|
exports.FIREBASE_FUNCTIONS_VERSION = "^4.3.0";
|
|
21
19
|
exports.FIREBASE_ADMIN_VERSION = "^11.0.1";
|
|
22
20
|
exports.SHARP_VERSION = "^0.32.1";
|
|
@@ -32,17 +30,6 @@ exports.ALLOWED_SSR_REGIONS = [
|
|
|
32
30
|
{ name: "asia-east1 (Taiwan)", value: "asia-east1" },
|
|
33
31
|
];
|
|
34
32
|
exports.I18N_ROOT = "/";
|
|
35
|
-
exports.WebFrameworks = Object.fromEntries((0, fs_1.readdirSync)(__dirname)
|
|
36
|
-
.filter((path) => (0, fs_1.statSync)((0, path_1.join)(__dirname, path)).isDirectory())
|
|
37
|
-
.map((path) => {
|
|
38
|
-
try {
|
|
39
|
-
return [path, require((0, path_1.join)(__dirname, path))];
|
|
40
|
-
}
|
|
41
|
-
catch (e) {
|
|
42
|
-
return [];
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
|
-
.filter(([, obj]) => obj && obj.name && obj.discover && obj.build && obj.type !== undefined && obj.support));
|
|
46
33
|
function GET_DEFAULT_BUILD_TARGETS() {
|
|
47
34
|
return Promise.resolve(["production", "development"]);
|
|
48
35
|
}
|