firebase-tools 10.1.5 → 10.2.2
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 +1 -0
- package/lib/apiv2.js +3 -0
- package/lib/appdistribution/options-parser-util.js +1 -1
- package/lib/auth.js +62 -25
- package/lib/command.js +1 -1
- package/lib/commands/apps-android-sha-create.js +2 -2
- package/lib/commands/apps-sdkconfig.js +1 -1
- package/lib/commands/auth-import.js +1 -1
- package/lib/commands/database-rules-list.js +2 -2
- package/lib/commands/emulators-start.js +1 -1
- package/lib/commands/ext-configure.js +1 -0
- package/lib/commands/ext-dev-init.js +49 -49
- package/lib/commands/ext-export.js +12 -2
- package/lib/commands/ext-install.js +104 -103
- package/lib/commands/ext-uninstall.js +9 -8
- package/lib/commands/ext-update.js +10 -9
- package/lib/commands/functions-config-clone.js +1 -1
- package/lib/commands/functions-config-export.js +1 -1
- package/lib/commands/functions-secrets-access.js +17 -0
- package/lib/commands/functions-secrets-destroy.js +40 -0
- package/lib/commands/functions-secrets-get.js +21 -0
- package/lib/commands/functions-secrets-prune.js +50 -0
- package/lib/commands/functions-secrets-set.js +46 -0
- package/lib/commands/hosting-clone.js +3 -3
- package/lib/commands/index.js +7 -3
- package/lib/commands/login.js +1 -1
- package/lib/commands/remoteconfig-get.js +1 -1
- package/lib/deploy/extensions/deploymentSummary.js +3 -3
- package/lib/deploy/extensions/params.js +3 -0
- package/lib/deploy/extensions/planner.js +2 -1
- package/lib/deploy/extensions/tasks.js +1 -1
- package/lib/deploy/functions/backend.js +20 -5
- package/lib/deploy/functions/checkIam.js +1 -1
- package/lib/deploy/functions/containerCleaner.js +3 -3
- package/lib/deploy/functions/ensure.js +112 -0
- package/lib/deploy/functions/ensureCloudBuildEnabled.js +0 -49
- package/lib/deploy/functions/functionsDeployHelper.js +2 -2
- package/lib/deploy/functions/prepare.js +15 -20
- package/lib/deploy/functions/pricing.js +1 -1
- package/lib/deploy/functions/prompts.js +2 -2
- package/lib/deploy/functions/release/fabricator.js +3 -3
- package/lib/deploy/functions/release/index.js +1 -1
- package/lib/deploy/functions/release/planner.js +11 -8
- package/lib/deploy/functions/release/reporter.js +3 -0
- package/lib/deploy/functions/runtimes/discovery/index.js +6 -6
- package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +17 -11
- package/lib/deploy/functions/runtimes/golang/index.js +2 -2
- package/lib/deploy/functions/runtimes/node/index.js +26 -0
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +40 -7
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/validate.js +58 -3
- package/lib/deploy/hosting/client.js +9 -0
- package/lib/deploy/hosting/convertConfig.js +6 -0
- package/lib/deploy/hosting/deploy.js +2 -2
- package/lib/deploy/hosting/hashcache.js +21 -19
- package/lib/deploy/hosting/index.js +5 -5
- package/lib/deploy/hosting/prepare.js +25 -25
- package/lib/deploy/hosting/release.js +21 -24
- package/lib/deploy/hosting/uploader.js +5 -5
- package/lib/deploy/remoteconfig/functions.js +2 -2
- package/lib/emulator/auth/cloudFunctions.js +1 -1
- package/lib/emulator/auth/operations.js +1 -1
- package/lib/emulator/commandUtils.js +5 -1
- package/lib/emulator/constants.js +3 -0
- package/lib/emulator/controller.js +48 -18
- package/lib/emulator/download.js +18 -1
- package/lib/emulator/downloadableEmulators.js +30 -13
- package/lib/emulator/emulatorLogger.js +19 -1
- package/lib/emulator/extensions/validation.js +35 -0
- package/lib/emulator/extensionsEmulator.js +140 -0
- package/lib/emulator/functionsEmulator.js +175 -86
- package/lib/emulator/functionsEmulatorRuntime.js +108 -83
- package/lib/emulator/functionsEmulatorShared.js +51 -1
- package/lib/emulator/functionsEmulatorShell.js +1 -2
- package/lib/emulator/functionsEmulatorUtils.js +4 -4
- package/lib/emulator/functionsRuntimeWorker.js +3 -3
- package/lib/emulator/hub.js +4 -3
- package/lib/emulator/loggingEmulator.js +1 -1
- package/lib/emulator/pubsubEmulator.js +1 -1
- package/lib/emulator/registry.js +10 -2
- package/lib/emulator/storage/apis/firebase.js +31 -26
- package/lib/emulator/storage/apis/gcloud.js +7 -12
- package/lib/emulator/storage/files.js +36 -34
- package/lib/emulator/storage/index.js +2 -2
- package/lib/emulator/storage/metadata.js +2 -2
- package/lib/emulator/storage/rules/runtime.js +8 -7
- package/lib/emulator/types.js +3 -0
- package/lib/ensureApiEnabled.js +5 -1
- package/lib/error.js +1 -1
- package/lib/extensions/askUserForParam.js +2 -2
- package/lib/extensions/changelog.js +3 -1
- package/lib/extensions/checkProjectBilling.js +1 -1
- package/lib/extensions/diagnose.js +56 -0
- package/lib/extensions/displayExtensionInfo.js +1 -1
- package/lib/extensions/emulator/optionsHelper.js +24 -8
- package/lib/extensions/emulator/specHelper.js +10 -23
- package/lib/extensions/export.js +1 -51
- package/lib/extensions/extensionsApi.js +1 -1
- package/lib/extensions/extensionsHelper.js +23 -10
- package/lib/extensions/listExtensions.js +2 -0
- package/lib/extensions/manifest.js +48 -0
- package/lib/extensions/metricsUtils.js +4 -4
- package/lib/extensions/paramHelper.js +4 -4
- package/lib/extensions/refs.js +1 -1
- package/lib/extensions/secretsUtils.js +4 -4
- package/lib/functional.js +1 -1
- package/lib/functions/env.js +7 -8
- package/lib/functions/secrets.js +112 -0
- package/lib/gcp/cloudfunctions.js +24 -5
- package/lib/gcp/cloudfunctionsv2.js +18 -5
- package/lib/gcp/cloudtasks.js +1 -1
- package/lib/gcp/docker.js +2 -2
- package/lib/gcp/run.js +2 -2
- package/lib/gcp/secretManager.js +128 -46
- package/lib/gcp/storage.js +1 -0
- package/lib/hosting/api.js +1 -1
- package/lib/hosting/functionsProxy.js +15 -5
- package/lib/hosting/proxy.js +2 -2
- package/lib/init/features/account.js +1 -1
- package/lib/management/database.js +1 -1
- package/lib/previews.js +1 -1
- package/lib/responseToError.js +16 -7
- package/lib/serve/functions.js +2 -2
- package/lib/serve/hosting.js +1 -1
- package/lib/utils.js +7 -2
- package/npm-shrinkwrap.json +904 -412
- package/package.json +3 -3
- package/schema/firebase-config.json +32 -0
- package/templates/init/functions/javascript/package.lint.json +3 -3
- package/templates/init/functions/javascript/package.nolint.json +2 -2
- package/templates/init/functions/typescript/package.lint.json +7 -7
- package/templates/init/functions/typescript/package.nolint.json +3 -3
|
@@ -92,7 +92,7 @@ async function getIamPolicy(fnName) {
|
|
|
92
92
|
}
|
|
93
93
|
exports.getIamPolicy = getIamPolicy;
|
|
94
94
|
async function setInvokerCreate(projectId, fnName, invoker) {
|
|
95
|
-
if (invoker.length
|
|
95
|
+
if (invoker.length === 0) {
|
|
96
96
|
throw new error_1.FirebaseError("Invoker cannot be an empty array");
|
|
97
97
|
}
|
|
98
98
|
const invokerMembers = proto.getInvokerMembers(invoker, projectId);
|
|
@@ -108,7 +108,7 @@ async function setInvokerCreate(projectId, fnName, invoker) {
|
|
|
108
108
|
exports.setInvokerCreate = setInvokerCreate;
|
|
109
109
|
async function setInvokerUpdate(projectId, fnName, invoker) {
|
|
110
110
|
var _a;
|
|
111
|
-
if (invoker.length
|
|
111
|
+
if (invoker.length === 0) {
|
|
112
112
|
throw new error_1.FirebaseError("Invoker cannot be an empty array");
|
|
113
113
|
}
|
|
114
114
|
const invokerMembers = proto.getInvokerMembers(invoker, projectId);
|
|
@@ -206,6 +206,7 @@ function endpointFromFunction(gcfFunction) {
|
|
|
206
206
|
const [, project, , region, , id] = gcfFunction.name.split("/");
|
|
207
207
|
let trigger;
|
|
208
208
|
let uri;
|
|
209
|
+
let securityLevel;
|
|
209
210
|
if ((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) {
|
|
210
211
|
trigger = {
|
|
211
212
|
scheduleTrigger: {},
|
|
@@ -219,6 +220,7 @@ function endpointFromFunction(gcfFunction) {
|
|
|
219
220
|
else if (gcfFunction.httpsTrigger) {
|
|
220
221
|
trigger = { httpsTrigger: {} };
|
|
221
222
|
uri = gcfFunction.httpsTrigger.url;
|
|
223
|
+
securityLevel = gcfFunction.httpsTrigger.securityLevel;
|
|
222
224
|
}
|
|
223
225
|
else {
|
|
224
226
|
trigger = {
|
|
@@ -240,12 +242,19 @@ function endpointFromFunction(gcfFunction) {
|
|
|
240
242
|
if (uri) {
|
|
241
243
|
endpoint.uri = uri;
|
|
242
244
|
}
|
|
243
|
-
|
|
245
|
+
if (securityLevel) {
|
|
246
|
+
endpoint.securityLevel = securityLevel;
|
|
247
|
+
}
|
|
248
|
+
proto.copyIfPresent(endpoint, gcfFunction, "serviceAccountEmail", "availableMemoryMb", "timeout", "minInstances", "maxInstances", "ingressSettings", "labels", "environmentVariables", "secretEnvironmentVariables", "sourceUploadUrl");
|
|
249
|
+
if (gcfFunction.vpcConnector) {
|
|
250
|
+
endpoint.vpc = { connector: gcfFunction.vpcConnector };
|
|
251
|
+
proto.renameIfPresent(endpoint.vpc, gcfFunction, "egressSettings", "vpcConnectorEgressSettings");
|
|
252
|
+
}
|
|
244
253
|
return endpoint;
|
|
245
254
|
}
|
|
246
255
|
exports.endpointFromFunction = endpointFromFunction;
|
|
247
256
|
function functionFromEndpoint(endpoint, sourceUploadUrl) {
|
|
248
|
-
if (endpoint.platform
|
|
257
|
+
if (endpoint.platform !== "gcfv1") {
|
|
249
258
|
throw new error_1.FirebaseError("Trying to create a v1 CloudFunction with v2 API. This should never happen");
|
|
250
259
|
}
|
|
251
260
|
if (!runtimes.isValidRuntime(endpoint.runtime)) {
|
|
@@ -282,8 +291,18 @@ function functionFromEndpoint(endpoint, sourceUploadUrl) {
|
|
|
282
291
|
}
|
|
283
292
|
else {
|
|
284
293
|
gcfFunction.httpsTrigger = {};
|
|
294
|
+
if (backend.isCallableTriggered(endpoint)) {
|
|
295
|
+
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-callabled": "true" });
|
|
296
|
+
}
|
|
297
|
+
if (endpoint.securityLevel) {
|
|
298
|
+
gcfFunction.httpsTrigger.securityLevel = endpoint.securityLevel;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
proto.copyIfPresent(gcfFunction, endpoint, "serviceAccountEmail", "timeout", "availableMemoryMb", "minInstances", "maxInstances", "ingressSettings", "environmentVariables", "secretEnvironmentVariables");
|
|
302
|
+
if (endpoint.vpc) {
|
|
303
|
+
proto.renameIfPresent(gcfFunction, endpoint.vpc, "vpcConnector", "connector");
|
|
304
|
+
proto.renameIfPresent(gcfFunction, endpoint.vpc, "vpcConnectorEgressSettings", "egressSettings");
|
|
285
305
|
}
|
|
286
|
-
proto.copyIfPresent(gcfFunction, endpoint, "serviceAccountEmail", "timeout", "availableMemoryMb", "minInstances", "maxInstances", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "environmentVariables");
|
|
287
306
|
return gcfFunction;
|
|
288
307
|
}
|
|
289
308
|
exports.functionFromEndpoint = functionFromEndpoint;
|
|
@@ -106,7 +106,7 @@ async function listFunctionsInternal(projectId, region) {
|
|
|
106
106
|
let pageToken = "";
|
|
107
107
|
while (true) {
|
|
108
108
|
const url = `projects/${projectId}/locations/${region}/functions`;
|
|
109
|
-
const opts = pageToken
|
|
109
|
+
const opts = pageToken === "" ? {} : { queryParams: { pageToken } };
|
|
110
110
|
const res = await client.get(url, opts);
|
|
111
111
|
functions.push(...(res.body.functions || []));
|
|
112
112
|
for (const region of res.body.unreachable || []) {
|
|
@@ -122,9 +122,10 @@ async function listFunctionsInternal(projectId, region) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
async function updateFunction(cloudFunction) {
|
|
125
|
+
const fieldMasks = proto.fieldMasks(cloudFunction, "labels", "serviceConfig.environmentVariables");
|
|
125
126
|
try {
|
|
126
127
|
const queryParams = {
|
|
127
|
-
updateMask:
|
|
128
|
+
updateMask: fieldMasks.join(","),
|
|
128
129
|
};
|
|
129
130
|
const res = await client.patch(cloudFunction.name, cloudFunction, { queryParams });
|
|
130
131
|
return res.body;
|
|
@@ -145,7 +146,7 @@ async function deleteFunction(cloudFunction) {
|
|
|
145
146
|
}
|
|
146
147
|
exports.deleteFunction = deleteFunction;
|
|
147
148
|
function functionFromEndpoint(endpoint, source) {
|
|
148
|
-
if (endpoint.platform
|
|
149
|
+
if (endpoint.platform !== "gcfv2") {
|
|
149
150
|
throw new error_1.FirebaseError("Trying to create a v2 CloudFunction with v1 API. This should never happen");
|
|
150
151
|
}
|
|
151
152
|
if (!runtimes.isValidRuntime(endpoint.runtime)) {
|
|
@@ -165,11 +166,15 @@ function functionFromEndpoint(endpoint, source) {
|
|
|
165
166
|
serviceConfig: {},
|
|
166
167
|
};
|
|
167
168
|
proto.copyIfPresent(gcfFunction, endpoint, "labels");
|
|
168
|
-
proto.copyIfPresent(gcfFunction.serviceConfig, endpoint, "environmentVariables", "
|
|
169
|
+
proto.copyIfPresent(gcfFunction.serviceConfig, endpoint, "environmentVariables", "serviceAccountEmail", "ingressSettings");
|
|
169
170
|
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "availableMemory", "availableMemoryMb", (mb) => `${mb}M`);
|
|
170
171
|
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "timeoutSeconds", "timeout", proto.secondsFromDuration);
|
|
171
172
|
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "minInstanceCount", "minInstances");
|
|
172
173
|
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "maxInstanceCount", "maxInstances");
|
|
174
|
+
if (endpoint.vpc) {
|
|
175
|
+
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint.vpc, "vpcConnector", "connector");
|
|
176
|
+
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint.vpc, "vpcConnectorEgressSettings", "egressSettings");
|
|
177
|
+
}
|
|
173
178
|
if (backend.isEventTriggered(endpoint)) {
|
|
174
179
|
gcfFunction.eventTrigger = {
|
|
175
180
|
eventType: endpoint.eventTrigger.eventType,
|
|
@@ -187,6 +192,7 @@ function functionFromEndpoint(endpoint, source) {
|
|
|
187
192
|
if (endpoint.eventTrigger.retry) {
|
|
188
193
|
logger_1.logger.warn("Cannot set a retry policy on Cloud Function", endpoint.id);
|
|
189
194
|
}
|
|
195
|
+
gcfFunction.serviceConfig.environmentVariables = Object.assign(Object.assign({}, gcfFunction.serviceConfig.environmentVariables), { FUNCTION_SIGNATURE_TYPE: "cloudevent" });
|
|
190
196
|
}
|
|
191
197
|
else if (backend.isScheduleTriggered(endpoint)) {
|
|
192
198
|
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-scheduled": "true" });
|
|
@@ -194,6 +200,9 @@ function functionFromEndpoint(endpoint, source) {
|
|
|
194
200
|
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
195
201
|
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-taskqueue": "true" });
|
|
196
202
|
}
|
|
203
|
+
else if (backend.isCallableTriggered(endpoint)) {
|
|
204
|
+
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-callable": "true" });
|
|
205
|
+
}
|
|
197
206
|
return gcfFunction;
|
|
198
207
|
}
|
|
199
208
|
exports.functionFromEndpoint = functionFromEndpoint;
|
|
@@ -238,12 +247,16 @@ function endpointFromFunction(gcfFunction) {
|
|
|
238
247
|
const endpoint = Object.assign(Object.assign({ platform: "gcfv2", id,
|
|
239
248
|
project,
|
|
240
249
|
region }, trigger), { entryPoint: gcfFunction.buildConfig.entryPoint, runtime: gcfFunction.buildConfig.runtime, uri: gcfFunction.serviceConfig.uri });
|
|
241
|
-
proto.copyIfPresent(endpoint, gcfFunction.serviceConfig, "serviceAccountEmail", "
|
|
250
|
+
proto.copyIfPresent(endpoint, gcfFunction.serviceConfig, "serviceAccountEmail", "ingressSettings", "environmentVariables");
|
|
242
251
|
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "availableMemoryMb", "availableMemory", megabytes);
|
|
243
252
|
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "timeout", "timeoutSeconds", proto.durationFromSeconds);
|
|
244
253
|
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "minInstances", "minInstanceCount");
|
|
245
254
|
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "maxInstances", "maxInstanceCount");
|
|
246
255
|
proto.copyIfPresent(endpoint, gcfFunction, "labels");
|
|
256
|
+
if (gcfFunction.serviceConfig.vpcConnector) {
|
|
257
|
+
endpoint.vpc = { connector: gcfFunction.serviceConfig.vpcConnector };
|
|
258
|
+
proto.renameIfPresent(endpoint.vpc, gcfFunction.serviceConfig, "egressSettings", "vpcConnectorEgressSettings");
|
|
259
|
+
}
|
|
247
260
|
return endpoint;
|
|
248
261
|
}
|
|
249
262
|
exports.endpointFromFunction = endpointFromFunction;
|
package/lib/gcp/cloudtasks.js
CHANGED
|
@@ -102,7 +102,7 @@ async function setEnqueuer(name, invoker, assumeEmpty = false) {
|
|
|
102
102
|
const invokerMembers = proto.getInvokerMembers(invoker, project);
|
|
103
103
|
while (true) {
|
|
104
104
|
const policy = {
|
|
105
|
-
bindings: existing.bindings.filter((binding) => binding.role
|
|
105
|
+
bindings: existing.bindings.filter((binding) => binding.role !== ENQUEUER_ROLE),
|
|
106
106
|
etag: existing.etag,
|
|
107
107
|
version: existing.version,
|
|
108
108
|
};
|
package/lib/gcp/docker.js
CHANGED
|
@@ -58,7 +58,7 @@ class Client {
|
|
|
58
58
|
if (!response.body) {
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
-
if (((_a = response.body.errors) === null || _a === void 0 ? void 0 : _a.length)
|
|
61
|
+
if (((_a = response.body.errors) === null || _a === void 0 ? void 0 : _a.length) !== 0) {
|
|
62
62
|
throw new error_1.FirebaseError(`Failed to delete tag ${tag} at path ${path}`, {
|
|
63
63
|
children: response.body.errors,
|
|
64
64
|
});
|
|
@@ -70,7 +70,7 @@ class Client {
|
|
|
70
70
|
if (!response.body) {
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
|
-
if (((_a = response.body.errors) === null || _a === void 0 ? void 0 : _a.length)
|
|
73
|
+
if (((_a = response.body.errors) === null || _a === void 0 ? void 0 : _a.length) !== 0) {
|
|
74
74
|
throw new error_1.FirebaseError(`Failed to delete image ${digest} at path ${path}`, {
|
|
75
75
|
children: response.body.errors,
|
|
76
76
|
});
|
package/lib/gcp/run.js
CHANGED
|
@@ -63,7 +63,7 @@ async function getIamPolicy(serviceName, httpClient = client) {
|
|
|
63
63
|
}
|
|
64
64
|
exports.getIamPolicy = getIamPolicy;
|
|
65
65
|
async function setInvokerCreate(projectId, serviceName, invoker, httpClient = client) {
|
|
66
|
-
if (invoker.length
|
|
66
|
+
if (invoker.length === 0) {
|
|
67
67
|
throw new error_1.FirebaseError("Invoker cannot be an empty array");
|
|
68
68
|
}
|
|
69
69
|
const invokerMembers = proto.getInvokerMembers(invoker, projectId);
|
|
@@ -79,7 +79,7 @@ async function setInvokerCreate(projectId, serviceName, invoker, httpClient = cl
|
|
|
79
79
|
exports.setInvokerCreate = setInvokerCreate;
|
|
80
80
|
async function setInvokerUpdate(projectId, serviceName, invoker, httpClient = client) {
|
|
81
81
|
var _a;
|
|
82
|
-
if (invoker.length
|
|
82
|
+
if (invoker.length === 0) {
|
|
83
83
|
throw new error_1.FirebaseError("Invoker cannot be an empty array");
|
|
84
84
|
}
|
|
85
85
|
const invokerMembers = proto.getInvokerMembers(invoker, projectId);
|
package/lib/gcp/secretManager.js
CHANGED
|
@@ -1,30 +1,88 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.ensureServiceAgentRole = exports.setIamPolicy = exports.getIamPolicy = exports.addVersion = exports.deleteSecret = exports.patchSecret = exports.createSecret = exports.toSecretVersionResourceName = exports.parseSecretVersionResourceName = exports.parseSecretResourceName = exports.secretExists = exports.destroySecretVersion = exports.accessSecretVersion = exports.getSecretVersion = exports.listSecretVersions = exports.listSecrets = exports.getSecret = exports.secretManagerConsoleUri = void 0;
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
|
-
const
|
|
5
|
+
const error_1 = require("../error");
|
|
6
6
|
const apiv2_1 = require("../apiv2");
|
|
7
|
+
const api_1 = require("../api");
|
|
8
|
+
const SECRET_NAME_REGEX = new RegExp("projects\\/" +
|
|
9
|
+
"(?<project>(?:\\d+)|(?:[A-Za-z]+[A-Za-z\\d-]*[A-Za-z\\d]?))\\/" +
|
|
10
|
+
"secrets\\/" +
|
|
11
|
+
"(?<secret>[A-Za-z\\d\\-_]+)");
|
|
12
|
+
const SECRET_VERSION_NAME_REGEX = new RegExp(SECRET_NAME_REGEX.source + "\\/versions\\/" + "(?<version>latest|[0-9]+)");
|
|
7
13
|
const secretManagerConsoleUri = (projectId) => `https://console.cloud.google.com/security/secret-manager?project=${projectId}`;
|
|
8
14
|
exports.secretManagerConsoleUri = secretManagerConsoleUri;
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const listRes = await apiClient.get(`/projects/${projectId}/secrets`);
|
|
12
|
-
return listRes.body.secrets.map((s) => parseSecretResourceName(s.name));
|
|
13
|
-
}
|
|
14
|
-
exports.listSecrets = listSecrets;
|
|
15
|
+
const API_VERSION = "v1";
|
|
16
|
+
const client = new apiv2_1.Client({ urlPrefix: api_1.secretManagerOrigin, apiVersion: API_VERSION });
|
|
15
17
|
async function getSecret(projectId, name) {
|
|
16
18
|
var _a;
|
|
17
|
-
const getRes = await
|
|
19
|
+
const getRes = await client.get(`projects/${projectId}/secrets/${name}`);
|
|
18
20
|
const secret = parseSecretResourceName(getRes.body.name);
|
|
19
21
|
secret.labels = (_a = getRes.body.labels) !== null && _a !== void 0 ? _a : {};
|
|
20
22
|
return secret;
|
|
21
23
|
}
|
|
22
24
|
exports.getSecret = getSecret;
|
|
25
|
+
async function listSecrets(projectId, filter) {
|
|
26
|
+
var _a;
|
|
27
|
+
const secrets = [];
|
|
28
|
+
const path = `projects/${projectId}/secrets`;
|
|
29
|
+
const baseOpts = filter ? { queryParams: { filter } } : {};
|
|
30
|
+
let pageToken = "";
|
|
31
|
+
while (true) {
|
|
32
|
+
const opts = pageToken === ""
|
|
33
|
+
? baseOpts
|
|
34
|
+
: Object.assign(Object.assign({}, baseOpts), { queryParams: Object.assign(Object.assign({}, baseOpts === null || baseOpts === void 0 ? void 0 : baseOpts.queryParams), { pageToken }) });
|
|
35
|
+
const res = await client.get(path, opts);
|
|
36
|
+
for (const s of res.body.secrets) {
|
|
37
|
+
secrets.push(Object.assign(Object.assign({}, parseSecretResourceName(s.name)), { labels: (_a = s.labels) !== null && _a !== void 0 ? _a : {} }));
|
|
38
|
+
}
|
|
39
|
+
if (!res.body.nextPageToken) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
pageToken = res.body.nextPageToken;
|
|
43
|
+
}
|
|
44
|
+
return secrets;
|
|
45
|
+
}
|
|
46
|
+
exports.listSecrets = listSecrets;
|
|
47
|
+
async function listSecretVersions(projectId, name, filter) {
|
|
48
|
+
const secrets = [];
|
|
49
|
+
const path = `projects/${projectId}/secrets/${name}/versions`;
|
|
50
|
+
const baseOpts = filter ? { queryParams: { filter } } : {};
|
|
51
|
+
let pageToken = "";
|
|
52
|
+
while (true) {
|
|
53
|
+
const opts = pageToken === ""
|
|
54
|
+
? baseOpts
|
|
55
|
+
: Object.assign(Object.assign({}, baseOpts), { queryParams: Object.assign(Object.assign({}, baseOpts === null || baseOpts === void 0 ? void 0 : baseOpts.queryParams), { pageToken }) });
|
|
56
|
+
const res = await client.get(path, opts);
|
|
57
|
+
for (const s of res.body.versions || []) {
|
|
58
|
+
secrets.push(Object.assign(Object.assign({}, parseSecretVersionResourceName(s.name)), { state: s.state }));
|
|
59
|
+
}
|
|
60
|
+
if (!res.body.nextPageToken) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
pageToken = res.body.nextPageToken;
|
|
64
|
+
}
|
|
65
|
+
return secrets;
|
|
66
|
+
}
|
|
67
|
+
exports.listSecretVersions = listSecretVersions;
|
|
23
68
|
async function getSecretVersion(projectId, name, version) {
|
|
24
|
-
const getRes = await
|
|
25
|
-
return parseSecretVersionResourceName(getRes.body.name);
|
|
69
|
+
const getRes = await client.get(`projects/${projectId}/secrets/${name}/versions/${version}`);
|
|
70
|
+
return Object.assign(Object.assign({}, parseSecretVersionResourceName(getRes.body.name)), { state: getRes.body.state });
|
|
26
71
|
}
|
|
27
72
|
exports.getSecretVersion = getSecretVersion;
|
|
73
|
+
async function accessSecretVersion(projectId, name, version) {
|
|
74
|
+
const res = await client.get(`projects/${projectId}/secrets/${name}/versions/${version}:access`);
|
|
75
|
+
return Buffer.from(res.body.payload.data, "base64").toString();
|
|
76
|
+
}
|
|
77
|
+
exports.accessSecretVersion = accessSecretVersion;
|
|
78
|
+
async function destroySecretVersion(projectId, name, version) {
|
|
79
|
+
if (version === "latest") {
|
|
80
|
+
const sv = await getSecretVersion(projectId, name, "latest");
|
|
81
|
+
version = sv.versionId;
|
|
82
|
+
}
|
|
83
|
+
await client.post(`projects/${projectId}/secrets/${name}/versions/${version}:destroy`);
|
|
84
|
+
}
|
|
85
|
+
exports.destroySecretVersion = destroySecretVersion;
|
|
28
86
|
async function secretExists(projectId, name) {
|
|
29
87
|
try {
|
|
30
88
|
await getSecret(projectId, name);
|
|
@@ -39,21 +97,27 @@ async function secretExists(projectId, name) {
|
|
|
39
97
|
}
|
|
40
98
|
exports.secretExists = secretExists;
|
|
41
99
|
function parseSecretResourceName(resourceName) {
|
|
42
|
-
const
|
|
100
|
+
const match = SECRET_NAME_REGEX.exec(resourceName);
|
|
101
|
+
if (!(match === null || match === void 0 ? void 0 : match.groups)) {
|
|
102
|
+
throw new error_1.FirebaseError(`Invalid secret resource name [${resourceName}].`);
|
|
103
|
+
}
|
|
43
104
|
return {
|
|
44
|
-
projectId:
|
|
45
|
-
name:
|
|
105
|
+
projectId: match.groups.project,
|
|
106
|
+
name: match.groups.secret,
|
|
46
107
|
};
|
|
47
108
|
}
|
|
48
109
|
exports.parseSecretResourceName = parseSecretResourceName;
|
|
49
110
|
function parseSecretVersionResourceName(resourceName) {
|
|
50
|
-
const
|
|
111
|
+
const match = resourceName.match(SECRET_VERSION_NAME_REGEX);
|
|
112
|
+
if (!(match === null || match === void 0 ? void 0 : match.groups)) {
|
|
113
|
+
throw new error_1.FirebaseError(`Invalid secret version resource name [${resourceName}].`);
|
|
114
|
+
}
|
|
51
115
|
return {
|
|
52
116
|
secret: {
|
|
53
|
-
projectId:
|
|
54
|
-
name:
|
|
117
|
+
projectId: match.groups.project,
|
|
118
|
+
name: match.groups.secret,
|
|
55
119
|
},
|
|
56
|
-
versionId:
|
|
120
|
+
versionId: match.groups.version,
|
|
57
121
|
};
|
|
58
122
|
}
|
|
59
123
|
exports.parseSecretVersionResourceName = parseSecretVersionResourceName;
|
|
@@ -62,7 +126,8 @@ function toSecretVersionResourceName(secretVersion) {
|
|
|
62
126
|
}
|
|
63
127
|
exports.toSecretVersionResourceName = toSecretVersionResourceName;
|
|
64
128
|
async function createSecret(projectId, name, labels) {
|
|
65
|
-
const createRes = await
|
|
129
|
+
const createRes = await client.post(`projects/${projectId}/secrets`, {
|
|
130
|
+
name,
|
|
66
131
|
replication: {
|
|
67
132
|
automatic: {},
|
|
68
133
|
},
|
|
@@ -71,41 +136,58 @@ async function createSecret(projectId, name, labels) {
|
|
|
71
136
|
return parseSecretResourceName(createRes.body.name);
|
|
72
137
|
}
|
|
73
138
|
exports.createSecret = createSecret;
|
|
74
|
-
async function
|
|
75
|
-
const
|
|
139
|
+
async function patchSecret(projectId, name, labels) {
|
|
140
|
+
const fullName = `projects/${projectId}/secrets/${name}`;
|
|
141
|
+
const res = await client.patch(fullName, { name: fullName, labels }, { queryParams: { updateMask: "labels" } });
|
|
142
|
+
return parseSecretResourceName(res.body.name);
|
|
143
|
+
}
|
|
144
|
+
exports.patchSecret = patchSecret;
|
|
145
|
+
async function deleteSecret(projectId, name) {
|
|
146
|
+
const path = `projects/${projectId}/secrets/${name}`;
|
|
147
|
+
await client.delete(path);
|
|
148
|
+
}
|
|
149
|
+
exports.deleteSecret = deleteSecret;
|
|
150
|
+
async function addVersion(projectId, name, payloadData) {
|
|
151
|
+
const res = await client.post(`projects/${projectId}/secrets/${name}:addVersion`, {
|
|
76
152
|
payload: {
|
|
77
153
|
data: Buffer.from(payloadData).toString("base64"),
|
|
78
154
|
},
|
|
79
155
|
});
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
secret: {
|
|
83
|
-
projectId: nameTokens[1],
|
|
84
|
-
name: nameTokens[3],
|
|
85
|
-
},
|
|
86
|
-
versionId: nameTokens[5],
|
|
87
|
-
};
|
|
156
|
+
return Object.assign(Object.assign({}, parseSecretVersionResourceName(res.body.name)), { state: res.body.state });
|
|
88
157
|
}
|
|
89
158
|
exports.addVersion = addVersion;
|
|
90
|
-
async function
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
bindings.push({
|
|
98
|
-
role: role,
|
|
99
|
-
members: [`serviceAccount:${serviceAccountEmail}`],
|
|
100
|
-
});
|
|
101
|
-
await apiClient.post(`/projects/${secret.projectId}/secrets/${secret.name}:setIamPolicy`, {
|
|
159
|
+
async function getIamPolicy(secret) {
|
|
160
|
+
const res = await client.get(`projects/${secret.projectId}/secrets/${secret.name}:getIamPolicy`);
|
|
161
|
+
return res.body;
|
|
162
|
+
}
|
|
163
|
+
exports.getIamPolicy = getIamPolicy;
|
|
164
|
+
async function setIamPolicy(secret, bindings) {
|
|
165
|
+
await client.post(`projects/${secret.projectId}/secrets/${secret.name}:setIamPolicy`, {
|
|
102
166
|
policy: {
|
|
103
167
|
bindings,
|
|
104
168
|
},
|
|
105
|
-
updateMask:
|
|
106
|
-
paths: "bindings",
|
|
107
|
-
},
|
|
169
|
+
updateMask: "bindings",
|
|
108
170
|
});
|
|
109
|
-
(0, utils_1.logLabeledSuccess)("SecretManager", `Granted ${role} on projects/${secret.projectId}/secrets/${secret.name} to ${serviceAccountEmail}`);
|
|
110
171
|
}
|
|
111
|
-
exports.
|
|
172
|
+
exports.setIamPolicy = setIamPolicy;
|
|
173
|
+
async function ensureServiceAgentRole(secret, serviceAccountEmails, role) {
|
|
174
|
+
const policy = await module.exports.getIamPolicy(secret);
|
|
175
|
+
const bindings = policy.bindings || [];
|
|
176
|
+
let binding = bindings.find((b) => b.role === role);
|
|
177
|
+
if (!binding) {
|
|
178
|
+
binding = { role, members: [] };
|
|
179
|
+
bindings.push(binding);
|
|
180
|
+
}
|
|
181
|
+
let shouldShortCircuit = true;
|
|
182
|
+
for (const serviceAccount of serviceAccountEmails) {
|
|
183
|
+
if (!binding.members.find((m) => m === `serviceAccount:${serviceAccount}`)) {
|
|
184
|
+
binding.members.push(`serviceAccount:${serviceAccount}`);
|
|
185
|
+
shouldShortCircuit = false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (shouldShortCircuit)
|
|
189
|
+
return;
|
|
190
|
+
await module.exports.setIamPolicy(secret, bindings);
|
|
191
|
+
(0, utils_1.logLabeledSuccess)("secretmanager", `Granted ${role} on projects/${secret.projectId}/secrets/${secret.name} to ${serviceAccountEmails.join(", ")}`);
|
|
192
|
+
}
|
|
193
|
+
exports.ensureServiceAgentRole = ensureServiceAgentRole;
|
package/lib/gcp/storage.js
CHANGED
|
@@ -29,6 +29,7 @@ async function upload(source, uploadUrl, extraHeaders) {
|
|
|
29
29
|
method: "PUT",
|
|
30
30
|
path: url.pathname,
|
|
31
31
|
queryParams: url.searchParams,
|
|
32
|
+
responseType: "xml",
|
|
32
33
|
headers: Object.assign({ "content-type": "application/zip" }, extraHeaders),
|
|
33
34
|
body: source.stream,
|
|
34
35
|
skipLog: { resBody: true },
|
package/lib/hosting/api.js
CHANGED
|
@@ -192,7 +192,7 @@ async function removeAuthDomain(project, url) {
|
|
|
192
192
|
return domains;
|
|
193
193
|
}
|
|
194
194
|
const targetDomain = url.replace("https://", "");
|
|
195
|
-
const authDomains = domains.filter((domain) => domain
|
|
195
|
+
const authDomains = domains.filter((domain) => domain !== targetDomain);
|
|
196
196
|
return (0, auth_1.updateAuthDomains)(project, authDomains);
|
|
197
197
|
}
|
|
198
198
|
exports.removeAuthDomain = removeAuthDomain;
|
|
@@ -1,26 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.functionsProxy = void 0;
|
|
3
4
|
const lodash_1 = require("lodash");
|
|
4
5
|
const proxy_1 = require("./proxy");
|
|
5
6
|
const projectUtils_1 = require("../projectUtils");
|
|
6
7
|
const registry_1 = require("../emulator/registry");
|
|
7
8
|
const types_1 = require("../emulator/types");
|
|
8
9
|
const functionsEmulator_1 = require("../emulator/functionsEmulator");
|
|
9
|
-
|
|
10
|
+
const error_1 = require("../error");
|
|
11
|
+
function functionsProxy(options) {
|
|
10
12
|
return (rewrite) => {
|
|
11
13
|
return new Promise((resolve) => {
|
|
12
14
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
13
|
-
|
|
15
|
+
if (!("function" in rewrite)) {
|
|
16
|
+
throw new error_1.FirebaseError(`A non-function rewrite cannot be used in functionsProxy`, {
|
|
17
|
+
exit: 2,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
if (!rewrite.region) {
|
|
21
|
+
rewrite.region = "us-central1";
|
|
22
|
+
}
|
|
23
|
+
let url = `https://${rewrite.region}-${projectId}.cloudfunctions.net/${rewrite.function}`;
|
|
14
24
|
let destLabel = "live";
|
|
15
25
|
if ((0, lodash_1.includes)(options.targets, "functions")) {
|
|
16
26
|
destLabel = "local";
|
|
17
27
|
const functionsEmu = registry_1.EmulatorRegistry.get(types_1.Emulators.FUNCTIONS);
|
|
18
28
|
if (functionsEmu) {
|
|
19
|
-
url = functionsEmulator_1.FunctionsEmulator.getHttpFunctionUrl(functionsEmu.getInfo().host, functionsEmu.getInfo().port, projectId, rewrite.function,
|
|
29
|
+
url = functionsEmulator_1.FunctionsEmulator.getHttpFunctionUrl(functionsEmu.getInfo().host, functionsEmu.getInfo().port, projectId, rewrite.function, rewrite.region);
|
|
20
30
|
}
|
|
21
31
|
}
|
|
22
|
-
resolve((0, proxy_1.proxyRequestHandler)(url, `${destLabel} Function ${rewrite.function}`));
|
|
32
|
+
resolve((0, proxy_1.proxyRequestHandler)(url, `${destLabel} Function ${rewrite.region}/${rewrite.function}`));
|
|
23
33
|
});
|
|
24
34
|
};
|
|
25
35
|
}
|
|
26
|
-
exports.
|
|
36
|
+
exports.functionsProxy = functionsProxy;
|
package/lib/hosting/proxy.js
CHANGED
|
@@ -54,7 +54,7 @@ function proxyRequestHandler(url, rewriteIdentifier) {
|
|
|
54
54
|
continue;
|
|
55
55
|
}
|
|
56
56
|
const value = req.headers[key];
|
|
57
|
-
if (value
|
|
57
|
+
if (value === undefined) {
|
|
58
58
|
headers.delete(key);
|
|
59
59
|
}
|
|
60
60
|
else if (Array.isArray(value)) {
|
|
@@ -115,7 +115,7 @@ function proxyRequestHandler(url, rewriteIdentifier) {
|
|
|
115
115
|
if (location) {
|
|
116
116
|
try {
|
|
117
117
|
const locationURL = new url_1.URL(location);
|
|
118
|
-
if (locationURL.origin
|
|
118
|
+
if (locationURL.origin === u.origin) {
|
|
119
119
|
const unborkedLocation = location.replace(locationURL.origin, "");
|
|
120
120
|
proxyRes.response.headers.set("location", unborkedLocation);
|
|
121
121
|
}
|
|
@@ -27,7 +27,7 @@ async function promptForAccount() {
|
|
|
27
27
|
message: "Please select an option:",
|
|
28
28
|
choices,
|
|
29
29
|
});
|
|
30
|
-
if (emailChoice
|
|
30
|
+
if (emailChoice === "__add__") {
|
|
31
31
|
const newAccount = await (0, auth_1.loginAdditionalAccount)(true);
|
|
32
32
|
if (!newAccount) {
|
|
33
33
|
throw new error_1.FirebaseError("Failed to add new account", { exit: 1 });
|
|
@@ -168,7 +168,7 @@ function convertDatabaseInstance(serverInstance) {
|
|
|
168
168
|
throw new error_1.FirebaseError(`DatabaseInstance response is missing field "name"`);
|
|
169
169
|
}
|
|
170
170
|
const m = serverInstance.name.match(INSTANCE_RESOURCE_NAME_REGEX);
|
|
171
|
-
if (!m || m.length
|
|
171
|
+
if (!m || m.length !== 4) {
|
|
172
172
|
throw new error_1.FirebaseError(`Error parsing instance resource name: ${serverInstance.name}, matches: ${m}`);
|
|
173
173
|
}
|
|
174
174
|
return {
|
package/lib/previews.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.previews = void 0;
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
const configstore_1 = require("./configstore");
|
|
6
|
-
exports.previews = Object.assign({ rtdbrules: false, ext: false, extdev: false, rtdbmanagement: false, functionsv2: false, golang: false, deletegcfartifacts: false,
|
|
6
|
+
exports.previews = Object.assign({ rtdbrules: false, ext: false, extdev: false, extensionsemulator: false, rtdbmanagement: false, functionsv2: false, golang: false, deletegcfartifacts: false, artifactregistry: false, emulatoruisnapshot: false }, configstore_1.configstore.get("previews"));
|
|
7
7
|
if (process.env.FIREBASE_CLI_PREVIEWS) {
|
|
8
8
|
process.env.FIREBASE_CLI_PREVIEWS.split(",").forEach((feature) => {
|
|
9
9
|
if ((0, lodash_1.has)(exports.previews, feature)) {
|
package/lib/responseToError.js
CHANGED
|
@@ -2,16 +2,25 @@
|
|
|
2
2
|
const _ = require("lodash");
|
|
3
3
|
const { FirebaseError } = require("./error");
|
|
4
4
|
module.exports = function (response, body) {
|
|
5
|
-
if (typeof body === "string" && response.statusCode === 404) {
|
|
6
|
-
body = {
|
|
7
|
-
error: {
|
|
8
|
-
message: "Not Found",
|
|
9
|
-
},
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
5
|
if (response.statusCode < 400) {
|
|
13
6
|
return null;
|
|
14
7
|
}
|
|
8
|
+
if (typeof body === "string") {
|
|
9
|
+
if (response.statusCode === 404) {
|
|
10
|
+
body = {
|
|
11
|
+
error: {
|
|
12
|
+
message: "Not Found",
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
body = {
|
|
18
|
+
error: {
|
|
19
|
+
message: body,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
15
24
|
if (typeof body !== "object") {
|
|
16
25
|
try {
|
|
17
26
|
body = JSON.parse(body);
|
package/lib/serve/functions.js
CHANGED
|
@@ -27,10 +27,10 @@ class FunctionsServer {
|
|
|
27
27
|
const nodeMajorVersion = (0, functionsEmulatorUtils_1.parseRuntimeVersion)(options.config.get("functions.runtime"));
|
|
28
28
|
this.backend = {
|
|
29
29
|
functionsDir,
|
|
30
|
-
env: {},
|
|
31
30
|
nodeMajorVersion,
|
|
31
|
+
env: {},
|
|
32
32
|
};
|
|
33
|
-
const args = Object.assign({ projectId, emulatableBackends: [this.backend], account }, partialArgs);
|
|
33
|
+
const args = Object.assign({ projectId, projectDir: options.config.projectDir, emulatableBackends: [this.backend], account }, partialArgs);
|
|
34
34
|
if (options.host) {
|
|
35
35
|
utils.assertIsStringOrUndefined(options.host);
|
|
36
36
|
args.host = options.host;
|
package/lib/serve/hosting.js
CHANGED
|
@@ -46,7 +46,7 @@ function startServer(options, config, port, init) {
|
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
48
|
rewriters: {
|
|
49
|
-
function: (0, functionsProxy_1.
|
|
49
|
+
function: (0, functionsProxy_1.functionsProxy)(options),
|
|
50
50
|
run: (0, cloudRunProxy_1.default)(options),
|
|
51
51
|
},
|
|
52
52
|
}).listen(() => {
|
package/lib/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.assertDefined = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
|
|
3
|
+
exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.assertDefined = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const url = require("url");
|
|
6
6
|
const clc = require("cli-color");
|
|
@@ -17,6 +17,7 @@ const logger_1 = require("./logger");
|
|
|
17
17
|
const IS_WINDOWS = process.platform === "win32";
|
|
18
18
|
const SUCCESS_CHAR = IS_WINDOWS ? "+" : "✔";
|
|
19
19
|
const WARNING_CHAR = IS_WINDOWS ? "!" : "⚠";
|
|
20
|
+
const ERROR_CHAR = IS_WINDOWS ? "!!" : "⬢";
|
|
20
21
|
const THIRTY_DAYS_IN_MILLISECONDS = 30 * 24 * 60 * 60 * 1000;
|
|
21
22
|
exports.envOverrides = [];
|
|
22
23
|
function consoleUrl(project, path) {
|
|
@@ -104,6 +105,10 @@ function logLabeledWarning(label, message, type = "warn", data = undefined) {
|
|
|
104
105
|
logger_1.logger[type](clc.yellow.bold(`${WARNING_CHAR} ${label}:`), message, data);
|
|
105
106
|
}
|
|
106
107
|
exports.logLabeledWarning = logLabeledWarning;
|
|
108
|
+
function logLabeledError(label, message, type = "error", data = undefined) {
|
|
109
|
+
logger_1.logger[type](clc.red.bold(`${ERROR_CHAR} ${label}:`), message, data);
|
|
110
|
+
}
|
|
111
|
+
exports.logLabeledError = logLabeledError;
|
|
107
112
|
function reject(message, options) {
|
|
108
113
|
return Promise.reject(new error_1.FirebaseError(message, options));
|
|
109
114
|
}
|
|
@@ -290,7 +295,7 @@ function setupLoggers() {
|
|
|
290
295
|
logger_1.logger.add(new winston.transports.Console({
|
|
291
296
|
level: "info",
|
|
292
297
|
format: winston.format.printf((info) => [info.message, ...(info[triple_beam_1.SPLAT] || [])]
|
|
293
|
-
.filter((chunk) => typeof chunk
|
|
298
|
+
.filter((chunk) => typeof chunk === "string")
|
|
294
299
|
.join(" ")),
|
|
295
300
|
}));
|
|
296
301
|
}
|