firebase-tools 11.17.0 → 11.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/api.js +3 -2
- package/lib/commands/index.js +5 -0
- package/lib/commands/internaltesting-functions-discover.js +25 -0
- package/lib/deploy/extensions/prepare.js +6 -1
- package/lib/deploy/extensions/v2FunctionHelper.js +53 -0
- package/lib/deploy/functions/build.js +17 -2
- package/lib/deploy/functions/cel.js +90 -13
- package/lib/deploy/functions/params.js +141 -6
- package/lib/deploy/functions/prepare.js +40 -25
- package/lib/deploy/functions/release/fabricator.js +27 -1
- package/lib/deploy/functions/runtimes/discovery/parsing.js +7 -1
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +1 -1
- package/lib/deploy/functions/runtimes/index.js +2 -1
- package/lib/deploy/functions/runtimes/node/index.js +2 -2
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +1 -0
- package/lib/deploy/functions/runtimes/node/versioning.js +30 -14
- package/lib/emulator/commandUtils.js +2 -1
- package/lib/emulator/downloadableEmulators.js +3 -3
- package/lib/emulator/env.js +29 -27
- package/lib/emulator/extensions/validation.js +2 -0
- package/lib/emulator/extensionsEmulator.js +1 -1
- package/lib/emulator/functionsEmulator.js +44 -32
- package/lib/emulator/storage/rules/runtime.js +2 -2
- package/lib/emulator/workQueue.js +11 -6
- package/lib/experiments.js +6 -0
- package/lib/extensions/billingMigrationHelper.js +2 -1
- package/lib/extensions/displayExtensionInfo.js +2 -1
- package/lib/extensions/emulator/specHelper.js +4 -3
- package/lib/extensions/emulator/triggerHelper.js +64 -20
- package/lib/extensions/extensionsHelper.js +1 -4
- package/lib/extensions/types.js +2 -1
- package/lib/extensions/utils.js +14 -1
- package/lib/firestore/indexes-api.js +7 -1
- package/lib/firestore/indexes-sort.js +4 -0
- package/lib/firestore/indexes.js +31 -5
- package/lib/firestore/util.js +5 -1
- package/lib/firestore/validator.js +7 -1
- package/lib/frameworks/angular/index.js +3 -0
- package/lib/frameworks/index.js +7 -1
- package/lib/frameworks/next/constants.js +10 -0
- package/lib/frameworks/next/index.js +170 -127
- package/lib/frameworks/next/interfaces.js +2 -0
- package/lib/frameworks/next/utils.js +92 -0
- package/lib/frameworks/nuxt/index.js +3 -0
- package/lib/frameworks/utils.js +24 -0
- package/lib/frameworks/vite/index.js +4 -1
- package/lib/gcp/eventarc.js +42 -0
- package/lib/init/features/emulators.js +1 -1
- package/npm-shrinkwrap.json +2 -93
- package/package.json +1 -4
- package/schema/firebase-config.json +4 -2
package/lib/experiments.js
CHANGED
|
@@ -74,6 +74,12 @@ exports.ALL_EXPERIMENTS = experiments({
|
|
|
74
74
|
crossservicerules: {
|
|
75
75
|
shortDescription: "Allow Firebase Rules to reference resources in other services",
|
|
76
76
|
},
|
|
77
|
+
internaltesting: {
|
|
78
|
+
shortDescription: "Exposes Firebase CLI commands intended for internal testing purposes.",
|
|
79
|
+
fullDescription: "Exposes Firebase CLI commands intended for internal testing purposes. " +
|
|
80
|
+
"These commands are not meant for public consumption and may break or disappear " +
|
|
81
|
+
"without a notice.",
|
|
82
|
+
},
|
|
77
83
|
});
|
|
78
84
|
function isValidExperiment(name) {
|
|
79
85
|
return Object.keys(exports.ALL_EXPERIMENTS).includes(name);
|
|
@@ -7,6 +7,7 @@ const error_1 = require("../error");
|
|
|
7
7
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
8
8
|
const prompt_1 = require("../prompt");
|
|
9
9
|
const utils = require("../utils");
|
|
10
|
+
const utils_1 = require("./utils");
|
|
10
11
|
marked.setOptions({
|
|
11
12
|
renderer: new TerminalRenderer(),
|
|
12
13
|
});
|
|
@@ -34,7 +35,7 @@ function hasRuntime(spec, runtime) {
|
|
|
34
35
|
const specVersion = spec.specVersion || defaultSpecVersion;
|
|
35
36
|
const defaultRuntime = defaultRuntimes[specVersion];
|
|
36
37
|
const resources = spec.resources || [];
|
|
37
|
-
return resources.some((r) =>
|
|
38
|
+
return resources.some((r) => runtime === ((0, utils_1.getResourceRuntime)(r) || defaultRuntime));
|
|
38
39
|
}
|
|
39
40
|
function displayNode10UpdateBillingNotice(curSpec, newSpec) {
|
|
40
41
|
if (hasRuntime(curSpec, "nodejs8") && hasRuntime(newSpec, "nodejs10")) {
|
|
@@ -8,6 +8,7 @@ const utils = require("../utils");
|
|
|
8
8
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
9
9
|
const logger_1 = require("../logger");
|
|
10
10
|
const error_1 = require("../error");
|
|
11
|
+
const types_1 = require("./types");
|
|
11
12
|
const iam = require("../gcp/iam");
|
|
12
13
|
const secretsUtils_1 = require("./secretsUtils");
|
|
13
14
|
marked.setOptions({
|
|
@@ -80,7 +81,7 @@ function displayApis(apis) {
|
|
|
80
81
|
return "**APIs used by this Extension**:\n" + lines.join("\n");
|
|
81
82
|
}
|
|
82
83
|
function usesTasks(spec) {
|
|
83
|
-
return spec.resources.some((r) => { var _a; return ((_a = r.properties) === null || _a === void 0 ? void 0 : _a.taskQueueTrigger) !== undefined; });
|
|
84
|
+
return spec.resources.some((r) => { var _a; return r.type === types_1.FUNCTIONS_RESOURCE_TYPE && ((_a = r.properties) === null || _a === void 0 ? void 0 : _a.taskQueueTrigger) !== undefined; });
|
|
84
85
|
}
|
|
85
86
|
function impliedRoles(spec) {
|
|
86
87
|
var _a, _b, _c;
|
|
@@ -6,11 +6,13 @@ const path = require("path");
|
|
|
6
6
|
const fs = require("fs-extra");
|
|
7
7
|
const error_1 = require("../../error");
|
|
8
8
|
const extensionsHelper_1 = require("../extensionsHelper");
|
|
9
|
+
const utils_1 = require("../utils");
|
|
9
10
|
const functionsEmulatorUtils_1 = require("../../emulator/functionsEmulatorUtils");
|
|
10
11
|
const SPEC_FILE = "extension.yaml";
|
|
11
12
|
const POSTINSTALL_FILE = "POSTINSTALL.md";
|
|
12
13
|
const validFunctionTypes = [
|
|
13
14
|
"firebaseextensions.v1beta.function",
|
|
15
|
+
"firebaseextensions.v1beta.v2function",
|
|
14
16
|
"firebaseextensions.v1beta.scheduledFunction",
|
|
15
17
|
];
|
|
16
18
|
function wrappedSafeLoad(source) {
|
|
@@ -68,9 +70,8 @@ exports.getFunctionProperties = getFunctionProperties;
|
|
|
68
70
|
function getNodeVersion(resources) {
|
|
69
71
|
const invalidRuntimes = [];
|
|
70
72
|
const versions = resources.map((r) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const runtimeName = (_b = r.properties) === null || _b === void 0 ? void 0 : _b.runtime;
|
|
73
|
+
if ((0, utils_1.getResourceRuntime)(r)) {
|
|
74
|
+
const runtimeName = (0, utils_1.getResourceRuntime)(r);
|
|
74
75
|
const runtime = (0, functionsEmulatorUtils_1.parseRuntimeVersion)(runtimeName);
|
|
75
76
|
if (!runtime) {
|
|
76
77
|
invalidRuntimes.push(runtimeName);
|
|
@@ -4,30 +4,74 @@ exports.functionResourceToEmulatedTriggerDefintion = void 0;
|
|
|
4
4
|
const functionsEmulatorShared_1 = require("../../emulator/functionsEmulatorShared");
|
|
5
5
|
const emulatorLogger_1 = require("../../emulator/emulatorLogger");
|
|
6
6
|
const types_1 = require("../../emulator/types");
|
|
7
|
+
const types_2 = require("../../extensions/types");
|
|
7
8
|
const proto = require("../../gcp/proto");
|
|
9
|
+
const error_1 = require("../../error");
|
|
8
10
|
function functionResourceToEmulatedTriggerDefintion(resource) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
proto.convertIfPresent(etd, properties, "timeoutSeconds", "timeout", proto.secondsFromDuration);
|
|
16
|
-
proto.convertIfPresent(etd, properties, "regions", "location", (str) => [str]);
|
|
17
|
-
proto.copyIfPresent(etd, properties, "availableMemoryMb");
|
|
18
|
-
if (properties.httpsTrigger) {
|
|
19
|
-
etd.httpsTrigger = properties.httpsTrigger;
|
|
20
|
-
}
|
|
21
|
-
if (properties.eventTrigger) {
|
|
22
|
-
etd.eventTrigger = {
|
|
23
|
-
eventType: properties.eventTrigger.eventType,
|
|
24
|
-
resource: properties.eventTrigger.resource,
|
|
25
|
-
service: (0, functionsEmulatorShared_1.getServiceFromEventType)(properties.eventTrigger.eventType),
|
|
11
|
+
const resourceType = resource.type;
|
|
12
|
+
if (resource.type === types_2.FUNCTIONS_RESOURCE_TYPE) {
|
|
13
|
+
const etd = {
|
|
14
|
+
name: resource.name,
|
|
15
|
+
entryPoint: resource.name,
|
|
16
|
+
platform: "gcfv1",
|
|
26
17
|
};
|
|
18
|
+
const properties = resource.properties || {};
|
|
19
|
+
proto.convertIfPresent(etd, properties, "timeoutSeconds", "timeout", proto.secondsFromDuration);
|
|
20
|
+
proto.convertIfPresent(etd, properties, "regions", "location", (str) => [str]);
|
|
21
|
+
proto.copyIfPresent(etd, properties, "availableMemoryMb");
|
|
22
|
+
if (properties.httpsTrigger) {
|
|
23
|
+
etd.httpsTrigger = properties.httpsTrigger;
|
|
24
|
+
}
|
|
25
|
+
if (properties.eventTrigger) {
|
|
26
|
+
etd.eventTrigger = {
|
|
27
|
+
eventType: properties.eventTrigger.eventType,
|
|
28
|
+
resource: properties.eventTrigger.resource,
|
|
29
|
+
service: (0, functionsEmulatorShared_1.getServiceFromEventType)(properties.eventTrigger.eventType),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).log("WARN", `Function '${resource.name} is missing a trigger in extension.yaml. Please add one, as triggers defined in code are ignored.`);
|
|
34
|
+
}
|
|
35
|
+
return etd;
|
|
27
36
|
}
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
if (resource.type === types_2.FUNCTIONS_V2_RESOURCE_TYPE) {
|
|
38
|
+
const etd = {
|
|
39
|
+
name: resource.name,
|
|
40
|
+
entryPoint: resource.name,
|
|
41
|
+
platform: "gcfv2",
|
|
42
|
+
};
|
|
43
|
+
const properties = resource.properties || {};
|
|
44
|
+
proto.convertIfPresent(etd, properties, "regions", "location", (str) => [str]);
|
|
45
|
+
if (properties.serviceConfig) {
|
|
46
|
+
proto.copyIfPresent(etd, properties.serviceConfig, "timeoutSeconds");
|
|
47
|
+
proto.convertIfPresent(etd, properties.serviceConfig, "availableMemoryMb", "availableMemory", (mem) => parseInt(mem));
|
|
48
|
+
}
|
|
49
|
+
if (properties.eventTrigger) {
|
|
50
|
+
etd.eventTrigger = {
|
|
51
|
+
eventType: properties.eventTrigger.eventType,
|
|
52
|
+
service: (0, functionsEmulatorShared_1.getServiceFromEventType)(properties.eventTrigger.eventType),
|
|
53
|
+
};
|
|
54
|
+
proto.copyIfPresent(etd.eventTrigger, properties.eventTrigger, "channel");
|
|
55
|
+
if (properties.eventTrigger.eventFilters) {
|
|
56
|
+
const eventFilters = {};
|
|
57
|
+
const eventFilterPathPatterns = {};
|
|
58
|
+
for (const filter of properties.eventTrigger.eventFilters) {
|
|
59
|
+
if (filter.operator === undefined) {
|
|
60
|
+
eventFilters[filter.attribute] = filter.value;
|
|
61
|
+
}
|
|
62
|
+
else if (filter.operator === "match-path-pattern") {
|
|
63
|
+
eventFilterPathPatterns[filter.attribute] = filter.value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
etd.eventTrigger.eventFilters = eventFilters;
|
|
67
|
+
etd.eventTrigger.eventFilterPathPatterns = eventFilterPathPatterns;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).log("WARN", `Function '${resource.name} is missing a trigger in extension.yaml. Please add one, as triggers defined in code are ignored.`);
|
|
72
|
+
}
|
|
73
|
+
return etd;
|
|
30
74
|
}
|
|
31
|
-
|
|
75
|
+
throw new error_1.FirebaseError("Unexpected resource type " + resourceType);
|
|
32
76
|
}
|
|
33
77
|
exports.functionResourceToEmulatedTriggerDefintion = functionResourceToEmulatedTriggerDefintion;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.canonicalizeRefInput = exports.diagnoseAndFixProject = exports.confirm = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.publishExtensionVersionFromLocalSource = exports.incrementPrereleaseVersion = exports.ensureExtensionsApiEnabled = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.
|
|
3
|
+
exports.canonicalizeRefInput = exports.diagnoseAndFixProject = exports.confirm = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.publishExtensionVersionFromLocalSource = exports.incrementPrereleaseVersion = exports.ensureExtensionsApiEnabled = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.AUTOPOULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const ora = require("ora");
|
|
6
6
|
const semver = require("semver");
|
|
@@ -66,9 +66,6 @@ exports.AUTOPOULATED_PARAM_PLACEHOLDERS = {
|
|
|
66
66
|
DATABASE_INSTANCE: "project-id-default-rtdb",
|
|
67
67
|
DATABASE_URL: "https://project-id-default-rtdb.firebaseio.com",
|
|
68
68
|
};
|
|
69
|
-
exports.resourceTypeToNiceName = {
|
|
70
|
-
"firebaseextensions.v1beta.function": "Cloud Function",
|
|
71
|
-
};
|
|
72
69
|
function getDBInstanceFromURL(databaseUrl = "") {
|
|
73
70
|
const instanceRegex = new RegExp("(?:https://)(.*)(?:.firebaseio.com)");
|
|
74
71
|
const matches = instanceRegex.exec(databaseUrl);
|
package/lib/extensions/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ParamType = exports.FUNCTIONS_RESOURCE_TYPE = exports.Visibility = exports.RegistryLaunchStage = void 0;
|
|
3
|
+
exports.ParamType = exports.FUNCTIONS_V2_RESOURCE_TYPE = exports.FUNCTIONS_RESOURCE_TYPE = exports.Visibility = exports.RegistryLaunchStage = void 0;
|
|
4
4
|
var RegistryLaunchStage;
|
|
5
5
|
(function (RegistryLaunchStage) {
|
|
6
6
|
RegistryLaunchStage["EXPERIMENTAL"] = "EXPERIMENTAL";
|
|
@@ -15,6 +15,7 @@ var Visibility;
|
|
|
15
15
|
Visibility["PUBLIC"] = "public";
|
|
16
16
|
})(Visibility = exports.Visibility || (exports.Visibility = {}));
|
|
17
17
|
exports.FUNCTIONS_RESOURCE_TYPE = "firebaseextensions.v1beta.function";
|
|
18
|
+
exports.FUNCTIONS_V2_RESOURCE_TYPE = "firebaseextensions.v1beta.v2function";
|
|
18
19
|
var ParamType;
|
|
19
20
|
(function (ParamType) {
|
|
20
21
|
ParamType["STRING"] = "STRING";
|
package/lib/extensions/utils.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatTimestamp = exports.getRandomString = exports.convertOfficialExtensionsToList = exports.convertExtensionOptionToLabeledList = exports.onceWithJoin = void 0;
|
|
3
|
+
exports.getResourceRuntime = exports.formatTimestamp = exports.getRandomString = exports.convertOfficialExtensionsToList = exports.convertExtensionOptionToLabeledList = exports.onceWithJoin = void 0;
|
|
4
4
|
const prompt_1 = require("../prompt");
|
|
5
|
+
const types_1 = require("./types");
|
|
5
6
|
async function onceWithJoin(question) {
|
|
6
7
|
const response = await (0, prompt_1.promptOnce)(question);
|
|
7
8
|
if (Array.isArray(response)) {
|
|
@@ -48,3 +49,15 @@ function formatTimestamp(timestamp) {
|
|
|
48
49
|
return withoutMs.replace("T", " ");
|
|
49
50
|
}
|
|
50
51
|
exports.formatTimestamp = formatTimestamp;
|
|
52
|
+
function getResourceRuntime(resource) {
|
|
53
|
+
var _a, _b, _c;
|
|
54
|
+
switch (resource.type) {
|
|
55
|
+
case types_1.FUNCTIONS_RESOURCE_TYPE:
|
|
56
|
+
return (_a = resource.properties) === null || _a === void 0 ? void 0 : _a.runtime;
|
|
57
|
+
case types_1.FUNCTIONS_V2_RESOURCE_TYPE:
|
|
58
|
+
return (_c = (_b = resource.properties) === null || _b === void 0 ? void 0 : _b.buildConfig) === null || _c === void 0 ? void 0 : _c.runtime;
|
|
59
|
+
default:
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.getResourceRuntime = getResourceRuntime;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.State = exports.ArrayConfig = exports.Order = exports.QueryScope = exports.Mode = void 0;
|
|
3
|
+
exports.StateTtl = exports.State = exports.ArrayConfig = exports.Order = exports.QueryScope = exports.Mode = void 0;
|
|
4
4
|
var Mode;
|
|
5
5
|
(function (Mode) {
|
|
6
6
|
Mode["ASCENDING"] = "ASCENDING";
|
|
@@ -27,3 +27,9 @@ var State;
|
|
|
27
27
|
State["READY"] = "READY";
|
|
28
28
|
State["NEEDS_REPAIR"] = "NEEDS_REPAIR";
|
|
29
29
|
})(State = exports.State || (exports.State = {}));
|
|
30
|
+
var StateTtl;
|
|
31
|
+
(function (StateTtl) {
|
|
32
|
+
StateTtl["CREATING"] = "CREATING";
|
|
33
|
+
StateTtl["ACTIVE"] = "ACTIVE";
|
|
34
|
+
StateTtl["NEEDS_REPAIR"] = "NEEDS_REPAIR";
|
|
35
|
+
})(StateTtl = exports.StateTtl || (exports.StateTtl = {}));
|
|
@@ -50,6 +50,10 @@ function compareFieldOverride(a, b) {
|
|
|
50
50
|
if (a.collectionGroup !== b.collectionGroup) {
|
|
51
51
|
return a.collectionGroup.localeCompare(b.collectionGroup);
|
|
52
52
|
}
|
|
53
|
+
const compareTtl = Number(!!a.ttl) - Number(!!b.ttl);
|
|
54
|
+
if (compareTtl) {
|
|
55
|
+
return compareTtl;
|
|
56
|
+
}
|
|
53
57
|
if (a.fieldPath !== b.fieldPath) {
|
|
54
58
|
return a.fieldPath.localeCompare(b.fieldPath);
|
|
55
59
|
}
|
package/lib/firestore/indexes.js
CHANGED
|
@@ -98,7 +98,8 @@ class FirestoreIndexes {
|
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
const sortedFieldOverridesToDeploy = fieldOverridesToDeploy.sort(sort.compareFieldOverride);
|
|
102
|
+
for (const field of sortedFieldOverridesToDeploy) {
|
|
102
103
|
const exists = existingFieldOverrides.some((x) => this.fieldMatchesSpec(x, field));
|
|
103
104
|
if (exists) {
|
|
104
105
|
logger_1.logger.debug(`Skipping existing field override: ${JSON.stringify(field)}`);
|
|
@@ -136,7 +137,7 @@ class FirestoreIndexes {
|
|
|
136
137
|
}
|
|
137
138
|
async listFieldOverrides(project) {
|
|
138
139
|
const parent = `projects/${project}/databases/(default)/collectionGroups/-`;
|
|
139
|
-
const url = `/${parent}/fields?filter=indexConfig.usesAncestorConfig=false
|
|
140
|
+
const url = `/${parent}/fields?filter=indexConfig.usesAncestorConfig=false OR ttlConfig:*`;
|
|
140
141
|
const res = await this.apiClient.get(url);
|
|
141
142
|
const fields = res.body.fields;
|
|
142
143
|
if (!fields) {
|
|
@@ -164,6 +165,7 @@ class FirestoreIndexes {
|
|
|
164
165
|
return {
|
|
165
166
|
collectionGroup: parsedName.collectionGroupId,
|
|
166
167
|
fieldPath: parsedName.fieldPath,
|
|
168
|
+
ttl: !!field.ttlConfig,
|
|
167
169
|
indexes: fieldIndexes.map((index) => {
|
|
168
170
|
const firstField = index.fields[0];
|
|
169
171
|
return {
|
|
@@ -232,6 +234,9 @@ class FirestoreIndexes {
|
|
|
232
234
|
validator.assertHas(field, "collectionGroup");
|
|
233
235
|
validator.assertHas(field, "fieldPath");
|
|
234
236
|
validator.assertHas(field, "indexes");
|
|
237
|
+
if (typeof field.ttl !== "undefined") {
|
|
238
|
+
validator.assertType("ttl", field.ttl, "boolean");
|
|
239
|
+
}
|
|
235
240
|
field.indexes.forEach((index) => {
|
|
236
241
|
validator.assertHasOneOf(index, ["arrayConfig", "order"]);
|
|
237
242
|
if (index.arrayConfig) {
|
|
@@ -259,17 +264,27 @@ class FirestoreIndexes {
|
|
|
259
264
|
],
|
|
260
265
|
};
|
|
261
266
|
});
|
|
262
|
-
|
|
267
|
+
let data = {
|
|
263
268
|
indexConfig: {
|
|
264
269
|
indexes,
|
|
265
270
|
},
|
|
266
271
|
};
|
|
267
|
-
|
|
272
|
+
if (spec.ttl) {
|
|
273
|
+
data = Object.assign(data, {
|
|
274
|
+
ttlConfig: {},
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
if (typeof spec.ttl !== "undefined") {
|
|
278
|
+
await this.apiClient.patch(url, data);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
await this.apiClient.patch(url, data, { queryParams: { updateMask: "indexConfig" } });
|
|
282
|
+
}
|
|
268
283
|
}
|
|
269
284
|
deleteField(field) {
|
|
270
285
|
const url = field.name;
|
|
271
286
|
const data = {};
|
|
272
|
-
return this.apiClient.patch(`/${url}`, data
|
|
287
|
+
return this.apiClient.patch(`/${url}`, data);
|
|
273
288
|
}
|
|
274
289
|
createIndex(project, index) {
|
|
275
290
|
const url = `/projects/${project}/databases/(default)/collectionGroups/${index.collectionGroup}/indexes`;
|
|
@@ -318,6 +333,13 @@ class FirestoreIndexes {
|
|
|
318
333
|
if (parsedName.fieldPath !== spec.fieldPath) {
|
|
319
334
|
return false;
|
|
320
335
|
}
|
|
336
|
+
if (typeof spec.ttl !== "undefined" && util.booleanXOR(!!field.ttlConfig, spec.ttl)) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
else if (!!field.ttlConfig && typeof spec.ttl === "undefined") {
|
|
340
|
+
utils.logLabeledBullet("firestore", `there are TTL field overrides for collection ${spec.collectionGroup} defined in your project that are not present in your ` +
|
|
341
|
+
"firestore indexes file. The TTL policy won't be deleted since is not specified as false.");
|
|
342
|
+
}
|
|
321
343
|
const fieldIndexes = field.indexConfig.indexes || [];
|
|
322
344
|
if (fieldIndexes.length !== spec.indexes.length) {
|
|
323
345
|
return false;
|
|
@@ -427,6 +449,10 @@ class FirestoreIndexes {
|
|
|
427
449
|
else {
|
|
428
450
|
result += " (no indexes)";
|
|
429
451
|
}
|
|
452
|
+
const fieldTtl = field.ttlConfig;
|
|
453
|
+
if (fieldTtl) {
|
|
454
|
+
result += ` TTL(${fieldTtl.state})`;
|
|
455
|
+
}
|
|
430
456
|
return result;
|
|
431
457
|
}
|
|
432
458
|
}
|
package/lib/firestore/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseFieldName = exports.parseIndexName = void 0;
|
|
3
|
+
exports.booleanXOR = exports.parseFieldName = exports.parseIndexName = void 0;
|
|
4
4
|
const error_1 = require("../error");
|
|
5
5
|
const INDEX_NAME_REGEX = /projects\/([^\/]+?)\/databases\/\(default\)\/collectionGroups\/([^\/]+?)\/indexes\/([^\/]*)/;
|
|
6
6
|
const FIELD_NAME_REGEX = /projects\/([^\/]+?)\/databases\/\(default\)\/collectionGroups\/([^\/]+?)\/fields\/([^\/]*)/;
|
|
@@ -31,3 +31,7 @@ function parseFieldName(name) {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
exports.parseFieldName = parseFieldName;
|
|
34
|
+
function booleanXOR(a, b) {
|
|
35
|
+
return !!(Number(a) - Number(b));
|
|
36
|
+
}
|
|
37
|
+
exports.booleanXOR = booleanXOR;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.assertEnum = exports.assertHasOneOf = exports.assertHas = void 0;
|
|
3
|
+
exports.assertType = exports.assertEnum = exports.assertHasOneOf = exports.assertHas = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const error_1 = require("../error");
|
|
6
6
|
function assertHas(obj, prop) {
|
|
@@ -30,3 +30,9 @@ function assertEnum(obj, prop, valid) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
exports.assertEnum = assertEnum;
|
|
33
|
+
function assertType(prop, propValue, type) {
|
|
34
|
+
if (typeof propValue !== type) {
|
|
35
|
+
throw new error_1.FirebaseError(`Property "${prop}" must be of type ${type}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.assertType = assertType;
|
|
@@ -8,10 +8,12 @@ const promises_1 = require("fs/promises");
|
|
|
8
8
|
const __1 = require("..");
|
|
9
9
|
const prompt_1 = require("../../prompt");
|
|
10
10
|
const proxy_1 = require("../../hosting/proxy");
|
|
11
|
+
const utils_1 = require("../utils");
|
|
11
12
|
exports.name = "Angular";
|
|
12
13
|
exports.support = "experimental";
|
|
13
14
|
exports.type = 3;
|
|
14
15
|
const CLI_COMMAND = (0, path_1.join)("node_modules", ".bin", process.platform === "win32" ? "ng.cmd" : "ng");
|
|
16
|
+
const DEFAULT_BUILD_SCRIPT = ["ng build"];
|
|
15
17
|
async function discover(dir) {
|
|
16
18
|
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "package.json"))))
|
|
17
19
|
return;
|
|
@@ -48,6 +50,7 @@ async function build(dir) {
|
|
|
48
50
|
if (!success)
|
|
49
51
|
throw new Error(error);
|
|
50
52
|
};
|
|
53
|
+
await (0, utils_1.warnIfCustomBuildScript)(dir, exports.name, DEFAULT_BUILD_SCRIPT);
|
|
51
54
|
if (!browserTarget)
|
|
52
55
|
throw new Error("No build target...");
|
|
53
56
|
if (prerenderTarget) {
|
package/lib/frameworks/index.js
CHANGED
|
@@ -230,7 +230,10 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
|
|
|
230
230
|
const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, } = exports.WebFrameworks[framework];
|
|
231
231
|
console.log(`Detected a ${name} codebase. ${SupportLevelWarnings[support] || ""}\n`);
|
|
232
232
|
const isDevMode = context._name === "serve" || context._name === "emulators:start";
|
|
233
|
-
const
|
|
233
|
+
const hostingEmulatorInfo = emulators.find((e) => e.name === types_1.Emulators.HOSTING);
|
|
234
|
+
const devModeHandle = isDevMode &&
|
|
235
|
+
getDevModeHandle &&
|
|
236
|
+
(await getDevModeHandle(getProjectPath(), hostingEmulatorInfo));
|
|
234
237
|
let codegenFunctionsDirectory;
|
|
235
238
|
if (devModeHandle) {
|
|
236
239
|
config.public = (0, path_1.relative)(projectRoot, publicDirectory);
|
|
@@ -326,6 +329,9 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
|
|
|
326
329
|
${firebaseDefaults ? `__FIREBASE_DEFAULTS__=${JSON.stringify(firebaseDefaults)}\n` : ""}`);
|
|
327
330
|
await (0, promises_1.copyFile)(getProjectPath("package-lock.json"), (0, path_1.join)(functionsDist, "package-lock.json")).catch(() => {
|
|
328
331
|
});
|
|
332
|
+
if (await (0, fs_extra_1.pathExists)(getProjectPath(".npmrc"))) {
|
|
333
|
+
await (0, promises_1.copyFile)(getProjectPath(".npmrc"), (0, path_1.join)(functionsDist, ".npmrc"));
|
|
334
|
+
}
|
|
329
335
|
(0, child_process_1.execSync)(`${NPM_COMMAND} i --omit dev --no-audit`, {
|
|
330
336
|
cwd: functionsDist,
|
|
331
337
|
stdio: "inherit",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ROUTES_MANIFEST = exports.PRERENDER_MANIFEST = exports.PAGES_MANIFEST = exports.MIDDLEWARE_MANIFEST = exports.IMAGES_MANIFEST = exports.EXPORT_MARKER = exports.APP_PATH_ROUTES_MANIFEST = void 0;
|
|
4
|
+
exports.APP_PATH_ROUTES_MANIFEST = "app-path-routes-manifest.json";
|
|
5
|
+
exports.EXPORT_MARKER = "export-marker.json";
|
|
6
|
+
exports.IMAGES_MANIFEST = "images-manifest.json";
|
|
7
|
+
exports.MIDDLEWARE_MANIFEST = "middleware-manifest.json";
|
|
8
|
+
exports.PAGES_MANIFEST = "pages-manifest.json";
|
|
9
|
+
exports.PRERENDER_MANIFEST = "prerender-manifest.json";
|
|
10
|
+
exports.ROUTES_MANIFEST = "routes-manifest.json";
|