firebase-tools 9.22.0 → 10.0.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/CHANGELOG.md +5 -3
- package/lib/api.js +0 -1
- package/lib/commands/database-remove.js +2 -2
- package/lib/commands/database-set.js +2 -2
- package/lib/commands/database-update.js +2 -2
- package/lib/commands/firestore-delete.js +2 -2
- package/lib/commands/functions-delete.js +7 -1
- package/lib/commands/hosting-disable.js +3 -3
- package/lib/commands/remoteconfig-get.js +6 -5
- package/lib/deploy/extensions/params.js +39 -0
- package/lib/deploy/extensions/planner.js +11 -12
- package/lib/deploy/extensions/prepare.js +9 -1
- package/lib/deploy/functions/checkIam.js +65 -4
- package/lib/deploy/functions/containerCleaner.js +68 -77
- package/lib/deploy/functions/deploy.js +6 -7
- package/lib/deploy/functions/eventTypes.js +10 -0
- package/lib/deploy/functions/prepare.js +12 -1
- package/lib/deploy/functions/release/fabricator.js +6 -1
- package/lib/deploy/functions/release/index.js +6 -2
- package/lib/deploy/functions/release/reporter.js +4 -0
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +1 -1
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +3 -9
- package/lib/deploy/functions/services/index.js +38 -0
- package/lib/deploy/functions/services/storage.js +43 -0
- package/lib/deploy/functions/triggerRegionHelper.js +6 -30
- package/lib/deploy/index.js +9 -1
- package/lib/emulator/auth/handlers.js +1 -1
- package/lib/emulator/auth/operations.js +27 -9
- package/lib/emulator/auth/widget_ui.js +17 -3
- package/lib/emulator/functionsEmulator.js +15 -1
- package/lib/emulator/functionsEmulatorRuntime.js +1 -1
- package/lib/emulator/functionsEmulatorShared.js +1 -0
- package/lib/emulator/pubsubEmulator.js +58 -45
- package/lib/emulator/storage/cloudFunctions.js +13 -6
- package/lib/ensureApiEnabled.js +11 -14
- package/lib/extensions/askUserForParam.js +32 -8
- package/lib/extensions/emulator/triggerHelper.js +1 -0
- package/lib/functions/env.js +2 -2
- package/lib/gcp/cloudfunctions.js +8 -6
- package/lib/gcp/cloudfunctionsv2.js +35 -3
- package/lib/gcp/docker.js +29 -1
- package/lib/gcp/location.js +44 -0
- package/lib/gcp/storage.js +48 -32
- package/lib/init/features/functions/index.js +3 -3
- package/lib/init/features/hosting/github.js +3 -0
- package/lib/init/features/project.js +2 -1
- package/lib/projectUtils.js +10 -1
- package/package.json +5 -5
- package/templates/init/functions/javascript/package.lint.json +1 -1
- package/templates/init/functions/javascript/package.nolint.json +1 -1
- package/templates/init/functions/typescript/package.lint.json +1 -1
- package/templates/init/functions/typescript/package.nolint.json +1 -1
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PubsubEmulator = void 0;
|
|
4
4
|
const uuid = require("uuid");
|
|
5
5
|
const pubsub_1 = require("@google-cloud/pubsub");
|
|
6
|
-
const api = require("../api");
|
|
7
6
|
const downloadableEmulators = require("./downloadableEmulators");
|
|
7
|
+
const apiv2_1 = require("../apiv2");
|
|
8
8
|
const emulatorLogger_1 = require("./emulatorLogger");
|
|
9
9
|
const types_1 = require("../emulator/types");
|
|
10
10
|
const constants_1 = require("./constants");
|
|
@@ -87,47 +87,54 @@ class PubsubEmulator {
|
|
|
87
87
|
this.triggersForTopic.set(topicName, triggers);
|
|
88
88
|
this.subscriptionForTopic.set(topicName, sub);
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
context: {
|
|
97
|
-
eventId: uuid.v4(),
|
|
98
|
-
resource: {
|
|
99
|
-
service: "pubsub.googleapis.com",
|
|
100
|
-
name: `projects/${this.args.projectId}/topics/${topic}`,
|
|
101
|
-
},
|
|
102
|
-
eventType: "google.pubsub.topic.publish",
|
|
103
|
-
timestamp: message.publishTime.toISOString(),
|
|
104
|
-
},
|
|
105
|
-
data: {
|
|
106
|
-
data: message.data,
|
|
107
|
-
attributes: message.attributes,
|
|
108
|
-
},
|
|
109
|
-
} });
|
|
90
|
+
ensureFunctionsClient() {
|
|
91
|
+
if (this.client != undefined)
|
|
92
|
+
return;
|
|
93
|
+
const funcEmulator = registry_1.EmulatorRegistry.get(types_1.Emulators.FUNCTIONS);
|
|
94
|
+
if (!funcEmulator) {
|
|
95
|
+
throw new error_1.FirebaseError(`Attempted to execute pubsub trigger but could not find the Functions emulator`);
|
|
110
96
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
97
|
+
this.client = new apiv2_1.Client({
|
|
98
|
+
urlPrefix: `http://${registry_1.EmulatorRegistry.getInfoHostString(funcEmulator.getInfo())}`,
|
|
99
|
+
auth: false,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
createLegacyEventRequestBody(topic, message) {
|
|
103
|
+
return {
|
|
104
|
+
context: {
|
|
105
|
+
eventId: uuid.v4(),
|
|
106
|
+
resource: {
|
|
107
|
+
service: "pubsub.googleapis.com",
|
|
108
|
+
name: `projects/${this.args.projectId}/topics/${topic}`,
|
|
119
109
|
},
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
110
|
+
eventType: "google.pubsub.topic.publish",
|
|
111
|
+
timestamp: message.publishTime.toISOString(),
|
|
112
|
+
},
|
|
113
|
+
data: {
|
|
114
|
+
data: message.data,
|
|
115
|
+
attributes: message.attributes,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
createCloudEventRequestBody(topic, message) {
|
|
120
|
+
const data = {
|
|
121
|
+
message: {
|
|
122
|
+
messageId: message.id,
|
|
123
|
+
publishTime: message.publishTime,
|
|
124
|
+
attributes: message.attributes,
|
|
125
|
+
orderingKey: message.orderingKey,
|
|
126
|
+
data: message.data.toString("base64"),
|
|
127
|
+
},
|
|
128
|
+
subscription: this.subscriptionForTopic.get(topic).name,
|
|
129
|
+
};
|
|
130
|
+
return {
|
|
131
|
+
specversion: "1",
|
|
132
|
+
id: uuid.v4(),
|
|
133
|
+
time: message.publishTime.toISOString(),
|
|
134
|
+
type: "google.cloud.pubsub.topic.v1.messagePublished",
|
|
135
|
+
source: `//pubsub.googleapis.com/projects/${this.args.projectId}/topics/${topic}`,
|
|
136
|
+
data,
|
|
137
|
+
};
|
|
131
138
|
}
|
|
132
139
|
async onMessage(topicName, message) {
|
|
133
140
|
this.logger.logLabeled("DEBUG", "pubsub", `onMessage(${topicName}, ${message.id})`);
|
|
@@ -135,14 +142,20 @@ class PubsubEmulator {
|
|
|
135
142
|
if (!triggers || triggers.length === 0) {
|
|
136
143
|
throw new error_1.FirebaseError(`No trigger for topic: ${topicName}`);
|
|
137
144
|
}
|
|
138
|
-
if (!registry_1.EmulatorRegistry.get(types_1.Emulators.FUNCTIONS)) {
|
|
139
|
-
throw new error_1.FirebaseError(`Attempted to execute pubsub trigger for topic ${topicName} but could not find Functions emulator`);
|
|
140
|
-
}
|
|
141
145
|
this.logger.logLabeled("DEBUG", "pubsub", `Executing ${triggers.length} matching triggers (${JSON.stringify(triggers.map((t) => t.triggerKey))})`);
|
|
146
|
+
this.ensureFunctionsClient();
|
|
142
147
|
for (const { triggerKey, signatureType } of triggers) {
|
|
143
|
-
const reqOpts = this.getRequestOptions(topicName, message, signatureType);
|
|
144
148
|
try {
|
|
145
|
-
|
|
149
|
+
const path = `/functions/projects/${this.args.projectId}/triggers/${triggerKey}`;
|
|
150
|
+
if (signatureType === "event") {
|
|
151
|
+
await this.client.post(path, this.createLegacyEventRequestBody(topicName, message));
|
|
152
|
+
}
|
|
153
|
+
else if (signatureType === "cloudevent") {
|
|
154
|
+
await this.client.post(path, this.createCloudEventRequestBody(topicName, message), { headers: { "Content-Type": "application/cloudevents+json; charset=UTF-8" } });
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
throw new error_1.FirebaseError(`Unsupported trigger signature: ${signatureType}`);
|
|
158
|
+
}
|
|
146
159
|
}
|
|
147
160
|
catch (e) {
|
|
148
161
|
this.logger.logLabeled("DEBUG", "pubsub", e);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StorageCloudFunctions = void 0;
|
|
4
|
+
const uuid = require("uuid");
|
|
4
5
|
const registry_1 = require("../registry");
|
|
5
6
|
const types_1 = require("../types");
|
|
6
7
|
const emulatorLogger_1 = require("../emulatorLogger");
|
|
@@ -57,7 +58,7 @@ class StorageCloudFunctions {
|
|
|
57
58
|
}
|
|
58
59
|
createLegacyEventRequestBody(action, objectMetadataPayload) {
|
|
59
60
|
const timestamp = new Date();
|
|
60
|
-
return
|
|
61
|
+
return {
|
|
61
62
|
eventId: `${timestamp.getTime()}`,
|
|
62
63
|
timestamp: metadata_1.toSerializedDate(timestamp),
|
|
63
64
|
eventType: `google.storage.object.${action}`,
|
|
@@ -67,20 +68,26 @@ class StorageCloudFunctions {
|
|
|
67
68
|
type: "storage#object",
|
|
68
69
|
},
|
|
69
70
|
data: objectMetadataPayload,
|
|
70
|
-
}
|
|
71
|
+
};
|
|
71
72
|
}
|
|
72
73
|
createCloudEventRequestBody(action, objectMetadataPayload) {
|
|
73
74
|
const ceAction = STORAGE_V2_ACTION_MAP[action];
|
|
74
75
|
if (!ceAction) {
|
|
75
|
-
throw new Error("Action is not
|
|
76
|
+
throw new Error("Action is not defined as a CloudEvents action");
|
|
76
77
|
}
|
|
77
78
|
const data = objectMetadataPayload;
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
let time = new Date().toISOString();
|
|
80
|
+
if (data.updated) {
|
|
81
|
+
time = typeof data.updated === "string" ? data.updated : data.updated.toISOString();
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
specversion: "1",
|
|
85
|
+
id: uuid.v4(),
|
|
80
86
|
type: `google.cloud.storage.object.v1.${ceAction}`,
|
|
81
87
|
source: `//storage.googleapis.com/projects/_/buckets/${objectMetadataPayload.bucket}/objects/${objectMetadataPayload.name}`,
|
|
88
|
+
time,
|
|
82
89
|
data,
|
|
83
|
-
}
|
|
90
|
+
};
|
|
84
91
|
}
|
|
85
92
|
}
|
|
86
93
|
exports.StorageCloudFunctions = StorageCloudFunctions;
|
package/lib/ensureApiEnabled.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ensure = exports.
|
|
4
|
-
const _ = require("lodash");
|
|
3
|
+
exports.ensure = exports.check = exports.POLL_SETTINGS = void 0;
|
|
5
4
|
const cli_color_1 = require("cli-color");
|
|
6
5
|
const track = require("./track");
|
|
7
|
-
const
|
|
6
|
+
const api_1 = require("./api");
|
|
7
|
+
const apiv2_1 = require("./apiv2");
|
|
8
8
|
const utils = require("./utils");
|
|
9
9
|
const error_1 = require("./error");
|
|
10
10
|
exports.POLL_SETTINGS = {
|
|
11
11
|
pollInterval: 10000,
|
|
12
12
|
pollsBeforeRetry: 12,
|
|
13
13
|
};
|
|
14
|
+
const apiClient = new apiv2_1.Client({
|
|
15
|
+
urlPrefix: api_1.serviceUsageOrigin,
|
|
16
|
+
apiVersion: "v1",
|
|
17
|
+
});
|
|
14
18
|
async function check(projectId, apiName, prefix, silent = false) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
origin: api.serviceUsageOrigin,
|
|
18
|
-
});
|
|
19
|
-
const isEnabled = _.get(response.body, "state") === "ENABLED";
|
|
19
|
+
const res = await apiClient.get(`/projects/${projectId}/services/${apiName}`);
|
|
20
|
+
const isEnabled = res.body.state === "ENABLED";
|
|
20
21
|
if (isEnabled && !silent) {
|
|
21
22
|
utils.logLabeledSuccess(prefix, `required API ${cli_color_1.bold(apiName)} is enabled`);
|
|
22
23
|
}
|
|
@@ -25,10 +26,7 @@ async function check(projectId, apiName, prefix, silent = false) {
|
|
|
25
26
|
exports.check = check;
|
|
26
27
|
async function enable(projectId, apiName) {
|
|
27
28
|
try {
|
|
28
|
-
await
|
|
29
|
-
auth: true,
|
|
30
|
-
origin: api.serviceUsageOrigin,
|
|
31
|
-
});
|
|
29
|
+
await apiClient.post(`/projects/${projectId}/services/${apiName}:enable`);
|
|
32
30
|
}
|
|
33
31
|
catch (err) {
|
|
34
32
|
if (error_1.isBillingError(err)) {
|
|
@@ -39,7 +37,6 @@ https://console.firebase.google.com/project/${projectId}/usage/details`);
|
|
|
39
37
|
throw err;
|
|
40
38
|
}
|
|
41
39
|
}
|
|
42
|
-
exports.enable = enable;
|
|
43
40
|
async function pollCheckEnabled(projectId, apiName, prefix, silent, enablementRetries, pollRetries = 0) {
|
|
44
41
|
if (pollRetries > exports.POLL_SETTINGS.pollsBeforeRetry) {
|
|
45
42
|
return enableApiWithRetries(projectId, apiName, prefix, silent, enablementRetries + 1);
|
|
@@ -49,7 +46,7 @@ async function pollCheckEnabled(projectId, apiName, prefix, silent, enablementRe
|
|
|
49
46
|
});
|
|
50
47
|
const isEnabled = await check(projectId, apiName, prefix, silent);
|
|
51
48
|
if (isEnabled) {
|
|
52
|
-
track("api_enabled", apiName);
|
|
49
|
+
void track("api_enabled", apiName);
|
|
53
50
|
return;
|
|
54
51
|
}
|
|
55
52
|
if (!silent) {
|
|
@@ -77,6 +77,7 @@ async function askForParam(projectId, instanceId, paramSpec, reconfiguring) {
|
|
|
77
77
|
"You may only select one option.",
|
|
78
78
|
choices: utils_1.convertExtensionOptionToLabeledList(paramSpec.options),
|
|
79
79
|
});
|
|
80
|
+
valid = checkResponse(response, paramSpec);
|
|
80
81
|
break;
|
|
81
82
|
case extensionsApi_1.ParamType.MULTISELECT:
|
|
82
83
|
response = await utils_1.onceWithJoin({
|
|
@@ -95,11 +96,13 @@ async function askForParam(projectId, instanceId, paramSpec, reconfiguring) {
|
|
|
95
96
|
"You may select multiple options.",
|
|
96
97
|
choices: utils_1.convertExtensionOptionToLabeledList(paramSpec.options),
|
|
97
98
|
});
|
|
99
|
+
valid = checkResponse(response, paramSpec);
|
|
98
100
|
break;
|
|
99
101
|
case extensionsApi_1.ParamType.SECRET:
|
|
100
102
|
response = reconfiguring
|
|
101
103
|
? await promptReconfigureSecret(projectId, instanceId, paramSpec)
|
|
102
104
|
: await promptCreateSecret(projectId, instanceId, paramSpec);
|
|
105
|
+
valid = true;
|
|
103
106
|
break;
|
|
104
107
|
default:
|
|
105
108
|
response = await prompt_1.promptOnce({
|
|
@@ -108,8 +111,8 @@ async function askForParam(projectId, instanceId, paramSpec, reconfiguring) {
|
|
|
108
111
|
default: paramSpec.default,
|
|
109
112
|
message: `Enter a value for ${label}:`,
|
|
110
113
|
});
|
|
114
|
+
valid = checkResponse(response, paramSpec);
|
|
111
115
|
}
|
|
112
|
-
valid = checkResponse(response, paramSpec);
|
|
113
116
|
}
|
|
114
117
|
return response;
|
|
115
118
|
}
|
|
@@ -139,10 +142,24 @@ async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
|
|
|
139
142
|
type: "password",
|
|
140
143
|
message: `This secret will be stored in Cloud Secret Manager as ${secretName}.\nEnter new value for ${paramSpec.label.trim()}:`,
|
|
141
144
|
});
|
|
142
|
-
if (
|
|
143
|
-
|
|
145
|
+
if (secretValue === "" && paramSpec.required) {
|
|
146
|
+
logger_1.logger.info(`Secret value cannot be empty for required param ${paramSpec.param}`);
|
|
147
|
+
return promptReconfigureSecret(projectId, instanceId, paramSpec);
|
|
148
|
+
}
|
|
149
|
+
else if (secretValue !== "") {
|
|
150
|
+
if (checkResponse(secretValue, paramSpec)) {
|
|
151
|
+
if (!secret) {
|
|
152
|
+
secret = await secretManagerApi.createSecret(projectId, secretName, secretsUtils.getSecretLabels(instanceId));
|
|
153
|
+
}
|
|
154
|
+
return addNewSecretVersion(projectId, instanceId, secret, paramSpec, secretValue);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
return promptReconfigureSecret(projectId, instanceId, paramSpec);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
return "";
|
|
144
162
|
}
|
|
145
|
-
return addNewSecretVersion(projectId, instanceId, secret, paramSpec, secretValue);
|
|
146
163
|
case SecretUpdateAction.LEAVE:
|
|
147
164
|
default:
|
|
148
165
|
return paramSpec.default || "";
|
|
@@ -158,13 +175,20 @@ async function promptCreateSecret(projectId, instanceId, paramSpec, secretName)
|
|
|
158
175
|
});
|
|
159
176
|
if (secretValue === "" && paramSpec.required) {
|
|
160
177
|
logger_1.logger.info(`Secret value cannot be empty for required param ${paramSpec.param}`);
|
|
161
|
-
return
|
|
178
|
+
return promptCreateSecret(projectId, instanceId, paramSpec, name);
|
|
162
179
|
}
|
|
163
180
|
else if (secretValue !== "") {
|
|
164
|
-
|
|
165
|
-
|
|
181
|
+
if (checkResponse(secretValue, paramSpec)) {
|
|
182
|
+
const secret = await secretManagerApi.createSecret(projectId, name, secretsUtils.getSecretLabels(instanceId));
|
|
183
|
+
return addNewSecretVersion(projectId, instanceId, secret, paramSpec, secretValue);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
return promptCreateSecret(projectId, instanceId, paramSpec, name);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
return "";
|
|
166
191
|
}
|
|
167
|
-
return secretValue;
|
|
168
192
|
}
|
|
169
193
|
exports.promptCreateSecret = promptCreateSecret;
|
|
170
194
|
async function generateSecretName(projectId, instanceId, paramName) {
|
package/lib/functions/env.js
CHANGED
|
@@ -32,11 +32,11 @@ const RESERVED_KEYS = [
|
|
|
32
32
|
const LINE_RE = new RegExp("^" +
|
|
33
33
|
"\\s*" +
|
|
34
34
|
"(\\w+)" +
|
|
35
|
-
"\\s
|
|
35
|
+
"\\s*=[\\f\\t\\v]*" +
|
|
36
36
|
"(" +
|
|
37
37
|
"\\s*'(?:\\\\'|[^'])*'|" +
|
|
38
38
|
'\\s*"(?:\\\\"|[^"])*"|' +
|
|
39
|
-
"[^#\\r\\n]
|
|
39
|
+
"[^#\\r\\n]*" +
|
|
40
40
|
")?" +
|
|
41
41
|
"\\s*" +
|
|
42
42
|
"(?:#[^\\n]*)?" +
|
|
@@ -51,9 +51,10 @@ async function createFunction(cloudFunction) {
|
|
|
51
51
|
const apiPath = cloudFunction.name.substring(0, cloudFunction.name.lastIndexOf("/"));
|
|
52
52
|
const endpoint = `/${exports.API_VERSION}/${apiPath}`;
|
|
53
53
|
try {
|
|
54
|
-
const headers =
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const headers = {};
|
|
55
|
+
if (previews_1.previews.artifactregistry) {
|
|
56
|
+
headers["X-Firebase-Artifact-Registry"] = "optin";
|
|
57
|
+
}
|
|
57
58
|
const res = await api.request("POST", endpoint, {
|
|
58
59
|
headers,
|
|
59
60
|
auth: true,
|
|
@@ -150,9 +151,10 @@ async function updateFunction(cloudFunction) {
|
|
|
150
151
|
const endpoint = `/${exports.API_VERSION}/${cloudFunction.name}`;
|
|
151
152
|
const fieldMasks = proto.fieldMasks(cloudFunction, "labels", "environmentVariables");
|
|
152
153
|
try {
|
|
153
|
-
const headers =
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
const headers = {};
|
|
155
|
+
if (previews_1.previews.artifactregistry) {
|
|
156
|
+
headers["X-Firebase-Artifact-Registry"] = "optin";
|
|
157
|
+
}
|
|
156
158
|
const res = await api.request("PATCH", endpoint, {
|
|
157
159
|
headers,
|
|
158
160
|
qs: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.endpointFromFunction = exports.functionFromEndpoint = exports.deleteFunction = exports.updateFunction = exports.listAllFunctions = exports.listFunctions = exports.getFunction = exports.createFunction = exports.generateUploadUrl = exports.PUBSUB_PUBLISH_EVENT = exports.API_VERSION = void 0;
|
|
3
|
+
exports.endpointFromFunction = exports.functionFromEndpoint = exports.deleteFunction = exports.updateFunction = exports.listAllFunctions = exports.listFunctions = exports.getFunction = exports.createFunction = exports.generateUploadUrl = exports.megabytes = exports.PUBSUB_PUBLISH_EVENT = exports.API_VERSION = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const apiv2_1 = require("../apiv2");
|
|
6
6
|
const error_1 = require("../error");
|
|
@@ -17,6 +17,35 @@ const client = new apiv2_1.Client({
|
|
|
17
17
|
apiVersion: exports.API_VERSION,
|
|
18
18
|
});
|
|
19
19
|
exports.PUBSUB_PUBLISH_EVENT = "google.cloud.pubsub.topic.v1.messagePublished";
|
|
20
|
+
const BYTES_PER_UNIT = {
|
|
21
|
+
"": 1,
|
|
22
|
+
k: 1e3,
|
|
23
|
+
M: 1e6,
|
|
24
|
+
G: 1e9,
|
|
25
|
+
T: 1e12,
|
|
26
|
+
Ki: 1 << 10,
|
|
27
|
+
Mi: 1 << 20,
|
|
28
|
+
Gi: 1 << 30,
|
|
29
|
+
Ti: 1 << 40,
|
|
30
|
+
};
|
|
31
|
+
function megabytes(memory) {
|
|
32
|
+
const re = /^([0-9]+(\.[0-9]*)?)(Ki|Mi|Gi|Ti|k|M|G|T|([eE]([0-9]+)))?$/;
|
|
33
|
+
const matches = re.exec(memory);
|
|
34
|
+
if (!matches) {
|
|
35
|
+
throw new Error(`Invalid memory quantity "${memory}""`);
|
|
36
|
+
}
|
|
37
|
+
const quantity = Number.parseFloat(matches[1]);
|
|
38
|
+
let bytes;
|
|
39
|
+
if (matches[5]) {
|
|
40
|
+
bytes = quantity * Math.pow(10, Number.parseFloat(matches[5]));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const suffix = matches[3] || "";
|
|
44
|
+
bytes = quantity * BYTES_PER_UNIT[suffix];
|
|
45
|
+
}
|
|
46
|
+
return bytes / 1e6;
|
|
47
|
+
}
|
|
48
|
+
exports.megabytes = megabytes;
|
|
20
49
|
function functionsOpLogReject(funcName, type, err) {
|
|
21
50
|
var _a, _b;
|
|
22
51
|
if (((_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode) === 429) {
|
|
@@ -136,7 +165,8 @@ function functionFromEndpoint(endpoint, source) {
|
|
|
136
165
|
serviceConfig: {},
|
|
137
166
|
};
|
|
138
167
|
proto.copyIfPresent(gcfFunction, endpoint, "labels");
|
|
139
|
-
proto.copyIfPresent(gcfFunction.serviceConfig, endpoint, "
|
|
168
|
+
proto.copyIfPresent(gcfFunction.serviceConfig, endpoint, "environmentVariables", "vpcConnector", "vpcConnectorEgressSettings", "serviceAccountEmail", "ingressSettings");
|
|
169
|
+
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "availableMemory", "availableMemoryMb", (mb) => `${mb}M`);
|
|
140
170
|
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "timeoutSeconds", "timeout", proto.secondsFromDuration);
|
|
141
171
|
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "minInstanceCount", "minInstances");
|
|
142
172
|
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "maxInstanceCount", "maxInstances");
|
|
@@ -153,6 +183,7 @@ function functionFromEndpoint(endpoint, source) {
|
|
|
153
183
|
gcfFunction.eventTrigger.eventFilters.push({ attribute, value });
|
|
154
184
|
}
|
|
155
185
|
}
|
|
186
|
+
proto.renameIfPresent(gcfFunction.eventTrigger, endpoint.eventTrigger, "triggerRegion", "region");
|
|
156
187
|
if (endpoint.eventTrigger.retry) {
|
|
157
188
|
logger_1.logger.warn("Cannot set a retry policy on Cloud Function", endpoint.id);
|
|
158
189
|
}
|
|
@@ -207,7 +238,8 @@ function endpointFromFunction(gcfFunction) {
|
|
|
207
238
|
const endpoint = Object.assign(Object.assign({ platform: "gcfv2", id,
|
|
208
239
|
project,
|
|
209
240
|
region }, trigger), { entryPoint: gcfFunction.buildConfig.entryPoint, runtime: gcfFunction.buildConfig.runtime, uri: gcfFunction.serviceConfig.uri });
|
|
210
|
-
proto.copyIfPresent(endpoint, gcfFunction.serviceConfig, "serviceAccountEmail", "
|
|
241
|
+
proto.copyIfPresent(endpoint, gcfFunction.serviceConfig, "serviceAccountEmail", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "environmentVariables");
|
|
242
|
+
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "availableMemoryMb", "availableMemory", megabytes);
|
|
211
243
|
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "timeout", "timeoutSeconds", proto.durationFromSeconds);
|
|
212
244
|
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "minInstances", "minInstanceCount");
|
|
213
245
|
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "maxInstances", "maxInstanceCount");
|
package/lib/gcp/docker.js
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Client = void 0;
|
|
3
|
+
exports.Client = exports.GCR_SUBDOMAIN_MAPPING = void 0;
|
|
4
4
|
const error_1 = require("../error");
|
|
5
5
|
const api = require("../apiv2");
|
|
6
|
+
exports.GCR_SUBDOMAIN_MAPPING = {
|
|
7
|
+
"us-west1": "us",
|
|
8
|
+
"us-west2": "us",
|
|
9
|
+
"us-west3": "us",
|
|
10
|
+
"us-west4": "us",
|
|
11
|
+
"us-central1": "us",
|
|
12
|
+
"us-central2": "us",
|
|
13
|
+
"us-east1": "us",
|
|
14
|
+
"us-east4": "us",
|
|
15
|
+
"northamerica-northeast1": "us",
|
|
16
|
+
"southamerica-east1": "us",
|
|
17
|
+
"europe-west1": "eu",
|
|
18
|
+
"europe-west2": "eu",
|
|
19
|
+
"europe-west3": "eu",
|
|
20
|
+
"europe-west4": "eu",
|
|
21
|
+
"europe-west5": "eu",
|
|
22
|
+
"europe-west6": "eu",
|
|
23
|
+
"europe-central2": "eu",
|
|
24
|
+
"europe-north1": "eu",
|
|
25
|
+
"asia-east1": "asia",
|
|
26
|
+
"asia-east2": "asia",
|
|
27
|
+
"asia-northeast1": "asia",
|
|
28
|
+
"asia-northeast2": "asia",
|
|
29
|
+
"asia-northeast3": "asia",
|
|
30
|
+
"asia-south1": "asia",
|
|
31
|
+
"asia-southeast2": "asia",
|
|
32
|
+
"australia-southeast1": "asia",
|
|
33
|
+
};
|
|
6
34
|
function isErrors(response) {
|
|
7
35
|
return !!response && Object.prototype.hasOwnProperty.call(response, "errors");
|
|
8
36
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.regionInLocation = exports.DUAL_REGION_MAPPING = exports.MULTI_REGION_MAPPING = void 0;
|
|
4
|
+
exports.MULTI_REGION_MAPPING = {
|
|
5
|
+
"us-central1": "us",
|
|
6
|
+
"us-east1": "us",
|
|
7
|
+
"us-east4": "us",
|
|
8
|
+
"us-west1": "us",
|
|
9
|
+
"us-west2": "us",
|
|
10
|
+
"us-west3": "us",
|
|
11
|
+
"us-west4": "us",
|
|
12
|
+
"europe-central2": "eu",
|
|
13
|
+
"europe-north1": "eu",
|
|
14
|
+
"europe-west1": "eu",
|
|
15
|
+
"europe-west3": "eu",
|
|
16
|
+
"europe-west4": "eu",
|
|
17
|
+
"europe-west5": "eu",
|
|
18
|
+
"asia-east1": "asia",
|
|
19
|
+
"asia-east2": "asia",
|
|
20
|
+
"asia-northeast1": "asia",
|
|
21
|
+
"asia-northeast2": "asia",
|
|
22
|
+
"asia-northeast3": "asia",
|
|
23
|
+
"asia-south1": "asia",
|
|
24
|
+
"asia-south2": "asia",
|
|
25
|
+
"asia-southeast1": "asia",
|
|
26
|
+
"asia-southeast2": "asia",
|
|
27
|
+
};
|
|
28
|
+
exports.DUAL_REGION_MAPPING = {
|
|
29
|
+
"asia-northeast1": "asia1",
|
|
30
|
+
"asia-northeast2": "asia1",
|
|
31
|
+
"europe-north1": "eur4",
|
|
32
|
+
"europe-west4": "eur4",
|
|
33
|
+
"us-central1": "nam4",
|
|
34
|
+
"us-east1": "nam4",
|
|
35
|
+
};
|
|
36
|
+
function regionInLocation(region, location) {
|
|
37
|
+
region = region.toLowerCase();
|
|
38
|
+
location = location.toLowerCase();
|
|
39
|
+
if (exports.MULTI_REGION_MAPPING[region] === location || exports.DUAL_REGION_MAPPING[region] === location) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
exports.regionInLocation = regionInLocation;
|
package/lib/gcp/storage.js
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getServiceAccount = exports.getBucket = exports.deleteObject = exports.uploadObject = exports.upload = exports.getDefaultBucket = void 0;
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const api = require("../api");
|
|
6
|
+
const logger_1 = require("../logger");
|
|
7
|
+
const error_1 = require("../error");
|
|
8
|
+
async function getDefaultBucket(projectId) {
|
|
9
|
+
try {
|
|
10
|
+
const resp = await api.request("GET", "/v1/apps/" + projectId, {
|
|
11
|
+
auth: true,
|
|
12
|
+
origin: api.appengineOrigin,
|
|
13
|
+
});
|
|
13
14
|
if (resp.body.defaultBucket === "undefined") {
|
|
14
|
-
logger.debug("Default storage bucket is undefined.");
|
|
15
|
-
|
|
15
|
+
logger_1.logger.debug("Default storage bucket is undefined.");
|
|
16
|
+
throw new error_1.FirebaseError("Your project is being set up. Please wait a minute before deploying again.");
|
|
16
17
|
}
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
return resp.body.defaultBucket;
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
logger_1.logger.info("\n\nThere was an issue deploying your functions. Verify that your project has a Google App Engine instance setup at https://console.cloud.google.com/appengine and try again. If this issue persists, please contact support.");
|
|
22
|
+
throw err;
|
|
23
|
+
}
|
|
22
24
|
}
|
|
23
|
-
|
|
25
|
+
exports.getDefaultBucket = getDefaultBucket;
|
|
26
|
+
async function upload(source, uploadUrl, extraHeaders) {
|
|
24
27
|
const url = new URL(uploadUrl);
|
|
25
28
|
const result = await api.request("PUT", url.pathname + url.search, {
|
|
26
29
|
data: source.stream,
|
|
@@ -33,9 +36,10 @@ async function _uploadSource(source, uploadUrl, extraHeaders) {
|
|
|
33
36
|
generation: result.response.headers["x-goog-generation"],
|
|
34
37
|
};
|
|
35
38
|
}
|
|
36
|
-
|
|
39
|
+
exports.upload = upload;
|
|
40
|
+
async function uploadObject(source, bucketName) {
|
|
37
41
|
if (path.extname(source.file) !== ".zip") {
|
|
38
|
-
throw new FirebaseError(`Expected a file name ending in .zip, got ${source.file}`);
|
|
42
|
+
throw new error_1.FirebaseError(`Expected a file name ending in .zip, got ${source.file}`);
|
|
39
43
|
}
|
|
40
44
|
const location = `/${bucketName}/${path.basename(source.file)}`;
|
|
41
45
|
const result = await api.request("PUT", location, {
|
|
@@ -55,13 +59,15 @@ async function _uploadObject(source, bucketName) {
|
|
|
55
59
|
generation: result.response.headers["x-goog-generation"],
|
|
56
60
|
};
|
|
57
61
|
}
|
|
58
|
-
|
|
62
|
+
exports.uploadObject = uploadObject;
|
|
63
|
+
function deleteObject(location) {
|
|
59
64
|
return api.request("DELETE", location, {
|
|
60
65
|
auth: true,
|
|
61
66
|
origin: api.storageOrigin,
|
|
62
67
|
});
|
|
63
68
|
}
|
|
64
|
-
|
|
69
|
+
exports.deleteObject = deleteObject;
|
|
70
|
+
async function getBucket(bucketName) {
|
|
65
71
|
try {
|
|
66
72
|
const result = await api.request("GET", `/storage/v1/b/${bucketName}`, {
|
|
67
73
|
auth: true,
|
|
@@ -70,16 +76,26 @@ async function _getBucket(bucketName) {
|
|
|
70
76
|
return result.body;
|
|
71
77
|
}
|
|
72
78
|
catch (err) {
|
|
73
|
-
logger.debug(err);
|
|
74
|
-
throw new FirebaseError("Failed to obtain the storage bucket", {
|
|
79
|
+
logger_1.logger.debug(err);
|
|
80
|
+
throw new error_1.FirebaseError("Failed to obtain the storage bucket", {
|
|
81
|
+
original: err,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.getBucket = getBucket;
|
|
86
|
+
async function getServiceAccount(projectId) {
|
|
87
|
+
try {
|
|
88
|
+
const response = await api.request("GET", `/storage/v1/projects/${projectId}/serviceAccount`, {
|
|
89
|
+
auth: true,
|
|
90
|
+
origin: api.storageOrigin,
|
|
91
|
+
});
|
|
92
|
+
return response.body;
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
logger_1.logger.debug(err);
|
|
96
|
+
throw new error_1.FirebaseError("Failed to obtain the Cloud Storage service agent", {
|
|
75
97
|
original: err,
|
|
76
98
|
});
|
|
77
99
|
}
|
|
78
100
|
}
|
|
79
|
-
|
|
80
|
-
getDefaultBucket: _getDefaultBucket,
|
|
81
|
-
deleteObject: _deleteObject,
|
|
82
|
-
upload: _uploadSource,
|
|
83
|
-
uploadObject: _uploadObject,
|
|
84
|
-
getBucket: _getBucket,
|
|
85
|
-
};
|
|
101
|
+
exports.getServiceAccount = getServiceAccount;
|