firebase-tools 13.7.5 → 13.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api.js +9 -1
- package/lib/apiv2.js +19 -13
- package/lib/apphosting/app.js +38 -58
- package/lib/apphosting/githubConnections.js +1 -1
- package/lib/apphosting/index.js +72 -20
- package/lib/checkValidTargetFilters.js +8 -1
- package/lib/commands/apphosting-backends-create.js +4 -3
- package/lib/commands/apphosting-backends-delete.js +24 -17
- package/lib/commands/apphosting-backends-list.js +3 -3
- package/lib/commands/apphosting-secrets-grantaccess.js +9 -5
- package/lib/commands/dataconnect-list.js +64 -0
- package/lib/commands/dataconnect-sdk-generate.js +37 -0
- package/lib/commands/dataconnect-sql-diff.js +25 -0
- package/lib/commands/dataconnect-sql-migrate.js +46 -0
- package/lib/commands/deploy.js +27 -1
- package/lib/commands/index.js +10 -0
- package/lib/commands/init.js +7 -0
- package/lib/commands/setup-emulators-dataconnect.js +12 -0
- package/lib/config.js +1 -0
- package/lib/dataconnect/build.js +23 -0
- package/lib/dataconnect/checkIam.js +30 -0
- package/lib/dataconnect/client.js +115 -0
- package/lib/dataconnect/dataplaneClient.js +16 -0
- package/lib/dataconnect/ensureApis.js +12 -0
- package/lib/dataconnect/fileUtils.js +89 -0
- package/lib/dataconnect/filters.js +45 -0
- package/lib/dataconnect/freeTrial.js +23 -0
- package/lib/dataconnect/graphqlError.js +13 -0
- package/lib/dataconnect/load.js +40 -0
- package/lib/dataconnect/names.js +48 -0
- package/lib/dataconnect/prompts.js +20 -0
- package/lib/dataconnect/provisionCloudSql.js +74 -0
- package/lib/dataconnect/schemaMigration.js +171 -0
- package/lib/dataconnect/types.js +23 -0
- package/lib/deploy/dataconnect/deploy.js +84 -0
- package/lib/deploy/dataconnect/index.js +9 -0
- package/lib/deploy/dataconnect/prepare.js +30 -0
- package/lib/deploy/dataconnect/release.js +65 -0
- package/lib/deploy/functions/checkIam.js +4 -34
- package/lib/deploy/functions/release/fabricator.js +7 -2
- package/lib/deploy/index.js +2 -0
- package/lib/downloadUtils.js +2 -2
- package/lib/emulator/constants.js +3 -0
- package/lib/emulator/controller.js +39 -12
- package/lib/emulator/dataconnectEmulator.js +88 -0
- package/lib/emulator/download.js +1 -1
- package/lib/emulator/downloadableEmulators.js +42 -3
- package/lib/emulator/portUtils.js +3 -3
- package/lib/emulator/registry.js +6 -1
- package/lib/emulator/types.js +3 -0
- package/lib/experiments.js +12 -5
- package/lib/extensions/emulator/specHelper.js +5 -39
- package/lib/frameworks/next/index.js +3 -1
- package/lib/frameworks/next/utils.js +1 -1
- package/lib/gcp/apphosting.js +6 -1
- package/lib/gcp/cloudsql/cloudsqladmin.js +155 -0
- package/lib/gcp/cloudsql/connect.js +128 -0
- package/lib/gcp/cloudsql/fbToolsAuthClient.js +42 -0
- package/lib/gcp/cloudsql/types.js +2 -0
- package/lib/gcp/firedata.js +26 -0
- package/lib/gcp/iam.js +33 -1
- package/lib/gcp/secretManager.js +1 -1
- package/lib/hosting/interactive.js +4 -0
- package/lib/init/features/dataconnect/index.js +160 -0
- package/lib/init/features/emulators.js +13 -0
- package/lib/init/features/functions/index.js +15 -3
- package/lib/init/features/index.js +3 -1
- package/lib/init/index.js +1 -0
- package/lib/logger.js +22 -2
- package/lib/operation-poller.js +8 -2
- package/lib/rc.js +10 -1
- package/lib/requireAuth.js +1 -0
- package/lib/requireTosAcceptance.js +21 -0
- package/lib/utils.js +55 -4
- package/package.json +6 -2
- package/schema/connector-yaml.json +54 -0
- package/schema/dataconnect-yaml.json +72 -0
- package/schema/firebase-config.json +103 -0
- package/templates/extensions/javascript/package.lint.json +2 -2
- package/templates/extensions/javascript/package.nolint.json +2 -2
- package/templates/extensions/typescript/package.lint.json +2 -2
- package/templates/extensions/typescript/package.nolint.json +2 -2
- package/templates/init/dataconnect/connector.yaml +2 -0
- package/templates/init/dataconnect/dataconnect.yaml +10 -0
- package/templates/init/dataconnect/mutations.gql +4 -0
- package/templates/init/dataconnect/queries.gql +6 -0
- package/templates/init/dataconnect/schema.gql +15 -0
- package/templates/init/functions/javascript/_gitignore +2 -1
- package/templates/init/functions/javascript/package.lint.json +2 -2
- package/templates/init/functions/javascript/package.nolint.json +2 -2
- package/templates/init/functions/python/_gitignore +1 -0
- package/templates/init/functions/typescript/_gitignore +1 -0
- package/templates/init/functions/typescript/package.lint.json +2 -2
- package/templates/init/functions/typescript/package.nolint.json +2 -2
package/lib/api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.serviceUsageOrigin = exports.cloudRunApiOrigin = exports.hostingApiOrigin = exports.firebaseStorageOrigin = exports.storageOrigin = exports.runtimeconfigOrigin = exports.rulesOrigin = exports.resourceManagerOrigin = exports.remoteConfigApiOrigin = exports.rtdbMetadataOrigin = exports.rtdbManagementOrigin = exports.realtimeOrigin = exports.extensionsTOSOrigin = exports.extensionsPublisherOrigin = exports.extensionsOrigin = exports.iamOrigin = exports.identityOrigin = exports.hostingOrigin = exports.googleOrigin = exports.pubsubOrigin = exports.cloudTasksOrigin = exports.cloudschedulerOrigin = exports.cloudbuildOrigin = exports.functionsDefaultRegion = exports.runOrigin = exports.functionsV2Origin = exports.functionsOrigin = exports.firestoreOrigin = exports.firestoreOriginOrEmulator = exports.firedataOrigin = exports.firebaseExtensionsRegistryOrigin = exports.firebaseApiOrigin = exports.eventarcOrigin = exports.dynamicLinksKey = exports.dynamicLinksOrigin = exports.consoleOrigin = exports.authOrigin = exports.apphostingP4SADomain = exports.apphostingOrigin = exports.appDistributionOrigin = exports.artifactRegistryDomain = exports.developerConnectP4SADomain = exports.developerConnectOrigin = exports.containerRegistryDomain = exports.cloudMonitoringOrigin = exports.cloudloggingOrigin = exports.cloudbillingOrigin = exports.clientSecret = exports.clientId = exports.authProxyOrigin = void 0;
|
|
4
|
-
exports.setScopes = exports.getScopes = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = void 0;
|
|
4
|
+
exports.setScopes = exports.getScopes = exports.vertexAIOrigin = exports.cloudSQLAdminOrigin = exports.dataConnectLocalConnString = exports.dataconnectOrigin = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = void 0;
|
|
5
5
|
const constants_1 = require("./emulator/constants");
|
|
6
6
|
const logger_1 = require("./logger");
|
|
7
7
|
const scopes = require("./scopes");
|
|
@@ -124,6 +124,14 @@ const githubClientId = () => utils.envOverride("GITHUB_CLIENT_ID", "89cf50f02ac6
|
|
|
124
124
|
exports.githubClientId = githubClientId;
|
|
125
125
|
const githubClientSecret = () => utils.envOverride("GITHUB_CLIENT_SECRET", "3330d14abc895d9a74d5f17cd7a00711fa2c5bf0");
|
|
126
126
|
exports.githubClientSecret = githubClientSecret;
|
|
127
|
+
const dataconnectOrigin = () => utils.envOverride("FIREBASE_DATACONNECT_URL", "https://firebasedataconnect.googleapis.com");
|
|
128
|
+
exports.dataconnectOrigin = dataconnectOrigin;
|
|
129
|
+
const dataConnectLocalConnString = () => utils.envOverride("FIREBASE_DATACONNECT_POSTGRESQL_STRING", "");
|
|
130
|
+
exports.dataConnectLocalConnString = dataConnectLocalConnString;
|
|
131
|
+
const cloudSQLAdminOrigin = () => utils.envOverride("CLOUD_SQL_URL", "https://sqladmin.googleapis.com");
|
|
132
|
+
exports.cloudSQLAdminOrigin = cloudSQLAdminOrigin;
|
|
133
|
+
const vertexAIOrigin = () => utils.envOverride("VERTEX_AI_URL", "https://aiplatform.googleapis.com");
|
|
134
|
+
exports.vertexAIOrigin = vertexAIOrigin;
|
|
127
135
|
function getScopes() {
|
|
128
136
|
return Array.from(commandScopes);
|
|
129
137
|
}
|
package/lib/apiv2.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Client = exports.setAccessToken = exports.setRefreshToken = void 0;
|
|
3
|
+
exports.Client = exports.getAccessToken = exports.setAccessToken = exports.setRefreshToken = exports.STANDARD_HEADERS = void 0;
|
|
4
4
|
const url_1 = require("url");
|
|
5
5
|
const stream_1 = require("stream");
|
|
6
6
|
const proxy_agent_1 = require("proxy-agent");
|
|
@@ -15,6 +15,11 @@ const responseToError_1 = require("./responseToError");
|
|
|
15
15
|
const FormData = require("form-data");
|
|
16
16
|
const pkg = require("../package.json");
|
|
17
17
|
const CLI_VERSION = pkg.version;
|
|
18
|
+
exports.STANDARD_HEADERS = {
|
|
19
|
+
Connection: "keep-alive",
|
|
20
|
+
"User-Agent": `FirebaseCLI/${CLI_VERSION}`,
|
|
21
|
+
"X-Client-Version": `FirebaseCLI/${CLI_VERSION}`,
|
|
22
|
+
};
|
|
18
23
|
const GOOG_QUOTA_USER_HEADER = "x-goog-quota-user";
|
|
19
24
|
const GOOG_USER_PROJECT_HEADER = "x-goog-user-project";
|
|
20
25
|
const GOOGLE_CLOUD_QUOTA_PROJECT = process.env.GOOGLE_CLOUD_QUOTA_PROJECT;
|
|
@@ -28,6 +33,14 @@ function setAccessToken(token = "") {
|
|
|
28
33
|
accessToken = token;
|
|
29
34
|
}
|
|
30
35
|
exports.setAccessToken = setAccessToken;
|
|
36
|
+
async function getAccessToken() {
|
|
37
|
+
if (accessToken) {
|
|
38
|
+
return accessToken;
|
|
39
|
+
}
|
|
40
|
+
const data = await auth.getAccessToken(refreshToken, []);
|
|
41
|
+
return data.access_token;
|
|
42
|
+
}
|
|
43
|
+
exports.getAccessToken = getAccessToken;
|
|
31
44
|
function proxyURIFromEnv() {
|
|
32
45
|
return (process.env.HTTPS_PROXY ||
|
|
33
46
|
process.env.https_proxy ||
|
|
@@ -125,11 +138,11 @@ class Client {
|
|
|
125
138
|
if (!reqOptions.headers) {
|
|
126
139
|
reqOptions.headers = new node_fetch_1.Headers();
|
|
127
140
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
for (const [h, v] of Object.entries(exports.STANDARD_HEADERS)) {
|
|
142
|
+
if (!reqOptions.headers.has(h)) {
|
|
143
|
+
reqOptions.headers.set(h, v);
|
|
144
|
+
}
|
|
131
145
|
}
|
|
132
|
-
reqOptions.headers.set("X-Client-Version", `FirebaseCLI/${CLI_VERSION}`);
|
|
133
146
|
if (!reqOptions.headers.has("Content-Type")) {
|
|
134
147
|
if (reqOptions.responseType === "json") {
|
|
135
148
|
reqOptions.headers.set("Content-Type", "application/json");
|
|
@@ -151,18 +164,11 @@ class Client {
|
|
|
151
164
|
token = "owner";
|
|
152
165
|
}
|
|
153
166
|
else {
|
|
154
|
-
token = await
|
|
167
|
+
token = await getAccessToken();
|
|
155
168
|
}
|
|
156
169
|
reqOptions.headers.set("Authorization", `Bearer ${token}`);
|
|
157
170
|
return reqOptions;
|
|
158
171
|
}
|
|
159
|
-
async getAccessToken() {
|
|
160
|
-
if (accessToken) {
|
|
161
|
-
return accessToken;
|
|
162
|
-
}
|
|
163
|
-
const data = await auth.getAccessToken(refreshToken, []);
|
|
164
|
-
return data.access_token;
|
|
165
|
-
}
|
|
166
172
|
requestURL(options) {
|
|
167
173
|
const versionPath = this.opts.apiVersion ? `/${this.opts.apiVersion}` : "";
|
|
168
174
|
return `${this.opts.urlPrefix}${versionPath}${options.path}`;
|
package/lib/apphosting/app.js
CHANGED
|
@@ -1,86 +1,67 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.webApps = void 0;
|
|
4
4
|
const apps_1 = require("../management/apps");
|
|
5
|
-
const prompt_1 = require("../prompt");
|
|
6
5
|
const error_1 = require("../error");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
7
|
const CREATE_NEW_FIREBASE_WEB_APP = "CREATE_NEW_WEB_APP";
|
|
8
8
|
const CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP = "CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP";
|
|
9
|
-
|
|
9
|
+
exports.webApps = {
|
|
10
10
|
CREATE_NEW_FIREBASE_WEB_APP,
|
|
11
11
|
CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP,
|
|
12
12
|
getOrCreateWebApp,
|
|
13
|
-
|
|
13
|
+
generateWebAppName,
|
|
14
14
|
};
|
|
15
15
|
async function getOrCreateWebApp(projectId, firebaseWebAppName, backendId) {
|
|
16
16
|
const webAppsInProject = await (0, apps_1.listFirebaseApps)(projectId, apps_1.AppPlatform.WEB);
|
|
17
|
-
|
|
18
|
-
const { displayName, appId } = await createFirebaseWebApp(projectId, {
|
|
19
|
-
displayName: backendId,
|
|
20
|
-
});
|
|
21
|
-
return { name: displayName, id: appId };
|
|
22
|
-
}
|
|
23
|
-
const existingUserProjectWebApps = new Map(webAppsInProject.map((obj) => {
|
|
24
|
-
var _a;
|
|
25
|
-
return [
|
|
26
|
-
(_a = obj.displayName) !== null && _a !== void 0 ? _a : obj.appId,
|
|
27
|
-
obj.appId,
|
|
28
|
-
];
|
|
29
|
-
}));
|
|
17
|
+
const existingUserProjectWebApps = firebaseAppsToMap(webAppsInProject);
|
|
30
18
|
if (firebaseWebAppName) {
|
|
31
19
|
if (existingUserProjectWebApps.get(firebaseWebAppName) === undefined) {
|
|
32
20
|
throw new error_1.FirebaseError(`The web app '${firebaseWebAppName}' does not exist in project ${projectId}`);
|
|
33
21
|
}
|
|
34
|
-
return {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
async function promptFirebaseWebApp(projectId, backendId, existingUserProjectWebApps) {
|
|
39
|
-
const existingWebAppKeys = Array.from(existingUserProjectWebApps.keys());
|
|
40
|
-
const firebaseWebAppName = await (0, prompt_1.promptOnce)({
|
|
41
|
-
type: "autocomplete",
|
|
42
|
-
name: "app",
|
|
43
|
-
message: "Which of the following Firebase web apps would you like to associate your backend with?",
|
|
44
|
-
source: (_, input = "") => {
|
|
45
|
-
return new Promise((resolve) => resolve([
|
|
46
|
-
new inquirer.Separator(),
|
|
47
|
-
{
|
|
48
|
-
name: "Create a new Firebase web app.",
|
|
49
|
-
value: CREATE_NEW_FIREBASE_WEB_APP,
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
name: "Continue without a Firebase web app.",
|
|
53
|
-
value: CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP,
|
|
54
|
-
},
|
|
55
|
-
new inquirer.Separator(),
|
|
56
|
-
...fuzzy.filter(input, existingWebAppKeys).map((result) => {
|
|
57
|
-
return result.original;
|
|
58
|
-
}),
|
|
59
|
-
]));
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
if (firebaseWebAppName === CREATE_NEW_FIREBASE_WEB_APP) {
|
|
63
|
-
const newFirebaseWebApp = await createFirebaseWebApp(projectId, { displayName: backendId });
|
|
64
|
-
return { name: newFirebaseWebApp.displayName, id: newFirebaseWebApp.appId };
|
|
65
|
-
}
|
|
66
|
-
else if (firebaseWebAppName === CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP) {
|
|
67
|
-
return;
|
|
22
|
+
return {
|
|
23
|
+
name: firebaseWebAppName,
|
|
24
|
+
id: existingUserProjectWebApps.get(firebaseWebAppName),
|
|
25
|
+
};
|
|
68
26
|
}
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
async function createFirebaseWebApp(projectId, options) {
|
|
27
|
+
const webAppName = await generateWebAppName(projectId, backendId);
|
|
72
28
|
try {
|
|
73
|
-
|
|
29
|
+
const app = await (0, apps_1.createWebApp)(projectId, { displayName: webAppName });
|
|
30
|
+
return { name: app.displayName, id: app.appId };
|
|
74
31
|
}
|
|
75
32
|
catch (e) {
|
|
76
33
|
if (isQuotaError(e)) {
|
|
77
|
-
|
|
34
|
+
(0, utils_1.logWarning)("Unable to create a new web app, the project has reached the quota for Firebase apps. Navigate to your Firebase console to manage or delete a Firebase app to continue. ");
|
|
35
|
+
return;
|
|
78
36
|
}
|
|
79
37
|
throw new error_1.FirebaseError("Unable to create a Firebase web app", {
|
|
80
38
|
original: e instanceof Error ? e : undefined,
|
|
81
39
|
});
|
|
82
40
|
}
|
|
83
41
|
}
|
|
42
|
+
async function generateWebAppName(projectId, backendId) {
|
|
43
|
+
const webAppsInProject = await (0, apps_1.listFirebaseApps)(projectId, apps_1.AppPlatform.WEB);
|
|
44
|
+
const appsMap = firebaseAppsToMap(webAppsInProject);
|
|
45
|
+
if (!appsMap.get(backendId)) {
|
|
46
|
+
return backendId;
|
|
47
|
+
}
|
|
48
|
+
let uniqueId = 1;
|
|
49
|
+
let webAppName = `${backendId}_${uniqueId}`;
|
|
50
|
+
while (appsMap.get(webAppName)) {
|
|
51
|
+
uniqueId += 1;
|
|
52
|
+
webAppName = `${backendId}_${uniqueId}`;
|
|
53
|
+
}
|
|
54
|
+
return webAppName;
|
|
55
|
+
}
|
|
56
|
+
function firebaseAppsToMap(apps) {
|
|
57
|
+
return new Map(apps.map((obj) => {
|
|
58
|
+
var _a;
|
|
59
|
+
return [
|
|
60
|
+
(_a = obj.displayName) !== null && _a !== void 0 ? _a : obj.appId,
|
|
61
|
+
obj.appId,
|
|
62
|
+
];
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
84
65
|
function isQuotaError(error) {
|
|
85
66
|
var _a, _b, _c, _d, _e;
|
|
86
67
|
const original = error.original;
|
|
@@ -89,4 +70,3 @@ function isQuotaError(error) {
|
|
|
89
70
|
((_e = (_d = (_c = original === null || original === void 0 ? void 0 : original.context) === null || _c === void 0 ? void 0 : _c.body) === null || _d === void 0 ? void 0 : _d.error) === null || _e === void 0 ? void 0 : _e.code);
|
|
90
71
|
return code === 429;
|
|
91
72
|
}
|
|
92
|
-
module.exports = webApps;
|
|
@@ -77,7 +77,7 @@ async function linkGitHubRepository(projectId, location) {
|
|
|
77
77
|
});
|
|
78
78
|
const repo = await getOrCreateRepository(projectId, location, connectionId, repoCloneUri);
|
|
79
79
|
utils.logSuccess(`Successfully linked GitHub repository at remote URI`);
|
|
80
|
-
utils.logSuccess(`\t${repo.cloneUri}`);
|
|
80
|
+
utils.logSuccess(`\t${repo.cloneUri}\n`);
|
|
81
81
|
return repo;
|
|
82
82
|
}
|
|
83
83
|
exports.linkGitHubRepository = linkGitHubRepository;
|
package/lib/apphosting/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.promptLocation = exports.deleteBackendAndPoll = exports.orchestrateRollout = exports.setDefaultTrafficPolicy = exports.createBackend = exports.ensureAppHostingComputeServiceAccount = exports.doSetup = void 0;
|
|
4
|
-
const repo = require("./repo");
|
|
3
|
+
exports.getBackendForAmbiguousLocation = exports.promptLocation = exports.deleteBackendAndPoll = exports.orchestrateRollout = exports.setDefaultTrafficPolicy = exports.createBackend = exports.ensureAppHostingComputeServiceAccount = exports.doSetup = void 0;
|
|
5
4
|
const poller = require("../operation-poller");
|
|
6
5
|
const apphosting = require("../gcp/apphosting");
|
|
7
6
|
const githubConnections = require("./githubConnections");
|
|
@@ -15,7 +14,9 @@ const prompt_1 = require("../prompt");
|
|
|
15
14
|
const constants_1 = require("./constants");
|
|
16
15
|
const ensureApiEnabled_1 = require("../ensureApiEnabled");
|
|
17
16
|
const deploymentTool = require("../deploymentTool");
|
|
18
|
-
const
|
|
17
|
+
const app_1 = require("./app");
|
|
18
|
+
const ora = require("ora");
|
|
19
|
+
const node_fetch_1 = require("node-fetch");
|
|
19
20
|
const DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME = "firebase-app-hosting-compute";
|
|
20
21
|
const apphostingPollerOptions = {
|
|
21
22
|
apiOrigin: (0, api_1.apphostingOrigin)(),
|
|
@@ -23,9 +24,32 @@ const apphostingPollerOptions = {
|
|
|
23
24
|
masterTimeout: 25 * 60 * 1000,
|
|
24
25
|
maxBackoff: 10000,
|
|
25
26
|
};
|
|
26
|
-
async function
|
|
27
|
+
async function tlsReady(url) {
|
|
28
|
+
var _a;
|
|
29
|
+
try {
|
|
30
|
+
await (0, node_fetch_1.default)(url);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const maybeNodeError = err;
|
|
35
|
+
if (/HANDSHAKE_FAILURE/.test((_a = maybeNodeError === null || maybeNodeError === void 0 ? void 0 : maybeNodeError.cause) === null || _a === void 0 ? void 0 : _a.code)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function awaitTlsReady(url) {
|
|
42
|
+
let ready;
|
|
43
|
+
do {
|
|
44
|
+
ready = await tlsReady(url);
|
|
45
|
+
if (!ready) {
|
|
46
|
+
await (0, utils_1.sleep)(1000);
|
|
47
|
+
}
|
|
48
|
+
} while (!ready);
|
|
49
|
+
}
|
|
50
|
+
async function doSetup(projectId, webAppName, location, serviceAccount) {
|
|
27
51
|
await Promise.all([
|
|
28
|
-
|
|
52
|
+
(0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.developerConnectOrigin)(), "apphosting", true),
|
|
29
53
|
(0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.cloudbuildOrigin)(), "apphosting", true),
|
|
30
54
|
(0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.secretManagerOrigin)(), "apphosting", true),
|
|
31
55
|
(0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.cloudRunApiOrigin)(), "apphosting", true),
|
|
@@ -49,23 +73,23 @@ async function doSetup(projectId, webAppName, location, serviceAccount, withDevC
|
|
|
49
73
|
default: "my-web-app",
|
|
50
74
|
message: "Create a name for your backend [1-30 characters]",
|
|
51
75
|
});
|
|
52
|
-
const webApp = await
|
|
76
|
+
const webApp = await app_1.webApps.getOrCreateWebApp(projectId, webAppName, backendId);
|
|
53
77
|
if (webApp) {
|
|
54
|
-
(0, utils_1.logSuccess)(`Firebase web app
|
|
78
|
+
(0, utils_1.logSuccess)(`Created a new Firebase web app named "${webApp.name}"`);
|
|
55
79
|
}
|
|
56
80
|
else {
|
|
57
81
|
(0, utils_1.logWarning)(`Firebase web app not set`);
|
|
58
82
|
}
|
|
59
|
-
const gitRepositoryConnection =
|
|
60
|
-
? await githubConnections.linkGitHubRepository(projectId, location)
|
|
61
|
-
: await repo.linkGitHubRepository(projectId, location);
|
|
83
|
+
const gitRepositoryConnection = await githubConnections.linkGitHubRepository(projectId, location);
|
|
62
84
|
const rootDir = await (0, prompt_1.promptOnce)({
|
|
63
85
|
name: "rootDir",
|
|
64
86
|
type: "input",
|
|
65
87
|
default: "/",
|
|
66
88
|
message: "Specify your app's root directory relative to your repository",
|
|
67
89
|
});
|
|
90
|
+
const createBackendSpinner = ora("Creating your new backend...").start();
|
|
68
91
|
const backend = await createBackend(projectId, location, backendId, gitRepositoryConnection, serviceAccount, webApp === null || webApp === void 0 ? void 0 : webApp.id, rootDir);
|
|
92
|
+
createBackendSpinner.succeed(`Successfully created backend:\n\t${backend.name}\n`);
|
|
69
93
|
const branch = await (0, prompt_1.promptOnce)({
|
|
70
94
|
name: "branch",
|
|
71
95
|
type: "input",
|
|
@@ -80,10 +104,12 @@ async function doSetup(projectId, webAppName, location, serviceAccount, withDevC
|
|
|
80
104
|
message: "Do you want to deploy now?",
|
|
81
105
|
});
|
|
82
106
|
if (!confirmRollout) {
|
|
83
|
-
(0, utils_1.logSuccess)(`Successfully created backend:\n\t${backend.name}`);
|
|
84
107
|
(0, utils_1.logSuccess)(`Your backend will be deployed at:\n\thttps://${backend.uri}`);
|
|
85
108
|
return;
|
|
86
109
|
}
|
|
110
|
+
const url = `https://${backend.uri}`;
|
|
111
|
+
(0, utils_1.logBullet)(`You may also track this rollout at:\n\t${(0, api_1.consoleOrigin)()}/project/${projectId}/apphosting`);
|
|
112
|
+
const createRolloutSpinner = ora("Starting a new rollout; this may take a few minutes. It's safe to exit now.").start();
|
|
87
113
|
await orchestrateRollout(projectId, location, backendId, {
|
|
88
114
|
source: {
|
|
89
115
|
codebase: {
|
|
@@ -91,7 +117,12 @@ async function doSetup(projectId, webAppName, location, serviceAccount, withDevC
|
|
|
91
117
|
},
|
|
92
118
|
},
|
|
93
119
|
});
|
|
94
|
-
|
|
120
|
+
createRolloutSpinner.succeed("Rollout complete");
|
|
121
|
+
if (!(await tlsReady(url))) {
|
|
122
|
+
const tlsSpinner = ora("Finalizing your backend's TLS certificate; this may take a few minutes.").start();
|
|
123
|
+
await awaitTlsReady(url);
|
|
124
|
+
tlsSpinner.succeed("TLS certificate ready");
|
|
125
|
+
}
|
|
95
126
|
(0, utils_1.logSuccess)(`Your backend is now deployed at:\n\thttps://${backend.uri}`);
|
|
96
127
|
}
|
|
97
128
|
exports.doSetup = doSetup;
|
|
@@ -163,7 +194,7 @@ async function provisionDefaultComputeServiceAccount(projectId) {
|
|
|
163
194
|
await (0, resourceManager_1.addServiceAccountToRoles)(projectId, defaultComputeServiceAccountEmail(projectId), [
|
|
164
195
|
"roles/firebaseapphosting.computeRunner",
|
|
165
196
|
"roles/firebase.sdkAdminServiceAgent",
|
|
166
|
-
"roles/developerconnect.
|
|
197
|
+
"roles/developerconnect.readTokenAccessor",
|
|
167
198
|
], true);
|
|
168
199
|
}
|
|
169
200
|
async function setDefaultTrafficPolicy(projectId, location, backendId, codebaseBranch) {
|
|
@@ -182,12 +213,7 @@ async function setDefaultTrafficPolicy(projectId, location, backendId, codebaseB
|
|
|
182
213
|
await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `updateTraffic-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
|
|
183
214
|
}
|
|
184
215
|
exports.setDefaultTrafficPolicy = setDefaultTrafficPolicy;
|
|
185
|
-
function delay(ms) {
|
|
186
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
187
|
-
}
|
|
188
216
|
async function orchestrateRollout(projectId, location, backendId, buildInput) {
|
|
189
|
-
(0, utils_1.logBullet)("Starting a new rollout... this may take a few minutes.");
|
|
190
|
-
await delay(45 * 1000);
|
|
191
217
|
const buildId = await apphosting.getNextRolloutId(projectId, location, backendId, 1);
|
|
192
218
|
const buildOp = await apphosting.createBuild(projectId, location, backendId, buildId, buildInput);
|
|
193
219
|
const rolloutBody = {
|
|
@@ -207,7 +233,7 @@ async function orchestrateRollout(projectId, location, backendId, buildInput) {
|
|
|
207
233
|
if (tries >= 5) {
|
|
208
234
|
throw err;
|
|
209
235
|
}
|
|
210
|
-
await
|
|
236
|
+
await (0, utils_1.sleep)(1000);
|
|
211
237
|
}
|
|
212
238
|
else {
|
|
213
239
|
throw err;
|
|
@@ -218,7 +244,6 @@ async function orchestrateRollout(projectId, location, backendId, buildInput) {
|
|
|
218
244
|
const rolloutPoll = poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `create-${projectId}-${location}-backend-${backendId}-rollout-${buildId}`, operationResourceName: rolloutOp.name }));
|
|
219
245
|
const buildPoll = poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `create-${projectId}-${location}-backend-${backendId}-build-${buildId}`, operationResourceName: buildOp.name }));
|
|
220
246
|
const [rollout, build] = await Promise.all([rolloutPoll, buildPoll]);
|
|
221
|
-
(0, utils_1.logSuccess)("Rollout completed.");
|
|
222
247
|
if (build.state !== "READY") {
|
|
223
248
|
if (!build.buildLogsUri) {
|
|
224
249
|
throw new error_1.FirebaseError("Failed to build your app, but failed to get build logs as well. " +
|
|
@@ -236,6 +261,9 @@ async function deleteBackendAndPoll(projectId, location, backendId) {
|
|
|
236
261
|
exports.deleteBackendAndPoll = deleteBackendAndPoll;
|
|
237
262
|
async function promptLocation(projectId, prompt = "Please select a location:") {
|
|
238
263
|
const allowedLocations = (await apphosting.listLocations(projectId)).map((loc) => loc.locationId);
|
|
264
|
+
if (allowedLocations.length === 1) {
|
|
265
|
+
return allowedLocations[0];
|
|
266
|
+
}
|
|
239
267
|
return (await (0, prompt_1.promptOnce)({
|
|
240
268
|
name: "location",
|
|
241
269
|
type: "list",
|
|
@@ -245,3 +273,27 @@ async function promptLocation(projectId, prompt = "Please select a location:") {
|
|
|
245
273
|
}));
|
|
246
274
|
}
|
|
247
275
|
exports.promptLocation = promptLocation;
|
|
276
|
+
async function getBackendForAmbiguousLocation(projectId, backendId, locationDisambugationPrompt) {
|
|
277
|
+
let { unreachable, backends } = await apphosting.listBackends(projectId, "-");
|
|
278
|
+
if (unreachable && unreachable.length !== 0) {
|
|
279
|
+
(0, utils_1.logWarning)(`The following locations are currently unreachable: ${unreachable}.\n` +
|
|
280
|
+
"If your backend is in one of these regions, please try again later.");
|
|
281
|
+
}
|
|
282
|
+
backends = backends.filter((backend) => apphosting.parseBackendName(backend.name).id === backendId);
|
|
283
|
+
if (backends.length === 0) {
|
|
284
|
+
throw new error_1.FirebaseError(`No backend named "${backendId}" found.`);
|
|
285
|
+
}
|
|
286
|
+
if (backends.length === 1) {
|
|
287
|
+
return backends[0];
|
|
288
|
+
}
|
|
289
|
+
const backendsByLocation = new Map();
|
|
290
|
+
backends.forEach((backend) => backendsByLocation.set(apphosting.parseBackendName(backend.name).location, backend));
|
|
291
|
+
const location = await (0, prompt_1.promptOnce)({
|
|
292
|
+
name: "location",
|
|
293
|
+
type: "list",
|
|
294
|
+
message: locationDisambugationPrompt,
|
|
295
|
+
choices: [...backendsByLocation.keys()],
|
|
296
|
+
});
|
|
297
|
+
return backendsByLocation.get(location);
|
|
298
|
+
}
|
|
299
|
+
exports.getBackendForAmbiguousLocation = getBackendForAmbiguousLocation;
|
|
@@ -19,7 +19,14 @@ function targetsHaveFilters(...targets) {
|
|
|
19
19
|
function targetsHaveNoFilters(...targets) {
|
|
20
20
|
return targets.some((t) => !t.includes(":"));
|
|
21
21
|
}
|
|
22
|
-
const FILTERABLE_TARGETS = new Set([
|
|
22
|
+
const FILTERABLE_TARGETS = new Set([
|
|
23
|
+
"hosting",
|
|
24
|
+
"functions",
|
|
25
|
+
"firestore",
|
|
26
|
+
"storage",
|
|
27
|
+
"database",
|
|
28
|
+
"dataconnect",
|
|
29
|
+
]);
|
|
23
30
|
async function checkValidTargetFilters(options) {
|
|
24
31
|
const only = !options.only ? [] : options.only.split(",");
|
|
25
32
|
return new Promise((resolve, reject) => {
|
|
@@ -6,19 +6,20 @@ const projectUtils_1 = require("../projectUtils");
|
|
|
6
6
|
const requireInteractive_1 = require("../requireInteractive");
|
|
7
7
|
const apphosting_1 = require("../apphosting");
|
|
8
8
|
const apphosting_2 = require("../gcp/apphosting");
|
|
9
|
+
const firedata_1 = require("../gcp/firedata");
|
|
10
|
+
const requireTosAcceptance_1 = require("../requireTosAcceptance");
|
|
9
11
|
exports.command = new command_1.Command("apphosting:backends:create")
|
|
10
12
|
.description("create a Firebase App Hosting backend")
|
|
11
13
|
.option("-a, --app <webApp>", "specify an existing Firebase web app to associate your App Hosting backend with")
|
|
12
14
|
.option("-l, --location <location>", "specify the location of the backend", "")
|
|
13
15
|
.option("-s, --service-account <serviceAccount>", "specify the service account used to run the server", "")
|
|
14
|
-
.option("-w, --with-dev-connect", "use the Developer Connect flow instead of Cloud Build Repositories (testing)", true)
|
|
15
16
|
.before(apphosting_2.ensureApiEnabled)
|
|
16
17
|
.before(requireInteractive_1.default)
|
|
18
|
+
.before((0, requireTosAcceptance_1.requireTosAcceptance)(firedata_1.APPHOSTING_TOS_ID))
|
|
17
19
|
.action(async (options) => {
|
|
18
20
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
19
21
|
const webApp = options.app;
|
|
20
22
|
const location = options.location;
|
|
21
23
|
const serviceAccount = options.serviceAccount;
|
|
22
|
-
|
|
23
|
-
await (0, apphosting_1.doSetup)(projectId, webApp, location, serviceAccount, withDevConnect);
|
|
24
|
+
await (0, apphosting_1.doSetup)(projectId, webApp, location, serviceAccount);
|
|
24
25
|
});
|
|
@@ -9,29 +9,25 @@ const utils = require("../utils");
|
|
|
9
9
|
const apphosting = require("../gcp/apphosting");
|
|
10
10
|
const apphosting_backends_list_1 = require("./apphosting-backends-list");
|
|
11
11
|
const apphosting_1 = require("../apphosting");
|
|
12
|
+
const ora = require("ora");
|
|
12
13
|
exports.command = new command_1.Command("apphosting:backends:delete <backend>")
|
|
13
14
|
.description("delete a Firebase App Hosting backend")
|
|
14
|
-
.option("-l, --location <location>", "specify the location of the backend", "")
|
|
15
|
+
.option("-l, --location <location>", "specify the location of the backend", "-")
|
|
15
16
|
.withForce()
|
|
16
17
|
.before(apphosting.ensureApiEnabled)
|
|
17
18
|
.action(async (backendId, options) => {
|
|
18
19
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
19
20
|
let location = options.location;
|
|
20
|
-
location =
|
|
21
|
-
location ||
|
|
22
|
-
(await (0, apphosting_1.promptLocation)(projectId, "Please select the location of the backend you'd like to delete:"));
|
|
23
21
|
let backend;
|
|
24
|
-
|
|
25
|
-
backend = await
|
|
22
|
+
if (location === "-" || location === "") {
|
|
23
|
+
backend = await (0, apphosting_1.getBackendForAmbiguousLocation)(projectId, backendId, "Please select the location of the backend you'd like to delete:");
|
|
24
|
+
location = apphosting.parseBackendName(backend.name).location;
|
|
26
25
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
original: err,
|
|
30
|
-
});
|
|
26
|
+
else {
|
|
27
|
+
backend = await getBackendForLocation(projectId, location, backendId);
|
|
31
28
|
}
|
|
32
|
-
utils.logWarning("You are about to permanently delete
|
|
33
|
-
|
|
34
|
-
(0, apphosting_backends_list_1.printBackendsTable)(backends);
|
|
29
|
+
utils.logWarning("You are about to permanently delete this backend:");
|
|
30
|
+
(0, apphosting_backends_list_1.printBackendsTable)([backend]);
|
|
35
31
|
const confirmDeletion = await (0, prompt_1.promptOnce)({
|
|
36
32
|
type: "confirm",
|
|
37
33
|
name: "force",
|
|
@@ -39,14 +35,25 @@ exports.command = new command_1.Command("apphosting:backends:delete <backend>")
|
|
|
39
35
|
message: "Are you sure?",
|
|
40
36
|
}, options);
|
|
41
37
|
if (!confirmDeletion) {
|
|
42
|
-
|
|
38
|
+
return;
|
|
43
39
|
}
|
|
40
|
+
const spinner = ora("Deleting backend...").start();
|
|
44
41
|
try {
|
|
45
42
|
await (0, apphosting_1.deleteBackendAndPoll)(projectId, location, backendId);
|
|
46
|
-
|
|
43
|
+
spinner.succeed(`Successfully deleted the backend: ${backendId}`);
|
|
47
44
|
}
|
|
48
45
|
catch (err) {
|
|
49
|
-
|
|
46
|
+
spinner.stop();
|
|
47
|
+
throw new error_1.FirebaseError(`Failed to delete backend: ${backendId}.`, { original: err });
|
|
50
48
|
}
|
|
51
|
-
return backend;
|
|
52
49
|
});
|
|
50
|
+
async function getBackendForLocation(projectId, location, backendId) {
|
|
51
|
+
try {
|
|
52
|
+
return await apphosting.getBackend(projectId, location, backendId);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
throw new error_1.FirebaseError(`No backend named "${backendId}" found in ${location}.`, {
|
|
56
|
+
original: err,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -35,12 +35,12 @@ function printBackendsTable(backends) {
|
|
|
35
35
|
style: { head: ["green"] },
|
|
36
36
|
});
|
|
37
37
|
for (const backend of backends) {
|
|
38
|
-
const
|
|
38
|
+
const { location, id } = apphosting.parseBackendName(backend.name);
|
|
39
39
|
table.push([
|
|
40
|
-
|
|
40
|
+
id,
|
|
41
41
|
(_c = (_b = (_a = backend.codebase) === null || _a === void 0 ? void 0 : _a.repository) === null || _b === void 0 ? void 0 : _b.split("/").pop()) !== null && _c !== void 0 ? _c : "",
|
|
42
42
|
backend.uri.startsWith("https:") ? backend.uri : "https://" + backend.uri,
|
|
43
|
-
|
|
43
|
+
location,
|
|
44
44
|
(0, utils_1.datetimeString)(new Date(backend.updateTime)),
|
|
45
45
|
]);
|
|
46
46
|
}
|
|
@@ -12,7 +12,7 @@ const secrets = require("../apphosting/secrets");
|
|
|
12
12
|
const apphosting_1 = require("../apphosting");
|
|
13
13
|
exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretName>")
|
|
14
14
|
.description("grant service accounts permissions to the provided secret")
|
|
15
|
-
.option("-l, --location <location>", "backend location")
|
|
15
|
+
.option("-l, --location <location>", "backend location", "-")
|
|
16
16
|
.option("-b, --backend <backend>", "backend name")
|
|
17
17
|
.before(requireAuth_1.requireAuth)
|
|
18
18
|
.before(secretManager.ensureApi)
|
|
@@ -31,15 +31,19 @@ exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretN
|
|
|
31
31
|
if (!options.backend) {
|
|
32
32
|
throw new error_1.FirebaseError("Missing required flag --backend. See firebase apphosting:secrets:grantaccess --help for more info");
|
|
33
33
|
}
|
|
34
|
-
let location = options.location;
|
|
35
|
-
location =
|
|
36
|
-
location || (await (0, apphosting_1.promptLocation)(projectId, "Please select the location of your backend"));
|
|
37
34
|
const exists = await secretManager.secretExists(projectId, secretName);
|
|
38
35
|
if (!exists) {
|
|
39
36
|
throw new error_1.FirebaseError(`Cannot find secret ${secretName}`);
|
|
40
37
|
}
|
|
41
38
|
const backendId = options.backend;
|
|
42
|
-
const
|
|
39
|
+
const location = options.location;
|
|
40
|
+
let backend;
|
|
41
|
+
if (location === "" || location === "-") {
|
|
42
|
+
backend = await (0, apphosting_1.getBackendForAmbiguousLocation)(projectId, backendId, "Please select the location of your backend:");
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
backend = await apphosting.getBackend(projectId, location, backendId);
|
|
46
|
+
}
|
|
43
47
|
const accounts = secrets.toMulti(secrets.serviceAccountsForBackend(projectNumber, backend));
|
|
44
48
|
await secrets.grantSecretAccess(projectId, projectNumber, secretName, accounts);
|
|
45
49
|
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.command = void 0;
|
|
4
|
+
const command_1 = require("../command");
|
|
5
|
+
const projectUtils_1 = require("../projectUtils");
|
|
6
|
+
const names = require("../dataconnect/names");
|
|
7
|
+
const client = require("../dataconnect/client");
|
|
8
|
+
const logger_1 = require("../logger");
|
|
9
|
+
const requirePermissions_1 = require("../requirePermissions");
|
|
10
|
+
const ensureApis_1 = require("../dataconnect/ensureApis");
|
|
11
|
+
const Table = require("cli-table");
|
|
12
|
+
exports.command = new command_1.Command("dataconnect:list")
|
|
13
|
+
.description("list all deployed services in your Firebase project")
|
|
14
|
+
.before(requirePermissions_1.requirePermissions, [
|
|
15
|
+
"dataconnect.services.list",
|
|
16
|
+
"dataconnect.schemas.list",
|
|
17
|
+
"dataconnect.connectors.list",
|
|
18
|
+
])
|
|
19
|
+
.action(async (options) => {
|
|
20
|
+
var _a, _b, _c, _d, _e;
|
|
21
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
22
|
+
await (0, ensureApis_1.ensureApis)(projectId);
|
|
23
|
+
const services = await client.listAllServices(projectId);
|
|
24
|
+
const table = new Table({
|
|
25
|
+
head: [
|
|
26
|
+
"Service ID",
|
|
27
|
+
"Location",
|
|
28
|
+
"Data Source",
|
|
29
|
+
"Schema Last Updated",
|
|
30
|
+
"Connector ID",
|
|
31
|
+
"Connector Last Updated",
|
|
32
|
+
],
|
|
33
|
+
style: { head: ["yellow"] },
|
|
34
|
+
});
|
|
35
|
+
const jsonOutput = { services: [] };
|
|
36
|
+
for (const service of services) {
|
|
37
|
+
const schema = await client.getSchema(service.name);
|
|
38
|
+
const connectors = await client.listConnectors(service.name);
|
|
39
|
+
const serviceName = names.parseServiceName(service.name);
|
|
40
|
+
const instanceName = (_b = (_a = schema === null || schema === void 0 ? void 0 : schema.primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql.instance) !== null && _b !== void 0 ? _b : "";
|
|
41
|
+
const instanceId = instanceName.split("/").pop();
|
|
42
|
+
const dbId = (_d = (_c = schema === null || schema === void 0 ? void 0 : schema.primaryDatasource.postgresql) === null || _c === void 0 ? void 0 : _c.database) !== null && _d !== void 0 ? _d : "";
|
|
43
|
+
const dbName = `CloudSQL Instance: ${instanceId} Database:${dbId}`;
|
|
44
|
+
table.push([serviceName.serviceId, serviceName.location, dbName, schema === null || schema === void 0 ? void 0 : schema.updateTime, "", ""]);
|
|
45
|
+
const serviceJson = {
|
|
46
|
+
serviceId: serviceName.serviceId,
|
|
47
|
+
location: serviceName.location,
|
|
48
|
+
datasource: dbName,
|
|
49
|
+
schemaUpdateTime: schema === null || schema === void 0 ? void 0 : schema.updateTime,
|
|
50
|
+
connectors: [],
|
|
51
|
+
};
|
|
52
|
+
for (const conn of connectors) {
|
|
53
|
+
const connectorName = names.parseConnectorName(conn.name);
|
|
54
|
+
table.push(["", "", "", "", connectorName.connectorId, conn.updateTime]);
|
|
55
|
+
serviceJson.connectors.push({
|
|
56
|
+
connectorId: connectorName.connectorId,
|
|
57
|
+
connectorLastUpdated: (_e = conn.updateTime) !== null && _e !== void 0 ? _e : "",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
jsonOutput.services.push(serviceJson);
|
|
61
|
+
}
|
|
62
|
+
logger_1.logger.info(table.toString());
|
|
63
|
+
return jsonOutput;
|
|
64
|
+
});
|