firebase-tools 13.24.2 → 13.26.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/appdistribution/client.js +62 -8
- package/lib/appdistribution/distribution.js +1 -1
- package/lib/apphosting/backend.js +4 -4
- package/lib/apphosting/config.js +2 -10
- package/lib/apphosting/secrets/index.js +7 -7
- package/lib/archiveDirectory.js +1 -1
- package/lib/auth.js +5 -3
- package/lib/command.js +9 -1
- package/lib/commands/appdistribution-distribute.js +4 -4
- package/lib/commands/{appdistribution-group-create.js → appdistribution-groups-create.js} +2 -1
- package/lib/commands/{appdistribution-group-delete.js → appdistribution-groups-delete.js} +3 -2
- package/lib/commands/appdistribution-groups-list.js +56 -0
- package/lib/commands/appdistribution-testers-list.js +54 -0
- package/lib/commands/appdistribution-testers-remove.js +1 -1
- package/lib/commands/apphosting-backends-delete.js +3 -1
- package/lib/commands/apphosting-backends-get.js +1 -1
- package/lib/commands/database-import.js +4 -2
- package/lib/commands/database-push.js +4 -2
- package/lib/commands/database-set.js +4 -2
- package/lib/commands/database-settings-get.js +1 -1
- package/lib/commands/database-settings-set.js +1 -1
- package/lib/commands/ext-dev-init.js +2 -2
- package/lib/commands/ext-dev-list.js +1 -1
- package/lib/commands/ext-dev-register.js +2 -2
- package/lib/commands/ext-dev-upload.js +2 -2
- package/lib/commands/ext-dev-usage.js +2 -2
- package/lib/commands/ext-install.js +2 -2
- package/lib/commands/index.js +5 -2
- package/lib/commands/use.js +1 -1
- package/lib/deploy/extensions/deploy.js +3 -1
- package/lib/deploy/extensions/deploymentSummary.js +4 -1
- package/lib/deploy/extensions/planner.js +14 -3
- package/lib/deploy/extensions/prepare.js +9 -9
- package/lib/deploy/functions/ensure.js +1 -1
- package/lib/deploy/lifecycleHooks.js +2 -1
- package/lib/emulator/apphosting/config.js +13 -3
- package/lib/emulator/apphosting/index.js +1 -0
- package/lib/emulator/apphosting/serve.js +9 -7
- package/lib/emulator/controller.js +3 -2
- package/lib/emulator/dataconnectEmulator.js +13 -12
- package/lib/emulator/downloadableEmulators.js +11 -11
- package/lib/emulator/emulatorLogger.js +3 -0
- package/lib/emulator/hub.js +10 -7
- package/lib/emulator/tasksEmulator.js +5 -2
- package/lib/emulator/ui.js +47 -25
- package/lib/error.js +8 -1
- package/lib/getProjectNumber.js +1 -1
- package/lib/init/features/genkit/index.js +417 -0
- package/lib/init/features/project.js +7 -6
- package/lib/logger.js +2 -2
- package/lib/management/projects.js +24 -4
- package/lib/projectUtils.js +1 -1
- package/lib/requireDatabaseInstance.js +1 -1
- package/lib/requirePermissions.js +1 -1
- package/lib/rulesDeploy.js +1 -1
- package/lib/templates.js +2 -2
- package/lib/utils.js +5 -8
- package/lib/vsCodeUtils.js +8 -0
- package/package.json +2 -2
- package/schema/firebase-config.json +3 -0
- package/templates/genkit/firebase.0.9.0.template +57 -0
- package/lib/init/features/genkit.js +0 -54
|
@@ -44,13 +44,13 @@ async function uploadExtensionAction(extensionRef, options) {
|
|
|
44
44
|
profile = await (0, publisherApi_1.getPublisherProfile)("-", publisherId);
|
|
45
45
|
}
|
|
46
46
|
catch (err) {
|
|
47
|
-
if (err
|
|
47
|
+
if ((0, error_1.getErrStatus)(err) === 404) {
|
|
48
48
|
throw (0, extensionsHelper_1.getMissingPublisherError)(publisherId);
|
|
49
49
|
}
|
|
50
50
|
throw err;
|
|
51
51
|
}
|
|
52
52
|
const projectNumber = `${(0, extensionsHelper_2.getPublisherProjectFromName)(profile.name)}`;
|
|
53
|
-
const { projectId } = await (0, projects_1.
|
|
53
|
+
const { projectId } = await (0, projects_1.getProject)(projectNumber);
|
|
54
54
|
await (0, tos_1.acceptLatestPublisherTOS)(options, projectNumber);
|
|
55
55
|
let res;
|
|
56
56
|
if (options.local) {
|
|
@@ -36,7 +36,7 @@ exports.command = new command_1.Command("ext:dev:usage <publisherId>")
|
|
|
36
36
|
extensions = await (0, publisherApi_1.listExtensions)(publisherId);
|
|
37
37
|
}
|
|
38
38
|
catch (err) {
|
|
39
|
-
throw new error_1.FirebaseError(err);
|
|
39
|
+
throw new error_1.FirebaseError((0, error_1.getErrMsg)(err));
|
|
40
40
|
}
|
|
41
41
|
if (extensions.length < 1) {
|
|
42
42
|
throw new error_1.FirebaseError(`There are no published extensions associated with publisher ID ${clc.bold(publisherId)}. This could happen for two reasons:\n` +
|
|
@@ -77,7 +77,7 @@ exports.command = new command_1.Command("ext:dev:usage <publisherId>")
|
|
|
77
77
|
}
|
|
78
78
|
catch (err) {
|
|
79
79
|
throw new error_1.FirebaseError(`Error occurred when fetching usage data for extension ${extensionName}`, {
|
|
80
|
-
original: err,
|
|
80
|
+
original: (0, error_1.getError)(err),
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
83
|
if (!response) {
|
|
@@ -110,8 +110,8 @@ exports.command = new command_1.Command("ext:install [extensionRef]")
|
|
|
110
110
|
}
|
|
111
111
|
catch (err) {
|
|
112
112
|
if (!(err instanceof error_1.FirebaseError)) {
|
|
113
|
-
throw new error_1.FirebaseError(`Error occurred saving the extension to manifest: ${err
|
|
114
|
-
original: err,
|
|
113
|
+
throw new error_1.FirebaseError(`Error occurred saving the extension to manifest: ${(0, error_1.getErrMsg)(err)}`, {
|
|
114
|
+
original: (0, error_1.getError)(err),
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
throw err;
|
package/lib/commands/index.js
CHANGED
|
@@ -17,11 +17,14 @@ function load(client) {
|
|
|
17
17
|
client.appdistribution = {};
|
|
18
18
|
client.appdistribution.distribute = loadCommand("appdistribution-distribute");
|
|
19
19
|
client.appdistribution.testers = {};
|
|
20
|
+
client.appdistribution.testers.list = loadCommand("appdistribution-testers-list");
|
|
20
21
|
client.appdistribution.testers.add = loadCommand("appdistribution-testers-add");
|
|
21
22
|
client.appdistribution.testers.delete = loadCommand("appdistribution-testers-remove");
|
|
22
23
|
client.appdistribution.group = {};
|
|
23
|
-
client.appdistribution.group.
|
|
24
|
-
client.appdistribution.group.
|
|
24
|
+
client.appdistribution.group.list = loadCommand("appdistribution-groups-list");
|
|
25
|
+
client.appdistribution.group.create = loadCommand("appdistribution-groups-create");
|
|
26
|
+
client.appdistribution.group.delete = loadCommand("appdistribution-groups-delete");
|
|
27
|
+
client.appdistribution.groups = client.appdistribution.group;
|
|
25
28
|
client.apps = {};
|
|
26
29
|
client.apps.create = loadCommand("apps-create");
|
|
27
30
|
client.apps.list = loadCommand("apps-list");
|
package/lib/commands/use.js
CHANGED
|
@@ -53,7 +53,7 @@ exports.command = new command_1.Command("use [alias_or_project_id]")
|
|
|
53
53
|
const hasAlias = options.rc.hasProjectAlias(newActive);
|
|
54
54
|
const resolvedProject = options.rc.resolveAlias(newActive);
|
|
55
55
|
(0, command_2.validateProjectId)(resolvedProject);
|
|
56
|
-
return (0, projects_1.
|
|
56
|
+
return (0, projects_1.getProject)(resolvedProject)
|
|
57
57
|
.then((foundProject) => {
|
|
58
58
|
project = foundProject;
|
|
59
59
|
})
|
|
@@ -18,7 +18,9 @@ async function deploy(context, options, payload) {
|
|
|
18
18
|
...((_b = payload.instancesToUpdate) !== null && _b !== void 0 ? _b : []),
|
|
19
19
|
...((_c = payload.instancesToConfigure) !== null && _c !== void 0 ? _c : []),
|
|
20
20
|
]);
|
|
21
|
-
|
|
21
|
+
if (context.have) {
|
|
22
|
+
await (0, secrets_1.handleSecretParams)(payload, context.have, options.nonInteractive);
|
|
23
|
+
}
|
|
22
24
|
const errorHandler = new errors_1.ErrorHandler();
|
|
23
25
|
const validationQueue = new queue_1.default({
|
|
24
26
|
retries: 5,
|
|
@@ -11,7 +11,7 @@ const humanReadableUpdate = (from, to) => {
|
|
|
11
11
|
to.ref &&
|
|
12
12
|
from.ref.publisherId === to.ref.publisherId &&
|
|
13
13
|
from.ref.extensionId === to.ref.extensionId) {
|
|
14
|
-
return `\t${clc.bold(from.instanceId)} (${refs.toExtensionVersionRef(from.ref)} => ${(_a = to.ref) === null || _a === void 0 ? void 0 : _a.version})`;
|
|
14
|
+
return `\t${clc.bold(from.instanceId)} (${refs.toExtensionVersionRef(from.ref)} => ${((_a = to.ref) === null || _a === void 0 ? void 0 : _a.version) || ""})`;
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
17
17
|
const fromRef = from.ref
|
|
@@ -32,6 +32,9 @@ function updatesSummary(toUpdate, have) {
|
|
|
32
32
|
const instancesToUpdate = toUpdate
|
|
33
33
|
.map((to) => {
|
|
34
34
|
const from = have.find((exists) => exists.instanceId === to.instanceId);
|
|
35
|
+
if (!from) {
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
35
38
|
return humanReadableUpdate(from, to);
|
|
36
39
|
})
|
|
37
40
|
.join("\n");
|
|
@@ -46,6 +46,9 @@ async function getExtensionSpec(i) {
|
|
|
46
46
|
throw new error_1.FirebaseError("InstanceSpec had no ref or localPath, unable to get extensionSpec");
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
if (!i.extensionSpec) {
|
|
50
|
+
throw new error_1.FirebaseError("Internal error getting extension");
|
|
51
|
+
}
|
|
49
52
|
return i.extensionSpec;
|
|
50
53
|
}
|
|
51
54
|
exports.getExtensionSpec = getExtensionSpec;
|
|
@@ -54,8 +57,12 @@ async function haveDynamic(projectId) {
|
|
|
54
57
|
.filter((i) => { var _a; return ((_a = i.labels) === null || _a === void 0 ? void 0 : _a.createdBy) === "SDK"; })
|
|
55
58
|
.map((i) => {
|
|
56
59
|
var _a;
|
|
60
|
+
const instanceId = i.name.split("/").pop();
|
|
61
|
+
if (!instanceId) {
|
|
62
|
+
throw new error_1.FirebaseError(`Internal error getting instanceId from ${i.name}`);
|
|
63
|
+
}
|
|
57
64
|
const dep = {
|
|
58
|
-
instanceId
|
|
65
|
+
instanceId,
|
|
59
66
|
params: i.config.params,
|
|
60
67
|
systemParams: (_a = i.config.systemParams) !== null && _a !== void 0 ? _a : {},
|
|
61
68
|
allowedEventTypes: i.config.allowedEventTypes,
|
|
@@ -77,8 +84,12 @@ async function have(projectId) {
|
|
|
77
84
|
.filter((i) => { var _a; return !(((_a = i.labels) === null || _a === void 0 ? void 0 : _a.createdBy) === "SDK"); })
|
|
78
85
|
.map((i) => {
|
|
79
86
|
var _a;
|
|
87
|
+
const instanceId = i.name.split("/").pop();
|
|
88
|
+
if (!instanceId) {
|
|
89
|
+
throw new error_1.FirebaseError(`Internal error getting instanceId from ${i.name}`);
|
|
90
|
+
}
|
|
80
91
|
const dep = {
|
|
81
|
-
instanceId
|
|
92
|
+
instanceId,
|
|
82
93
|
params: i.config.params,
|
|
83
94
|
systemParams: (_a = i.config.systemParams) !== null && _a !== void 0 ? _a : {},
|
|
84
95
|
allowedEventTypes: i.config.allowedEventTypes,
|
|
@@ -196,7 +207,7 @@ async function want(args) {
|
|
|
196
207
|
}
|
|
197
208
|
}
|
|
198
209
|
catch (err) {
|
|
199
|
-
logger_1.logger.debug(`Got error reading extensions entry ${e}: ${err}`);
|
|
210
|
+
logger_1.logger.debug(`Got error reading extensions entry ${e[0]} (${e[1]}): ${(0, error_1.getErrMsg)(err)}`);
|
|
200
211
|
errors.push(err);
|
|
201
212
|
}
|
|
202
213
|
}
|
|
@@ -18,6 +18,15 @@ const v2FunctionHelper_1 = require("./v2FunctionHelper");
|
|
|
18
18
|
const tos_1 = require("../../extensions/tos");
|
|
19
19
|
const common_1 = require("../../extensions/runtimes/common");
|
|
20
20
|
const functionsDeployHelper_1 = require("../functions/functionsDeployHelper");
|
|
21
|
+
const matchesInstanceId = (dep) => (test) => {
|
|
22
|
+
return dep.instanceId === test.instanceId;
|
|
23
|
+
};
|
|
24
|
+
const isUpdate = (dep) => (test) => {
|
|
25
|
+
return dep.instanceId === test.instanceId && !refs.equal(dep.ref, test.ref);
|
|
26
|
+
};
|
|
27
|
+
const isConfigure = (dep) => (test) => {
|
|
28
|
+
return dep.instanceId === test.instanceId && refs.equal(dep.ref, test.ref);
|
|
29
|
+
};
|
|
21
30
|
async function prepareHelper(context, options, payload, wantExtensions, haveExtensions, isDynamic) {
|
|
22
31
|
var _a, _b;
|
|
23
32
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
@@ -146,12 +155,3 @@ async function prepare(context, options, payload) {
|
|
|
146
155
|
return prepareHelper(context, options, payload, wantExtensions, haveExtensions, false);
|
|
147
156
|
}
|
|
148
157
|
exports.prepare = prepare;
|
|
149
|
-
const matchesInstanceId = (dep) => (test) => {
|
|
150
|
-
return dep.instanceId === test.instanceId;
|
|
151
|
-
};
|
|
152
|
-
const isUpdate = (dep) => (test) => {
|
|
153
|
-
return dep.instanceId === test.instanceId && !refs.equal(dep.ref, test.ref);
|
|
154
|
-
};
|
|
155
|
-
const isConfigure = (dep) => (test) => {
|
|
156
|
-
return dep.instanceId === test.instanceId && refs.equal(dep.ref, test.ref);
|
|
157
|
-
};
|
|
@@ -15,7 +15,7 @@ const metadataCallCache = new Map();
|
|
|
15
15
|
async function defaultServiceAccount(e) {
|
|
16
16
|
let metadataCall = metadataCallCache.get(e.project);
|
|
17
17
|
if (!metadataCall) {
|
|
18
|
-
metadataCall = (0, projects_1.
|
|
18
|
+
metadataCall = (0, projects_1.getProject)(e.project);
|
|
19
19
|
metadataCallCache.set(e.project, metadataCall);
|
|
20
20
|
}
|
|
21
21
|
const metadata = await metadataCall;
|
|
@@ -8,9 +8,10 @@ const error_1 = require("../error");
|
|
|
8
8
|
const needProjectId = require("../projectUtils").needProjectId;
|
|
9
9
|
const logger_1 = require("../logger");
|
|
10
10
|
const path = require("path");
|
|
11
|
+
const vsCodeUtils_1 = require("../vsCodeUtils");
|
|
11
12
|
function runCommand(command, childOptions) {
|
|
12
13
|
const escapedCommand = command.replace(/\"/g, '\\"');
|
|
13
|
-
const isVSCode =
|
|
14
|
+
const isVSCode = (0, vsCodeUtils_1.isVSCodeExtension)();
|
|
14
15
|
const nodeExecutable = isVSCode ? "node" : process.execPath;
|
|
15
16
|
const crossEnvShellPath = isVSCode
|
|
16
17
|
? path.resolve(__dirname, "./cross-env/dist/bin/cross-env-shell.js")
|
|
@@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getLocalAppHostingConfiguration = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
const config_1 = require("../../apphosting/config");
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const yaml_1 = require("../../apphosting/yaml");
|
|
7
|
+
async function getLocalAppHostingConfiguration(backendDir) {
|
|
8
|
+
const appHostingConfigPaths = (0, config_1.listAppHostingFilesInPath)(backendDir);
|
|
8
9
|
const fileNameToPathMap = new Map();
|
|
9
10
|
for (const path of appHostingConfigPaths) {
|
|
10
11
|
const fileName = (0, path_1.basename)(path);
|
|
@@ -12,6 +13,15 @@ async function getLocalAppHostingConfiguration(cwd) {
|
|
|
12
13
|
}
|
|
13
14
|
const baseFilePath = fileNameToPathMap.get(config_1.APPHOSTING_BASE_YAML_FILE);
|
|
14
15
|
const localFilePath = fileNameToPathMap.get(config_1.APPHOSTING_LOCAL_YAML_FILE);
|
|
15
|
-
|
|
16
|
+
if (!baseFilePath && !localFilePath) {
|
|
17
|
+
return yaml_1.AppHostingYamlConfig.empty();
|
|
18
|
+
}
|
|
19
|
+
if (!baseFilePath || !localFilePath) {
|
|
20
|
+
return await yaml_1.AppHostingYamlConfig.loadFromFile((baseFilePath || localFilePath));
|
|
21
|
+
}
|
|
22
|
+
const localYamlConfig = await yaml_1.AppHostingYamlConfig.loadFromFile(localFilePath);
|
|
23
|
+
const baseConfig = await yaml_1.AppHostingYamlConfig.loadFromFile(baseFilePath);
|
|
24
|
+
baseConfig.merge(localYamlConfig);
|
|
25
|
+
return baseConfig;
|
|
16
26
|
}
|
|
17
27
|
exports.getLocalAppHostingConfiguration = getLocalAppHostingConfiguration;
|
|
@@ -11,6 +11,7 @@ class AppHostingEmulator {
|
|
|
11
11
|
async start() {
|
|
12
12
|
const { hostname, port } = await (0, serve_1.start)({
|
|
13
13
|
startCommand: this.args.startCommandOverride,
|
|
14
|
+
rootDirectory: this.args.rootDirectory,
|
|
14
15
|
});
|
|
15
16
|
this.args.options.host = hostname;
|
|
16
17
|
this.args.options.port = port;
|
|
@@ -9,19 +9,21 @@ const spawn_1 = require("../../init/spawn");
|
|
|
9
9
|
const utils_2 = require("./utils");
|
|
10
10
|
const types_1 = require("../types");
|
|
11
11
|
const config_1 = require("./config");
|
|
12
|
+
const projectPath_1 = require("../../projectPath");
|
|
12
13
|
async function start(options) {
|
|
13
14
|
const hostname = constants_1.DEFAULT_HOST;
|
|
14
15
|
let port = constants_1.DEFAULT_PORTS.apphosting;
|
|
15
16
|
while (!(await availablePort(hostname, port))) {
|
|
16
17
|
port += 1;
|
|
17
18
|
}
|
|
18
|
-
serve(port, options === null || options === void 0 ? void 0 : options.startCommand);
|
|
19
|
+
serve(port, options === null || options === void 0 ? void 0 : options.startCommand, options === null || options === void 0 ? void 0 : options.rootDirectory);
|
|
19
20
|
return { hostname, port };
|
|
20
21
|
}
|
|
21
22
|
exports.start = start;
|
|
22
|
-
async function serve(port, startCommand) {
|
|
23
|
-
|
|
24
|
-
const
|
|
23
|
+
async function serve(port, startCommand, backendRelativeDir) {
|
|
24
|
+
backendRelativeDir = backendRelativeDir !== null && backendRelativeDir !== void 0 ? backendRelativeDir : "./";
|
|
25
|
+
const backendRoot = (0, projectPath_1.resolveProjectPath)({}, backendRelativeDir);
|
|
26
|
+
const apphostingLocalConfig = await (0, config_1.getLocalAppHostingConfiguration)(backendRoot);
|
|
25
27
|
const environmentVariablesAsRecord = {};
|
|
26
28
|
for (const env of apphostingLocalConfig.environmentVariables) {
|
|
27
29
|
environmentVariablesAsRecord[env.variable] = env.value;
|
|
@@ -29,12 +31,12 @@ async function serve(port, startCommand) {
|
|
|
29
31
|
const environmentVariablesToInject = Object.assign(Object.assign({}, environmentVariablesAsRecord), { PORT: port.toString() });
|
|
30
32
|
if (startCommand) {
|
|
31
33
|
utils_2.logger.logLabeled("BULLET", types_1.Emulators.APPHOSTING, `running custom start command: '${startCommand}'`);
|
|
32
|
-
await (0, spawn_1.spawnWithCommandString)(startCommand,
|
|
34
|
+
await (0, spawn_1.spawnWithCommandString)(startCommand, backendRoot, environmentVariablesToInject);
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
|
-
const packageManager = await (0, utils_1.discoverPackageManager)(
|
|
37
|
+
const packageManager = await (0, utils_1.discoverPackageManager)(backendRoot);
|
|
36
38
|
utils_2.logger.logLabeled("BULLET", types_1.Emulators.APPHOSTING, `starting app with: '${packageManager} run dev'`);
|
|
37
|
-
await (0, spawn_1.wrapSpawn)(packageManager, ["run", "dev"],
|
|
39
|
+
await (0, spawn_1.wrapSpawn)(packageManager, ["run", "dev"], backendRoot, environmentVariablesToInject);
|
|
38
40
|
}
|
|
39
41
|
function availablePort(host, port) {
|
|
40
42
|
return (0, portUtils_1.checkListenable)({
|
|
@@ -47,6 +47,7 @@ const fileUtils_1 = require("../dataconnect/fileUtils");
|
|
|
47
47
|
const tasksEmulator_1 = require("./tasksEmulator");
|
|
48
48
|
const apphosting_1 = require("./apphosting");
|
|
49
49
|
const webhook_1 = require("../dataconnect/webhook");
|
|
50
|
+
const api_1 = require("../api");
|
|
50
51
|
const START_LOGGING_EMULATOR = utils.envOverride("START_LOGGING_EMULATOR", "false", (val) => val === "true");
|
|
51
52
|
async function exportOnExit(options) {
|
|
52
53
|
const exportOnExitDir = options.exportOnExit;
|
|
@@ -264,7 +265,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
264
265
|
portFixed: !!wsPortConfig,
|
|
265
266
|
};
|
|
266
267
|
}
|
|
267
|
-
if (emulator === types_1.Emulators.DATACONNECT) {
|
|
268
|
+
if (emulator === types_1.Emulators.DATACONNECT && !(0, api_1.dataConnectLocalConnString)()) {
|
|
268
269
|
const pglitePortConfig = (_f = (_e = options.config.src.emulators) === null || _e === void 0 ? void 0 : _e.dataconnect) === null || _f === void 0 ? void 0 : _f.postgresPort;
|
|
269
270
|
listenConfig["dataconnect.postgres"] = {
|
|
270
271
|
host: config.host,
|
|
@@ -608,6 +609,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
608
609
|
host: apphostingAddr.host,
|
|
609
610
|
port: apphostingAddr.port,
|
|
610
611
|
startCommandOverride: apphostingConfig === null || apphostingConfig === void 0 ? void 0 : apphostingConfig.startCommandOverride,
|
|
612
|
+
rootDirectory: apphostingConfig === null || apphostingConfig === void 0 ? void 0 : apphostingConfig.rootDirectory,
|
|
611
613
|
options,
|
|
612
614
|
});
|
|
613
615
|
await startEmulator(apphostingEmulator);
|
|
@@ -629,7 +631,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
629
631
|
if (listenForEmulator.ui) {
|
|
630
632
|
const ui = new ui_1.EmulatorUI({
|
|
631
633
|
projectId: projectId,
|
|
632
|
-
auto_download: true,
|
|
633
634
|
listen: listenForEmulator[types_1.Emulators.UI],
|
|
634
635
|
});
|
|
635
636
|
await startEmulator(ui);
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DataConnectEmulatorClient = exports.DataConnectEmulator = exports.dataConnectEmulatorEvents = void 0;
|
|
4
4
|
const childProcess = require("child_process");
|
|
5
5
|
const events_1 = require("events");
|
|
6
|
+
const clc = require("colorette");
|
|
6
7
|
const api_1 = require("../api");
|
|
7
8
|
const constants_1 = require("./constants");
|
|
8
9
|
const downloadableEmulators_1 = require("./downloadableEmulators");
|
|
@@ -26,26 +27,23 @@ class DataConnectEmulator {
|
|
|
26
27
|
this.emulatorClient = new DataConnectEmulatorClient();
|
|
27
28
|
}
|
|
28
29
|
async start() {
|
|
29
|
-
var _a, _b, _c
|
|
30
|
+
var _a, _b, _c;
|
|
30
31
|
let resolvedConfigDir;
|
|
31
32
|
try {
|
|
32
33
|
resolvedConfigDir = this.args.config.path(this.args.configDir);
|
|
33
34
|
const info = await DataConnectEmulator.build({ configDir: resolvedConfigDir });
|
|
34
35
|
if ((0, types_2.requiresVector)(info.metadata)) {
|
|
35
36
|
if (constants_1.Constants.isDemoProject(this.args.projectId)) {
|
|
36
|
-
this.logger.logLabeled("WARN", "
|
|
37
|
+
this.logger.logLabeled("WARN", "dataconnect", "Detected a 'demo-' project, but vector embeddings require a real project. Operations that use vector_embed will fail.");
|
|
37
38
|
}
|
|
38
39
|
else {
|
|
39
|
-
this.logger.logLabeled("WARN", "
|
|
40
|
+
this.logger.logLabeled("WARN", "dataconnect", "Operations that use vector_embed will make calls to production Vertex AI");
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
catch (err) {
|
|
44
45
|
this.logger.log("DEBUG", `'fdc build' failed with error: ${err.message}`);
|
|
45
46
|
}
|
|
46
|
-
const info = await (0, load_1.load)(this.args.projectId, this.args.config, this.args.configDir);
|
|
47
|
-
const dbId = ((_a = info.dataConnectYaml.schema.datasource.postgresql) === null || _a === void 0 ? void 0 : _a.database) || "postgres";
|
|
48
|
-
const serviceId = info.dataConnectYaml.serviceId;
|
|
49
47
|
await (0, downloadableEmulators_1.start)(types_1.Emulators.DATACONNECT, {
|
|
50
48
|
auto_download: this.args.auto_download,
|
|
51
49
|
listen: (0, portUtils_1.listenSpecsToString)(this.args.listen),
|
|
@@ -55,11 +53,14 @@ class DataConnectEmulator {
|
|
|
55
53
|
});
|
|
56
54
|
this.usingExistingEmulator = false;
|
|
57
55
|
if (this.args.autoconnectToPostgres) {
|
|
56
|
+
const info = await (0, load_1.load)(this.args.projectId, this.args.config, this.args.configDir);
|
|
57
|
+
const dbId = ((_a = info.dataConnectYaml.schema.datasource.postgresql) === null || _a === void 0 ? void 0 : _a.database) || "postgres";
|
|
58
|
+
const serviceId = info.dataConnectYaml.serviceId;
|
|
58
59
|
const pgPort = (_b = this.args.postgresListen) === null || _b === void 0 ? void 0 : _b[0].port;
|
|
59
60
|
const pgHost = (_c = this.args.postgresListen) === null || _c === void 0 ? void 0 : _c[0].address;
|
|
60
61
|
let connStr = (0, api_1.dataConnectLocalConnString)();
|
|
61
|
-
if (
|
|
62
|
-
this.logger.logLabeled("INFO", "
|
|
62
|
+
if (connStr) {
|
|
63
|
+
this.logger.logLabeled("INFO", "dataconnect", `FIREBASE_DATACONNECT_POSTGRESQL_STRING is set to ${clc.bold(connStr)} - using that instead of starting a new database`);
|
|
63
64
|
}
|
|
64
65
|
else if (pgHost && pgPort) {
|
|
65
66
|
const pgServer = new pgliteServer_1.PostgresServer(dbId, "postgres");
|
|
@@ -71,11 +72,11 @@ class DataConnectEmulator {
|
|
|
71
72
|
this.logger.logLabeled("ERROR", "Data Connect", `${err}`);
|
|
72
73
|
}
|
|
73
74
|
else {
|
|
74
|
-
this.logger.logLabeled("ERROR", "
|
|
75
|
+
this.logger.logLabeled("ERROR", "dataconnect", `Postgres threw an unexpected error, shutting down the Data Connect emulator: ${err}`);
|
|
75
76
|
}
|
|
76
77
|
void (0, controller_1.cleanShutdown)();
|
|
77
78
|
});
|
|
78
|
-
this.logger.logLabeled("INFO", "
|
|
79
|
+
this.logger.logLabeled("INFO", "dataconnect", `Started up Postgres server, listening on ${JSON.stringify(server.address())}`);
|
|
79
80
|
}
|
|
80
81
|
await this.connectToPostgres(new URL(connStr), dbId, serviceId);
|
|
81
82
|
}
|
|
@@ -84,14 +85,14 @@ class DataConnectEmulator {
|
|
|
84
85
|
async connect() {
|
|
85
86
|
const emuInfo = await this.emulatorClient.getInfo();
|
|
86
87
|
if (!emuInfo) {
|
|
87
|
-
this.logger.logLabeled("ERROR", "
|
|
88
|
+
this.logger.logLabeled("ERROR", "dataconnect", "Could not connect to Data Connect emulator. Check dataconnect-debug.log for more details.");
|
|
88
89
|
return Promise.reject();
|
|
89
90
|
}
|
|
90
91
|
return Promise.resolve();
|
|
91
92
|
}
|
|
92
93
|
async stop() {
|
|
93
94
|
if (this.usingExistingEmulator) {
|
|
94
|
-
this.logger.logLabeled("INFO", "
|
|
95
|
+
this.logger.logLabeled("INFO", "dataconnect", "Skipping cleanup of Data Connect emulator, as it was not started by this process.");
|
|
95
96
|
return;
|
|
96
97
|
}
|
|
97
98
|
return (0, downloadableEmulators_1.stop)(types_1.Emulators.DATACONNECT);
|
|
@@ -48,20 +48,20 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
48
48
|
},
|
|
49
49
|
dataconnect: process.platform === "darwin"
|
|
50
50
|
? {
|
|
51
|
-
version: "1.
|
|
52
|
-
expectedSize:
|
|
53
|
-
expectedChecksum: "
|
|
51
|
+
version: "1.7.3",
|
|
52
|
+
expectedSize: 25211648,
|
|
53
|
+
expectedChecksum: "8410794304b2ae340c3facf07d7edc16",
|
|
54
54
|
}
|
|
55
55
|
: process.platform === "win32"
|
|
56
56
|
? {
|
|
57
|
-
version: "1.
|
|
58
|
-
expectedSize:
|
|
59
|
-
expectedChecksum: "
|
|
57
|
+
version: "1.7.3",
|
|
58
|
+
expectedSize: 25641984,
|
|
59
|
+
expectedChecksum: "a4bd0f9d9d884528fa4494e4d7918c08",
|
|
60
60
|
}
|
|
61
61
|
: {
|
|
62
|
-
version: "1.
|
|
63
|
-
expectedSize:
|
|
64
|
-
expectedChecksum: "
|
|
62
|
+
version: "1.7.3",
|
|
63
|
+
expectedSize: 25125016,
|
|
64
|
+
expectedChecksum: "48660e6370aeed973f33c3420c3255fb",
|
|
65
65
|
},
|
|
66
66
|
};
|
|
67
67
|
exports.DownloadDetails = {
|
|
@@ -233,8 +233,8 @@ const Commands = {
|
|
|
233
233
|
shell: true,
|
|
234
234
|
},
|
|
235
235
|
ui: {
|
|
236
|
-
binary: "
|
|
237
|
-
args: [
|
|
236
|
+
binary: "",
|
|
237
|
+
args: [],
|
|
238
238
|
optionalArgs: [],
|
|
239
239
|
joinArgs: false,
|
|
240
240
|
shell: false,
|
|
@@ -210,6 +210,9 @@ You can probably fix this by running "npm install ${systemLog.data.name}@latest"
|
|
|
210
210
|
case "BULLET":
|
|
211
211
|
utils.logLabeledBullet(label, text, "info", mergedData);
|
|
212
212
|
break;
|
|
213
|
+
case "INFO":
|
|
214
|
+
utils.logLabeledBullet(label, text, "info", mergedData);
|
|
215
|
+
break;
|
|
213
216
|
case "SUCCESS":
|
|
214
217
|
utils.logLabeledSuccess(label, text, "info", mergedData);
|
|
215
218
|
break;
|
package/lib/emulator/hub.js
CHANGED
|
@@ -10,7 +10,7 @@ const types_1 = require("./types");
|
|
|
10
10
|
const hubExport_1 = require("./hubExport");
|
|
11
11
|
const registry_1 = require("./registry");
|
|
12
12
|
const ExpressBasedEmulator_1 = require("./ExpressBasedEmulator");
|
|
13
|
-
const
|
|
13
|
+
const vsCodeUtils_1 = require("../vsCodeUtils");
|
|
14
14
|
const pkg = require("../../package.json");
|
|
15
15
|
class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
16
16
|
static readLocatorFile(projectId) {
|
|
@@ -20,7 +20,7 @@ class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
|
20
20
|
}
|
|
21
21
|
const data = fs.readFileSync(locatorPath, "utf8").toString();
|
|
22
22
|
const locator = JSON.parse(data);
|
|
23
|
-
if (!
|
|
23
|
+
if (!vsCodeUtils_1.isVSCodeExtension && locator.version !== this.CLI_VERSION) {
|
|
24
24
|
logger_1.logger.debug(`Found locator with mismatched version, ignoring: ${JSON.stringify(locator)}`);
|
|
25
25
|
return undefined;
|
|
26
26
|
}
|
|
@@ -41,17 +41,20 @@ class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
|
41
41
|
await super.start();
|
|
42
42
|
await this.writeLocatorFile();
|
|
43
43
|
}
|
|
44
|
+
getRunningEmulatorsMapping() {
|
|
45
|
+
const emulators = {};
|
|
46
|
+
for (const info of registry_1.EmulatorRegistry.listRunningWithInfo()) {
|
|
47
|
+
emulators[info.name] = Object.assign({ listen: this.args.listenForEmulator[info.name] }, info);
|
|
48
|
+
}
|
|
49
|
+
return emulators;
|
|
50
|
+
}
|
|
44
51
|
async createExpressApp() {
|
|
45
52
|
const app = await super.createExpressApp();
|
|
46
53
|
app.get("/", (req, res) => {
|
|
47
54
|
res.json(Object.assign(Object.assign({}, this.getLocator()), { host: utils.connectableHostname(this.args.listen[0].address), port: this.args.listen[0].port }));
|
|
48
55
|
});
|
|
49
56
|
app.get(EmulatorHub.PATH_EMULATORS, (req, res) => {
|
|
50
|
-
|
|
51
|
-
for (const info of registry_1.EmulatorRegistry.listRunningWithInfo()) {
|
|
52
|
-
body[info.name] = Object.assign({ listen: this.args.listenForEmulator[info.name] }, info);
|
|
53
|
-
}
|
|
54
|
-
res.json(body);
|
|
57
|
+
res.json(this.getRunningEmulatorsMapping());
|
|
55
58
|
});
|
|
56
59
|
app.post(EmulatorHub.PATH_EXPORT, async (req, res) => {
|
|
57
60
|
if (req.headers.origin) {
|
|
@@ -116,7 +116,10 @@ class TasksEmulator {
|
|
|
116
116
|
const locationId = req.params.location_id;
|
|
117
117
|
const queueName = req.params.queue_name;
|
|
118
118
|
if (!this.validateQueueId(queueName)) {
|
|
119
|
-
res.status(400).
|
|
119
|
+
res.status(400).json({
|
|
120
|
+
error: "Queue ID must start with a letter followed by up to 62 letters, numbers, " +
|
|
121
|
+
"hyphens, or underscores and must end with a letter or a number",
|
|
122
|
+
});
|
|
120
123
|
return;
|
|
121
124
|
}
|
|
122
125
|
const key = `queue:${projectId}-${locationId}-${queueName}`;
|
|
@@ -139,7 +142,7 @@ class TasksEmulator {
|
|
|
139
142
|
defaultUri: body.defaultUri,
|
|
140
143
|
};
|
|
141
144
|
if (taskQueueConfig.rateLimits.maxConcurrentDispatches > 5000) {
|
|
142
|
-
res.status(400).
|
|
145
|
+
res.status(400).json({ error: "cannot set maxConcurrentDispatches to a value over 5000" });
|
|
143
146
|
return;
|
|
144
147
|
}
|
|
145
148
|
this.controller.createQueue(key, taskQueueConfig);
|
package/lib/emulator/ui.js
CHANGED
|
@@ -1,52 +1,74 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EmulatorUI = void 0;
|
|
4
|
+
const express = require("express");
|
|
5
|
+
const path = require("path");
|
|
4
6
|
const types_1 = require("./types");
|
|
5
7
|
const downloadableEmulators = require("./downloadableEmulators");
|
|
6
8
|
const registry_1 = require("./registry");
|
|
7
9
|
const error_1 = require("../error");
|
|
10
|
+
const emulatorLogger_1 = require("./emulatorLogger");
|
|
8
11
|
const constants_1 = require("./constants");
|
|
9
12
|
const track_1 = require("../track");
|
|
10
13
|
const ExpressBasedEmulator_1 = require("./ExpressBasedEmulator");
|
|
11
14
|
const experiments_1 = require("../experiments");
|
|
12
|
-
class EmulatorUI {
|
|
15
|
+
class EmulatorUI extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
13
16
|
constructor(args) {
|
|
17
|
+
super({
|
|
18
|
+
listen: args.listen,
|
|
19
|
+
});
|
|
14
20
|
this.args = args;
|
|
15
21
|
}
|
|
16
|
-
start() {
|
|
22
|
+
async start() {
|
|
23
|
+
await super.start();
|
|
24
|
+
}
|
|
25
|
+
async createExpressApp() {
|
|
17
26
|
if (!registry_1.EmulatorRegistry.isRunning(types_1.Emulators.HUB)) {
|
|
18
27
|
throw new error_1.FirebaseError(`Cannot start ${constants_1.Constants.description(types_1.Emulators.UI)} without ${constants_1.Constants.description(types_1.Emulators.HUB)}!`);
|
|
19
28
|
}
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
GCLOUD_PROJECT: projectId,
|
|
24
|
-
[constants_1.Constants.FIREBASE_EMULATOR_HUB]: registry_1.EmulatorRegistry.url(types_1.Emulators.HUB).host,
|
|
25
|
-
};
|
|
26
|
-
const session = (0, track_1.emulatorSession)();
|
|
27
|
-
if (session) {
|
|
28
|
-
env[constants_1.Constants.FIREBASE_GA_SESSION] = JSON.stringify(session);
|
|
29
|
-
}
|
|
29
|
+
const hub = registry_1.EmulatorRegistry.get(types_1.Emulators.HUB);
|
|
30
|
+
const app = await super.createExpressApp();
|
|
31
|
+
const { projectId } = this.args;
|
|
30
32
|
const enabledExperiments = Object.keys(experiments_1.ALL_EXPERIMENTS).filter((experimentName) => (0, experiments_1.isEnabled)(experimentName));
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
const emulatorGaSession = (0, track_1.emulatorSession)();
|
|
34
|
+
await downloadableEmulators.downloadIfNecessary(types_1.Emulators.UI);
|
|
35
|
+
const downloadDetails = downloadableEmulators.getDownloadDetails(types_1.Emulators.UI);
|
|
36
|
+
const webDir = path.join(downloadDetails.unzipDir, "client");
|
|
37
|
+
app.get("/api/config", this.jsonHandler(() => {
|
|
38
|
+
const json = Object.assign({ projectId, experiments: [] }, hub.getRunningEmulatorsMapping());
|
|
39
|
+
if (emulatorGaSession) {
|
|
40
|
+
json.analytics = emulatorGaSession;
|
|
41
|
+
}
|
|
42
|
+
if (enabledExperiments) {
|
|
43
|
+
json.experiments = enabledExperiments;
|
|
44
|
+
}
|
|
45
|
+
return Promise.resolve(json);
|
|
46
|
+
}));
|
|
47
|
+
app.use(express.static(webDir));
|
|
48
|
+
app.get("*", (_, res) => {
|
|
49
|
+
res.sendFile(path.join(webDir, "index.html"));
|
|
50
|
+
});
|
|
51
|
+
return app;
|
|
33
52
|
}
|
|
34
53
|
connect() {
|
|
35
54
|
return Promise.resolve();
|
|
36
55
|
}
|
|
37
|
-
stop() {
|
|
38
|
-
return downloadableEmulators.stop(types_1.Emulators.UI);
|
|
39
|
-
}
|
|
40
|
-
getInfo() {
|
|
41
|
-
return {
|
|
42
|
-
name: this.getName(),
|
|
43
|
-
host: this.args.listen[0].address,
|
|
44
|
-
port: this.args.listen[0].port,
|
|
45
|
-
pid: downloadableEmulators.getPID(types_1.Emulators.UI),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
56
|
getName() {
|
|
49
57
|
return types_1.Emulators.UI;
|
|
50
58
|
}
|
|
59
|
+
jsonHandler(handler) {
|
|
60
|
+
return (req, res) => {
|
|
61
|
+
handler(req).then((body) => {
|
|
62
|
+
res.status(200).json(body);
|
|
63
|
+
}, (err) => {
|
|
64
|
+
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.UI).log("ERROR", err);
|
|
65
|
+
res.status(500).json({
|
|
66
|
+
message: err.message,
|
|
67
|
+
stack: err.stack,
|
|
68
|
+
raw: err,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
}
|
|
51
73
|
}
|
|
52
74
|
exports.EmulatorUI = EmulatorUI;
|