firebase-tools 14.12.0 → 14.13.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/README.md +1 -1
- package/lib/commands/dataconnect-services-list.js +5 -5
- package/lib/commands/dataconnect-sql-grant.js +5 -0
- package/lib/commands/dataconnect-sql-setup.js +1 -3
- package/lib/commands/firestore-databases-create.js +11 -0
- package/lib/crashlytics/buildToolsJarHelper.js +1 -2
- package/lib/crashlytics/getIssueDetails.js +41 -0
- package/lib/crashlytics/getSampleCrash.js +48 -0
- package/lib/dataconnect/client.js +23 -15
- package/lib/dataconnect/ensureApis.js +5 -9
- package/lib/dataconnect/fileUtils.js +5 -6
- package/lib/dataconnect/freeTrial.js +16 -39
- package/lib/dataconnect/provisionCloudSql.js +67 -70
- package/lib/dataconnect/schemaMigration.js +75 -47
- package/lib/deploy/dataconnect/deploy.js +9 -11
- package/lib/deploy/dataconnect/prepare.js +9 -12
- package/lib/deploy/dataconnect/release.js +13 -7
- package/lib/deploy/firestore/deploy.js +10 -0
- package/lib/deploy/functions/backend.js +8 -2
- package/lib/deploy/functions/build.js +23 -1
- package/lib/deploy/functions/ensure.js +1 -1
- package/lib/deploy/functions/functionsDeployHelper.js +8 -1
- package/lib/deploy/functions/prepare.js +6 -4
- package/lib/deploy/functions/prepareFunctionsUpload.js +3 -1
- package/lib/deploy/functions/pricing.js +12 -5
- package/lib/deploy/functions/release/fabricator.js +25 -3
- package/lib/emulator/controller.js +2 -1
- package/lib/emulator/downloadableEmulatorInfo.json +18 -18
- package/lib/emulator/functionsEmulator.js +9 -1
- package/lib/experiments.js +4 -0
- package/lib/extensions/extensionsHelper.js +4 -15
- package/lib/extensions/utils.js +1 -12
- package/lib/firestore/api-sort.js +96 -3
- package/lib/firestore/api-types.js +14 -1
- package/lib/firestore/api.js +85 -4
- package/lib/firestore/pretty-print.js +7 -0
- package/lib/firestore/validator.js +1 -1
- package/lib/functional.js +7 -1
- package/lib/functions/deprecationWarnings.js +4 -4
- package/lib/functions/projectConfig.js +25 -2
- package/lib/functions/secrets.js +3 -0
- package/lib/gcp/cloudfunctionsv2.js +3 -31
- package/lib/gcp/cloudscheduler.js +1 -1
- package/lib/gcp/cloudsql/cloudsqladmin.js +2 -14
- package/lib/gcp/cloudsql/connect.js +2 -2
- package/lib/gcp/cloudsql/permissionsSetup.js +13 -15
- package/lib/gcp/k8s.js +32 -0
- package/lib/gcp/runv2.js +178 -0
- package/lib/gemini/fdcExperience.js +5 -3
- package/lib/init/features/dataconnect/index.js +266 -162
- package/lib/init/features/dataconnect/sdk.js +32 -17
- package/lib/init/features/project.js +4 -0
- package/lib/management/studio.js +1 -1
- package/lib/mcp/index.js +75 -2
- package/lib/mcp/prompt.js +10 -0
- package/lib/mcp/prompts/core/deploy.js +58 -0
- package/lib/mcp/prompts/core/index.js +5 -0
- package/lib/mcp/prompts/index.js +45 -0
- package/lib/mcp/tools/core/get_sdk_config.js +10 -0
- package/lib/mcp/tools/core/init.js +7 -6
- package/lib/mcp/tools/crashlytics/get_issue_details.js +33 -0
- package/lib/mcp/tools/crashlytics/get_sample_crash.js +43 -0
- package/lib/mcp/tools/crashlytics/index.js +7 -1
- package/lib/mcp/tools/crashlytics/list_top_issues.js +2 -1
- package/lib/mcp/tools/database/get_data.js +49 -0
- package/lib/mcp/tools/database/get_rules.js +39 -0
- package/lib/mcp/tools/database/index.js +8 -0
- package/lib/mcp/tools/database/set_data.js +57 -0
- package/lib/mcp/tools/database/set_rules.js +41 -0
- package/lib/mcp/tools/database/validate_rules.js +41 -0
- package/lib/mcp/tools/index.js +4 -1
- package/lib/mcp/tools/rules/get_rules.js +1 -1
- package/lib/mcp/types.js +2 -0
- package/lib/mcp/util.js +2 -0
- package/lib/rtdb.js +10 -6
- package/lib/utils.js +24 -1
- package/package.json +1 -1
- package/schema/firebase-config.json +6 -0
- package/templates/init/firestore/firestore.indexes.json +26 -1
- package/lib/extensions/resolveSource.js +0 -24
|
@@ -136,6 +136,11 @@ class Fabricator {
|
|
|
136
136
|
else if (endpoint.platform === "gcfv2") {
|
|
137
137
|
await this.createV2Function(endpoint, scraperV2);
|
|
138
138
|
}
|
|
139
|
+
else if (endpoint.platform === "run") {
|
|
140
|
+
throw new error_1.FirebaseError("Creating new Cloud Run functions is not supported yet.", {
|
|
141
|
+
exit: 1,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
139
144
|
else {
|
|
140
145
|
(0, functional_1.assertExhaustive)(endpoint.platform);
|
|
141
146
|
}
|
|
@@ -154,6 +159,9 @@ class Fabricator {
|
|
|
154
159
|
else if (update.endpoint.platform === "gcfv2") {
|
|
155
160
|
await this.updateV2Function(update.endpoint, scraperV2);
|
|
156
161
|
}
|
|
162
|
+
else if (update.endpoint.platform === "run") {
|
|
163
|
+
throw new error_1.FirebaseError("Updating Cloud Run functions is not supported yet.", { exit: 1 });
|
|
164
|
+
}
|
|
157
165
|
else {
|
|
158
166
|
(0, functional_1.assertExhaustive)(update.endpoint.platform);
|
|
159
167
|
}
|
|
@@ -162,11 +170,15 @@ class Fabricator {
|
|
|
162
170
|
async deleteEndpoint(endpoint) {
|
|
163
171
|
await this.deleteTrigger(endpoint);
|
|
164
172
|
if (endpoint.platform === "gcfv1") {
|
|
165
|
-
|
|
173
|
+
return this.deleteV1Function(endpoint);
|
|
166
174
|
}
|
|
167
|
-
else {
|
|
168
|
-
|
|
175
|
+
else if (endpoint.platform === "gcfv2") {
|
|
176
|
+
return this.deleteV2Function(endpoint);
|
|
169
177
|
}
|
|
178
|
+
else if (endpoint.platform === "run") {
|
|
179
|
+
throw new error_1.FirebaseError("Deleting Cloud Run functions is not supported yet.", { exit: 1 });
|
|
180
|
+
}
|
|
181
|
+
(0, functional_1.assertExhaustive)(endpoint.platform);
|
|
170
182
|
}
|
|
171
183
|
async createV1Function(endpoint, scraper) {
|
|
172
184
|
var _a, _b;
|
|
@@ -471,6 +483,11 @@ class Fabricator {
|
|
|
471
483
|
.catch(rethrowAs(endpoint, "set concurrency"));
|
|
472
484
|
}
|
|
473
485
|
async setTrigger(endpoint) {
|
|
486
|
+
if (endpoint.platform === "run") {
|
|
487
|
+
throw new error_1.FirebaseError("Setting triggers for Cloud Run functions is not supported yet.", {
|
|
488
|
+
exit: 1,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
474
491
|
if (backend.isScheduleTriggered(endpoint)) {
|
|
475
492
|
if (endpoint.platform === "gcfv1") {
|
|
476
493
|
await this.upsertScheduleV1(endpoint);
|
|
@@ -490,6 +507,11 @@ class Fabricator {
|
|
|
490
507
|
}
|
|
491
508
|
}
|
|
492
509
|
async deleteTrigger(endpoint) {
|
|
510
|
+
if (endpoint.platform === "run") {
|
|
511
|
+
throw new error_1.FirebaseError("Deleting triggers for Cloud Run functions is not supported yet.", {
|
|
512
|
+
exit: 1,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
493
515
|
if (backend.isScheduleTriggered(endpoint)) {
|
|
494
516
|
if (endpoint.platform === "gcfv1") {
|
|
495
517
|
await this.deleteScheduleV1(endpoint);
|
|
@@ -116,7 +116,7 @@ function shouldStart(options, name) {
|
|
|
116
116
|
return true;
|
|
117
117
|
}
|
|
118
118
|
catch (err) {
|
|
119
|
-
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).logLabeled("
|
|
119
|
+
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).logLabeled("ERROR", "functions", `Failed to start Functions emulator: ${err.message}`);
|
|
120
120
|
return false;
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -348,6 +348,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
348
348
|
functionsDir,
|
|
349
349
|
runtime,
|
|
350
350
|
codebase: cfg.codebase,
|
|
351
|
+
prefix: cfg.prefix,
|
|
351
352
|
env: Object.assign({}, options.extDevEnv),
|
|
352
353
|
secretEnv: [],
|
|
353
354
|
predefinedTriggers: options.extDevTriggers,
|
|
@@ -54,28 +54,28 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dataconnect": {
|
|
56
56
|
"darwin": {
|
|
57
|
-
"version": "2.11.
|
|
58
|
-
"expectedSize":
|
|
59
|
-
"expectedChecksum": "
|
|
60
|
-
"expectedChecksumSHA256": "
|
|
61
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-v2.11.
|
|
62
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.11.
|
|
57
|
+
"version": "2.11.2",
|
|
58
|
+
"expectedSize": 29447008,
|
|
59
|
+
"expectedChecksum": "13bc7d3bb0a0bbfe601991361e4413c2",
|
|
60
|
+
"expectedChecksumSHA256": "e3b029eb461f0fe6f0c825c7a71d42c7a09c2b8ee4fac10c3e187d78fe5083f6",
|
|
61
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-v2.11.2",
|
|
62
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.11.2"
|
|
63
63
|
},
|
|
64
64
|
"win32": {
|
|
65
|
-
"version": "2.11.
|
|
66
|
-
"expectedSize":
|
|
67
|
-
"expectedChecksum": "
|
|
68
|
-
"expectedChecksumSHA256": "
|
|
69
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-v2.11.
|
|
70
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.11.
|
|
65
|
+
"version": "2.11.2",
|
|
66
|
+
"expectedSize": 29934592,
|
|
67
|
+
"expectedChecksum": "032a0749781fc338b446d753dd543bf5",
|
|
68
|
+
"expectedChecksumSHA256": "2d0498b3ef94b4e777d6fc1d526279376caf3842549f39f13a8ca327393bf810",
|
|
69
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-v2.11.2",
|
|
70
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.11.2.exe"
|
|
71
71
|
},
|
|
72
72
|
"linux": {
|
|
73
|
-
"version": "2.11.
|
|
74
|
-
"expectedSize":
|
|
75
|
-
"expectedChecksum": "
|
|
76
|
-
"expectedChecksumSHA256": "
|
|
77
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-v2.11.
|
|
78
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.11.
|
|
73
|
+
"version": "2.11.2",
|
|
74
|
+
"expectedSize": 29368504,
|
|
75
|
+
"expectedChecksum": "065a7523f881952040ac678a9a1e9323",
|
|
76
|
+
"expectedChecksumSHA256": "41ca6561cf77107b5d1d829233844d21c46a5e4bb823c150b1b32591dc2463e0",
|
|
77
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-v2.11.2",
|
|
78
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.11.2"
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -28,8 +28,9 @@ const utils_1 = require("../utils");
|
|
|
28
28
|
const adminSdkConfig_1 = require("./adminSdkConfig");
|
|
29
29
|
const validate_1 = require("../deploy/functions/validate");
|
|
30
30
|
const secretManager_1 = require("../gcp/secretManager");
|
|
31
|
-
const runtimes = require("../deploy/functions/runtimes");
|
|
32
31
|
const backend = require("../deploy/functions/backend");
|
|
32
|
+
const build = require("../deploy/functions/build");
|
|
33
|
+
const runtimes = require("../deploy/functions/runtimes");
|
|
33
34
|
const functionsEnv = require("../functions/env");
|
|
34
35
|
const v1_1 = require("../functions/events/v1");
|
|
35
36
|
const build_1 = require("../deploy/functions/build");
|
|
@@ -82,6 +83,7 @@ class FunctionsEmulator {
|
|
|
82
83
|
this.blockingFunctionsConfig = {};
|
|
83
84
|
this.staticBackends = [];
|
|
84
85
|
this.dynamicBackends = [];
|
|
86
|
+
this.watchers = [];
|
|
85
87
|
this.debugMode = false;
|
|
86
88
|
this.staticBackends = args.emulatableBackends;
|
|
87
89
|
emulatorLogger_1.EmulatorLogger.setVerbosity(this.args.verbosity ? emulatorLogger_1.Verbosity[this.args.verbosity] : emulatorLogger_1.Verbosity["DEBUG"]);
|
|
@@ -271,6 +273,7 @@ class FunctionsEmulator {
|
|
|
271
273
|
],
|
|
272
274
|
persistent: true,
|
|
273
275
|
});
|
|
276
|
+
this.watchers.push(watcher);
|
|
274
277
|
const debouncedLoadTriggers = (0, utils_1.debounce)(() => this.loadTriggers(backend), 1000);
|
|
275
278
|
watcher.on("change", (filePath) => {
|
|
276
279
|
this.logger.log("DEBUG", `File ${filePath} changed, reloading triggers`);
|
|
@@ -292,6 +295,10 @@ class FunctionsEmulator {
|
|
|
292
295
|
for (const pool of Object.values(this.workerPools)) {
|
|
293
296
|
pool.exit();
|
|
294
297
|
}
|
|
298
|
+
for (const watcher of this.watchers) {
|
|
299
|
+
await watcher.close();
|
|
300
|
+
}
|
|
301
|
+
this.watchers = [];
|
|
295
302
|
if (this.destroyServer) {
|
|
296
303
|
await this.destroyServer();
|
|
297
304
|
}
|
|
@@ -329,6 +336,7 @@ class FunctionsEmulator {
|
|
|
329
336
|
await this.args.extensionsEmulator.addDynamicExtensions(emulatableBackend.codebase, discoveredBuild);
|
|
330
337
|
await this.loadDynamicExtensionBackends();
|
|
331
338
|
}
|
|
339
|
+
build.applyPrefix(discoveredBuild, emulatableBackend.prefix || "");
|
|
332
340
|
const resolution = await (0, build_1.resolveBackend)({
|
|
333
341
|
build: discoveredBuild,
|
|
334
342
|
firebaseConfig: JSON.parse(firebaseConfig),
|
package/lib/experiments.js
CHANGED
|
@@ -48,6 +48,10 @@ exports.ALL_EXPERIMENTS = experiments({
|
|
|
48
48
|
default: true,
|
|
49
49
|
public: true,
|
|
50
50
|
},
|
|
51
|
+
runfunctions: {
|
|
52
|
+
shortDescription: "Functions created using the V2 API target Cloud Run Functions (not production ready)",
|
|
53
|
+
public: false,
|
|
54
|
+
},
|
|
51
55
|
emulatoruisnapshot: {
|
|
52
56
|
shortDescription: "Load pre-release versions of the emulator UI",
|
|
53
57
|
},
|
|
@@ -7,7 +7,7 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
|
7
7
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
8
8
|
};
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.diagnoseAndFixProject = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.
|
|
10
|
+
exports.diagnoseAndFixProject = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.getMissingPublisherError = exports.uploadExtensionVersionFromLocalSource = exports.uploadExtensionVersionFromGitHubSource = exports.unpackExtensionState = exports.getNextVersionByStage = exports.ensureExtensionsPublisherApiEnabled = exports.ensureExtensionsApiEnabled = exports.checkExtensionsApiEnabled = exports.promptForExtensionRoot = exports.promptForValidRepoURI = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteSecretParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.AUTOPOPULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
|
|
11
11
|
const clc = require("colorette");
|
|
12
12
|
const ora = require("ora");
|
|
13
13
|
const semver = require("semver");
|
|
@@ -21,10 +21,8 @@ const unzip_1 = require("./../unzip");
|
|
|
21
21
|
marked_1.marked.use((0, marked_terminal_1.markedTerminal)());
|
|
22
22
|
const api_1 = require("../api");
|
|
23
23
|
const archiveDirectory_1 = require("../archiveDirectory");
|
|
24
|
-
const utils_1 = require("./utils");
|
|
25
24
|
const functionsConfig_1 = require("../functionsConfig");
|
|
26
25
|
const adminSdkConfig_1 = require("../emulator/adminSdkConfig");
|
|
27
|
-
const resolveSource_1 = require("./resolveSource");
|
|
28
26
|
const error_1 = require("../error");
|
|
29
27
|
const diagnose_1 = require("./diagnose");
|
|
30
28
|
const askUserForParam_1 = require("./askUserForParam");
|
|
@@ -37,7 +35,7 @@ const prompt_1 = require("../prompt");
|
|
|
37
35
|
const refs = require("./refs");
|
|
38
36
|
const localHelper_1 = require("./localHelper");
|
|
39
37
|
const logger_1 = require("../logger");
|
|
40
|
-
const
|
|
38
|
+
const utils_1 = require("../utils");
|
|
41
39
|
const change_log_1 = require("./change-log");
|
|
42
40
|
const getProjectNumber_1 = require("../getProjectNumber");
|
|
43
41
|
const constants_1 = require("../emulator/constants");
|
|
@@ -61,7 +59,7 @@ var SourceOrigin;
|
|
|
61
59
|
exports.logPrefix = "extensions";
|
|
62
60
|
const VALID_LICENSES = ["apache-2.0"];
|
|
63
61
|
exports.URL_REGEX = /^https:/;
|
|
64
|
-
exports.EXTENSIONS_BUCKET_NAME = (0,
|
|
62
|
+
exports.EXTENSIONS_BUCKET_NAME = (0, utils_1.envOverride)("FIREBASE_EXTENSIONS_UPLOAD_BUCKET", "firebase-ext-eap-uploads");
|
|
65
63
|
const AUTOPOPULATED_PARAM_NAMES = [
|
|
66
64
|
"PROJECT_ID",
|
|
67
65
|
"STORAGE_BUCKET",
|
|
@@ -104,7 +102,7 @@ async function getFirebaseProjectParams(projectId, emulatorMode = false) {
|
|
|
104
102
|
projectNumber = await (0, getProjectNumber_1.getProjectNumber)({ projectId });
|
|
105
103
|
}
|
|
106
104
|
catch (err) {
|
|
107
|
-
(0,
|
|
105
|
+
(0, utils_1.logLabeledError)("extensions", `Unable to look up project number for ${projectId}.\n` +
|
|
108
106
|
" If this is a real project, ensure that you are logged in and have access to it.\n" +
|
|
109
107
|
" If this is a fake project, please use a project ID starting with 'demo-' to skip production calls.\n" +
|
|
110
108
|
" Continuing with a fake project number - secrets and other features that require production access may behave unexpectedly.");
|
|
@@ -810,15 +808,6 @@ function displayReleaseNotes(args) {
|
|
|
810
808
|
logger_1.logger.info(message);
|
|
811
809
|
}
|
|
812
810
|
exports.displayReleaseNotes = displayReleaseNotes;
|
|
813
|
-
async function promptForOfficialExtension(message) {
|
|
814
|
-
const officialExts = await (0, resolveSource_1.getExtensionRegistry)(true);
|
|
815
|
-
return await (0, prompt_1.select)({
|
|
816
|
-
message,
|
|
817
|
-
choices: (0, utils_1.convertOfficialExtensionsToList)(officialExts),
|
|
818
|
-
pageSize: Object.keys(officialExts).length,
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
exports.promptForOfficialExtension = promptForOfficialExtension;
|
|
822
811
|
async function promptForRepeatInstance(projectName, extensionName) {
|
|
823
812
|
const message = `An extension with the ID '${clc.bold(extensionName)}' already exists in the project '${clc.bold(projectName)}'. What would you like to do?`;
|
|
824
813
|
return await (0, prompt_1.select)({
|
package/lib/extensions/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getResourceRuntime = exports.formatTimestamp = exports.getRandomString = exports.
|
|
3
|
+
exports.getResourceRuntime = exports.formatTimestamp = exports.getRandomString = exports.convertExtensionOptionToLabeledList = void 0;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
function convertExtensionOptionToLabeledList(options) {
|
|
6
6
|
return options.map((option) => {
|
|
@@ -12,17 +12,6 @@ function convertExtensionOptionToLabeledList(options) {
|
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
14
|
exports.convertExtensionOptionToLabeledList = convertExtensionOptionToLabeledList;
|
|
15
|
-
function convertOfficialExtensionsToList(officialExts) {
|
|
16
|
-
const l = Object.entries(officialExts).map(([key, entry]) => {
|
|
17
|
-
return {
|
|
18
|
-
checked: false,
|
|
19
|
-
value: `${entry.publisher}/${key}`,
|
|
20
|
-
};
|
|
21
|
-
});
|
|
22
|
-
l.sort((a, b) => a.value.localeCompare(b.value));
|
|
23
|
-
return l;
|
|
24
|
-
}
|
|
25
|
-
exports.convertOfficialExtensionsToList = convertOfficialExtensionsToList;
|
|
26
15
|
function getRandomString(length) {
|
|
27
16
|
const SUFFIX_CHAR_SET = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
28
17
|
let result = "";
|
|
@@ -8,6 +8,19 @@ const QUERY_SCOPE_SEQUENCE = [
|
|
|
8
8
|
API.QueryScope.COLLECTION,
|
|
9
9
|
undefined,
|
|
10
10
|
];
|
|
11
|
+
const API_SCOPE_SEQUENCE = [
|
|
12
|
+
API.ApiScope.ANY_API,
|
|
13
|
+
API.ApiScope.DATASTORE_MODE_API,
|
|
14
|
+
API.ApiScope.MONGODB_COMPATIBLE_API,
|
|
15
|
+
undefined,
|
|
16
|
+
];
|
|
17
|
+
const DENSITY_SEQUENCE = [
|
|
18
|
+
API.Density.DENSITY_UNSPECIFIED,
|
|
19
|
+
API.Density.SPARSE_ALL,
|
|
20
|
+
API.Density.SPARSE_ANY,
|
|
21
|
+
API.Density.DENSE,
|
|
22
|
+
undefined,
|
|
23
|
+
];
|
|
11
24
|
const ORDER_SEQUENCE = [API.Order.ASCENDING, API.Order.DESCENDING, undefined];
|
|
12
25
|
const ARRAY_CONFIG_SEQUENCE = [API.ArrayConfig.CONTAINS, undefined];
|
|
13
26
|
function compareSpecIndex(a, b) {
|
|
@@ -17,7 +30,23 @@ function compareSpecIndex(a, b) {
|
|
|
17
30
|
if (a.queryScope !== b.queryScope) {
|
|
18
31
|
return compareQueryScope(a.queryScope, b.queryScope);
|
|
19
32
|
}
|
|
20
|
-
|
|
33
|
+
let cmp = compareArrays(a.fields, b.fields, compareIndexField);
|
|
34
|
+
if (cmp !== 0) {
|
|
35
|
+
return cmp;
|
|
36
|
+
}
|
|
37
|
+
cmp = compareApiScope(a.apiScope, b.apiScope);
|
|
38
|
+
if (cmp !== 0) {
|
|
39
|
+
return cmp;
|
|
40
|
+
}
|
|
41
|
+
cmp = compareDensity(a.density, b.density);
|
|
42
|
+
if (cmp !== 0) {
|
|
43
|
+
return cmp;
|
|
44
|
+
}
|
|
45
|
+
cmp = compareBoolean(a.multikey, b.multikey);
|
|
46
|
+
if (cmp !== 0) {
|
|
47
|
+
return cmp;
|
|
48
|
+
}
|
|
49
|
+
return compareBoolean(a.unique, b.unique);
|
|
21
50
|
}
|
|
22
51
|
exports.compareSpecIndex = compareSpecIndex;
|
|
23
52
|
function compareApiIndex(a, b) {
|
|
@@ -31,7 +60,23 @@ function compareApiIndex(a, b) {
|
|
|
31
60
|
if (a.queryScope !== b.queryScope) {
|
|
32
61
|
return compareQueryScope(a.queryScope, b.queryScope);
|
|
33
62
|
}
|
|
34
|
-
|
|
63
|
+
let cmp = compareArrays(a.fields, b.fields, compareIndexField);
|
|
64
|
+
if (cmp !== 0) {
|
|
65
|
+
return cmp;
|
|
66
|
+
}
|
|
67
|
+
cmp = compareApiScope(a.apiScope, b.apiScope);
|
|
68
|
+
if (cmp !== 0) {
|
|
69
|
+
return cmp;
|
|
70
|
+
}
|
|
71
|
+
cmp = compareDensity(a.density, b.density);
|
|
72
|
+
if (cmp !== 0) {
|
|
73
|
+
return cmp;
|
|
74
|
+
}
|
|
75
|
+
cmp = compareBoolean(a.multikey, b.multikey);
|
|
76
|
+
if (cmp !== 0) {
|
|
77
|
+
return cmp;
|
|
78
|
+
}
|
|
79
|
+
return compareBoolean(a.unique, b.unique);
|
|
35
80
|
}
|
|
36
81
|
exports.compareApiIndex = compareApiIndex;
|
|
37
82
|
function compareApiDatabase(a, b) {
|
|
@@ -115,14 +160,62 @@ function compareFieldIndex(a, b) {
|
|
|
115
160
|
if (a.arrayConfig !== b.arrayConfig) {
|
|
116
161
|
return compareArrayConfig(a.arrayConfig, b.arrayConfig);
|
|
117
162
|
}
|
|
118
|
-
|
|
163
|
+
let cmp = compareApiScope(a.apiScope, b.apiScope);
|
|
164
|
+
if (cmp !== 0) {
|
|
165
|
+
return cmp;
|
|
166
|
+
}
|
|
167
|
+
cmp = compareDensity(a.density, b.density);
|
|
168
|
+
if (cmp !== 0) {
|
|
169
|
+
return cmp;
|
|
170
|
+
}
|
|
171
|
+
cmp = compareBoolean(a.multikey, b.multikey);
|
|
172
|
+
if (cmp !== 0) {
|
|
173
|
+
return cmp;
|
|
174
|
+
}
|
|
175
|
+
return compareBoolean(a.unique, b.unique);
|
|
119
176
|
}
|
|
120
177
|
function compareQueryScope(a, b) {
|
|
121
178
|
return QUERY_SCOPE_SEQUENCE.indexOf(a) - QUERY_SCOPE_SEQUENCE.indexOf(b);
|
|
122
179
|
}
|
|
180
|
+
function compareApiScope(a, b) {
|
|
181
|
+
if (a === b) {
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
if (a === undefined) {
|
|
185
|
+
return -1;
|
|
186
|
+
}
|
|
187
|
+
if (b === undefined) {
|
|
188
|
+
return 1;
|
|
189
|
+
}
|
|
190
|
+
return API_SCOPE_SEQUENCE.indexOf(a) - API_SCOPE_SEQUENCE.indexOf(b);
|
|
191
|
+
}
|
|
192
|
+
function compareDensity(a, b) {
|
|
193
|
+
if (a === b) {
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
if (a === undefined) {
|
|
197
|
+
return -1;
|
|
198
|
+
}
|
|
199
|
+
if (b === undefined) {
|
|
200
|
+
return 1;
|
|
201
|
+
}
|
|
202
|
+
return DENSITY_SEQUENCE.indexOf(a) - DENSITY_SEQUENCE.indexOf(b);
|
|
203
|
+
}
|
|
123
204
|
function compareOrder(a, b) {
|
|
124
205
|
return ORDER_SEQUENCE.indexOf(a) - ORDER_SEQUENCE.indexOf(b);
|
|
125
206
|
}
|
|
207
|
+
function compareBoolean(a, b) {
|
|
208
|
+
if (a === b) {
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
if (a === undefined) {
|
|
212
|
+
return -1;
|
|
213
|
+
}
|
|
214
|
+
if (b === undefined) {
|
|
215
|
+
return 1;
|
|
216
|
+
}
|
|
217
|
+
return Number(a) - Number(b);
|
|
218
|
+
}
|
|
126
219
|
function compareArrayConfig(a, b) {
|
|
127
220
|
return ARRAY_CONFIG_SEQUENCE.indexOf(a) - ARRAY_CONFIG_SEQUENCE.indexOf(b);
|
|
128
221
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RecurrenceType = exports.DatabaseEdition = exports.PointInTimeRecoveryEnablement = exports.PointInTimeRecoveryEnablementOption = exports.DatabaseDeleteProtectionState = exports.DatabaseDeleteProtectionStateOption = exports.DatabaseType = exports.StateTtl = exports.State = exports.ArrayConfig = exports.Order = exports.QueryScope = exports.Mode = void 0;
|
|
3
|
+
exports.RecurrenceType = exports.DatabaseEdition = exports.PointInTimeRecoveryEnablement = exports.PointInTimeRecoveryEnablementOption = exports.DatabaseDeleteProtectionState = exports.DatabaseDeleteProtectionStateOption = exports.DatabaseType = exports.StateTtl = exports.State = exports.ArrayConfig = exports.Order = exports.Density = exports.ApiScope = exports.QueryScope = exports.Mode = void 0;
|
|
4
4
|
var Mode;
|
|
5
5
|
(function (Mode) {
|
|
6
6
|
Mode["ASCENDING"] = "ASCENDING";
|
|
@@ -12,6 +12,19 @@ var QueryScope;
|
|
|
12
12
|
QueryScope["COLLECTION"] = "COLLECTION";
|
|
13
13
|
QueryScope["COLLECTION_GROUP"] = "COLLECTION_GROUP";
|
|
14
14
|
})(QueryScope = exports.QueryScope || (exports.QueryScope = {}));
|
|
15
|
+
var ApiScope;
|
|
16
|
+
(function (ApiScope) {
|
|
17
|
+
ApiScope["ANY_API"] = "ANY_API";
|
|
18
|
+
ApiScope["DATASTORE_MODE_API"] = "DATASTORE_MODE_API";
|
|
19
|
+
ApiScope["MONGODB_COMPATIBLE_API"] = "MONGODB_COMPATIBLE_API";
|
|
20
|
+
})(ApiScope = exports.ApiScope || (exports.ApiScope = {}));
|
|
21
|
+
var Density;
|
|
22
|
+
(function (Density) {
|
|
23
|
+
Density["DENSITY_UNSPECIFIED"] = "DENSITY_UNSPECIFIED";
|
|
24
|
+
Density["SPARSE_ALL"] = "SPARSE_ALL";
|
|
25
|
+
Density["SPARSE_ANY"] = "SPARSE_ANY";
|
|
26
|
+
Density["DENSE"] = "DENSE";
|
|
27
|
+
})(Density = exports.Density || (exports.Density = {}));
|
|
15
28
|
var Order;
|
|
16
29
|
(function (Order) {
|
|
17
30
|
Order["ASCENDING"] = "ASCENDING";
|
package/lib/firestore/api.js
CHANGED
|
@@ -6,6 +6,7 @@ const logger_1 = require("../logger");
|
|
|
6
6
|
const utils = require("../utils");
|
|
7
7
|
const validator = require("./validator");
|
|
8
8
|
const types = require("./api-types");
|
|
9
|
+
const api_types_1 = require("./api-types");
|
|
9
10
|
const sort = require("./api-sort");
|
|
10
11
|
const util = require("./util");
|
|
11
12
|
const prompt_1 = require("../prompt");
|
|
@@ -13,6 +14,7 @@ const api_1 = require("../api");
|
|
|
13
14
|
const error_1 = require("../error");
|
|
14
15
|
const apiv2_1 = require("../apiv2");
|
|
15
16
|
const pretty_print_1 = require("./pretty-print");
|
|
17
|
+
const functional_1 = require("../functional");
|
|
16
18
|
class FirestoreApi {
|
|
17
19
|
constructor() {
|
|
18
20
|
this.apiClient = new apiv2_1.Client({ urlPrefix: (0, api_1.firestoreOrigin)(), apiVersion: "v1" });
|
|
@@ -33,6 +35,7 @@ class FirestoreApi {
|
|
|
33
35
|
});
|
|
34
36
|
}
|
|
35
37
|
async deploy(options, indexes, fieldOverrides, databaseId = "(default)") {
|
|
38
|
+
var _a;
|
|
36
39
|
const spec = this.upgradeOldSpec({
|
|
37
40
|
indexes,
|
|
38
41
|
fieldOverrides,
|
|
@@ -42,8 +45,10 @@ class FirestoreApi {
|
|
|
42
45
|
const fieldOverridesToDeploy = spec.fieldOverrides;
|
|
43
46
|
const existingIndexes = await this.listIndexes(options.project, databaseId);
|
|
44
47
|
const existingFieldOverrides = await this.listFieldOverrides(options.project, databaseId);
|
|
48
|
+
const database = await this.getDatabase(options.project, databaseId);
|
|
49
|
+
const edition = (_a = database.databaseEdition) !== null && _a !== void 0 ? _a : api_types_1.DatabaseEdition.STANDARD;
|
|
45
50
|
const indexesToDelete = existingIndexes.filter((index) => {
|
|
46
|
-
return !indexesToDeploy.some((spec) => this.indexMatchesSpec(index, spec));
|
|
51
|
+
return !indexesToDeploy.some((spec) => this.indexMatchesSpec(index, spec, edition));
|
|
47
52
|
});
|
|
48
53
|
const fieldOverridesToDelete = existingFieldOverrides.filter((field) => {
|
|
49
54
|
return !fieldOverridesToDeploy.some((spec) => {
|
|
@@ -79,7 +84,7 @@ class FirestoreApi {
|
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
86
|
for (const index of indexesToDeploy) {
|
|
82
|
-
const exists = existingIndexes.some((x) => this.indexMatchesSpec(x, index));
|
|
87
|
+
const exists = existingIndexes.some((x) => this.indexMatchesSpec(x, index, edition));
|
|
83
88
|
if (exists) {
|
|
84
89
|
logger_1.logger.debug(`Skipping existing index: ${JSON.stringify(index)}`);
|
|
85
90
|
}
|
|
@@ -160,6 +165,10 @@ class FirestoreApi {
|
|
|
160
165
|
collectionGroup: util.parseIndexName(index.name).collectionGroupId,
|
|
161
166
|
queryScope: index.queryScope,
|
|
162
167
|
fields: index.fields,
|
|
168
|
+
apiScope: index.apiScope,
|
|
169
|
+
density: index.density,
|
|
170
|
+
multikey: index.multikey,
|
|
171
|
+
unique: index.unique,
|
|
163
172
|
};
|
|
164
173
|
});
|
|
165
174
|
if (!fields) {
|
|
@@ -179,6 +188,10 @@ class FirestoreApi {
|
|
|
179
188
|
order: firstField.order,
|
|
180
189
|
arrayConfig: firstField.arrayConfig,
|
|
181
190
|
queryScope: index.queryScope,
|
|
191
|
+
apiScope: index.apiScope,
|
|
192
|
+
density: index.density,
|
|
193
|
+
multikey: index.multikey,
|
|
194
|
+
unique: index.unique,
|
|
182
195
|
};
|
|
183
196
|
}),
|
|
184
197
|
};
|
|
@@ -205,6 +218,19 @@ class FirestoreApi {
|
|
|
205
218
|
validator.assertHas(index, "collectionGroup");
|
|
206
219
|
validator.assertHas(index, "queryScope");
|
|
207
220
|
validator.assertEnum(index, "queryScope", Object.keys(types.QueryScope));
|
|
221
|
+
if (index.apiScope) {
|
|
222
|
+
validator.assertEnum(index, "apiScope", Object.keys(types.ApiScope));
|
|
223
|
+
}
|
|
224
|
+
if (index.density) {
|
|
225
|
+
validator.assertEnum(index, "density", Object.keys(types.Density));
|
|
226
|
+
}
|
|
227
|
+
if (index.multikey) {
|
|
228
|
+
validator.assertType("multikey", index.multikey, "boolean");
|
|
229
|
+
}
|
|
230
|
+
if (index.unique !== undefined) {
|
|
231
|
+
validator.assertType("unique", index.unique, "boolean");
|
|
232
|
+
throw new error_1.FirebaseError("The `unique` index configuration is not supported yet.");
|
|
233
|
+
}
|
|
208
234
|
validator.assertHas(index, "fields");
|
|
209
235
|
index.fields.forEach((field) => {
|
|
210
236
|
validator.assertHas(field, "fieldPath");
|
|
@@ -239,6 +265,18 @@ class FirestoreApi {
|
|
|
239
265
|
if (index.queryScope) {
|
|
240
266
|
validator.assertEnum(index, "queryScope", Object.keys(types.QueryScope));
|
|
241
267
|
}
|
|
268
|
+
if (index.apiScope) {
|
|
269
|
+
validator.assertEnum(index, "apiScope", Object.keys(types.ApiScope));
|
|
270
|
+
}
|
|
271
|
+
if (index.density) {
|
|
272
|
+
validator.assertEnum(index, "density", Object.keys(types.Density));
|
|
273
|
+
}
|
|
274
|
+
if (index.multikey) {
|
|
275
|
+
validator.assertType("multikey", index.multikey, "boolean");
|
|
276
|
+
}
|
|
277
|
+
if (index.unique) {
|
|
278
|
+
validator.assertType("unique", index.unique, "boolean");
|
|
279
|
+
}
|
|
242
280
|
});
|
|
243
281
|
}
|
|
244
282
|
async patchField(project, spec, databaseId = "(default)") {
|
|
@@ -246,6 +284,10 @@ class FirestoreApi {
|
|
|
246
284
|
const indexes = spec.indexes.map((index) => {
|
|
247
285
|
return {
|
|
248
286
|
queryScope: index.queryScope,
|
|
287
|
+
apiScope: index.apiScope,
|
|
288
|
+
density: index.density,
|
|
289
|
+
multikey: index.multikey,
|
|
290
|
+
unique: index.unique,
|
|
249
291
|
fields: [
|
|
250
292
|
{
|
|
251
293
|
fieldPath: spec.fieldPath,
|
|
@@ -282,13 +324,28 @@ class FirestoreApi {
|
|
|
282
324
|
return this.apiClient.post(url, {
|
|
283
325
|
fields: index.fields,
|
|
284
326
|
queryScope: index.queryScope,
|
|
327
|
+
apiScope: index.apiScope,
|
|
328
|
+
density: index.density,
|
|
329
|
+
multikey: index.multikey,
|
|
330
|
+
unique: index.unique,
|
|
285
331
|
});
|
|
286
332
|
}
|
|
287
333
|
deleteIndex(index) {
|
|
288
334
|
const url = index.name;
|
|
289
335
|
return this.apiClient.delete(`/${url}`);
|
|
290
336
|
}
|
|
291
|
-
|
|
337
|
+
optionalApiScopeMatches(lhs, rhs) {
|
|
338
|
+
return (0, functional_1.optionalValueMatches)(lhs, rhs, types.ApiScope.ANY_API);
|
|
339
|
+
}
|
|
340
|
+
optionalDensityMatches(lhs, rhs, edition) {
|
|
341
|
+
const defaultValue = edition === api_types_1.DatabaseEdition.STANDARD ? types.Density.SPARSE_ALL : types.Density.DENSE;
|
|
342
|
+
return (0, functional_1.optionalValueMatches)(lhs, rhs, defaultValue);
|
|
343
|
+
}
|
|
344
|
+
optionalMultikeyMatches(lhs, rhs) {
|
|
345
|
+
const defaultValue = false;
|
|
346
|
+
return (0, functional_1.optionalValueMatches)(lhs, rhs, defaultValue);
|
|
347
|
+
}
|
|
348
|
+
indexMatchesSpec(index, spec, edition) {
|
|
292
349
|
const collection = util.parseIndexName(index.name).collectionGroupId;
|
|
293
350
|
if (collection !== spec.collectionGroup) {
|
|
294
351
|
return false;
|
|
@@ -296,6 +353,15 @@ class FirestoreApi {
|
|
|
296
353
|
if (index.queryScope !== spec.queryScope) {
|
|
297
354
|
return false;
|
|
298
355
|
}
|
|
356
|
+
if (!this.optionalApiScopeMatches(index.apiScope, spec.apiScope)) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
if (!this.optionalDensityMatches(index.density, spec.density, edition)) {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
if (!this.optionalMultikeyMatches(index.multikey, spec.multikey)) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
299
365
|
if (index.fields.length !== spec.fields.length) {
|
|
300
366
|
return false;
|
|
301
367
|
}
|
|
@@ -312,6 +378,9 @@ class FirestoreApi {
|
|
|
312
378
|
if (iField.arrayConfig !== sField.arrayConfig) {
|
|
313
379
|
return false;
|
|
314
380
|
}
|
|
381
|
+
if (!utils.deepEqual(iField.vectorConfig, sField.vectorConfig)) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
315
384
|
i++;
|
|
316
385
|
}
|
|
317
386
|
return true;
|
|
@@ -368,8 +437,19 @@ class FirestoreApi {
|
|
|
368
437
|
const i = {
|
|
369
438
|
collectionGroup: index.collectionGroup || index.collectionId,
|
|
370
439
|
queryScope: index.queryScope || types.QueryScope.COLLECTION,
|
|
371
|
-
fields: [],
|
|
372
440
|
};
|
|
441
|
+
if (index.apiScope) {
|
|
442
|
+
i.apiScope = index.apiScope;
|
|
443
|
+
}
|
|
444
|
+
if (index.density) {
|
|
445
|
+
i.density = index.density;
|
|
446
|
+
}
|
|
447
|
+
if (index.multikey !== undefined) {
|
|
448
|
+
i.multikey = index.multikey;
|
|
449
|
+
}
|
|
450
|
+
if (index.unique !== undefined) {
|
|
451
|
+
i.unique = index.unique;
|
|
452
|
+
}
|
|
373
453
|
if (index.fields) {
|
|
374
454
|
i.fields = index.fields.map((field) => {
|
|
375
455
|
const f = {
|
|
@@ -429,6 +509,7 @@ class FirestoreApi {
|
|
|
429
509
|
const payload = {
|
|
430
510
|
locationId: req.locationId,
|
|
431
511
|
type: req.type,
|
|
512
|
+
databaseEdition: req.databaseEdition,
|
|
432
513
|
deleteProtectionState: req.deleteProtectionState,
|
|
433
514
|
pointInTimeRecoveryEnablement: req.pointInTimeRecoveryEnablement,
|
|
434
515
|
cmekConfig: req.cmekConfig,
|
|
@@ -177,6 +177,13 @@ class PrettyPrint {
|
|
|
177
177
|
}
|
|
178
178
|
result += `(${field.fieldPath},${configString}) `;
|
|
179
179
|
});
|
|
180
|
+
result += " -- ";
|
|
181
|
+
if (index.density !== undefined) {
|
|
182
|
+
result += clc.cyan(`Density:${index.density} `);
|
|
183
|
+
}
|
|
184
|
+
if (index.multikey !== undefined) {
|
|
185
|
+
result += clc.cyan(`Multikey:${index.multikey ? "YES" : "NO"}`);
|
|
186
|
+
}
|
|
180
187
|
return result;
|
|
181
188
|
}
|
|
182
189
|
prettyBackupString(backup) {
|
|
@@ -26,7 +26,7 @@ exports.assertHasOneOf = assertHasOneOf;
|
|
|
26
26
|
function assertEnum(obj, prop, valid) {
|
|
27
27
|
const objString = clc.cyan(JSON.stringify(obj));
|
|
28
28
|
if (valid.indexOf(obj[prop]) < 0) {
|
|
29
|
-
throw new error_1.FirebaseError(`Field "${prop}" must be one of
|
|
29
|
+
throw new error_1.FirebaseError(`Field "${prop}" must be one of ${valid.join(", ")}: ${objString}`);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
exports.assertEnum = assertEnum;
|