firebase-tools 13.15.0 → 13.15.1
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/commands/deploy.js +3 -1
- package/lib/dataconnect/fileUtils.js +52 -11
- package/lib/dataconnect/provisionCloudSql.js +5 -1
- package/lib/deploy/extensions/planner.js +46 -1
- package/lib/deploy/extensions/prepare.js +99 -23
- package/lib/deploy/functions/build.js +5 -5
- package/lib/deploy/functions/deploy.js +12 -12
- package/lib/deploy/functions/params.js +5 -3
- package/lib/deploy/functions/prepare.js +16 -1
- package/lib/deploy/functions/release/index.js +4 -0
- package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +46 -0
- package/lib/emulator/downloadableEmulators.js +9 -9
- package/lib/emulator/functionsEmulator.js +8 -1
- package/lib/extensions/askUserForEventsConfig.js +18 -8
- package/lib/extensions/askUserForParam.js +2 -1
- package/lib/extensions/displayExtensionInfo.js +5 -5
- package/lib/extensions/extensionsApi.js +1 -1
- package/lib/extensions/extensionsHelper.js +42 -3
- package/lib/extensions/localHelper.js +1 -1
- package/lib/extensions/refs.js +26 -11
- package/lib/extensions/runtimes/common.js +75 -0
- package/lib/extensions/types.js +56 -1
- package/lib/frameworks/constants.js +1 -1
- package/lib/frameworks/next/constants.js +1 -1
- package/lib/frameworks/next/index.js +26 -14
- package/lib/frameworks/next/utils.js +45 -1
- package/lib/init/features/dataconnect/index.js +10 -7
- package/lib/init/features/dataconnect/sdk.js +67 -51
- package/lib/prompt.js +22 -1
- package/package.json +1 -1
- package/templates/init/dataconnect/connector.yaml +5 -3
- package/templates/init/dataconnect/dataconnect.yaml +5 -5
- package/templates/init/dataconnect/mutations.gql +44 -29
- package/templates/init/dataconnect/queries.gql +66 -38
- package/templates/init/dataconnect/schema.gql +38 -21
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.askForEventArcLocation = exports.askShouldCollectEventsConfig = exports.askForAllowedEventTypes = exports.askForEventsConfig = exports.checkAllowedEventTypesResponse = void 0;
|
|
3
|
+
exports.askForEventArcLocation = exports.EXTENSIONS_DEFAULT_EVENT_ARC_REGION = exports.ALLOWED_EVENT_ARC_REGIONS = exports.askShouldCollectEventsConfig = exports.askForAllowedEventTypes = exports.getEventArcChannel = exports.askForEventsConfig = exports.checkAllowedEventTypesResponse = void 0;
|
|
4
4
|
const prompt_1 = require("../prompt");
|
|
5
5
|
const extensionsApi = require("../extensions/extensionsApi");
|
|
6
6
|
const utils = require("../utils");
|
|
@@ -23,7 +23,7 @@ function checkAllowedEventTypesResponse(response, validEvents) {
|
|
|
23
23
|
exports.checkAllowedEventTypesResponse = checkAllowedEventTypesResponse;
|
|
24
24
|
async function askForEventsConfig(events, projectId, instanceId) {
|
|
25
25
|
var _a, _b;
|
|
26
|
-
logger_1.logger.info(`\n${clc.bold("Enable Events")}: ${(0, marked_1.marked)("If you enable events, you can write custom event handlers ([https://firebase.google.com/docs/extensions/install-extensions#eventarc](https://firebase.google.com/docs/extensions/install-extensions#eventarc)) that respond to these events.\n\nYou can always enable or disable events later. Events will be emitted via Eventarc. Fees apply ([https://cloud.google.com/eventarc/pricing](https://cloud.google.com/eventarc/pricing)).")}`);
|
|
26
|
+
logger_1.logger.info(`\n${clc.bold("Enable Events")}: ${await (0, marked_1.marked)("If you enable events, you can write custom event handlers ([https://firebase.google.com/docs/extensions/install-extensions#eventarc](https://firebase.google.com/docs/extensions/install-extensions#eventarc)) that respond to these events.\n\nYou can always enable or disable events later. Events will be emitted via Eventarc. Fees apply ([https://cloud.google.com/eventarc/pricing](https://cloud.google.com/eventarc/pricing)).")}`);
|
|
27
27
|
if (!(await askShouldCollectEventsConfig())) {
|
|
28
28
|
return undefined;
|
|
29
29
|
}
|
|
@@ -38,11 +38,15 @@ async function askForEventsConfig(events, projectId, instanceId) {
|
|
|
38
38
|
const preselectedTypes = (_a = existingInstance === null || existingInstance === void 0 ? void 0 : existingInstance.config.allowedEventTypes) !== null && _a !== void 0 ? _a : [];
|
|
39
39
|
const oldLocation = (_b = existingInstance === null || existingInstance === void 0 ? void 0 : existingInstance.config.eventarcChannel) === null || _b === void 0 ? void 0 : _b.split("/")[3];
|
|
40
40
|
const location = await askForEventArcLocation(oldLocation);
|
|
41
|
-
const channel =
|
|
41
|
+
const channel = getEventArcChannel(projectId, location);
|
|
42
42
|
const allowedEventTypes = await askForAllowedEventTypes(events, preselectedTypes);
|
|
43
43
|
return { channel, allowedEventTypes };
|
|
44
44
|
}
|
|
45
45
|
exports.askForEventsConfig = askForEventsConfig;
|
|
46
|
+
function getEventArcChannel(projectId, location) {
|
|
47
|
+
return `projects/${projectId}/locations/${location}/channels/firebase`;
|
|
48
|
+
}
|
|
49
|
+
exports.getEventArcChannel = getEventArcChannel;
|
|
46
50
|
async function askForAllowedEventTypes(eventDescriptors, preselectedTypes) {
|
|
47
51
|
let valid = false;
|
|
48
52
|
let response = [];
|
|
@@ -75,21 +79,27 @@ async function askShouldCollectEventsConfig() {
|
|
|
75
79
|
});
|
|
76
80
|
}
|
|
77
81
|
exports.askShouldCollectEventsConfig = askShouldCollectEventsConfig;
|
|
82
|
+
exports.ALLOWED_EVENT_ARC_REGIONS = [
|
|
83
|
+
"us-central1",
|
|
84
|
+
"us-west1",
|
|
85
|
+
"europe-west4",
|
|
86
|
+
"asia-northeast1",
|
|
87
|
+
];
|
|
88
|
+
exports.EXTENSIONS_DEFAULT_EVENT_ARC_REGION = "us-central1";
|
|
78
89
|
async function askForEventArcLocation(preselectedLocation) {
|
|
79
90
|
let valid = false;
|
|
80
|
-
const allowedRegions = ["us-central1", "us-west1", "europe-west4", "asia-northeast1"];
|
|
81
91
|
let location = "";
|
|
82
92
|
while (!valid) {
|
|
83
93
|
location = await (0, prompt_1.promptOnce)({
|
|
84
94
|
name: "input",
|
|
85
95
|
type: "list",
|
|
86
|
-
default: preselectedLocation !== null && preselectedLocation !== void 0 ? preselectedLocation :
|
|
96
|
+
default: preselectedLocation !== null && preselectedLocation !== void 0 ? preselectedLocation : exports.EXTENSIONS_DEFAULT_EVENT_ARC_REGION,
|
|
87
97
|
message: "Which location would you like the Eventarc channel to live in? We recommend using the default option. A channel location that differs from the extension's Cloud Functions location can incur egress cost.",
|
|
88
|
-
choices:
|
|
98
|
+
choices: exports.ALLOWED_EVENT_ARC_REGIONS.map((e) => ({ checked: false, value: e })),
|
|
89
99
|
});
|
|
90
|
-
valid =
|
|
100
|
+
valid = exports.ALLOWED_EVENT_ARC_REGIONS.includes(location);
|
|
91
101
|
if (!valid) {
|
|
92
|
-
utils.logWarning(`Unexpected EventArc region '${location}' was specified. Allowed regions: ${
|
|
102
|
+
utils.logWarning(`Unexpected EventArc region '${location}' was specified. Allowed regions: ${exports.ALLOWED_EVENT_ARC_REGIONS.join(", ")}`);
|
|
93
103
|
}
|
|
94
104
|
}
|
|
95
105
|
return location;
|
|
@@ -255,7 +255,7 @@ async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
|
|
|
255
255
|
],
|
|
256
256
|
});
|
|
257
257
|
switch (action) {
|
|
258
|
-
case SecretUpdateAction.SET_NEW:
|
|
258
|
+
case SecretUpdateAction.SET_NEW: {
|
|
259
259
|
let secret;
|
|
260
260
|
let secretName;
|
|
261
261
|
if (paramSpec.default) {
|
|
@@ -288,6 +288,7 @@ async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
|
|
|
288
288
|
else {
|
|
289
289
|
return "";
|
|
290
290
|
}
|
|
291
|
+
}
|
|
291
292
|
case SecretUpdateAction.LEAVE:
|
|
292
293
|
default:
|
|
293
294
|
return paramSpec.default || "";
|
|
@@ -50,7 +50,7 @@ async function displayExtensionVersionInfo(args) {
|
|
|
50
50
|
if (extensionVersion.buildSourceUri) {
|
|
51
51
|
const buildSourceUri = new URL(extensionVersion.buildSourceUri);
|
|
52
52
|
buildSourceUri.pathname = path.join(buildSourceUri.pathname, (_c = extensionVersion.extensionRoot) !== null && _c !== void 0 ? _c : "");
|
|
53
|
-
lines.push(`${clc.bold("Source in GitHub:")} ${buildSourceUri}`);
|
|
53
|
+
lines.push(`${clc.bold("Source in GitHub:")} ${buildSourceUri.toString()}`);
|
|
54
54
|
}
|
|
55
55
|
else {
|
|
56
56
|
lines.push(`${clc.bold("Source download URI:")} ${(_d = extensionVersion.sourceDownloadUri) !== null && _d !== void 0 ? _d : "-"}`);
|
|
@@ -105,24 +105,24 @@ function displayResources(spec) {
|
|
|
105
105
|
break;
|
|
106
106
|
default:
|
|
107
107
|
}
|
|
108
|
-
return ` - ${clc.
|
|
108
|
+
return ` - ${clc.blueBright(`${resource.name} (${type})`)}${resource.description ? `: ${resource.description}` : ""}`;
|
|
109
109
|
});
|
|
110
110
|
lines.push(...new Set((_a = spec.lifecycleEvents) === null || _a === void 0 ? void 0 : _a.map((event) => {
|
|
111
|
-
return ` - ${clc.
|
|
111
|
+
return ` - ${clc.blueBright(`${event.taskQueueTriggerFunction} (Cloud Task queue)`)}`;
|
|
112
112
|
})));
|
|
113
113
|
lines.push(...spec.params
|
|
114
114
|
.filter((param) => {
|
|
115
115
|
return param.type === "SECRET";
|
|
116
116
|
})
|
|
117
117
|
.map((param) => {
|
|
118
|
-
return ` - ${clc.
|
|
118
|
+
return ` - ${clc.blueBright(`${param.param} (Cloud Secret Manager secret)`)}`;
|
|
119
119
|
}));
|
|
120
120
|
return clc.bold("Resources created:\n") + (lines.length ? lines.join("\n") : " - None");
|
|
121
121
|
}
|
|
122
122
|
exports.displayResources = displayResources;
|
|
123
123
|
async function retrieveRoleInfo(role) {
|
|
124
124
|
const res = await iam.getRole(role);
|
|
125
|
-
return ` - ${clc.yellow(res.title)}${res.description ? `: ${res.description}` : ""}`;
|
|
125
|
+
return ` - ${clc.yellow(res.title || res.name)}${res.description ? `: ${res.description}` : ""}`;
|
|
126
126
|
}
|
|
127
127
|
exports.retrieveRoleInfo = retrieveRoleInfo;
|
|
128
128
|
async function displayRoles(roles) {
|
|
@@ -356,6 +356,6 @@ function refNotFoundError(ref) {
|
|
|
356
356
|
return new error_1.FirebaseError(`The extension reference '${clc.bold(ref.version ? refs.toExtensionVersionRef(ref) : refs.toExtensionRef(ref))}' doesn't exist. This could happen for two reasons:\n` +
|
|
357
357
|
` -The publisher ID '${clc.bold(ref.publisherId)}' doesn't exist or could be misspelled\n` +
|
|
358
358
|
` -The name of the ${ref.version ? "extension version" : "extension"} '${clc.bold(ref.version ? `${ref.extensionId}@${ref.version}` : ref.extensionId)}' doesn't exist or could be misspelled\n\n` +
|
|
359
|
-
`Please correct the extension reference and try again. If you meant to
|
|
359
|
+
`Please correct the extension reference and try again. If you meant to reference an extension from a local source, please provide a relative path prefixed with '${clc.bold("./")}', '${clc.bold("../")}', or '${clc.bold("~/")}'.}`, { status: 404 });
|
|
360
360
|
}
|
|
361
361
|
exports.refNotFoundError = refNotFoundError;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
3
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
4
|
+
var m = o[Symbol.asyncIterator], i;
|
|
5
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
6
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
7
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
8
|
+
};
|
|
2
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.diagnoseAndFixProject = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.getMissingPublisherError = exports.uploadExtensionVersionFromLocalSource = exports.uploadExtensionVersionFromGitHubSource = exports.unpackExtensionState = exports.getNextVersionByStage = exports.ensureExtensionsPublisherApiEnabled = exports.ensureExtensionsApiEnabled = exports.promptForExtensionRoot = exports.promptForValidRepoURI = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.AUTOPOULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
|
|
10
|
+
exports.diagnoseAndFixProject = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.getMissingPublisherError = exports.uploadExtensionVersionFromLocalSource = exports.uploadExtensionVersionFromGitHubSource = exports.unpackExtensionState = exports.getNextVersionByStage = exports.ensureExtensionsPublisherApiEnabled = exports.ensureExtensionsApiEnabled = exports.promptForExtensionRoot = exports.promptForValidRepoURI = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteSecretParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.AUTOPOULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
|
|
4
11
|
const clc = require("colorette");
|
|
5
12
|
const ora = require("ora");
|
|
6
13
|
const semver = require("semver");
|
|
@@ -126,6 +133,38 @@ function substituteParams(original, params) {
|
|
|
126
133
|
return JSON.parse(s);
|
|
127
134
|
}
|
|
128
135
|
exports.substituteParams = substituteParams;
|
|
136
|
+
async function substituteSecretParams(projectNumber, params) {
|
|
137
|
+
var _a, e_1, _b, _c;
|
|
138
|
+
const newParams = {};
|
|
139
|
+
try {
|
|
140
|
+
for (var _d = true, _e = __asyncValues(Object.entries(params)), _f; _f = await _e.next(), _a = _f.done, !_a;) {
|
|
141
|
+
_c = _f.value;
|
|
142
|
+
_d = false;
|
|
143
|
+
try {
|
|
144
|
+
const [key, value] = _c;
|
|
145
|
+
if (typeof value !== "string") {
|
|
146
|
+
newParams[key] =
|
|
147
|
+
`projects/${projectNumber}/secrets/${value.name}/versions/latest`;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
newParams[key] = value;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
_d = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
159
|
+
finally {
|
|
160
|
+
try {
|
|
161
|
+
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
|
|
162
|
+
}
|
|
163
|
+
finally { if (e_1) throw e_1.error; }
|
|
164
|
+
}
|
|
165
|
+
return newParams;
|
|
166
|
+
}
|
|
167
|
+
exports.substituteSecretParams = substituteSecretParams;
|
|
129
168
|
function populateDefaultParams(paramVars, paramSpecs) {
|
|
130
169
|
const newParams = paramVars;
|
|
131
170
|
for (const param of paramSpecs) {
|
|
@@ -472,7 +511,7 @@ function displayExtensionHeader(extensionRef, extension, extensionRoot) {
|
|
|
472
511
|
}
|
|
473
512
|
else {
|
|
474
513
|
logger_1.logger.info(`\n${clc.bold("Extension:")} ${extensionRef}\n` +
|
|
475
|
-
`${clc.bold("State:")} ${clc.bold(clc.
|
|
514
|
+
`${clc.bold("State:")} ${clc.bold(clc.blueBright("New"))}\n`);
|
|
476
515
|
}
|
|
477
516
|
}
|
|
478
517
|
async function fetchExtensionSource(repoUri, sourceRef, extensionRoot) {
|
|
@@ -794,7 +833,7 @@ async function instanceIdExists(projectId, instanceId) {
|
|
|
794
833
|
if (err.status === 404) {
|
|
795
834
|
return false;
|
|
796
835
|
}
|
|
797
|
-
const msg = `Unexpected error when checking if instance ID exists: ${err}`;
|
|
836
|
+
const msg = `Unexpected error when checking if instance ID exists: ${err.message}`;
|
|
798
837
|
throw new error_1.FirebaseError(msg, {
|
|
799
838
|
original: err,
|
|
800
839
|
});
|
|
@@ -38,7 +38,7 @@ function readFile(pathToFile) {
|
|
|
38
38
|
}
|
|
39
39
|
catch (err) {
|
|
40
40
|
if (err.code === "ENOENT") {
|
|
41
|
-
throw new error_1.FirebaseError(`Could not find "${pathToFile}"
|
|
41
|
+
throw new error_1.FirebaseError(`Could not find "${pathToFile}"`, { original: err });
|
|
42
42
|
}
|
|
43
43
|
throw new error_1.FirebaseError(`Failed to read file at "${pathToFile}"`, { original: err });
|
|
44
44
|
}
|
package/lib/extensions/refs.js
CHANGED
|
@@ -7,13 +7,16 @@ const refRegex = new RegExp(/^([^/@\n]+)\/{1}([^/@\n]+)(@{1}([^\n]+)|)$/);
|
|
|
7
7
|
function parse(refOrName) {
|
|
8
8
|
const ret = parseRef(refOrName) || parseName(refOrName);
|
|
9
9
|
if (!ret || !ret.publisherId || !ret.extensionId) {
|
|
10
|
-
throw new error_1.FirebaseError(`Unable to parse ${refOrName} as an extension ref`
|
|
10
|
+
throw new error_1.FirebaseError(`Unable to parse ${refOrName} as an extension ref.\n` +
|
|
11
|
+
"Expected format is either publisherId/extensionId@version or " +
|
|
12
|
+
"publishers/publisherId/extensions/extensionId/versions/version. If you " +
|
|
13
|
+
"are referring to a local extension directory, please ensure the directory exists.");
|
|
11
14
|
}
|
|
12
15
|
if (ret.version &&
|
|
13
16
|
!semver.valid(ret.version) &&
|
|
14
17
|
!semver.validRange(ret.version) &&
|
|
15
18
|
!["latest", "latest-approved"].includes(ret.version)) {
|
|
16
|
-
throw new error_1.FirebaseError(`Extension reference ${ret} contains an invalid version ${ret.version}.`);
|
|
19
|
+
throw new error_1.FirebaseError(`Extension reference ${JSON.stringify(ret, null, 2)} contains an invalid version ${ret.version}.`);
|
|
17
20
|
}
|
|
18
21
|
return ret;
|
|
19
22
|
}
|
|
@@ -21,19 +24,31 @@ exports.parse = parse;
|
|
|
21
24
|
function parseRef(ref) {
|
|
22
25
|
const parts = refRegex.exec(ref);
|
|
23
26
|
if (parts && (parts.length === 5 || parts.length === 7)) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
return {
|
|
28
|
+
publisherId: parts[1],
|
|
29
|
+
extensionId: parts[2],
|
|
30
|
+
version: parts[4],
|
|
31
|
+
};
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
function parseName(name) {
|
|
31
35
|
const parts = name.split("/");
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
if (parts[0] !== "publishers" || parts[2] !== "extensions") {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (parts.length === 4) {
|
|
40
|
+
return {
|
|
41
|
+
publisherId: parts[1],
|
|
42
|
+
extensionId: parts[3],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (parts.length === 6 && parts[4] === "versions") {
|
|
46
|
+
return {
|
|
47
|
+
publisherId: parts[1],
|
|
48
|
+
extensionId: parts[3],
|
|
49
|
+
version: parts[5],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
37
52
|
}
|
|
38
53
|
function toExtensionRef(ref) {
|
|
39
54
|
return `${ref.publisherId}/${ref.extensionId}`;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractExtensionsFromBuilds = exports.extractAllDynamicExtensions = void 0;
|
|
4
|
+
const projectConfig_1 = require("../../functions/projectConfig");
|
|
5
|
+
const prepare_1 = require("../../deploy/functions/prepare");
|
|
6
|
+
const functionsConfig_1 = require("../../functionsConfig");
|
|
7
|
+
const functionsDeployHelper_1 = require("../../deploy/functions/functionsDeployHelper");
|
|
8
|
+
const logger_1 = require("../../logger");
|
|
9
|
+
const savedLoggerSilent = logger_1.logger.silent;
|
|
10
|
+
function silenceLogging() {
|
|
11
|
+
logger_1.logger.silent = true;
|
|
12
|
+
}
|
|
13
|
+
function resumeLogging() {
|
|
14
|
+
logger_1.logger.silent = savedLoggerSilent;
|
|
15
|
+
}
|
|
16
|
+
async function extractAllDynamicExtensions(options) {
|
|
17
|
+
const firebaseConfig = await (0, functionsConfig_1.getFirebaseConfig)(options);
|
|
18
|
+
const runtimeConfig = { firebase: firebaseConfig };
|
|
19
|
+
const functionsConfig = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
|
|
20
|
+
let functionsBuilds = {};
|
|
21
|
+
const codebases = (0, functionsDeployHelper_1.targetCodebases)(functionsConfig);
|
|
22
|
+
silenceLogging();
|
|
23
|
+
for (const codebase of codebases) {
|
|
24
|
+
try {
|
|
25
|
+
const filters = [{ codebase: `${codebase}` }];
|
|
26
|
+
const builds = await (0, prepare_1.loadCodebases)(functionsConfig, options, firebaseConfig, runtimeConfig, filters);
|
|
27
|
+
functionsBuilds = Object.assign(Object.assign({}, functionsBuilds), builds);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
resumeLogging();
|
|
33
|
+
return extractExtensionsFromBuilds(functionsBuilds);
|
|
34
|
+
}
|
|
35
|
+
exports.extractAllDynamicExtensions = extractAllDynamicExtensions;
|
|
36
|
+
function extractExtensionsFromBuilds(builds, filters) {
|
|
37
|
+
const extRecords = {};
|
|
38
|
+
for (const [codebase, build] of Object.entries(builds)) {
|
|
39
|
+
if (build.extensions) {
|
|
40
|
+
for (const [id, ext] of Object.entries(build.extensions)) {
|
|
41
|
+
if (extensionMatchesAnyFilter(codebase, id, filters)) {
|
|
42
|
+
extRecords[id] = ext;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return extRecords;
|
|
48
|
+
}
|
|
49
|
+
exports.extractExtensionsFromBuilds = extractExtensionsFromBuilds;
|
|
50
|
+
function extensionMatchesAnyFilter(codebase, extensionId, filters) {
|
|
51
|
+
if (!filters) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return filters.some((f) => extensionMatchesFilter(codebase, extensionId, f));
|
|
55
|
+
}
|
|
56
|
+
function extensionMatchesFilter(codebase, extensionId, filter) {
|
|
57
|
+
if (codebase && filter.codebase) {
|
|
58
|
+
if (codebase !== filter.codebase) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (!filter.idChunks) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
const idChunks = extensionId.split("-");
|
|
66
|
+
if (idChunks.length < filter.idChunks.length) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
for (let i = 0; i < filter.idChunks.length; i++) {
|
|
70
|
+
if (idChunks[i] !== filter.idChunks[i]) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
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_V2_RESOURCE_TYPE = exports.FUNCTIONS_RESOURCE_TYPE = exports.Visibility = exports.RegistryLaunchStage = void 0;
|
|
3
|
+
exports.isExtensionSpec = exports.isResource = exports.isParam = 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";
|
|
@@ -21,5 +21,60 @@ var ParamType;
|
|
|
21
21
|
ParamType["STRING"] = "STRING";
|
|
22
22
|
ParamType["SELECT"] = "SELECT";
|
|
23
23
|
ParamType["MULTISELECT"] = "MULTISELECT";
|
|
24
|
+
ParamType["SELECT_RESOURCE"] = "SELECT_RESOURCE";
|
|
24
25
|
ParamType["SECRET"] = "SECRET";
|
|
25
26
|
})(ParamType = exports.ParamType || (exports.ParamType = {}));
|
|
27
|
+
function isObject(value) {
|
|
28
|
+
return typeof value === "object" && value !== null;
|
|
29
|
+
}
|
|
30
|
+
const isParam = (param) => {
|
|
31
|
+
return (isObject(param) && typeof param["param"] === "string" && typeof param["label"] === "string");
|
|
32
|
+
};
|
|
33
|
+
exports.isParam = isParam;
|
|
34
|
+
const isResource = (res) => {
|
|
35
|
+
return isObject(res) && typeof res["name"] === "string";
|
|
36
|
+
};
|
|
37
|
+
exports.isResource = isResource;
|
|
38
|
+
const isExtensionSpec = (spec) => {
|
|
39
|
+
if (!isObject(spec) || typeof spec.name !== "string" || typeof spec.version !== "string") {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
let validResources = true;
|
|
43
|
+
if (spec.resources && Array.isArray(spec.resources)) {
|
|
44
|
+
for (const res of spec.resources) {
|
|
45
|
+
validResources = validResources && (0, exports.isResource)(res);
|
|
46
|
+
if (!validResources) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
let validParams = true;
|
|
55
|
+
if (spec.params && Array.isArray(spec.params)) {
|
|
56
|
+
for (const param of spec.params) {
|
|
57
|
+
validParams = validParams && (0, exports.isParam)(param);
|
|
58
|
+
if (!validParams) {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
let validSysParams = true;
|
|
67
|
+
if (spec.systemParams && Array.isArray(spec.systemParams)) {
|
|
68
|
+
for (const param of spec.systemParams) {
|
|
69
|
+
validSysParams = validSysParams && (0, exports.isParam)(param);
|
|
70
|
+
if (!validSysParams) {
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
};
|
|
80
|
+
exports.isExtensionSpec = isExtensionSpec;
|
|
@@ -20,7 +20,7 @@ exports.FIREBASE_FRAMEWORKS_VERSION = (experiments.isEnabled("internaltesting")
|
|
|
20
20
|
DEFAULT_FIREBASE_FRAMEWORKS_VERSION;
|
|
21
21
|
exports.FIREBASE_FUNCTIONS_VERSION = "^4.5.0";
|
|
22
22
|
exports.FIREBASE_ADMIN_VERSION = "^11.11.1";
|
|
23
|
-
exports.SHARP_VERSION = "^0.32.
|
|
23
|
+
exports.SHARP_VERSION = "^0.32 || ^0.33";
|
|
24
24
|
exports.NODE_VERSION = parseInt(process.versions.node, 10);
|
|
25
25
|
exports.VALID_ENGINES = { node: [16, 18, 20] };
|
|
26
26
|
exports.VALID_LOCALE_FORMATS = [/^ALL_[a-z]+$/, /^[a-z]+_ALL$/, /^[a-z]+(_[a-z]+)?$/];
|
|
@@ -11,7 +11,7 @@ exports.ROUTES_MANIFEST = "routes-manifest.json";
|
|
|
11
11
|
exports.APP_PATHS_MANIFEST = "app-paths-manifest.json";
|
|
12
12
|
exports.SERVER_REFERENCE_MANIFEST = "server-reference-manifest.json";
|
|
13
13
|
exports.CONFIG_FILES = ["next.config.js", "next.config.mjs"];
|
|
14
|
-
exports.ESBUILD_VERSION = "0.19.2";
|
|
14
|
+
exports.ESBUILD_VERSION = "^0.19.2";
|
|
15
15
|
const WEBPACK_LAYERS_NAMES = {
|
|
16
16
|
shared: "shared",
|
|
17
17
|
reactServerComponents: "rsc",
|
|
@@ -29,7 +29,6 @@ exports.name = "Next.js";
|
|
|
29
29
|
exports.support = "preview";
|
|
30
30
|
exports.type = 2;
|
|
31
31
|
exports.docsUrl = "https://firebase.google.com/docs/hosting/frameworks/nextjs";
|
|
32
|
-
const BUNDLE_NEXT_CONFIG_TIMEOUT = 60000;
|
|
33
32
|
const DEFAULT_NUMBER_OF_REASONS_TO_LIST = 5;
|
|
34
33
|
function getReactVersion(cwd) {
|
|
35
34
|
var _a;
|
|
@@ -338,6 +337,19 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir, target, context)
|
|
|
338
337
|
const configFile = await (0, utils_2.whichNextConfigFile)(sourceDir);
|
|
339
338
|
if (configFile) {
|
|
340
339
|
try {
|
|
340
|
+
let esbuildPath = (0, utils_2.findEsbuildPath)();
|
|
341
|
+
if (!esbuildPath || !(0, fs_extra_1.pathExistsSync)(esbuildPath)) {
|
|
342
|
+
console.warn("esbuild not found, installing...");
|
|
343
|
+
(0, utils_2.installEsbuild)(constants_2.ESBUILD_VERSION);
|
|
344
|
+
esbuildPath = (0, utils_2.findEsbuildPath)();
|
|
345
|
+
if (!esbuildPath || !(0, fs_extra_1.pathExistsSync)(esbuildPath)) {
|
|
346
|
+
throw new error_1.FirebaseError("Failed to locate esbuild after installation.");
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const esbuild = require(esbuildPath);
|
|
350
|
+
if (!esbuild) {
|
|
351
|
+
throw new error_1.FirebaseError(`Failed to load esbuild from path: ${esbuildPath}`);
|
|
352
|
+
}
|
|
341
353
|
const productionDeps = await new Promise((resolve) => {
|
|
342
354
|
const dependencies = [];
|
|
343
355
|
const npmLs = (0, cross_spawn_1.spawn)("npm", ["ls", "--omit=dev", "--all", "--json=true"], {
|
|
@@ -359,21 +371,21 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir, target, context)
|
|
|
359
371
|
resolve([...new Set(dependencies)]);
|
|
360
372
|
});
|
|
361
373
|
});
|
|
362
|
-
const esbuildArgs =
|
|
363
|
-
.
|
|
364
|
-
|
|
374
|
+
const esbuildArgs = {
|
|
375
|
+
entryPoints: [(0, path_1.join)(sourceDir, configFile)],
|
|
376
|
+
outfile: (0, path_1.join)(destDir, configFile),
|
|
377
|
+
bundle: true,
|
|
378
|
+
platform: "node",
|
|
379
|
+
target: `node${constants_1.NODE_VERSION}`,
|
|
380
|
+
logLevel: "error",
|
|
381
|
+
external: productionDeps,
|
|
382
|
+
};
|
|
365
383
|
if (configFile === "next.config.mjs") {
|
|
366
|
-
esbuildArgs.
|
|
384
|
+
esbuildArgs.format = "esm";
|
|
367
385
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const bundle = (0, cross_spawn_1.sync)("npx", ["--yes", `esbuild@${constants_2.ESBUILD_VERSION}`, configFile, ...esbuildArgs], {
|
|
372
|
-
cwd: sourceDir,
|
|
373
|
-
timeout: BUNDLE_NEXT_CONFIG_TIMEOUT,
|
|
374
|
-
});
|
|
375
|
-
if (bundle.status !== 0) {
|
|
376
|
-
throw new error_1.FirebaseError(bundle.stderr.toString());
|
|
386
|
+
const bundle = await esbuild.build(esbuildArgs);
|
|
387
|
+
if (bundle.errors && bundle.errors.length > 0) {
|
|
388
|
+
throw new error_1.FirebaseError(bundle.errors.toString());
|
|
377
389
|
}
|
|
378
390
|
}
|
|
379
391
|
catch (e) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.whichNextConfigFile = exports.getProductionDistDirFiles = exports.getRoutesWithServerAction = exports.hasStaticAppNotFoundComponent = exports.getNextVersion = exports.getBuildId = exports.getHeadersFromMetaFiles = exports.getNonStaticServerComponents = exports.getNonStaticRoutes = exports.getMiddlewareMatcherRegexes = exports.allDependencyNames = exports.isUsingAppDirectory = exports.isUsingNextImageInAppDirectory = exports.isUsingImageOptimization = exports.isUsingMiddleware = exports.hasUnoptimizedImage = exports.usesNextImage = exports.usesAppDirRouter = exports.getNextjsRewritesToUse = exports.isHeaderSupportedByHosting = exports.isRedirectSupportedByHosting = exports.isRewriteSupportedByHosting = exports.cleanI18n = exports.cleanCustomRouteI18n = exports.cleanEscapedChars = exports.I18N_SOURCE = void 0;
|
|
3
|
+
exports.installEsbuild = exports.getGlobalEsbuildVersion = exports.findEsbuildPath = exports.whichNextConfigFile = exports.getProductionDistDirFiles = exports.getRoutesWithServerAction = exports.hasStaticAppNotFoundComponent = exports.getNextVersion = exports.getBuildId = exports.getHeadersFromMetaFiles = exports.getNonStaticServerComponents = exports.getNonStaticRoutes = exports.getMiddlewareMatcherRegexes = exports.allDependencyNames = exports.isUsingAppDirectory = exports.isUsingNextImageInAppDirectory = exports.isUsingImageOptimization = exports.isUsingMiddleware = exports.hasUnoptimizedImage = exports.usesNextImage = exports.usesAppDirRouter = exports.getNextjsRewritesToUse = exports.isHeaderSupportedByHosting = exports.isRedirectSupportedByHosting = exports.isRewriteSupportedByHosting = exports.cleanI18n = exports.cleanCustomRouteI18n = exports.cleanEscapedChars = exports.I18N_SOURCE = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const fs_extra_1 = require("fs-extra");
|
|
6
6
|
const path_1 = require("path");
|
|
@@ -11,6 +11,8 @@ const utils_1 = require("../utils");
|
|
|
11
11
|
const constants_1 = require("./constants");
|
|
12
12
|
const fsutils_1 = require("../../fsutils");
|
|
13
13
|
const utils_2 = require("../../utils");
|
|
14
|
+
const child_process_1 = require("child_process");
|
|
15
|
+
const error_1 = require("../../error");
|
|
14
16
|
exports.I18N_SOURCE = /\/:nextInternalLocale(\([^\)]+\))?/;
|
|
15
17
|
function cleanEscapedChars(path) {
|
|
16
18
|
return path.replace(/\\([(){}:+?*])/g, (a, b) => b);
|
|
@@ -241,3 +243,45 @@ async function whichNextConfigFile(dir) {
|
|
|
241
243
|
return null;
|
|
242
244
|
}
|
|
243
245
|
exports.whichNextConfigFile = whichNextConfigFile;
|
|
246
|
+
function findEsbuildPath() {
|
|
247
|
+
try {
|
|
248
|
+
const esbuildBinPath = (0, child_process_1.execSync)("npx which esbuild", { encoding: "utf8" }).trim();
|
|
249
|
+
const globalVersion = getGlobalEsbuildVersion();
|
|
250
|
+
if (globalVersion && !(0, semver_1.satisfies)(globalVersion, constants_1.ESBUILD_VERSION)) {
|
|
251
|
+
console.warn(`Warning: Global esbuild version (${globalVersion}) does not match the required version (${constants_1.ESBUILD_VERSION}).`);
|
|
252
|
+
}
|
|
253
|
+
return (0, path_1.resolve)((0, path_1.dirname)(esbuildBinPath), "../esbuild");
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
console.error(`Failed to find esbuild with npx which: ${error}`);
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
exports.findEsbuildPath = findEsbuildPath;
|
|
261
|
+
function getGlobalEsbuildVersion() {
|
|
262
|
+
try {
|
|
263
|
+
const versionOutput = (0, child_process_1.execSync)("esbuild --version", { encoding: "utf8" }).trim();
|
|
264
|
+
const versionMatch = versionOutput.match(/(\d+\.\d+\.\d+)/);
|
|
265
|
+
return versionMatch ? versionMatch[0] : null;
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
console.error(`Failed to get global esbuild version: ${error}`);
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
exports.getGlobalEsbuildVersion = getGlobalEsbuildVersion;
|
|
273
|
+
function installEsbuild(version) {
|
|
274
|
+
const installCommand = `npm install esbuild@${version} --no-save`;
|
|
275
|
+
try {
|
|
276
|
+
(0, child_process_1.execSync)(installCommand, { stdio: "inherit" });
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
if (error instanceof error_1.FirebaseError) {
|
|
280
|
+
throw error;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
throw new error_1.FirebaseError(`Failed to install esbuild: ${error}`, { original: error });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
exports.installEsbuild = installEsbuild;
|
|
@@ -21,6 +21,7 @@ const QUERIES_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/que
|
|
|
21
21
|
const MUTATIONS_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/mutations.gql");
|
|
22
22
|
const defaultConnector = {
|
|
23
23
|
id: "default",
|
|
24
|
+
path: "./connector",
|
|
24
25
|
files: [
|
|
25
26
|
{
|
|
26
27
|
path: "queries.gql",
|
|
@@ -92,7 +93,7 @@ exports.actuate = actuate;
|
|
|
92
93
|
async function writeFiles(config, info) {
|
|
93
94
|
const dir = config.get("dataconnect.source") || "dataconnect";
|
|
94
95
|
console.log(dir);
|
|
95
|
-
const subbedDataconnectYaml = subDataconnectYamlValues(Object.assign(Object.assign({}, info), {
|
|
96
|
+
const subbedDataconnectYaml = subDataconnectYamlValues(Object.assign(Object.assign({}, info), { connectorDirs: info.connectors.map((c) => c.path) }));
|
|
96
97
|
config.set("dataconnect", { source: dir });
|
|
97
98
|
await config.askWriteProjectFile((0, path_1.join)(dir, "dataconnect.yaml"), subbedDataconnectYaml);
|
|
98
99
|
if (info.schemaGql.length) {
|
|
@@ -111,9 +112,9 @@ async function writeFiles(config, info) {
|
|
|
111
112
|
async function writeConnectorFiles(config, connectorInfo) {
|
|
112
113
|
const subbedConnectorYaml = subConnectorYamlValues({ connectorId: connectorInfo.id });
|
|
113
114
|
const dir = config.get("dataconnect.source") || "dataconnect";
|
|
114
|
-
await config.askWriteProjectFile((0, path_1.join)(dir, connectorInfo.
|
|
115
|
+
await config.askWriteProjectFile((0, path_1.join)(dir, connectorInfo.path, "connector.yaml"), subbedConnectorYaml);
|
|
115
116
|
for (const f of connectorInfo.files) {
|
|
116
|
-
await config.askWriteProjectFile((0, path_1.join)(dir, connectorInfo.
|
|
117
|
+
await config.askWriteProjectFile((0, path_1.join)(dir, connectorInfo.path, f.path), f.content);
|
|
117
118
|
}
|
|
118
119
|
}
|
|
119
120
|
function subDataconnectYamlValues(replacementValues) {
|
|
@@ -121,12 +122,12 @@ function subDataconnectYamlValues(replacementValues) {
|
|
|
121
122
|
serviceId: "__serviceId__",
|
|
122
123
|
cloudSqlDatabase: "__cloudSqlDatabase__",
|
|
123
124
|
cloudSqlInstanceId: "__cloudSqlInstanceId__",
|
|
124
|
-
|
|
125
|
+
connectorDirs: "__connectorDirs__",
|
|
125
126
|
locationId: "__location__",
|
|
126
127
|
};
|
|
127
128
|
let replaced = DATACONNECT_YAML_TEMPLATE;
|
|
128
129
|
for (const [k, v] of Object.entries(replacementValues)) {
|
|
129
|
-
replaced = replaced.replace(replacements[k], v);
|
|
130
|
+
replaced = replaced.replace(replacements[k], JSON.stringify(v));
|
|
130
131
|
}
|
|
131
132
|
return replaced;
|
|
132
133
|
}
|
|
@@ -136,7 +137,7 @@ function subConnectorYamlValues(replacementValues) {
|
|
|
136
137
|
};
|
|
137
138
|
let replaced = CONNECTOR_YAML_TEMPLATE;
|
|
138
139
|
for (const [k, v] of Object.entries(replacementValues)) {
|
|
139
|
-
replaced = replaced.replace(replacements[k], v);
|
|
140
|
+
replaced = replaced.replace(replacements[k], JSON.stringify(v));
|
|
140
141
|
}
|
|
141
142
|
return replaced;
|
|
142
143
|
}
|
|
@@ -181,8 +182,10 @@ async function promptForService(setup, info) {
|
|
|
181
182
|
const connectors = await (0, client_1.listConnectors)(choice.service.name);
|
|
182
183
|
if (connectors.length) {
|
|
183
184
|
info.connectors = connectors.map((c) => {
|
|
185
|
+
const id = c.name.split("/").pop();
|
|
184
186
|
return {
|
|
185
|
-
id
|
|
187
|
+
id,
|
|
188
|
+
path: `./${id}`,
|
|
186
189
|
files: c.source.files || [],
|
|
187
190
|
};
|
|
188
191
|
});
|