firebase-tools 12.4.6 → 12.4.8
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/commands/ext-configure.js +2 -1
- package/lib/commands/functions-secrets-access.js +2 -0
- package/lib/commands/functions-secrets-destroy.js +2 -0
- package/lib/commands/functions-secrets-get.js +2 -0
- package/lib/commands/functions-secrets-prune.js +3 -1
- package/lib/commands/functions-secrets-set.js +2 -0
- package/lib/deploy/lifecycleHooks.js +6 -7
- package/lib/emulator/auth/apiSpec.js +712 -51
- package/lib/emulator/functionsEmulatorRuntime.js +5 -4
- package/lib/emulator/functionsEmulatorShell.js +54 -22
- package/lib/extensions/paramHelper.js +24 -16
- package/lib/frameworks/astro/index.js +1 -5
- package/lib/frameworks/astro/utils.js +22 -4
- package/lib/frameworks/next/index.js +1 -1
- package/lib/frameworks/utils.js +2 -3
- package/lib/functions/secrets.js +1 -1
- package/lib/gcp/frameworks.js +8 -2
- package/lib/gcp/iam.js +6 -1
- package/lib/init/features/frameworks/index.js +52 -8
- package/lib/init/features/frameworks/repo.js +1 -1
- package/lib/init/features/hosting/github.js +9 -0
- package/lib/localFunction.js +27 -9
- package/lib/utils.js +7 -3
- package/package.json +1 -1
|
@@ -642,22 +642,23 @@ async function main() {
|
|
|
642
642
|
}
|
|
643
643
|
const app = express();
|
|
644
644
|
app.enable("trust proxy");
|
|
645
|
+
const bodyParserLimit = "32mb";
|
|
645
646
|
app.use(bodyParser.json({
|
|
646
|
-
limit:
|
|
647
|
+
limit: bodyParserLimit,
|
|
647
648
|
verify: rawBodySaver,
|
|
648
649
|
}));
|
|
649
650
|
app.use(bodyParser.text({
|
|
650
|
-
limit:
|
|
651
|
+
limit: bodyParserLimit,
|
|
651
652
|
verify: rawBodySaver,
|
|
652
653
|
}));
|
|
653
654
|
app.use(bodyParser.urlencoded({
|
|
654
655
|
extended: true,
|
|
655
|
-
limit:
|
|
656
|
+
limit: bodyParserLimit,
|
|
656
657
|
verify: rawBodySaver,
|
|
657
658
|
}));
|
|
658
659
|
app.use(bodyParser.raw({
|
|
659
660
|
type: "*/*",
|
|
660
|
-
limit:
|
|
661
|
+
limit: bodyParserLimit,
|
|
661
662
|
verify: rawBodySaver,
|
|
662
663
|
}));
|
|
663
664
|
app.get("/__/health", (req, res) => {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FunctionsEmulatorShell = void 0;
|
|
4
4
|
const uuid = require("uuid");
|
|
5
|
-
const functionsEmulator_1 = require("./functionsEmulator");
|
|
6
5
|
const utils = require("../utils");
|
|
6
|
+
const functionsEmulator_1 = require("./functionsEmulator");
|
|
7
7
|
const logger_1 = require("../logger");
|
|
8
8
|
const error_1 = require("../error");
|
|
9
9
|
class FunctionsEmulatorShell {
|
|
@@ -20,37 +20,69 @@ class FunctionsEmulatorShell {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
logger_1.logger.debug(`shell:${name}: trigger=${JSON.stringify(trigger)}`);
|
|
26
|
-
logger_1.logger.debug(`shell:${name}: opts=${JSON.stringify(opts)}, data=${JSON.stringify(data)}`);
|
|
27
|
-
if (!trigger.eventTrigger) {
|
|
28
|
-
throw new error_1.FirebaseError(`Function ${name} is not a background function`);
|
|
29
|
-
}
|
|
30
|
-
const eventType = trigger.eventTrigger.eventType;
|
|
23
|
+
createLegacyEvent(eventTrigger, data, opts) {
|
|
24
|
+
var _a, _b;
|
|
31
25
|
let resource = opts.resource;
|
|
32
26
|
if (typeof resource === "object" && resource.name) {
|
|
33
27
|
resource = resource.name;
|
|
34
28
|
}
|
|
35
|
-
|
|
29
|
+
return {
|
|
36
30
|
eventId: uuid.v4(),
|
|
37
31
|
timestamp: new Date().toISOString(),
|
|
38
|
-
eventType,
|
|
39
|
-
resource,
|
|
32
|
+
eventType: eventTrigger.eventType,
|
|
33
|
+
resource: resource,
|
|
40
34
|
params: opts.params,
|
|
41
|
-
auth: opts.auth,
|
|
35
|
+
auth: { admin: ((_a = opts.auth) === null || _a === void 0 ? void 0 : _a.admin) || false, variable: (_b = opts.auth) === null || _b === void 0 ? void 0 : _b.variable },
|
|
42
36
|
data,
|
|
43
37
|
};
|
|
44
|
-
this.emu.sendRequest(trigger, proto);
|
|
45
38
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
39
|
+
createCloudEvent(eventTrigger, data, opts) {
|
|
40
|
+
var _a, _b;
|
|
41
|
+
const ce = {
|
|
42
|
+
specversion: "1.0",
|
|
43
|
+
datacontenttype: "application/json",
|
|
44
|
+
id: uuid.v4(),
|
|
45
|
+
type: eventTrigger.eventType,
|
|
46
|
+
time: new Date().toISOString(),
|
|
47
|
+
source: "",
|
|
48
|
+
data,
|
|
49
|
+
};
|
|
50
|
+
if (eventTrigger.eventType.startsWith("google.cloud.storage")) {
|
|
51
|
+
ce.source = `projects/_/buckets/${(_a = eventTrigger.eventFilters) === null || _a === void 0 ? void 0 : _a.bucket}`;
|
|
52
|
+
}
|
|
53
|
+
else if (eventTrigger.eventType.startsWith("google.cloud.pubsub")) {
|
|
54
|
+
ce.source = eventTrigger.eventFilters.topic;
|
|
55
|
+
data = Object.assign(Object.assign({}, data), { messageId: uuid.v4() });
|
|
56
|
+
}
|
|
57
|
+
else if (eventTrigger.eventType.startsWith("google.cloud.firestore")) {
|
|
58
|
+
ce.source = `projects/_/databases/(default)`;
|
|
59
|
+
if (opts.resource) {
|
|
60
|
+
ce.document = opts.resource;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (eventTrigger.eventType.startsWith("google.firebase.database")) {
|
|
64
|
+
ce.source = `projects/_/locations/_/instances/${(_b = eventTrigger.eventFilterPathPatterns) === null || _b === void 0 ? void 0 : _b.instance}`;
|
|
65
|
+
if (opts.resource) {
|
|
66
|
+
ce.ref = opts.resource;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return ce;
|
|
70
|
+
}
|
|
71
|
+
call(trigger, data, opts) {
|
|
72
|
+
logger_1.logger.debug(`shell:${trigger.name}: trigger=${JSON.stringify(trigger)}`);
|
|
73
|
+
logger_1.logger.debug(`shell:${trigger.name}: opts=${JSON.stringify(opts)}, data=${JSON.stringify(data)}`);
|
|
74
|
+
const eventTrigger = trigger.eventTrigger;
|
|
75
|
+
if (!eventTrigger) {
|
|
76
|
+
throw new error_1.FirebaseError(`Function ${trigger.name} is not a background function`);
|
|
77
|
+
}
|
|
78
|
+
let body;
|
|
79
|
+
if (trigger.platform === "gcfv1") {
|
|
80
|
+
body = this.createLegacyEvent(eventTrigger, data, opts);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
body = this.createCloudEvent(eventTrigger, data, opts);
|
|
84
|
+
}
|
|
85
|
+
this.emu.sendRequest(trigger, body);
|
|
54
86
|
}
|
|
55
87
|
}
|
|
56
88
|
exports.FunctionsEmulatorShell = FunctionsEmulatorShell;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isSystemParam = exports.readEnvFile = exports.promptForNewParams = exports.getParamsForUpdate = exports.getParams = exports.
|
|
3
|
+
exports.isSystemParam = exports.readEnvFile = exports.promptForNewParams = exports.getParamsForUpdate = exports.getParams = exports.setNewDefaults = exports.buildBindingOptionsWithBaseValue = exports.getBaseParamBindings = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const clc = require("colorette");
|
|
6
6
|
const fs = require("fs-extra");
|
|
@@ -9,7 +9,6 @@ const logger_1 = require("../logger");
|
|
|
9
9
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
10
10
|
const askUserForParam = require("./askUserForParam");
|
|
11
11
|
const env = require("../functions/env");
|
|
12
|
-
const utils_1 = require("../utils");
|
|
13
12
|
const NONINTERACTIVE_ERROR_MESSAGE = "As of firebase-tools@11, `ext:install`, `ext:update` and `ext:configure` are interactive only commands. " +
|
|
14
13
|
"To deploy an extension noninteractively, use an extensions manifest and `firebase deploy --only extensions`. " +
|
|
15
14
|
"See https://firebase.google.com/docs/extensions/manifest for more details";
|
|
@@ -30,21 +29,17 @@ function buildBindingOptionsWithBaseValue(baseParams) {
|
|
|
30
29
|
}
|
|
31
30
|
exports.buildBindingOptionsWithBaseValue = buildBindingOptionsWithBaseValue;
|
|
32
31
|
function setNewDefaults(params, newDefaults) {
|
|
33
|
-
|
|
34
|
-
if (newDefaults[param.param
|
|
35
|
-
param.default = newDefaults[param.param
|
|
32
|
+
for (const param of params) {
|
|
33
|
+
if (newDefaults[param.param]) {
|
|
34
|
+
param.default = newDefaults[param.param];
|
|
36
35
|
}
|
|
37
|
-
|
|
36
|
+
else if ((param.param = `firebaseextensions.v1beta.function/location` && newDefaults["LOCATION"])) {
|
|
37
|
+
param.default = newDefaults["LOCATION"];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
38
40
|
return params;
|
|
39
41
|
}
|
|
40
42
|
exports.setNewDefaults = setNewDefaults;
|
|
41
|
-
function getParamsWithCurrentValuesAsDefaults(extensionInstance) {
|
|
42
|
-
var _a, _b, _c, _d;
|
|
43
|
-
const specParams = (0, utils_1.cloneDeep)(((_c = (_b = (_a = extensionInstance === null || extensionInstance === void 0 ? void 0 : extensionInstance.config) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.spec) === null || _c === void 0 ? void 0 : _c.params) || []);
|
|
44
|
-
const currentParams = (0, utils_1.cloneDeep)(((_d = extensionInstance === null || extensionInstance === void 0 ? void 0 : extensionInstance.config) === null || _d === void 0 ? void 0 : _d.params) || {});
|
|
45
|
-
return setNewDefaults(specParams, currentParams);
|
|
46
|
-
}
|
|
47
|
-
exports.getParamsWithCurrentValuesAsDefaults = getParamsWithCurrentValuesAsDefaults;
|
|
48
43
|
async function getParams(args) {
|
|
49
44
|
let params;
|
|
50
45
|
if (args.nonInteractive) {
|
|
@@ -81,6 +76,7 @@ async function getParamsForUpdate(args) {
|
|
|
81
76
|
}
|
|
82
77
|
exports.getParamsForUpdate = getParamsForUpdate;
|
|
83
78
|
async function promptForNewParams(args) {
|
|
79
|
+
var _a, _b;
|
|
84
80
|
const newParamBindingOptions = buildBindingOptionsWithBaseValue(args.currentParams);
|
|
85
81
|
const firebaseProjectParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
|
|
86
82
|
const sameParam = (param1) => (param2) => {
|
|
@@ -89,10 +85,22 @@ async function promptForNewParams(args) {
|
|
|
89
85
|
const paramDiff = (left, right) => {
|
|
90
86
|
return left.filter((aLeft) => !right.find(sameParam(aLeft)));
|
|
91
87
|
};
|
|
92
|
-
|
|
93
|
-
let
|
|
88
|
+
let combinedOldParams = args.spec.params.concat((_a = args.spec.systemParams.filter((p) => !p.advanced)) !== null && _a !== void 0 ? _a : []);
|
|
89
|
+
let combinedNewParams = args.newSpec.params.concat((_b = args.newSpec.systemParams.filter((p) => !p.advanced)) !== null && _b !== void 0 ? _b : []);
|
|
90
|
+
if (combinedOldParams.some((p) => p.param === "LOCATION") &&
|
|
91
|
+
combinedNewParams.some((p) => p.param === "firebaseextensions.v1beta.function/location") &&
|
|
92
|
+
!!args.currentParams["LOCATION"]) {
|
|
93
|
+
newParamBindingOptions["firebaseextensions.v1beta.function/location"] = {
|
|
94
|
+
baseValue: args.currentParams["LOCATION"],
|
|
95
|
+
};
|
|
96
|
+
delete newParamBindingOptions["LOCATION"];
|
|
97
|
+
combinedOldParams = combinedOldParams.filter((p) => p.param !== "LOCATION");
|
|
98
|
+
combinedNewParams = combinedNewParams.filter((p) => p.param !== "firebaseextensions.v1beta.function/location");
|
|
99
|
+
}
|
|
100
|
+
const oldParams = combinedOldParams.filter((p) => Object.keys(args.currentParams).includes(p.param));
|
|
101
|
+
let paramsDiffDeletions = paramDiff(oldParams, combinedNewParams);
|
|
94
102
|
paramsDiffDeletions = (0, extensionsHelper_1.substituteParams)(paramsDiffDeletions, firebaseProjectParams);
|
|
95
|
-
let paramsDiffAdditions = paramDiff(
|
|
103
|
+
let paramsDiffAdditions = paramDiff(combinedNewParams, oldParams);
|
|
96
104
|
paramsDiffAdditions = (0, extensionsHelper_1.substituteParams)(paramsDiffAdditions, firebaseProjectParams);
|
|
97
105
|
if (paramsDiffDeletions.length) {
|
|
98
106
|
logger_1.logger.info("The following params will no longer be used:");
|
|
@@ -10,14 +10,10 @@ const utils_2 = require("./utils");
|
|
|
10
10
|
exports.name = "Astro";
|
|
11
11
|
exports.support = "experimental";
|
|
12
12
|
exports.type = 2;
|
|
13
|
-
function getAstroVersion(cwd) {
|
|
14
|
-
var _a;
|
|
15
|
-
return (_a = (0, utils_1.findDependency)("astro", { cwd, depth: 0, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
|
|
16
|
-
}
|
|
17
13
|
async function discover(dir) {
|
|
18
14
|
if (!(0, fs_extra_1.existsSync)((0, path_1.join)(dir, "package.json")))
|
|
19
15
|
return;
|
|
20
|
-
if (!getAstroVersion(dir))
|
|
16
|
+
if (!(0, utils_2.getAstroVersion)(dir))
|
|
21
17
|
return;
|
|
22
18
|
const { output, publicDir: publicDirectory } = await (0, utils_2.getConfig)(dir);
|
|
23
19
|
return {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getConfig = exports.getBootstrapScript = void 0;
|
|
3
|
+
exports.getAstroVersion = exports.getConfig = exports.getBootstrapScript = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const semver_1 = require("semver");
|
|
5
7
|
const { dynamicImport } = require(true && "../../dynamicImport");
|
|
6
8
|
function getBootstrapScript() {
|
|
7
9
|
return `const entry = import('./entry.mjs');\nexport const handle = async (req, res) => (await entry).handler(req, res)`;
|
|
@@ -9,9 +11,20 @@ function getBootstrapScript() {
|
|
|
9
11
|
exports.getBootstrapScript = getBootstrapScript;
|
|
10
12
|
async function getConfig(cwd) {
|
|
11
13
|
const astroDirectory = (0, path_1.dirname)(require.resolve("astro/package.json", { paths: [cwd] }));
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const
|
|
14
|
+
const version = getAstroVersion(cwd);
|
|
15
|
+
let config;
|
|
16
|
+
const configPath = (0, path_1.join)(astroDirectory, "dist", "core", "config", "config.js");
|
|
17
|
+
if ((0, semver_1.gte)(version, "2.9.7")) {
|
|
18
|
+
const { resolveConfig } = await dynamicImport(configPath);
|
|
19
|
+
const { astroConfig } = await resolveConfig({ root: cwd }, "build");
|
|
20
|
+
config = astroConfig;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const { openConfig } = await dynamicImport(configPath);
|
|
24
|
+
const logging = undefined;
|
|
25
|
+
const { astroConfig } = await openConfig({ cmd: "build", cwd, logging });
|
|
26
|
+
config = astroConfig;
|
|
27
|
+
}
|
|
15
28
|
return {
|
|
16
29
|
outDir: (0, path_1.relative)(cwd, config.outDir.pathname),
|
|
17
30
|
publicDir: (0, path_1.relative)(cwd, config.publicDir.pathname),
|
|
@@ -20,3 +33,8 @@ async function getConfig(cwd) {
|
|
|
20
33
|
};
|
|
21
34
|
}
|
|
22
35
|
exports.getConfig = getConfig;
|
|
36
|
+
function getAstroVersion(cwd) {
|
|
37
|
+
var _a;
|
|
38
|
+
return (_a = (0, utils_1.findDependency)("astro", { cwd, depth: 0, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
|
|
39
|
+
}
|
|
40
|
+
exports.getAstroVersion = getAstroVersion;
|
|
@@ -29,6 +29,7 @@ exports.name = "Next.js";
|
|
|
29
29
|
exports.support = "preview";
|
|
30
30
|
exports.type = 2;
|
|
31
31
|
exports.docsUrl = "https://firebase.google.com/docs/hosting/frameworks/nextjs";
|
|
32
|
+
const BUNDLE_NEXT_CONFIG_TIMEOUT = 60000;
|
|
32
33
|
const DEFAULT_NUMBER_OF_REASONS_TO_LIST = 5;
|
|
33
34
|
function getReactVersion(cwd) {
|
|
34
35
|
var _a;
|
|
@@ -297,7 +298,6 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
|
|
|
297
298
|
}));
|
|
298
299
|
}
|
|
299
300
|
exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
|
|
300
|
-
const BUNDLE_NEXT_CONFIG_TIMEOUT = 10000;
|
|
301
301
|
async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
|
|
302
302
|
const { distDir } = await getConfig(sourceDir);
|
|
303
303
|
const packageJson = await (0, utils_1.readJSON)((0, path_1.join)(sourceDir, "package.json"));
|
package/lib/frameworks/utils.js
CHANGED
|
@@ -144,14 +144,13 @@ function getNpmRoot(cwd) {
|
|
|
144
144
|
}
|
|
145
145
|
exports.getNpmRoot = getNpmRoot;
|
|
146
146
|
function getNodeModuleBin(name, cwd) {
|
|
147
|
-
const cantFindExecutable = new error_1.FirebaseError(`Could not find the ${name} executable.`);
|
|
148
147
|
const npmRoot = getNpmRoot(cwd);
|
|
149
148
|
if (!npmRoot) {
|
|
150
|
-
throw
|
|
149
|
+
throw new error_1.FirebaseError(`Error finding ${name} executable: failed to spawn 'npm'`);
|
|
151
150
|
}
|
|
152
151
|
const path = (0, path_1.join)(npmRoot, ".bin", name);
|
|
153
152
|
if (!(0, fsutils_1.fileExistsSync)(path)) {
|
|
154
|
-
throw
|
|
153
|
+
throw new error_1.FirebaseError(`Could not find the ${name} executable.`);
|
|
155
154
|
}
|
|
156
155
|
return path;
|
|
157
156
|
}
|
package/lib/functions/secrets.js
CHANGED
|
@@ -44,7 +44,7 @@ function toUpperSnakeCase(key) {
|
|
|
44
44
|
}
|
|
45
45
|
function ensureApi(options) {
|
|
46
46
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
47
|
-
return ensureApiEnabled.ensure(projectId, "secretmanager.googleapis.com", "
|
|
47
|
+
return ensureApiEnabled.ensure(projectId, "secretmanager.googleapis.com", "secretmanager", true);
|
|
48
48
|
}
|
|
49
49
|
exports.ensureApi = ensureApi;
|
|
50
50
|
async function ensureValidKey(key, options) {
|
package/lib/gcp/frameworks.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createBuild = exports.createStack = exports.API_VERSION = void 0;
|
|
3
|
+
exports.createBuild = exports.getStack = exports.createStack = exports.API_VERSION = void 0;
|
|
4
4
|
const apiv2_1 = require("../apiv2");
|
|
5
5
|
const api_1 = require("../api");
|
|
6
|
-
exports.API_VERSION = "
|
|
6
|
+
exports.API_VERSION = "v1alpha";
|
|
7
7
|
const client = new apiv2_1.Client({
|
|
8
8
|
urlPrefix: api_1.frameworksOrigin,
|
|
9
9
|
auth: true,
|
|
@@ -15,6 +15,12 @@ async function createStack(projectId, location, stackInput) {
|
|
|
15
15
|
return res.body;
|
|
16
16
|
}
|
|
17
17
|
exports.createStack = createStack;
|
|
18
|
+
async function getStack(projectId, location, stackId) {
|
|
19
|
+
const name = `projects/${projectId}/locations/${location}/stacks/${stackId}`;
|
|
20
|
+
const res = await client.get(name);
|
|
21
|
+
return res.body;
|
|
22
|
+
}
|
|
23
|
+
exports.getStack = getStack;
|
|
18
24
|
async function createBuild(projectId, location, stackId, buildInput) {
|
|
19
25
|
const buildId = buildInput.name;
|
|
20
26
|
const res = await client.post(`projects/${projectId}/locations/${location}/stacks/${stackId}/builds`, buildInput, { queryParams: { buildId } });
|
package/lib/gcp/iam.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.testIamPermissions = exports.testResourceIamPermissions = exports.getRole = exports.deleteServiceAccount = exports.createServiceAccountKey = exports.getServiceAccount = exports.createServiceAccount = void 0;
|
|
3
|
+
exports.testIamPermissions = exports.testResourceIamPermissions = exports.getRole = exports.listServiceAccountKeys = exports.deleteServiceAccount = exports.createServiceAccountKey = exports.getServiceAccount = exports.createServiceAccount = void 0;
|
|
4
4
|
const api_1 = require("../api");
|
|
5
5
|
const logger_1 = require("../logger");
|
|
6
6
|
const apiv2_1 = require("../apiv2");
|
|
@@ -35,6 +35,11 @@ async function deleteServiceAccount(projectId, accountEmail) {
|
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
exports.deleteServiceAccount = deleteServiceAccount;
|
|
38
|
+
async function listServiceAccountKeys(projectId, serviceAccountName) {
|
|
39
|
+
const response = await apiClient.get(`/projects/${projectId}/serviceAccounts/${serviceAccountName}@${projectId}.iam.gserviceaccount.com/keys`);
|
|
40
|
+
return response.body.keys;
|
|
41
|
+
}
|
|
42
|
+
exports.listServiceAccountKeys = listServiceAccountKeys;
|
|
38
43
|
async function getRole(role) {
|
|
39
44
|
const response = await apiClient.get(`/roles/${role}`, {
|
|
40
45
|
retryCodes: [500, 503],
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createStack = exports.doSetup = void 0;
|
|
3
|
+
exports.createStack = exports.getOrCreateStack = exports.doSetup = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const utils = require("../../../utils");
|
|
6
6
|
const logger_1 = require("../../../logger");
|
|
7
7
|
const prompt_1 = require("../../../prompt");
|
|
8
8
|
const constants_1 = require("./constants");
|
|
9
|
-
const
|
|
9
|
+
const repo = require("./repo");
|
|
10
10
|
const poller = require("../../../operation-poller");
|
|
11
11
|
const api_1 = require("../../../api");
|
|
12
12
|
const gcp = require("../../../gcp/frameworks");
|
|
13
13
|
const frameworks_1 = require("../../../gcp/frameworks");
|
|
14
|
+
const error_1 = require("../../../error");
|
|
14
15
|
const frameworksPollerOptions = {
|
|
15
16
|
apiOrigin: api_1.frameworksOrigin,
|
|
16
17
|
apiVersion: frameworks_1.API_VERSION,
|
|
@@ -26,7 +27,7 @@ async function doSetup(setup) {
|
|
|
26
27
|
name: "serviceName",
|
|
27
28
|
type: "input",
|
|
28
29
|
default: "acme-inc-web",
|
|
29
|
-
message: "Create a name for your service [
|
|
30
|
+
message: "Create a name for your service [1-30 characters]",
|
|
30
31
|
}, setup.frameworks);
|
|
31
32
|
await (0, prompt_1.promptOnce)({
|
|
32
33
|
name: "region",
|
|
@@ -45,19 +46,62 @@ async function doSetup(setup) {
|
|
|
45
46
|
message: "How do you want to deploy",
|
|
46
47
|
choices: constants_1.ALLOWED_DEPLOY_METHODS,
|
|
47
48
|
}, setup.frameworks);
|
|
48
|
-
|
|
49
|
-
const cloudBuildConnRepo = await (0, repo_1.linkGitHubRepository)(projectId, setup.frameworks.region, setup.frameworks.serviceName);
|
|
50
|
-
toStack(cloudBuildConnRepo, setup.frameworks.serviceName);
|
|
51
|
-
}
|
|
49
|
+
await getOrCreateStack(projectId, setup);
|
|
52
50
|
}
|
|
53
51
|
exports.doSetup = doSetup;
|
|
54
52
|
function toStack(cloudBuildConnRepo, stackId) {
|
|
55
53
|
return {
|
|
56
54
|
name: stackId,
|
|
57
|
-
codebase: { repository: cloudBuildConnRepo.name, rootDirectory: "/" },
|
|
58
55
|
labels: {},
|
|
59
56
|
};
|
|
60
57
|
}
|
|
58
|
+
async function getOrCreateStack(projectId, setup) {
|
|
59
|
+
const location = setup.frameworks.region;
|
|
60
|
+
const deployMethod = setup.frameworks.deployMethod;
|
|
61
|
+
try {
|
|
62
|
+
return await getExistingStack(projectId, setup, location);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
if (err.status === 404) {
|
|
66
|
+
logger_1.logger.info("Creating new stack.");
|
|
67
|
+
if (deployMethod === "github") {
|
|
68
|
+
const cloudBuildConnRepo = await repo.linkGitHubRepository(projectId, location, setup.frameworks.serviceName);
|
|
69
|
+
const stackDetails = toStack(cloudBuildConnRepo, setup.frameworks.serviceName);
|
|
70
|
+
return await createStack(projectId, location, stackDetails);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
throw new error_1.FirebaseError(`Failed to get or create a stack using the given initialization details: ${err}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
exports.getOrCreateStack = getOrCreateStack;
|
|
80
|
+
async function getExistingStack(projectId, setup, location) {
|
|
81
|
+
let stack = await gcp.getStack(projectId, location, setup.frameworks.serviceName);
|
|
82
|
+
while (stack) {
|
|
83
|
+
setup.frameworks.serviceName = undefined;
|
|
84
|
+
await (0, prompt_1.promptOnce)({
|
|
85
|
+
name: "existingStack",
|
|
86
|
+
type: "confirm",
|
|
87
|
+
default: true,
|
|
88
|
+
message: "A stack already exists for the given serviceName, do you want to use existing stack? (yes/no)",
|
|
89
|
+
}, setup.frameworks);
|
|
90
|
+
if (setup.frameworks.existingStack) {
|
|
91
|
+
logger_1.logger.info("Using the existing stack.");
|
|
92
|
+
return stack;
|
|
93
|
+
}
|
|
94
|
+
await (0, prompt_1.promptOnce)({
|
|
95
|
+
name: "serviceName",
|
|
96
|
+
type: "input",
|
|
97
|
+
default: "acme-inc-web",
|
|
98
|
+
message: "Please enter a new service name [1-30 characters]",
|
|
99
|
+
}, setup.frameworks);
|
|
100
|
+
stack = await gcp.getStack(projectId, location, setup.frameworks.serviceName);
|
|
101
|
+
setup.frameworks.existingStack = undefined;
|
|
102
|
+
}
|
|
103
|
+
return stack;
|
|
104
|
+
}
|
|
61
105
|
async function createStack(projectId, location, stackInput) {
|
|
62
106
|
const op = await gcp.createStack(projectId, location, stackInput);
|
|
63
107
|
const stack = await poller.pollOperation(Object.assign(Object.assign({}, frameworksPollerOptions), { pollerName: `create-${projectId}-${location}-${stackInput.name}`, operationResourceName: op.name }));
|
|
@@ -32,7 +32,7 @@ async function linkGitHubRepository(projectId, location, stackId) {
|
|
|
32
32
|
await utils.openInBrowser("https://github.com/apps/google-cloud-build/installations/new");
|
|
33
33
|
await (0, prompt_1.promptOnce)({
|
|
34
34
|
type: "input",
|
|
35
|
-
message: "Press
|
|
35
|
+
message: "Press ENTER once you have finished configuring your installation's access settings.",
|
|
36
36
|
});
|
|
37
37
|
remoteUri = await promptRepositoryURI(projectId, location, connectionId);
|
|
38
38
|
}
|
|
@@ -17,6 +17,7 @@ const prompt_1 = require("../../../prompt");
|
|
|
17
17
|
const utils_1 = require("../../../utils");
|
|
18
18
|
const api_1 = require("../../../api");
|
|
19
19
|
const apiv2_1 = require("../../../apiv2");
|
|
20
|
+
const error_1 = require("../../../error");
|
|
20
21
|
let GIT_DIR;
|
|
21
22
|
let GITHUB_DIR;
|
|
22
23
|
let WORKFLOW_DIR;
|
|
@@ -26,6 +27,7 @@ const YML_PULL_REQUEST_FILENAME = "firebase-hosting-pull-request.yml";
|
|
|
26
27
|
const YML_MERGE_FILENAME = "firebase-hosting-merge.yml";
|
|
27
28
|
const CHECKOUT_GITHUB_ACTION_NAME = "actions/checkout@v3";
|
|
28
29
|
const HOSTING_GITHUB_ACTION_NAME = "FirebaseExtended/action-hosting-deploy@v0";
|
|
30
|
+
const SERVICE_ACCOUNT_MAX_KEY_NUMBER = 10;
|
|
29
31
|
const githubApiClient = new apiv2_1.Client({ urlPrefix: api_1.githubApiOrigin, auth: false });
|
|
30
32
|
async function initGitHub(setup) {
|
|
31
33
|
if (!setup.projectId) {
|
|
@@ -344,6 +346,13 @@ async function createServiceAccountAndKeyWithRetry(options, repo, accountId) {
|
|
|
344
346
|
catch (e) {
|
|
345
347
|
spinnerServiceAccount.stop();
|
|
346
348
|
if (!e.message.includes("429")) {
|
|
349
|
+
const serviceAccountKeys = await (0, iam_1.listServiceAccountKeys)(options.projectId, accountId);
|
|
350
|
+
if (serviceAccountKeys.length >= SERVICE_ACCOUNT_MAX_KEY_NUMBER) {
|
|
351
|
+
throw new error_1.FirebaseError(`You cannot add another key because the service account ${(0, colorette_1.bold)(accountId)} already contains the max number of keys: ${SERVICE_ACCOUNT_MAX_KEY_NUMBER}.`, {
|
|
352
|
+
original: e,
|
|
353
|
+
exit: 1,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
347
356
|
throw e;
|
|
348
357
|
}
|
|
349
358
|
spinnerServiceAccount.start();
|
package/lib/localFunction.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const uuid = require("uuid");
|
|
3
4
|
const request = require("request");
|
|
4
|
-
const utils = require("./utils");
|
|
5
5
|
const encodeFirestoreValue_1 = require("./firestore/encodeFirestoreValue");
|
|
6
|
+
const utils = require("./utils");
|
|
6
7
|
class LocalFunction {
|
|
7
8
|
constructor(trigger, urls, controller) {
|
|
8
9
|
this.trigger = trigger;
|
|
@@ -17,7 +18,7 @@ class LocalFunction {
|
|
|
17
18
|
return resource.replace(this.paramWildcardRegex, (wildcard) => {
|
|
18
19
|
const wildcardNoBraces = wildcard.slice(1, -1);
|
|
19
20
|
const sub = params === null || params === void 0 ? void 0 : params[wildcardNoBraces];
|
|
20
|
-
return sub ||
|
|
21
|
+
return sub || wildcardNoBraces + utils.randomInt(1, 9);
|
|
21
22
|
});
|
|
22
23
|
}
|
|
23
24
|
constructCallableFunc(data, opts) {
|
|
@@ -118,24 +119,30 @@ class LocalFunction {
|
|
|
118
119
|
isFirestoreFunc(eventTrigger) {
|
|
119
120
|
return utils.getFunctionsEventProvider(eventTrigger.eventType) === "Firestore";
|
|
120
121
|
}
|
|
122
|
+
isPubsubFunc(eventTrigger) {
|
|
123
|
+
return utils.getFunctionsEventProvider(eventTrigger.eventType) === "PubSub";
|
|
124
|
+
}
|
|
121
125
|
triggerEvent(data, opts) {
|
|
126
|
+
var _a, _b, _c, _d;
|
|
122
127
|
opts = opts || {};
|
|
123
128
|
let operationType;
|
|
124
129
|
let dataPayload;
|
|
125
130
|
if (this.trigger.httpsTrigger) {
|
|
126
|
-
this.controller.call(this.trigger
|
|
131
|
+
this.controller.call(this.trigger, data || {}, opts);
|
|
127
132
|
}
|
|
128
133
|
else if (this.trigger.eventTrigger) {
|
|
129
134
|
if (this.isDatabaseFn(this.trigger.eventTrigger)) {
|
|
130
135
|
operationType = utils.last(this.trigger.eventTrigger.eventType.split("."));
|
|
131
136
|
switch (operationType) {
|
|
132
137
|
case "create":
|
|
138
|
+
case "created":
|
|
133
139
|
dataPayload = {
|
|
134
140
|
data: null,
|
|
135
141
|
delta: data,
|
|
136
142
|
};
|
|
137
143
|
break;
|
|
138
144
|
case "delete":
|
|
145
|
+
case "deleted":
|
|
139
146
|
dataPayload = {
|
|
140
147
|
data: data,
|
|
141
148
|
delta: null,
|
|
@@ -147,20 +154,23 @@ class LocalFunction {
|
|
|
147
154
|
delta: data.after,
|
|
148
155
|
};
|
|
149
156
|
}
|
|
150
|
-
|
|
157
|
+
const resource = (_a = this.trigger.eventTrigger.resource) !== null && _a !== void 0 ? _a : (_b = this.trigger.eventTrigger.eventFilterPathPatterns) === null || _b === void 0 ? void 0 : _b.ref;
|
|
158
|
+
opts.resource = this.substituteParams(resource, opts.params);
|
|
151
159
|
opts.auth = this.constructAuth(opts.auth, opts.authType);
|
|
152
|
-
this.controller.call(this.trigger
|
|
160
|
+
this.controller.call(this.trigger, dataPayload, opts);
|
|
153
161
|
}
|
|
154
162
|
else if (this.isFirestoreFunc(this.trigger.eventTrigger)) {
|
|
155
163
|
operationType = utils.last(this.trigger.eventTrigger.eventType.split("."));
|
|
156
164
|
switch (operationType) {
|
|
157
165
|
case "create":
|
|
166
|
+
case "created":
|
|
158
167
|
dataPayload = {
|
|
159
168
|
value: this.makeFirestoreValue(data),
|
|
160
169
|
oldValue: {},
|
|
161
170
|
};
|
|
162
171
|
break;
|
|
163
172
|
case "delete":
|
|
173
|
+
case "deleted":
|
|
164
174
|
dataPayload = {
|
|
165
175
|
value: {},
|
|
166
176
|
oldValue: this.makeFirestoreValue(data),
|
|
@@ -172,14 +182,22 @@ class LocalFunction {
|
|
|
172
182
|
oldValue: this.makeFirestoreValue(data.before),
|
|
173
183
|
};
|
|
174
184
|
}
|
|
175
|
-
|
|
176
|
-
this.
|
|
185
|
+
const resource = (_c = this.trigger.eventTrigger.resource) !== null && _c !== void 0 ? _c : (_d = this.trigger.eventTrigger.eventFilterPathPatterns) === null || _d === void 0 ? void 0 : _d.document;
|
|
186
|
+
opts.resource = this.substituteParams(resource, opts.params);
|
|
187
|
+
this.controller.call(this.trigger, dataPayload, opts);
|
|
188
|
+
}
|
|
189
|
+
else if (this.isPubsubFunc(this.trigger.eventTrigger)) {
|
|
190
|
+
dataPayload = data;
|
|
191
|
+
if (this.trigger.platform === "gcfv2") {
|
|
192
|
+
dataPayload = { message: Object.assign(Object.assign({}, data), { messageId: uuid.v4() }) };
|
|
193
|
+
}
|
|
194
|
+
this.controller.call(this.trigger, dataPayload || {}, opts);
|
|
177
195
|
}
|
|
178
196
|
else {
|
|
179
|
-
this.controller.call(this.trigger
|
|
197
|
+
this.controller.call(this.trigger, data || {}, opts);
|
|
180
198
|
}
|
|
181
199
|
}
|
|
182
|
-
return
|
|
200
|
+
return "Successfully invoked function.";
|
|
183
201
|
}
|
|
184
202
|
makeFn() {
|
|
185
203
|
var _a;
|
package/lib/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.openInBrowser = exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.withTimeout = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
|
|
3
|
+
exports.openInBrowser = exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isVSCodeExtension = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.withTimeout = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const url = require("url");
|
|
6
6
|
const clc = require("colorette");
|
|
@@ -194,7 +194,7 @@ function getFunctionsEventProvider(eventType) {
|
|
|
194
194
|
const provider = last(parts[1].split("."));
|
|
195
195
|
return _.capitalize(provider);
|
|
196
196
|
}
|
|
197
|
-
if (/google
|
|
197
|
+
if (/google.*pubsub/.exec(eventType)) {
|
|
198
198
|
return "PubSub";
|
|
199
199
|
}
|
|
200
200
|
else if (/google.storage/.exec(eventType)) {
|
|
@@ -212,7 +212,7 @@ function getFunctionsEventProvider(eventType) {
|
|
|
212
212
|
else if (/google.firebase.crashlytics/.exec(eventType)) {
|
|
213
213
|
return "Crashlytics";
|
|
214
214
|
}
|
|
215
|
-
else if (/google
|
|
215
|
+
else if (/google.*firestore/.exec(eventType)) {
|
|
216
216
|
return "Firestore";
|
|
217
217
|
}
|
|
218
218
|
return _.capitalize(eventType.split(".")[1]);
|
|
@@ -367,6 +367,10 @@ function isCloudEnvironment() {
|
|
|
367
367
|
return !!process.env.CODESPACES || !!process.env.GOOGLE_CLOUD_WORKSTATIONS;
|
|
368
368
|
}
|
|
369
369
|
exports.isCloudEnvironment = isCloudEnvironment;
|
|
370
|
+
function isVSCodeExtension() {
|
|
371
|
+
return !!process.env.VSCODE_CWD;
|
|
372
|
+
}
|
|
373
|
+
exports.isVSCodeExtension = isVSCodeExtension;
|
|
370
374
|
function isRunningInWSL() {
|
|
371
375
|
return !!process.env.WSL_DISTRO_NAME;
|
|
372
376
|
}
|