firebase-tools 10.6.0 → 10.7.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/command.js +4 -4
- package/lib/commands/deploy.js +1 -1
- package/lib/commands/emulators-start.js +7 -2
- package/lib/commands/ext-configure.js +15 -5
- package/lib/commands/ext-export.js +6 -5
- package/lib/commands/ext-install.js +28 -44
- package/lib/commands/ext-update.js +9 -1
- package/lib/commands/functions-delete.js +7 -3
- package/lib/commands/hosting-channel-deploy.js +2 -2
- package/lib/deploy/database/deploy.js +4 -0
- package/lib/deploy/database/index.js +1 -0
- package/lib/deploy/extensions/deploy.js +4 -4
- package/lib/deploy/extensions/deploymentSummary.js +8 -5
- package/lib/deploy/extensions/planner.js +36 -9
- package/lib/deploy/extensions/prepare.js +1 -1
- package/lib/deploy/extensions/secrets.js +2 -2
- package/lib/deploy/extensions/tasks.js +60 -21
- package/lib/deploy/functions/backend.js +37 -2
- package/lib/deploy/functions/build.js +173 -0
- package/lib/deploy/functions/checkIam.js +11 -14
- package/lib/deploy/functions/containerCleaner.js +8 -7
- package/lib/deploy/functions/deploy.js +49 -28
- package/lib/deploy/functions/ensure.js +4 -4
- package/lib/deploy/functions/functionsDeployHelper.js +99 -24
- package/lib/deploy/functions/prepare.js +129 -71
- package/lib/deploy/functions/prepareFunctionsUpload.js +16 -21
- package/lib/deploy/functions/pricing.js +6 -3
- package/lib/deploy/functions/prompts.js +1 -7
- package/lib/deploy/functions/release/executor.js +1 -1
- package/lib/deploy/functions/release/fabricator.js +69 -25
- package/lib/deploy/functions/release/index.js +20 -6
- package/lib/deploy/functions/release/planner.js +18 -10
- package/lib/deploy/functions/release/reporter.js +14 -11
- package/lib/deploy/functions/runtimes/discovery/parsing.js +12 -6
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +50 -3
- package/lib/deploy/functions/runtimes/golang/index.js +3 -0
- package/lib/deploy/functions/runtimes/node/index.js +7 -0
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +3 -3
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +132 -6
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/services/auth.js +95 -0
- package/lib/deploy/functions/services/index.js +41 -21
- package/lib/deploy/functions/validate.js +33 -7
- package/lib/deploy/hosting/args.js +2 -0
- package/lib/deploy/hosting/convertConfig.js +39 -8
- package/lib/deploy/hosting/deploy.js +3 -3
- package/lib/deploy/hosting/prepare.js +2 -2
- package/lib/deploy/hosting/release.js +6 -2
- package/lib/deploy/index.js +82 -93
- package/lib/deploy/remoteconfig/deploy.js +4 -0
- package/lib/deploy/remoteconfig/index.js +3 -1
- package/lib/emulator/auth/cloudFunctions.js +6 -2
- package/lib/emulator/auth/operations.js +5 -1
- package/lib/emulator/auth/server.js +8 -1
- package/lib/emulator/auth/state.js +27 -24
- package/lib/emulator/auth/utils.js +3 -25
- package/lib/emulator/controller.js +17 -14
- package/lib/emulator/databaseEmulator.js +36 -3
- package/lib/emulator/downloadableEmulators.js +39 -23
- package/lib/emulator/extensions/validation.js +2 -2
- package/lib/emulator/extensionsEmulator.js +85 -21
- package/lib/emulator/functionsEmulator.js +89 -15
- package/lib/emulator/functionsEmulatorRuntime.js +1 -1
- package/lib/emulator/functionsEmulatorShared.js +25 -2
- package/lib/emulator/functionsEmulatorShell.js +2 -3
- package/lib/emulator/functionsEmulatorUtils.js +5 -1
- package/lib/emulator/pubsubEmulator.js +13 -9
- package/lib/emulator/registry.js +34 -12
- package/lib/emulator/storage/apis/firebase.js +33 -6
- package/lib/emulator/storage/apis/gcloud.js +6 -3
- package/lib/emulator/storage/files.js +9 -1
- package/lib/ensureApiEnabled.js +8 -4
- package/lib/extensions/changelog.js +1 -1
- package/lib/extensions/emulator/optionsHelper.js +4 -3
- package/lib/extensions/emulator/specHelper.js +7 -1
- package/lib/extensions/extensionsHelper.js +30 -24
- package/lib/extensions/manifest.js +27 -7
- package/lib/extensions/paramHelper.js +7 -5
- package/lib/extensions/provisioningHelper.js +2 -2
- package/lib/extensions/warnings.js +11 -4
- package/lib/functions/events/index.js +7 -0
- package/lib/functions/events/v1.js +6 -0
- package/lib/functions/projectConfig.js +32 -6
- package/lib/functionsShellCommandAction.js +1 -1
- package/lib/gcp/cloudfunctions.js +38 -5
- package/lib/gcp/cloudfunctionsv2.js +46 -7
- package/lib/gcp/identityPlatform.js +44 -0
- package/lib/gcp/secretManager.js +1 -1
- package/lib/metaprogramming.js +2 -0
- package/lib/previews.js +1 -1
- package/lib/serve/functions.js +16 -19
- package/lib/serve/hosting.js +25 -12
- package/lib/serve/index.js +6 -0
- package/lib/track.js +15 -21
- package/npm-shrinkwrap.json +256 -527
- package/package.json +6 -3
- package/schema/firebase-config.json +6 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BlockingFunctionEvents = exports.UsageMode = exports.TenantProjectState = exports.AgentProjectState = exports.ProjectState = exports.SIGNIN_METHOD_EMAIL_LINK = exports.PROVIDER_GAME_CENTER = exports.PROVIDER_CUSTOM = exports.PROVIDER_ANONYMOUS = exports.PROVIDER_PHONE = exports.PROVIDER_PASSWORD = void 0;
|
|
3
|
+
exports.decodeRefreshToken = exports.encodeRefreshToken = exports.BlockingFunctionEvents = exports.UsageMode = exports.TenantProjectState = exports.AgentProjectState = exports.ProjectState = exports.SIGNIN_METHOD_EMAIL_LINK = exports.PROVIDER_GAME_CENTER = exports.PROVIDER_CUSTOM = exports.PROVIDER_ANONYMOUS = exports.PROVIDER_PHONE = exports.PROVIDER_PASSWORD = void 0;
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
5
|
const cloudFunctions_1 = require("./cloudFunctions");
|
|
6
6
|
const errors_1 = require("./errors");
|
|
@@ -19,8 +19,6 @@ class ProjectState {
|
|
|
19
19
|
this.localIdForPhoneNumber = new Map();
|
|
20
20
|
this.localIdsForProviderEmail = new Map();
|
|
21
21
|
this.userIdForProviderRawId = new Map();
|
|
22
|
-
this.refreshTokens = new Map();
|
|
23
|
-
this.refreshTokensForLocalId = new Map();
|
|
24
22
|
this.oobs = new Map();
|
|
25
23
|
this.verificationCodes = new Map();
|
|
26
24
|
this.temporaryProofs = new Map();
|
|
@@ -73,13 +71,6 @@ class ProjectState {
|
|
|
73
71
|
deleteUser(user) {
|
|
74
72
|
this.users.delete(user.localId);
|
|
75
73
|
this.removeUserFromIndex(user);
|
|
76
|
-
const refreshTokens = this.refreshTokensForLocalId.get(user.localId);
|
|
77
|
-
if (refreshTokens) {
|
|
78
|
-
this.refreshTokensForLocalId.delete(user.localId);
|
|
79
|
-
for (const refreshToken of refreshTokens) {
|
|
80
|
-
this.refreshTokens.delete(refreshToken);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
74
|
this.authCloudFunction.dispatch("delete", user);
|
|
84
75
|
}
|
|
85
76
|
updateUserByLocalId(localId, fields, options = {}) {
|
|
@@ -282,26 +273,23 @@ class ProjectState {
|
|
|
282
273
|
}
|
|
283
274
|
createRefreshTokenFor(userInfo, provider, { extraClaims = {}, secondFactor, } = {}) {
|
|
284
275
|
const localId = userInfo.localId;
|
|
285
|
-
const
|
|
286
|
-
|
|
276
|
+
const refreshTokenRecord = {
|
|
277
|
+
_AuthEmulatorRefreshToken: "DO NOT MODIFY",
|
|
287
278
|
localId,
|
|
288
279
|
provider,
|
|
289
280
|
extraClaims,
|
|
281
|
+
projectId: this.projectId,
|
|
290
282
|
secondFactor,
|
|
291
283
|
tenantId: userInfo.tenantId,
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (!refreshTokens) {
|
|
295
|
-
refreshTokens = new Set();
|
|
296
|
-
this.refreshTokensForLocalId.set(localId, refreshTokens);
|
|
297
|
-
}
|
|
298
|
-
refreshTokens.add(refreshToken);
|
|
284
|
+
};
|
|
285
|
+
const refreshToken = encodeRefreshToken(refreshTokenRecord);
|
|
299
286
|
return refreshToken;
|
|
300
287
|
}
|
|
301
288
|
validateRefreshToken(refreshToken) {
|
|
302
|
-
const record =
|
|
303
|
-
|
|
304
|
-
|
|
289
|
+
const record = decodeRefreshToken(refreshToken);
|
|
290
|
+
(0, errors_1.assert)(record.projectId === this.projectId, "INVALID_REFRESH_TOKEN");
|
|
291
|
+
if (this instanceof TenantProjectState) {
|
|
292
|
+
(0, errors_1.assert)(record.tenantId === this.tenantId, "TENANT_ID_MISMATCH");
|
|
305
293
|
}
|
|
306
294
|
return {
|
|
307
295
|
user: this.getUserByLocalIdAssertingExists(record.localId),
|
|
@@ -356,8 +344,6 @@ class ProjectState {
|
|
|
356
344
|
this.localIdForPhoneNumber.clear();
|
|
357
345
|
this.localIdsForProviderEmail.clear();
|
|
358
346
|
this.userIdForProviderRawId.clear();
|
|
359
|
-
this.refreshTokens.clear();
|
|
360
|
-
this.refreshTokensForLocalId.clear();
|
|
361
347
|
}
|
|
362
348
|
getUserCount() {
|
|
363
349
|
return this.users.size;
|
|
@@ -617,6 +603,23 @@ var BlockingFunctionEvents;
|
|
|
617
603
|
BlockingFunctionEvents["BEFORE_CREATE"] = "beforeCreate";
|
|
618
604
|
BlockingFunctionEvents["BEFORE_SIGN_IN"] = "beforeSignIn";
|
|
619
605
|
})(BlockingFunctionEvents = exports.BlockingFunctionEvents || (exports.BlockingFunctionEvents = {}));
|
|
606
|
+
function encodeRefreshToken(refreshTokenRecord) {
|
|
607
|
+
return Buffer.from(JSON.stringify(refreshTokenRecord), "utf8").toString("base64");
|
|
608
|
+
}
|
|
609
|
+
exports.encodeRefreshToken = encodeRefreshToken;
|
|
610
|
+
function decodeRefreshToken(refreshTokenString) {
|
|
611
|
+
let refreshTokenRecord;
|
|
612
|
+
try {
|
|
613
|
+
const json = Buffer.from(refreshTokenString, "base64").toString("utf8");
|
|
614
|
+
refreshTokenRecord = JSON.parse(json);
|
|
615
|
+
}
|
|
616
|
+
catch (_a) {
|
|
617
|
+
throw new errors_1.BadRequestError("INVALID_REFRESH_TOKEN");
|
|
618
|
+
}
|
|
619
|
+
(0, errors_1.assert)(refreshTokenRecord._AuthEmulatorRefreshToken, "INVALID_REFRESH_TOKEN");
|
|
620
|
+
return refreshTokenRecord;
|
|
621
|
+
}
|
|
622
|
+
exports.decodeRefreshToken = decodeRefreshToken;
|
|
620
623
|
function getProviderEmailsForUser(user) {
|
|
621
624
|
var _a;
|
|
622
625
|
const emails = new Set();
|
|
@@ -64,34 +64,12 @@ function logError(err) {
|
|
|
64
64
|
}
|
|
65
65
|
exports.logError = logError;
|
|
66
66
|
function authEmulatorUrl(req) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (info) {
|
|
70
|
-
if (info.host === "0.0.0.0") {
|
|
71
|
-
url.hostname = "127.0.0.1";
|
|
72
|
-
}
|
|
73
|
-
else if (info.host === "::") {
|
|
74
|
-
url.hostname = "[::1]";
|
|
75
|
-
}
|
|
76
|
-
else if (info.host.includes(":")) {
|
|
77
|
-
url.hostname = `[${info.host}]`;
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
url.hostname = info.host;
|
|
81
|
-
}
|
|
82
|
-
url.port = info.port.toString();
|
|
67
|
+
if (registry_1.EmulatorRegistry.getInfo(types_1.Emulators.AUTH)) {
|
|
68
|
+
return registry_1.EmulatorRegistry.url(types_1.Emulators.AUTH);
|
|
83
69
|
}
|
|
84
70
|
else {
|
|
85
|
-
|
|
86
|
-
url.protocol = req.protocol;
|
|
87
|
-
if (host) {
|
|
88
|
-
url.host = host;
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
console.warn("Cannot determine host and port of auth emulator server.");
|
|
92
|
-
}
|
|
71
|
+
return registry_1.EmulatorRegistry.url(types_1.Emulators.AUTH, req);
|
|
93
72
|
}
|
|
94
|
-
return url;
|
|
95
73
|
}
|
|
96
74
|
exports.authEmulatorUrl = authEmulatorUrl;
|
|
97
75
|
function mirrorFieldTo(dest, field, source) {
|
|
@@ -6,7 +6,7 @@ const clc = require("cli-color");
|
|
|
6
6
|
const fs = require("fs");
|
|
7
7
|
const path = require("path");
|
|
8
8
|
const logger_1 = require("../logger");
|
|
9
|
-
const
|
|
9
|
+
const track_1 = require("../track");
|
|
10
10
|
const utils = require("../utils");
|
|
11
11
|
const registry_1 = require("./registry");
|
|
12
12
|
const types_1 = require("./types");
|
|
@@ -95,7 +95,7 @@ async function getAndCheckAddress(emulator, options) {
|
|
|
95
95
|
}
|
|
96
96
|
async function startEmulator(instance) {
|
|
97
97
|
const name = instance.getName();
|
|
98
|
-
void track("Emulator Run", name);
|
|
98
|
+
void (0, track_1.track)("Emulator Run", name);
|
|
99
99
|
await registry_1.EmulatorRegistry.start(instance);
|
|
100
100
|
}
|
|
101
101
|
exports.startEmulator = startEmulator;
|
|
@@ -248,7 +248,7 @@ async function startAll(options, showUI = true) {
|
|
|
248
248
|
if (shouldStart(options, types_1.Emulators.HUB)) {
|
|
249
249
|
const hubAddr = await getAndCheckAddress(types_1.Emulators.HUB, options);
|
|
250
250
|
const hub = new hub_1.EmulatorHub(Object.assign({ projectId }, hubAddr));
|
|
251
|
-
void track("emulators:start", "hub");
|
|
251
|
+
void (0, track_1.track)("emulators:start", "hub");
|
|
252
252
|
await startEmulator(hub);
|
|
253
253
|
}
|
|
254
254
|
let exportMetadata = {
|
|
@@ -268,16 +268,19 @@ async function startAll(options, showUI = true) {
|
|
|
268
268
|
const emulatableBackends = [];
|
|
269
269
|
const projectDir = (options.extDevDir || options.config.projectDir);
|
|
270
270
|
if (shouldStart(options, types_1.Emulators.FUNCTIONS)) {
|
|
271
|
-
const functionsCfg = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions)
|
|
271
|
+
const functionsCfg = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
|
|
272
272
|
utils.assertIsStringOrUndefined(options.extDevDir);
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
273
|
+
for (const cfg of functionsCfg) {
|
|
274
|
+
const functionsDir = path.join(projectDir, cfg.source);
|
|
275
|
+
emulatableBackends.push({
|
|
276
|
+
functionsDir,
|
|
277
|
+
codebase: cfg.codebase,
|
|
278
|
+
env: Object.assign({}, options.extDevEnv),
|
|
279
|
+
secretEnv: [],
|
|
280
|
+
predefinedTriggers: options.extDevTriggers,
|
|
281
|
+
nodeMajorVersion: (0, functionsEmulatorUtils_1.parseRuntimeVersion)(options.extDevNodeVersion || cfg.runtime),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
281
284
|
}
|
|
282
285
|
if (shouldStart(options, types_1.Emulators.EXTENSIONS) && previews_1.previews.extensionsemulator) {
|
|
283
286
|
const projectNumber = constants_1.Constants.isDemoProject(projectId)
|
|
@@ -294,8 +297,8 @@ async function startAll(options, showUI = true) {
|
|
|
294
297
|
const extensionsBackends = await extensionEmulator.getExtensionBackends();
|
|
295
298
|
const filteredExtensionsBackends = extensionEmulator.filterUnemulatedTriggers(options, extensionsBackends);
|
|
296
299
|
emulatableBackends.push(...filteredExtensionsBackends);
|
|
297
|
-
void track("Emulator Run", types_1.Emulators.EXTENSIONS);
|
|
298
|
-
|
|
300
|
+
void (0, track_1.track)("Emulator Run", types_1.Emulators.EXTENSIONS);
|
|
301
|
+
await startEmulator(extensionEmulator);
|
|
299
302
|
}
|
|
300
303
|
if (emulatableBackends.length) {
|
|
301
304
|
const functionsLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS);
|
|
@@ -56,7 +56,15 @@ class DatabaseEmulator {
|
|
|
56
56
|
if (!c.instance) {
|
|
57
57
|
continue;
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
try {
|
|
60
|
+
await this.updateRules(c.instance, c.rules);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
const rulesError = this.prettyPrintRulesError(c.rules, e);
|
|
64
|
+
this.logger.logLabeled("WARN", "database", rulesError);
|
|
65
|
+
this.logger.logLabeled("WARN", "database", "Failed to update rules");
|
|
66
|
+
throw new error_1.FirebaseError(`Failed to load initial ${constants_1.Constants.description(this.getName())} rules:\n${rulesError}`);
|
|
67
|
+
}
|
|
60
68
|
}
|
|
61
69
|
}
|
|
62
70
|
}
|
|
@@ -114,6 +122,7 @@ class DatabaseEmulator {
|
|
|
114
122
|
});
|
|
115
123
|
}
|
|
116
124
|
async updateRules(instance, rulesPath) {
|
|
125
|
+
var _a;
|
|
117
126
|
const rulesExt = path.extname(rulesPath);
|
|
118
127
|
const content = rulesExt === ".bolt"
|
|
119
128
|
? parseBoltRules(rulesPath).toString()
|
|
@@ -131,12 +140,36 @@ class DatabaseEmulator {
|
|
|
131
140
|
if (e.context && e.context.body) {
|
|
132
141
|
throw e.context.body.error;
|
|
133
142
|
}
|
|
134
|
-
throw e.original;
|
|
143
|
+
throw (_a = e.original) !== null && _a !== void 0 ? _a : e;
|
|
135
144
|
}
|
|
136
145
|
}
|
|
137
146
|
prettyPrintRulesError(filePath, error) {
|
|
147
|
+
let errStr;
|
|
148
|
+
switch (typeof error) {
|
|
149
|
+
case "string":
|
|
150
|
+
errStr = error;
|
|
151
|
+
break;
|
|
152
|
+
case "object":
|
|
153
|
+
if (error != null && "message" in error) {
|
|
154
|
+
const message = error.message;
|
|
155
|
+
errStr = `${message}`;
|
|
156
|
+
if (typeof message === "string") {
|
|
157
|
+
try {
|
|
158
|
+
const parsed = JSON.parse(message);
|
|
159
|
+
if (typeof parsed === "object" && parsed.error) {
|
|
160
|
+
errStr = `${parsed.error}`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (_) {
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
default:
|
|
169
|
+
errStr = `Unknown error: ${JSON.stringify(error)}`;
|
|
170
|
+
}
|
|
138
171
|
const relativePath = path.relative(process.cwd(), filePath);
|
|
139
|
-
return `${clc.cyan(relativePath)}:${
|
|
172
|
+
return `${clc.cyan(relativePath)}:${errStr.trim()}`;
|
|
140
173
|
}
|
|
141
174
|
}
|
|
142
175
|
exports.DatabaseEmulator = DatabaseEmulator;
|
|
@@ -29,13 +29,13 @@ exports.DownloadDetails = {
|
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
31
|
firestore: {
|
|
32
|
-
downloadPath: path.join(CACHE_DIR, "cloud-firestore-emulator-v1.14.
|
|
33
|
-
version: "1.14.
|
|
32
|
+
downloadPath: path.join(CACHE_DIR, "cloud-firestore-emulator-v1.14.3.jar"),
|
|
33
|
+
version: "1.14.3",
|
|
34
34
|
opts: {
|
|
35
35
|
cacheDir: CACHE_DIR,
|
|
36
|
-
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-firestore-emulator-v1.14.
|
|
37
|
-
expectedSize:
|
|
38
|
-
expectedChecksum: "
|
|
36
|
+
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-firestore-emulator-v1.14.3.jar",
|
|
37
|
+
expectedSize: 60442855,
|
|
38
|
+
expectedChecksum: "63517534875818689639ee5dee57dd52",
|
|
39
39
|
namePrefix: "cloud-firestore-emulator",
|
|
40
40
|
},
|
|
41
41
|
},
|
|
@@ -50,15 +50,15 @@ exports.DownloadDetails = {
|
|
|
50
50
|
namePrefix: "cloud-storage-rules-emulator",
|
|
51
51
|
},
|
|
52
52
|
},
|
|
53
|
-
ui: previews_1.previews.
|
|
53
|
+
ui: previews_1.previews.extensionsemulator
|
|
54
54
|
? {
|
|
55
|
-
version: "
|
|
56
|
-
downloadPath: path.join(CACHE_DIR, "ui-
|
|
57
|
-
unzipDir: path.join(CACHE_DIR, "ui-
|
|
58
|
-
binaryPath: path.join(CACHE_DIR, "ui-
|
|
55
|
+
version: "EXTENSIONS",
|
|
56
|
+
downloadPath: path.join(CACHE_DIR, "ui-vEXTENSIONS.zip"),
|
|
57
|
+
unzipDir: path.join(CACHE_DIR, "ui-vEXTENSIONS"),
|
|
58
|
+
binaryPath: path.join(CACHE_DIR, "ui-vEXTENSIONS", "server.bundle.js"),
|
|
59
59
|
opts: {
|
|
60
60
|
cacheDir: CACHE_DIR,
|
|
61
|
-
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/ui-
|
|
61
|
+
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/ui-vEXTENSIONS.zip",
|
|
62
62
|
expectedSize: -1,
|
|
63
63
|
expectedChecksum: "",
|
|
64
64
|
skipCache: true,
|
|
@@ -66,19 +66,35 @@ exports.DownloadDetails = {
|
|
|
66
66
|
namePrefix: "ui",
|
|
67
67
|
},
|
|
68
68
|
}
|
|
69
|
-
:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
: previews_1.previews.emulatoruisnapshot
|
|
70
|
+
? {
|
|
71
|
+
version: "SNAPSHOT",
|
|
72
|
+
downloadPath: path.join(CACHE_DIR, "ui-vSNAPSHOT.zip"),
|
|
73
|
+
unzipDir: path.join(CACHE_DIR, "ui-vSNAPSHOT"),
|
|
74
|
+
binaryPath: path.join(CACHE_DIR, "ui-vSNAPSHOT", "server.bundle.js"),
|
|
75
|
+
opts: {
|
|
76
|
+
cacheDir: CACHE_DIR,
|
|
77
|
+
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/ui-vSNAPSHOT.zip",
|
|
78
|
+
expectedSize: -1,
|
|
79
|
+
expectedChecksum: "",
|
|
80
|
+
skipCache: true,
|
|
81
|
+
skipChecksumAndSize: true,
|
|
82
|
+
namePrefix: "ui",
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
: {
|
|
86
|
+
version: "1.6.6",
|
|
87
|
+
downloadPath: path.join(CACHE_DIR, "ui-v1.6.6.zip"),
|
|
88
|
+
unzipDir: path.join(CACHE_DIR, "ui-v1.6.6"),
|
|
89
|
+
binaryPath: path.join(CACHE_DIR, "ui-v1.6.6", "server.bundle.js"),
|
|
90
|
+
opts: {
|
|
91
|
+
cacheDir: CACHE_DIR,
|
|
92
|
+
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/ui-v1.6.6.zip",
|
|
93
|
+
expectedSize: 3817247,
|
|
94
|
+
expectedChecksum: "c80a3f0ae1e3f682ace0a18a9cdd2861",
|
|
95
|
+
namePrefix: "ui",
|
|
96
|
+
},
|
|
80
97
|
},
|
|
81
|
-
},
|
|
82
98
|
pubsub: {
|
|
83
99
|
downloadPath: path.join(CACHE_DIR, "pubsub-emulator-0.1.0.zip"),
|
|
84
100
|
version: "0.1.0",
|
|
@@ -17,8 +17,8 @@ async function getUnemulatedAPIs(projectId, instances) {
|
|
|
17
17
|
var _a;
|
|
18
18
|
const unemulatedAPIs = {};
|
|
19
19
|
for (const i of instances) {
|
|
20
|
-
const
|
|
21
|
-
for (const api of (_a =
|
|
20
|
+
const extensionSpec = await planner.getExtensionSpec(i);
|
|
21
|
+
for (const api of (_a = extensionSpec.apis) !== null && _a !== void 0 ? _a : []) {
|
|
22
22
|
if (!EMULATED_APIS.includes(api.apiName)) {
|
|
23
23
|
if (unemulatedAPIs[api.apiName]) {
|
|
24
24
|
unemulatedAPIs[api.apiName].instanceIds.push(i.instanceId);
|
|
@@ -18,13 +18,37 @@ const validation_1 = require("./extensions/validation");
|
|
|
18
18
|
const ensureApiEnabled_1 = require("../ensureApiEnabled");
|
|
19
19
|
const shortenUrl_1 = require("../shortenUrl");
|
|
20
20
|
const constants_1 = require("./constants");
|
|
21
|
+
const registry_1 = require("./registry");
|
|
21
22
|
class ExtensionsEmulator {
|
|
22
23
|
constructor(args) {
|
|
23
24
|
this.want = [];
|
|
25
|
+
this.backends = [];
|
|
24
26
|
this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.EXTENSIONS);
|
|
25
27
|
this.pendingDownloads = new Map();
|
|
26
28
|
this.args = args;
|
|
27
29
|
}
|
|
30
|
+
start() {
|
|
31
|
+
this.logger.logLabeled("DEBUG", "Extensions", "Started Extensions emulator, this is a noop.");
|
|
32
|
+
return Promise.resolve();
|
|
33
|
+
}
|
|
34
|
+
stop() {
|
|
35
|
+
this.logger.logLabeled("DEBUG", "Extensions", "Stopping Extensions emulator, this is a noop.");
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
}
|
|
38
|
+
connect() {
|
|
39
|
+
this.logger.logLabeled("DEBUG", "Extensions", "Connecting Extensions emulator, this is a noop.");
|
|
40
|
+
return Promise.resolve();
|
|
41
|
+
}
|
|
42
|
+
getInfo() {
|
|
43
|
+
const info = registry_1.EmulatorRegistry.getInfo(types_1.Emulators.FUNCTIONS);
|
|
44
|
+
if (!info) {
|
|
45
|
+
throw new error_1.FirebaseError("Extensions Emulator is running but Functions emulator is not. This should never happen.");
|
|
46
|
+
}
|
|
47
|
+
return info;
|
|
48
|
+
}
|
|
49
|
+
getName() {
|
|
50
|
+
return types_1.Emulators.EXTENSIONS;
|
|
51
|
+
}
|
|
28
52
|
async readManifest() {
|
|
29
53
|
var _a;
|
|
30
54
|
this.want = await planner.want({
|
|
@@ -37,22 +61,30 @@ class ExtensionsEmulator {
|
|
|
37
61
|
});
|
|
38
62
|
}
|
|
39
63
|
async ensureSourceCode(instance) {
|
|
40
|
-
if (
|
|
41
|
-
|
|
64
|
+
if (instance.localPath) {
|
|
65
|
+
if (!this.hasValidSource({ path: instance.localPath, extTarget: instance.localPath })) {
|
|
66
|
+
throw new error_1.FirebaseError(`Tried to emulate local extension at ${instance.localPath}, but it was missing required files.`);
|
|
67
|
+
}
|
|
68
|
+
return instance.localPath;
|
|
42
69
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
70
|
+
else if (instance.ref) {
|
|
71
|
+
const ref = (0, refs_1.toExtensionVersionRef)(instance.ref);
|
|
72
|
+
const cacheDir = process.env.FIREBASE_EXTENSIONS_CACHE_PATH ||
|
|
73
|
+
path.join(os.homedir(), ".cache", "firebase", "extensions");
|
|
74
|
+
const sourceCodePath = path.join(cacheDir, ref);
|
|
75
|
+
if (this.pendingDownloads.get(ref)) {
|
|
76
|
+
await this.pendingDownloads.get(ref);
|
|
77
|
+
}
|
|
78
|
+
if (!this.hasValidSource({ path: sourceCodePath, extTarget: ref })) {
|
|
79
|
+
const promise = this.downloadSource(instance, ref, sourceCodePath);
|
|
80
|
+
this.pendingDownloads.set(ref, promise);
|
|
81
|
+
await promise;
|
|
82
|
+
}
|
|
83
|
+
return sourceCodePath;
|
|
49
84
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.pendingDownloads.set(ref, promise);
|
|
53
|
-
await promise;
|
|
85
|
+
else {
|
|
86
|
+
throw new error_1.FirebaseError("Tried to emulate an extension instance without a ref or localPath. This should never happen.");
|
|
54
87
|
}
|
|
55
|
-
return sourceCodePath;
|
|
56
88
|
}
|
|
57
89
|
async downloadSource(instance, ref, sourceCodePath) {
|
|
58
90
|
const extensionVersion = await planner.getExtensionVersion(instance);
|
|
@@ -71,7 +103,7 @@ class ExtensionsEmulator {
|
|
|
71
103
|
for (const requiredFile of requiredFiles) {
|
|
72
104
|
const f = path.join(args.path, requiredFile);
|
|
73
105
|
if (!fs.existsSync(f)) {
|
|
74
|
-
emulatorLogger_1.EmulatorLogger.forExtension({ ref: args.
|
|
106
|
+
emulatorLogger_1.EmulatorLogger.forExtension({ ref: args.extTarget }).logLabeled("BULLET", "extensions", `Detected invalid source code for ${args.extTarget}, expected to find ${f}`);
|
|
75
107
|
return false;
|
|
76
108
|
}
|
|
77
109
|
}
|
|
@@ -92,27 +124,32 @@ class ExtensionsEmulator {
|
|
|
92
124
|
async getExtensionBackends() {
|
|
93
125
|
await this.readManifest();
|
|
94
126
|
await this.checkAndWarnAPIs(this.want);
|
|
95
|
-
|
|
127
|
+
this.backends = await Promise.all(this.want.map((i) => {
|
|
96
128
|
return this.toEmulatableBackend(i);
|
|
97
129
|
}));
|
|
130
|
+
return this.backends;
|
|
98
131
|
}
|
|
99
132
|
async toEmulatableBackend(instance) {
|
|
100
133
|
const extensionDir = await this.ensureSourceCode(instance);
|
|
101
134
|
const functionsDir = path.join(extensionDir, "functions");
|
|
102
135
|
const env = Object.assign(this.autoPopulatedParams(instance), instance.params);
|
|
103
|
-
const { extensionTriggers, nodeMajorVersion, nonSecretEnv, secretEnvVariables } = await (0, optionsHelper_1.getExtensionFunctionInfo)(
|
|
104
|
-
const
|
|
105
|
-
const extensionVersion = await planner.getExtensionVersion(instance);
|
|
106
|
-
return {
|
|
136
|
+
const { extensionTriggers, nodeMajorVersion, nonSecretEnv, secretEnvVariables } = await (0, optionsHelper_1.getExtensionFunctionInfo)(instance, env);
|
|
137
|
+
const emulatableBackend = {
|
|
107
138
|
functionsDir,
|
|
108
139
|
env: nonSecretEnv,
|
|
109
140
|
secretEnv: secretEnvVariables,
|
|
110
141
|
predefinedTriggers: extensionTriggers,
|
|
111
142
|
nodeMajorVersion: nodeMajorVersion,
|
|
112
143
|
extensionInstanceId: instance.instanceId,
|
|
113
|
-
extension,
|
|
114
|
-
extensionVersion,
|
|
115
144
|
};
|
|
145
|
+
if (instance.ref) {
|
|
146
|
+
emulatableBackend.extension = await planner.getExtension(instance);
|
|
147
|
+
emulatableBackend.extensionVersion = await planner.getExtensionVersion(instance);
|
|
148
|
+
}
|
|
149
|
+
else if (instance.localPath) {
|
|
150
|
+
emulatableBackend.extensionSpec = await planner.getExtensionSpec(instance);
|
|
151
|
+
}
|
|
152
|
+
return emulatableBackend;
|
|
116
153
|
}
|
|
117
154
|
autoPopulatedParams(instance) {
|
|
118
155
|
const projectId = this.args.projectId;
|
|
@@ -174,5 +211,32 @@ class ExtensionsEmulator {
|
|
|
174
211
|
}
|
|
175
212
|
return filteredBackends;
|
|
176
213
|
}
|
|
214
|
+
extensionDetailsUILink(backend) {
|
|
215
|
+
const uiInfo = registry_1.EmulatorRegistry.getInfo(types_1.Emulators.UI);
|
|
216
|
+
if (!uiInfo || !backend.extensionInstanceId) {
|
|
217
|
+
return "";
|
|
218
|
+
}
|
|
219
|
+
const uiUrl = registry_1.EmulatorRegistry.getInfoHostString(uiInfo);
|
|
220
|
+
return clc.underline(clc.bold(`http://${uiUrl}/${types_1.Emulators.EXTENSIONS}/${backend.extensionInstanceId}`));
|
|
221
|
+
}
|
|
222
|
+
extensionsInfoTable(options) {
|
|
223
|
+
var _a;
|
|
224
|
+
const filtedBackends = this.filterUnemulatedTriggers(options, this.backends);
|
|
225
|
+
const uiRunning = registry_1.EmulatorRegistry.isRunning(types_1.Emulators.UI);
|
|
226
|
+
const tableHead = ["Extension Instance Name", "Extension Ref"];
|
|
227
|
+
if (uiRunning) {
|
|
228
|
+
tableHead.push("View in Emulator UI");
|
|
229
|
+
}
|
|
230
|
+
const table = new Table({ head: tableHead, style: { head: ["yellow"] } });
|
|
231
|
+
for (const b of filtedBackends) {
|
|
232
|
+
if (b.extensionInstanceId) {
|
|
233
|
+
const tableEntry = [b.extensionInstanceId, ((_a = b.extensionVersion) === null || _a === void 0 ? void 0 : _a.ref) || "Local Extension"];
|
|
234
|
+
if (uiRunning)
|
|
235
|
+
tableEntry.push(this.extensionDetailsUILink(b));
|
|
236
|
+
table.push(tableEntry);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return table.toString();
|
|
240
|
+
}
|
|
177
241
|
}
|
|
178
242
|
exports.ExtensionsEmulator = ExtensionsEmulator;
|