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
|
@@ -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;
|
|
@@ -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
|
}
|
package/lib/frameworks/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.prepareFrameworks = exports.discover = exports.WebFrameworks = void 0;
|
|
3
|
+
exports.prepareFrameworks = exports.generateSSRCodebaseId = exports.discover = exports.WebFrameworks = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
const process_1 = require("process");
|
|
6
6
|
const child_process_1 = require("child_process");
|
|
@@ -25,21 +25,22 @@ const experiments = require("../experiments");
|
|
|
25
25
|
const implicitInit_1 = require("../hosting/implicitInit");
|
|
26
26
|
const utils_1 = require("./utils");
|
|
27
27
|
const constants_2 = require("./constants");
|
|
28
|
-
Object.defineProperty(exports, "WebFrameworks", { enumerable: true, get: function () { return constants_2.WebFrameworks; } });
|
|
29
28
|
const utils_2 = require("../utils");
|
|
30
29
|
const ensureTargeted_1 = require("../functions/ensureTargeted");
|
|
31
30
|
const util_1 = require("util");
|
|
32
31
|
const projectPath_1 = require("../projectPath");
|
|
33
32
|
const logger_1 = require("../logger");
|
|
33
|
+
const frameworks_1 = require("./frameworks");
|
|
34
|
+
Object.defineProperty(exports, "WebFrameworks", { enumerable: true, get: function () { return frameworks_1.WebFrameworks; } });
|
|
34
35
|
async function discover(dir, warn = true) {
|
|
35
36
|
const allFrameworkTypes = [
|
|
36
|
-
...new Set(Object.values(
|
|
37
|
+
...new Set(Object.values(frameworks_1.WebFrameworks).map(({ type }) => type)),
|
|
37
38
|
].sort();
|
|
38
39
|
for (const discoveryType of allFrameworkTypes) {
|
|
39
40
|
const frameworksDiscovered = [];
|
|
40
|
-
for (const framework in
|
|
41
|
-
if (
|
|
42
|
-
const { discover, type } =
|
|
41
|
+
for (const framework in frameworks_1.WebFrameworks) {
|
|
42
|
+
if (frameworks_1.WebFrameworks[framework]) {
|
|
43
|
+
const { discover, type } = frameworks_1.WebFrameworks[framework];
|
|
43
44
|
if (type !== discoveryType)
|
|
44
45
|
continue;
|
|
45
46
|
const result = await discover(dir);
|
|
@@ -72,6 +73,10 @@ function memoizeBuild(dir, build, deps, target) {
|
|
|
72
73
|
BUILD_MEMO.set(key, value);
|
|
73
74
|
return value;
|
|
74
75
|
}
|
|
76
|
+
function generateSSRCodebaseId(site) {
|
|
77
|
+
return `firebase-frameworks-${site}`;
|
|
78
|
+
}
|
|
79
|
+
exports.generateSSRCodebaseId = generateSSRCodebaseId;
|
|
75
80
|
async function prepareFrameworks(purpose, targetNames, context, options, emulators = []) {
|
|
76
81
|
var _a, _b, _c, _d, _e, _f;
|
|
77
82
|
var _g, _h, _j, _k, _l;
|
|
@@ -185,7 +190,7 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
|
|
|
185
190
|
throw new error_1.FirebaseError((0, utils_1.frameworksCallToAction)("Unable to detect the web framework in use, check firebase-debug.log for more info."));
|
|
186
191
|
}
|
|
187
192
|
const { framework, mayWantBackend, publicDirectory } = results;
|
|
188
|
-
const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, docsUrl, getValidBuildTargets = constants_2.GET_DEFAULT_BUILD_TARGETS, shouldUseDevModeHandle = constants_2.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, } =
|
|
193
|
+
const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, docsUrl, getValidBuildTargets = constants_2.GET_DEFAULT_BUILD_TARGETS, shouldUseDevModeHandle = constants_2.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, } = frameworks_1.WebFrameworks[framework];
|
|
189
194
|
logger_1.logger.info(`\n${(0, utils_1.frameworksCallToAction)(constants_2.SupportLevelWarnings[support](name), docsUrl, " ")}\n`);
|
|
190
195
|
const hostingEmulatorInfo = emulators.find((e) => e.name === types_1.Emulators.HOSTING);
|
|
191
196
|
const validBuildTargets = await getValidBuildTargets(purpose, getProjectPath());
|
|
@@ -242,7 +247,7 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
|
|
|
242
247
|
if (context === null || context === void 0 ? void 0 : context.hostingChannel) {
|
|
243
248
|
experiments.assertEnabled("pintags", "deploy an app that requires a backend to a preview channel");
|
|
244
249
|
}
|
|
245
|
-
const codebase =
|
|
250
|
+
const codebase = generateSSRCodebaseId(site);
|
|
246
251
|
const existingFunctionsConfig = options.config.get("functions")
|
|
247
252
|
? [].concat(options.config.get("functions"))
|
|
248
253
|
: [];
|
package/lib/frameworks/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getFrameworksBuildTarget = exports.validateLocales = exports.frameworksCallToAction = exports.conjoinOptions = exports.relativeRequire = exports.findDependency = exports.getNodeModuleBin = exports.getNpmRoot = exports.simpleProxy = exports.warnIfCustomBuildScript = exports.readJSON = exports.isUrl = void 0;
|
|
3
|
+
exports.getFrameworksBuildTarget = exports.validateLocales = exports.frameworksCallToAction = exports.conjoinOptions = exports.relativeRequire = exports.findDependency = exports.getNodeModuleBin = exports.getNpmRoot = exports.simpleProxy = exports.proxyResponse = exports.warnIfCustomBuildScript = exports.readJSON = exports.isUrl = void 0;
|
|
4
4
|
const fs_extra_1 = require("fs-extra");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
const promises_1 = require("fs/promises");
|
|
@@ -32,21 +32,51 @@ async function warnIfCustomBuildScript(dir, framework, defaultBuildScripts) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
exports.warnIfCustomBuildScript = warnIfCustomBuildScript;
|
|
35
|
-
function proxyResponse(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
function proxyResponse(req, res, next) {
|
|
36
|
+
const proxiedRes = new http_1.ServerResponse(req);
|
|
37
|
+
const buffer = [];
|
|
38
|
+
proxiedRes.write = new Proxy(proxiedRes.write.bind(proxiedRes), {
|
|
39
|
+
apply: (target, thisArg, args) => {
|
|
40
|
+
target.call(thisArg, ...args);
|
|
41
|
+
buffer.push(["write", args]);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
proxiedRes.setHeader = new Proxy(proxiedRes.setHeader.bind(proxiedRes), {
|
|
45
|
+
apply: (target, thisArg, args) => {
|
|
46
|
+
target.call(thisArg, ...args);
|
|
47
|
+
buffer.push(["setHeader", args]);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
proxiedRes.removeHeader = new Proxy(proxiedRes.removeHeader.bind(proxiedRes), {
|
|
51
|
+
apply: (target, thisArg, args) => {
|
|
52
|
+
target.call(thisArg, ...args);
|
|
53
|
+
buffer.push(["removeHeader", args]);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
proxiedRes.writeHead = new Proxy(proxiedRes.writeHead.bind(proxiedRes), {
|
|
57
|
+
apply: (target, thisArg, args) => {
|
|
58
|
+
target.call(thisArg, ...args);
|
|
59
|
+
buffer.push(["writeHead", args]);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
proxiedRes.end = new Proxy(proxiedRes.end.bind(proxiedRes), {
|
|
63
|
+
apply: (target, thisArg, args) => {
|
|
64
|
+
target.call(thisArg, ...args);
|
|
65
|
+
if (proxiedRes.statusCode === 404) {
|
|
66
|
+
next();
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
for (const [fn, args] of buffer) {
|
|
70
|
+
res[fn](...args);
|
|
71
|
+
}
|
|
72
|
+
res.end(...args);
|
|
73
|
+
buffer.length = 0;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
return proxiedRes;
|
|
49
78
|
}
|
|
79
|
+
exports.proxyResponse = proxyResponse;
|
|
50
80
|
function simpleProxy(hostOrRequestHandler) {
|
|
51
81
|
const agent = new http_1.Agent({ keepAlive: true });
|
|
52
82
|
const firebaseDefaultsJSON = process.env.__FIREBASE_DEFAULTS__;
|
|
@@ -91,9 +121,8 @@ function simpleProxy(hostOrRequestHandler) {
|
|
|
91
121
|
});
|
|
92
122
|
}
|
|
93
123
|
else {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
proxyResponse(originalRes, next)(proxiedRes);
|
|
124
|
+
const proxiedRes = proxyResponse(originalReq, originalRes, next);
|
|
125
|
+
await hostOrRequestHandler(originalReq, proxiedRes, next);
|
|
97
126
|
}
|
|
98
127
|
};
|
|
99
128
|
}
|
|
@@ -153,12 +182,13 @@ function findDependency(name, options = {}) {
|
|
|
153
182
|
exports.findDependency = findDependency;
|
|
154
183
|
function relativeRequire(dir, mod) {
|
|
155
184
|
try {
|
|
156
|
-
const
|
|
185
|
+
const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
|
|
186
|
+
const path = requireFunc.resolve(mod, { paths: [dir] });
|
|
157
187
|
if ((0, path_1.extname)(path) === ".mjs") {
|
|
158
188
|
return dynamicImport((0, url_1.pathToFileURL)(path).toString());
|
|
159
189
|
}
|
|
160
190
|
else {
|
|
161
|
-
return
|
|
191
|
+
return requireFunc(path);
|
|
162
192
|
}
|
|
163
193
|
}
|
|
164
194
|
catch (e) {
|
package/lib/functionsConfig.js
CHANGED
|
@@ -82,7 +82,7 @@ exports.setVariablesRecursive = setVariablesRecursive;
|
|
|
82
82
|
async function materializeConfig(configName, output) {
|
|
83
83
|
const materializeVariable = async function (varName) {
|
|
84
84
|
const variable = await runtimeconfig.variables.get(varName);
|
|
85
|
-
const id =
|
|
85
|
+
const id = varNameToIds(variable.name);
|
|
86
86
|
const key = id.config + "." + id.variable.split("/").join(".");
|
|
87
87
|
_.set(output, key, variable.text);
|
|
88
88
|
};
|
|
@@ -106,7 +106,7 @@ async function materializeAll(projectId) {
|
|
|
106
106
|
if (config.name.match(new RegExp("configs/firebase"))) {
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
109
|
-
return
|
|
109
|
+
return materializeConfig(config.name, output);
|
|
110
110
|
}));
|
|
111
111
|
return output;
|
|
112
112
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deleteRepository = exports.getRepository = exports.createRepository = exports.fetchLinkableRepositories = exports.deleteConnection = exports.getConnection = exports.createConnection = void 0;
|
|
4
|
+
const apiv2_1 = require("../apiv2");
|
|
5
|
+
const api_1 = require("../api");
|
|
6
|
+
const client = new apiv2_1.Client({
|
|
7
|
+
urlPrefix: api_1.cloudbuildOrigin,
|
|
8
|
+
auth: true,
|
|
9
|
+
apiVersion: "v2",
|
|
10
|
+
});
|
|
11
|
+
async function createConnection(projectId, location, connectionId) {
|
|
12
|
+
const res = await client.post(`projects/${projectId}/locations/${location}/connections`, { githubConfig: {} }, { queryParams: { connectionId } });
|
|
13
|
+
return res.body;
|
|
14
|
+
}
|
|
15
|
+
exports.createConnection = createConnection;
|
|
16
|
+
async function getConnection(projectId, location, connectionId) {
|
|
17
|
+
const name = `projects/${projectId}/locations/${location}/connections/${connectionId}`;
|
|
18
|
+
const res = await client.get(name);
|
|
19
|
+
return res.body;
|
|
20
|
+
}
|
|
21
|
+
exports.getConnection = getConnection;
|
|
22
|
+
async function deleteConnection(projectId, location, connectionId) {
|
|
23
|
+
const name = `projects/${projectId}/locations/${location}/connections/${connectionId}`;
|
|
24
|
+
const res = await client.delete(name);
|
|
25
|
+
return res.body;
|
|
26
|
+
}
|
|
27
|
+
exports.deleteConnection = deleteConnection;
|
|
28
|
+
async function fetchLinkableRepositories(projectId, location, connectionId) {
|
|
29
|
+
const name = `projects/${projectId}/locations/${location}/connections/${connectionId}:fetchLinkableRepositories`;
|
|
30
|
+
const res = await client.get(name);
|
|
31
|
+
return res.body;
|
|
32
|
+
}
|
|
33
|
+
exports.fetchLinkableRepositories = fetchLinkableRepositories;
|
|
34
|
+
async function createRepository(projectId, location, connectionId, repositoryId, remoteUri) {
|
|
35
|
+
const res = await client.post(`projects/${projectId}/locations/${location}/connections/${connectionId}/repositories`, { remoteUri }, { queryParams: { repositoryId } });
|
|
36
|
+
return res.body;
|
|
37
|
+
}
|
|
38
|
+
exports.createRepository = createRepository;
|
|
39
|
+
async function getRepository(projectId, location, connectionId, repositoryId) {
|
|
40
|
+
const name = `projects/${projectId}/locations/${location}/connections/${connectionId}/repositories/${repositoryId}`;
|
|
41
|
+
const res = await client.get(name);
|
|
42
|
+
return res.body;
|
|
43
|
+
}
|
|
44
|
+
exports.getRepository = getRepository;
|
|
45
|
+
async function deleteRepository(projectId, location, connectionId, repositoryId) {
|
|
46
|
+
const name = `projects/${projectId}/locations/${location}/connections/${connectionId}/repositories/${repositoryId}`;
|
|
47
|
+
const res = await client.delete(name);
|
|
48
|
+
return res.body;
|
|
49
|
+
}
|
|
50
|
+
exports.deleteRepository = deleteRepository;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getOrCreateRepository = exports.getOrCreateConnection = exports.linkGitHubRepository = void 0;
|
|
4
|
+
const api_1 = require("../../../api");
|
|
5
|
+
const error_1 = require("../../../error");
|
|
6
|
+
const gcb = require("../../../gcp/cloudbuild");
|
|
7
|
+
const logger_1 = require("../../../logger");
|
|
8
|
+
const poller = require("../../../operation-poller");
|
|
9
|
+
const utils = require("../../../utils");
|
|
10
|
+
const prompt_1 = require("../../../prompt");
|
|
11
|
+
const gcbPollerOptions = {
|
|
12
|
+
apiOrigin: api_1.cloudbuildOrigin,
|
|
13
|
+
apiVersion: "v2",
|
|
14
|
+
masterTimeout: 25 * 60 * 1000,
|
|
15
|
+
maxBackoff: 10000,
|
|
16
|
+
};
|
|
17
|
+
function extractRepoSlugFromURI(remoteUri) {
|
|
18
|
+
const match = /github.com\/(.+).git/.exec(remoteUri);
|
|
19
|
+
if (!match) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
return match[1];
|
|
23
|
+
}
|
|
24
|
+
function generateConnectionId(stackId) {
|
|
25
|
+
return `composer-${stackId}-conn`;
|
|
26
|
+
}
|
|
27
|
+
function generateRepositoryId() {
|
|
28
|
+
return `composer-repo`;
|
|
29
|
+
}
|
|
30
|
+
async function linkGitHubRepository(projectId, location, stackId) {
|
|
31
|
+
const connectionId = generateConnectionId(stackId);
|
|
32
|
+
await getOrCreateConnection(projectId, location, connectionId);
|
|
33
|
+
let remoteUri = await promptRepositoryURI(projectId, location, connectionId);
|
|
34
|
+
while (remoteUri === "") {
|
|
35
|
+
await utils.openInBrowser("https://github.com/apps/google-cloud-build/installations/new");
|
|
36
|
+
await (0, prompt_1.promptOnce)({
|
|
37
|
+
type: "input",
|
|
38
|
+
message: "Press any key once you have finished configuring your installation's access settings.",
|
|
39
|
+
});
|
|
40
|
+
remoteUri = await promptRepositoryURI(projectId, location, connectionId);
|
|
41
|
+
}
|
|
42
|
+
const repo = await getOrCreateRepository(projectId, location, connectionId, remoteUri);
|
|
43
|
+
logger_1.logger.info(`Successfully linked GitHub repository at remote URI ${remoteUri}.`);
|
|
44
|
+
return repo;
|
|
45
|
+
}
|
|
46
|
+
exports.linkGitHubRepository = linkGitHubRepository;
|
|
47
|
+
async function promptRepositoryURI(projectId, location, connectionId) {
|
|
48
|
+
const resp = await gcb.fetchLinkableRepositories(projectId, location, connectionId);
|
|
49
|
+
if (!resp.repositories || resp.repositories.length === 0) {
|
|
50
|
+
throw new error_1.FirebaseError("The GitHub App does not have access to any repositories. Please configure " +
|
|
51
|
+
"your app installation permissions at https://github.com/settings/installations.");
|
|
52
|
+
}
|
|
53
|
+
const choices = resp.repositories.map((repo) => ({
|
|
54
|
+
name: extractRepoSlugFromURI(repo.remoteUri) || repo.remoteUri,
|
|
55
|
+
value: repo.remoteUri,
|
|
56
|
+
}));
|
|
57
|
+
choices.push({
|
|
58
|
+
name: "Missing a repo? Select this option to configure your installation's access settings",
|
|
59
|
+
value: "",
|
|
60
|
+
});
|
|
61
|
+
return await (0, prompt_1.promptOnce)({
|
|
62
|
+
type: "list",
|
|
63
|
+
message: "Which of the following repositories would you like to link?",
|
|
64
|
+
choices,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async function promptConnectionAuth(conn, projectId, location, connectionId) {
|
|
68
|
+
logger_1.logger.info(conn.installationState.message);
|
|
69
|
+
logger_1.logger.info(conn.installationState.actionUri);
|
|
70
|
+
await utils.openInBrowser(conn.installationState.actionUri);
|
|
71
|
+
await (0, prompt_1.promptOnce)({
|
|
72
|
+
type: "input",
|
|
73
|
+
message: "Press any key once you have authorized the app (Cloud Build) to access your GitHub repo.",
|
|
74
|
+
});
|
|
75
|
+
return await gcb.getConnection(projectId, location, connectionId);
|
|
76
|
+
}
|
|
77
|
+
async function getOrCreateConnection(projectId, location, connectionId) {
|
|
78
|
+
let conn;
|
|
79
|
+
try {
|
|
80
|
+
conn = await gcb.getConnection(projectId, location, connectionId);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
if (err.status === 404) {
|
|
84
|
+
const op = await gcb.createConnection(projectId, location, connectionId);
|
|
85
|
+
conn = await poller.pollOperation(Object.assign(Object.assign({}, gcbPollerOptions), { pollerName: `create-${location}-${connectionId}`, operationResourceName: op.name }));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
while (conn.installationState.stage !== "COMPLETE") {
|
|
92
|
+
conn = await promptConnectionAuth(conn, projectId, location, connectionId);
|
|
93
|
+
}
|
|
94
|
+
return conn;
|
|
95
|
+
}
|
|
96
|
+
exports.getOrCreateConnection = getOrCreateConnection;
|
|
97
|
+
async function getOrCreateRepository(projectId, location, connectionId, remoteUri) {
|
|
98
|
+
const repositoryId = generateRepositoryId();
|
|
99
|
+
if (!repositoryId) {
|
|
100
|
+
throw new error_1.FirebaseError(`Failed to generate repositoryId for URI "${remoteUri}".`);
|
|
101
|
+
}
|
|
102
|
+
let repo;
|
|
103
|
+
try {
|
|
104
|
+
repo = await gcb.getRepository(projectId, location, connectionId, repositoryId);
|
|
105
|
+
const repoSlug = extractRepoSlugFromURI(repo.remoteUri);
|
|
106
|
+
if (repoSlug) {
|
|
107
|
+
throw new error_1.FirebaseError(`${repoSlug} has already been linked.`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (err.status === 404) {
|
|
112
|
+
const op = await gcb.createRepository(projectId, location, connectionId, repositoryId, remoteUri);
|
|
113
|
+
repo = await poller.pollOperation(Object.assign(Object.assign({}, gcbPollerOptions), { pollerName: `create-${location}-${connectionId}-${repositoryId}`, operationResourceName: op.name }));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return repo;
|
|
120
|
+
}
|
|
121
|
+
exports.getOrCreateRepository = getOrCreateRepository;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ALLOWED_DEPLOY_METHODS = exports.DEFAULT_DEPLOY_METHOD = exports.ALLOWED_REGIONS = exports.DEFAULT_REGION = void 0;
|
|
4
|
+
exports.DEFAULT_REGION = "us-central1";
|
|
5
|
+
exports.ALLOWED_REGIONS = [{ name: "us-central1 (Iowa)", value: "us-central1" }];
|
|
6
|
+
exports.DEFAULT_DEPLOY_METHOD = "github";
|
|
7
|
+
exports.ALLOWED_DEPLOY_METHODS = [{ name: "Deploy using github", value: "github" }];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.doSetup = void 0;
|
|
4
|
+
const clc = require("colorette");
|
|
5
|
+
const utils = require("../../../utils");
|
|
6
|
+
const logger_1 = require("../../../logger");
|
|
7
|
+
const prompt_1 = require("../../../prompt");
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
async function doSetup(setup) {
|
|
10
|
+
setup.frameworks = {};
|
|
11
|
+
utils.logBullet("First we need a few details to create your service.");
|
|
12
|
+
await (0, prompt_1.promptOnce)({
|
|
13
|
+
name: "serviceName",
|
|
14
|
+
type: "input",
|
|
15
|
+
default: "acme-inc-web",
|
|
16
|
+
message: "Create a name for your service [6-32 characters]",
|
|
17
|
+
}, setup.frameworks);
|
|
18
|
+
await (0, prompt_1.promptOnce)({
|
|
19
|
+
name: "region",
|
|
20
|
+
type: "list",
|
|
21
|
+
default: constants_1.DEFAULT_REGION,
|
|
22
|
+
message: "Please select a region " +
|
|
23
|
+
`(${clc.yellow("info")}: Your region determines where your backend is located):\n`,
|
|
24
|
+
choices: constants_1.ALLOWED_REGIONS,
|
|
25
|
+
}, setup.frameworks);
|
|
26
|
+
utils.logSuccess(`Region set to ${setup.frameworks.region}.`);
|
|
27
|
+
logger_1.logger.info(clc.bold(`\n${clc.white("===")} Deploy Setup`));
|
|
28
|
+
await (0, prompt_1.promptOnce)({
|
|
29
|
+
name: "deployMethod",
|
|
30
|
+
type: "list",
|
|
31
|
+
default: constants_1.DEFAULT_DEPLOY_METHOD,
|
|
32
|
+
message: "How do you want to deploy",
|
|
33
|
+
choices: constants_1.ALLOWED_DEPLOY_METHODS,
|
|
34
|
+
}, setup.frameworks);
|
|
35
|
+
}
|
|
36
|
+
exports.doSetup = doSetup;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storage = exports.hosting = exports.functions = exports.firestore = exports.database = exports.account = void 0;
|
|
3
|
+
exports.frameworks = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storage = exports.hosting = exports.functions = exports.firestore = exports.database = exports.account = void 0;
|
|
4
4
|
var account_1 = require("./account");
|
|
5
5
|
Object.defineProperty(exports, "account", { enumerable: true, get: function () { return account_1.doSetup; } });
|
|
6
6
|
var database_1 = require("./database");
|
|
@@ -23,3 +23,5 @@ var remoteconfig_1 = require("./remoteconfig");
|
|
|
23
23
|
Object.defineProperty(exports, "remoteconfig", { enumerable: true, get: function () { return remoteconfig_1.doSetup; } });
|
|
24
24
|
var github_1 = require("./hosting/github");
|
|
25
25
|
Object.defineProperty(exports, "hostingGithub", { enumerable: true, get: function () { return github_1.initGitHub; } });
|
|
26
|
+
var frameworks_1 = require("./frameworks");
|
|
27
|
+
Object.defineProperty(exports, "frameworks", { enumerable: true, get: function () { return frameworks_1.doSetup; } });
|