@opennextjs/aws 3.9.14 → 3.9.16

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.
@@ -209,7 +209,13 @@ export default class Cache {
209
209
  break;
210
210
  }
211
211
  case "APP_PAGE": {
212
- const { html, rscData, headers, status } = data;
212
+ const { html, rscData, headers, status, segmentData, postponed } = data;
213
+ const segmentToWrite = {};
214
+ if (segmentData) {
215
+ for (const [segmentPath, segmentContent,] of segmentData.entries()) {
216
+ segmentToWrite[segmentPath] = segmentContent.toString("utf8");
217
+ }
218
+ }
213
219
  await globalThis.incrementalCache.set(key, {
214
220
  type: "app",
215
221
  html,
@@ -217,8 +223,10 @@ export default class Cache {
217
223
  meta: {
218
224
  status,
219
225
  headers,
226
+ postponed,
220
227
  },
221
228
  revalidate,
229
+ segmentData: segmentData ? segmentToWrite : undefined,
222
230
  }, "cache");
223
231
  break;
224
232
  }
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Copies a file and ensures the destination is writable.
3
+ * This is necessary because copyFileSync preserves file permissions,
4
+ * and source files may be read-only (e.g., in Bazel's node_modules).
5
+ * Without this, subsequent patches would fail with EACCES errors.
6
+ */
7
+ export declare function copyFileAndMakeOwnerWritable(src: string, dest: string): void;
1
8
  export declare function isExcluded(srcPath: string): boolean;
2
9
  interface CopyTracedFilesOptions {
3
10
  buildOutputPath: string;
@@ -1,11 +1,25 @@
1
1
  import url from "node:url";
2
- import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, statSync, symlinkSync, writeFileSync, } from "node:fs";
2
+ import { chmodSync, copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, statSync, symlinkSync, writeFileSync, } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { loadAppPathsManifest, loadBuildId, loadConfig, loadFunctionsConfigManifest, loadMiddlewareManifest, loadPagesManifest, loadPrerenderManifest, } from "../adapters/config/util.js";
5
5
  import { getCrossPlatformPathRegex } from "../utils/regex.js";
6
6
  import logger from "../logger.js";
7
7
  import { INSTRUMENTATION_TRACE_FILE, MIDDLEWARE_TRACE_FILE, } from "./constant.js";
8
8
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
9
+ /**
10
+ * Copies a file and ensures the destination is writable.
11
+ * This is necessary because copyFileSync preserves file permissions,
12
+ * and source files may be read-only (e.g., in Bazel's node_modules).
13
+ * Without this, subsequent patches would fail with EACCES errors.
14
+ */
15
+ export function copyFileAndMakeOwnerWritable(src, dest) {
16
+ copyFileSync(src, dest);
17
+ // Ensure the copied file is writable (add owner write permission)
18
+ const stats = statSync(dest);
19
+ if (!(stats.mode & 0o200)) {
20
+ chmodSync(dest, stats.mode | 0o200);
21
+ }
22
+ }
9
23
  //TODO: we need to figure which packages we could safely remove
10
24
  const EXCLUDED_PACKAGES = [
11
25
  "caniuse-lite",
@@ -29,7 +43,7 @@ export function isExcluded(srcPath) {
29
43
  function copyPatchFile(outputDir) {
30
44
  const patchFile = path.join(__dirname, "patch", "patchedAsyncStorage.js");
31
45
  const outputPatchFile = path.join(outputDir, "patchedAsyncStorage.cjs");
32
- copyFileSync(patchFile, outputPatchFile);
46
+ copyFileAndMakeOwnerWritable(patchFile, outputPatchFile);
33
47
  }
34
48
  export function getManifests(nextDir) {
35
49
  return {
@@ -138,13 +152,13 @@ File ${serverPath} does not exist
138
152
  // Check for instrumentation trace file
139
153
  if (existsSync(path.join(dotNextDir, INSTRUMENTATION_TRACE_FILE))) {
140
154
  // We still need to copy the nft.json file so that computeCopyFilesForPage doesn't throw
141
- copyFileSync(path.join(dotNextDir, INSTRUMENTATION_TRACE_FILE), path.join(standaloneNextDir, INSTRUMENTATION_TRACE_FILE));
155
+ copyFileAndMakeOwnerWritable(path.join(dotNextDir, INSTRUMENTATION_TRACE_FILE), path.join(standaloneNextDir, INSTRUMENTATION_TRACE_FILE));
142
156
  computeCopyFilesForPage("instrumentation");
143
157
  logger.debug("Adding instrumentation trace files");
144
158
  }
145
159
  if (existsSync(path.join(dotNextDir, MIDDLEWARE_TRACE_FILE))) {
146
160
  // We still need to copy the nft.json file so that computeCopyFilesForPage doesn't throw
147
- copyFileSync(path.join(dotNextDir, MIDDLEWARE_TRACE_FILE), path.join(standaloneNextDir, MIDDLEWARE_TRACE_FILE));
161
+ copyFileAndMakeOwnerWritable(path.join(dotNextDir, MIDDLEWARE_TRACE_FILE), path.join(standaloneNextDir, MIDDLEWARE_TRACE_FILE));
148
162
  computeCopyFilesForPage("middleware");
149
163
  logger.debug("Adding node middleware trace files");
150
164
  }
@@ -207,7 +221,7 @@ File ${serverPath} does not exist
207
221
  // where some files listed in the .nft.json might not be present in the standalone folder
208
222
  // TODO: investigate that further - is it expected?
209
223
  try {
210
- copyFileSync(from, to);
224
+ copyFileAndMakeOwnerWritable(from, to);
211
225
  }
212
226
  catch (e) {
213
227
  logger.debug("Error copying file:", e);
@@ -218,7 +232,7 @@ File ${serverPath} does not exist
218
232
  readdirSync(standaloneNextDir)
219
233
  .filter((fileOrDir) => !statSync(path.join(standaloneNextDir, fileOrDir)).isDirectory())
220
234
  .forEach((file) => {
221
- copyFileSync(path.join(standaloneNextDir, file), path.join(outputNextDir, file));
235
+ copyFileAndMakeOwnerWritable(path.join(standaloneNextDir, file), path.join(outputNextDir, file));
222
236
  tracedFiles.push(path.join(outputNextDir, file));
223
237
  });
224
238
  // We then need to copy all the files at the root of server
@@ -227,7 +241,7 @@ File ${serverPath} does not exist
227
241
  .filter((fileOrDir) => !statSync(path.join(standaloneServerDir, fileOrDir)).isDirectory())
228
242
  .filter((file) => file !== "server.js")
229
243
  .forEach((file) => {
230
- copyFileSync(path.join(standaloneServerDir, file), path.join(path.join(outputNextDir, "server"), file));
244
+ copyFileAndMakeOwnerWritable(path.join(standaloneServerDir, file), path.join(path.join(outputNextDir, "server"), file));
231
245
  tracedFiles.push(path.join(outputNextDir, "server", file));
232
246
  });
233
247
  // Copy patch file
@@ -245,7 +259,7 @@ File ${serverPath} does not exist
245
259
  mkdirSync(path.dirname(path.join(outputNextDir, filePath)), {
246
260
  recursive: true,
247
261
  });
248
- copyFileSync(path.join(standaloneNextDir, filePath), path.join(outputNextDir, filePath));
262
+ copyFileAndMakeOwnerWritable(path.join(standaloneNextDir, filePath), path.join(outputNextDir, filePath));
249
263
  }
250
264
  };
251
265
  const manifests = getManifests(standaloneNextDir);
@@ -95,9 +95,12 @@ export declare function copyEnvFile(appPath: string, packagePath: string, output
95
95
  * Finds the path to the Next configuration file if it exists.
96
96
  *
97
97
  * @param appPath The directory to check for the Next config file
98
- * @returns The full path to Next config file if it exists, undefined otherwise
98
+ * @returns An object with the full path to Next config file alongside a flag indicating whether the file is in typescript if it exists, undefined otherwise
99
99
  */
100
- export declare function findNextConfig({ appPath, }: Pick<BuildOptions, "appPath">): string | undefined;
100
+ export declare function findNextConfig({ appPath, }: Pick<BuildOptions, "appPath">): {
101
+ path: string;
102
+ isTypescript: boolean;
103
+ } | undefined;
101
104
  /**
102
105
  * Check we are in a Nextjs app by looking for the Nextjs config file.
103
106
  */
@@ -352,10 +352,26 @@ export function copyEnvFile(appPath, packagePath, outputPath) {
352
352
  * Finds the path to the Next configuration file if it exists.
353
353
  *
354
354
  * @param appPath The directory to check for the Next config file
355
- * @returns The full path to Next config file if it exists, undefined otherwise
355
+ * @returns An object with the full path to Next config file alongside a flag indicating whether the file is in typescript if it exists, undefined otherwise
356
356
  */
357
357
  export function findNextConfig({ appPath, }) {
358
- return ["js", "cjs", "mjs", "ts"].find((ext) => fs.existsSync(path.join(appPath, `next.config.${ext}`)));
358
+ const extensions = [
359
+ { ext: "ts", isTypescript: true },
360
+ { ext: "mts", isTypescript: true },
361
+ { ext: "cts", isTypescript: true },
362
+ { ext: "js", isTypescript: false },
363
+ { ext: "mjs", isTypescript: false },
364
+ { ext: "cjs", isTypescript: false },
365
+ ];
366
+ for (const { ext, isTypescript } of extensions) {
367
+ const configPath = path.join(appPath, `next.config.${ext}`);
368
+ if (fs.existsSync(configPath)) {
369
+ return {
370
+ path: configPath,
371
+ isTypescript,
372
+ };
373
+ }
374
+ }
359
375
  }
360
376
  /**
361
377
  * Check we are in a Nextjs app by looking for the Nextjs config file.
@@ -45,25 +45,14 @@ export async function patchOriginalNextConfig(options) {
45
45
  * @returns
46
46
  */
47
47
  async function importNextConfigFromSource(buildOptions) {
48
- // Find the `next.config file with any supported extension
49
- const tsExtensions = [".ts", ".mts", ".cts"];
50
- const possibleExtensions = [...tsExtensions, ".mjs", ".js", ".cjs"];
51
- let configPath;
52
- let configExtension;
53
- for (const ext of possibleExtensions) {
54
- const testPath = path.join(buildOptions.appPath, `next.config${ext}`);
55
- if (fs.existsSync(testPath)) {
56
- configPath = testPath;
57
- configExtension = ext;
58
- break;
59
- }
60
- }
61
- if (!configPath || !configExtension) {
48
+ const nextConfigDetails = buildHelper.findNextConfig(buildOptions);
49
+ if (!nextConfigDetails) {
62
50
  throw new Error("Could not find next.config file");
63
51
  }
52
+ const { path: configPath, isTypescript: configIsTs } = nextConfigDetails;
64
53
  let configToImport;
65
54
  // Only compile if the extension is a TypeScript extension
66
- if (tsExtensions.includes(configExtension)) {
55
+ if (configIsTs) {
67
56
  await build({
68
57
  entryPoints: [configPath],
69
58
  outfile: path.join(buildOptions.tempBuildDir, "next.config.mjs"),
@@ -44,6 +44,7 @@ interface IncrementalCachedAppPageValue {
44
44
  headers?: Record<string, undefined | string | string[]>;
45
45
  postponed?: string;
46
46
  status?: number;
47
+ segmentData?: Map<string, Buffer>;
47
48
  }
48
49
  export type IncrementalCacheValue = CachedRedirectValue | IncrementalCachedPageValue | IncrementalCachedAppPageValue | CachedImageValue | CachedFetchValue | CachedRouteValue;
49
50
  export interface CacheHandlerContext {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "access": "public"
4
4
  },
5
5
  "name": "@opennextjs/aws",
6
- "version": "3.9.14",
6
+ "version": "3.9.16",
7
7
  "bin": {
8
8
  "open-next": "./dist/index.js"
9
9
  },
@@ -33,12 +33,12 @@
33
33
  "README.md"
34
34
  ],
35
35
  "dependencies": {
36
- "@ast-grep/napi": "^0.40.0",
37
- "@aws-sdk/client-cloudfront": "3.398.0",
38
- "@aws-sdk/client-dynamodb": "^3.398.0",
39
- "@aws-sdk/client-lambda": "^3.398.0",
40
- "@aws-sdk/client-s3": "^3.398.0",
41
- "@aws-sdk/client-sqs": "^3.398.0",
36
+ "@ast-grep/napi": "^0.40.5",
37
+ "@aws-sdk/client-cloudfront": "3.984.0",
38
+ "@aws-sdk/client-dynamodb": "3.984.0",
39
+ "@aws-sdk/client-lambda": "3.984.0",
40
+ "@aws-sdk/client-s3": "3.984.0",
41
+ "@aws-sdk/client-sqs": "3.984.0",
42
42
  "@node-minify/core": "^8.0.6",
43
43
  "@node-minify/terser": "^8.0.6",
44
44
  "@tsconfig/node18": "^1.0.3",