firebase-tools 14.2.2 → 14.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api.js +4 -2
- package/lib/apphosting/backend.js +12 -23
- package/lib/apphosting/config.js +9 -20
- package/lib/apphosting/githubConnections.js +52 -80
- package/lib/apphosting/repo.js +22 -36
- package/lib/apphosting/secrets/dialogs.js +2 -3
- package/lib/apphosting/utils.js +1 -3
- package/lib/auth.js +1 -4
- package/lib/commands/apphosting-backends-delete.js +5 -5
- package/lib/commands/apphosting-secrets-set.js +2 -6
- package/lib/commands/apps-create.js +2 -3
- package/lib/commands/apps-sdkconfig.js +2 -7
- package/lib/commands/database-import.js +4 -6
- package/lib/commands/database-remove.js +4 -6
- package/lib/commands/database-set.js +6 -6
- package/lib/commands/database-update.js +5 -5
- package/lib/commands/dataconnect-sql-shell.js +4 -6
- package/lib/commands/ext-dev-deprecate.js +1 -0
- package/lib/commands/ext-dev-init.js +3 -12
- package/lib/commands/ext-dev-register.js +2 -4
- package/lib/commands/ext-dev-undeprecate.js +1 -2
- package/lib/commands/ext-dev-usage.js +1 -3
- package/lib/commands/ext-export.js +1 -2
- package/lib/commands/ext-install.js +1 -0
- package/lib/commands/ext-sdk-install.js +1 -0
- package/lib/commands/ext-update.js +1 -0
- package/lib/commands/firestore-backups-delete.js +1 -2
- package/lib/commands/firestore-backups-schedules-delete.js +1 -2
- package/lib/commands/firestore-databases-delete.js +1 -5
- package/lib/commands/firestore-delete.js +6 -6
- package/lib/commands/functions-artifacts-setpolicy.js +12 -2
- package/lib/commands/functions-config-export.js +5 -9
- package/lib/commands/functions-delete.js +5 -5
- package/lib/commands/functions-deletegcfartifacts.js +4 -4
- package/lib/commands/functions-secrets-destroy.js +8 -10
- package/lib/commands/functions-secrets-prune.js +12 -13
- package/lib/commands/functions-secrets-set.js +11 -15
- package/lib/commands/hosting-channel-create.js +1 -2
- package/lib/commands/hosting-channel-delete.js +4 -4
- package/lib/commands/hosting-channel-open.js +2 -3
- package/lib/commands/hosting-disable.js +5 -5
- package/lib/commands/hosting-sites-delete.js +4 -4
- package/lib/commands/init.js +41 -58
- package/lib/commands/login.js +1 -5
- package/lib/commands/logout.js +2 -3
- package/lib/commands/open.js +1 -2
- package/lib/commands/projects-create.js +1 -2
- package/lib/commands/remoteconfig-rollback.js +5 -5
- package/lib/commands/use.js +110 -110
- package/lib/config.js +1 -2
- package/lib/dataconnect/build.js +2 -4
- package/lib/dataconnect/client.js +20 -1
- package/lib/dataconnect/schemaMigration.js +1 -6
- package/lib/deploy/functions/params.js +10 -17
- package/lib/deploy/functions/prompts.js +6 -28
- package/lib/emulator/commandUtils.js +4 -13
- package/lib/emulator/controller.js +1 -2
- package/lib/emulator/downloadableEmulators.js +12 -12
- package/lib/emulator/initEmulators.js +9 -20
- package/lib/extensions/askUserForEventsConfig.js +6 -15
- package/lib/extensions/askUserForParam.js +23 -52
- package/lib/extensions/checkProjectBilling.js +3 -9
- package/lib/extensions/diagnose.js +3 -6
- package/lib/extensions/extensionsHelper.js +17 -27
- package/lib/extensions/manifest.js +1 -2
- package/lib/extensions/tos.js +10 -2
- package/lib/extensions/utils.js +1 -10
- package/lib/frameworks/index.js +1 -2
- package/lib/frameworks/next/index.js +7 -4
- package/lib/frameworks/vite/index.js +1 -2
- package/lib/functions/secrets.js +14 -15
- package/lib/gcp/auth.js +29 -1
- package/lib/gif/fdcExperience.js +45 -0
- package/lib/hosting/interactive.js +2 -3
- package/lib/init/features/account.js +2 -4
- package/lib/init/features/database.js +11 -20
- package/lib/init/features/dataconnect/index.js +7 -14
- package/lib/init/features/dataconnect/sdk.js +15 -22
- package/lib/init/features/emulators.js +19 -41
- package/lib/init/features/firestore/index.js +2 -6
- package/lib/init/features/firestore/indexes.js +17 -31
- package/lib/init/features/firestore/rules.js +17 -31
- package/lib/init/features/functions/index.js +9 -16
- package/lib/init/features/functions/javascript.js +16 -30
- package/lib/init/features/functions/npm-dependencies.js +4 -8
- package/lib/init/features/functions/python.js +1 -3
- package/lib/init/features/functions/typescript.js +24 -43
- package/lib/init/features/genkit/index.js +23 -38
- package/lib/init/features/hosting/github.js +20 -51
- package/lib/init/features/hosting/index.js +36 -57
- package/lib/init/features/project.js +6 -16
- package/lib/init/features/remoteconfig.js +2 -8
- package/lib/init/features/storage.js +1 -3
- package/lib/management/apps.js +19 -44
- package/lib/management/projects.js +17 -28
- package/lib/mcp/index.js +12 -1
- package/lib/mcp/tools/auth/index.js +7 -1
- package/lib/mcp/tools/auth/set_sms_region_policy.js +36 -0
- package/lib/mcp/tools/core/consult_firebase_assistant.js +27 -0
- package/lib/mcp/tools/core/index.js +6 -1
- package/lib/mcp/tools/dataconnect/converter.js +33 -0
- package/lib/mcp/tools/dataconnect/generate_dataconnect_operation.js +33 -0
- package/lib/mcp/tools/dataconnect/generate_dataconnect_schema.js +25 -0
- package/lib/mcp/tools/dataconnect/get_dataconnect_connector.js +31 -0
- package/lib/mcp/tools/dataconnect/get_dataconnect_schema.js +31 -0
- package/lib/mcp/tools/dataconnect/index.js +11 -1
- package/lib/mcp/tools/firestore/{get_documents.js → get_firestore_documents.js} +5 -5
- package/lib/mcp/tools/firestore/index.js +7 -3
- package/lib/mcp/tools/firestore/{list_collections.js → list_firestore_collections.js} +3 -3
- package/lib/mcp/tools/index.js +2 -1
- package/lib/mcp/tools/storage/get_storage_rules.js +26 -0
- package/lib/mcp/tools/storage/index.js +5 -0
- package/lib/prompt.js +78 -65
- package/lib/requireTosAcceptance.js +4 -0
- package/lib/rulesDeploy.js +10 -15
- package/lib/track.js +1 -34
- package/lib/utils.js +27 -5
- package/package.json +2 -3
|
@@ -69,7 +69,7 @@ function printNoticeIfEmulated(options, emulator) {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
exports.printNoticeIfEmulated = printNoticeIfEmulated;
|
|
72
|
-
function warnEmulatorNotSupported(options, emulator) {
|
|
72
|
+
async function warnEmulatorNotSupported(options, emulator) {
|
|
73
73
|
if (emulator !== types_1.Emulators.DATABASE && emulator !== types_1.Emulators.FIRESTORE) {
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
@@ -80,18 +80,9 @@ function warnEmulatorNotSupported(options, emulator) {
|
|
|
80
80
|
const envVal = process.env[envKey];
|
|
81
81
|
if (envVal) {
|
|
82
82
|
utils.logWarning(`You have set ${clc.bold(`${envKey}=${envVal}`)}, however this command does not support running against the ${emuName} so this action will affect production.`);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
return (0, prompt_1.promptOnce)({
|
|
87
|
-
type: "confirm",
|
|
88
|
-
default: false,
|
|
89
|
-
message: "Do you want to continue?",
|
|
90
|
-
}).then(() => {
|
|
91
|
-
if (!opts.confirm) {
|
|
92
|
-
return utils.reject("Command aborted.", { exit: 1 });
|
|
93
|
-
}
|
|
94
|
-
});
|
|
83
|
+
if (!(await (0, prompt_1.confirm)("Do you want to continue?"))) {
|
|
84
|
+
throw new error_1.FirebaseError("Command aborted.", { exit: 1 });
|
|
85
|
+
}
|
|
95
86
|
}
|
|
96
87
|
}
|
|
97
88
|
exports.warnEmulatorNotSupported = warnEmulatorNotSupported;
|
|
@@ -583,8 +583,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
583
583
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATACONNECT).logLabeled("WARN", "dataconnect", "'firebase.json#emulators.dataconnect.dataDir' is set and `--import` flag was passed. " +
|
|
584
584
|
"This will overwrite any data saved from previous runs.");
|
|
585
585
|
if (!options.nonInteractive &&
|
|
586
|
-
!(await (0, prompt_1.
|
|
587
|
-
type: "confirm",
|
|
586
|
+
!(await (0, prompt_1.confirm)({
|
|
588
587
|
message: `Do you wish to continue and overwrite data in ${dataDirectory}?`,
|
|
589
588
|
default: false,
|
|
590
589
|
}))) {
|
|
@@ -37,9 +37,9 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
37
37
|
ui: experiments.isEnabled("emulatoruisnapshot")
|
|
38
38
|
? { version: "SNAPSHOT", expectedSize: -1, expectedChecksum: "" }
|
|
39
39
|
: {
|
|
40
|
-
version: "1.
|
|
41
|
-
expectedSize:
|
|
42
|
-
expectedChecksum: "
|
|
40
|
+
version: "1.15.0",
|
|
41
|
+
expectedSize: 3538469,
|
|
42
|
+
expectedChecksum: "2f13d5aea9524564c8b7adaa9cfa2128",
|
|
43
43
|
},
|
|
44
44
|
pubsub: {
|
|
45
45
|
version: "0.8.14",
|
|
@@ -48,20 +48,20 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
48
48
|
},
|
|
49
49
|
dataconnect: process.platform === "darwin"
|
|
50
50
|
? {
|
|
51
|
-
version: "2.
|
|
52
|
-
expectedSize:
|
|
53
|
-
expectedChecksum: "
|
|
51
|
+
version: "2.5.0",
|
|
52
|
+
expectedSize: 27378432,
|
|
53
|
+
expectedChecksum: "d18bc3a07be90886f6ec212f3393b66e",
|
|
54
54
|
}
|
|
55
55
|
: process.platform === "win32"
|
|
56
56
|
? {
|
|
57
|
-
version: "2.
|
|
58
|
-
expectedSize:
|
|
59
|
-
expectedChecksum: "
|
|
57
|
+
version: "2.5.0",
|
|
58
|
+
expectedSize: 27836416,
|
|
59
|
+
expectedChecksum: "d335e9295b00381eb12682bc944ffef7",
|
|
60
60
|
}
|
|
61
61
|
: {
|
|
62
|
-
version: "2.
|
|
63
|
-
expectedSize:
|
|
64
|
-
expectedChecksum: "
|
|
62
|
+
version: "2.5.0",
|
|
63
|
+
expectedSize: 27295896,
|
|
64
|
+
expectedChecksum: "dc44dbfd972a9b3608794909df517077",
|
|
65
65
|
},
|
|
66
66
|
};
|
|
67
67
|
exports.DownloadDetails = {
|
|
@@ -8,21 +8,18 @@ const developmentServer_1 = require("./apphosting/developmentServer");
|
|
|
8
8
|
const emulatorLogger_1 = require("./emulatorLogger");
|
|
9
9
|
const types_1 = require("./types");
|
|
10
10
|
const config_1 = require("../apphosting/config");
|
|
11
|
-
const detectProjectRoot_1 = require("../detectProjectRoot");
|
|
12
11
|
const projectUtils_1 = require("../projectUtils");
|
|
13
12
|
const secrets_1 = require("../apphosting/secrets");
|
|
14
13
|
exports.AdditionalInitFns = {
|
|
15
14
|
[types_1.Emulators.APPHOSTING]: async (config) => {
|
|
16
|
-
var _a
|
|
15
|
+
var _a;
|
|
17
16
|
const cwd = process.cwd();
|
|
18
17
|
const additionalConfigs = new Map();
|
|
19
18
|
const logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.APPHOSTING);
|
|
20
19
|
logger.logLabeled("INFO", "Initializing Emulator");
|
|
21
|
-
const backendRelativeDir = await (0, prompt_1.
|
|
22
|
-
name: "rootDir",
|
|
23
|
-
type: "input",
|
|
24
|
-
default: "./",
|
|
20
|
+
const backendRelativeDir = await (0, prompt_1.input)({
|
|
25
21
|
message: "Specify your app's root directory relative to your repository",
|
|
22
|
+
default: "./",
|
|
26
23
|
});
|
|
27
24
|
additionalConfigs.set("rootDirectory", backendRelativeDir);
|
|
28
25
|
const backendRoot = (0, path_1.join)(cwd, backendRelativeDir);
|
|
@@ -36,23 +33,19 @@ exports.AdditionalInitFns = {
|
|
|
36
33
|
const projectId = (0, projectUtils_1.getProjectId)(config.options);
|
|
37
34
|
let env = [];
|
|
38
35
|
try {
|
|
39
|
-
|
|
40
|
-
env = await (0, config_1.maybeGenerateEmulatorYaml)(projectId, projectRoot);
|
|
36
|
+
env = await (0, config_1.maybeGenerateEmulatorYaml)(projectId, backendRoot);
|
|
41
37
|
}
|
|
42
38
|
catch (e) {
|
|
43
39
|
logger.log("WARN", "failed to export app hosting configs");
|
|
44
40
|
}
|
|
45
|
-
const secretIds = (
|
|
41
|
+
const secretIds = (_a = env === null || env === void 0 ? void 0 : env.filter((e) => "secret" in e)) === null || _a === void 0 ? void 0 : _a.map((e) => e.secret);
|
|
46
42
|
if (secretIds === null || secretIds === void 0 ? void 0 : secretIds.length) {
|
|
47
43
|
if (!projectId) {
|
|
48
44
|
logger.log("WARN", "Cannot grant developers access to secrets for local development without knowing what project the secret is in. " +
|
|
49
45
|
`Run ${clc.bold(`firebase apphosting:secrets:grantaccess ${secretIds.join(",")} --project [project] --emails [email list]`)}`);
|
|
50
46
|
}
|
|
51
47
|
else {
|
|
52
|
-
const users = await (0, prompt_1.
|
|
53
|
-
type: "input",
|
|
54
|
-
message: "Your config has secret values. Please provide a comma-separated list of users or groups who should have access to secrets for local development:",
|
|
55
|
-
});
|
|
48
|
+
const users = await (0, prompt_1.input)("Your config has secret values. Please provide a comma-separated list of users or groups who should have access to secrets for local development: ");
|
|
56
49
|
if (users.length) {
|
|
57
50
|
await (0, secrets_1.grantEmailsSecretAccess)(projectId, secretIds, users.split(",").map((u) => u.trim()));
|
|
58
51
|
}
|
|
@@ -68,13 +61,9 @@ exports.AdditionalInitFns = {
|
|
|
68
61
|
const additionalConfig = {};
|
|
69
62
|
const defaultDataConnectDir = config.get("dataconnect.source", "dataconnect");
|
|
70
63
|
const defaultDataDir = config.get("emulators.dataconnect.dataDir", `${defaultDataConnectDir}/.dataconnect/pgliteData`);
|
|
71
|
-
if (await (0, prompt_1.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
message: "Do you want to persist Postgres data from the Data Connect emulator between runs? " +
|
|
75
|
-
`Data will be saved to ${defaultDataDir}. ` +
|
|
76
|
-
`You can change this directory by editing 'firebase.json#emulators.dataconnect.dataDir'.`,
|
|
77
|
-
})) {
|
|
64
|
+
if (await (0, prompt_1.confirm)("Do you want to persist Postgres data from the Data Connect emulator between runs? " +
|
|
65
|
+
`Data will be saved to ${defaultDataDir}. ` +
|
|
66
|
+
`You can change this directory by editing 'firebase.json#emulators.dataconnect.dataDir'.`)) {
|
|
78
67
|
additionalConfig["dataDir"] = defaultDataDir;
|
|
79
68
|
}
|
|
80
69
|
return additionalConfig;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.askForEventArcLocation = exports.EXTENSIONS_DEFAULT_EVENT_ARC_REGION = exports.ALLOWED_EVENT_ARC_REGIONS = exports.askShouldCollectEventsConfig = exports.askForAllowedEventTypes = exports.getEventArcChannel = exports.askForEventsConfig = exports.checkAllowedEventTypesResponse = void 0;
|
|
4
|
-
const prompt_1 = require("../prompt");
|
|
5
4
|
const extensionsApi = require("../extensions/extensionsApi");
|
|
6
5
|
const utils = require("../utils");
|
|
7
6
|
const clc = require("colorette");
|
|
8
7
|
const logger_1 = require("../logger");
|
|
9
8
|
const marked_1 = require("marked");
|
|
9
|
+
const prompt_1 = require("../prompt");
|
|
10
10
|
function checkAllowedEventTypesResponse(response, validEvents) {
|
|
11
11
|
const validEventTypes = validEvents.map((e) => e.type);
|
|
12
12
|
if (response.length === 0) {
|
|
@@ -56,9 +56,7 @@ async function askForAllowedEventTypes(eventDescriptors, preselectedTypes) {
|
|
|
56
56
|
value: e.type,
|
|
57
57
|
}));
|
|
58
58
|
while (!valid) {
|
|
59
|
-
response = await (0, prompt_1.
|
|
60
|
-
name: "selectedEventTypesInput",
|
|
61
|
-
type: "checkbox",
|
|
59
|
+
response = await (0, prompt_1.checkbox)({
|
|
62
60
|
default: preselectedTypes !== null && preselectedTypes !== void 0 ? preselectedTypes : [],
|
|
63
61
|
message: `Please select the events [${eventTypes.length} types total] that this extension is permitted to emit. ` +
|
|
64
62
|
"You can implement your own handlers that trigger when these events are emitted to customize the extension's behavior. ",
|
|
@@ -70,13 +68,8 @@ async function askForAllowedEventTypes(eventDescriptors, preselectedTypes) {
|
|
|
70
68
|
return response.filter((e) => e !== "");
|
|
71
69
|
}
|
|
72
70
|
exports.askForAllowedEventTypes = askForAllowedEventTypes;
|
|
73
|
-
|
|
74
|
-
return (0, prompt_1.
|
|
75
|
-
type: "confirm",
|
|
76
|
-
name: "shouldCollectEvents",
|
|
77
|
-
message: `Would you like to enable events?`,
|
|
78
|
-
default: false,
|
|
79
|
-
});
|
|
71
|
+
function askShouldCollectEventsConfig() {
|
|
72
|
+
return (0, prompt_1.confirm)("Would you like to enable events?");
|
|
80
73
|
}
|
|
81
74
|
exports.askShouldCollectEventsConfig = askShouldCollectEventsConfig;
|
|
82
75
|
exports.ALLOWED_EVENT_ARC_REGIONS = [
|
|
@@ -90,12 +83,10 @@ async function askForEventArcLocation(preselectedLocation) {
|
|
|
90
83
|
let valid = false;
|
|
91
84
|
let location = "";
|
|
92
85
|
while (!valid) {
|
|
93
|
-
location = await (0, prompt_1.
|
|
94
|
-
name: "input",
|
|
95
|
-
type: "list",
|
|
86
|
+
location = await (0, prompt_1.select)({
|
|
96
87
|
default: preselectedLocation !== null && preselectedLocation !== void 0 ? preselectedLocation : exports.EXTENSIONS_DEFAULT_EVENT_ARC_REGION,
|
|
97
88
|
message: "Which location would you like the Eventarc channel to live in? We recommend using the default option. A channel location that differs from the extension's Cloud Functions location can incur egress cost.",
|
|
98
|
-
choices: exports.ALLOWED_EVENT_ARC_REGIONS
|
|
89
|
+
choices: exports.ALLOWED_EVENT_ARC_REGIONS,
|
|
99
90
|
});
|
|
100
91
|
valid = exports.ALLOWED_EVENT_ARC_REGIONS.includes(location);
|
|
101
92
|
if (!valid) {
|
|
@@ -82,11 +82,7 @@ async function ask(args) {
|
|
|
82
82
|
});
|
|
83
83
|
if (advancedParams.length) {
|
|
84
84
|
promises.push(async () => {
|
|
85
|
-
const shouldPrompt = await (0, prompt_1.
|
|
86
|
-
type: "confirm",
|
|
87
|
-
message: "Do you want to configure any advanced parameters for this instance?",
|
|
88
|
-
default: false,
|
|
89
|
-
});
|
|
85
|
+
const shouldPrompt = await (0, prompt_1.confirm)("Do you want to configure any advanced parameters for this instance?");
|
|
90
86
|
if (shouldPrompt) {
|
|
91
87
|
const advancedPromises = advancedParams.map((paramSpec) => {
|
|
92
88
|
return async () => {
|
|
@@ -126,14 +122,10 @@ async function askForParam(args) {
|
|
|
126
122
|
while (!valid) {
|
|
127
123
|
switch (paramSpec.type) {
|
|
128
124
|
case types_1.ParamType.SELECT:
|
|
129
|
-
response = await (0, prompt_1.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (paramSpec.default) {
|
|
134
|
-
return getInquirerDefault(_.get(paramSpec, "options", []), paramSpec.default);
|
|
135
|
-
}
|
|
136
|
-
},
|
|
125
|
+
response = await (0, prompt_1.select)({
|
|
126
|
+
default: paramSpec.default
|
|
127
|
+
? getInquirerDefault(_.get(paramSpec, "options", []), paramSpec.default)
|
|
128
|
+
: undefined,
|
|
137
129
|
message: "Which option do you want enabled for this parameter? " +
|
|
138
130
|
"Select an option with the arrow keys, and use Enter to confirm your choice. " +
|
|
139
131
|
"You may only select one option.",
|
|
@@ -142,21 +134,16 @@ async function askForParam(args) {
|
|
|
142
134
|
valid = checkResponse(response, paramSpec);
|
|
143
135
|
break;
|
|
144
136
|
case types_1.ParamType.MULTISELECT:
|
|
145
|
-
response = await (0,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return defaults.map((def) => {
|
|
152
|
-
return getInquirerDefault(_.get(paramSpec, "options", []), def);
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
},
|
|
137
|
+
response = (await (0, prompt_1.checkbox)({
|
|
138
|
+
default: paramSpec.default
|
|
139
|
+
? paramSpec.default.split(",").map((def) => {
|
|
140
|
+
return getInquirerDefault(_.get(paramSpec, "options", []), def);
|
|
141
|
+
})
|
|
142
|
+
: undefined,
|
|
156
143
|
message: "Which options do you want enabled for this parameter? " +
|
|
157
144
|
"Press Space to select, then Enter to confirm your choices. ",
|
|
158
145
|
choices: (0, utils_1.convertExtensionOptionToLabeledList)(paramSpec.options),
|
|
159
|
-
});
|
|
146
|
+
})).join(",");
|
|
160
147
|
valid = checkResponse(response, paramSpec);
|
|
161
148
|
break;
|
|
162
149
|
case types_1.ParamType.SECRET:
|
|
@@ -175,9 +162,7 @@ async function askForParam(args) {
|
|
|
175
162
|
valid = true;
|
|
176
163
|
break;
|
|
177
164
|
default:
|
|
178
|
-
response = await (0, prompt_1.
|
|
179
|
-
name: paramSpec.param,
|
|
180
|
-
type: "input",
|
|
165
|
+
response = await (0, prompt_1.input)({
|
|
181
166
|
default: paramSpec.default,
|
|
182
167
|
message: `Enter a value for ${label}:`,
|
|
183
168
|
});
|
|
@@ -195,9 +180,7 @@ function isValidSecretLocations(secretLocations, paramSpec) {
|
|
|
195
180
|
}
|
|
196
181
|
async function promptSecretLocations(paramSpec) {
|
|
197
182
|
if (paramSpec.required) {
|
|
198
|
-
return await (0, prompt_1.
|
|
199
|
-
name: "input",
|
|
200
|
-
type: "checkbox",
|
|
183
|
+
return await (0, prompt_1.checkbox)({
|
|
201
184
|
message: "Where would you like to store your secrets? You must select at least one value",
|
|
202
185
|
choices: [
|
|
203
186
|
{
|
|
@@ -213,9 +196,7 @@ async function promptSecretLocations(paramSpec) {
|
|
|
213
196
|
],
|
|
214
197
|
});
|
|
215
198
|
}
|
|
216
|
-
return await (0, prompt_1.
|
|
217
|
-
name: "input",
|
|
218
|
-
type: "checkbox",
|
|
199
|
+
return await (0, prompt_1.checkbox)({
|
|
219
200
|
message: "Where would you like to store your secrets? " +
|
|
220
201
|
"If you don't want to set this optional secret, leave both options unselected to skip it",
|
|
221
202
|
choices: [
|
|
@@ -236,18 +217,13 @@ async function promptLocalSecret(instanceId, paramSpec) {
|
|
|
236
217
|
let value;
|
|
237
218
|
do {
|
|
238
219
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, "Configure a local secret value for Extensions Emulator");
|
|
239
|
-
value = await (0, prompt_1.
|
|
240
|
-
|
|
241
|
-
type: "input",
|
|
242
|
-
message: `This secret will be stored in ./extensions/${instanceId}.secret.local.\n` +
|
|
243
|
-
`Enter value for "${paramSpec.label.trim()}" to be used by Extensions Emulator:`,
|
|
244
|
-
});
|
|
220
|
+
value = await (0, prompt_1.input)(`This secret will be stored in ./extensions/${instanceId}.secret.local.\n` +
|
|
221
|
+
`Enter value for "${paramSpec.label.trim()}" to be used by Extensions Emulator:`);
|
|
245
222
|
} while (!value);
|
|
246
223
|
return value;
|
|
247
224
|
}
|
|
248
225
|
async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
|
|
249
|
-
const action = await (0, prompt_1.
|
|
250
|
-
type: "list",
|
|
226
|
+
const action = await (0, prompt_1.select)({
|
|
251
227
|
message: `Choose what you would like to do with this secret:`,
|
|
252
228
|
choices: [
|
|
253
229
|
{ name: "Leave unchanged", value: SecretUpdateAction.LEAVE },
|
|
@@ -265,11 +241,7 @@ async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
|
|
|
265
241
|
else {
|
|
266
242
|
secretName = await generateSecretName(projectId, instanceId, paramSpec.param);
|
|
267
243
|
}
|
|
268
|
-
const secretValue = await (0, prompt_1.
|
|
269
|
-
name: paramSpec.param,
|
|
270
|
-
type: "password",
|
|
271
|
-
message: `This secret will be stored in Cloud Secret Manager as ${secretName}.\nEnter new value for ${paramSpec.label.trim()}:`,
|
|
272
|
-
});
|
|
244
|
+
const secretValue = await (0, prompt_1.password)(`This secret will be stored in Cloud Secret Manager as ${secretName}.\nEnter new value for ${paramSpec.label.trim()}:`);
|
|
273
245
|
if (secretValue === "" && paramSpec.required) {
|
|
274
246
|
logger_1.logger.info(`Secret value cannot be empty for required param ${paramSpec.param}`);
|
|
275
247
|
return promptReconfigureSecret(projectId, instanceId, paramSpec);
|
|
@@ -296,12 +268,11 @@ async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
|
|
|
296
268
|
}
|
|
297
269
|
async function promptCreateSecret(projectId, instanceId, paramSpec, secretName) {
|
|
298
270
|
const name = secretName !== null && secretName !== void 0 ? secretName : (await generateSecretName(projectId, instanceId, paramSpec.param));
|
|
299
|
-
const secretValue = await (0, prompt_1.
|
|
300
|
-
name: paramSpec.param,
|
|
301
|
-
type: "password",
|
|
302
|
-
default: paramSpec.default,
|
|
271
|
+
const secretValue = (await (0, prompt_1.password)({
|
|
303
272
|
message: `This secret will be stored in Cloud Secret Manager (https://cloud.google.com/secret-manager/pricing) as ${name} and managed by Firebase Extensions (Firebase Extensions Service Agent will be granted Secret Admin role on this secret).\nEnter a value for ${paramSpec.label.trim()}:`,
|
|
304
|
-
})
|
|
273
|
+
})) ||
|
|
274
|
+
paramSpec.default ||
|
|
275
|
+
"";
|
|
305
276
|
if (secretValue === "" && paramSpec.required) {
|
|
306
277
|
logger_1.logger.info(`Secret value cannot be empty for required param ${paramSpec.param}`);
|
|
307
278
|
return promptCreateSecret(projectId, instanceId, paramSpec, name);
|
|
@@ -25,9 +25,7 @@ async function openBillingAccount(projectId, url, open) {
|
|
|
25
25
|
logger_1.logger.debug("Unable to open billing URL: " + err.stack);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
await prompt.
|
|
29
|
-
name: "continue",
|
|
30
|
-
type: "confirm",
|
|
28
|
+
await prompt.confirm({
|
|
31
29
|
message: "Press enter when finished upgrading your project to continue setting up your extension.",
|
|
32
30
|
default: true,
|
|
33
31
|
});
|
|
@@ -36,9 +34,7 @@ async function openBillingAccount(projectId, url, open) {
|
|
|
36
34
|
async function chooseBillingAccount(projectId, accounts) {
|
|
37
35
|
const choices = accounts.map((m) => m.displayName);
|
|
38
36
|
choices.push(ADD_BILLING_ACCOUNT);
|
|
39
|
-
const answer = await prompt.
|
|
40
|
-
name: "billing",
|
|
41
|
-
type: "list",
|
|
37
|
+
const answer = await prompt.select({
|
|
42
38
|
message: `Extensions require your project to be upgraded to the Blaze plan. You have access to the following billing accounts.
|
|
43
39
|
Please select the one that you would like to associate with this project:`,
|
|
44
40
|
choices: choices,
|
|
@@ -61,9 +57,7 @@ async function setUpBillingAccount(projectId) {
|
|
|
61
57
|
logger_1.logger.info();
|
|
62
58
|
logger_1.logger.info(clc.bold(clc.underline(billingURL)));
|
|
63
59
|
logger_1.logger.info();
|
|
64
|
-
const open = await prompt.
|
|
65
|
-
name: "open-url",
|
|
66
|
-
type: "confirm",
|
|
60
|
+
const open = await prompt.confirm({
|
|
67
61
|
message: "Press enter to open the URL.",
|
|
68
62
|
default: true,
|
|
69
63
|
});
|
|
@@ -5,8 +5,8 @@ const extensionsHelper_1 = require("./extensionsHelper");
|
|
|
5
5
|
const getProjectNumber_1 = require("../getProjectNumber");
|
|
6
6
|
const utils = require("../utils");
|
|
7
7
|
const resourceManager = require("../gcp/resourceManager");
|
|
8
|
-
const extensionsApi_1 = require("./extensionsApi");
|
|
9
8
|
const prompt_1 = require("../prompt");
|
|
9
|
+
const extensionsApi_1 = require("./extensionsApi");
|
|
10
10
|
const logger_1 = require("../logger");
|
|
11
11
|
const error_1 = require("../error");
|
|
12
12
|
const SERVICE_AGENT_ROLE = "roles/firebasemods.serviceAgent";
|
|
@@ -36,11 +36,8 @@ async function diagnose(projectId) {
|
|
|
36
36
|
else {
|
|
37
37
|
utils.logWarning("Firebase Extensions Service Agent is missing a required IAM role " +
|
|
38
38
|
"`Firebase Extensions API Service Agent`.");
|
|
39
|
-
const fix = await (0, prompt_1.
|
|
40
|
-
|
|
41
|
-
message: "Would you like to fix the issue by updating IAM policy to include Firebase " +
|
|
42
|
-
"Extensions Service Agent with role `Firebase Extensions API Service Agent`",
|
|
43
|
-
});
|
|
39
|
+
const fix = await (0, prompt_1.confirm)("Would you like to fix the issue by updating IAM policy to include Firebase " +
|
|
40
|
+
"Extensions Service Agent with role `Firebase Extensions API Service Agent`");
|
|
44
41
|
if (fix) {
|
|
45
42
|
policy.bindings.push({
|
|
46
43
|
role: SERVICE_AGENT_ROLE,
|
|
@@ -33,9 +33,9 @@ const storage_1 = require("../gcp/storage");
|
|
|
33
33
|
const projectUtils_1 = require("../projectUtils");
|
|
34
34
|
const extensionsApi_1 = require("./extensionsApi");
|
|
35
35
|
const publisherApi_1 = require("./publisherApi");
|
|
36
|
+
const prompt_1 = require("../prompt");
|
|
36
37
|
const refs = require("./refs");
|
|
37
38
|
const localHelper_1 = require("./localHelper");
|
|
38
|
-
const prompt_1 = require("../prompt");
|
|
39
39
|
const logger_1 = require("../logger");
|
|
40
40
|
const utils_2 = require("../utils");
|
|
41
41
|
const change_log_1 = require("./change-log");
|
|
@@ -309,8 +309,7 @@ async function promptForValidInstanceId(instanceId) {
|
|
|
309
309
|
let newInstanceId = "";
|
|
310
310
|
const instanceIdRegex = /^[a-z][a-z\d\-]*[a-z\d]$/;
|
|
311
311
|
while (!instanceIdIsValid) {
|
|
312
|
-
newInstanceId = await (0, prompt_1.
|
|
313
|
-
type: "input",
|
|
312
|
+
newInstanceId = await (0, prompt_1.input)({
|
|
314
313
|
default: instanceId,
|
|
315
314
|
message: `Please enter a new name for this instance:`,
|
|
316
315
|
});
|
|
@@ -332,10 +331,7 @@ async function promptForValidRepoURI() {
|
|
|
332
331
|
let repoIsValid = false;
|
|
333
332
|
let extensionRoot = "";
|
|
334
333
|
while (!repoIsValid) {
|
|
335
|
-
extensionRoot = await (0, prompt_1.
|
|
336
|
-
type: "input",
|
|
337
|
-
message: "Enter the GitHub repo URI where this extension's source code is located:",
|
|
338
|
-
});
|
|
334
|
+
extensionRoot = await (0, prompt_1.input)("Enter the GitHub repo URI where this extension's source code is located:");
|
|
339
335
|
if (!repoRegex.test(extensionRoot)) {
|
|
340
336
|
logger_1.logger.info("Repo URI must follow this format: https://github.com/<user>/<repo>");
|
|
341
337
|
}
|
|
@@ -347,8 +343,7 @@ async function promptForValidRepoURI() {
|
|
|
347
343
|
}
|
|
348
344
|
exports.promptForValidRepoURI = promptForValidRepoURI;
|
|
349
345
|
async function promptForExtensionRoot(defaultRoot) {
|
|
350
|
-
return await (0, prompt_1.
|
|
351
|
-
type: "input",
|
|
346
|
+
return await (0, prompt_1.input)({
|
|
352
347
|
message: "Enter this extension's root directory in the repo (defaults to previous root if set):",
|
|
353
348
|
default: defaultRoot,
|
|
354
349
|
});
|
|
@@ -369,22 +364,20 @@ async function promptForReleaseStage(args) {
|
|
|
369
364
|
};
|
|
370
365
|
choices.push(stableChoice);
|
|
371
366
|
}
|
|
372
|
-
stage = await (0, prompt_1.
|
|
373
|
-
type: "list",
|
|
367
|
+
stage = await (0, prompt_1.select)({
|
|
374
368
|
message: "Choose the release stage:",
|
|
375
369
|
choices: choices,
|
|
376
370
|
default: stage,
|
|
377
371
|
});
|
|
378
372
|
if (stage === "stable" && !args.hasVersions) {
|
|
379
|
-
logger_1.logger.info(`${clc.bold(clc.yellow("Warning:"))} It's highly recommended to first upload a pre-release version before choosing stable.`);
|
|
380
373
|
const confirmed = await (0, prompt_1.confirm)({
|
|
374
|
+
message: `${clc.bold(clc.yellow("Warning:"))} It's highly recommended to first upload a pre-release version before choosing stable.`,
|
|
381
375
|
nonInteractive: args.nonInteractive,
|
|
382
376
|
force: args.force,
|
|
383
377
|
default: false,
|
|
384
378
|
});
|
|
385
379
|
if (!confirmed) {
|
|
386
|
-
stage = await (0, prompt_1.
|
|
387
|
-
type: "list",
|
|
380
|
+
stage = await (0, prompt_1.select)({
|
|
388
381
|
message: "Choose the release stage:",
|
|
389
382
|
choices: choices,
|
|
390
383
|
default: stage,
|
|
@@ -605,8 +598,7 @@ async function uploadExtensionVersionFromGitHubSource(args) {
|
|
|
605
598
|
const defaultSourceRef = "HEAD";
|
|
606
599
|
if (!sourceRef) {
|
|
607
600
|
if (!args.nonInteractive) {
|
|
608
|
-
sourceRef = await (0, prompt_1.
|
|
609
|
-
type: "input",
|
|
601
|
+
sourceRef = await (0, prompt_1.input)({
|
|
610
602
|
message: "Enter the commit hash, branch, or tag name to build from in the repo:",
|
|
611
603
|
default: defaultSourceRef,
|
|
612
604
|
});
|
|
@@ -645,6 +637,7 @@ async function uploadExtensionVersionFromGitHubSource(args) {
|
|
|
645
637
|
autoReview: stage === "stable" && autoReview,
|
|
646
638
|
});
|
|
647
639
|
const confirmed = await (0, prompt_1.confirm)({
|
|
640
|
+
message: "Continue?",
|
|
648
641
|
nonInteractive: args.nonInteractive,
|
|
649
642
|
force: args.force,
|
|
650
643
|
default: false,
|
|
@@ -713,6 +706,7 @@ async function uploadExtensionVersionFromLocalSource(args) {
|
|
|
713
706
|
const releaseNotes = validateReleaseNotes(args.rootDirectory, extensionSpec.version, extension);
|
|
714
707
|
displayReleaseNotes({ extensionRef, newVersion, releaseNotes, autoReview: false });
|
|
715
708
|
const confirmed = await (0, prompt_1.confirm)({
|
|
709
|
+
message: "Continue?",
|
|
716
710
|
nonInteractive: args.nonInteractive,
|
|
717
711
|
force: args.force,
|
|
718
712
|
default: false,
|
|
@@ -818,9 +812,7 @@ function displayReleaseNotes(args) {
|
|
|
818
812
|
exports.displayReleaseNotes = displayReleaseNotes;
|
|
819
813
|
async function promptForOfficialExtension(message) {
|
|
820
814
|
const officialExts = await (0, resolveSource_1.getExtensionRegistry)(true);
|
|
821
|
-
return await (0, prompt_1.
|
|
822
|
-
name: "input",
|
|
823
|
-
type: "list",
|
|
815
|
+
return await (0, prompt_1.select)({
|
|
824
816
|
message,
|
|
825
817
|
choices: (0, utils_1.convertOfficialExtensionsToList)(officialExts),
|
|
826
818
|
pageSize: Object.keys(officialExts).length,
|
|
@@ -829,15 +821,13 @@ async function promptForOfficialExtension(message) {
|
|
|
829
821
|
exports.promptForOfficialExtension = promptForOfficialExtension;
|
|
830
822
|
async function promptForRepeatInstance(projectName, extensionName) {
|
|
831
823
|
const message = `An extension with the ID '${clc.bold(extensionName)}' already exists in the project '${clc.bold(projectName)}'. What would you like to do?`;
|
|
832
|
-
|
|
833
|
-
{ name: "Update or reconfigure the existing instance", value: "updateExisting" },
|
|
834
|
-
{ name: "Install a new instance with a different ID", value: "installNew" },
|
|
835
|
-
{ name: "Cancel extension installation", value: "cancel" },
|
|
836
|
-
];
|
|
837
|
-
return await (0, prompt_1.promptOnce)({
|
|
838
|
-
type: "list",
|
|
824
|
+
return await (0, prompt_1.select)({
|
|
839
825
|
message,
|
|
840
|
-
choices
|
|
826
|
+
choices: [
|
|
827
|
+
{ name: "Update or reconfigure the existing instance", value: "updateExisting" },
|
|
828
|
+
{ name: "Install a new instance with a different ID", value: "installNew" },
|
|
829
|
+
{ name: "Cancel extension installation", value: "cancel" },
|
|
830
|
+
],
|
|
841
831
|
});
|
|
842
832
|
}
|
|
843
833
|
exports.promptForRepeatInstance = promptForRepeatInstance;
|
|
@@ -24,8 +24,7 @@ async function writeToManifest(specs, config, options, allowOverwrite = false) {
|
|
|
24
24
|
.map((i) => `${i[0]}: ${i[1]}`)
|
|
25
25
|
.join("\n\t");
|
|
26
26
|
if (allowOverwrite) {
|
|
27
|
-
const overwrite = await (0, prompt_1.
|
|
28
|
-
type: "list",
|
|
27
|
+
const overwrite = await (0, prompt_1.select)({
|
|
29
28
|
message: `firebase.json already contains extensions:\n${currentExtensions}\nWould you like to overwrite or merge?`,
|
|
30
29
|
choices: [
|
|
31
30
|
{ name: "Overwrite", value: true },
|
package/lib/extensions/tos.js
CHANGED
|
@@ -49,7 +49,11 @@ async function acceptLatestPublisherTOS(options, projectId) {
|
|
|
49
49
|
else {
|
|
50
50
|
const tosLink = extensionsTosUrl("publisher");
|
|
51
51
|
logger_1.logger.info(`To continue, you must accept the Firebase Extensions Publisher Terms of Service: ${tosLink}`);
|
|
52
|
-
if (await (0, prompt_1.confirm)(
|
|
52
|
+
if (await (0, prompt_1.confirm)({
|
|
53
|
+
message: "Do you accept the Firebase Extensions Publisher Terms of Service?",
|
|
54
|
+
nonInteractive: options.nonInteractive,
|
|
55
|
+
force: options.force,
|
|
56
|
+
})) {
|
|
53
57
|
return acceptPublisherTOS(projectId, currentAcceptance.latestTosVersion);
|
|
54
58
|
}
|
|
55
59
|
}
|
|
@@ -69,7 +73,11 @@ async function acceptLatestAppDeveloperTOS(options, projectId, instanceIds) {
|
|
|
69
73
|
if (currentAcceptance.lastAcceptedVersion) {
|
|
70
74
|
logger_1.logger.debug(`User Terms of Service aready accepted on project ${projectId}.`);
|
|
71
75
|
}
|
|
72
|
-
else if (!(await (0, prompt_1.confirm)(
|
|
76
|
+
else if (!(await (0, prompt_1.confirm)({
|
|
77
|
+
message: "Do you accept the Firebase Extensions User Terms of Service?",
|
|
78
|
+
nonInteractive: options.nonInteractive,
|
|
79
|
+
force: options.force,
|
|
80
|
+
}))) {
|
|
73
81
|
throw new error_1.FirebaseError("You must accept the terms of service to continue.");
|
|
74
82
|
}
|
|
75
83
|
const tosPromises = instanceIds.map((instanceId) => {
|
package/lib/extensions/utils.js
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getResourceRuntime = exports.formatTimestamp = exports.getRandomString = exports.convertOfficialExtensionsToList = exports.convertExtensionOptionToLabeledList =
|
|
4
|
-
const prompt_1 = require("../prompt");
|
|
3
|
+
exports.getResourceRuntime = exports.formatTimestamp = exports.getRandomString = exports.convertOfficialExtensionsToList = exports.convertExtensionOptionToLabeledList = void 0;
|
|
5
4
|
const types_1 = require("./types");
|
|
6
|
-
async function onceWithJoin(question) {
|
|
7
|
-
const response = await (0, prompt_1.promptOnce)(question);
|
|
8
|
-
if (Array.isArray(response)) {
|
|
9
|
-
return response.join(",");
|
|
10
|
-
}
|
|
11
|
-
return response;
|
|
12
|
-
}
|
|
13
|
-
exports.onceWithJoin = onceWithJoin;
|
|
14
5
|
function convertExtensionOptionToLabeledList(options) {
|
|
15
6
|
return options.map((option) => {
|
|
16
7
|
return {
|
package/lib/frameworks/index.js
CHANGED
|
@@ -177,8 +177,7 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
|
|
|
177
177
|
console.warn(`No Firebase app associated with site ${site}, unable to provide authenticated server context.
|
|
178
178
|
You can link a Web app to a Hosting site here https://console.firebase.google.com/project/${project}/settings/general/web`);
|
|
179
179
|
if (!options.nonInteractive) {
|
|
180
|
-
const continueDeploy = await (0, prompt_1.
|
|
181
|
-
type: "confirm",
|
|
180
|
+
const continueDeploy = await (0, prompt_1.confirm)({
|
|
182
181
|
default: true,
|
|
183
182
|
message: "Would you like to continue with the deploy?",
|
|
184
183
|
});
|
|
@@ -205,13 +205,16 @@ async function build(dir, target, context) {
|
|
|
205
205
|
}
|
|
206
206
|
exports.build = build;
|
|
207
207
|
async function init(setup, config) {
|
|
208
|
-
const language = await (0, prompt_1.
|
|
209
|
-
type: "list",
|
|
208
|
+
const language = await (0, prompt_1.select)({
|
|
210
209
|
default: "TypeScript",
|
|
211
210
|
message: "What language would you like to use?",
|
|
212
|
-
choices: [
|
|
211
|
+
choices: [
|
|
212
|
+
{ name: "JavaScript", value: "js" },
|
|
213
|
+
{ name: "TypeScript", value: "ts" },
|
|
214
|
+
],
|
|
213
215
|
});
|
|
214
|
-
(0, child_process_1.execSync)(`npx --yes create-next-app@"${exports.supportedRange}" -e hello-world
|
|
216
|
+
(0, child_process_1.execSync)(`npx --yes create-next-app@"${exports.supportedRange}" -e hello-world ` +
|
|
217
|
+
`${setup.hosting.source} --use-npm --${language}`, { stdio: "inherit", cwd: config.projectDir });
|
|
215
218
|
}
|
|
216
219
|
exports.init = init;
|
|
217
220
|
async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
|
|
@@ -17,8 +17,7 @@ exports.DEFAULT_BUILD_SCRIPT = ["vite build", "tsc && vite build"];
|
|
|
17
17
|
const initViteTemplate = (template) => async (setup, config) => await init(setup, config, template);
|
|
18
18
|
exports.initViteTemplate = initViteTemplate;
|
|
19
19
|
async function init(setup, config, baseTemplate = "vanilla") {
|
|
20
|
-
const template = await (0, prompt_1.
|
|
21
|
-
type: "list",
|
|
20
|
+
const template = await (0, prompt_1.select)({
|
|
22
21
|
default: "JavaScript",
|
|
23
22
|
message: "What language would you like to use?",
|
|
24
23
|
choices: [
|