firebase-tools 15.17.0 → 15.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/accountExporter.js +13 -6
- package/lib/accountImporter.js +18 -1
- package/lib/apphosting/constants.js +2 -1
- package/lib/apphosting/localbuilds.js +105 -37
- package/lib/apphosting/universalMakerDownload.js +72 -0
- package/lib/apphosting/universalMakerInfo.json +16 -0
- package/lib/archiveDirectory.js +1 -1
- package/lib/commands/dataconnect-sql-shell.js +21 -3
- package/lib/deploy/apphosting/deploy.js +39 -23
- package/lib/deploy/apphosting/prepare.js +28 -6
- package/lib/deploy/apphosting/release.js +26 -12
- package/lib/deploy/apphosting/util.js +35 -37
- package/lib/deploy/functions/backend.js +2 -1
- package/lib/deploy/functions/prepare.js +50 -57
- package/lib/deploy/functions/prepareFunctionsUpload.js +1 -1
- package/lib/deploy/functions/services/ailogic.js +14 -6
- package/lib/deploy/functions/validate.js +1 -1
- package/lib/downloadUtils.js +24 -0
- package/lib/emulator/download.js +2 -24
- package/lib/emulator/downloadableEmulatorInfo.json +31 -31
- package/lib/fsAsync.js +53 -10
- package/lib/gcp/cloudsql/connect.js +49 -25
- package/lib/tsconfig.compile.tsbuildinfo +1 -1
- package/lib/tsconfig.publish.tsbuildinfo +1 -1
- package/package.json +21 -6
- package/templates/init/functions/dart/_gitignore +1 -9
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createLocalBuildTarArchive = createLocalBuildTarArchive;
|
|
4
4
|
exports.createSourceDeployArchive = createSourceDeployArchive;
|
|
5
|
+
exports.resolveIgnorePatterns = resolveIgnorePatterns;
|
|
5
6
|
const archiver = require("archiver");
|
|
6
7
|
const fs = require("fs");
|
|
7
8
|
const path = require("path");
|
|
@@ -9,25 +10,28 @@ const tar = require("tar");
|
|
|
9
10
|
const tmp = require("tmp");
|
|
10
11
|
const error_1 = require("../../error");
|
|
11
12
|
const fsAsync = require("../../fsAsync");
|
|
12
|
-
const
|
|
13
|
-
async function createLocalBuildTarArchive(config, rootDir,
|
|
13
|
+
const utils_1 = require("../../utils");
|
|
14
|
+
async function createLocalBuildTarArchive(config, rootDir, outputFiles) {
|
|
14
15
|
const tmpFile = tmp.fileSync({ prefix: `${config.backendId}-`, postfix: ".tar.gz" }).name;
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
path
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
16
|
+
const filesToPackage = outputFiles.length > 0 ? outputFiles : ["."];
|
|
17
|
+
const allFiles = [];
|
|
18
|
+
for (const fileOrDir of filesToPackage) {
|
|
19
|
+
const absolutePath = path.join(rootDir, fileOrDir);
|
|
20
|
+
if (!fs.existsSync(absolutePath)) {
|
|
21
|
+
(0, utils_1.logLabeledWarning)("apphosting", `Expected build output file or directory not found: ${fileOrDir}`);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const stat = fs.statSync(absolutePath);
|
|
25
|
+
if (stat.isDirectory()) {
|
|
26
|
+
const rdrFiles = await fsAsync.readdirRecursive({
|
|
27
|
+
path: absolutePath,
|
|
28
|
+
ignoreStrings: ["firebase-debug.log", "firebase-debug.*.log"],
|
|
29
|
+
supportGitIgnore: false,
|
|
30
|
+
});
|
|
31
|
+
allFiles.push(...rdrFiles.map((rdrf) => path.relative(rootDir, rdrf.name)));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
allFiles.push(path.relative(rootDir, absolutePath));
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
37
|
try {
|
|
@@ -58,15 +62,12 @@ async function createSourceDeployArchive(config, rootDir, targetSubDir) {
|
|
|
58
62
|
});
|
|
59
63
|
const archive = archiver("zip");
|
|
60
64
|
const targetDir = targetSubDir ? path.join(rootDir, targetSubDir) : rootDir;
|
|
61
|
-
const ignore = config
|
|
62
|
-
ignore.push("firebase-debug.log", "firebase-debug.*.log");
|
|
63
|
-
const gitIgnorePatterns = parseGitIgnorePatterns(targetDir);
|
|
64
|
-
ignore.push(...gitIgnorePatterns);
|
|
65
|
+
const ignore = resolveIgnorePatterns(config);
|
|
65
66
|
try {
|
|
66
67
|
const files = await fsAsync.readdirRecursive({
|
|
67
68
|
path: targetDir,
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
ignoreStrings: ignore,
|
|
70
|
+
supportGitIgnore: true,
|
|
70
71
|
});
|
|
71
72
|
for (const file of files) {
|
|
72
73
|
const name = path.relative(rootDir, file.name);
|
|
@@ -78,22 +79,19 @@ async function createSourceDeployArchive(config, rootDir, targetSubDir) {
|
|
|
78
79
|
await pipeAsync(archive, fileStream);
|
|
79
80
|
}
|
|
80
81
|
catch (err) {
|
|
81
|
-
throw new error_1.FirebaseError(`Could not read source directory. Remove links and shortcuts and try again. Original: ${err}`, { original: err, exit: 1 });
|
|
82
|
+
throw new error_1.FirebaseError(`Could not read source directory. Remove links and shortcuts and try again. Original: ${String(err)}`, { original: err, exit: 1 });
|
|
82
83
|
}
|
|
83
84
|
return tmpFile;
|
|
84
85
|
}
|
|
85
|
-
function
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.map((line) => line.trim())
|
|
95
|
-
.filter((line) => !line.startsWith("#") && !(line === ""));
|
|
96
|
-
return lines;
|
|
86
|
+
function resolveIgnorePatterns(config, skipDefaultNodeModules = false) {
|
|
87
|
+
const ignore = config.ignore
|
|
88
|
+
? [...config.ignore]
|
|
89
|
+
: skipDefaultNodeModules
|
|
90
|
+
? [".git"]
|
|
91
|
+
: ["node_modules", ".git"];
|
|
92
|
+
ignore.push("firebase-debug.log", "firebase-debug.*.log");
|
|
93
|
+
ignore.push(".local_build_*");
|
|
94
|
+
return ignore;
|
|
97
95
|
}
|
|
98
96
|
async function pipeAsync(from, to) {
|
|
99
97
|
from.pipe(to);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.missingEndpoint = exports.hasEndpoint = exports.AllFunctionsPlatforms = exports.SCHEDULED_FUNCTION_LABEL = exports.MIN_CPU_FOR_CONCURRENCY = exports.DEFAULT_MEMORY = exports.DEFAULT_CONCURRENCY = exports.AllIngressSettings = exports.AllVpcEgressSettings = void 0;
|
|
3
|
+
exports.missingEndpoint = exports.hasEndpoint = exports.AllFunctionsPlatforms = exports.SCHEDULED_FUNCTION_LABEL = exports.MIN_CPU_FOR_CONCURRENCY = exports.DEFAULT_TIMEOUT_SECONDS = exports.DEFAULT_MEMORY = exports.DEFAULT_CONCURRENCY = exports.AllIngressSettings = exports.AllVpcEgressSettings = void 0;
|
|
4
4
|
exports.endpointTriggerType = endpointTriggerType;
|
|
5
5
|
exports.isValidMemoryOption = isValidMemoryOption;
|
|
6
6
|
exports.isValidEgressSetting = isValidEgressSetting;
|
|
@@ -116,6 +116,7 @@ function memoryToGen2Cpu(memory) {
|
|
|
116
116
|
}
|
|
117
117
|
exports.DEFAULT_CONCURRENCY = 80;
|
|
118
118
|
exports.DEFAULT_MEMORY = 256;
|
|
119
|
+
exports.DEFAULT_TIMEOUT_SECONDS = 60;
|
|
119
120
|
exports.MIN_CPU_FOR_CONCURRENCY = 1;
|
|
120
121
|
exports.SCHEDULED_FUNCTION_LABEL = Object.freeze({ deployment: "firebase-schedule" });
|
|
121
122
|
function secretVersionName(s) {
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DEFAULT_FUNCTION_REGION = exports.EVENTARC_SOURCE_ENV = void 0;
|
|
4
4
|
exports.prepare = prepare;
|
|
5
|
-
exports.
|
|
6
|
-
exports.resolveDefaultRegions = resolveDefaultRegions;
|
|
5
|
+
exports.resolveDefaultRegionsForBuild = resolveDefaultRegionsForBuild;
|
|
7
6
|
exports.inferDetailsFromExisting = inferDetailsFromExisting;
|
|
8
7
|
exports.updateEndpointTargetedStatus = updateEndpointTargetedStatus;
|
|
9
8
|
exports.inferBlockingDetails = inferBlockingDetails;
|
|
10
9
|
exports.resolveCpuAndConcurrency = resolveCpuAndConcurrency;
|
|
10
|
+
exports.resolveDefaultTimeout = resolveDefaultTimeout;
|
|
11
11
|
exports.loadCodebases = loadCodebases;
|
|
12
12
|
exports.warnIfNewGenkitFunctionIsMissingSecrets = warnIfNewGenkitFunctionIsMissingSecrets;
|
|
13
13
|
exports.ensureAllRequiredAPIsEnabled = ensureAllRequiredAPIsEnabled;
|
|
@@ -78,6 +78,7 @@ async function prepare(context, options, payload) {
|
|
|
78
78
|
}
|
|
79
79
|
context.hasRuntimeConfig = Object.keys(runtimeConfig).some((k) => k !== "firebase");
|
|
80
80
|
const wantBuilds = await loadCodebases(context.config, options, firebaseConfig, runtimeConfig, context.filters);
|
|
81
|
+
const existingBackend = await backend.existingBackend(context);
|
|
81
82
|
if (Object.values(wantBuilds).some((b) => b.extensions)) {
|
|
82
83
|
const extContext = {};
|
|
83
84
|
const extPayload = {};
|
|
@@ -99,6 +100,10 @@ async function prepare(context, options, payload) {
|
|
|
99
100
|
proto.convertIfPresent(userEnvOpt, localCfg, "configDir", (cd) => options.config.path(cd));
|
|
100
101
|
const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
|
|
101
102
|
const envs = { ...userEnvs, ...firebaseEnvs };
|
|
103
|
+
const relevantEndpoints = backend
|
|
104
|
+
.allEndpoints(existingBackend)
|
|
105
|
+
.filter((e) => e.codebase === codebase || e.codebase === undefined);
|
|
106
|
+
await resolveDefaultRegionsForBuild(wantBuild, backend.of(...relevantEndpoints));
|
|
102
107
|
const { backend: wantBackend, envs: resolvedEnvs } = await build.resolveBackend({
|
|
103
108
|
build: wantBuild,
|
|
104
109
|
firebaseConfig,
|
|
@@ -194,13 +199,6 @@ async function prepare(context, options, payload) {
|
|
|
194
199
|
context.sources[codebase] = source;
|
|
195
200
|
}
|
|
196
201
|
payload.functions = {};
|
|
197
|
-
const existingBackend = await backend.existingBackend(context);
|
|
198
|
-
for (const [codebase, wantBackend] of Object.entries(wantBackends)) {
|
|
199
|
-
const relevantEndpoints = backend
|
|
200
|
-
.allEndpoints(existingBackend)
|
|
201
|
-
.filter((e) => e.codebase === codebase || e.codebase === undefined);
|
|
202
|
-
await resolveDefaultRegions(wantBackend, backend.of(...relevantEndpoints));
|
|
203
|
-
}
|
|
204
202
|
const haveBackends = (0, functionsDeployHelper_1.groupEndpointsByCodebase)(wantBackends, backend.allEndpoints(existingBackend));
|
|
205
203
|
for (const [codebase, wantBackend] of Object.entries(wantBackends)) {
|
|
206
204
|
const haveBackend = haveBackends[codebase] || backend.empty();
|
|
@@ -210,6 +208,7 @@ async function prepare(context, options, payload) {
|
|
|
210
208
|
inferDetailsFromExisting(wantBackend, haveBackend, codebaseUsesEnvs.includes(codebase));
|
|
211
209
|
await (0, triggerRegionHelper_1.ensureTriggerRegions)(wantBackend);
|
|
212
210
|
resolveCpuAndConcurrency(wantBackend);
|
|
211
|
+
resolveDefaultTimeout(wantBackend);
|
|
213
212
|
validate.endpointsAreValid(wantBackend);
|
|
214
213
|
inferBlockingDetails(wantBackend);
|
|
215
214
|
}
|
|
@@ -232,66 +231,50 @@ async function prepare(context, options, payload) {
|
|
|
232
231
|
validate.checkFiltersIntegrity(wantBackends, context.filters);
|
|
233
232
|
(0, applyHash_1.applyBackendHashToBackends)(wantBackends, context);
|
|
234
233
|
}
|
|
235
|
-
function
|
|
236
|
-
endpoint.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
let matching;
|
|
247
|
-
for (const region of Object.keys(have.endpoints)) {
|
|
248
|
-
if (region === build.REGION_TBD) {
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
if (have.endpoints[region][id]) {
|
|
252
|
-
if (matching) {
|
|
253
|
-
throw new error_1.FirebaseError(`Cannot resolve default region for function ${id}. It exists in multiple regions. The region must be specified to continue.`);
|
|
234
|
+
async function resolveDefaultRegionsForBuild(buildObj, have) {
|
|
235
|
+
for (const [id, endpoint] of Object.entries(buildObj.endpoints)) {
|
|
236
|
+
if (!endpoint.region?.length || endpoint.region.includes(build.REGION_TBD)) {
|
|
237
|
+
let resolvedRegion = exports.DEFAULT_FUNCTION_REGION;
|
|
238
|
+
let matching;
|
|
239
|
+
for (const region of Object.keys(have.endpoints)) {
|
|
240
|
+
if (have.endpoints[region][id]) {
|
|
241
|
+
if (matching) {
|
|
242
|
+
throw new error_1.FirebaseError(`Cannot resolve default region for function ${id}. It exists in multiple regions. The region must be specified to continue.`);
|
|
243
|
+
}
|
|
244
|
+
matching = have.endpoints[region][id];
|
|
254
245
|
}
|
|
255
|
-
matching = have.endpoints[region][id];
|
|
256
246
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
moveEndpointToRegion(want, wantE, matching.region);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
async function resolveDefaultRegions(want, have) {
|
|
265
|
-
matchRegionsForExisting(want, have);
|
|
266
|
-
const endpoints = Object.values(want.endpoints[build.REGION_TBD] || {});
|
|
267
|
-
for (const endpoint of endpoints) {
|
|
268
|
-
let resolvedRegion = "us-central1";
|
|
269
|
-
try {
|
|
270
|
-
if (backend.isBlockingTriggered(endpoint)) {
|
|
271
|
-
resolvedRegion = resolveRegionForBlockingTrigger(endpoint);
|
|
247
|
+
if (matching) {
|
|
248
|
+
resolvedRegion = matching.region;
|
|
272
249
|
}
|
|
273
|
-
else
|
|
274
|
-
|
|
250
|
+
else {
|
|
251
|
+
try {
|
|
252
|
+
if (build.isBlockingTriggered(endpoint)) {
|
|
253
|
+
resolvedRegion = resolveRegionForBlockingTrigger(endpoint.blockingTrigger);
|
|
254
|
+
}
|
|
255
|
+
else if (build.isEventTriggered(endpoint)) {
|
|
256
|
+
resolvedRegion = await resolveRegionForEventTrigger(endpoint.project, endpoint.eventTrigger);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
logger_1.logger.debug(`Failed to resolve region for endpoint ${id}. Defaulting to ${exports.DEFAULT_FUNCTION_REGION}.`, (0, error_1.getErrStack)(err));
|
|
261
|
+
}
|
|
275
262
|
}
|
|
263
|
+
endpoint.region = [resolvedRegion];
|
|
276
264
|
}
|
|
277
|
-
catch (err) {
|
|
278
|
-
logger_1.logger.debug(`Failed to resolve region for endpoint ${endpoint.id}. Defaulting to us-central1.`, (0, error_1.getErrStack)(err));
|
|
279
|
-
}
|
|
280
|
-
moveEndpointToRegion(want, endpoint, resolvedRegion);
|
|
281
265
|
}
|
|
282
266
|
}
|
|
283
|
-
function resolveRegionForBlockingTrigger(
|
|
284
|
-
const eventType =
|
|
267
|
+
function resolveRegionForBlockingTrigger(blockingTrigger) {
|
|
268
|
+
const eventType = blockingTrigger.eventType;
|
|
285
269
|
if (events.AUTH_BLOCKING_EVENTS.includes(eventType)) {
|
|
286
270
|
return "us-east1";
|
|
287
271
|
}
|
|
288
|
-
if ((0, ailogic_1.
|
|
272
|
+
if ((0, ailogic_1.isGlobalAILogicTrigger)(blockingTrigger)) {
|
|
289
273
|
return "us-east1";
|
|
290
274
|
}
|
|
291
275
|
return exports.DEFAULT_FUNCTION_REGION;
|
|
292
276
|
}
|
|
293
|
-
async function resolveRegionForEventTrigger(
|
|
294
|
-
const eventTrigger = endpoint.eventTrigger;
|
|
277
|
+
async function resolveRegionForEventTrigger(project, eventTrigger) {
|
|
295
278
|
const eventType = eventTrigger.eventType;
|
|
296
279
|
if (eventType.startsWith("google.cloud.pubsub.") ||
|
|
297
280
|
eventType.startsWith("providers/cloud.auth/eventTypes/") ||
|
|
@@ -304,7 +287,7 @@ async function resolveRegionForEventTrigger(endpoint) {
|
|
|
304
287
|
if (eventType.startsWith("google.cloud.firestore.")) {
|
|
305
288
|
try {
|
|
306
289
|
const databaseId = eventTrigger.eventFilters?.database || "(default)";
|
|
307
|
-
const db = await (0, firestore_1.getDatabase)(
|
|
290
|
+
const db = await (0, firestore_1.getDatabase)(project, databaseId);
|
|
308
291
|
const locationId = db.locationId.toLowerCase();
|
|
309
292
|
if (locationId === "nam5" || locationId === "nam7")
|
|
310
293
|
return "us-central1";
|
|
@@ -341,7 +324,7 @@ async function resolveRegionForEventTrigger(endpoint) {
|
|
|
341
324
|
try {
|
|
342
325
|
const instanceName = eventTrigger.eventFilters?.instance;
|
|
343
326
|
if (instanceName) {
|
|
344
|
-
const details = await (0, database_1.getDatabaseInstanceDetails)(
|
|
327
|
+
const details = await (0, database_1.getDatabaseInstanceDetails)(project, instanceName);
|
|
345
328
|
if (details.location && details.location !== "-") {
|
|
346
329
|
return details.location.toLowerCase();
|
|
347
330
|
}
|
|
@@ -389,6 +372,9 @@ function inferDetailsFromExisting(want, have, usedDotenv) {
|
|
|
389
372
|
if (typeof wantE.cpu === "undefined" && haveE.cpu) {
|
|
390
373
|
wantE.cpu = haveE.cpu;
|
|
391
374
|
}
|
|
375
|
+
if (typeof wantE.timeoutSeconds === "undefined" && haveE.timeoutSeconds) {
|
|
376
|
+
wantE.timeoutSeconds = haveE.timeoutSeconds;
|
|
377
|
+
}
|
|
392
378
|
wantE.securityLevel = haveE.securityLevel ? haveE.securityLevel : "SECURE_ALWAYS";
|
|
393
379
|
maybeCopyTriggerRegion(wantE, haveE);
|
|
394
380
|
}
|
|
@@ -454,6 +440,13 @@ function resolveCpuAndConcurrency(want) {
|
|
|
454
440
|
}
|
|
455
441
|
}
|
|
456
442
|
}
|
|
443
|
+
function resolveDefaultTimeout(want) {
|
|
444
|
+
for (const e of backend.allEndpoints(want)) {
|
|
445
|
+
if (e.platform === "run" && e.timeoutSeconds === undefined) {
|
|
446
|
+
e.timeoutSeconds = backend.DEFAULT_TIMEOUT_SECONDS;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
457
450
|
async function loadCodebases(config, options, firebaseConfig, runtimeConfig, filters) {
|
|
458
451
|
const codebases = (0, functionsDeployHelper_1.targetCodebases)(config, filters);
|
|
459
452
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
@@ -78,7 +78,7 @@ async function packageSource(projectDir, sourceDir, config, additionalSources, r
|
|
|
78
78
|
const ignore = config.ignore || ["node_modules", ".git"];
|
|
79
79
|
ignore.push("firebase-debug.log", "firebase-debug.*.log", CONFIG_DEST_FILE);
|
|
80
80
|
try {
|
|
81
|
-
const files = await fsAsync.readdirRecursive({ path: sourceDir,
|
|
81
|
+
const files = await fsAsync.readdirRecursive({ path: sourceDir, ignoreStrings: ignore });
|
|
82
82
|
hashes.push(...(await addFilesToArchive(archive, files, sourceDir, options?.executablePaths)));
|
|
83
83
|
for (const name of additionalSources) {
|
|
84
84
|
const absPath = utils.resolveWithin(projectDir, name);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AILogicService = exports.AI_LOGIC_EVENTS = exports.AI_LOGIC_AFTER_GENERATE_CONTENT = exports.AI_LOGIC_BEFORE_GENERATE_CONTENT = void 0;
|
|
4
4
|
exports.isAILogicEvent = isAILogicEvent;
|
|
5
|
-
exports.
|
|
5
|
+
exports.isGlobalAILogicTrigger = isGlobalAILogicTrigger;
|
|
6
6
|
const backend = require("../backend");
|
|
7
7
|
const error_1 = require("../../../error");
|
|
8
8
|
const ailogicApi = require("../../../gcp/ailogic");
|
|
@@ -20,11 +20,9 @@ function isAILogicEvent(endpoint) {
|
|
|
20
20
|
}
|
|
21
21
|
return exports.AI_LOGIC_EVENTS.includes(endpoint.blockingTrigger.eventType);
|
|
22
22
|
}
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
return !endpoint.blockingTrigger.options?.regionalWebhook;
|
|
23
|
+
function isGlobalAILogicTrigger(blockingTrigger) {
|
|
24
|
+
return (exports.AI_LOGIC_EVENTS.includes(blockingTrigger.eventType) &&
|
|
25
|
+
!blockingTrigger.options?.regionalWebhook);
|
|
28
26
|
}
|
|
29
27
|
class AILogicService {
|
|
30
28
|
constructor() {
|
|
@@ -32,6 +30,16 @@ class AILogicService {
|
|
|
32
30
|
this.name = "ailogic";
|
|
33
31
|
this.api = "firebasevertexai.googleapis.com";
|
|
34
32
|
}
|
|
33
|
+
async requiredProjectBindings(projectNumber) {
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
role: "roles/run.invoker",
|
|
37
|
+
members: [
|
|
38
|
+
`serviceAccount:service-${projectNumber}@gcp-sa-firebasevertexai.iam.gserviceaccount.com`,
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
}
|
|
35
43
|
validateTrigger(endpoint, wantBackend) {
|
|
36
44
|
if (!isAILogicEvent(endpoint)) {
|
|
37
45
|
return;
|
|
@@ -221,7 +221,7 @@ async function secretsAreValid(projectId, wantBackend) {
|
|
|
221
221
|
validatePlatformTargets(endpoints);
|
|
222
222
|
await validateSecretVersions(projectId, endpoints);
|
|
223
223
|
}
|
|
224
|
-
const secretsSupportedPlatforms =
|
|
224
|
+
const secretsSupportedPlatforms = backend.AllFunctionsPlatforms;
|
|
225
225
|
function validatePlatformTargets(endpoints) {
|
|
226
226
|
const unsupported = endpoints.filter((e) => !secretsSupportedPlatforms.includes(e.platform));
|
|
227
227
|
if (unsupported.length > 0) {
|
package/lib/downloadUtils.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.downloadToTmp = downloadToTmp;
|
|
4
|
+
exports.validateSize = validateSize;
|
|
5
|
+
exports.validateChecksum = validateChecksum;
|
|
4
6
|
const url_1 = require("url");
|
|
7
|
+
const crypto = require("crypto");
|
|
5
8
|
const fs = require("fs-extra");
|
|
6
9
|
const ProgressBar = require("progress");
|
|
7
10
|
const tmp = require("tmp");
|
|
@@ -37,3 +40,24 @@ async function downloadToTmp(remoteUrl, auth = false) {
|
|
|
37
40
|
});
|
|
38
41
|
return tmpfile.name;
|
|
39
42
|
}
|
|
43
|
+
function validateSize(filepath, expectedSize) {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
const stat = fs.statSync(filepath);
|
|
46
|
+
return stat.size === expectedSize
|
|
47
|
+
? resolve()
|
|
48
|
+
: reject(new error_1.FirebaseError(`download failed, expected ${expectedSize} bytes but got ${stat.size}`, { exit: 1 }));
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function validateChecksum(filepath, expectedChecksum, algorithm = "md5") {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const hash = crypto.createHash(algorithm);
|
|
54
|
+
const stream = fs.createReadStream(filepath);
|
|
55
|
+
stream.on("data", (data) => hash.update(data));
|
|
56
|
+
stream.on("end", () => {
|
|
57
|
+
const checksum = hash.digest("hex");
|
|
58
|
+
return checksum === expectedChecksum
|
|
59
|
+
? resolve()
|
|
60
|
+
: reject(new error_1.FirebaseError(`download failed, expected checksum ${expectedChecksum} but got ${checksum}`, { exit: 1 }));
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
package/lib/emulator/download.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.downloadEmulator = downloadEmulator;
|
|
4
4
|
exports.downloadExtensionVersion = downloadExtensionVersion;
|
|
5
|
-
const crypto = require("crypto");
|
|
6
5
|
const fs = require("fs-extra");
|
|
7
6
|
const path = require("path");
|
|
8
7
|
const tmp = require("tmp");
|
|
@@ -36,8 +35,8 @@ async function downloadEmulator(name) {
|
|
|
36
35
|
throw err;
|
|
37
36
|
}
|
|
38
37
|
if (!emulator.opts.skipChecksumAndSize) {
|
|
39
|
-
await validateSize(tmpfile, emulator.opts.expectedSize);
|
|
40
|
-
await validateChecksum(tmpfile, emulator.opts.expectedChecksum);
|
|
38
|
+
await downloadUtils.validateSize(tmpfile, emulator.opts.expectedSize);
|
|
39
|
+
await downloadUtils.validateChecksum(tmpfile, emulator.opts.expectedChecksum, "md5");
|
|
41
40
|
}
|
|
42
41
|
if (emulator.opts.skipCache) {
|
|
43
42
|
removeOldFiles(name, emulator, true);
|
|
@@ -82,24 +81,3 @@ function removeOldFiles(name, emulator, removeAllVersions = false) {
|
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
}
|
|
85
|
-
function validateSize(filepath, expectedSize) {
|
|
86
|
-
return new Promise((resolve, reject) => {
|
|
87
|
-
const stat = fs.statSync(filepath);
|
|
88
|
-
return stat.size === expectedSize
|
|
89
|
-
? resolve()
|
|
90
|
-
: reject(new error_1.FirebaseError(`download failed, expected ${expectedSize} bytes but got ${stat.size}`, { exit: 1 }));
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
function validateChecksum(filepath, expectedChecksum) {
|
|
94
|
-
return new Promise((resolve, reject) => {
|
|
95
|
-
const hash = crypto.createHash("md5");
|
|
96
|
-
const stream = fs.createReadStream(filepath);
|
|
97
|
-
stream.on("data", (data) => hash.update(data));
|
|
98
|
-
stream.on("end", () => {
|
|
99
|
-
const checksum = hash.digest("hex");
|
|
100
|
-
return checksum === expectedChecksum
|
|
101
|
-
? resolve()
|
|
102
|
-
: reject(new error_1.FirebaseError(`download failed, expected checksum ${expectedChecksum} but got ${checksum}`, { exit: 1 }));
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
}
|
|
@@ -44,46 +44,46 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"pubsub": {
|
|
47
|
-
"version": "0.8.
|
|
48
|
-
"expectedSize":
|
|
49
|
-
"expectedChecksum": "
|
|
50
|
-
"expectedChecksumSHA256": "
|
|
51
|
-
"remoteUrl": "https://storage.googleapis.com/firebase-preview-drop/emulator/pubsub-emulator-0.8.
|
|
52
|
-
"downloadPathRelativeToCacheDir": "pubsub-emulator-0.8.
|
|
53
|
-
"binaryPathRelativeToCacheDir": "pubsub-emulator-0.8.
|
|
47
|
+
"version": "0.8.32",
|
|
48
|
+
"expectedSize": 52942305,
|
|
49
|
+
"expectedChecksum": "b47a3698985bff5f6aedec04fad9354e",
|
|
50
|
+
"expectedChecksumSHA256": "476d6492718210837f13e64b5b9f54335469381827bad25eda62e36572e47a82",
|
|
51
|
+
"remoteUrl": "https://storage.googleapis.com/firebase-preview-drop/emulator/pubsub-emulator-0.8.32.zip",
|
|
52
|
+
"downloadPathRelativeToCacheDir": "pubsub-emulator-0.8.32.zip",
|
|
53
|
+
"binaryPathRelativeToCacheDir": "pubsub-emulator-0.8.32/pubsub-emulator/bin/cloud-pubsub-emulator"
|
|
54
54
|
},
|
|
55
55
|
"dataconnect": {
|
|
56
56
|
"darwin": {
|
|
57
|
-
"version": "3.4.
|
|
58
|
-
"expectedSize":
|
|
59
|
-
"expectedChecksum": "
|
|
60
|
-
"expectedChecksumSHA256": "
|
|
61
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-amd64-v3.4.
|
|
62
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.
|
|
57
|
+
"version": "3.4.9",
|
|
58
|
+
"expectedSize": 32423488,
|
|
59
|
+
"expectedChecksum": "75788cfdb69c2762ac9f78e37714d364",
|
|
60
|
+
"expectedChecksumSHA256": "af26c22a6fe131b111b4e71eb4c179b2b42a9cf8d334d50e4c2c419bbbb54416",
|
|
61
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-amd64-v3.4.9",
|
|
62
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.9"
|
|
63
63
|
},
|
|
64
64
|
"darwin_arm64": {
|
|
65
|
-
"version": "3.4.
|
|
66
|
-
"expectedSize":
|
|
67
|
-
"expectedChecksum": "
|
|
68
|
-
"expectedChecksumSHA256": "
|
|
69
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-arm64-v3.4.
|
|
70
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.
|
|
65
|
+
"version": "3.4.9",
|
|
66
|
+
"expectedSize": 30554802,
|
|
67
|
+
"expectedChecksum": "7e64aba6ffc071ef60b8f2a51b3f5683",
|
|
68
|
+
"expectedChecksumSHA256": "49ba258954b3568e93ef75b4c7e9a50c708a7e15ba9a22697ff967e195a907aa",
|
|
69
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-arm64-v3.4.9",
|
|
70
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.9"
|
|
71
71
|
},
|
|
72
72
|
"win32": {
|
|
73
|
-
"version": "3.4.
|
|
74
|
-
"expectedSize":
|
|
75
|
-
"expectedChecksum": "
|
|
76
|
-
"expectedChecksumSHA256": "
|
|
77
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-amd64-v3.4.
|
|
78
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.
|
|
73
|
+
"version": "3.4.9",
|
|
74
|
+
"expectedSize": 32464896,
|
|
75
|
+
"expectedChecksum": "1bc40de5be6bab9280904ee68f849594",
|
|
76
|
+
"expectedChecksumSHA256": "b0b277ed1efd374099b90a74ebb2994ffa5755c185d8d9d2cf667f49c0c31139",
|
|
77
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-amd64-v3.4.9",
|
|
78
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.9.exe"
|
|
79
79
|
},
|
|
80
80
|
"linux": {
|
|
81
|
-
"version": "3.4.
|
|
82
|
-
"expectedSize":
|
|
83
|
-
"expectedChecksum": "
|
|
84
|
-
"expectedChecksumSHA256": "
|
|
85
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-amd64-v3.4.
|
|
86
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.
|
|
81
|
+
"version": "3.4.9",
|
|
82
|
+
"expectedSize": 31580344,
|
|
83
|
+
"expectedChecksum": "4de2d7d37652d652d059335a43dc02b4",
|
|
84
|
+
"expectedChecksumSHA256": "803ec59b5ec1590ed4521df70864a46808f3ec8008756206bf210852e2298291",
|
|
85
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-amd64-v3.4.9",
|
|
86
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.9"
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|
package/lib/fsAsync.js
CHANGED
|
@@ -6,12 +6,37 @@ const ignore_1 = require("ignore");
|
|
|
6
6
|
const _ = require("lodash");
|
|
7
7
|
const minimatch = require("minimatch");
|
|
8
8
|
const path_1 = require("path");
|
|
9
|
+
const logger_1 = require("./logger");
|
|
9
10
|
async function readdirRecursiveHelper(options) {
|
|
10
11
|
const dirContents = (0, fs_extra_1.readdirSync)(options.path, { withFileTypes: true });
|
|
12
|
+
let currentGitIgnoreStack = options.gitIgnoreStack || [];
|
|
13
|
+
if (options.supportGitIgnore) {
|
|
14
|
+
if (dirContents.find((n) => n.name === ".gitignore")?.isFile()) {
|
|
15
|
+
const localGitIgnore = (0, path_1.join)(options.path, ".gitignore");
|
|
16
|
+
try {
|
|
17
|
+
const lines = (0, fs_extra_1.readFileSync)(localGitIgnore)
|
|
18
|
+
.toString()
|
|
19
|
+
.split("\n")
|
|
20
|
+
.map((line) => line.trim())
|
|
21
|
+
.filter((line) => !line.startsWith("#") && line !== "");
|
|
22
|
+
const subIgnore = (0, ignore_1.default)().add(lines);
|
|
23
|
+
currentGitIgnoreStack = [
|
|
24
|
+
...currentGitIgnoreStack,
|
|
25
|
+
{
|
|
26
|
+
dirPath: options.path,
|
|
27
|
+
ignore: subIgnore,
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
logger_1.logger.debug(`Error reading .gitignore file at ${localGitIgnore}:`, e);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
11
36
|
const fullPaths = dirContents
|
|
12
37
|
.filter((n) => !options.ignoreSymlinks || !n.isSymbolicLink())
|
|
13
38
|
.map((n) => (0, path_1.join)(options.path, n.name));
|
|
14
|
-
const filteredPaths = fullPaths.filter((p) => !options.filter(p));
|
|
39
|
+
const filteredPaths = fullPaths.filter((p) => !options.filter(p, currentGitIgnoreStack));
|
|
15
40
|
const filePromises = [];
|
|
16
41
|
for (const p of filteredPaths) {
|
|
17
42
|
const fstat = (0, fs_extra_1.statSync)(p);
|
|
@@ -27,6 +52,8 @@ async function readdirRecursiveHelper(options) {
|
|
|
27
52
|
filter: options.filter,
|
|
28
53
|
maxDepth: options.maxDepth - 1,
|
|
29
54
|
ignoreSymlinks: options.ignoreSymlinks,
|
|
55
|
+
supportGitIgnore: options.supportGitIgnore,
|
|
56
|
+
gitIgnoreStack: currentGitIgnoreStack,
|
|
30
57
|
}));
|
|
31
58
|
}
|
|
32
59
|
}
|
|
@@ -37,25 +64,41 @@ async function readdirRecursiveHelper(options) {
|
|
|
37
64
|
}
|
|
38
65
|
async function readdirRecursive(options) {
|
|
39
66
|
const mmopts = { matchBase: true, dot: true };
|
|
40
|
-
const
|
|
67
|
+
const ignoreRules = (options.ignoreStrings || []).map((glob) => {
|
|
41
68
|
return (p) => minimatch(p, glob, mmopts);
|
|
42
69
|
});
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
70
|
+
const filter = (targetPath, gitIgnoreStack = []) => {
|
|
71
|
+
if (options.supportGitIgnore) {
|
|
72
|
+
let ignored = false;
|
|
73
|
+
for (let i = gitIgnoreStack.length - 1; i >= 0; i--) {
|
|
74
|
+
const state = gitIgnoreStack[i];
|
|
75
|
+
const relPath = (0, path_1.relative)(state.dirPath, targetPath);
|
|
76
|
+
const result = state.ignore.test(relPath);
|
|
77
|
+
if (result.ignored || result.unignored) {
|
|
78
|
+
ignored = result.ignored;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return ignored;
|
|
49
83
|
}
|
|
50
|
-
return
|
|
51
|
-
return rule(
|
|
84
|
+
return ignoreRules.some((rule) => {
|
|
85
|
+
return rule(targetPath);
|
|
52
86
|
});
|
|
53
87
|
};
|
|
88
|
+
const initialGitIgnoreStack = [];
|
|
89
|
+
if (options.supportGitIgnore) {
|
|
90
|
+
initialGitIgnoreStack.push({
|
|
91
|
+
dirPath: options.path,
|
|
92
|
+
ignore: (0, ignore_1.default)().add(options.ignoreStrings || []),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
54
95
|
const maxDepth = options.maxDepth && options.maxDepth > 0 ? options.maxDepth : Infinity;
|
|
55
96
|
return await readdirRecursiveHelper({
|
|
56
97
|
path: options.path,
|
|
57
98
|
filter: filter,
|
|
58
99
|
maxDepth,
|
|
59
100
|
ignoreSymlinks: !!options.ignoreSymlinks,
|
|
101
|
+
supportGitIgnore: options.supportGitIgnore,
|
|
102
|
+
gitIgnoreStack: initialGitIgnoreStack,
|
|
60
103
|
});
|
|
61
104
|
}
|