@opennextjs/aws 3.1.4 → 3.1.6

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.
@@ -101,6 +101,7 @@ export default class S3Cache {
101
101
  rscData: Buffer.from(cacheData.rsc),
102
102
  status: meta?.status,
103
103
  headers: meta?.headers,
104
+ postponed: meta?.postponed,
104
105
  },
105
106
  };
106
107
  }
@@ -145,65 +146,76 @@ export default class S3Cache {
145
146
  .getStore()
146
147
  ?.pendingPromiseRunner.withResolvers();
147
148
  try {
148
- if (data?.kind === "ROUTE" || data?.kind === "APP_ROUTE") {
149
- const { body, status, headers } = data;
150
- await globalThis.incrementalCache.set(key, {
151
- type: "route",
152
- body: body.toString(isBinaryContentType(String(headers["content-type"]))
153
- ? "base64"
154
- : "utf8"),
155
- meta: {
156
- status,
157
- headers,
158
- },
159
- }, false);
149
+ if (data === null || data === undefined) {
150
+ await globalThis.incrementalCache.delete(key);
160
151
  }
161
- else if (data?.kind === "PAGE" || data?.kind === "PAGES") {
162
- const { html, pageData, status, headers } = data;
163
- const isAppPath = typeof pageData === "string";
164
- if (isAppPath) {
165
- await globalThis.incrementalCache.set(key, {
166
- type: "app",
167
- html,
168
- rsc: pageData,
169
- meta: {
170
- status,
171
- headers,
172
- },
173
- }, false);
174
- }
175
- else {
176
- await globalThis.incrementalCache.set(key, {
177
- type: "page",
178
- html,
179
- json: pageData,
180
- }, false);
152
+ else {
153
+ switch (data.kind) {
154
+ case "ROUTE":
155
+ case "APP_ROUTE":
156
+ const { body, status, headers } = data;
157
+ await globalThis.incrementalCache.set(key, {
158
+ type: "route",
159
+ body: body.toString(isBinaryContentType(String(headers["content-type"]))
160
+ ? "base64"
161
+ : "utf8"),
162
+ meta: {
163
+ status,
164
+ headers,
165
+ },
166
+ }, false);
167
+ break;
168
+ case "PAGE":
169
+ case "PAGES": {
170
+ const { html, pageData, status, headers } = data;
171
+ const isAppPath = typeof pageData === "string";
172
+ if (isAppPath) {
173
+ await globalThis.incrementalCache.set(key, {
174
+ type: "app",
175
+ html,
176
+ rsc: pageData,
177
+ meta: {
178
+ status,
179
+ headers,
180
+ },
181
+ }, false);
182
+ }
183
+ else {
184
+ await globalThis.incrementalCache.set(key, {
185
+ type: "page",
186
+ html,
187
+ json: pageData,
188
+ }, false);
189
+ }
190
+ break;
191
+ }
192
+ case "APP_PAGE": {
193
+ const { html, rscData, headers, status } = data;
194
+ await globalThis.incrementalCache.set(key, {
195
+ type: "app",
196
+ html,
197
+ rsc: rscData.toString("utf8"),
198
+ meta: {
199
+ status,
200
+ headers,
201
+ },
202
+ }, false);
203
+ break;
204
+ }
205
+ case "FETCH":
206
+ await globalThis.incrementalCache.set(key, data, true);
207
+ break;
208
+ case "REDIRECT":
209
+ await globalThis.incrementalCache.set(key, {
210
+ type: "redirect",
211
+ props: data.props,
212
+ }, false);
213
+ break;
214
+ case "IMAGE":
215
+ // Not implemented
216
+ break;
181
217
  }
182
218
  }
183
- else if (data?.kind === "APP_PAGE") {
184
- const { html, rscData, headers, status } = data;
185
- await globalThis.incrementalCache.set(key, {
186
- type: "app",
187
- html,
188
- rsc: rscData.toString("utf8"),
189
- meta: {
190
- status,
191
- headers,
192
- },
193
- }, false);
194
- }
195
- else if (data?.kind === "FETCH") {
196
- await globalThis.incrementalCache.set(key, data, true);
197
- }
198
- else if (data?.kind === "REDIRECT") {
199
- await globalThis.incrementalCache.set(key, {
200
- type: "redirect",
201
- props: data.props,
202
- }, false);
203
- }
204
- else if (data === null || data === undefined) {
205
- await globalThis.incrementalCache.delete(key);
206
- }
207
219
  // Write derivedTags to dynamodb
208
220
  // If we use an in house version of getDerivedTags in build we should use it here instead of next's one
209
221
  const derivedTags = data?.kind === "FETCH"
@@ -8,6 +8,7 @@ function copyPatchFile(outputDir) {
8
8
  const outputPatchFile = path.join(outputDir, "patchedAsyncStorage.cjs");
9
9
  copyFileSync(patchFile, outputPatchFile);
10
10
  }
11
+ // eslint-disable-next-line sonarjs/cognitive-complexity
11
12
  export async function copyTracedFiles(buildOutputPath, packagePath, outputDir, routes, bundledNextServer) {
12
13
  const tsStart = Date.now();
13
14
  const dotNextDir = path.join(buildOutputPath, ".next");
@@ -1,3 +1,2 @@
1
- import { OpenNextConfig } from "../types/open-next";
2
1
  import type { BuildOptions } from "./helper.js";
3
- export declare function createServerBundle(config: OpenNextConfig, options: BuildOptions): Promise<void>;
2
+ export declare function createServerBundle(options: BuildOptions): Promise<void>;
@@ -14,7 +14,8 @@ import { generateEdgeBundle } from "./edge/createEdgeBundle.js";
14
14
  import { compareSemver, copyEnvFile, copyOpenNextConfig, esbuildAsync, traverseFiles, } from "./helper.js";
15
15
  const require = topLevelCreateRequire(import.meta.url);
16
16
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
17
- export async function createServerBundle(config, options) {
17
+ export async function createServerBundle(options) {
18
+ const { config } = options;
18
19
  const foundRoutes = new Set();
19
20
  // Get all functions to build
20
21
  const defaultFn = config.default;
@@ -22,7 +23,7 @@ export async function createServerBundle(config, options) {
22
23
  // Recompile cache.ts as ESM if any function is using Deno runtime
23
24
  if (defaultFn.runtime === "deno" ||
24
25
  functions.some(([, fn]) => fn.runtime === "deno")) {
25
- compileCache("esm");
26
+ compileCache(options, "esm");
26
27
  }
27
28
  const promises = functions.map(async ([name, fnOptions]) => {
28
29
  const routes = fnOptions.routes;
@@ -208,7 +209,7 @@ function addDenoJson(outputPath, packagePath) {
208
209
  };
209
210
  fs.writeFileSync(path.join(outputPath, packagePath, "deno.json"), JSON.stringify(config, null, 2));
210
211
  }
211
- //TODO: check if this PR is still necessary https://github.com/sst/open-next/pull/341
212
+ //TODO: check if this PR is still necessary https://github.com/opennextjs/opennextjs-aws/pull/341
212
213
  function addMonorepoEntrypoint(outputPath, packagePath) {
213
214
  // Note: in the monorepo case, the handler file is output to
214
215
  // `.next/standalone/package/path/index.mjs`, but we want
@@ -1,2 +1,2 @@
1
- import { OpenNextConfig } from "../types/open-next";
2
- export declare function generateOutput(outputPath: string, config: OpenNextConfig): Promise<void>;
1
+ import { type BuildOptions } from "./helper.js";
2
+ export declare function generateOutput(options: BuildOptions): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { getBuildId } from "./helper.js";
4
+ const indexHandler = "index.handler";
4
5
  async function canStream(opts) {
5
6
  if (!opts.override?.wrapper) {
6
7
  return false;
@@ -59,7 +60,9 @@ function prefixPattern(basePath) {
59
60
  : pattern;
60
61
  };
61
62
  }
62
- export async function generateOutput(outputPath, config) {
63
+ // eslint-disable-next-line sonarjs/cognitive-complexity
64
+ export async function generateOutput(options) {
65
+ const { appBuildOutputPath, config } = options;
63
66
  const edgeFunctions = {};
64
67
  const isExternalMiddleware = config.middleware?.external ?? false;
65
68
  if (isExternalMiddleware) {
@@ -75,14 +78,14 @@ export async function generateOutput(outputPath, config) {
75
78
  if (value.placement === "global") {
76
79
  edgeFunctions[key] = {
77
80
  bundle: `.open-next/functions/${key}`,
78
- handler: "index.handler",
81
+ handler: indexHandler,
79
82
  ...(await extractOverrideFn(value.override)),
80
83
  };
81
84
  }
82
85
  });
83
86
  const defaultOriginCanstream = await canStream(config.default);
84
87
  //Load required-server-files.json
85
- const requiredServerFiles = JSON.parse(fs.readFileSync(path.join(outputPath, ".next", "required-server-files.json"), "utf-8")).config;
88
+ const requiredServerFiles = JSON.parse(fs.readFileSync(path.join(appBuildOutputPath, ".next", "required-server-files.json"), "utf-8")).config;
86
89
  const prefixer = prefixPattern(requiredServerFiles.basePath ?? "");
87
90
  // First add s3 origins and image optimization
88
91
  const defaultOrigins = {
@@ -111,7 +114,7 @@ export async function generateOutput(outputPath, config) {
111
114
  },
112
115
  imageOptimizer: {
113
116
  type: "function",
114
- handler: "index.handler",
117
+ handler: indexHandler,
115
118
  bundle: ".open-next/image-optimization-function",
116
119
  streaming: false,
117
120
  imageLoader: await extractOverrideName("s3", config.imageOptimization?.loader),
@@ -127,7 +130,7 @@ export async function generateOutput(outputPath, config) {
127
130
  }
128
131
  : {
129
132
  type: "function",
130
- handler: "index.handler",
133
+ handler: indexHandler,
131
134
  bundle: ".open-next/server-functions/default",
132
135
  streaming: defaultOriginCanstream,
133
136
  ...(await extractOverrideFn(config.default.override)),
@@ -152,7 +155,7 @@ export async function generateOutput(outputPath, config) {
152
155
  const streaming = await canStream(value);
153
156
  origins[key] = {
154
157
  type: "function",
155
- handler: "index.handler",
158
+ handler: indexHandler,
156
159
  bundle: `.open-next/server-functions/${key}`,
157
160
  streaming,
158
161
  ...(await extractOverrideFn(value.override)),
@@ -170,7 +173,7 @@ export async function generateOutput(outputPath, config) {
170
173
  const patterns = "patterns" in value ? value.patterns : ["*"];
171
174
  patterns.forEach((pattern) => {
172
175
  behaviors.push({
173
- pattern: prefixer(pattern.replace(/BUILD_ID/, getBuildId(outputPath))),
176
+ pattern: prefixer(pattern.replace(/BUILD_ID/, getBuildId(appBuildOutputPath))),
174
177
  origin: value.placement === "global" ? undefined : key,
175
178
  edgeFunction: value.placement === "global"
176
179
  ? key
@@ -192,7 +195,7 @@ export async function generateOutput(outputPath, config) {
192
195
  edgeFunction: isExternalMiddleware ? "middleware" : undefined,
193
196
  });
194
197
  //Compute behaviors for assets files
195
- const assetPath = path.join(outputPath, ".open-next", "assets");
198
+ const assetPath = path.join(appBuildOutputPath, ".open-next", "assets");
196
199
  fs.readdirSync(assetPath).forEach((item) => {
197
200
  if (fs.statSync(path.join(assetPath, item)).isDirectory()) {
198
201
  behaviors.push({
@@ -209,7 +212,7 @@ export async function generateOutput(outputPath, config) {
209
212
  });
210
213
  // Check if we produced a dynamodb provider output
211
214
  const isTagCacheDisabled = config.dangerous?.disableTagCache ||
212
- !fs.existsSync(path.join(outputPath, ".open-next", "dynamodb-provider"));
215
+ !fs.existsSync(path.join(appBuildOutputPath, ".open-next", "dynamodb-provider"));
213
216
  const output = {
214
217
  edgeFunctions,
215
218
  origins,
@@ -218,22 +221,22 @@ export async function generateOutput(outputPath, config) {
218
221
  disableIncrementalCache: config.dangerous?.disableIncrementalCache,
219
222
  disableTagCache: config.dangerous?.disableTagCache,
220
223
  warmer: {
221
- handler: "index.handler",
224
+ handler: indexHandler,
222
225
  bundle: ".open-next/warmer-function",
223
226
  },
224
227
  initializationFunction: isTagCacheDisabled
225
228
  ? undefined
226
229
  : {
227
- handler: "index.handler",
230
+ handler: indexHandler,
228
231
  bundle: ".open-next/dynamodb-provider",
229
232
  },
230
233
  revalidationFunction: config.dangerous?.disableIncrementalCache
231
234
  ? undefined
232
235
  : {
233
- handler: "index.handler",
236
+ handler: indexHandler,
234
237
  bundle: ".open-next/revalidation-function",
235
238
  },
236
239
  },
237
240
  };
238
- fs.writeFileSync(path.join(outputPath, ".open-next", "open-next.output.json"), JSON.stringify(output));
241
+ fs.writeFileSync(path.join(appBuildOutputPath, ".open-next", "open-next.output.json"), JSON.stringify(output));
239
242
  }
@@ -1,17 +1,19 @@
1
1
  import { BuildOptions as ESBuildOptions } from "esbuild";
2
2
  import { OpenNextConfig } from "../types/open-next.js";
3
3
  export type BuildOptions = ReturnType<typeof normalizeOptions>;
4
- export declare function normalizeOptions(config: OpenNextConfig, root: string): {
5
- openNextVersion: string;
6
- nextVersion: string;
4
+ export declare function normalizeOptions(config: OpenNextConfig): {
5
+ appBuildOutputPath: string;
7
6
  appPackageJsonPath: string;
8
7
  appPath: string;
9
- appBuildOutputPath: string;
10
8
  appPublicPath: string;
11
- outputDir: string;
12
- tempDir: string;
9
+ config: OpenNextConfig;
13
10
  debug: boolean;
14
11
  monorepoRoot: string;
12
+ nextVersion: string;
13
+ openNextVersion: string;
14
+ outputDir: string;
15
+ packager: "npm" | "yarn" | "pnpm" | "bun";
16
+ tempDir: string;
15
17
  };
16
18
  export declare function esbuildSync(esbuildOptions: ESBuildOptions, options: BuildOptions): void;
17
19
  export declare function esbuildAsync(esbuildOptions: ESBuildOptions, options: BuildOptions): Promise<void>;
@@ -6,10 +6,11 @@ import { build as buildAsync, buildSync, } from "esbuild";
6
6
  import logger from "../logger.js";
7
7
  const require = topLevelCreateRequire(import.meta.url);
8
8
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
9
- export function normalizeOptions(config, root) {
9
+ export function normalizeOptions(config) {
10
10
  const appPath = path.join(process.cwd(), config.appPath || ".");
11
11
  const buildOutputPath = path.join(process.cwd(), config.buildOutputPath || ".");
12
12
  const outputDir = path.join(buildOutputPath, ".open-next");
13
+ const { root: monorepoRoot, packager } = findMonorepoRoot(path.join(process.cwd(), config.appPath || "."));
13
14
  let appPackageJsonPath;
14
15
  if (config.packageJsonPath) {
15
16
  const _pkgPath = path.join(process.cwd(), config.packageJsonPath);
@@ -18,21 +19,45 @@ export function normalizeOptions(config, root) {
18
19
  : path.join(_pkgPath, "./package.json");
19
20
  }
20
21
  else {
21
- appPackageJsonPath = findNextPackageJsonPath(appPath, root);
22
+ appPackageJsonPath = findNextPackageJsonPath(appPath, monorepoRoot);
22
23
  }
23
24
  return {
24
- openNextVersion: getOpenNextVersion(),
25
- nextVersion: getNextVersion(appPath),
25
+ appBuildOutputPath: buildOutputPath,
26
26
  appPackageJsonPath,
27
27
  appPath,
28
- appBuildOutputPath: buildOutputPath,
29
28
  appPublicPath: path.join(appPath, "public"),
29
+ config,
30
+ debug: Boolean(process.env.OPEN_NEXT_DEBUG) ?? false,
31
+ monorepoRoot,
32
+ nextVersion: getNextVersion(appPath),
33
+ openNextVersion: getOpenNextVersion(),
30
34
  outputDir,
35
+ packager,
31
36
  tempDir: path.join(outputDir, ".build"),
32
- debug: Boolean(process.env.OPEN_NEXT_DEBUG) ?? false,
33
- monorepoRoot: root,
34
37
  };
35
38
  }
39
+ function findMonorepoRoot(appPath) {
40
+ let currentPath = appPath;
41
+ while (currentPath !== "/") {
42
+ const found = [
43
+ { file: "package-lock.json", packager: "npm" },
44
+ { file: "yarn.lock", packager: "yarn" },
45
+ { file: "pnpm-lock.yaml", packager: "pnpm" },
46
+ { file: "bun.lockb", packager: "bun" },
47
+ ].find((f) => fs.existsSync(path.join(currentPath, f.file)));
48
+ if (found) {
49
+ if (currentPath !== appPath) {
50
+ logger.info("Monorepo detected at", currentPath);
51
+ }
52
+ return { root: currentPath, packager: found.packager };
53
+ }
54
+ currentPath = path.dirname(currentPath);
55
+ }
56
+ // note: a lock file (package-lock.json, yarn.lock, or pnpm-lock.yaml) is
57
+ // not found in the app's directory or any of its parent directories.
58
+ // We are going to assume that the app is not part of a monorepo.
59
+ return { root: appPath, packager: "npm" };
60
+ }
36
61
  function findNextPackageJsonPath(appPath, root) {
37
62
  // This is needed for the case where the app is a single-version monorepo and the package.json is in the root of the monorepo
38
63
  return fs.existsSync(path.join(appPath, "./package.json"))
package/dist/build.d.ts CHANGED
@@ -1,7 +1,8 @@
1
+ import { BuildOptions } from "./build/helper.js";
1
2
  export type PublicFiles = {
2
3
  files: string[];
3
4
  };
4
5
  export declare function build(openNextConfigPath?: string, nodeExternals?: string): Promise<void>;
5
6
  /***************************/
6
7
  /***************************/
7
- export declare function compileCache(format?: "cjs" | "esm"): string;
8
+ export declare function compileCache(options: BuildOptions, format?: "cjs" | "esm"): string;
package/dist/build.js CHANGED
@@ -16,8 +16,6 @@ import { openNextReplacementPlugin } from "./plugins/replacement.js";
16
16
  import { openNextResolvePlugin } from "./plugins/resolve.js";
17
17
  const require = topLevelCreateRequire(import.meta.url);
18
18
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
19
- let options;
20
- let config;
21
19
  export async function build(openNextConfigPath, nodeExternals) {
22
20
  showWindowsWarning();
23
21
  // Load open-next.config.ts
@@ -26,39 +24,38 @@ export async function build(openNextConfigPath, nodeExternals) {
26
24
  // On Windows, we need to use file:// protocol to load the config file using import()
27
25
  if (process.platform === "win32")
28
26
  configPath = `file://${configPath}`;
29
- config = (await import(configPath)).default;
27
+ const config = (await import(configPath)).default;
30
28
  if (!config || !config.default) {
31
29
  logger.error(`config.default cannot be empty, it should be at least {}, see more info here: https://open-next.js.org/config#configuration-file`);
32
30
  process.exit(1);
33
31
  }
34
32
  validateConfig(config);
35
33
  compileOpenNextConfigEdge(tempDir, config, openNextConfigPath);
36
- const { root: monorepoRoot, packager } = findMonorepoRoot(path.join(process.cwd(), config.appPath || "."));
37
34
  // Initialize options
38
- options = normalizeOptions(config, monorepoRoot);
35
+ const options = normalizeOptions(config);
39
36
  logger.setLevel(options.debug ? "debug" : "info");
40
37
  // Pre-build validation
41
- checkRunningInsideNextjsApp();
42
- printNextjsVersion();
43
- printOpenNextVersion();
38
+ checkRunningInsideNextjsApp(options);
39
+ printNextjsVersion(options);
40
+ printOpenNextVersion(options);
44
41
  // Build Next.js app
45
42
  printHeader("Building Next.js app");
46
- setStandaloneBuildMode(monorepoRoot);
47
- buildNextjsApp(packager);
43
+ setStandaloneBuildMode(options);
44
+ buildNextjsApp(options);
48
45
  // Generate deployable bundle
49
46
  printHeader("Generating bundle");
50
- initOutputDir(tempDir);
47
+ initOutputDir(tempDir, options);
51
48
  // Compile cache.ts
52
- compileCache();
49
+ compileCache(options);
53
50
  // Compile middleware
54
- await createMiddleware();
55
- createStaticAssets();
56
- await createCacheAssets(monorepoRoot);
57
- await createServerBundle(config, options);
58
- await createRevalidationBundle(config);
59
- await createImageOptimizationBundle(config);
60
- await createWarmerBundle(config);
61
- await generateOutput(options.appBuildOutputPath, config);
51
+ await createMiddleware(options);
52
+ createStaticAssets(options);
53
+ await createCacheAssets(options);
54
+ await createServerBundle(options);
55
+ await createRevalidationBundle(options);
56
+ await createImageOptimizationBundle(options);
57
+ await createWarmerBundle(options);
58
+ await generateOutput(options);
62
59
  logger.info("OpenNext build complete.");
63
60
  }
64
61
  function showWindowsWarning() {
@@ -75,7 +72,7 @@ function initTempDir() {
75
72
  fs.mkdirSync(tempDir, { recursive: true });
76
73
  return tempDir;
77
74
  }
78
- function checkRunningInsideNextjsApp() {
75
+ function checkRunningInsideNextjsApp(options) {
79
76
  const { appPath } = options;
80
77
  const extension = ["js", "cjs", "mjs", "ts"].find((ext) => fs.existsSync(path.join(appPath, `next.config.${ext}`)));
81
78
  if (!extension) {
@@ -83,43 +80,21 @@ function checkRunningInsideNextjsApp() {
83
80
  process.exit(1);
84
81
  }
85
82
  }
86
- function findMonorepoRoot(appPath) {
87
- let currentPath = appPath;
88
- while (currentPath !== "/") {
89
- const found = [
90
- { file: "package-lock.json", packager: "npm" },
91
- { file: "yarn.lock", packager: "yarn" },
92
- { file: "pnpm-lock.yaml", packager: "pnpm" },
93
- { file: "bun.lockb", packager: "bun" },
94
- ].find((f) => fs.existsSync(path.join(currentPath, f.file)));
95
- if (found) {
96
- if (currentPath !== appPath) {
97
- logger.info("Monorepo detected at", currentPath);
98
- }
99
- return { root: currentPath, packager: found.packager };
100
- }
101
- currentPath = path.dirname(currentPath);
102
- }
103
- // note: a lock file (package-lock.json, yarn.lock, or pnpm-lock.yaml) is
104
- // not found in the app's directory or any of its parent directories.
105
- // We are going to assume that the app is not part of a monorepo.
106
- return { root: appPath, packager: "npm" };
107
- }
108
- function setStandaloneBuildMode(monorepoRoot) {
109
- // Equivalent to setting `target: "standalone"` in next.config.js
83
+ function setStandaloneBuildMode(options) {
84
+ // Equivalent to setting `output: "standalone"` in next.config.js
110
85
  process.env.NEXT_PRIVATE_STANDALONE = "true";
111
86
  // Equivalent to setting `experimental.outputFileTracingRoot` in next.config.js
112
- process.env.NEXT_PRIVATE_OUTPUT_TRACE_ROOT = monorepoRoot;
87
+ process.env.NEXT_PRIVATE_OUTPUT_TRACE_ROOT = options.monorepoRoot;
113
88
  }
114
- function buildNextjsApp(packager) {
115
- const { appPackageJsonPath } = options;
89
+ function buildNextjsApp(options) {
90
+ const { config, packager } = options;
116
91
  const command = config.buildCommand ??
117
92
  (["bun", "npm"].includes(packager)
118
93
  ? `${packager} run build`
119
94
  : `${packager} build`);
120
95
  cp.execSync(command, {
121
96
  stdio: "inherit",
122
- cwd: path.dirname(appPackageJsonPath),
97
+ cwd: path.dirname(options.appPackageJsonPath),
123
98
  });
124
99
  }
125
100
  function printHeader(header) {
@@ -132,34 +107,32 @@ function printHeader(header) {
132
107
  "",
133
108
  ].join("\n"));
134
109
  }
135
- function printNextjsVersion() {
136
- const { nextVersion } = options;
137
- logger.info(`Next.js version : ${nextVersion}`);
110
+ function printNextjsVersion(options) {
111
+ logger.info(`Next.js version : ${options.nextVersion}`);
138
112
  }
139
- function printOpenNextVersion() {
140
- const { openNextVersion } = options;
141
- logger.info(`OpenNext v${openNextVersion}`);
113
+ function printOpenNextVersion(options) {
114
+ logger.info(`OpenNext v${options.openNextVersion}`);
142
115
  }
143
- function initOutputDir(tempDir) {
116
+ function initOutputDir(srcTempDir, options) {
144
117
  // We need to get the build relative to the cwd to find the compiled config
145
118
  // This is needed for the case where the app is a single-version monorepo and the package.json is in the root of the monorepo
146
119
  // where the build is in the app directory, but the compiled config is in the root of the monorepo.
147
- const { outputDir, tempDir: lTempDir } = options;
148
- const openNextConfig = readFileSync(path.join(tempDir, "open-next.config.mjs"), "utf8");
120
+ const openNextConfig = readFileSync(path.join(srcTempDir, "open-next.config.mjs"), "utf8");
149
121
  let openNextConfigEdge = null;
150
- if (fs.existsSync(path.join(tempDir, "open-next.config.edge.mjs"))) {
151
- openNextConfigEdge = readFileSync(path.join(tempDir, "open-next.config.edge.mjs"), "utf8");
122
+ if (fs.existsSync(path.join(srcTempDir, "open-next.config.edge.mjs"))) {
123
+ openNextConfigEdge = readFileSync(path.join(srcTempDir, "open-next.config.edge.mjs"), "utf8");
152
124
  }
153
- fs.rmSync(outputDir, { recursive: true, force: true });
154
- fs.mkdirSync(lTempDir, { recursive: true });
155
- fs.writeFileSync(path.join(lTempDir, "open-next.config.mjs"), openNextConfig);
125
+ fs.rmSync(options.outputDir, { recursive: true, force: true });
126
+ const destTempDir = options.tempDir;
127
+ fs.mkdirSync(destTempDir, { recursive: true });
128
+ fs.writeFileSync(path.join(destTempDir, "open-next.config.mjs"), openNextConfig);
156
129
  if (openNextConfigEdge) {
157
- fs.writeFileSync(path.join(lTempDir, "open-next.config.edge.mjs"), openNextConfigEdge);
130
+ fs.writeFileSync(path.join(destTempDir, "open-next.config.edge.mjs"), openNextConfigEdge);
158
131
  }
159
132
  }
160
- async function createWarmerBundle(config) {
133
+ async function createWarmerBundle(options) {
161
134
  logger.info(`Bundling warmer function...`);
162
- const { outputDir } = options;
135
+ const { config, outputDir } = options;
163
136
  // Create output folder
164
137
  const outputPath = path.join(outputDir, "warmer-function");
165
138
  fs.mkdirSync(outputPath, { recursive: true });
@@ -192,9 +165,9 @@ async function createWarmerBundle(config) {
192
165
  },
193
166
  }, options);
194
167
  }
195
- async function createRevalidationBundle(config) {
168
+ async function createRevalidationBundle(options) {
196
169
  logger.info(`Bundling revalidation function...`);
197
- const { appBuildOutputPath, outputDir } = options;
170
+ const { appBuildOutputPath, config, outputDir } = options;
198
171
  // Create output folder
199
172
  const outputPath = path.join(outputDir, "revalidation-function");
200
173
  fs.mkdirSync(outputPath, { recursive: true });
@@ -218,9 +191,9 @@ async function createRevalidationBundle(config) {
218
191
  // Copy over .next/prerender-manifest.json file
219
192
  fs.copyFileSync(path.join(appBuildOutputPath, ".next", "prerender-manifest.json"), path.join(outputPath, "prerender-manifest.json"));
220
193
  }
221
- async function createImageOptimizationBundle(config) {
194
+ async function createImageOptimizationBundle(options) {
222
195
  logger.info(`Bundling image optimization function...`);
223
- const { appPath, appBuildOutputPath, outputDir } = options;
196
+ const { appPath, appBuildOutputPath, config, outputDir } = options;
224
197
  // Create output folder
225
198
  const outputPath = path.join(outputDir, "image-optimization-function");
226
199
  fs.mkdirSync(outputPath, { recursive: true });
@@ -306,7 +279,7 @@ async function createImageOptimizationBundle(config) {
306
279
  logger.error("Failed to install sharp.");
307
280
  }
308
281
  }
309
- function createStaticAssets() {
282
+ function createStaticAssets(options) {
310
283
  logger.info(`Bundling static assets...`);
311
284
  const { appBuildOutputPath, appPublicPath, outputDir, appPath } = options;
312
285
  // Create output folder
@@ -331,12 +304,13 @@ function createStaticAssets() {
331
304
  fs.copyFileSync(faviconPath, path.join(outputPath, "favicon.ico"));
332
305
  }
333
306
  }
334
- async function createCacheAssets(monorepoRoot) {
307
+ async function createCacheAssets(options) {
308
+ const { config } = options;
335
309
  if (config.dangerous?.disableIncrementalCache)
336
310
  return;
337
311
  logger.info(`Bundling cache assets...`);
338
312
  const { appBuildOutputPath, outputDir } = options;
339
- const packagePath = path.relative(monorepoRoot, appBuildOutputPath);
313
+ const packagePath = path.relative(options.monorepoRoot, appBuildOutputPath);
340
314
  const buildId = getBuildId(appBuildOutputPath);
341
315
  // Copy pages to cache folder
342
316
  const dotNextPath = path.join(appBuildOutputPath, ".next/standalone", packagePath);
@@ -354,7 +328,11 @@ async function createCacheAssets(monorepoRoot) {
354
328
  const cacheFilesPath = {};
355
329
  traverseFiles(outputPath, () => true, (filepath) => {
356
330
  const ext = path.extname(filepath);
357
- const newFilePath = ext !== "" ? filepath.replace(ext, ".cache") : `${filepath}.cache`;
331
+ let newFilePath = ext !== "" ? filepath.replace(ext, ".cache") : `${filepath}.cache`;
332
+ // Handle prefetch cache files for partial prerendering
333
+ if (newFilePath.endsWith(".prefetch.cache")) {
334
+ newFilePath = newFilePath.replace(".prefetch.cache", ".cache");
335
+ }
358
336
  switch (ext) {
359
337
  case ".meta":
360
338
  case ".html":
@@ -470,7 +448,8 @@ async function createCacheAssets(monorepoRoot) {
470
448
  /***************************/
471
449
  /* Server Helper Functions */
472
450
  /***************************/
473
- export function compileCache(format = "cjs") {
451
+ export function compileCache(options, format = "cjs") {
452
+ const { config } = options;
474
453
  const ext = format === "cjs" ? "cjs" : "mjs";
475
454
  const outfile = path.join(options.outputDir, ".build", `cache.${ext}`);
476
455
  const isAfter15 = compareSemver(options.nextVersion, "15.0.0") >= 0;
@@ -490,9 +469,9 @@ export function compileCache(format = "cjs") {
490
469
  }, options);
491
470
  return outfile;
492
471
  }
493
- async function createMiddleware() {
472
+ async function createMiddleware(options) {
494
473
  console.info(`Bundling middleware function...`);
495
- const { appBuildOutputPath, outputDir } = options;
474
+ const { appBuildOutputPath, config, outputDir } = options;
496
475
  // Get middleware manifest
497
476
  const middlewareManifest = JSON.parse(readFileSync(path.join(appBuildOutputPath, ".next/server/middleware-manifest.json"), "utf8"));
498
477
  const entry = middlewareManifest.middleware["/"];
@@ -58,5 +58,6 @@ export type Extension = "cache" | "fetch";
58
58
  export interface Meta {
59
59
  status?: number;
60
60
  headers?: Record<string, undefined | string | string[]>;
61
+ postponed?: string;
61
62
  }
62
63
  export {};
@@ -73,6 +73,7 @@ async function convertFromAPIGatewayProxyEventV2(event) {
73
73
  async function convertToApiGatewayProxyResultV2(result) {
74
74
  const headers = {};
75
75
  Object.entries(result.headers)
76
+ .map(([key, value]) => [key.toLowerCase(), value])
76
77
  .filter(([key]) => !CloudFrontBlacklistedHeaders.some((header) => typeof header === "string" ? header === key : header.test(key)))
77
78
  .forEach(([key, value]) => {
78
79
  if (value === null || value === undefined) {
@@ -75,6 +75,7 @@ async function convertFromCloudFrontRequestEvent(event) {
75
75
  function convertToCloudfrontHeaders(headers, directResponse) {
76
76
  const cloudfrontHeaders = {};
77
77
  Object.entries(headers)
78
+ .map(([key, value]) => [key.toLowerCase(), value])
78
79
  .filter(([key]) => !CloudFrontBlacklistedHeaders.some((header) => typeof header === "string" ? header === key : header.test(key)) &&
79
80
  // Only remove read-only headers when directly responding in lambda@edge
80
81
  (directResponse ? !cloudfrontReadOnlyHeaders.includes(key) : true))
@@ -1,5 +1,6 @@
1
1
  // Copied from Next.js source code
2
2
  // https://github.com/vercel/next.js/blob/canary/packages/next/src/server/accept-header.ts
3
+ // eslint-disable-next-line sonarjs/cognitive-complexity
3
4
  function parse(raw, preferences, options) {
4
5
  const lowers = new Map();
5
6
  const header = raw.replace(/[ \t]/g, "");
@@ -212,7 +212,7 @@ export async function proxyRequest(internalEvent, res) {
212
212
  res.end();
213
213
  reject(e);
214
214
  });
215
- _res.on("end", () => {
215
+ res.on("finish", () => {
216
216
  resolve();
217
217
  });
218
218
  });
@@ -5,7 +5,7 @@ import { addNextConfigHeaders, fixDataPage, handleFallbackFalse, handleRedirects
5
5
  import { handleMiddleware } from "./routing/middleware";
6
6
  // Add the locale prefix to the regex so we correctly match the rawPath
7
7
  const optionalLocalePrefixRegex = !!RoutesManifest.locales.length
8
- ? `^/(?:${RoutesManifest.locales.map((locale) => `${locale}/?`).join("|")})?`
8
+ ? `^/(?:${RoutesManifest.locales.map((locale) => locale + "/?").join("|")})?`
9
9
  : "^/";
10
10
  // Add the basepath prefix to the regex so we correctly match the rawPath
11
11
  const optionalBasepathPrefixRegex = !!RoutesManifest.basePath
@@ -5,8 +5,8 @@ export declare class IncomingMessage extends http.IncomingMessage {
5
5
  constructor({ method, url, headers, body, remoteAddress, }: {
6
6
  method: string;
7
7
  url: string;
8
- headers: Record<string, string>;
8
+ headers: Record<string, string | string[]>;
9
9
  body?: Buffer;
10
- remoteAddress: string;
10
+ remoteAddress?: string;
11
11
  });
12
12
  }
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ function parseArgs() {
15
15
  }
16
16
  else if (self[ind + 1]) {
17
17
  acc[key] = self[ind + 1];
18
+ // eslint-disable-next-line sonarjs/elseif-without-else
18
19
  }
19
20
  else if (!self[ind + 1]) {
20
21
  acc[key] = undefined;
@@ -1,3 +1,4 @@
1
+ /* eslint-disable */
1
2
  // Copied and modified from node-minify-all-js by Adones Pitogo
2
3
  // https://github.com/adonespitogo/node-minify-all-js/blob/master/index.js
3
4
  // @ts-nocheck
@@ -28,7 +28,7 @@ export function openNextEdgePlugins({ nextDir, edgeFunctionHandlerPath, middlewa
28
28
  };
29
29
  });
30
30
  }
31
- build.onResolve({ filter: /\.(mjs|wasm)$/g }, (args) => {
31
+ build.onResolve({ filter: /\.(mjs|wasm)$/g }, () => {
32
32
  return {
33
33
  external: true,
34
34
  };
@@ -55,7 +55,6 @@ const handler = async (handler, converter) => awslambda.streamifyResponse(async
55
55
  }
56
56
  const streamCreator = {
57
57
  writeHeaders: (_prelude) => {
58
- _prelude.headers["content-encoding"] = contentEncoding;
59
58
  responseStream.setContentType("application/vnd.awslambda.http-integration-response");
60
59
  _prelude.headers["content-encoding"] = contentEncoding;
61
60
  const prelude = JSON.stringify(_prelude);
package/package.json CHANGED
@@ -3,10 +3,9 @@
3
3
  "access": "public"
4
4
  },
5
5
  "name": "@opennextjs/aws",
6
- "version": "3.1.4",
6
+ "version": "3.1.6",
7
7
  "bin": {
8
- "open-next": "./dist/index.js",
9
- "@opennextjs/aws": "./dist/index.js"
8
+ "open-next": "./dist/index.js"
10
9
  },
11
10
  "license": "MIT",
12
11
  "type": "module",
@@ -53,11 +52,12 @@
53
52
  "typescript": "^4.9.3"
54
53
  },
55
54
  "bugs": {
56
- "url": "https://github.com/sst/open-next/issues"
55
+ "url": "https://github.com/opennextjs/opennextjs-aws/issues"
57
56
  },
58
57
  "repository": {
59
58
  "type": "git",
60
- "url": "git+https://github.com/sst/open-next.git"
59
+ "url": "https://github.com/opennextjs/opennextjs-aws",
60
+ "directory": "packages/open-next"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "tsc && tsc-alias",