firebase-tools 12.4.0 → 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 -2
- package/lib/auth.js +3 -3
- package/lib/command.js +15 -4
- package/lib/commands/ext-install.js +10 -4
- package/lib/commands/index.js +2 -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/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/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/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 +7 -7
- package/lib/requireAuth.js +1 -1
- package/lib/track.js +91 -52
- package/lib/utils.js +6 -1
- package/package.json +1 -1
- package/schema/extension-yaml.json +432 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBuild = exports.createStack = exports.API_VERSION = void 0;
|
|
4
|
+
const apiv2_1 = require("../apiv2");
|
|
5
|
+
const api_1 = require("../api");
|
|
6
|
+
exports.API_VERSION = "v1";
|
|
7
|
+
const client = new apiv2_1.Client({
|
|
8
|
+
urlPrefix: api_1.frameworksOrigin,
|
|
9
|
+
auth: true,
|
|
10
|
+
apiVersion: exports.API_VERSION,
|
|
11
|
+
});
|
|
12
|
+
async function createStack(projectId, location, stackId, stack) {
|
|
13
|
+
const res = await client.post(`projects/${projectId}/locations/${location}/stacks`, stack, { queryParams: { stackId } });
|
|
14
|
+
return res.body;
|
|
15
|
+
}
|
|
16
|
+
exports.createStack = createStack;
|
|
17
|
+
async function createBuild(projectId, location, stackId, buildId, build) {
|
|
18
|
+
const res = await client.post(`projects/${projectId}/locations/${location}/stacks/${stackId}/builds`, build, { queryParams: { buildId } });
|
|
19
|
+
return res.body;
|
|
20
|
+
}
|
|
21
|
+
exports.createBuild = createBuild;
|
package/lib/api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.setScopes = exports.getScopes = exports.githubClientSecret = void 0;
|
|
3
|
+
exports.githubApiOrigin = exports.githubOrigin = exports.frameworksOrigin = exports.serviceUsageOrigin = exports.cloudRunApiOrigin = exports.hostingApiOrigin = exports.firebaseStorageOrigin = exports.storageOrigin = exports.runtimeconfigOrigin = exports.rulesOrigin = exports.resourceManagerOrigin = exports.remoteConfigApiOrigin = exports.rtdbMetadataOrigin = exports.rtdbManagementOrigin = exports.realtimeOrigin = exports.extensionsTOSOrigin = exports.extensionsPublisherOrigin = exports.extensionsOrigin = exports.iamOrigin = exports.identityOrigin = exports.hostingOrigin = exports.googleOrigin = exports.pubsubOrigin = exports.cloudTasksOrigin = exports.cloudschedulerOrigin = exports.cloudbuildOrigin = exports.functionsDefaultRegion = exports.runOrigin = exports.functionsV2Origin = exports.functionsOrigin = exports.firestoreOrigin = exports.firestoreOriginOrEmulator = exports.firedataOrigin = exports.firebaseExtensionsRegistryOrigin = exports.firebaseApiOrigin = exports.eventarcOrigin = exports.dynamicLinksKey = exports.dynamicLinksOrigin = exports.deployOrigin = exports.consoleOrigin = exports.authOrigin = exports.appDistributionOrigin = exports.artifactRegistryDomain = exports.containerRegistryDomain = exports.cloudMonitoringOrigin = exports.cloudloggingOrigin = exports.cloudbillingOrigin = exports.clientSecret = exports.clientId = exports.authProxyOrigin = void 0;
|
|
4
|
+
exports.setScopes = exports.getScopes = exports.githubClientSecret = exports.githubClientId = exports.secretManagerOrigin = void 0;
|
|
5
5
|
const constants_1 = require("./emulator/constants");
|
|
6
6
|
const logger_1 = require("./logger");
|
|
7
7
|
const scopes = require("./scopes");
|
|
@@ -36,6 +36,7 @@ exports.functionsOrigin = utils.envOverride("FIREBASE_FUNCTIONS_URL", "https://c
|
|
|
36
36
|
exports.functionsV2Origin = utils.envOverride("FIREBASE_FUNCTIONS_V2_URL", "https://cloudfunctions.googleapis.com");
|
|
37
37
|
exports.runOrigin = utils.envOverride("CLOUD_RUN_URL", "https://run.googleapis.com");
|
|
38
38
|
exports.functionsDefaultRegion = utils.envOverride("FIREBASE_FUNCTIONS_DEFAULT_REGION", "us-central1");
|
|
39
|
+
exports.cloudbuildOrigin = utils.envOverride("FIREBASE_CLOUDBUILD_URL", "https://cloudbuild.googleapis.com");
|
|
39
40
|
exports.cloudschedulerOrigin = utils.envOverride("FIREBASE_CLOUDSCHEDULER_URL", "https://cloudscheduler.googleapis.com");
|
|
40
41
|
exports.cloudTasksOrigin = utils.envOverride("FIREBASE_CLOUD_TAKS_URL", "https://cloudtasks.googleapis.com");
|
|
41
42
|
exports.pubsubOrigin = utils.envOverride("FIREBASE_PUBSUB_URL", "https://pubsub.googleapis.com");
|
|
@@ -58,6 +59,7 @@ exports.firebaseStorageOrigin = utils.envOverride("FIREBASE_FIREBASESTORAGE_URL"
|
|
|
58
59
|
exports.hostingApiOrigin = utils.envOverride("FIREBASE_HOSTING_API_URL", "https://firebasehosting.googleapis.com");
|
|
59
60
|
exports.cloudRunApiOrigin = utils.envOverride("CLOUD_RUN_API_URL", "https://run.googleapis.com");
|
|
60
61
|
exports.serviceUsageOrigin = utils.envOverride("FIREBASE_SERVICE_USAGE_URL", "https://serviceusage.googleapis.com");
|
|
62
|
+
exports.frameworksOrigin = utils.envOverride("FRAMEWORKS_URL", "https://placeholder.googleapis.com");
|
|
61
63
|
exports.githubOrigin = utils.envOverride("GITHUB_URL", "https://github.com");
|
|
62
64
|
exports.githubApiOrigin = utils.envOverride("GITHUB_API_URL", "https://api.github.com");
|
|
63
65
|
exports.secretManagerOrigin = utils.envOverride("CLOUD_SECRET_MANAGER_URL", "https://secretmanager.googleapis.com");
|
package/lib/auth.js
CHANGED
|
@@ -307,7 +307,7 @@ async function loginRemotely() {
|
|
|
307
307
|
});
|
|
308
308
|
try {
|
|
309
309
|
const tokens = await getTokensFromAuthorizationCode(code, `${api_1.authProxyOrigin}/complete`, codeVerifier);
|
|
310
|
-
void (0, track_1.
|
|
310
|
+
void (0, track_1.trackGA4)("login", { method: "google_remote" });
|
|
311
311
|
return {
|
|
312
312
|
user: jwt.decode(tokens.id_token),
|
|
313
313
|
tokens: tokens,
|
|
@@ -323,7 +323,7 @@ async function loginWithLocalhostGoogle(port, userHint) {
|
|
|
323
323
|
const authUrl = getLoginUrl(callbackUrl, userHint);
|
|
324
324
|
const successTemplate = "../templates/loginSuccess.html";
|
|
325
325
|
const tokens = await loginWithLocalhost(port, callbackUrl, authUrl, successTemplate, getTokensFromAuthorizationCode);
|
|
326
|
-
void (0, track_1.
|
|
326
|
+
void (0, track_1.trackGA4)("login", { method: "google_localhost" });
|
|
327
327
|
return {
|
|
328
328
|
user: jwt.decode(tokens.id_token),
|
|
329
329
|
tokens: tokens,
|
|
@@ -335,7 +335,7 @@ async function loginWithLocalhostGitHub(port) {
|
|
|
335
335
|
const authUrl = getGithubLoginUrl(callbackUrl);
|
|
336
336
|
const successTemplate = "../templates/loginSuccessGithub.html";
|
|
337
337
|
const tokens = await loginWithLocalhost(port, callbackUrl, authUrl, successTemplate, getGithubTokensFromAuthorizationCode);
|
|
338
|
-
void (0, track_1.
|
|
338
|
+
void (0, track_1.trackGA4)("login", { method: "github_localhost" });
|
|
339
339
|
return tokens;
|
|
340
340
|
}
|
|
341
341
|
async function loginWithLocalhost(port, callbackUrl, authUrl, successTemplate, getTokens) {
|
package/lib/command.js
CHANGED
|
@@ -89,7 +89,12 @@ class Command {
|
|
|
89
89
|
}, null, 2));
|
|
90
90
|
}
|
|
91
91
|
const duration = Math.floor((process.uptime() - start) * 1000);
|
|
92
|
-
const trackSuccess = (0, track_1.
|
|
92
|
+
const trackSuccess = (0, track_1.trackGA4)("command_execution", {
|
|
93
|
+
command_name: this.name,
|
|
94
|
+
result: "success",
|
|
95
|
+
duration,
|
|
96
|
+
interactive: (0, utils_1.getInheritedOption)(options, "nonInteractive") ? "false" : "true",
|
|
97
|
+
});
|
|
93
98
|
if (!isEmulator) {
|
|
94
99
|
await (0, utils_1.withTimeout)(5000, trackSuccess);
|
|
95
100
|
}
|
|
@@ -113,8 +118,11 @@ class Command {
|
|
|
113
118
|
}
|
|
114
119
|
const duration = Math.floor((process.uptime() - start) * 1000);
|
|
115
120
|
await (0, utils_1.withTimeout)(5000, Promise.all([
|
|
116
|
-
(0, track_1.
|
|
117
|
-
|
|
121
|
+
(0, track_1.trackGA4)("command_execution", {
|
|
122
|
+
command_name: this.name,
|
|
123
|
+
result: "error",
|
|
124
|
+
interactive: (0, utils_1.getInheritedOption)(options, "nonInteractive") ? "false" : "true",
|
|
125
|
+
}, duration),
|
|
118
126
|
isEmulator
|
|
119
127
|
? (0, track_1.trackEmulator)("command_error", {
|
|
120
128
|
command_name: this.name,
|
|
@@ -223,7 +231,10 @@ function validateProjectId(project) {
|
|
|
223
231
|
if (PROJECT_ID_REGEX.test(project)) {
|
|
224
232
|
return;
|
|
225
233
|
}
|
|
226
|
-
(0, track_1.
|
|
234
|
+
(0, track_1.trackGA4)("error", {
|
|
235
|
+
error_type: "Error (User)",
|
|
236
|
+
details: "Invalid project ID",
|
|
237
|
+
});
|
|
227
238
|
const invalidMessage = "Invalid project id: " + clc.bold(project) + ".";
|
|
228
239
|
if (project.toLowerCase() !== project) {
|
|
229
240
|
throw new error_1.FirebaseError(invalidMessage + "\nNote: Project id must be all lowercase.");
|
|
@@ -35,7 +35,7 @@ exports.command = new command_1.Command("ext:install [extensionName]")
|
|
|
35
35
|
.before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
|
|
36
36
|
.before(extensionsHelper_1.diagnoseAndFixProject)
|
|
37
37
|
.action(async (extensionName, options) => {
|
|
38
|
-
var _a;
|
|
38
|
+
var _a, _b;
|
|
39
39
|
const projectId = (0, projectUtils_1.getProjectId)(options);
|
|
40
40
|
const paramsEnvPath = "";
|
|
41
41
|
let learnMore = false;
|
|
@@ -61,12 +61,18 @@ exports.command = new command_1.Command("ext:install [extensionName]")
|
|
|
61
61
|
if ((0, extensionsHelper_1.isLocalPath)(extensionName)) {
|
|
62
62
|
source = await (0, extensionsHelper_1.createSourceFromLocation)((0, projectUtils_1.needProjectId)({ projectId }), extensionName);
|
|
63
63
|
await (0, displayExtensionInfo_1.displayExtInfo)(extensionName, "", source.spec);
|
|
64
|
-
void (0, track_1.
|
|
64
|
+
void (0, track_1.trackGA4)("extension_added_to_manifest", {
|
|
65
|
+
published: "local",
|
|
66
|
+
interactive: options.nonInteractive ? "false" : "true",
|
|
67
|
+
});
|
|
65
68
|
}
|
|
66
69
|
else {
|
|
67
|
-
void (0, track_1.track)("Extension Install", "Install by Extension Ref", options.interactive ? 1 : 0);
|
|
68
70
|
extensionName = await (0, extensionsHelper_1.canonicalizeRefInput)(extensionName);
|
|
69
71
|
extensionVersion = await extensionsApi.getExtensionVersion(extensionName);
|
|
72
|
+
void (0, track_1.trackGA4)("extension_added_to_manifest", {
|
|
73
|
+
published: ((_a = extensionVersion.listing) === null || _a === void 0 ? void 0 : _a.state) === "APPROVED" ? "published" : "uploaded",
|
|
74
|
+
interactive: options.nonInteractive ? "false" : "true",
|
|
75
|
+
});
|
|
70
76
|
await infoExtensionVersion({
|
|
71
77
|
extensionName,
|
|
72
78
|
extensionVersion,
|
|
@@ -82,7 +88,7 @@ exports.command = new command_1.Command("ext:install [extensionName]")
|
|
|
82
88
|
if (!source && !extensionVersion) {
|
|
83
89
|
throw new error_1.FirebaseError("Could not find a source. Please specify a valid source to continue.");
|
|
84
90
|
}
|
|
85
|
-
const spec = (
|
|
91
|
+
const spec = (_b = source === null || source === void 0 ? void 0 : source.spec) !== null && _b !== void 0 ? _b : extensionVersion === null || extensionVersion === void 0 ? void 0 : extensionVersion.spec;
|
|
86
92
|
if (!spec) {
|
|
87
93
|
throw new error_1.FirebaseError(`Could not find the extension.yaml for extension '${clc.bold(extensionName)}'. Please make sure this is a valid extension and try again.`);
|
|
88
94
|
}
|
package/lib/commands/index.js
CHANGED
|
@@ -144,6 +144,8 @@ function load(client) {
|
|
|
144
144
|
client.internaltesting.frameworks.compose = loadCommand("internaltesting-frameworks-compose");
|
|
145
145
|
client.internaltesting.functions = {};
|
|
146
146
|
client.internaltesting.functions.discover = loadCommand("internaltesting-functions-discover");
|
|
147
|
+
client.internaltesting.frameworks = {};
|
|
148
|
+
client.internaltesting.frameworks.init = loadCommand("internaltesting-frameworks-init");
|
|
147
149
|
}
|
|
148
150
|
client.login = loadCommand("login");
|
|
149
151
|
client.login.add = loadCommand("login-add");
|
package/lib/commands/init.js
CHANGED
|
@@ -14,6 +14,7 @@ const prompt_1 = require("../prompt");
|
|
|
14
14
|
const requireAuth_1 = require("../requireAuth");
|
|
15
15
|
const fsutils = require("../fsutils");
|
|
16
16
|
const utils = require("../utils");
|
|
17
|
+
const experiments_1 = require("../experiments");
|
|
17
18
|
const homeDir = os.homedir();
|
|
18
19
|
const TEMPLATE_ROOT = path.resolve(__dirname, "../../templates/");
|
|
19
20
|
const BANNER_TEXT = fs.readFileSync(path.join(TEMPLATE_ROOT, "banner.txt"), "utf8");
|
|
@@ -68,6 +69,13 @@ const choices = [
|
|
|
68
69
|
checked: false,
|
|
69
70
|
},
|
|
70
71
|
];
|
|
72
|
+
if ((0, experiments_1.isEnabled)("frameworks")) {
|
|
73
|
+
choices.push({
|
|
74
|
+
value: "frameworks",
|
|
75
|
+
name: "Frameworks: Get started with Frameworks projects.",
|
|
76
|
+
checked: false,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
71
79
|
const featureNames = choices.map((choice) => choice.value);
|
|
72
80
|
const DESCRIPTION = `Interactively configure the current directory as a Firebase project or initialize new features in an already configured Firebase project directory.
|
|
73
81
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.command = void 0;
|
|
4
|
+
const command_1 = require("../command");
|
|
5
|
+
const repo_1 = require("../init/features/composer/repo");
|
|
6
|
+
const projectUtils_1 = require("../projectUtils");
|
|
7
|
+
const requireInteractive_1 = require("../requireInteractive");
|
|
8
|
+
exports.command = new command_1.Command("internaltesting:frameworks:init")
|
|
9
|
+
.description("connect github repo to cloud build")
|
|
10
|
+
.before(requireInteractive_1.default)
|
|
11
|
+
.action(async (options) => {
|
|
12
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
13
|
+
await (0, repo_1.linkGitHubRepository)(projectId, "us-central2", "stack0");
|
|
14
|
+
});
|
package/lib/config.js
CHANGED
|
@@ -18,6 +18,7 @@ const v2FunctionHelper_1 = require("./v2FunctionHelper");
|
|
|
18
18
|
const tos_1 = require("../../extensions/tos");
|
|
19
19
|
async function prepare(context, options, payload) {
|
|
20
20
|
var _a, _b;
|
|
21
|
+
context.extensionsStartTime = Date.now();
|
|
21
22
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
22
23
|
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
23
24
|
const aliases = (0, projectUtils_1.getAliases)(options, projectId);
|
|
@@ -8,8 +8,9 @@ const error_1 = require("../../error");
|
|
|
8
8
|
const errors_1 = require("./errors");
|
|
9
9
|
const projectUtils_1 = require("../../projectUtils");
|
|
10
10
|
const etags_1 = require("../../extensions/etags");
|
|
11
|
+
const track_1 = require("../../track");
|
|
11
12
|
async function release(context, options, payload) {
|
|
12
|
-
var _a, _b, _c, _d;
|
|
13
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
13
14
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
14
15
|
const errorHandler = new errors_1.ErrorHandler();
|
|
15
16
|
const deploymentQueue = new queue_1.default({
|
|
@@ -37,6 +38,15 @@ async function release(context, options, payload) {
|
|
|
37
38
|
deploymentQueue.process();
|
|
38
39
|
deploymentQueue.close();
|
|
39
40
|
await deploymentPromise;
|
|
41
|
+
const duration = context.extensionsStartTime ? Date.now() - context.extensionsStartTime : 1;
|
|
42
|
+
await (0, track_1.trackGA4)("extensions_deploy", {
|
|
43
|
+
extension_instance_created: (_f = (_e = payload.instancesToCreate) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0,
|
|
44
|
+
extension_instance_updated: (_h = (_g = payload.instancesToUpdate) === null || _g === void 0 ? void 0 : _g.length) !== null && _h !== void 0 ? _h : 0,
|
|
45
|
+
extension_instance_configured: (_k = (_j = payload.instancesToConfigure) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : 0,
|
|
46
|
+
extension_instance_deleted: (_m = (_l = payload.instancesToDelete) === null || _l === void 0 ? void 0 : _l.length) !== null && _m !== void 0 ? _m : 0,
|
|
47
|
+
errors: (_o = errorHandler.errors.length) !== null && _o !== void 0 ? _o : 0,
|
|
48
|
+
interactive: options.nonInteractive ? "false" : "true",
|
|
49
|
+
}, duration);
|
|
40
50
|
const newHave = await planner.have(projectId);
|
|
41
51
|
(0, etags_1.saveEtags)(options.rc, projectId, newHave);
|
|
42
52
|
if (errorHandler.hasErrors()) {
|
|
@@ -59,7 +59,10 @@ async function checkHttpIam(context, options, payload) {
|
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
if (!passed) {
|
|
62
|
-
void (0, track_1.
|
|
62
|
+
void (0, track_1.trackGA4)("error", {
|
|
63
|
+
error_type: "Error (User)",
|
|
64
|
+
details: "deploy:functions:http_create_missing_iam",
|
|
65
|
+
});
|
|
63
66
|
throw new error_1.FirebaseError(`Missing required permission on project ${(0, colorette_1.bold)(context.projectId)} to deploy new HTTPS functions. The permission ${(0, colorette_1.bold)(PERMISSION)} is required to deploy the following functions:\n\n- ` +
|
|
64
67
|
newHttpsEndpoints.map((func) => func.id).join("\n- ") +
|
|
65
68
|
`\n\nTo address this error, please ask a project Owner to assign your account the "Cloud Functions Admin" role at the following URL:\n\nhttps://console.cloud.google.com/iam-admin/iam?project=${context.projectId}`);
|
|
@@ -301,7 +301,8 @@ async function loadCodebases(config, options, firebaseConfig, runtimeConfig, fil
|
|
|
301
301
|
logger_1.logger.debug(`Building ${runtimeDelegate.name} source`);
|
|
302
302
|
await runtimeDelegate.build();
|
|
303
303
|
const firebaseEnvs = functionsEnv.loadFirebaseEnvs(firebaseConfig, projectId);
|
|
304
|
-
|
|
304
|
+
(0, utils_1.logLabeledBullet)("functions", `Loading and anaylzing source code for codebase ${codebase} to determine what to deploy`);
|
|
305
|
+
wantBuilds[codebase] = await runtimeDelegate.discoverBuild(runtimeConfig, Object.assign(Object.assign({}, firebaseEnvs), { GOOGLE_CLOUD_QUOTA_PROJECT: projectId }));
|
|
305
306
|
}
|
|
306
307
|
return wantBuilds;
|
|
307
308
|
}
|
|
@@ -64,6 +64,12 @@ async function detectFromPort(port, project, runtime, timeout = 10000) {
|
|
|
64
64
|
throw err;
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
+
if (res.status !== 200) {
|
|
68
|
+
const text = await res.text();
|
|
69
|
+
logger_1.logger.debug(`Got response code ${res.status}; body ${text}`);
|
|
70
|
+
throw new error_1.FirebaseError("Functions codebase could not be analyzed successfully. " +
|
|
71
|
+
"It may have a syntax or runtime error");
|
|
72
|
+
}
|
|
67
73
|
const text = await res.text();
|
|
68
74
|
logger_1.logger.debug("Got response from /__/functions.yaml", text);
|
|
69
75
|
let parsed;
|
|
@@ -92,7 +92,7 @@ class Delegate {
|
|
|
92
92
|
return Promise.resolve(() => Promise.resolve());
|
|
93
93
|
}
|
|
94
94
|
serveAdmin(port, config, envs) {
|
|
95
|
-
var _a;
|
|
95
|
+
var _a, _b;
|
|
96
96
|
const env = Object.assign(Object.assign({}, envs), { PORT: port, FUNCTIONS_CONTROL_API: "true", HOME: process.env.HOME, PATH: process.env.PATH, NODE_ENV: process.env.NODE_ENV, __FIREBASE_FRAMEWORKS_ENTRY__: process.env.__FIREBASE_FRAMEWORKS_ENTRY__ });
|
|
97
97
|
if (Object.keys(config || {}).length) {
|
|
98
98
|
env.CLOUD_RUNTIME_CONFIG = JSON.stringify(config);
|
|
@@ -114,17 +114,25 @@ class Delegate {
|
|
|
114
114
|
const childProcess = spawn(binPath, [this.sourceDir], {
|
|
115
115
|
env,
|
|
116
116
|
cwd: this.sourceDir,
|
|
117
|
-
stdio: ["ignore", "pipe", "
|
|
117
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
118
118
|
});
|
|
119
119
|
(_a = childProcess.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (chunk) => {
|
|
120
|
-
logger_1.logger.
|
|
120
|
+
logger_1.logger.info(chunk.toString("utf8"));
|
|
121
|
+
});
|
|
122
|
+
(_b = childProcess.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (chunk) => {
|
|
123
|
+
logger_1.logger.error(chunk.toString("utf8"));
|
|
121
124
|
});
|
|
122
125
|
return Promise.resolve(async () => {
|
|
123
126
|
const p = new Promise((resolve, reject) => {
|
|
124
127
|
childProcess.once("exit", resolve);
|
|
125
128
|
childProcess.once("error", reject);
|
|
126
129
|
});
|
|
127
|
-
|
|
130
|
+
try {
|
|
131
|
+
await (0, node_fetch_1.default)(`http://localhost:${port}/__/quitquitquit`);
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
logger_1.logger.debug("Failed to call quitquitquit. This often means the server failed to start", e);
|
|
135
|
+
}
|
|
128
136
|
setTimeout(() => {
|
|
129
137
|
if (!childProcess.killed) {
|
|
130
138
|
childProcess.kill("SIGKILL");
|
|
@@ -11,7 +11,6 @@ const discovery = require("../discovery");
|
|
|
11
11
|
const logger_1 = require("../../../../logger");
|
|
12
12
|
const python_1 = require("../../../../functions/python");
|
|
13
13
|
const error_1 = require("../../../../error");
|
|
14
|
-
const utils_1 = require("../../../../utils");
|
|
15
14
|
exports.LATEST_VERSION = "python311";
|
|
16
15
|
async function tryCreateDelegate(context) {
|
|
17
16
|
const requirementsTextPath = path.join(context.sourceDir, "requirements.txt");
|
|
@@ -108,32 +107,31 @@ class Delegate {
|
|
|
108
107
|
const modulesDir = await this.modulesDir();
|
|
109
108
|
const envWithAdminPort = Object.assign(Object.assign({}, envs), { ADMIN_PORT: port.toString() });
|
|
110
109
|
const args = [this.bin, `"${path.join(modulesDir, "private", "serving.py")}"`];
|
|
111
|
-
const stdout = [];
|
|
112
|
-
const stderr = [];
|
|
113
110
|
logger_1.logger.debug(`Running admin server with args: ${JSON.stringify(args)} and env: ${JSON.stringify(envWithAdminPort)} in ${this.sourceDir}`);
|
|
114
111
|
const childProcess = (0, python_1.runWithVirtualEnv)(args, this.sourceDir, envWithAdminPort);
|
|
115
112
|
(_a = childProcess.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (chunk) => {
|
|
116
|
-
|
|
117
|
-
stdout.push(chunkString);
|
|
118
|
-
logger_1.logger.debug(`stdout: ${chunkString}`);
|
|
113
|
+
logger_1.logger.info(chunk.toString("utf8"));
|
|
119
114
|
});
|
|
120
115
|
(_b = childProcess.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (chunk) => {
|
|
121
|
-
|
|
122
|
-
stderr.push(chunkString);
|
|
123
|
-
logger_1.logger.debug(`stderr: ${chunkString}`);
|
|
116
|
+
logger_1.logger.error(chunk.toString("utf8"));
|
|
124
117
|
});
|
|
125
|
-
return Promise.resolve({
|
|
126
|
-
|
|
127
|
-
stdout,
|
|
128
|
-
killProcess: async () => {
|
|
118
|
+
return Promise.resolve(async () => {
|
|
119
|
+
try {
|
|
129
120
|
await (0, node_fetch_1.default)(`http://127.0.0.1:${port}/__/quitquitquit`);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
logger_1.logger.debug("Failed to call quitquitquit. This often means the server failed to start", e);
|
|
124
|
+
}
|
|
125
|
+
const quitTimeout = setTimeout(() => {
|
|
126
|
+
if (!childProcess.killed) {
|
|
127
|
+
childProcess.kill("SIGKILL");
|
|
128
|
+
}
|
|
129
|
+
}, 10000);
|
|
130
|
+
clearTimeout(quitTimeout);
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
childProcess.once("exit", resolve);
|
|
133
|
+
childProcess.once("error", reject);
|
|
134
|
+
});
|
|
137
135
|
});
|
|
138
136
|
}
|
|
139
137
|
async discoverBuild(_configValues, envs) {
|
|
@@ -142,14 +140,10 @@ class Delegate {
|
|
|
142
140
|
const adminPort = await portfinder.getPortPromise({
|
|
143
141
|
port: 8081,
|
|
144
142
|
});
|
|
145
|
-
const
|
|
143
|
+
const killProcess = await this.serveAdmin(adminPort, envs);
|
|
146
144
|
try {
|
|
147
145
|
discovered = await discovery.detectFromPort(adminPort, this.projectId, this.runtime);
|
|
148
146
|
}
|
|
149
|
-
catch (e) {
|
|
150
|
-
(0, utils_1.logLabeledWarning)("functions", `Failed to detect functions from source ${e}.\nstderr:${stderr.join("\n")}`);
|
|
151
|
-
throw e;
|
|
152
|
-
}
|
|
153
147
|
finally {
|
|
154
148
|
await killProcess();
|
|
155
149
|
}
|
|
@@ -5,7 +5,6 @@ const uploader_1 = require("./uploader");
|
|
|
5
5
|
const detectProjectRoot_1 = require("../../detectProjectRoot");
|
|
6
6
|
const listFiles_1 = require("../../listFiles");
|
|
7
7
|
const logger_1 = require("../../logger");
|
|
8
|
-
const track_1 = require("../../track");
|
|
9
8
|
const utils_1 = require("../../utils");
|
|
10
9
|
const colorette_1 = require("colorette");
|
|
11
10
|
const ora = require("ora");
|
|
@@ -67,10 +66,6 @@ async function deploy(context, options) {
|
|
|
67
66
|
try {
|
|
68
67
|
await uploader.start();
|
|
69
68
|
}
|
|
70
|
-
catch (err) {
|
|
71
|
-
void (0, track_1.track)("Hosting Deploy", "failure");
|
|
72
|
-
throw err;
|
|
73
|
-
}
|
|
74
69
|
finally {
|
|
75
70
|
clearInterval(progressInterval);
|
|
76
71
|
updateSpinner(uploader.statusMessage(), debugging);
|
|
@@ -81,7 +76,6 @@ async function deploy(context, options) {
|
|
|
81
76
|
(0, utils_1.logLabeledSuccess)(`hosting[${deploy.config.site}]`, "file upload complete");
|
|
82
77
|
const dt = Date.now() - t0;
|
|
83
78
|
logger_1.logger.debug(`[hosting] deploy completed after ${dt}ms`);
|
|
84
|
-
void (0, track_1.track)("Hosting Deploy", "success", dt);
|
|
85
79
|
return runDeploys(deploys, debugging);
|
|
86
80
|
}
|
|
87
81
|
const debugging = !!(options.debug || options.nonInteractive);
|
|
@@ -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
|
}
|
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,
|