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.
Files changed (51) hide show
  1. package/lib/api.js +3 -2
  2. package/lib/commands/index.js +5 -0
  3. package/lib/commands/internaltesting-functions-discover.js +25 -0
  4. package/lib/deploy/extensions/prepare.js +6 -1
  5. package/lib/deploy/extensions/v2FunctionHelper.js +53 -0
  6. package/lib/deploy/functions/build.js +17 -2
  7. package/lib/deploy/functions/cel.js +90 -13
  8. package/lib/deploy/functions/params.js +141 -6
  9. package/lib/deploy/functions/prepare.js +40 -25
  10. package/lib/deploy/functions/release/fabricator.js +27 -1
  11. package/lib/deploy/functions/runtimes/discovery/parsing.js +7 -1
  12. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +1 -1
  13. package/lib/deploy/functions/runtimes/index.js +2 -1
  14. package/lib/deploy/functions/runtimes/node/index.js +2 -2
  15. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +1 -0
  16. package/lib/deploy/functions/runtimes/node/versioning.js +30 -14
  17. package/lib/emulator/commandUtils.js +2 -1
  18. package/lib/emulator/downloadableEmulators.js +3 -3
  19. package/lib/emulator/env.js +29 -27
  20. package/lib/emulator/extensions/validation.js +2 -0
  21. package/lib/emulator/extensionsEmulator.js +1 -1
  22. package/lib/emulator/functionsEmulator.js +44 -32
  23. package/lib/emulator/storage/rules/runtime.js +2 -2
  24. package/lib/emulator/workQueue.js +11 -6
  25. package/lib/experiments.js +6 -0
  26. package/lib/extensions/billingMigrationHelper.js +2 -1
  27. package/lib/extensions/displayExtensionInfo.js +2 -1
  28. package/lib/extensions/emulator/specHelper.js +4 -3
  29. package/lib/extensions/emulator/triggerHelper.js +64 -20
  30. package/lib/extensions/extensionsHelper.js +1 -4
  31. package/lib/extensions/types.js +2 -1
  32. package/lib/extensions/utils.js +14 -1
  33. package/lib/firestore/indexes-api.js +7 -1
  34. package/lib/firestore/indexes-sort.js +4 -0
  35. package/lib/firestore/indexes.js +31 -5
  36. package/lib/firestore/util.js +5 -1
  37. package/lib/firestore/validator.js +7 -1
  38. package/lib/frameworks/angular/index.js +3 -0
  39. package/lib/frameworks/index.js +7 -1
  40. package/lib/frameworks/next/constants.js +10 -0
  41. package/lib/frameworks/next/index.js +170 -127
  42. package/lib/frameworks/next/interfaces.js +2 -0
  43. package/lib/frameworks/next/utils.js +92 -0
  44. package/lib/frameworks/nuxt/index.js +3 -0
  45. package/lib/frameworks/utils.js +24 -0
  46. package/lib/frameworks/vite/index.js +4 -1
  47. package/lib/gcp/eventarc.js +42 -0
  48. package/lib/init/features/emulators.js +1 -1
  49. package/npm-shrinkwrap.json +2 -93
  50. package/package.json +1 -4
  51. package/schema/firebase-config.json +4 -2
@@ -7,16 +7,22 @@ const path_1 = require("path");
7
7
  const fs_extra_1 = require("fs-extra");
8
8
  const url_1 = require("url");
9
9
  const fs_1 = require("fs");
10
+ const semver_1 = require("semver");
11
+ const clc = require("colorette");
10
12
  const __1 = require("..");
11
13
  const prompt_1 = require("../../prompt");
12
- const semver_1 = require("semver");
13
- const logger_1 = require("../../logger");
14
14
  const error_1 = require("../../error");
15
- const fsutils_1 = require("../../fsutils");
16
- const CLI_COMMAND = (0, path_1.join)("node_modules", ".bin", process.platform === "win32" ? "next.cmd" : "next");
15
+ const utils_1 = require("./utils");
16
+ const utils_2 = require("../utils");
17
+ const utils_3 = require("../utils");
18
+ const utils_4 = require("./utils");
19
+ const constants_1 = require("./constants");
20
+ const DEFAULT_BUILD_SCRIPT = ["next build"];
21
+ const PUBLIC_DIR = "public";
17
22
  exports.name = "Next.js";
18
23
  exports.support = "experimental";
19
24
  exports.type = 2;
25
+ const DEFAULT_NUMBER_OF_REASONS_TO_LIST = 5;
20
26
  function getNextVersion(cwd) {
21
27
  var _a;
22
28
  return (_a = (0, __1.findDependency)("next", { cwd, depth: 0, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
@@ -30,11 +36,13 @@ async function discover(dir) {
30
36
  return;
31
37
  if (!(await (0, fs_extra_1.pathExists)("next.config.js")) && !getNextVersion(dir))
32
38
  return;
33
- return { mayWantBackend: true, publicDirectory: (0, path_1.join)(dir, "public") };
39
+ return { mayWantBackend: true, publicDirectory: (0, path_1.join)(dir, PUBLIC_DIR) };
34
40
  }
35
41
  exports.discover = discover;
36
42
  async function build(dir) {
43
+ var _a, _b;
37
44
  const { default: nextBuild } = (0, __1.relativeRequire)(dir, "next/dist/build");
45
+ await (0, utils_3.warnIfCustomBuildScript)(dir, exports.name, DEFAULT_BUILD_SCRIPT);
38
46
  const reactVersion = getReactVersion(dir);
39
47
  if (reactVersion && (0, semver_1.gte)(reactVersion, "18.0.0")) {
40
48
  process.env.__NEXT_REACT_ROOT = "true";
@@ -43,54 +51,89 @@ async function build(dir) {
43
51
  console.error(e.message);
44
52
  throw e;
45
53
  });
46
- try {
47
- (0, child_process_1.execSync)(`${CLI_COMMAND} export`, { cwd: dir, stdio: "ignore" });
54
+ const reasonsForBackend = [];
55
+ const { distDir } = await getConfig(dir);
56
+ if (await (0, utils_1.isUsingMiddleware)((0, path_1.join)(dir, distDir), false)) {
57
+ reasonsForBackend.push("middleware");
48
58
  }
49
- catch (e) {
59
+ if (await (0, utils_1.isUsingImageOptimization)((0, path_1.join)(dir, distDir))) {
60
+ reasonsForBackend.push(`Image Optimization`);
50
61
  }
51
- let wantsBackend = true;
52
- const { distDir } = await getConfig(dir);
53
- const exportDetailPath = (0, path_1.join)(dir, distDir, "export-detail.json");
54
- const exportDetailExists = await (0, fs_extra_1.pathExists)(exportDetailPath);
55
- const exportDetailBuffer = exportDetailExists ? await (0, promises_1.readFile)(exportDetailPath) : undefined;
56
- const exportDetailJson = exportDetailBuffer && JSON.parse(exportDetailBuffer.toString());
57
- if (exportDetailJson === null || exportDetailJson === void 0 ? void 0 : exportDetailJson.success) {
58
- const appPathRoutesManifestPath = (0, path_1.join)(dir, distDir, "app-path-routes-manifest.json");
59
- const appPathRoutesManifestJSON = (0, fsutils_1.fileExistsSync)(appPathRoutesManifestPath)
60
- ? await (0, promises_1.readFile)(appPathRoutesManifestPath).then((it) => JSON.parse(it.toString()))
61
- : {};
62
- const prerenderManifestJSON = await (0, promises_1.readFile)((0, path_1.join)(dir, distDir, "prerender-manifest.json")).then((it) => JSON.parse(it.toString()));
63
- const anyDynamicRouteFallbacks = !!Object.values(prerenderManifestJSON.dynamicRoutes || {}).find((it) => it.fallback !== false);
64
- const pagesManifestJSON = await (0, promises_1.readFile)((0, path_1.join)(dir, distDir, "server", "pages-manifest.json")).then((it) => JSON.parse(it.toString()));
65
- const prerenderedRoutes = Object.keys(prerenderManifestJSON.routes);
66
- const dynamicRoutes = Object.keys(prerenderManifestJSON.dynamicRoutes);
67
- const unrenderedPages = [
68
- ...Object.keys(pagesManifestJSON),
69
- ...Object.values(appPathRoutesManifestJSON),
70
- ].filter((it) => !(["/_app", "/", "/_error", "/_document", "/404"].includes(it) ||
71
- prerenderedRoutes.includes(it) ||
72
- dynamicRoutes.includes(it)));
73
- if (!anyDynamicRouteFallbacks && unrenderedPages.length === 0) {
74
- wantsBackend = false;
62
+ if ((0, utils_1.isUsingAppDirectory)((0, path_1.join)(dir, distDir))) {
63
+ reasonsForBackend.push("app directory (unstable)");
64
+ }
65
+ const prerenderManifest = await (0, utils_2.readJSON)((0, path_1.join)(dir, distDir, constants_1.PRERENDER_MANIFEST));
66
+ const dynamicRoutesWithFallback = Object.entries(prerenderManifest.dynamicRoutes || {}).filter(([, it]) => it.fallback !== false);
67
+ if (dynamicRoutesWithFallback.length > 0) {
68
+ for (const [key] of dynamicRoutesWithFallback) {
69
+ reasonsForBackend.push(`use of fallback ${key}`);
70
+ }
71
+ }
72
+ const routesWithRevalidate = Object.entries(prerenderManifest.routes).filter(([, it]) => it.initialRevalidateSeconds);
73
+ if (routesWithRevalidate.length > 0) {
74
+ for (const [key] of routesWithRevalidate) {
75
+ reasonsForBackend.push(`use of revalidate ${key}`);
75
76
  }
76
77
  }
77
- const manifestBuffer = await (0, promises_1.readFile)((0, path_1.join)(dir, distDir, "routes-manifest.json"));
78
- const manifest = JSON.parse(manifestBuffer.toString());
78
+ const pagesManifestJSON = await (0, utils_2.readJSON)((0, path_1.join)(dir, distDir, "server", constants_1.PAGES_MANIFEST));
79
+ const prerenderedRoutes = Object.keys(prerenderManifest.routes);
80
+ const dynamicRoutes = Object.keys(prerenderManifest.dynamicRoutes);
81
+ const unrenderedPages = Object.keys(pagesManifestJSON).filter((it) => !(["/_app", "/", "/_error", "/_document", "/404"].includes(it) ||
82
+ prerenderedRoutes.includes(it) ||
83
+ dynamicRoutes.includes(it)));
84
+ if (unrenderedPages.length > 0) {
85
+ for (const key of unrenderedPages) {
86
+ reasonsForBackend.push(`non-static route ${key}`);
87
+ }
88
+ }
89
+ const manifest = await (0, utils_2.readJSON)((0, path_1.join)(dir, distDir, constants_1.ROUTES_MANIFEST));
79
90
  const { headers: nextJsHeaders = [], redirects: nextJsRedirects = [], rewrites: nextJsRewrites = [], } = manifest;
80
- const headers = nextJsHeaders.map(({ source, headers }) => ({ source, headers }));
91
+ const isEveryHeaderSupported = nextJsHeaders.every(utils_1.isHeaderSupportedByHosting);
92
+ if (!isEveryHeaderSupported) {
93
+ reasonsForBackend.push("advanced headers");
94
+ }
95
+ const headers = nextJsHeaders.filter(utils_1.isHeaderSupportedByHosting).map(({ source, headers }) => ({
96
+ source: (0, utils_1.cleanEscapedChars)(source),
97
+ headers,
98
+ }));
99
+ const isEveryRedirectSupported = nextJsRedirects.every(utils_1.isRedirectSupportedByHosting);
100
+ if (!isEveryRedirectSupported) {
101
+ reasonsForBackend.push("advanced redirects");
102
+ }
81
103
  const redirects = nextJsRedirects
82
- .filter(({ internal }) => !internal)
83
- .map(({ source, destination, statusCode: type }) => ({ source, destination, type }));
84
- const nextJsRewritesToUse = Array.isArray(nextJsRewrites)
85
- ? nextJsRewrites
86
- : nextJsRewrites.beforeFiles || [];
104
+ .filter(utils_1.isRedirectSupportedByHosting)
105
+ .map(({ source, destination, statusCode: type }) => ({
106
+ source: (0, utils_1.cleanEscapedChars)(source),
107
+ destination,
108
+ type,
109
+ }));
110
+ const nextJsRewritesToUse = (0, utils_1.getNextjsRewritesToUse)(nextJsRewrites);
111
+ if (!Array.isArray(nextJsRewrites) &&
112
+ (((_a = nextJsRewrites.afterFiles) === null || _a === void 0 ? void 0 : _a.length) || ((_b = nextJsRewrites.fallback) === null || _b === void 0 ? void 0 : _b.length))) {
113
+ reasonsForBackend.push("advanced rewrites");
114
+ }
115
+ const isEveryRewriteSupported = nextJsRewritesToUse.every(utils_1.isRewriteSupportedByHosting);
116
+ if (!isEveryRewriteSupported) {
117
+ reasonsForBackend.push("advanced rewrites");
118
+ }
87
119
  const rewrites = nextJsRewritesToUse
88
- .map(({ source, destination, has }) => {
89
- if (has)
90
- return undefined;
91
- return { source, destination };
92
- })
93
- .filter((it) => it);
120
+ .filter(utils_1.isRewriteSupportedByHosting)
121
+ .map(({ source, destination }) => ({
122
+ source: (0, utils_1.cleanEscapedChars)(source),
123
+ destination,
124
+ }));
125
+ const wantsBackend = reasonsForBackend.length > 0;
126
+ if (wantsBackend) {
127
+ const numberOfReasonsToList = process.env.DEBUG ? Infinity : DEFAULT_NUMBER_OF_REASONS_TO_LIST;
128
+ console.log("Building a Cloud Function to run this application. This is needed due to:");
129
+ for (const reason of reasonsForBackend.slice(0, numberOfReasonsToList)) {
130
+ console.log(` • ${reason}`);
131
+ }
132
+ if (reasonsForBackend.length > numberOfReasonsToList) {
133
+ console.log(` • and ${reasonsForBackend.length - numberOfReasonsToList} other reasons, use --debug to see more`);
134
+ }
135
+ console.log("");
136
+ }
94
137
  return { wantsBackend, headers, redirects, rewrites };
95
138
  }
96
139
  exports.build = build;
@@ -106,111 +149,111 @@ async function init(setup) {
106
149
  exports.init = init;
107
150
  async function ɵcodegenPublicDirectory(sourceDir, destDir) {
108
151
  const { distDir } = await getConfig(sourceDir);
109
- const exportDetailPath = (0, path_1.join)(sourceDir, distDir, "export-detail.json");
110
- const exportDetailExists = await (0, fs_extra_1.pathExists)(exportDetailPath);
111
- const exportDetailBuffer = exportDetailExists ? await (0, promises_1.readFile)(exportDetailPath) : undefined;
112
- const exportDetailJson = exportDetailBuffer && JSON.parse(exportDetailBuffer.toString());
113
- if (exportDetailJson === null || exportDetailJson === void 0 ? void 0 : exportDetailJson.success) {
114
- (0, fs_extra_1.copy)(exportDetailJson.outDirectory, destDir);
115
- }
116
- else {
117
- const publicPath = (0, path_1.join)(sourceDir, "public");
118
- await (0, promises_1.mkdir)((0, path_1.join)(destDir, "_next", "static"), { recursive: true });
119
- if (await (0, fs_extra_1.pathExists)(publicPath)) {
120
- await (0, fs_extra_1.copy)(publicPath, destDir);
152
+ const publicPath = (0, path_1.join)(sourceDir, "public");
153
+ await (0, promises_1.mkdir)((0, path_1.join)(destDir, "_next", "static"), { recursive: true });
154
+ if (await (0, fs_extra_1.pathExists)(publicPath)) {
155
+ await (0, fs_extra_1.copy)(publicPath, destDir);
156
+ }
157
+ await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, distDir, "static"), (0, path_1.join)(destDir, "_next", "static"));
158
+ for (const file of ["index.html", "404.html", "500.html"]) {
159
+ const pagesPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", file);
160
+ if (await (0, fs_extra_1.pathExists)(pagesPath)) {
161
+ await (0, promises_1.copyFile)(pagesPath, (0, path_1.join)(destDir, file));
162
+ continue;
121
163
  }
122
- await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, distDir, "static"), (0, path_1.join)(destDir, "_next", "static"));
123
- for (const file of ["index.html", "404.html", "500.html"]) {
124
- const pagesPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", file);
125
- if (await (0, fs_extra_1.pathExists)(pagesPath)) {
126
- await (0, promises_1.copyFile)(pagesPath, (0, path_1.join)(destDir, file));
127
- continue;
128
- }
129
- const appPath = (0, path_1.join)(sourceDir, distDir, "server", "app", file);
130
- if (await (0, fs_extra_1.pathExists)(appPath)) {
131
- await (0, promises_1.copyFile)(appPath, (0, path_1.join)(destDir, file));
132
- }
164
+ const appPath = (0, path_1.join)(sourceDir, distDir, "server", "app", file);
165
+ if (await (0, fs_extra_1.pathExists)(appPath)) {
166
+ await (0, promises_1.copyFile)(appPath, (0, path_1.join)(destDir, file));
133
167
  }
134
- const prerenderManifestBuffer = await (0, promises_1.readFile)((0, path_1.join)(sourceDir, distDir, "prerender-manifest.json"));
135
- const prerenderManifest = JSON.parse(prerenderManifestBuffer.toString());
136
- for (const path in prerenderManifest.routes) {
137
- if (prerenderManifest.routes[path]) {
138
- const { initialRevalidateSeconds } = prerenderManifest.routes[path];
139
- if (initialRevalidateSeconds) {
140
- continue;
141
- }
142
- const parts = path
143
- .split("/")
144
- .slice(1)
145
- .filter((it) => !!it);
146
- const partsOrIndex = parts.length > 0 ? parts : ["index"];
147
- const dataPath = `${(0, path_1.join)(...partsOrIndex)}.json`;
148
- const htmlPath = `${(0, path_1.join)(...partsOrIndex)}.html`;
149
- await (0, promises_1.mkdir)((0, path_1.join)(destDir, (0, path_1.dirname)(htmlPath)), { recursive: true });
150
- const pagesHtmlPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", htmlPath);
151
- if (await (0, fs_extra_1.pathExists)(pagesHtmlPath)) {
152
- await (0, promises_1.copyFile)(pagesHtmlPath, (0, path_1.join)(destDir, htmlPath));
153
- }
154
- else {
155
- const appHtmlPath = (0, path_1.join)(sourceDir, distDir, "server", "app", htmlPath);
156
- if (await (0, fs_extra_1.pathExists)(appHtmlPath)) {
157
- await (0, promises_1.copyFile)(appHtmlPath, (0, path_1.join)(destDir, htmlPath));
158
- }
159
- }
160
- const dataRoute = prerenderManifest.routes[path].dataRoute;
161
- await (0, promises_1.mkdir)((0, path_1.join)(destDir, (0, path_1.dirname)(dataRoute)), { recursive: true });
162
- const pagesDataPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", dataPath);
163
- if (await (0, fs_extra_1.pathExists)(pagesDataPath)) {
164
- await (0, promises_1.copyFile)(pagesDataPath, (0, path_1.join)(destDir, dataRoute));
165
- }
166
- else {
167
- const appDataPath = (0, path_1.join)(sourceDir, distDir, "server", "app", dataPath);
168
- if (await (0, fs_extra_1.pathExists)(appDataPath)) {
169
- await (0, promises_1.copyFile)(appDataPath, (0, path_1.join)(destDir, dataRoute));
170
- }
171
- }
172
- }
168
+ }
169
+ const [middlewareManifest, prerenderManifest, routesManifest] = await Promise.all([
170
+ (0, utils_2.readJSON)((0, path_1.join)(sourceDir, distDir, "server", constants_1.MIDDLEWARE_MANIFEST)),
171
+ (0, utils_2.readJSON)((0, path_1.join)(sourceDir, distDir, constants_1.PRERENDER_MANIFEST)),
172
+ (0, utils_2.readJSON)((0, path_1.join)(sourceDir, distDir, constants_1.ROUTES_MANIFEST)),
173
+ ]);
174
+ const middlewareMatcherRegexes = Object.values(middlewareManifest.middleware)
175
+ .map((it) => it.matchers)
176
+ .flat()
177
+ .map((it) => new RegExp(it.regexp));
178
+ const { redirects = [], rewrites = [], headers = [] } = routesManifest;
179
+ const rewritesRegexesNotSupportedByHosting = (0, utils_1.getNextjsRewritesToUse)(rewrites)
180
+ .filter((rewrite) => !(0, utils_1.isRewriteSupportedByHosting)(rewrite))
181
+ .map((rewrite) => new RegExp(rewrite.regex));
182
+ const redirectsRegexesNotSupportedByHosting = redirects
183
+ .filter((redirect) => !(0, utils_1.isRedirectSupportedByHosting)(redirect))
184
+ .map((redirect) => new RegExp(redirect.regex));
185
+ const headersRegexesNotSupportedByHosting = headers
186
+ .filter((header) => !(0, utils_1.isHeaderSupportedByHosting)(header))
187
+ .map((header) => new RegExp(header.regex));
188
+ const pathsUsingsFeaturesNotSupportedByHosting = [
189
+ ...middlewareMatcherRegexes,
190
+ ...rewritesRegexesNotSupportedByHosting,
191
+ ...redirectsRegexesNotSupportedByHosting,
192
+ ...headersRegexesNotSupportedByHosting,
193
+ ];
194
+ for (const [path, route] of Object.entries(prerenderManifest.routes)) {
195
+ if (route.initialRevalidateSeconds ||
196
+ pathsUsingsFeaturesNotSupportedByHosting.some((it) => path.match(it))) {
197
+ continue;
198
+ }
199
+ const isReactServerComponent = route.dataRoute.endsWith(".rsc");
200
+ const contentDist = (0, path_1.join)(sourceDir, distDir, "server", isReactServerComponent ? "app" : "pages");
201
+ const parts = path.split("/").filter((it) => !!it);
202
+ const partsOrIndex = parts.length > 0 ? parts : ["index"];
203
+ const htmlPath = `${(0, path_1.join)(...partsOrIndex)}.html`;
204
+ await (0, promises_1.mkdir)((0, path_1.join)(destDir, (0, path_1.dirname)(htmlPath)), { recursive: true });
205
+ await (0, promises_1.copyFile)((0, path_1.join)(contentDist, htmlPath), (0, path_1.join)(destDir, htmlPath));
206
+ if (!isReactServerComponent) {
207
+ const dataPath = `${(0, path_1.join)(...partsOrIndex)}.json`;
208
+ await (0, promises_1.mkdir)((0, path_1.join)(destDir, (0, path_1.dirname)(route.dataRoute)), { recursive: true });
209
+ await (0, promises_1.copyFile)((0, path_1.join)(contentDist, dataPath), (0, path_1.join)(destDir, route.dataRoute));
173
210
  }
174
211
  }
175
212
  }
176
213
  exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
177
214
  async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
178
215
  const { distDir } = await getConfig(sourceDir);
179
- const packageJsonBuffer = await (0, promises_1.readFile)((0, path_1.join)(sourceDir, "package.json"));
180
- const packageJson = JSON.parse(packageJsonBuffer.toString());
216
+ const packageJson = await (0, utils_2.readJSON)((0, path_1.join)(sourceDir, "package.json"));
181
217
  if ((0, fs_1.existsSync)((0, path_1.join)(sourceDir, "next.config.js"))) {
182
- let esbuild;
183
- try {
184
- esbuild = await Promise.resolve().then(() => require("esbuild"));
185
- }
186
- catch (e) {
187
- logger_1.logger.debug(`Failed to load 'esbuild': ${e}`);
188
- throw new error_1.FirebaseError(`Unable to find 'esbuild'. Install it into your local dev dependencies with 'npm i --save-dev esbuild''`);
189
- }
190
- await esbuild.build({
191
- bundle: true,
192
- external: Object.keys(packageJson.dependencies),
193
- absWorkingDir: sourceDir,
194
- entryPoints: ["next.config.js"],
195
- outfile: (0, path_1.join)(destDir, "next.config.js"),
196
- target: `node${__1.NODE_VERSION}`,
197
- platform: "node",
218
+ const dependencyTree = JSON.parse((0, child_process_1.spawnSync)("npm", ["ls", "--omit=dev", "--all", "--json"], {
219
+ cwd: sourceDir,
220
+ }).stdout.toString());
221
+ const esbuildArgs = (0, utils_1.allDependencyNames)(dependencyTree)
222
+ .map((it) => `--external:${it}`)
223
+ .concat("--bundle", "--platform=node", `--target=node${__1.NODE_VERSION}`, `--outdir=${destDir}`, "--log-level=error");
224
+ const bundle = (0, child_process_1.spawnSync)("npx", ["--yes", "esbuild", "next.config.js", ...esbuildArgs], {
225
+ cwd: sourceDir,
198
226
  });
227
+ if (bundle.status) {
228
+ console.error(bundle.stderr.toString());
229
+ throw new error_1.FirebaseError("Unable to bundle next.config.js for use in Cloud Functions");
230
+ }
199
231
  }
200
232
  if (await (0, fs_extra_1.pathExists)((0, path_1.join)(sourceDir, "public"))) {
201
233
  await (0, promises_1.mkdir)((0, path_1.join)(destDir, "public"));
202
234
  await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, "public"), (0, path_1.join)(destDir, "public"));
203
235
  }
236
+ if (!(await (0, utils_4.hasUnoptimizedImage)(sourceDir, distDir)) &&
237
+ ((0, utils_4.usesAppDirRouter)(sourceDir) || (await (0, utils_4.usesNextImage)(sourceDir, distDir)))) {
238
+ packageJson.dependencies["sharp"] = "latest";
239
+ }
204
240
  await (0, fs_extra_1.mkdirp)((0, path_1.join)(destDir, distDir));
205
241
  await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, distDir), (0, path_1.join)(destDir, distDir));
206
242
  return { packageJson, frameworksEntry: "next.js" };
207
243
  }
208
244
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
209
- async function getDevModeHandle(dir) {
245
+ async function getDevModeHandle(dir, hostingEmulatorInfo) {
246
+ if (!hostingEmulatorInfo) {
247
+ if (await (0, utils_1.isUsingMiddleware)(dir, true)) {
248
+ throw new error_1.FirebaseError(`${clc.bold("firebase serve")} does not support Next.js Middleware. Please use ${clc.bold("firebase emulators:start")} instead.`);
249
+ }
250
+ }
210
251
  const { default: next } = (0, __1.relativeRequire)(dir, "next");
211
252
  const nextApp = next({
212
253
  dev: true,
213
254
  dir,
255
+ hostname: hostingEmulatorInfo === null || hostingEmulatorInfo === void 0 ? void 0 : hostingEmulatorInfo.host,
256
+ port: hostingEmulatorInfo === null || hostingEmulatorInfo === void 0 ? void 0 : hostingEmulatorInfo.port,
214
257
  });
215
258
  const handler = nextApp.getRequestHandler();
216
259
  await nextApp.prepare();
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.allDependencyNames = exports.isUsingAppDirectory = exports.isUsingImageOptimization = exports.isUsingMiddleware = exports.hasUnoptimizedImage = exports.usesNextImage = exports.usesAppDirRouter = exports.getNextjsRewritesToUse = exports.isHeaderSupportedByHosting = exports.isRedirectSupportedByHosting = exports.isRewriteSupportedByHosting = exports.cleanEscapedChars = exports.pathHasRegex = void 0;
4
+ const fs_1 = require("fs");
5
+ const fs_extra_1 = require("fs-extra");
6
+ const path_1 = require("path");
7
+ const utils_1 = require("../utils");
8
+ const constants_1 = require("./constants");
9
+ const fsutils_1 = require("../../fsutils");
10
+ function pathHasRegex(path) {
11
+ return /(?<!\\)\(/.test(path);
12
+ }
13
+ exports.pathHasRegex = pathHasRegex;
14
+ function cleanEscapedChars(path) {
15
+ return path.replace(/\\([(){}:+?*])/g, (a, b) => b);
16
+ }
17
+ exports.cleanEscapedChars = cleanEscapedChars;
18
+ function isRewriteSupportedByHosting(rewrite) {
19
+ return !("has" in rewrite || pathHasRegex(rewrite.source) || (0, utils_1.isUrl)(rewrite.destination));
20
+ }
21
+ exports.isRewriteSupportedByHosting = isRewriteSupportedByHosting;
22
+ function isRedirectSupportedByHosting(redirect) {
23
+ return !("has" in redirect || pathHasRegex(redirect.source) || "internal" in redirect);
24
+ }
25
+ exports.isRedirectSupportedByHosting = isRedirectSupportedByHosting;
26
+ function isHeaderSupportedByHosting(header) {
27
+ return !("has" in header || pathHasRegex(header.source));
28
+ }
29
+ exports.isHeaderSupportedByHosting = isHeaderSupportedByHosting;
30
+ function getNextjsRewritesToUse(nextJsRewrites) {
31
+ if (Array.isArray(nextJsRewrites)) {
32
+ return nextJsRewrites;
33
+ }
34
+ if (nextJsRewrites === null || nextJsRewrites === void 0 ? void 0 : nextJsRewrites.beforeFiles) {
35
+ return nextJsRewrites.beforeFiles;
36
+ }
37
+ return [];
38
+ }
39
+ exports.getNextjsRewritesToUse = getNextjsRewritesToUse;
40
+ function usesAppDirRouter(sourceDir) {
41
+ const appPathRoutesManifestPath = (0, path_1.join)(sourceDir, constants_1.APP_PATH_ROUTES_MANIFEST);
42
+ return (0, fs_1.existsSync)(appPathRoutesManifestPath);
43
+ }
44
+ exports.usesAppDirRouter = usesAppDirRouter;
45
+ async function usesNextImage(sourceDir, distDir) {
46
+ const exportMarker = await (0, utils_1.readJSON)((0, path_1.join)(sourceDir, distDir, constants_1.EXPORT_MARKER));
47
+ return exportMarker.isNextImageImported;
48
+ }
49
+ exports.usesNextImage = usesNextImage;
50
+ async function hasUnoptimizedImage(sourceDir, distDir) {
51
+ const imagesManifest = await (0, utils_1.readJSON)((0, path_1.join)(sourceDir, distDir, constants_1.IMAGES_MANIFEST));
52
+ return imagesManifest.images.unoptimized;
53
+ }
54
+ exports.hasUnoptimizedImage = hasUnoptimizedImage;
55
+ async function isUsingMiddleware(dir, isDevMode) {
56
+ if (isDevMode) {
57
+ const [middlewareJs, middlewareTs] = await Promise.all([
58
+ (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "middleware.js")),
59
+ (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "middleware.ts")),
60
+ ]);
61
+ return middlewareJs || middlewareTs;
62
+ }
63
+ else {
64
+ const middlewareManifest = await (0, utils_1.readJSON)((0, path_1.join)(dir, "server", constants_1.MIDDLEWARE_MANIFEST));
65
+ return Object.keys(middlewareManifest.middleware).length > 0;
66
+ }
67
+ }
68
+ exports.isUsingMiddleware = isUsingMiddleware;
69
+ async function isUsingImageOptimization(dir) {
70
+ const { isNextImageImported } = await (0, utils_1.readJSON)((0, path_1.join)(dir, constants_1.EXPORT_MARKER));
71
+ if (isNextImageImported) {
72
+ const imagesManifest = await (0, utils_1.readJSON)((0, path_1.join)(dir, constants_1.IMAGES_MANIFEST));
73
+ const usingImageOptimization = imagesManifest.images.unoptimized === false;
74
+ if (usingImageOptimization) {
75
+ return true;
76
+ }
77
+ }
78
+ return false;
79
+ }
80
+ exports.isUsingImageOptimization = isUsingImageOptimization;
81
+ function isUsingAppDirectory(dir) {
82
+ const appPathRoutesManifestPath = (0, path_1.join)(dir, constants_1.APP_PATH_ROUTES_MANIFEST);
83
+ return (0, fsutils_1.fileExistsSync)(appPathRoutesManifestPath);
84
+ }
85
+ exports.isUsingAppDirectory = isUsingAppDirectory;
86
+ function allDependencyNames(mod) {
87
+ if (!mod.dependencies)
88
+ return [];
89
+ const dependencyNames = Object.keys(mod.dependencies).reduce((acc, it) => [...acc, it, ...allDependencyNames(mod.dependencies[it])], []);
90
+ return [...new Set(dependencyNames)];
91
+ }
92
+ exports.allDependencyNames = allDependencyNames;
@@ -6,9 +6,11 @@ const promises_1 = require("fs/promises");
6
6
  const path_1 = require("path");
7
7
  const semver_1 = require("semver");
8
8
  const __1 = require("..");
9
+ const utils_1 = require("../utils");
9
10
  exports.name = "Nuxt";
10
11
  exports.support = "experimental";
11
12
  exports.type = 4;
13
+ const DEFAULT_BUILD_SCRIPT = ["nuxt build"];
12
14
  async function discover(dir) {
13
15
  if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "package.json"))))
14
16
  return;
@@ -26,6 +28,7 @@ exports.discover = discover;
26
28
  async function build(root) {
27
29
  const { buildNuxt } = await (0, __1.relativeRequire)(root, "@nuxt/kit");
28
30
  const nuxtApp = await getNuxtApp(root);
31
+ await (0, utils_1.warnIfCustomBuildScript)(root, exports.name, DEFAULT_BUILD_SCRIPT);
29
32
  await buildNuxt(nuxtApp);
30
33
  return { wantsBackend: true };
31
34
  }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.warnIfCustomBuildScript = exports.readJSON = exports.isUrl = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const path_1 = require("path");
6
+ const promises_1 = require("fs/promises");
7
+ function isUrl(url) {
8
+ return /^https?:\/\//.test(url);
9
+ }
10
+ exports.isUrl = isUrl;
11
+ function readJSON(file, options) {
12
+ return (0, fs_extra_1.readJSON)(file, options);
13
+ }
14
+ exports.readJSON = readJSON;
15
+ async function warnIfCustomBuildScript(dir, framework, defaultBuildScripts) {
16
+ var _a;
17
+ const packageJsonBuffer = await (0, promises_1.readFile)((0, path_1.join)(dir, "package.json"));
18
+ const packageJson = JSON.parse(packageJsonBuffer.toString());
19
+ const buildScript = (_a = packageJson.scripts) === null || _a === void 0 ? void 0 : _a.build;
20
+ if (buildScript && !defaultBuildScripts.includes(buildScript)) {
21
+ console.warn(`\nWARNING: Your package.json contains a custom build that is being ignored. Only the ${framework} default build script (e.g, "${defaultBuildScripts[0]}") is respected. If you have a more advanced build process you should build a custom integration https://firebase.google.com/docs/hosting/express\n`);
22
+ }
23
+ }
24
+ exports.warnIfCustomBuildScript = warnIfCustomBuildScript;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDevModeHandle = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.vitePluginDiscover = exports.viteDiscoverWithNpmDependency = exports.init = exports.initViteTemplate = exports.type = exports.support = exports.name = void 0;
3
+ exports.getDevModeHandle = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.vitePluginDiscover = exports.viteDiscoverWithNpmDependency = exports.init = exports.initViteTemplate = exports.DEFAULT_BUILD_SCRIPT = exports.type = exports.support = exports.name = void 0;
4
4
  const child_process_1 = require("child_process");
5
5
  const fs_1 = require("fs");
6
6
  const fs_extra_1 = require("fs-extra");
@@ -8,10 +8,12 @@ const path_1 = require("path");
8
8
  const __1 = require("..");
9
9
  const proxy_1 = require("../../hosting/proxy");
10
10
  const prompt_1 = require("../../prompt");
11
+ const utils_1 = require("../utils");
11
12
  exports.name = "Vite";
12
13
  exports.support = "experimental";
13
14
  exports.type = 4;
14
15
  const CLI_COMMAND = (0, path_1.join)("node_modules", ".bin", process.platform === "win32" ? "vite.cmd" : "vite");
16
+ exports.DEFAULT_BUILD_SCRIPT = ["vite build", "tsc && vite build"];
15
17
  const initViteTemplate = (template) => async (setup) => await init(setup, template);
16
18
  exports.initViteTemplate = initViteTemplate;
17
19
  async function init(setup, baseTemplate = "vanilla") {
@@ -56,6 +58,7 @@ async function discover(dir, plugin, npmDependency) {
56
58
  exports.discover = discover;
57
59
  async function build(root) {
58
60
  const { build } = (0, __1.relativeRequire)(root, "vite");
61
+ await (0, utils_1.warnIfCustomBuildScript)(root, exports.name, exports.DEFAULT_BUILD_SCRIPT);
59
62
  await build({ root });
60
63
  }
61
64
  exports.build = build;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteChannel = exports.updateChannel = exports.createChannel = exports.getChannel = exports.API_VERSION = void 0;
4
+ const apiv2_1 = require("../apiv2");
5
+ const api_1 = require("../api");
6
+ const lodash_1 = require("lodash");
7
+ const proto_1 = require("./proto");
8
+ exports.API_VERSION = "v1";
9
+ const client = new apiv2_1.Client({
10
+ urlPrefix: api_1.eventarcOrigin,
11
+ auth: true,
12
+ apiVersion: exports.API_VERSION,
13
+ });
14
+ async function getChannel(name) {
15
+ const res = await client.get(name);
16
+ if (res.status === 404) {
17
+ return undefined;
18
+ }
19
+ return res.body;
20
+ }
21
+ exports.getChannel = getChannel;
22
+ async function createChannel(channel) {
23
+ const pathParts = channel.name.split("/");
24
+ const res = await client.post(pathParts.slice(0, -1).join("/"), channel, {
25
+ queryParams: { channelId: (0, lodash_1.last)(pathParts) },
26
+ });
27
+ return res.body;
28
+ }
29
+ exports.createChannel = createChannel;
30
+ async function updateChannel(channel) {
31
+ const res = await client.put(channel.name, channel, {
32
+ queryParams: {
33
+ updateMask: (0, proto_1.fieldMasks)(channel).join(","),
34
+ },
35
+ });
36
+ return res.body;
37
+ }
38
+ exports.updateChannel = updateChannel;
39
+ async function deleteChannel(name) {
40
+ await client.delete(name);
41
+ }
42
+ exports.deleteChannel = deleteChannel;
@@ -81,7 +81,7 @@ async function doSetup(setup, config) {
81
81
  name: "download",
82
82
  type: "confirm",
83
83
  message: "Would you like to download the emulators now?",
84
- default: false,
84
+ default: true,
85
85
  },
86
86
  ]);
87
87
  }