firebase-tools 13.15.0 → 13.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/lib/commands/deploy.js +3 -1
  2. package/lib/dataconnect/fileUtils.js +52 -11
  3. package/lib/dataconnect/provisionCloudSql.js +5 -1
  4. package/lib/deploy/extensions/planner.js +46 -1
  5. package/lib/deploy/extensions/prepare.js +99 -23
  6. package/lib/deploy/functions/build.js +5 -5
  7. package/lib/deploy/functions/deploy.js +12 -12
  8. package/lib/deploy/functions/params.js +5 -3
  9. package/lib/deploy/functions/prepare.js +16 -1
  10. package/lib/deploy/functions/release/index.js +4 -0
  11. package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
  12. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +46 -0
  13. package/lib/emulator/downloadableEmulators.js +9 -9
  14. package/lib/emulator/functionsEmulator.js +8 -1
  15. package/lib/extensions/askUserForEventsConfig.js +18 -8
  16. package/lib/extensions/askUserForParam.js +2 -1
  17. package/lib/extensions/displayExtensionInfo.js +5 -5
  18. package/lib/extensions/extensionsApi.js +1 -1
  19. package/lib/extensions/extensionsHelper.js +42 -3
  20. package/lib/extensions/localHelper.js +1 -1
  21. package/lib/extensions/refs.js +26 -11
  22. package/lib/extensions/runtimes/common.js +75 -0
  23. package/lib/extensions/types.js +56 -1
  24. package/lib/frameworks/constants.js +1 -1
  25. package/lib/frameworks/next/constants.js +1 -1
  26. package/lib/frameworks/next/index.js +35 -15
  27. package/lib/frameworks/next/utils.js +53 -1
  28. package/lib/init/features/dataconnect/index.js +10 -7
  29. package/lib/init/features/dataconnect/sdk.js +67 -51
  30. package/lib/prompt.js +22 -1
  31. package/package.json +1 -1
  32. package/templates/init/dataconnect/connector.yaml +5 -3
  33. package/templates/init/dataconnect/dataconnect.yaml +5 -5
  34. package/templates/init/dataconnect/mutations.gql +44 -29
  35. package/templates/init/dataconnect/queries.gql +66 -38
  36. 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 = `projects/${projectId}/locations/${location}/channels/firebase`;
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 : "us-central1",
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: allowedRegions.map((e) => ({ checked: false, value: e })),
98
+ choices: exports.ALLOWED_EVENT_ARC_REGIONS.map((e) => ({ checked: false, value: e })),
89
99
  });
90
- valid = allowedRegions.includes(location);
100
+ valid = exports.ALLOWED_EVENT_ARC_REGIONS.includes(location);
91
101
  if (!valid) {
92
- utils.logWarning(`Unexpected EventArc region '${location}' was specified. Allowed regions: ${allowedRegions.join(", ")}`);
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.blue(`${resource.name} (${type})`)}${resource.description ? `: ${resource.description}` : ""}`;
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.blue(`${event.taskQueueTriggerFunction} (Cloud Task queue)`)}`;
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.blue(`${param.param} (Cloud Secret Manager secret)`)}`;
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 install an extension from a local source, please provide a relative path prefixed with '${clc.bold("./")}', '${clc.bold("../")}', or '${clc.bold("~/")}'.}`, { status: 404 });
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.blue("New"))}\n`);
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}""`, { original: err });
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
  }
@@ -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
- const publisherId = parts[1];
25
- const extensionId = parts[2];
26
- const version = parts[4];
27
- return { publisherId, extensionId, version };
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
- return {
33
- publisherId: parts[1],
34
- extensionId: parts[3],
35
- version: parts[5],
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
+ }
@@ -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.1";
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",
@@ -22,6 +22,7 @@ const constants_1 = require("../constants");
22
22
  const constants_2 = require("./constants");
23
23
  const api_1 = require("../../hosting/api");
24
24
  const logger_1 = require("../../logger");
25
+ const env_1 = require("../../functions/env");
25
26
  const DEFAULT_BUILD_SCRIPT = ["next build"];
26
27
  const PUBLIC_DIR = "public";
27
28
  exports.supportedRange = "12 - 14.0";
@@ -29,7 +30,6 @@ exports.name = "Next.js";
29
30
  exports.support = "preview";
30
31
  exports.type = 2;
31
32
  exports.docsUrl = "https://firebase.google.com/docs/hosting/frameworks/nextjs";
32
- const BUNDLE_NEXT_CONFIG_TIMEOUT = 60000;
33
33
  const DEFAULT_NUMBER_OF_REASONS_TO_LIST = 5;
34
34
  function getReactVersion(cwd) {
35
35
  var _a;
@@ -51,7 +51,14 @@ async function build(dir, target, context) {
51
51
  if (reactVersion && (0, semver_1.gte)(reactVersion, "18.0.0")) {
52
52
  process.env.__NEXT_REACT_ROOT = "true";
53
53
  }
54
- const env = Object.assign({}, process.env);
54
+ let env = Object.assign({}, process.env);
55
+ if (context === null || context === void 0 ? void 0 : context.projectId) {
56
+ const projectEnvPath = (0, path_1.join)(dir, `.env.${context.projectId}`);
57
+ if (await (0, fs_extra_1.pathExists)(projectEnvPath)) {
58
+ const projectEnvVars = (0, env_1.parseStrict)((await (0, fs_extra_1.readFile)(projectEnvPath)).toString());
59
+ env = Object.assign(Object.assign({}, projectEnvVars), env);
60
+ }
61
+ }
55
62
  if ((context === null || context === void 0 ? void 0 : context.projectId) && (context === null || context === void 0 ? void 0 : context.site)) {
56
63
  const deploymentDomain = await (0, api_1.getDeploymentDomain)(context.projectId, context.site, context.hostingChannel);
57
64
  if (deploymentDomain) {
@@ -338,6 +345,19 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir, target, context)
338
345
  const configFile = await (0, utils_2.whichNextConfigFile)(sourceDir);
339
346
  if (configFile) {
340
347
  try {
348
+ let esbuildPath = (0, utils_2.findEsbuildPath)();
349
+ if (!esbuildPath || !(0, fs_extra_1.pathExistsSync)(esbuildPath)) {
350
+ console.warn("esbuild not found, installing...");
351
+ (0, utils_2.installEsbuild)(constants_2.ESBUILD_VERSION);
352
+ esbuildPath = (0, utils_2.findEsbuildPath)();
353
+ if (!esbuildPath || !(0, fs_extra_1.pathExistsSync)(esbuildPath)) {
354
+ throw new error_1.FirebaseError("Failed to locate esbuild after installation.");
355
+ }
356
+ }
357
+ const esbuild = require(esbuildPath);
358
+ if (!esbuild) {
359
+ throw new error_1.FirebaseError(`Failed to load esbuild from path: ${esbuildPath}`);
360
+ }
341
361
  const productionDeps = await new Promise((resolve) => {
342
362
  const dependencies = [];
343
363
  const npmLs = (0, cross_spawn_1.spawn)("npm", ["ls", "--omit=dev", "--all", "--json=true"], {
@@ -359,21 +379,21 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir, target, context)
359
379
  resolve([...new Set(dependencies)]);
360
380
  });
361
381
  });
362
- const esbuildArgs = productionDeps
363
- .map((it) => `--external:${it}`)
364
- .concat("--bundle", "--platform=node", `--target=node${constants_1.NODE_VERSION}`, "--log-level=error");
382
+ const esbuildArgs = {
383
+ entryPoints: [(0, path_1.join)(sourceDir, configFile)],
384
+ outfile: (0, path_1.join)(destDir, configFile),
385
+ bundle: true,
386
+ platform: "node",
387
+ target: `node${constants_1.NODE_VERSION}`,
388
+ logLevel: "error",
389
+ external: productionDeps,
390
+ };
365
391
  if (configFile === "next.config.mjs") {
366
- esbuildArgs.push(...[`--outfile=${(0, path_1.join)(destDir, configFile)}`, "--format=esm"]);
367
- }
368
- else {
369
- esbuildArgs.push(`--outfile=${(0, path_1.join)(destDir, configFile)}`);
392
+ esbuildArgs.format = "esm";
370
393
  }
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());
394
+ const bundle = await esbuild.build(esbuildArgs);
395
+ if (bundle.errors && bundle.errors.length > 0) {
396
+ throw new error_1.FirebaseError(bundle.errors.toString());
377
397
  }
378
398
  }
379
399
  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,53 @@ async function whichNextConfigFile(dir) {
241
243
  return null;
242
244
  }
243
245
  exports.whichNextConfigFile = whichNextConfigFile;
246
+ function findEsbuildPath() {
247
+ var _a;
248
+ try {
249
+ const esbuildBinPath = (_a = (0, child_process_1.execSync)("npx which esbuild", { encoding: "utf8" })) === null || _a === void 0 ? void 0 : _a.trim();
250
+ if (!esbuildBinPath) {
251
+ return null;
252
+ }
253
+ const globalVersion = getGlobalEsbuildVersion(esbuildBinPath);
254
+ if (globalVersion && !(0, semver_1.satisfies)(globalVersion, constants_1.ESBUILD_VERSION)) {
255
+ console.warn(`Warning: Global esbuild version (${globalVersion}) does not match the required version (${constants_1.ESBUILD_VERSION}).`);
256
+ }
257
+ return (0, path_1.resolve)((0, path_1.dirname)(esbuildBinPath), "../esbuild");
258
+ }
259
+ catch (error) {
260
+ console.error(`Failed to find esbuild with npx which: ${error}`);
261
+ return null;
262
+ }
263
+ }
264
+ exports.findEsbuildPath = findEsbuildPath;
265
+ function getGlobalEsbuildVersion(binPath) {
266
+ var _a;
267
+ try {
268
+ const versionOutput = (_a = (0, child_process_1.execSync)(`${binPath} --version`, { encoding: "utf8" })) === null || _a === void 0 ? void 0 : _a.trim();
269
+ if (!versionOutput) {
270
+ return null;
271
+ }
272
+ const versionMatch = versionOutput.match(/(\d+\.\d+\.\d+)/);
273
+ return versionMatch ? versionMatch[0] : null;
274
+ }
275
+ catch (error) {
276
+ console.error(`Failed to get global esbuild version: ${error}`);
277
+ return null;
278
+ }
279
+ }
280
+ exports.getGlobalEsbuildVersion = getGlobalEsbuildVersion;
281
+ function installEsbuild(version) {
282
+ const installCommand = `npm install esbuild@${version} --no-save`;
283
+ try {
284
+ (0, child_process_1.execSync)(installCommand, { stdio: "inherit" });
285
+ }
286
+ catch (error) {
287
+ if (error instanceof error_1.FirebaseError) {
288
+ throw error;
289
+ }
290
+ else {
291
+ throw new error_1.FirebaseError(`Failed to install esbuild: ${error}`, { original: error });
292
+ }
293
+ }
294
+ }
295
+ exports.installEsbuild = installEsbuild;