@opennextjs/aws 3.7.0 → 3.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,14 +7,16 @@ import routingHandler, { INTERNAL_EVENT_REQUEST_ID, INTERNAL_HEADER_INITIAL_URL,
7
7
  globalThis.internalFetch = fetch;
8
8
  globalThis.__openNextAls = new AsyncLocalStorage();
9
9
  const defaultHandler = async (internalEvent, options) => {
10
- const config = globalThis.openNextConfig.middleware;
11
- const originResolver = await resolveOriginResolver(config?.originResolver);
12
- const externalRequestProxy = await resolveProxyRequest(config?.override?.proxyExternalRequest);
13
- const assetResolver = await resolveAssetResolver(config?.assetResolver);
10
+ // We know that the middleware is external when this adapter is used
11
+ const middlewareConfig = globalThis.openNextConfig
12
+ .middleware;
13
+ const originResolver = await resolveOriginResolver(middlewareConfig?.originResolver);
14
+ const externalRequestProxy = await resolveProxyRequest(middlewareConfig?.override?.proxyExternalRequest);
15
+ const assetResolver = await resolveAssetResolver(middlewareConfig?.assetResolver);
14
16
  //#override includeCacheInMiddleware
15
- globalThis.tagCache = await resolveTagCache(config?.override?.tagCache);
16
- globalThis.queue = await resolveQueue(config?.override?.queue);
17
- globalThis.incrementalCache = await resolveIncrementalCache(config?.override?.incrementalCache);
17
+ globalThis.tagCache = await resolveTagCache(middlewareConfig?.override?.tagCache);
18
+ globalThis.queue = await resolveQueue(middlewareConfig?.override?.queue);
19
+ globalThis.incrementalCache = await resolveIncrementalCache(middlewareConfig?.override?.incrementalCache);
18
20
  //#endOverride
19
21
  const requestId = Math.random().toString(36);
20
22
  // We run everything in the async local storage context so that it is available in the external middleware
@@ -139,6 +139,7 @@ async function generateBundle(name, options, fnOptions, codeCustomization) {
139
139
  const isAfter141 = buildHelper.compareSemver(options.nextVersion, ">=", "14.1");
140
140
  const isAfter142 = buildHelper.compareSemver(options.nextVersion, ">=", "14.2");
141
141
  const isAfter152 = buildHelper.compareSemver(options.nextVersion, ">=", "15.2.0");
142
+ const isAfter154 = buildHelper.compareSemver(options.nextVersion, ">=", "15.4.0");
142
143
  const disableRouting = isBefore13413 || config.middleware?.external;
143
144
  const updater = new ContentUpdater(options);
144
145
  const additionalPlugins = codeCustomization?.additionalPlugins
@@ -153,6 +154,7 @@ async function generateBundle(name, options, fnOptions, codeCustomization) {
153
154
  ...(disableRouting ? ["withRouting"] : []),
154
155
  ...(isAfter142 ? ["patchAsyncStorage"] : []),
155
156
  ...(isAfter141 ? ["appendPrefetch"] : []),
157
+ ...(isAfter154 ? [] : ["setInitialURL"]),
156
158
  ],
157
159
  }),
158
160
  openNextReplacementPlugin({
@@ -61,11 +61,13 @@ export async function generateOutput(options) {
61
61
  const edgeFunctions = {};
62
62
  const isExternalMiddleware = config.middleware?.external ?? false;
63
63
  if (isExternalMiddleware) {
64
+ const middlewareConfig = options.config
65
+ .middleware;
64
66
  edgeFunctions.middleware = {
65
67
  bundle: ".open-next/middleware",
66
68
  handler: "handler.handler",
67
- pathResolver: await extractOverrideName("pattern-env", config.middleware.originResolver),
68
- ...(await extractOverrideFn(config.middleware?.override)),
69
+ pathResolver: await extractOverrideName("pattern-env", middlewareConfig.originResolver),
70
+ ...(await extractOverrideFn(middlewareConfig.override)),
69
71
  };
70
72
  }
71
73
  // Add edge functions
@@ -35,6 +35,28 @@ export function installDependencies(outputDir, installOptions) {
35
35
  });
36
36
  // Copy the node_modules to the outputDir
37
37
  fs.cpSync(path.join(tempInstallDir, "node_modules"), path.join(outputDir, "node_modules"), { recursive: true, force: true, dereference: true });
38
+ // This is a workaround for Node `22.17.0` and `22.17.1`
39
+ // https://github.com/nodejs/node/issues/59168
40
+ const nodeVersion = process.version;
41
+ if (nodeVersion === "v22.17.0" || nodeVersion === "v22.17.1") {
42
+ const tempBinDir = path.join(tempInstallDir, "node_modules", ".bin");
43
+ const outputBinDir = path.join(outputDir, "node_modules", ".bin");
44
+ for (const fileName of fs.readdirSync(tempBinDir)) {
45
+ const symlinkPath = path.join(tempBinDir, fileName);
46
+ const stat = fs.lstatSync(symlinkPath);
47
+ if (stat.isSymbolicLink()) {
48
+ const linkTarget = fs.readlinkSync(symlinkPath);
49
+ const realFilePath = path.resolve(tempBinDir, linkTarget);
50
+ const outputFilePath = path.join(outputBinDir, fileName);
51
+ if (fs.existsSync(outputFilePath)) {
52
+ fs.unlinkSync(outputFilePath);
53
+ }
54
+ fs.copyFileSync(realFilePath, outputFilePath);
55
+ fs.chmodSync(outputFilePath, "755");
56
+ logger.debug(`Replaced symlink ${fileName} with actual file`);
57
+ }
58
+ }
59
+ }
38
60
  // Cleanup tempDir
39
61
  fs.rmSync(tempInstallDir, { recursive: true, force: true });
40
62
  logger.info(`Dependencies installed for ${name}`);
@@ -1,15 +1,14 @@
1
1
  import type { getManifests } from "../copyTracedFiles.js";
2
2
  import * as buildHelper from "../helper.js";
3
- type Versions = `>=${number}.${number}.${number} <=${number}.${number}.${number}` | `>=${number}.${number}.${number}` | `<=${number}.${number}.${number}`;
4
- export interface VersionedField<T> {
5
- /**
6
- * The versions of Next.js that this field should be used for
7
- * Should be in the format `">=16.0.0 <=17.0.0"` or `">=16.0.0"` or `"<=17.0.0"`
8
- * **Be careful with spaces**
9
- */
10
- versions?: Versions;
11
- field: T;
12
- }
3
+ /**
4
+ * Accepted formats:
5
+ * - `">=16.0.0"`
6
+ * - `"<=16.0.0"`
7
+ * - `">=16.0.0 <=17.0.0"`
8
+ *
9
+ * **Be careful with spaces**
10
+ */
11
+ export type Versions = `>=${number}.${number}.${number} <=${number}.${number}.${number}` | `>=${number}.${number}.${number}` | `<=${number}.${number}.${number}`;
13
12
  export type PatchCodeFn = (args: {
14
13
  /**
15
14
  * The code of the file that needs to be patched
@@ -32,15 +31,23 @@ interface IndividualPatch {
32
31
  pathFilter: RegExp;
33
32
  contentFilter?: RegExp;
34
33
  patchCode: PatchCodeFn;
34
+ versions?: Versions;
35
35
  }
36
36
  export interface CodePatcher {
37
37
  name: string;
38
- patches: IndividualPatch | VersionedField<IndividualPatch>[];
38
+ patches: IndividualPatch[];
39
39
  }
40
40
  export declare function parseVersions(versions?: Versions): {
41
41
  before?: string;
42
42
  after?: string;
43
43
  };
44
- export declare function extractVersionedField<T>(fields: VersionedField<T>[], version: string): T[];
44
+ /**
45
+ * Check whether the version is in the range
46
+ *
47
+ * @param version A semver version
48
+ * @param versionRange A version range
49
+ * @returns whether the version satisfies the range
50
+ */
51
+ export declare function isVersionInRange(version: string, versionRange?: Versions): boolean;
45
52
  export declare function applyCodePatches(buildOptions: buildHelper.BuildOptions, tracedFiles: string[], manifests: ReturnType<typeof getManifests>, codePatcher: CodePatcher[]): Promise<void>;
46
53
  export {};
@@ -39,50 +39,33 @@ export function parseVersions(versions) {
39
39
  after,
40
40
  };
41
41
  }
42
- export function extractVersionedField(fields, version) {
43
- const result = [];
44
- for (const field of fields) {
45
- // No versions specified, the patch always apply
46
- if (!field.versions) {
47
- result.push(field.field);
48
- continue;
49
- }
50
- const { before, after } = parseVersions(field.versions);
51
- // range
52
- if (before && after) {
53
- if (buildHelper.compareSemver(version, "<=", before) &&
54
- buildHelper.compareSemver(version, ">=", after)) {
55
- result.push(field.field);
56
- }
57
- continue;
58
- }
59
- // before only
60
- if (before) {
61
- if (buildHelper.compareSemver(version, "<=", before)) {
62
- result.push(field.field);
63
- }
64
- continue;
65
- }
66
- // after only
67
- if (after) {
68
- if (buildHelper.compareSemver(version, ">=", after)) {
69
- result.push(field.field);
70
- }
71
- }
42
+ /**
43
+ * Check whether the version is in the range
44
+ *
45
+ * @param version A semver version
46
+ * @param versionRange A version range
47
+ * @returns whether the version satisfies the range
48
+ */
49
+ export function isVersionInRange(version, versionRange) {
50
+ const { before, after } = parseVersions(versionRange);
51
+ let inRange = true;
52
+ if (before) {
53
+ inRange &&= buildHelper.compareSemver(version, "<=", before);
54
+ }
55
+ if (after) {
56
+ inRange &&= buildHelper.compareSemver(version, ">=", after);
72
57
  }
73
- return result;
58
+ return inRange;
74
59
  }
75
60
  export async function applyCodePatches(buildOptions, tracedFiles, manifests, codePatcher) {
76
- const nextVersion = buildOptions.nextVersion;
77
61
  logger.time("Applying code patches");
78
62
  // We first filter against the version
79
63
  // We also flatten the array of patches so that we get both the name and all the necessary patches
80
- const patchesToApply = codePatcher.flatMap(({ name, patches }) => Array.isArray(patches)
81
- ? extractVersionedField(patches, nextVersion).map((patch) => ({
82
- name,
83
- patch,
84
- }))
85
- : [{ name, patch: patches }]);
64
+ const patchesToApply = codePatcher.flatMap(({ name, patches }) => {
65
+ return patches
66
+ .filter(({ versions }) => isVersionInRange(buildOptions.nextVersion, versions))
67
+ .map((patch) => ({ patch, name }));
68
+ });
86
69
  await Promise.all(tracedFiles.map(async (filePath) => {
87
70
  // We check the filename against the filter to see if we should apply the patch
88
71
  const patchMatchingPath = patchesToApply.filter(({ patch }) => {
@@ -3,9 +3,7 @@ export declare const patchBackgroundRevalidation: {
3
3
  name: string;
4
4
  patches: {
5
5
  versions: ">=14.1.0";
6
- field: {
7
- pathFilter: RegExp;
8
- patchCode: import("../codePatcher.js").PatchCodeFn;
9
- };
6
+ pathFilter: RegExp;
7
+ patchCode: import("../codePatcher.js").PatchCodeFn;
10
8
  }[];
11
9
  };
@@ -18,10 +18,8 @@ export const patchBackgroundRevalidation = {
18
18
  {
19
19
  // TODO: test for earlier versions of Next
20
20
  versions: ">=14.1.0",
21
- field: {
22
- pathFilter: getCrossPlatformPathRegex("server/response-cache/index.js"),
23
- patchCode: createPatchCode(rule),
24
- },
21
+ pathFilter: getCrossPlatformPathRegex("server/response-cache/index.js"),
22
+ patchCode: createPatchCode(rule),
25
23
  },
26
24
  ],
27
25
  };
@@ -24,29 +24,23 @@ export const patchEnvVars = {
24
24
  // This patch will set the `NEXT_RUNTIME` env var to "node" to avoid loading unnecessary edge deps at runtime
25
25
  {
26
26
  versions: ">=15.0.0",
27
- field: {
28
- pathFilter: /module\.compiled\.js$/,
29
- contentFilter: /process\.env\.NEXT_RUNTIME/,
30
- patchCode: createPatchCode(envVarRuleCreator("NEXT_RUNTIME", '"node"')),
31
- },
27
+ pathFilter: /module\.compiled\.js$/,
28
+ contentFilter: /process\.env\.NEXT_RUNTIME/,
29
+ patchCode: createPatchCode(envVarRuleCreator("NEXT_RUNTIME", '"node"')),
32
30
  },
33
31
  // This patch will set `NODE_ENV` to production to avoid loading unnecessary dev deps at runtime
34
32
  {
35
33
  versions: ">=15.0.0",
36
- field: {
37
- pathFilter: /(module\.compiled|react\/index|react\/jsx-runtime|react-dom\/index)\.js$/,
38
- contentFilter: /process\.env\.NODE_ENV/,
39
- patchCode: createPatchCode(envVarRuleCreator("NODE_ENV", '"production"')),
40
- },
34
+ pathFilter: /(module\.compiled|react\/index|react\/jsx-runtime|react-dom\/index)\.js$/,
35
+ contentFilter: /process\.env\.NODE_ENV/,
36
+ patchCode: createPatchCode(envVarRuleCreator("NODE_ENV", '"production"')),
41
37
  },
42
38
  // This patch will set `TURBOPACK` env to false to avoid loading turbopack related deps at runtime
43
39
  {
44
40
  versions: ">=15.0.0",
45
- field: {
46
- pathFilter: /module\.compiled\.js$/,
47
- contentFilter: /process\.env\.TURBOPACK/,
48
- patchCode: createPatchCode(envVarRuleCreator("TURBOPACK", "false")),
49
- },
41
+ pathFilter: /module\.compiled\.js$/,
42
+ contentFilter: /process\.env\.TURBOPACK/,
43
+ patchCode: createPatchCode(envVarRuleCreator("TURBOPACK", "false")),
50
44
  },
51
45
  ],
52
46
  };
@@ -1,7 +1,7 @@
1
1
  import type { CodePatcher } from "../codePatcher.js";
2
- export declare const fetchRule = "\nrule:\n kind: member_expression\n pattern: $WORK_STORE.isOnDemandRevalidate\n inside:\n kind: ternary_expression\n all:\n - has: {kind: 'null'}\n - has: \n kind: await_expression\n has:\n kind: call_expression\n all:\n - has:\n kind: member_expression\n has:\n kind: property_identifier\n field: property\n regex: get\n - has:\n kind: arguments\n has:\n kind: object\n has:\n kind: pair\n all:\n - has:\n kind: property_identifier\n field: key\n regex: softTags\n inside:\n kind: variable_declarator\n\nfix:\n ($WORK_STORE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)\n";
3
- export declare const unstable_cacheRule = "\nrule:\n kind: member_expression\n pattern: $STORE_OR_CACHE.isOnDemandRevalidate\n inside:\n kind: if_statement\n stopBy: end\n has:\n kind: statement_block\n has:\n kind: variable_declarator\n has: \n kind: await_expression\n has:\n kind: call_expression\n all:\n - has:\n kind: member_expression\n has:\n kind: property_identifier\n field: property\n regex: get\n - has:\n kind: arguments\n has:\n kind: object\n has:\n kind: pair\n all:\n - has:\n kind: property_identifier\n field: key\n regex: softTags\n stopBy: end\nfix:\n ($STORE_OR_CACHE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)\n";
4
- export declare const useCacheRule = "\nrule:\n kind: member_expression\n pattern: $STORE_OR_CACHE.isOnDemandRevalidate\n inside:\n kind: binary_expression\n has: \n kind: member_expression\n pattern: $STORE_OR_CACHE.isDraftMode\n inside:\n kind: if_statement\n stopBy: end\n has: \n kind: return_statement\n any:\n - has:\n kind: 'true'\n - has:\n regex: '!0'\n stopBy: end\nfix:\n '($STORE_OR_CACHE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)'";
2
+ export declare const fetchRule = "\nrule:\n kind: member_expression\n pattern: $WORK_STORE.isOnDemandRevalidate\n inside:\n kind: ternary_expression\n all:\n - has: {kind: 'null'}\n - has:\n kind: await_expression\n has:\n kind: call_expression\n all:\n - has:\n kind: member_expression\n has:\n kind: property_identifier\n field: property\n regex: get\n - has:\n kind: arguments\n has:\n kind: object\n has:\n kind: pair\n all:\n - has:\n kind: property_identifier\n field: key\n regex: softTags\n inside:\n kind: variable_declarator\n\nfix:\n ($WORK_STORE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)\n";
3
+ export declare const unstable_cacheRule = "\nrule:\n kind: member_expression\n pattern: $STORE_OR_CACHE.isOnDemandRevalidate\n inside:\n kind: if_statement\n stopBy: end\n has:\n kind: statement_block\n has:\n kind: variable_declarator\n has:\n kind: await_expression\n has:\n kind: call_expression\n all:\n - has:\n kind: member_expression\n has:\n kind: property_identifier\n field: property\n regex: get\n - has:\n kind: arguments\n has:\n kind: object\n has:\n kind: pair\n all:\n - has:\n kind: property_identifier\n field: key\n regex: softTags\n stopBy: end\nfix:\n ($STORE_OR_CACHE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)\n";
4
+ export declare const useCacheRule = "\nrule:\n kind: member_expression\n pattern: $STORE_OR_CACHE.isOnDemandRevalidate\n inside:\n kind: binary_expression\n has:\n kind: member_expression\n pattern: $STORE_OR_CACHE.isDraftMode\n inside:\n kind: if_statement\n stopBy: end\n has:\n kind: return_statement\n any:\n - has:\n kind: 'true'\n - has:\n regex: '!0'\n stopBy: end\nfix:\n '($STORE_OR_CACHE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)'";
5
5
  export declare const patchFetchCacheForISR: CodePatcher;
6
6
  export declare const patchUnstableCacheForISR: CodePatcher;
7
7
  export declare const patchUseCacheForISR: CodePatcher;
@@ -9,7 +9,7 @@ rule:
9
9
  kind: ternary_expression
10
10
  all:
11
11
  - has: {kind: 'null'}
12
- - has:
12
+ - has:
13
13
  kind: await_expression
14
14
  has:
15
15
  kind: call_expression
@@ -48,7 +48,7 @@ rule:
48
48
  kind: statement_block
49
49
  has:
50
50
  kind: variable_declarator
51
- has:
51
+ has:
52
52
  kind: await_expression
53
53
  has:
54
54
  kind: call_expression
@@ -80,13 +80,13 @@ rule:
80
80
  pattern: $STORE_OR_CACHE.isOnDemandRevalidate
81
81
  inside:
82
82
  kind: binary_expression
83
- has:
83
+ has:
84
84
  kind: member_expression
85
85
  pattern: $STORE_OR_CACHE.isDraftMode
86
86
  inside:
87
87
  kind: if_statement
88
88
  stopBy: end
89
- has:
89
+ has:
90
90
  kind: return_statement
91
91
  any:
92
92
  - has:
@@ -101,11 +101,9 @@ export const patchFetchCacheForISR = {
101
101
  patches: [
102
102
  {
103
103
  versions: ">=14.0.0",
104
- field: {
105
- pathFilter: getCrossPlatformPathRegex(String.raw `(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`, { escape: false }),
106
- contentFilter: /\.isOnDemandRevalidate/,
107
- patchCode: createPatchCode(fetchRule, Lang.JavaScript),
108
- },
104
+ pathFilter: getCrossPlatformPathRegex(String.raw `(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`, { escape: false }),
105
+ contentFilter: /\.isOnDemandRevalidate/,
106
+ patchCode: createPatchCode(fetchRule, Lang.JavaScript),
109
107
  },
110
108
  ],
111
109
  };
@@ -114,11 +112,9 @@ export const patchUnstableCacheForISR = {
114
112
  patches: [
115
113
  {
116
114
  versions: ">=14.2.0",
117
- field: {
118
- pathFilter: getCrossPlatformPathRegex(String.raw `(server/chunks/.*\.js|.*\.runtime\..*\.js|spec-extension/unstable-cache\.js)$`, { escape: false }),
119
- contentFilter: /\.isOnDemandRevalidate/,
120
- patchCode: createPatchCode(unstable_cacheRule, Lang.JavaScript),
121
- },
115
+ pathFilter: getCrossPlatformPathRegex(String.raw `(server/chunks/.*\.js|.*\.runtime\..*\.js|spec-extension/unstable-cache\.js)$`, { escape: false }),
116
+ contentFilter: /\.isOnDemandRevalidate/,
117
+ patchCode: createPatchCode(unstable_cacheRule, Lang.JavaScript),
122
118
  },
123
119
  ],
124
120
  };
@@ -127,11 +123,9 @@ export const patchUseCacheForISR = {
127
123
  patches: [
128
124
  {
129
125
  versions: ">=15.3.0",
130
- field: {
131
- pathFilter: getCrossPlatformPathRegex(String.raw `(server/chunks/.*\.js|\.runtime\..*\.js|use-cache/use-cache-wrapper\.js)$`, { escape: false }),
132
- contentFilter: /\.isOnDemandRevalidate/,
133
- patchCode: createPatchCode(useCacheRule, Lang.JavaScript),
134
- },
126
+ pathFilter: getCrossPlatformPathRegex(String.raw `(server/chunks/.*\.js|\.runtime\..*\.js|use-cache/use-cache-wrapper\.js)$`, { escape: false }),
127
+ contentFilter: /\.isOnDemandRevalidate/,
128
+ patchCode: createPatchCode(useCacheRule, Lang.JavaScript),
135
129
  },
136
130
  ],
137
131
  };
@@ -26,11 +26,9 @@ export const patchFetchCacheSetMissingWaitUntil = {
26
26
  patches: [
27
27
  {
28
28
  versions: ">=15.0.0",
29
- field: {
30
- pathFilter: getCrossPlatformPathRegex(String.raw `(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`, { escape: false }),
31
- contentFilter: /arrayBuffer\(\)\s*\.then/,
32
- patchCode: createPatchCode(rule),
33
- },
29
+ pathFilter: getCrossPlatformPathRegex(String.raw `(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`, { escape: false }),
30
+ contentFilter: /arrayBuffer\(\)\s*\.then/,
31
+ patchCode: createPatchCode(rule),
34
32
  },
35
33
  ],
36
34
  };
@@ -71,27 +71,21 @@ const pathFilter = getCrossPlatformPathRegex(String.raw `/next/dist/server/next-
71
71
  const babelPatches = [
72
72
  // Empty the body of `NextServer#runMiddleware`
73
73
  {
74
- field: {
75
- pathFilter,
76
- contentFilter: /runMiddleware\(/,
77
- patchCode: createPatchCode(createEmptyBodyRule("runMiddleware")),
78
- },
74
+ pathFilter,
75
+ contentFilter: /runMiddleware\(/,
76
+ patchCode: createPatchCode(createEmptyBodyRule("runMiddleware")),
79
77
  },
80
78
  // Empty the body of `NextServer#runEdgeFunction`
81
79
  {
82
- field: {
83
- pathFilter,
84
- contentFilter: /runEdgeFunction\(/,
85
- patchCode: createPatchCode(createEmptyBodyRule("runEdgeFunction")),
86
- },
80
+ pathFilter,
81
+ contentFilter: /runEdgeFunction\(/,
82
+ patchCode: createPatchCode(createEmptyBodyRule("runEdgeFunction")),
87
83
  },
88
84
  // Drop `error-inspect` that pulls babel
89
85
  {
90
- field: {
91
- pathFilter,
92
- contentFilter: /error-inspect/,
93
- patchCode: createPatchCode(errorInspectRule),
94
- },
86
+ pathFilter,
87
+ contentFilter: /error-inspect/,
88
+ patchCode: createPatchCode(errorInspectRule),
95
89
  },
96
90
  ];
97
91
  export const patchNextServer = {
@@ -99,30 +93,24 @@ export const patchNextServer = {
99
93
  patches: [
100
94
  // Empty the body of `NextServer#imageOptimizer` - unused in OpenNext
101
95
  {
102
- field: {
103
- pathFilter,
104
- contentFilter: /imageOptimizer\(/,
105
- patchCode: createPatchCode(createEmptyBodyRule("imageOptimizer")),
106
- },
96
+ pathFilter,
97
+ contentFilter: /imageOptimizer\(/,
98
+ patchCode: createPatchCode(createEmptyBodyRule("imageOptimizer")),
107
99
  },
108
100
  // Disable Next background preloading done at creation of `NextServer`
109
101
  {
110
102
  versions: ">=14.0.0",
111
- field: {
112
- pathFilter,
113
- contentFilter: /this\.nextConfig\.experimental\.preloadEntriesOnStart/,
114
- patchCode: createPatchCode(disablePreloadingRule),
115
- },
103
+ pathFilter,
104
+ contentFilter: /this\.nextConfig\.experimental\.preloadEntriesOnStart/,
105
+ patchCode: createPatchCode(disablePreloadingRule),
116
106
  },
117
107
  // Don't match edge functions in `NextServer`
118
108
  {
119
109
  // Next 12 and some version of 13 use the bundled middleware/edge function
120
110
  versions: ">=14.0.0",
121
- field: {
122
- pathFilter,
123
- contentFilter: /getMiddlewareManifest/,
124
- patchCode: createPatchCode(removeMiddlewareManifestRule),
125
- },
111
+ pathFilter,
112
+ contentFilter: /getMiddlewareManifest/,
113
+ patchCode: createPatchCode(removeMiddlewareManifestRule),
126
114
  },
127
115
  ...babelPatches,
128
116
  ],
@@ -72,7 +72,9 @@ export function validateConfig(config) {
72
72
  It is safe to disable if you only use page router`);
73
73
  }
74
74
  validateFunctionOptions(config.imageOptimization ?? {});
75
- validateFunctionOptions(config.middleware ?? {});
75
+ if (config.middleware?.external === true) {
76
+ validateFunctionOptions(config.middleware ?? {});
77
+ }
76
78
  //@ts-expect-error - Revalidate custom wrapper type is different
77
79
  validateFunctionOptions(config.revalidate ?? {});
78
80
  //@ts-expect-error - Warmer custom wrapper type is different
@@ -4,8 +4,10 @@ export async function createGenericHandler(handler) {
4
4
  // @ts-expect-error `./open-next.config.mjs` exists only in the build output
5
5
  const config = await import("./open-next.config.mjs").then((m) => m.default);
6
6
  globalThis.openNextConfig = config;
7
- const override = config[handler.type]
8
- ?.override;
7
+ const handlerConfig = config[handler.type];
8
+ const override = handlerConfig && "override" in handlerConfig
9
+ ? handlerConfig.override
10
+ : undefined;
9
11
  // From the config, we create the converter
10
12
  const converter = await resolveConverter(override?.converter);
11
13
  // Then we create the handler
@@ -4,7 +4,7 @@ import { runWithOpenNextRequestContext } from "../utils/promise";
4
4
  import { NextConfig } from "../adapters/config/index";
5
5
  import { debug, error } from "../adapters/logger";
6
6
  import { patchAsyncStorage } from "./patchAsyncStorage";
7
- import { constructNextUrl, convertRes, convertToQuery, createServerResponse, } from "./routing/util";
7
+ import { constructNextUrl, convertRes, convertToQuery, convertToQueryString, createServerResponse, } from "./routing/util";
8
8
  import routingHandler, { INTERNAL_EVENT_REQUEST_ID, INTERNAL_HEADER_INITIAL_URL, INTERNAL_HEADER_RESOLVED_ROUTES, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_HEADER_PREFIX_LEN, } from "./routingHandler";
9
9
  import { requestHandler, setNextjsPrebundledReact } from "./util";
10
10
  // This is used to identify requests in the cache
@@ -167,7 +167,10 @@ async function processRequest(req, res, routingResult) {
167
167
  // Here we try to apply as much request metadata as possible
168
168
  // We apply every metadata from `resolve-routes` https://github.com/vercel/next.js/blob/916f105b97211de50f8580f0b39c9e7c60de4886/packages/next/src/server/lib/router-utils/resolve-routes.ts
169
169
  // and `router-server` https://github.com/vercel/next.js/blob/916f105b97211de50f8580f0b39c9e7c60de4886/packages/next/src/server/lib/router-server.ts
170
- const initialURL = new URL(routingResult.initialURL);
170
+ const initialURL = new URL(
171
+ // We always assume that only the routing layer can set this header.
172
+ routingResult.internalEvent.headers[INTERNAL_HEADER_INITIAL_URL] ??
173
+ routingResult.initialURL);
171
174
  let invokeStatus;
172
175
  if (routingResult.internalEvent.rawPath === "/500") {
173
176
  invokeStatus = 500;
@@ -194,6 +197,13 @@ async function processRequest(req, res, routingResult) {
194
197
  setNextjsPrebundledReact(routingResult.internalEvent.rawPath);
195
198
  //#endOverride
196
199
  // Next Server
200
+ // TODO: only enable this on Next 15.4+
201
+ // We need to set the pathname to the data request path
202
+ //#override setInitialURL
203
+ req.url =
204
+ initialURL.pathname +
205
+ convertToQueryString(routingResult.internalEvent.query);
206
+ //#endOverride
197
207
  await requestHandler(requestMetadata)(req, res);
198
208
  }
199
209
  catch (e) {
@@ -253,6 +263,7 @@ async function tryRenderError(type, res, internalEvent) {
253
263
  }
254
264
  catch (e) {
255
265
  error("NextJS request failed.", e);
266
+ res.statusCode = 500;
256
267
  res.setHeader("Content-Type", "application/json");
257
268
  res.end(JSON.stringify({
258
269
  message: "Server failed to respond.",
@@ -1,4 +1,4 @@
1
- import type { BaseEventOrResult, DefaultOverrideOptions, InternalEvent, InternalResult, OpenNextConfig, OverrideOptions } from "../types/open-next";
1
+ import type { BaseEventOrResult, DefaultOverrideOptions, ExternalMiddlewareConfig, InternalEvent, InternalResult, OpenNextConfig, OverrideOptions } from "../types/open-next";
2
2
  import type { Converter, TagCache, Wrapper } from "../types/overrides";
3
3
  type RemoveUndefined<T> = T extends undefined ? never : T;
4
4
  export declare function resolveConverter<E extends BaseEventOrResult = InternalEvent, R extends BaseEventOrResult = InternalResult>(converter: DefaultOverrideOptions<E, R>["converter"]): Promise<Converter<E, R>>;
@@ -34,7 +34,7 @@ export declare function resolveImageLoader(imageLoader: RemoveUndefined<OpenNext
34
34
  * @returns
35
35
  * @__PURE__
36
36
  */
37
- export declare function resolveOriginResolver(originResolver: RemoveUndefined<OpenNextConfig["middleware"]>["originResolver"]): Promise<import("../types/overrides").OriginResolver>;
37
+ export declare function resolveOriginResolver(originResolver: RemoveUndefined<ExternalMiddlewareConfig>["originResolver"]): Promise<import("../types/overrides").OriginResolver>;
38
38
  /**
39
39
  * @returns
40
40
  * @__PURE__
@@ -144,6 +144,14 @@ export async function cacheInterceptor(event) {
144
144
  if (Boolean(event.headers["next-action"]) ||
145
145
  Boolean(event.headers["x-prerender-revalidate"]))
146
146
  return event;
147
+ // Check for Next.js preview mode cookies
148
+ const cookies = event.headers.cookie || "";
149
+ const hasPreviewData = cookies.includes("__prerender_bypass") ||
150
+ cookies.includes("__next_preview_data");
151
+ if (hasPreviewData) {
152
+ debug("Preview mode detected, passing through to handler");
153
+ return event;
154
+ }
147
155
  // We localize the path in case i18n is enabled
148
156
  let localizedPath = localizePath(event);
149
157
  // If using basePath we need to remove it from the path
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import type { OnLoadOptions, Plugin, PluginBuild } from "esbuild";
7
7
  import type { BuildOptions } from "../build/helper";
8
- import { type VersionedField } from "../build/patch/codePatcher.js";
8
+ import { type Versions } from "../build/patch/codePatcher.js";
9
9
  export type * from "esbuild";
10
10
  /**
11
11
  * The callbacks returns either an updated content or undefined if the content is unchanged.
@@ -23,6 +23,7 @@ export type OnUpdateOptions = OnLoadOptions & {
23
23
  };
24
24
  export type Updater = OnUpdateOptions & {
25
25
  callback: Callback;
26
+ versions?: Versions;
26
27
  };
27
28
  export declare class ContentUpdater {
28
29
  private buildOptions;
@@ -34,10 +35,10 @@ export declare class ContentUpdater {
34
35
  * The callbacks are called in order of registration.
35
36
  *
36
37
  * @param name The name of the plugin (must be unique).
37
- * @param updater A versioned field with the callback and `OnUpdateOptions`.
38
+ * @param updaters A list of code updaters
38
39
  * @returns A noop ESBuild plugin.
39
40
  */
40
- updateContent(name: string, versionedUpdaters: VersionedField<Updater>[]): Plugin;
41
+ updateContent(name: string, updaters: Updater[]): Plugin;
41
42
  /**
42
43
  * Returns an ESBuild plugin applying the registered updates.
43
44
  */
@@ -4,7 +4,7 @@
4
4
  * The updater allows multiple plugins to update the content.
5
5
  */
6
6
  import { readFile } from "node:fs/promises";
7
- import { extractVersionedField, } from "../build/patch/codePatcher.js";
7
+ import { isVersionInRange } from "../build/patch/codePatcher.js";
8
8
  export class ContentUpdater {
9
9
  buildOptions;
10
10
  updaters = new Map();
@@ -17,15 +17,14 @@ export class ContentUpdater {
17
17
  * The callbacks are called in order of registration.
18
18
  *
19
19
  * @param name The name of the plugin (must be unique).
20
- * @param updater A versioned field with the callback and `OnUpdateOptions`.
20
+ * @param updaters A list of code updaters
21
21
  * @returns A noop ESBuild plugin.
22
22
  */
23
- updateContent(name, versionedUpdaters) {
23
+ updateContent(name, updaters) {
24
24
  if (this.updaters.has(name)) {
25
25
  throw new Error(`Plugin "${name}" already registered`);
26
26
  }
27
- const updaters = extractVersionedField(versionedUpdaters, this.buildOptions.nextVersion);
28
- this.updaters.set(name, updaters);
27
+ this.updaters.set(name, updaters.filter(({ versions }) => isVersionInRange(this.buildOptions.nextVersion, versions)));
29
28
  return {
30
29
  name,
31
30
  setup() { },
@@ -244,43 +244,56 @@ export interface SplittedFunctionOptions extends FunctionOptions {
244
244
  */
245
245
  patterns: string[];
246
246
  }
247
+ /**
248
+ * MiddlewareConfig that applies to both external and internal middlewares
249
+ *
250
+ * Note: this type is internal and included in both `ExternalMiddlewareConfig` and `InternalMiddlewareConfig`
251
+ */
252
+ type CommonMiddlewareConfig = {
253
+ /**
254
+ * The assetResolver is used to resolve assets in the routing layer.
255
+ *
256
+ * @default "dummy"
257
+ */
258
+ assetResolver?: IncludedAssetResolver | LazyLoadedOverride<AssetResolver>;
259
+ };
260
+ /** MiddlewareConfig that applies to external middlewares only */
261
+ export type ExternalMiddlewareConfig = DefaultFunctionOptions & CommonMiddlewareConfig & {
262
+ external: true;
263
+ /**
264
+ * The runtime used by next for the middleware.
265
+ * @default "edge"
266
+ */
267
+ runtime?: "node" | "edge";
268
+ /**
269
+ * The override options for the middleware.
270
+ * By default the lite override are used (.i.e. s3-lite, dynamodb-lite, sqs-lite)
271
+ * @default undefined
272
+ */
273
+ override?: OverrideOptions;
274
+ /**
275
+ * Origin resolver is used to resolve the origin for internal rewrite.
276
+ * By default, it uses the pattern-env origin resolver.
277
+ * Pattern env uses pattern set in split function options and an env variable OPEN_NEXT_ORIGIN
278
+ * OPEN_NEXT_ORIGIN should be a json stringified object with the key of the splitted function as key and the origin as value
279
+ * @default "pattern-env"
280
+ */
281
+ originResolver?: IncludedOriginResolver | LazyLoadedOverride<OriginResolver>;
282
+ };
283
+ /** MiddlewareConfig that applies to internal middlewares only */
284
+ export type InternalMiddlewareConfig = {
285
+ external: false;
286
+ } & CommonMiddlewareConfig;
247
287
  export interface OpenNextConfig {
248
288
  default: FunctionOptions;
249
289
  functions?: Record<string, SplittedFunctionOptions>;
250
290
  /**
251
291
  * Override the default middleware
252
- * If you set this options, the middleware need to be deployed separately.
292
+ * When `external` is true, the middleware need to be deployed separately.
253
293
  * It supports both edge and node runtime.
254
- * @default undefined
294
+ * @default undefined - Which is equivalent to `external: false`
255
295
  */
256
- middleware?: DefaultFunctionOptions & {
257
- external: true;
258
- /**
259
- * The runtime used by next for the middleware.
260
- * @default "edge"
261
- */
262
- runtime?: "node" | "edge";
263
- /**
264
- * The override options for the middleware.
265
- * By default the lite override are used (.i.e. s3-lite, dynamodb-lite, sqs-lite)
266
- * @default undefined
267
- */
268
- override?: OverrideOptions;
269
- /**
270
- * Origin resolver is used to resolve the origin for internal rewrite.
271
- * By default, it uses the pattern-env origin resolver.
272
- * Pattern env uses pattern set in split function options and an env variable OPEN_NEXT_ORIGIN
273
- * OPEN_NEXT_ORIGIN should be a json stringified object with the key of the splitted function as key and the origin as value
274
- * @default "pattern-env"
275
- */
276
- originResolver?: IncludedOriginResolver | LazyLoadedOverride<OriginResolver>;
277
- /**
278
- * The assetResolver is used to resolve assets in the routing layer.
279
- *
280
- * @default "dummy"
281
- */
282
- assetResolver?: IncludedAssetResolver | LazyLoadedOverride<AssetResolver>;
283
- };
296
+ middleware?: ExternalMiddlewareConfig | InternalMiddlewareConfig;
284
297
  /**
285
298
  * Override the default warmer
286
299
  * By default, works for lambda only.
@@ -362,3 +375,4 @@ export interface OpenNextConfig {
362
375
  */
363
376
  edgeExternals?: string[];
364
377
  }
378
+ export {};
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "access": "public"
4
4
  },
5
5
  "name": "@opennextjs/aws",
6
- "version": "3.7.0",
6
+ "version": "3.7.2",
7
7
  "bin": {
8
8
  "open-next": "./dist/index.js"
9
9
  },