firebase-tools 11.18.0 → 11.20.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 (35) hide show
  1. package/lib/api.js +3 -2
  2. package/lib/bin/firebase.js +0 -0
  3. package/lib/commands/functions-delete.js +1 -1
  4. package/lib/commands/index.js +5 -0
  5. package/lib/commands/internaltesting-functions-discover.js +25 -0
  6. package/lib/deploy/extensions/prepare.js +6 -1
  7. package/lib/deploy/extensions/v2FunctionHelper.js +53 -0
  8. package/lib/deploy/functions/build.js +17 -2
  9. package/lib/deploy/functions/cel.js +90 -13
  10. package/lib/deploy/functions/params.js +141 -6
  11. package/lib/deploy/functions/prepare.js +40 -25
  12. package/lib/deploy/functions/release/fabricator.js +27 -1
  13. package/lib/deploy/functions/runtimes/discovery/parsing.js +7 -1
  14. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +1 -1
  15. package/lib/deploy/functions/runtimes/node/index.js +2 -2
  16. package/lib/deploy/functions/runtimes/node/versioning.js +30 -14
  17. package/lib/emulator/auth/operations.js +1 -1
  18. package/lib/emulator/commandUtils.js +2 -1
  19. package/lib/emulator/downloadableEmulators.js +6 -6
  20. package/lib/emulator/env.js +29 -27
  21. package/lib/emulator/extensionsEmulator.js +14 -9
  22. package/lib/emulator/functionsEmulator.js +16 -8
  23. package/lib/emulator/pubsubEmulator.js +13 -1
  24. package/lib/emulator/storage/rules/runtime.js +2 -2
  25. package/lib/emulator/workQueue.js +11 -6
  26. package/lib/experiments.js +6 -0
  27. package/lib/extensions/emulator/triggerHelper.js +12 -2
  28. package/lib/frameworks/index.js +7 -1
  29. package/lib/frameworks/next/constants.js +10 -0
  30. package/lib/frameworks/next/index.js +146 -146
  31. package/lib/frameworks/next/utils.js +65 -7
  32. package/lib/gcp/eventarc.js +42 -0
  33. package/lib/serve/hosting.js +5 -5
  34. package/npm-shrinkwrap.json +463 -737
  35. package/package.json +2 -5
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.functionResourceToEmulatedTriggerDefintion = void 0;
4
- const functionsEmulatorShared_1 = require("../../emulator/functionsEmulatorShared");
5
4
  const emulatorLogger_1 = require("../../emulator/emulatorLogger");
5
+ const functionsEmulatorShared_1 = require("../../emulator/functionsEmulatorShared");
6
6
  const types_1 = require("../../emulator/types");
7
+ const error_1 = require("../../error");
7
8
  const types_2 = require("../../extensions/types");
8
9
  const proto = require("../../gcp/proto");
9
- const error_1 = require("../../error");
10
10
  function functionResourceToEmulatedTriggerDefintion(resource) {
11
11
  const resourceType = resource.type;
12
12
  if (resource.type === types_2.FUNCTIONS_RESOURCE_TYPE) {
@@ -29,6 +29,16 @@ function functionResourceToEmulatedTriggerDefintion(resource) {
29
29
  service: (0, functionsEmulatorShared_1.getServiceFromEventType)(properties.eventTrigger.eventType),
30
30
  };
31
31
  }
32
+ else if (properties.scheduleTrigger) {
33
+ const schedule = {
34
+ schedule: properties.scheduleTrigger.schedule,
35
+ };
36
+ etd.schedule = schedule;
37
+ etd.eventTrigger = {
38
+ eventType: "google.pubsub.topic.publish",
39
+ resource: "",
40
+ };
41
+ }
32
42
  else {
33
43
  emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).log("WARN", `Function '${resource.name} is missing a trigger in extension.yaml. Please add one, as triggers defined in code are ignored.`);
34
44
  }
@@ -230,7 +230,10 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
230
230
  const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, } = exports.WebFrameworks[framework];
231
231
  console.log(`Detected a ${name} codebase. ${SupportLevelWarnings[support] || ""}\n`);
232
232
  const isDevMode = context._name === "serve" || context._name === "emulators:start";
233
- const devModeHandle = isDevMode && getDevModeHandle && (await getDevModeHandle(getProjectPath()));
233
+ const hostingEmulatorInfo = emulators.find((e) => e.name === types_1.Emulators.HOSTING);
234
+ const devModeHandle = isDevMode &&
235
+ getDevModeHandle &&
236
+ (await getDevModeHandle(getProjectPath(), hostingEmulatorInfo));
234
237
  let codegenFunctionsDirectory;
235
238
  if (devModeHandle) {
236
239
  config.public = (0, path_1.relative)(projectRoot, publicDirectory);
@@ -326,6 +329,9 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
326
329
  ${firebaseDefaults ? `__FIREBASE_DEFAULTS__=${JSON.stringify(firebaseDefaults)}\n` : ""}`);
327
330
  await (0, promises_1.copyFile)(getProjectPath("package-lock.json"), (0, path_1.join)(functionsDist, "package-lock.json")).catch(() => {
328
331
  });
332
+ if (await (0, fs_extra_1.pathExists)(getProjectPath(".npmrc"))) {
333
+ await (0, promises_1.copyFile)(getProjectPath(".npmrc"), (0, path_1.join)(functionsDist, ".npmrc"));
334
+ }
329
335
  (0, child_process_1.execSync)(`${NPM_COMMAND} i --omit dev --no-audit`, {
330
336
  cwd: functionsDist,
331
337
  stdio: "inherit",
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ROUTES_MANIFEST = exports.PRERENDER_MANIFEST = exports.PAGES_MANIFEST = exports.MIDDLEWARE_MANIFEST = exports.IMAGES_MANIFEST = exports.EXPORT_MARKER = exports.APP_PATH_ROUTES_MANIFEST = void 0;
4
+ exports.APP_PATH_ROUTES_MANIFEST = "app-path-routes-manifest.json";
5
+ exports.EXPORT_MARKER = "export-marker.json";
6
+ exports.IMAGES_MANIFEST = "images-manifest.json";
7
+ exports.MIDDLEWARE_MANIFEST = "middleware-manifest.json";
8
+ exports.PAGES_MANIFEST = "pages-manifest.json";
9
+ exports.PRERENDER_MANIFEST = "prerender-manifest.json";
10
+ exports.ROUTES_MANIFEST = "routes-manifest.json";
@@ -7,20 +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
15
  const utils_1 = require("./utils");
17
16
  const utils_2 = require("../utils");
18
17
  const utils_3 = require("../utils");
19
- const CLI_COMMAND = (0, path_1.join)("node_modules", ".bin", process.platform === "win32" ? "next.cmd" : "next");
18
+ const utils_4 = require("./utils");
19
+ const constants_1 = require("./constants");
20
20
  const DEFAULT_BUILD_SCRIPT = ["next build"];
21
+ const PUBLIC_DIR = "public";
21
22
  exports.name = "Next.js";
22
23
  exports.support = "experimental";
23
24
  exports.type = 2;
25
+ const DEFAULT_NUMBER_OF_REASONS_TO_LIST = 5;
24
26
  function getNextVersion(cwd) {
25
27
  var _a;
26
28
  return (_a = (0, __1.findDependency)("next", { cwd, depth: 0, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
@@ -34,7 +36,7 @@ async function discover(dir) {
34
36
  return;
35
37
  if (!(await (0, fs_extra_1.pathExists)("next.config.js")) && !getNextVersion(dir))
36
38
  return;
37
- return { mayWantBackend: true, publicDirectory: (0, path_1.join)(dir, "public") };
39
+ return { mayWantBackend: true, publicDirectory: (0, path_1.join)(dir, PUBLIC_DIR) };
38
40
  }
39
41
  exports.discover = discover;
40
42
  async function build(dir) {
@@ -49,51 +51,57 @@ async function build(dir) {
49
51
  console.error(e.message);
50
52
  throw e;
51
53
  });
52
- try {
53
- (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");
54
58
  }
55
- catch (e) {
59
+ if (await (0, utils_1.isUsingImageOptimization)((0, path_1.join)(dir, distDir))) {
60
+ reasonsForBackend.push(`Image Optimization`);
56
61
  }
57
- let wantsBackend = true;
58
- const { distDir } = await getConfig(dir);
59
- const exportDetailPath = (0, path_1.join)(dir, distDir, "export-detail.json");
60
- const exportDetailExists = await (0, fs_extra_1.pathExists)(exportDetailPath);
61
- const exportDetailBuffer = exportDetailExists ? await (0, promises_1.readFile)(exportDetailPath) : undefined;
62
- const exportDetailJson = exportDetailBuffer && JSON.parse(exportDetailBuffer.toString());
63
- if (exportDetailJson === null || exportDetailJson === void 0 ? void 0 : exportDetailJson.success) {
64
- const appPathRoutesManifestPath = (0, path_1.join)(dir, distDir, "app-path-routes-manifest.json");
65
- const appPathRoutesManifestJSON = (0, fsutils_1.fileExistsSync)(appPathRoutesManifestPath)
66
- ? await (0, promises_1.readFile)(appPathRoutesManifestPath).then((it) => JSON.parse(it.toString()))
67
- : {};
68
- const prerenderManifestJSON = await (0, promises_1.readFile)((0, path_1.join)(dir, distDir, "prerender-manifest.json")).then((it) => JSON.parse(it.toString()));
69
- const anyDynamicRouteFallbacks = !!Object.values(prerenderManifestJSON.dynamicRoutes || {}).find((it) => it.fallback !== false);
70
- const pagesManifestJSON = await (0, promises_1.readFile)((0, path_1.join)(dir, distDir, "server", "pages-manifest.json")).then((it) => JSON.parse(it.toString()));
71
- const prerenderedRoutes = Object.keys(prerenderManifestJSON.routes);
72
- const dynamicRoutes = Object.keys(prerenderManifestJSON.dynamicRoutes);
73
- const unrenderedPages = [
74
- ...Object.keys(pagesManifestJSON),
75
- ...Object.values(appPathRoutesManifestJSON),
76
- ].filter((it) => !(["/_app", "/", "/_error", "/_document", "/404"].includes(it) ||
77
- prerenderedRoutes.includes(it) ||
78
- dynamicRoutes.includes(it)));
79
- if (!anyDynamicRouteFallbacks && unrenderedPages.length === 0) {
80
- 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}`);
81
76
  }
82
77
  }
83
- const manifest = await (0, utils_2.readJSON)((0, path_1.join)(dir, distDir, "routes-manifest.json"));
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));
84
90
  const { headers: nextJsHeaders = [], redirects: nextJsRedirects = [], rewrites: nextJsRewrites = [], } = manifest;
85
- const isEveryHeaderSupported = nextJsHeaders.every(utils_1.isHeaderSupportedByFirebase);
86
- if (!isEveryHeaderSupported)
87
- wantsBackend = true;
88
- const headers = nextJsHeaders.filter(utils_1.isHeaderSupportedByFirebase).map(({ 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 }) => ({
89
96
  source: (0, utils_1.cleanEscapedChars)(source),
90
97
  headers,
91
98
  }));
92
- const isEveryRedirectSupported = nextJsRedirects.every(utils_1.isRedirectSupportedByFirebase);
93
- if (!isEveryRedirectSupported)
94
- wantsBackend = true;
99
+ const isEveryRedirectSupported = nextJsRedirects.every(utils_1.isRedirectSupportedByHosting);
100
+ if (!isEveryRedirectSupported) {
101
+ reasonsForBackend.push("advanced redirects");
102
+ }
95
103
  const redirects = nextJsRedirects
96
- .filter(utils_1.isRedirectSupportedByFirebase)
104
+ .filter(utils_1.isRedirectSupportedByHosting)
97
105
  .map(({ source, destination, statusCode: type }) => ({
98
106
  source: (0, utils_1.cleanEscapedChars)(source),
99
107
  destination,
@@ -102,19 +110,30 @@ async function build(dir) {
102
110
  const nextJsRewritesToUse = (0, utils_1.getNextjsRewritesToUse)(nextJsRewrites);
103
111
  if (!Array.isArray(nextJsRewrites) &&
104
112
  (((_a = nextJsRewrites.afterFiles) === null || _a === void 0 ? void 0 : _a.length) || ((_b = nextJsRewrites.fallback) === null || _b === void 0 ? void 0 : _b.length))) {
105
- wantsBackend = true;
113
+ reasonsForBackend.push("advanced rewrites");
106
114
  }
107
- else {
108
- const isEveryRewriteSupported = nextJsRewritesToUse.every(utils_1.isRewriteSupportedByFirebase);
109
- if (!isEveryRewriteSupported)
110
- wantsBackend = true;
115
+ const isEveryRewriteSupported = nextJsRewritesToUse.every(utils_1.isRewriteSupportedByHosting);
116
+ if (!isEveryRewriteSupported) {
117
+ reasonsForBackend.push("advanced rewrites");
111
118
  }
112
119
  const rewrites = nextJsRewritesToUse
113
- .filter(utils_1.isRewriteSupportedByFirebase)
120
+ .filter(utils_1.isRewriteSupportedByHosting)
114
121
  .map(({ source, destination }) => ({
115
122
  source: (0, utils_1.cleanEscapedChars)(source),
116
123
  destination,
117
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
+ }
118
137
  return { wantsBackend, headers, redirects, rewrites };
119
138
  }
120
139
  exports.build = build;
@@ -130,130 +149,111 @@ async function init(setup) {
130
149
  exports.init = init;
131
150
  async function ɵcodegenPublicDirectory(sourceDir, destDir) {
132
151
  const { distDir } = await getConfig(sourceDir);
133
- const exportDetailPath = (0, path_1.join)(sourceDir, distDir, "export-detail.json");
134
- const exportDetailExists = await (0, fs_extra_1.pathExists)(exportDetailPath);
135
- const exportDetailBuffer = exportDetailExists ? await (0, promises_1.readFile)(exportDetailPath) : undefined;
136
- const exportDetailJson = exportDetailBuffer && JSON.parse(exportDetailBuffer.toString());
137
- if (exportDetailJson === null || exportDetailJson === void 0 ? void 0 : exportDetailJson.success) {
138
- (0, fs_extra_1.copy)(exportDetailJson.outDirectory, 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);
139
156
  }
140
- else {
141
- const publicPath = (0, path_1.join)(sourceDir, "public");
142
- await (0, promises_1.mkdir)((0, path_1.join)(destDir, "_next", "static"), { recursive: true });
143
- if (await (0, fs_extra_1.pathExists)(publicPath)) {
144
- await (0, fs_extra_1.copy)(publicPath, destDir);
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;
145
163
  }
146
- await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, distDir, "static"), (0, path_1.join)(destDir, "_next", "static"));
147
- for (const file of ["index.html", "404.html", "500.html"]) {
148
- const pagesPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", file);
149
- if (await (0, fs_extra_1.pathExists)(pagesPath)) {
150
- await (0, promises_1.copyFile)(pagesPath, (0, path_1.join)(destDir, file));
151
- continue;
152
- }
153
- const appPath = (0, path_1.join)(sourceDir, distDir, "server", "app", file);
154
- if (await (0, fs_extra_1.pathExists)(appPath)) {
155
- await (0, promises_1.copyFile)(appPath, (0, path_1.join)(destDir, file));
156
- }
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));
157
167
  }
158
- const [prerenderManifest, routesManifest] = await Promise.all([
159
- (0, utils_2.readJSON)((0, path_1.join)(sourceDir, distDir, "prerender-manifest.json")),
160
- (0, utils_2.readJSON)((0, path_1.join)(sourceDir, distDir, "routes-manifest.json")),
161
- ]);
162
- const { redirects = [], rewrites = [], headers = [] } = routesManifest;
163
- const rewritesToUse = (0, utils_1.getNextjsRewritesToUse)(rewrites);
164
- const rewritesNotSupportedByFirebase = rewritesToUse.filter((rewrite) => !(0, utils_1.isRewriteSupportedByFirebase)(rewrite));
165
- const rewritesRegexesNotSupportedByFirebase = rewritesNotSupportedByFirebase.map((rewrite) => new RegExp(rewrite.regex));
166
- const redirectsNotSupportedByFirebase = redirects.filter((redirect) => !(0, utils_1.isRedirectSupportedByFirebase)(redirect));
167
- const redirectsRegexesNotSupportedByFirebase = redirectsNotSupportedByFirebase.map((redirect) => new RegExp(redirect.regex));
168
- const headersNotSupportedByFirebase = headers.filter((header) => !(0, utils_1.isHeaderSupportedByFirebase)(header));
169
- const headersRegexesNotSupportedByFirebase = headersNotSupportedByFirebase.map((header) => new RegExp(header.regex));
170
- for (const path in prerenderManifest.routes) {
171
- if (prerenderManifest.routes[path]) {
172
- const { initialRevalidateSeconds } = prerenderManifest.routes[path];
173
- if (initialRevalidateSeconds) {
174
- continue;
175
- }
176
- const routeMatchUnsupportedRewrite = rewritesRegexesNotSupportedByFirebase.some((rewriteRegex) => rewriteRegex.test(path));
177
- if (routeMatchUnsupportedRewrite)
178
- continue;
179
- const routeMatchUnsupportedRedirect = redirectsRegexesNotSupportedByFirebase.some((redirectRegex) => redirectRegex.test(path));
180
- if (routeMatchUnsupportedRedirect)
181
- continue;
182
- const routeMatchUnsupportedHeader = headersRegexesNotSupportedByFirebase.some((headerRegex) => headerRegex.test(path));
183
- if (routeMatchUnsupportedHeader)
184
- continue;
185
- const parts = path
186
- .split("/")
187
- .slice(1)
188
- .filter((it) => !!it);
189
- const partsOrIndex = parts.length > 0 ? parts : ["index"];
190
- const dataPath = `${(0, path_1.join)(...partsOrIndex)}.json`;
191
- const htmlPath = `${(0, path_1.join)(...partsOrIndex)}.html`;
192
- await (0, promises_1.mkdir)((0, path_1.join)(destDir, (0, path_1.dirname)(htmlPath)), { recursive: true });
193
- const pagesHtmlPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", htmlPath);
194
- if (await (0, fs_extra_1.pathExists)(pagesHtmlPath)) {
195
- await (0, promises_1.copyFile)(pagesHtmlPath, (0, path_1.join)(destDir, htmlPath));
196
- }
197
- else {
198
- const appHtmlPath = (0, path_1.join)(sourceDir, distDir, "server", "app", htmlPath);
199
- if (await (0, fs_extra_1.pathExists)(appHtmlPath)) {
200
- await (0, promises_1.copyFile)(appHtmlPath, (0, path_1.join)(destDir, htmlPath));
201
- }
202
- }
203
- const dataRoute = prerenderManifest.routes[path].dataRoute;
204
- await (0, promises_1.mkdir)((0, path_1.join)(destDir, (0, path_1.dirname)(dataRoute)), { recursive: true });
205
- const pagesDataPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", dataPath);
206
- if (await (0, fs_extra_1.pathExists)(pagesDataPath)) {
207
- await (0, promises_1.copyFile)(pagesDataPath, (0, path_1.join)(destDir, dataRoute));
208
- }
209
- else {
210
- const appDataPath = (0, path_1.join)(sourceDir, distDir, "server", "app", dataPath);
211
- if (await (0, fs_extra_1.pathExists)(appDataPath)) {
212
- await (0, promises_1.copyFile)(appDataPath, (0, path_1.join)(destDir, dataRoute));
213
- }
214
- }
215
- }
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));
216
210
  }
217
211
  }
218
212
  }
219
213
  exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
220
214
  async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
221
215
  const { distDir } = await getConfig(sourceDir);
222
- const packageJsonBuffer = await (0, promises_1.readFile)((0, path_1.join)(sourceDir, "package.json"));
223
- const packageJson = JSON.parse(packageJsonBuffer.toString());
216
+ const packageJson = await (0, utils_2.readJSON)((0, path_1.join)(sourceDir, "package.json"));
224
217
  if ((0, fs_1.existsSync)((0, path_1.join)(sourceDir, "next.config.js"))) {
225
- let esbuild;
226
- try {
227
- esbuild = await Promise.resolve().then(() => require("esbuild"));
228
- }
229
- catch (e) {
230
- logger_1.logger.debug(`Failed to load 'esbuild': ${e}`);
231
- throw new error_1.FirebaseError(`Unable to find 'esbuild'. Install it into your local dev dependencies with 'npm i --save-dev esbuild''`);
232
- }
233
- await esbuild.build({
234
- bundle: true,
235
- external: Object.keys(packageJson.dependencies),
236
- absWorkingDir: sourceDir,
237
- entryPoints: ["next.config.js"],
238
- outfile: (0, path_1.join)(destDir, "next.config.js"),
239
- target: `node${__1.NODE_VERSION}`,
240
- 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,
241
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
+ }
242
231
  }
243
232
  if (await (0, fs_extra_1.pathExists)((0, path_1.join)(sourceDir, "public"))) {
244
233
  await (0, promises_1.mkdir)((0, path_1.join)(destDir, "public"));
245
234
  await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, "public"), (0, path_1.join)(destDir, "public"));
246
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
+ }
247
240
  await (0, fs_extra_1.mkdirp)((0, path_1.join)(destDir, distDir));
248
241
  await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, distDir), (0, path_1.join)(destDir, distDir));
249
242
  return { packageJson, frameworksEntry: "next.js" };
250
243
  }
251
244
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
252
- 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
+ }
253
251
  const { default: next } = (0, __1.relativeRequire)(dir, "next");
254
252
  const nextApp = next({
255
253
  dev: true,
256
254
  dir,
255
+ hostname: hostingEmulatorInfo === null || hostingEmulatorInfo === void 0 ? void 0 : hostingEmulatorInfo.host,
256
+ port: hostingEmulatorInfo === null || hostingEmulatorInfo === void 0 ? void 0 : hostingEmulatorInfo.port,
257
257
  });
258
258
  const handler = nextApp.getRequestHandler();
259
259
  await nextApp.prepare();
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getNextjsRewritesToUse = exports.isHeaderSupportedByFirebase = exports.isRedirectSupportedByFirebase = exports.isRewriteSupportedByFirebase = exports.cleanEscapedChars = exports.pathHasRegex = void 0;
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");
4
7
  const utils_1 = require("../utils");
8
+ const constants_1 = require("./constants");
9
+ const fsutils_1 = require("../../fsutils");
5
10
  function pathHasRegex(path) {
6
11
  return /(?<!\\)\(/.test(path);
7
12
  }
@@ -10,18 +15,18 @@ function cleanEscapedChars(path) {
10
15
  return path.replace(/\\([(){}:+?*])/g, (a, b) => b);
11
16
  }
12
17
  exports.cleanEscapedChars = cleanEscapedChars;
13
- function isRewriteSupportedByFirebase(rewrite) {
18
+ function isRewriteSupportedByHosting(rewrite) {
14
19
  return !("has" in rewrite || pathHasRegex(rewrite.source) || (0, utils_1.isUrl)(rewrite.destination));
15
20
  }
16
- exports.isRewriteSupportedByFirebase = isRewriteSupportedByFirebase;
17
- function isRedirectSupportedByFirebase(redirect) {
21
+ exports.isRewriteSupportedByHosting = isRewriteSupportedByHosting;
22
+ function isRedirectSupportedByHosting(redirect) {
18
23
  return !("has" in redirect || pathHasRegex(redirect.source) || "internal" in redirect);
19
24
  }
20
- exports.isRedirectSupportedByFirebase = isRedirectSupportedByFirebase;
21
- function isHeaderSupportedByFirebase(header) {
25
+ exports.isRedirectSupportedByHosting = isRedirectSupportedByHosting;
26
+ function isHeaderSupportedByHosting(header) {
22
27
  return !("has" in header || pathHasRegex(header.source));
23
28
  }
24
- exports.isHeaderSupportedByFirebase = isHeaderSupportedByFirebase;
29
+ exports.isHeaderSupportedByHosting = isHeaderSupportedByHosting;
25
30
  function getNextjsRewritesToUse(nextJsRewrites) {
26
31
  if (Array.isArray(nextJsRewrites)) {
27
32
  return nextJsRewrites;
@@ -32,3 +37,56 @@ function getNextjsRewritesToUse(nextJsRewrites) {
32
37
  return [];
33
38
  }
34
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;
@@ -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;
@@ -2,9 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.connect = exports.start = exports.stop = void 0;
4
4
  const morgan = require("morgan");
5
- const { server: superstatic } = require("superstatic");
6
- const clc = require("colorette");
7
5
  const net_1 = require("net");
6
+ const superstatic_1 = require("superstatic");
7
+ const clc = require("colorette");
8
8
  const detectProjectRoot_1 = require("../detectProjectRoot");
9
9
  const error_1 = require("../error");
10
10
  const implicitInit_1 = require("../hosting/implicitInit");
@@ -36,13 +36,13 @@ function startServer(options, config, port, init) {
36
36
  const after = options.frameworksDevModeHandle && {
37
37
  files: options.frameworksDevModeHandle,
38
38
  };
39
- const server = superstatic({
39
+ const server = (0, superstatic_1.server)({
40
40
  debug: false,
41
41
  port: port,
42
- host: options.host,
42
+ hostname: options.host,
43
43
  config: config,
44
44
  compression: true,
45
- cwd: (0, detectProjectRoot_1.detectProjectRoot)(options),
45
+ cwd: (0, detectProjectRoot_1.detectProjectRoot)(options) || undefined,
46
46
  stack: "strict",
47
47
  before: {
48
48
  files: (req, res, next) => {