@opennextjs/aws 3.1.6 → 3.2.1

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 (152) hide show
  1. package/README.md +27 -22
  2. package/dist/adapters/binary.js +2 -0
  3. package/dist/adapters/cache.d.ts +4 -2
  4. package/dist/adapters/cache.js +14 -8
  5. package/dist/adapters/config/util.d.ts +2 -2
  6. package/dist/adapters/image-optimization-adapter.d.ts +2 -2
  7. package/dist/adapters/middleware.js +5 -52
  8. package/dist/adapters/plugins/image-optimization/image-optimization.d.ts +7 -4
  9. package/dist/adapters/plugins/image-optimization/image-optimization.js +2 -3
  10. package/dist/adapters/plugins/image-optimization/image-optimization.replacement.d.ts +3 -0
  11. package/dist/adapters/plugins/image-optimization/image-optimization.replacement.js +4 -7
  12. package/dist/adapters/warmer-function.js +2 -67
  13. package/dist/build/buildNextApp.d.ts +3 -0
  14. package/dist/build/buildNextApp.js +19 -0
  15. package/dist/build/bundleNextServer.js +2 -2
  16. package/dist/build/compileCache.d.ts +9 -0
  17. package/dist/build/compileCache.js +30 -0
  18. package/dist/build/compileConfig.d.ts +17 -3
  19. package/dist/build/compileConfig.js +56 -34
  20. package/dist/build/compileTagCacheProvider.d.ts +2 -0
  21. package/dist/build/compileTagCacheProvider.js +26 -0
  22. package/dist/build/copyTracedFiles.js +2 -2
  23. package/dist/build/createAssets.d.ts +11 -0
  24. package/dist/build/createAssets.js +161 -0
  25. package/dist/build/createImageOptimizationBundle.d.ts +2 -0
  26. package/dist/build/createImageOptimizationBundle.js +82 -0
  27. package/dist/build/createMiddleware.d.ts +10 -0
  28. package/dist/build/createMiddleware.js +47 -0
  29. package/dist/build/createRevalidationBundle.d.ts +2 -0
  30. package/dist/build/createRevalidationBundle.js +35 -0
  31. package/dist/build/createServerBundle.d.ts +2 -2
  32. package/dist/build/createServerBundle.js +35 -39
  33. package/dist/build/createWarmerBundle.d.ts +2 -0
  34. package/dist/build/createWarmerBundle.js +44 -0
  35. package/dist/build/edge/createEdgeBundle.d.ts +6 -8
  36. package/dist/build/edge/createEdgeBundle.js +11 -15
  37. package/dist/build/helper.d.ts +22 -5
  38. package/dist/build/helper.js +42 -11
  39. package/dist/build/installDeps.d.ts +2 -0
  40. package/dist/build/installDeps.js +46 -0
  41. package/dist/build/utils.d.ts +5 -0
  42. package/dist/build/utils.js +22 -0
  43. package/dist/build/validateConfig.d.ts +1 -1
  44. package/dist/build.d.ts +0 -4
  45. package/dist/build.js +26 -486
  46. package/dist/core/createGenericHandler.js +5 -5
  47. package/dist/core/createMainHandler.d.ts +3 -3
  48. package/dist/core/createMainHandler.js +5 -5
  49. package/dist/core/requestHandler.d.ts +2 -2
  50. package/dist/core/requestHandler.js +2 -2
  51. package/dist/core/resolve.d.ts +13 -4
  52. package/dist/core/resolve.js +30 -5
  53. package/dist/core/routing/cacheInterceptor.d.ts +1 -1
  54. package/dist/core/routing/i18n/index.d.ts +1 -1
  55. package/dist/core/routing/i18n/index.js +3 -0
  56. package/dist/core/routing/matcher.d.ts +2 -1
  57. package/dist/core/routing/matcher.js +13 -6
  58. package/dist/core/routing/middleware.d.ts +6 -2
  59. package/dist/core/routing/middleware.js +13 -7
  60. package/dist/core/routing/util.d.ts +3 -2
  61. package/dist/core/routing/util.js +16 -7
  62. package/dist/core/routingHandler.d.ts +1 -1
  63. package/dist/core/routingHandler.js +1 -1
  64. package/dist/helpers/withCloudflare.d.ts +1 -1
  65. package/dist/helpers/withSST.d.ts +1 -1
  66. package/dist/http/openNextResponse.d.ts +10 -2
  67. package/dist/http/openNextResponse.js +27 -0
  68. package/dist/http/request.d.ts +1 -0
  69. package/dist/http/util.d.ts +1 -1
  70. package/dist/{converters → overrides/converters}/aws-apigw-v1.d.ts +1 -1
  71. package/dist/{converters → overrides/converters}/aws-apigw-v1.js +2 -2
  72. package/dist/{converters → overrides/converters}/aws-apigw-v2.d.ts +1 -1
  73. package/dist/{converters → overrides/converters}/aws-apigw-v2.js +4 -4
  74. package/dist/{converters → overrides/converters}/aws-cloudfront.d.ts +1 -1
  75. package/dist/{converters → overrides/converters}/aws-cloudfront.js +6 -7
  76. package/dist/{converters → overrides/converters}/dummy.d.ts +1 -1
  77. package/dist/overrides/converters/edge.d.ts +9 -0
  78. package/dist/{converters → overrides/converters}/edge.js +6 -3
  79. package/dist/{converters → overrides/converters}/node.d.ts +1 -1
  80. package/dist/{converters → overrides/converters}/node.js +1 -1
  81. package/dist/overrides/converters/sqs-revalidate.d.ts +4 -0
  82. package/dist/overrides/imageLoader/dummy.d.ts +3 -0
  83. package/dist/overrides/imageLoader/dummy.js +8 -0
  84. package/dist/overrides/imageLoader/host.d.ts +1 -1
  85. package/dist/overrides/imageLoader/s3.d.ts +1 -1
  86. package/dist/overrides/incrementalCache/dummy.d.ts +3 -0
  87. package/dist/overrides/incrementalCache/dummy.js +13 -0
  88. package/dist/{cache/incremental → overrides/incrementalCache}/s3-lite.d.ts +1 -1
  89. package/dist/{cache/incremental → overrides/incrementalCache}/s3.d.ts +1 -1
  90. package/dist/{cache/incremental → overrides/incrementalCache}/types.d.ts +1 -1
  91. package/dist/overrides/originResolver/dummy.d.ts +3 -0
  92. package/dist/overrides/originResolver/dummy.js +7 -0
  93. package/dist/overrides/originResolver/pattern-env.d.ts +3 -0
  94. package/dist/overrides/originResolver/pattern-env.js +39 -0
  95. package/dist/overrides/queue/dummy.d.ts +3 -0
  96. package/dist/overrides/queue/dummy.js +7 -0
  97. package/dist/{queue → overrides/queue}/sqs-lite.d.ts +1 -1
  98. package/dist/{queue → overrides/queue}/sqs-lite.js +3 -3
  99. package/dist/{queue → overrides/queue}/sqs.d.ts +1 -1
  100. package/dist/{queue → overrides/queue}/sqs.js +1 -1
  101. package/dist/overrides/tagCache/dummy.d.ts +3 -0
  102. package/dist/overrides/tagCache/dummy.js +17 -0
  103. package/dist/{cache/tag → overrides/tagCache}/dynamodb-lite.d.ts +1 -1
  104. package/dist/{cache/tag → overrides/tagCache}/dynamodb-lite.js +1 -1
  105. package/dist/{cache/tag → overrides/tagCache}/dynamodb.d.ts +1 -1
  106. package/dist/{cache/tag → overrides/tagCache}/dynamodb.js +1 -1
  107. package/dist/overrides/warmer/aws-lambda.d.ts +3 -0
  108. package/dist/overrides/warmer/aws-lambda.js +59 -0
  109. package/dist/overrides/warmer/dummy.d.ts +3 -0
  110. package/dist/overrides/warmer/dummy.js +7 -0
  111. package/dist/overrides/wrappers/aws-lambda-streaming.d.ts +7 -0
  112. package/dist/{wrappers → overrides/wrappers}/aws-lambda-streaming.js +1 -1
  113. package/dist/overrides/wrappers/aws-lambda.d.ts +7 -0
  114. package/dist/{wrappers → overrides/wrappers}/cloudflare.d.ts +2 -2
  115. package/dist/{wrappers → overrides/wrappers}/cloudflare.js +1 -1
  116. package/dist/overrides/wrappers/dummy.d.ts +7 -0
  117. package/dist/overrides/wrappers/dummy.js +6 -0
  118. package/dist/overrides/wrappers/node.d.ts +7 -0
  119. package/dist/{wrappers → overrides/wrappers}/node.js +1 -1
  120. package/dist/plugins/edge.d.ts +5 -4
  121. package/dist/plugins/edge.js +27 -29
  122. package/dist/plugins/replacement.d.ts +2 -2
  123. package/dist/plugins/replacement.js +4 -5
  124. package/dist/plugins/resolve.d.ts +4 -2
  125. package/dist/plugins/resolve.js +32 -20
  126. package/dist/types/aws-lambda.d.ts +3 -2
  127. package/dist/{cache/next-types.d.ts → types/cache.d.ts} +1 -0
  128. package/dist/types/next-types.d.ts +3 -1
  129. package/dist/types/open-next.d.ts +44 -13
  130. package/package.json +2 -2
  131. package/dist/adapters/plugins/without-routing/requestHandler.d.ts +0 -2
  132. package/dist/adapters/plugins/without-routing/requestHandler.js +0 -10
  133. package/dist/converters/edge.d.ts +0 -6
  134. package/dist/converters/sqs-revalidate.d.ts +0 -4
  135. package/dist/wrappers/aws-lambda-streaming.d.ts +0 -7
  136. package/dist/wrappers/aws-lambda.d.ts +0 -7
  137. package/dist/wrappers/node.d.ts +0 -7
  138. /package/dist/{converters → overrides/converters}/dummy.js +0 -0
  139. /package/dist/{converters → overrides/converters}/sqs-revalidate.js +0 -0
  140. /package/dist/{converters → overrides/converters}/utils.d.ts +0 -0
  141. /package/dist/{converters → overrides/converters}/utils.js +0 -0
  142. /package/dist/{cache/incremental → overrides/incrementalCache}/s3-lite.js +0 -0
  143. /package/dist/{cache/incremental → overrides/incrementalCache}/s3.js +0 -0
  144. /package/dist/{cache/incremental → overrides/incrementalCache}/types.js +0 -0
  145. /package/dist/{queue → overrides/queue}/types.d.ts +0 -0
  146. /package/dist/{cache/tag → overrides/queue}/types.js +0 -0
  147. /package/dist/{cache/tag → overrides/tagCache}/constants.d.ts +0 -0
  148. /package/dist/{cache/tag → overrides/tagCache}/constants.js +0 -0
  149. /package/dist/{cache/tag → overrides/tagCache}/types.d.ts +0 -0
  150. /package/dist/{queue → overrides/tagCache}/types.js +0 -0
  151. /package/dist/{wrappers → overrides/wrappers}/aws-lambda.js +0 -0
  152. /package/dist/{cache/next-types.js → types/cache.js} +0 -0
@@ -3,7 +3,7 @@ export async function resolveConverter(converter) {
3
3
  return converter();
4
4
  }
5
5
  else {
6
- const m_1 = await import(`../converters/aws-apigw-v2.js`);
6
+ const m_1 = await import(`../overrides/converters/aws-apigw-v2.js`);
7
7
  // @ts-expect-error
8
8
  return m_1.default;
9
9
  }
@@ -14,7 +14,7 @@ export async function resolveWrapper(wrapper) {
14
14
  }
15
15
  else {
16
16
  // This will be replaced by the bundler
17
- const m_1 = await import("../wrappers/aws-lambda.js");
17
+ const m_1 = await import("../overrides/wrappers/aws-lambda.js");
18
18
  // @ts-expect-error
19
19
  return m_1.default;
20
20
  }
@@ -31,7 +31,7 @@ export async function resolveTagCache(tagCache) {
31
31
  }
32
32
  else {
33
33
  // This will be replaced by the bundler
34
- const m_1 = await import("../cache/tag/dynamodb.js");
34
+ const m_1 = await import("../overrides/tagCache/dynamodb.js");
35
35
  return m_1.default;
36
36
  }
37
37
  }
@@ -46,7 +46,7 @@ export async function resolveQueue(queue) {
46
46
  return queue();
47
47
  }
48
48
  else {
49
- const m_1 = await import("../queue/sqs.js");
49
+ const m_1 = await import("../overrides/queue/sqs.js");
50
50
  return m_1.default;
51
51
  }
52
52
  }
@@ -61,7 +61,7 @@ export async function resolveIncrementalCache(incrementalCache) {
61
61
  return incrementalCache();
62
62
  }
63
63
  else {
64
- const m_1 = await import("../cache/incremental/s3.js");
64
+ const m_1 = await import("../overrides/incrementalCache/s3.js");
65
65
  return m_1.default;
66
66
  }
67
67
  }
@@ -79,3 +79,28 @@ export async function resolveImageLoader(imageLoader) {
79
79
  return m_1.default;
80
80
  }
81
81
  }
82
+ /**
83
+ * @returns
84
+ * @__PURE__
85
+ */
86
+ export async function resolveOriginResolver(originResolver) {
87
+ if (typeof originResolver === "function") {
88
+ return originResolver();
89
+ }
90
+ else {
91
+ const m_1 = await import("../overrides/originResolver/pattern-env.js");
92
+ return m_1.default;
93
+ }
94
+ }
95
+ /**
96
+ * @__PURE__
97
+ */
98
+ export async function resolveWarmerInvoke(warmer) {
99
+ if (typeof warmer === "function") {
100
+ return warmer();
101
+ }
102
+ else {
103
+ const m_1 = await import("../overrides/warmer/aws-lambda.js");
104
+ return m_1.default;
105
+ }
106
+ }
@@ -1,2 +1,2 @@
1
- import { InternalEvent, InternalResult } from "../../types/open-next";
1
+ import type { InternalEvent, InternalResult } from "../../types/open-next";
2
2
  export declare function cacheInterceptor(event: InternalEvent): Promise<InternalEvent | InternalResult>;
@@ -1,2 +1,2 @@
1
- import { InternalEvent } from "../../../types/open-next";
1
+ import type { InternalEvent } from "../../../types/open-next";
2
2
  export declare function localizePath(internalEvent: InternalEvent): string;
@@ -13,6 +13,9 @@ function getLocaleFromCookie(cookies) {
13
13
  : undefined;
14
14
  }
15
15
  function detectLocale(internalEvent, i18n) {
16
+ if (i18n.localeDetection === false) {
17
+ return i18n.defaultLocale;
18
+ }
16
19
  const cookiesLocale = getLocaleFromCookie(internalEvent.cookies);
17
20
  const preferredLocale = acceptLanguage(internalEvent.headers["accept-language"], i18n?.locales);
18
21
  debug({
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import type { Header, PrerenderManifest, RedirectDefinition, RewriteDefinition } from "../../types/next-types";
3
- import { InternalEvent, InternalResult } from "../../types/open-next";
4
+ import type { InternalEvent, InternalResult } from "../../types/open-next";
4
5
  export declare function addNextConfigHeaders(event: InternalEvent, configHeaders?: Header[] | undefined): Record<string, string | undefined>;
5
6
  export declare function handleRewrites<T extends RewriteDefinition>(event: InternalEvent, rewrites: T[]): {
6
7
  internalEvent: {
@@ -1,5 +1,5 @@
1
1
  import { NextConfig } from "../../adapters/config/index";
2
- import { compile, match, } from "path-to-regexp";
2
+ import { compile, match } from "path-to-regexp";
3
3
  import { emptyReadableStream, toReadableStream } from "../../utils/stream";
4
4
  import { debug } from "../../adapters/logger";
5
5
  import { localizePath } from "./i18n";
@@ -122,10 +122,16 @@ export function handleRewrites(event, rewrites) {
122
122
  const { pathname, protocol, hostname, queryString } = getUrlParts(rewrite.destination, isExternalRewrite);
123
123
  // We need to use a localized path if the rewrite is not locale specific
124
124
  const pathToUse = rewrite.locale === false ? rawPath : localizedRawPath;
125
+ // We need to encode the "+" character with its UTF-8 equivalent "%20" to avoid 2 issues:
126
+ // 1. The compile function from path-to-regexp will throw an error if it finds a "+" character.
127
+ // https://github.com/pillarjs/path-to-regexp?tab=readme-ov-file#unexpected--or-
128
+ // 2. The convertToQueryString function will replace the "+" character with %2B instead of %20.
129
+ // %2B does not get interpreted as a space in the URL thus breaking the query string.
130
+ const encodePlusQueryString = queryString.replaceAll("+", "%20");
125
131
  debug("urlParts", { pathname, protocol, hostname, queryString });
126
132
  const toDestinationPath = compile(escapeRegex(pathname ?? "") ?? "");
127
133
  const toDestinationHost = compile(escapeRegex(hostname ?? "") ?? "");
128
- const toDestinationQuery = compile(escapeRegex(queryString ?? "") ?? "");
134
+ const toDestinationQuery = compile(escapeRegex(encodePlusQueryString ?? "") ?? "");
129
135
  let params = {
130
136
  // params for the source
131
137
  ...getParamsFromSource(match(escapeRegex(rewrite?.source) ?? ""))(pathToUse),
@@ -139,7 +145,7 @@ export function handleRewrites(event, rewrites) {
139
145
  }, {}),
140
146
  };
141
147
  const isUsingParams = Object.keys(params).length > 0;
142
- let rewrittenQuery = queryString;
148
+ let rewrittenQuery = encodePlusQueryString;
143
149
  let rewrittenHost = hostname;
144
150
  let rewrittenPath = pathname;
145
151
  if (isUsingParams) {
@@ -149,7 +155,7 @@ export function handleRewrites(event, rewrites) {
149
155
  }
150
156
  rewrittenUrl = isExternalRewrite
151
157
  ? `${protocol}//${rewrittenHost}${rewrittenPath}`
152
- : `/${rewrittenPath}`;
158
+ : `${rewrittenPath}`;
153
159
  // Should we merge the query params or use only the ones from the rewrite?
154
160
  finalQuery = {
155
161
  ...query,
@@ -244,8 +250,9 @@ export function fixDataPage(internalEvent, buildId) {
244
250
  };
245
251
  }
246
252
  if (rawPath.startsWith(dataPattern) && rawPath.endsWith(".json")) {
247
- let newPath = rawPath.replace(dataPattern, "").replace(/\.json$/, "");
248
- newPath = newPath === "/index" ? "/" : newPath;
253
+ const newPath = rawPath
254
+ .slice(dataPattern.length, -".json".length)
255
+ .replace(/^\/index$/, "/");
249
256
  query.__nextDataReq = "1";
250
257
  return {
251
258
  ...internalEvent,
@@ -1,7 +1,11 @@
1
- import { InternalEvent, InternalResult } from "../../types/open-next.js";
1
+ import type { InternalEvent, InternalResult } from "../../types/open-next.js";
2
2
  type MiddlewareOutputEvent = InternalEvent & {
3
3
  responseHeaders?: Record<string, string | string[]>;
4
4
  externalRewrite?: boolean;
5
5
  };
6
- export declare function handleMiddleware(internalEvent: InternalEvent): Promise<MiddlewareOutputEvent | InternalResult>;
6
+ type Middleware = (request: Request) => Response | Promise<Response>;
7
+ type MiddlewareLoader = () => Promise<{
8
+ default: Middleware;
9
+ }>;
10
+ export declare function handleMiddleware(internalEvent: InternalEvent, middlewareLoader?: MiddlewareLoader): Promise<MiddlewareOutputEvent | InternalResult>;
7
11
  export {};
@@ -11,12 +11,16 @@ import { localizePath } from "./i18n/index.js";
11
11
  import { convertBodyToReadableStream, convertToQueryString, getMiddlewareMatch, isExternal, } from "./util.js";
12
12
  const middlewareManifest = MiddlewareManifest;
13
13
  const middleMatch = getMiddlewareMatch(middlewareManifest);
14
+ function defaultMiddlewareLoader() {
15
+ // @ts-expect-error - This is bundled
16
+ return import("./middleware.mjs");
17
+ }
14
18
  // NOTE: As of Nextjs 13.4.13+, the middleware is handled outside the next-server.
15
19
  // OpenNext will run the middleware in a sandbox and set the appropriate req headers
16
20
  // and res.body prior to processing the next-server.
17
21
  // @returns undefined | res.end()
18
22
  // if res.end() is return, the parent needs to return and not process next server
19
- export async function handleMiddleware(internalEvent) {
23
+ export async function handleMiddleware(internalEvent, middlewareLoader = defaultMiddlewareLoader) {
20
24
  const { query } = internalEvent;
21
25
  const normalizedPath = localizePath(internalEvent);
22
26
  // We only need the normalizedPath to check if the middleware should run
@@ -26,15 +30,17 @@ export async function handleMiddleware(internalEvent) {
26
30
  // We bypass the middleware if the request is internal
27
31
  if (internalEvent.headers["x-isr"])
28
32
  return internalEvent;
33
+ // Retrieve the protocol:
34
+ // - In lambda, the url only contains the rawPath and the query - default to https
35
+ // - In cloudflare, the protocol is usually http in dev and https in production
36
+ const protocol = internalEvent.url.startsWith("http://") ? "http:" : "https:";
29
37
  const host = internalEvent.headers.host
30
- ? `https://${internalEvent.headers.host}`
38
+ ? `${protocol}//${internalEvent.headers.host}`
31
39
  : "http://localhost:3000";
32
40
  const initialUrl = new URL(normalizedPath, host);
33
41
  initialUrl.search = convertToQueryString(query);
34
42
  const url = initialUrl.toString();
35
- // console.log("url", url, normalizedPath);
36
- // @ts-expect-error - This is bundled
37
- const middleware = await import("./middleware.mjs");
43
+ const middleware = await middlewareLoader();
38
44
  const result = await middleware.default({
39
45
  geo: {
40
46
  city: internalEvent.headers["x-open-next-city"],
@@ -93,7 +99,7 @@ export async function handleMiddleware(internalEvent) {
93
99
  resHeaders.location =
94
100
  responseHeaders
95
101
  .get("location")
96
- ?.replace("http://localhost:3000", `https://${internalEvent.headers.host}`) ?? resHeaders.location;
102
+ ?.replace("http://localhost:3000", `${protocol}//${internalEvent.headers.host}`) ?? resHeaders.location;
97
103
  // res.setHeader("Location", location);
98
104
  return {
99
105
  body: emptyReadableStream(),
@@ -153,7 +159,7 @@ export async function handleMiddleware(internalEvent) {
153
159
  responseHeaders: resHeaders,
154
160
  url: newUrl,
155
161
  rawPath: rewritten
156
- ? newUrl ?? internalEvent.rawPath
162
+ ? (newUrl ?? internalEvent.rawPath)
157
163
  : internalEvent.rawPath,
158
164
  type: internalEvent.type,
159
165
  headers: { ...internalEvent.headers, ...reqHeaders },
@@ -1,10 +1,11 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
- import { OutgoingHttpHeaders } from "node:http";
3
+ /// <reference types="node" />
4
+ import type { OutgoingHttpHeaders } from "node:http";
4
5
  import type { IncomingMessage, StreamCreator } from "../../http/index.js";
5
6
  import { OpenNextNodeResponse } from "../../http/openNextResponse.js";
6
7
  import type { MiddlewareManifest } from "../../types/next-types";
7
- import { InternalEvent, InternalResult } from "../../types/open-next.js";
8
+ import type { InternalEvent, InternalResult } from "../../types/open-next.js";
8
9
  /**
9
10
  *
10
11
  * @__PURE__
@@ -1,6 +1,6 @@
1
1
  import crypto from "node:crypto";
2
2
  import { Readable } from "node:stream";
3
- import { BuildId, HtmlPages } from "../../adapters/config/index.js";
3
+ import { BuildId, HtmlPages, NextConfig } from "../../adapters/config/index.js";
4
4
  import { OpenNextNodeResponse } from "../../http/openNextResponse.js";
5
5
  import { parseHeaders } from "../../http/util.js";
6
6
  import { isBinaryContentType } from "../../adapters/binary.js";
@@ -37,7 +37,7 @@ export function getUrlParts(url, isExternal) {
37
37
  const match = url.match(regex);
38
38
  return {
39
39
  hostname: "",
40
- pathname: match?.[1] ?? url,
40
+ pathname: match?.[1] ? `/${match[1]}` : url,
41
41
  protocol: "",
42
42
  queryString: match?.[2] ?? "",
43
43
  };
@@ -50,7 +50,7 @@ export function getUrlParts(url, isExternal) {
50
50
  return {
51
51
  protocol: match[1] ?? "https:",
52
52
  hostname: match[2],
53
- pathname: match[3],
53
+ pathname: match[3] ?? "",
54
54
  queryString: match[4]?.slice(1) ?? "",
55
55
  };
56
56
  }
@@ -84,13 +84,16 @@ export function convertRes(res) {
84
84
  * @__PURE__
85
85
  */
86
86
  export function convertToQueryString(query) {
87
+ // URLSearchParams is a representation of the PARSED query.
88
+ // So we must decode the value before appending it to the URLSearchParams.
89
+ // https://stackoverflow.com/a/45516812
87
90
  const urlQuery = new URLSearchParams();
88
91
  Object.entries(query).forEach(([key, value]) => {
89
92
  if (Array.isArray(value)) {
90
- value.forEach((entry) => urlQuery.append(key, entry));
93
+ value.forEach((entry) => urlQuery.append(key, decodeURIComponent(entry)));
91
94
  }
92
95
  else {
93
- urlQuery.append(key, value);
96
+ urlQuery.append(key, decodeURIComponent(value));
94
97
  }
95
98
  });
96
99
  const queryString = urlQuery.toString();
@@ -237,6 +240,9 @@ var CommonHeaders;
237
240
  export function fixCacheHeaderForHtmlPages(rawPath, headers) {
238
241
  // We don't want to cache error pages
239
242
  if (rawPath === "/404" || rawPath === "/500") {
243
+ if (process.env.OPEN_NEXT_DANGEROUSLY_SET_ERROR_HEADERS === "true") {
244
+ return;
245
+ }
240
246
  headers[CommonHeaders.CACHE_CONTROL] =
241
247
  "private, no-cache, no-store, max-age=0, must-revalidate";
242
248
  return;
@@ -268,7 +274,9 @@ export function fixSWRCacheHeader(headers) {
268
274
  * @__PURE__
269
275
  */
270
276
  export function addOpenNextHeader(headers) {
271
- headers["X-OpenNext"] = "1";
277
+ if (NextConfig.poweredByHeader) {
278
+ headers["X-OpenNext"] = "1";
279
+ }
272
280
  if (globalThis.openNextDebug) {
273
281
  headers["X-OpenNext-Version"] = globalThis.openNextVersion;
274
282
  headers["X-OpenNext-RequestId"] = globalThis.__als.getStore()?.requestId;
@@ -383,7 +391,8 @@ export function fixISRHeaders(headers) {
383
391
  // 31536000 is the default s-maxage value for SSG pages
384
392
  if (sMaxAge && sMaxAge !== 31536000) {
385
393
  const remainingTtl = Math.max(sMaxAge - age, 1);
386
- headers[CommonHeaders.CACHE_CONTROL] = `s-maxage=${remainingTtl}, stale-while-revalidate=2592000`;
394
+ headers[CommonHeaders.CACHE_CONTROL] =
395
+ `s-maxage=${remainingTtl}, stale-while-revalidate=2592000`;
387
396
  }
388
397
  }
389
398
  if (headers[CommonHeaders.NEXT_CACHE] !== "STALE")
@@ -1,4 +1,4 @@
1
- import { InternalEvent, InternalResult, Origin } from "../types/open-next";
1
+ import type { InternalEvent, InternalResult, Origin } from "../types/open-next";
2
2
  export interface MiddlewareOutputEvent {
3
3
  internalEvent: InternalEvent;
4
4
  isExternalRewrite: boolean;
@@ -30,7 +30,7 @@ function applyMiddlewareHeaders(eventHeaders, middlewareHeaders, setPrefix = tru
30
30
  });
31
31
  }
32
32
  export default async function routingHandler(event) {
33
- const nextHeaders = addNextConfigHeaders(event, ConfigHeaders) ?? {};
33
+ const nextHeaders = addNextConfigHeaders(event, ConfigHeaders);
34
34
  let internalEvent = fixDataPage(event, BuildId);
35
35
  if ("statusCode" in internalEvent) {
36
36
  return internalEvent;
@@ -1,4 +1,4 @@
1
- import { FunctionOptions, OpenNextConfig, RouteTemplate, SplittedFunctionOptions } from "../types/open-next";
1
+ import type { FunctionOptions, OpenNextConfig, RouteTemplate, SplittedFunctionOptions } from "../types/open-next";
2
2
  type CloudflareCompatibleFunction<Placement extends "regional" | "global"> = Placement extends "regional" ? FunctionOptions & {
3
3
  placement: "regional";
4
4
  } : {
@@ -1,4 +1,4 @@
1
- import { FunctionOptions, OpenNextConfig, RouteTemplate } from "../types/open-next";
1
+ import type { FunctionOptions, OpenNextConfig, RouteTemplate } from "../types/open-next";
2
2
  type SSTCompatibleFunction = FunctionOptions & {
3
3
  override?: {
4
4
  wrapper?: "aws-lambda-streaming" | "aws-lambda";
@@ -2,9 +2,11 @@
2
2
  /// <reference types="node" />
3
3
  /// <reference types="node" />
4
4
  /// <reference types="node" />
5
+ /// <reference types="node" />
5
6
  import type { IncomingMessage, OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from "http";
6
- import { Socket } from "net";
7
- import { Transform, TransformCallback, Writable } from "stream";
7
+ import type { Socket } from "net";
8
+ import type { TransformCallback, Writable } from "stream";
9
+ import { Transform } from "stream";
8
10
  export interface StreamCreator {
9
11
  writeHeaders(prelude: {
10
12
  statusCode: number;
@@ -65,6 +67,11 @@ export declare class OpenNextNodeResponse extends Transform implements ServerRes
65
67
  private _internalWrite;
66
68
  _transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback): void;
67
69
  _flush(callback: TransformCallback): void;
70
+ /**
71
+ * New method in Node 18.15+
72
+ * There are probably not used right now in Next.js, but better be safe than sorry
73
+ */
74
+ setHeaders(headers: Headers | Map<string, number | string | readonly string[]>): this;
68
75
  /**
69
76
  * Next specific methods
70
77
  * On earlier versions of next.js, those methods are mandatory to make everything work
@@ -75,4 +82,5 @@ export declare class OpenNextNodeResponse extends Transform implements ServerRes
75
82
  body(value: string): this;
76
83
  onClose(callback: () => void): void;
77
84
  redirect(destination: string, statusCode: number): this;
85
+ private fixHeadersForError;
78
86
  }
@@ -141,6 +141,7 @@ export class OpenNextNodeResponse extends Transform {
141
141
  : [...initialCookies, ...this._cookies];
142
142
  }
143
143
  this.fixHeaders(this.headers);
144
+ this.fixHeadersForError();
144
145
  // We need to fix the set-cookie header here
145
146
  this.headers[SET_COOKIE_HEADER] = this._cookies;
146
147
  const parsedHeaders = parseHeaders(this.headers);
@@ -206,6 +207,7 @@ export class OpenNextNodeResponse extends Transform {
206
207
  getFixedHeaders() {
207
208
  // Do we want to apply this on writeHead?
208
209
  this.fixHeaders(this.headers);
210
+ this.fixHeadersForError();
209
211
  // This way we ensure that the cookies are correct
210
212
  this.headers[SET_COOKIE_HEADER] = this._cookies;
211
213
  return this.headers;
@@ -243,6 +245,16 @@ export class OpenNextNodeResponse extends Transform {
243
245
  }
244
246
  callback();
245
247
  }
248
+ /**
249
+ * New method in Node 18.15+
250
+ * There are probably not used right now in Next.js, but better be safe than sorry
251
+ */
252
+ setHeaders(headers) {
253
+ headers.forEach((value, key) => {
254
+ this.setHeader(key, Array.isArray(value) ? value : value.toString());
255
+ });
256
+ return this;
257
+ }
246
258
  /**
247
259
  * Next specific methods
248
260
  * On earlier versions of next.js, those methods are mandatory to make everything work
@@ -278,4 +290,19 @@ export class OpenNextNodeResponse extends Transform {
278
290
  //TODO: test to see if we need to call end here
279
291
  return this;
280
292
  }
293
+ // For some reason, next returns the 500 error page with some cache-control headers
294
+ // We need to fix that
295
+ fixHeadersForError() {
296
+ if (process.env.OPEN_NEXT_DANGEROUSLY_SET_ERROR_HEADERS === "true") {
297
+ return;
298
+ }
299
+ // We only check for 404 and 500 errors
300
+ // The rest should be errors that are handled by the user and they should set the cache headers themselves
301
+ if (this.statusCode === 404 || this.statusCode === 500) {
302
+ // For some reason calling this.setHeader("Cache-Control", "no-cache, no-store, must-revalidate") does not work here
303
+ // The function is not even called, i'm probably missing something obvious
304
+ this.headers["cache-control"] =
305
+ "private, no-cache, no-store, max-age=0, must-revalidate";
306
+ }
307
+ }
281
308
  }
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
+ /// <reference types="node" />
3
4
  import http from "node:http";
4
5
  export declare class IncomingMessage extends http.IncomingMessage {
5
6
  constructor({ method, url, headers, body, remoteAddress, }: {
@@ -1,4 +1,4 @@
1
- import http from "node:http";
1
+ import type http from "node:http";
2
2
  export declare const parseHeaders: (headers?: http.OutgoingHttpHeader[] | http.OutgoingHttpHeaders) => Record<string, string>;
3
3
  export declare const convertHeader: (header: http.OutgoingHttpHeader) => string;
4
4
  export declare function parseCookies(cookies?: string | string[]): string[] | undefined;
@@ -1,3 +1,3 @@
1
- import type { Converter, InternalEvent, InternalResult } from "../types/open-next";
1
+ import type { Converter, InternalEvent, InternalResult } from "../../types/open-next";
2
2
  declare const _default: Converter<InternalEvent, InternalResult>;
3
3
  export default _default;
@@ -1,5 +1,5 @@
1
- import { fromReadableStream } from "../utils/stream";
2
- import { debug } from "../adapters/logger";
1
+ import { fromReadableStream } from "../../utils/stream";
2
+ import { debug } from "../../adapters/logger";
3
3
  import { removeUndefinedFromQuery } from "./utils";
4
4
  function normalizeAPIGatewayProxyEventHeaders(event) {
5
5
  event.multiValueHeaders;
@@ -1,3 +1,3 @@
1
- import type { Converter, InternalEvent, InternalResult } from "../types/open-next";
1
+ import type { Converter, InternalEvent, InternalResult } from "../../types/open-next";
2
2
  declare const _default: Converter<InternalEvent, InternalResult>;
3
3
  export default _default;
@@ -1,7 +1,7 @@
1
- import { parseCookies } from "../http/util";
2
- import { fromReadableStream } from "../utils/stream";
3
- import { debug } from "../adapters/logger";
4
- import { convertToQuery } from "../core/routing/util";
1
+ import { parseCookies } from "../../http/util";
2
+ import { fromReadableStream } from "../../utils/stream";
3
+ import { debug } from "../../adapters/logger";
4
+ import { convertToQuery } from "../../core/routing/util";
5
5
  import { removeUndefinedFromQuery } from "./utils";
6
6
  // Not sure which one is reallly needed as this is not documented anywhere but server actions redirect are not working without this, it causes a 500 error from cloudfront itself with a 'x-amzErrortype: InternalFailure' header
7
7
  const CloudFrontBlacklistedHeaders = [
@@ -1,3 +1,3 @@
1
- import type { Converter, InternalEvent, InternalResult } from "../types/open-next";
1
+ import type { Converter, InternalEvent, InternalResult } from "../../types/open-next";
2
2
  declare const _default: Converter<InternalEvent, InternalResult>;
3
3
  export default _default;
@@ -1,7 +1,7 @@
1
- import { parseCookies } from "../http/util";
2
- import { fromReadableStream } from "../utils/stream";
3
- import { debug } from "../adapters/logger";
4
- import { convertRes, convertToQuery, convertToQueryString, createServerResponse, proxyRequest, } from "../core/routing/util";
1
+ import { parseCookies } from "../../http/util";
2
+ import { fromReadableStream } from "../../utils/stream";
3
+ import { debug } from "../../adapters/logger";
4
+ import { convertRes, convertToQuery, convertToQueryString, createServerResponse, proxyRequest, } from "../../core/routing/util";
5
5
  const CloudFrontBlacklistedHeaders = [
6
6
  // Disallowed headers, see: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-function-restrictions-all.html#function-restrictions-disallowed-headers
7
7
  "connection",
@@ -100,11 +100,9 @@ function convertToCloudfrontHeaders(headers, directResponse) {
100
100
  return cloudfrontHeaders;
101
101
  }
102
102
  async function convertToCloudFrontRequestResult(result, originalRequest) {
103
- let responseHeaders = result.type === "middleware"
104
- ? result.internalEvent.headers
105
- : result.headers;
106
103
  if (result.type === "middleware") {
107
104
  const { method, clientIp, origin } = originalRequest.Records[0].cf.request;
105
+ const responseHeaders = result.internalEvent.headers;
108
106
  // Handle external rewrite
109
107
  if (result.isExternalRewrite) {
110
108
  const serverResponse = createServerResponse(result.internalEvent, {});
@@ -154,6 +152,7 @@ async function convertToCloudFrontRequestResult(result, originalRequest) {
154
152
  return response;
155
153
  }
156
154
  const body = await fromReadableStream(result.body, result.isBase64Encoded);
155
+ const responseHeaders = result.headers;
157
156
  const response = {
158
157
  status: result.statusCode.toString(),
159
158
  statusDescription: "OK",
@@ -1,4 +1,4 @@
1
- import { Converter } from "../types/open-next";
1
+ import type { Converter } from "../../types/open-next";
2
2
  type DummyEventOrResult = {
3
3
  type: "dummy";
4
4
  original: any;
@@ -0,0 +1,9 @@
1
+ import type { Converter, InternalEvent, InternalResult } from "../../types/open-next";
2
+ import type { MiddlewareOutputEvent } from "../../core/routingHandler";
3
+ declare global {
4
+ var __dangerous_ON_edge_converter_returns_request: boolean | undefined;
5
+ }
6
+ declare const converter: Converter<InternalEvent, InternalResult | ({
7
+ type: "middleware";
8
+ } & MiddlewareOutputEvent)>;
9
+ export default converter;
@@ -1,5 +1,5 @@
1
1
  import { Buffer } from "node:buffer";
2
- import { parseCookies } from "../http/util";
2
+ import { parseCookies } from "../../http/util";
3
3
  const converter = {
4
4
  convertFrom: async (event) => {
5
5
  const searchParams = new URL(event.url).searchParams;
@@ -52,7 +52,7 @@ const converter = {
52
52
  url = `https://${result.internalEvent.headers.host}${url}`;
53
53
  }
54
54
  }
55
- const req = new Request(url, {
55
+ const request = new Request(url, {
56
56
  body: result.internalEvent.body,
57
57
  method: result.internalEvent.method,
58
58
  headers: {
@@ -60,12 +60,15 @@ const converter = {
60
60
  "x-forwarded-host": result.internalEvent.headers.host,
61
61
  },
62
62
  });
63
+ if (globalThis.__dangerous_ON_edge_converter_returns_request === true) {
64
+ return request;
65
+ }
63
66
  const cfCache = (result.isISR ||
64
67
  result.internalEvent.rawPath.startsWith("/_next/image")) &&
65
68
  process.env.DISABLE_CACHE !== "true"
66
69
  ? { cacheEverything: true }
67
70
  : {};
68
- return fetch(req, {
71
+ return fetch(request, {
69
72
  // This is a hack to make sure that the response is cached by Cloudflare
70
73
  // See https://developers.cloudflare.com/workers/examples/cache-using-fetch/#caching-html-resources
71
74
  // @ts-expect-error - This is a Cloudflare specific option
@@ -1,3 +1,3 @@
1
- import type { Converter } from "../types/open-next";
1
+ import type { Converter } from "../../types/open-next";
2
2
  declare const converter: Converter;
3
3
  export default converter;
@@ -1,4 +1,4 @@
1
- import { parseCookies } from "../http/util";
1
+ import { parseCookies } from "../../http/util";
2
2
  const converter = {
3
3
  convertFrom: async (req) => {
4
4
  const body = await new Promise((resolve) => {
@@ -0,0 +1,4 @@
1
+ import type { Converter } from "../../types/open-next";
2
+ import type { RevalidateEvent } from "../../adapters/revalidate";
3
+ declare const converter: Converter<RevalidateEvent, RevalidateEvent>;
4
+ export default converter;
@@ -0,0 +1,3 @@
1
+ import type { ImageLoader } from "../../types/open-next";
2
+ declare const dummyLoader: ImageLoader;
3
+ export default dummyLoader;
@@ -0,0 +1,8 @@
1
+ import { FatalError } from "../../utils/error";
2
+ const dummyLoader = {
3
+ name: "dummy",
4
+ load: async (_) => {
5
+ throw new FatalError("Dummy loader is not implemented");
6
+ },
7
+ };
8
+ export default dummyLoader;
@@ -1,3 +1,3 @@
1
- import { ImageLoader } from "../../types/open-next";
1
+ import type { ImageLoader } from "../../types/open-next";
2
2
  declare const hostLoader: ImageLoader;
3
3
  export default hostLoader;
@@ -1,3 +1,3 @@
1
- import { ImageLoader } from "../../types/open-next";
1
+ import type { ImageLoader } from "../../types/open-next";
2
2
  declare const s3Loader: ImageLoader;
3
3
  export default s3Loader;
@@ -0,0 +1,3 @@
1
+ import type { IncrementalCache } from "./types";
2
+ declare const dummyIncrementalCache: IncrementalCache;
3
+ export default dummyIncrementalCache;