@opennextjs/aws 3.1.4

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 (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +94 -0
  3. package/dist/adapters/binary.d.ts +1 -0
  4. package/dist/adapters/binary.js +63 -0
  5. package/dist/adapters/cache.d.ts +96 -0
  6. package/dist/adapters/cache.js +278 -0
  7. package/dist/adapters/config/index.d.ts +27 -0
  8. package/dist/adapters/config/index.js +21 -0
  9. package/dist/adapters/config/util.d.ts +28 -0
  10. package/dist/adapters/config/util.js +84 -0
  11. package/dist/adapters/dynamo-provider.d.ts +8 -0
  12. package/dist/adapters/dynamo-provider.js +42 -0
  13. package/dist/adapters/edge-adapter.d.ts +8 -0
  14. package/dist/adapters/edge-adapter.js +54 -0
  15. package/dist/adapters/image-optimization-adapter.d.ts +4 -0
  16. package/dist/adapters/image-optimization-adapter.js +193 -0
  17. package/dist/adapters/logger.d.ts +13 -0
  18. package/dist/adapters/logger.js +51 -0
  19. package/dist/adapters/middleware.d.ts +5 -0
  20. package/dist/adapters/middleware.js +84 -0
  21. package/dist/adapters/plugins/14.1/util.d.ts +1 -0
  22. package/dist/adapters/plugins/14.1/util.js +29 -0
  23. package/dist/adapters/plugins/image-optimization/image-optimization.d.ts +11 -0
  24. package/dist/adapters/plugins/image-optimization/image-optimization.js +14 -0
  25. package/dist/adapters/plugins/image-optimization/image-optimization.replacement.d.ts +11 -0
  26. package/dist/adapters/plugins/image-optimization/image-optimization.replacement.js +22 -0
  27. package/dist/adapters/plugins/without-routing/requestHandler.d.ts +2 -0
  28. package/dist/adapters/plugins/without-routing/requestHandler.js +10 -0
  29. package/dist/adapters/revalidate.d.ts +9 -0
  30. package/dist/adapters/revalidate.js +71 -0
  31. package/dist/adapters/server-adapter.d.ts +4 -0
  32. package/dist/adapters/server-adapter.js +27 -0
  33. package/dist/adapters/util.d.ts +10 -0
  34. package/dist/adapters/util.js +28 -0
  35. package/dist/adapters/warmer-function.d.ts +12 -0
  36. package/dist/adapters/warmer-function.js +80 -0
  37. package/dist/build/bundleNextServer.d.ts +1 -0
  38. package/dist/build/bundleNextServer.js +87 -0
  39. package/dist/build/compileConfig.d.ts +3 -0
  40. package/dist/build/compileConfig.js +64 -0
  41. package/dist/build/copyTracedFiles.d.ts +1 -0
  42. package/dist/build/copyTracedFiles.js +207 -0
  43. package/dist/build/createServerBundle.d.ts +3 -0
  44. package/dist/build/createServerBundle.js +228 -0
  45. package/dist/build/edge/createEdgeBundle.d.ts +20 -0
  46. package/dist/build/edge/createEdgeBundle.js +149 -0
  47. package/dist/build/generateOutput.d.ts +2 -0
  48. package/dist/build/generateOutput.js +239 -0
  49. package/dist/build/helper.d.ts +33 -0
  50. package/dist/build/helper.js +193 -0
  51. package/dist/build/patch/patchedAsyncStorage.d.ts +5 -0
  52. package/dist/build/patch/patchedAsyncStorage.js +16 -0
  53. package/dist/build/validateConfig.d.ts +2 -0
  54. package/dist/build/validateConfig.js +76 -0
  55. package/dist/build.d.ts +7 -0
  56. package/dist/build.js +533 -0
  57. package/dist/cache/incremental/s3-lite.d.ts +3 -0
  58. package/dist/cache/incremental/s3-lite.js +72 -0
  59. package/dist/cache/incremental/s3.d.ts +3 -0
  60. package/dist/cache/incremental/s3.js +44 -0
  61. package/dist/cache/incremental/types.d.ts +34 -0
  62. package/dist/cache/incremental/types.js +1 -0
  63. package/dist/cache/next-types.d.ts +62 -0
  64. package/dist/cache/next-types.js +1 -0
  65. package/dist/cache/tag/constants.d.ts +2 -0
  66. package/dist/cache/tag/constants.js +17 -0
  67. package/dist/cache/tag/dynamodb-lite.d.ts +3 -0
  68. package/dist/cache/tag/dynamodb-lite.js +174 -0
  69. package/dist/cache/tag/dynamodb.d.ts +3 -0
  70. package/dist/cache/tag/dynamodb.js +129 -0
  71. package/dist/cache/tag/types.d.ts +11 -0
  72. package/dist/cache/tag/types.js +1 -0
  73. package/dist/converters/aws-apigw-v1.d.ts +3 -0
  74. package/dist/converters/aws-apigw-v1.js +89 -0
  75. package/dist/converters/aws-apigw-v2.d.ts +3 -0
  76. package/dist/converters/aws-apigw-v2.js +99 -0
  77. package/dist/converters/aws-cloudfront.d.ts +3 -0
  78. package/dist/converters/aws-cloudfront.js +170 -0
  79. package/dist/converters/dummy.d.ts +7 -0
  80. package/dist/converters/dummy.js +16 -0
  81. package/dist/converters/edge.d.ts +6 -0
  82. package/dist/converters/edge.js +88 -0
  83. package/dist/converters/node.d.ts +3 -0
  84. package/dist/converters/node.js +45 -0
  85. package/dist/converters/sqs-revalidate.d.ts +4 -0
  86. package/dist/converters/sqs-revalidate.js +22 -0
  87. package/dist/converters/utils.d.ts +1 -0
  88. package/dist/converters/utils.js +9 -0
  89. package/dist/core/createGenericHandler.d.ts +11 -0
  90. package/dist/core/createGenericHandler.js +16 -0
  91. package/dist/core/createMainHandler.d.ts +18 -0
  92. package/dist/core/createMainHandler.js +24 -0
  93. package/dist/core/edgeFunctionHandler.d.ts +54 -0
  94. package/dist/core/edgeFunctionHandler.js +21 -0
  95. package/dist/core/patchAsyncStorage.d.ts +1 -0
  96. package/dist/core/patchAsyncStorage.js +16 -0
  97. package/dist/core/requestHandler.d.ts +3 -0
  98. package/dist/core/requestHandler.js +162 -0
  99. package/dist/core/require-hooks.d.ts +3 -0
  100. package/dist/core/require-hooks.js +102 -0
  101. package/dist/core/resolve.d.ts +31 -0
  102. package/dist/core/resolve.js +81 -0
  103. package/dist/core/routing/cacheInterceptor.d.ts +2 -0
  104. package/dist/core/routing/cacheInterceptor.js +162 -0
  105. package/dist/core/routing/i18n/accept-header.d.ts +1 -0
  106. package/dist/core/routing/i18n/accept-header.js +101 -0
  107. package/dist/core/routing/i18n/index.d.ts +2 -0
  108. package/dist/core/routing/i18n/index.js +36 -0
  109. package/dist/core/routing/matcher.d.ts +25 -0
  110. package/dist/core/routing/matcher.js +294 -0
  111. package/dist/core/routing/middleware.d.ts +7 -0
  112. package/dist/core/routing/middleware.js +167 -0
  113. package/dist/core/routing/util.d.ts +105 -0
  114. package/dist/core/routing/util.js +415 -0
  115. package/dist/core/routingHandler.d.ts +8 -0
  116. package/dist/core/routingHandler.js +127 -0
  117. package/dist/core/util.d.ts +5 -0
  118. package/dist/core/util.js +84 -0
  119. package/dist/helpers/withCloudflare.d.ts +65 -0
  120. package/dist/helpers/withCloudflare.js +58 -0
  121. package/dist/helpers/withSST.d.ts +54 -0
  122. package/dist/helpers/withSST.js +28 -0
  123. package/dist/http/index.d.ts +2 -0
  124. package/dist/http/index.js +4 -0
  125. package/dist/http/openNextResponse.d.ts +78 -0
  126. package/dist/http/openNextResponse.js +281 -0
  127. package/dist/http/request.d.ts +12 -0
  128. package/dist/http/request.js +35 -0
  129. package/dist/http/util.d.ts +4 -0
  130. package/dist/http/util.js +34 -0
  131. package/dist/index.d.ts +2 -0
  132. package/dist/index.js +37 -0
  133. package/dist/logger.d.ts +12 -0
  134. package/dist/logger.js +13 -0
  135. package/dist/minimize-js.d.ts +1 -0
  136. package/dist/minimize-js.js +101 -0
  137. package/dist/overrides/imageLoader/host.d.ts +3 -0
  138. package/dist/overrides/imageLoader/host.js +29 -0
  139. package/dist/overrides/imageLoader/s3.d.ts +3 -0
  140. package/dist/overrides/imageLoader/s3.js +33 -0
  141. package/dist/plugins/edge.d.ts +15 -0
  142. package/dist/plugins/edge.js +157 -0
  143. package/dist/plugins/replacement.d.ts +42 -0
  144. package/dist/plugins/replacement.js +74 -0
  145. package/dist/plugins/resolve.d.ts +18 -0
  146. package/dist/plugins/resolve.js +45 -0
  147. package/dist/queue/sqs-lite.d.ts +3 -0
  148. package/dist/queue/sqs-lite.js +52 -0
  149. package/dist/queue/sqs.d.ts +3 -0
  150. package/dist/queue/sqs.js +20 -0
  151. package/dist/queue/types.d.ts +12 -0
  152. package/dist/queue/types.js +1 -0
  153. package/dist/types/aws-lambda.d.ts +22 -0
  154. package/dist/types/aws-lambda.js +1 -0
  155. package/dist/types/next-types.d.ts +155 -0
  156. package/dist/types/next-types.js +2 -0
  157. package/dist/types/open-next.d.ts +303 -0
  158. package/dist/types/open-next.js +1 -0
  159. package/dist/utils/error.d.ts +23 -0
  160. package/dist/utils/error.js +32 -0
  161. package/dist/utils/fetch.d.ts +2 -0
  162. package/dist/utils/fetch.js +23 -0
  163. package/dist/utils/promise.d.ts +18 -0
  164. package/dist/utils/promise.js +48 -0
  165. package/dist/utils/stream.d.ts +5 -0
  166. package/dist/utils/stream.js +30 -0
  167. package/dist/wrappers/aws-lambda-streaming.d.ts +7 -0
  168. package/dist/wrappers/aws-lambda-streaming.js +88 -0
  169. package/dist/wrappers/aws-lambda.d.ts +7 -0
  170. package/dist/wrappers/aws-lambda.js +39 -0
  171. package/dist/wrappers/cloudflare.d.ts +11 -0
  172. package/dist/wrappers/cloudflare.js +20 -0
  173. package/dist/wrappers/node.d.ts +7 -0
  174. package/dist/wrappers/node.js +57 -0
  175. package/package.json +66 -0
@@ -0,0 +1,84 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ export function loadConfig(nextDir) {
4
+ const filePath = path.join(nextDir, "required-server-files.json");
5
+ const json = fs.readFileSync(filePath, "utf-8");
6
+ const { config } = JSON.parse(json);
7
+ return config;
8
+ }
9
+ export function loadBuildId(nextDir) {
10
+ const filePath = path.join(nextDir, "BUILD_ID");
11
+ return fs.readFileSync(filePath, "utf-8").trim();
12
+ }
13
+ export function loadHtmlPages(nextDir) {
14
+ const filePath = path.join(nextDir, "server", "pages-manifest.json");
15
+ const json = fs.readFileSync(filePath, "utf-8");
16
+ return Object.entries(JSON.parse(json))
17
+ .filter(([_, value]) => value.endsWith(".html"))
18
+ .map(([key]) => key);
19
+ }
20
+ export function loadPublicAssets(openNextDir) {
21
+ const filePath = path.join(openNextDir, "public-files.json");
22
+ const json = fs.readFileSync(filePath, "utf-8");
23
+ return JSON.parse(json);
24
+ }
25
+ export function loadRoutesManifest(nextDir) {
26
+ const filePath = path.join(nextDir, "routes-manifest.json");
27
+ const json = fs.readFileSync(filePath, "utf-8");
28
+ const routesManifest = JSON.parse(json);
29
+ const _dataRoutes = routesManifest.dataRoutes ?? [];
30
+ const dataRoutes = {
31
+ static: _dataRoutes.filter((r) => r.routeKeys === undefined),
32
+ dynamic: _dataRoutes.filter((r) => r.routeKeys !== undefined),
33
+ };
34
+ return {
35
+ basePath: routesManifest.basePath,
36
+ rewrites: Array.isArray(routesManifest.rewrites)
37
+ ? { beforeFiles: [], afterFiles: routesManifest.rewrites, fallback: [] }
38
+ : {
39
+ beforeFiles: routesManifest.rewrites.beforeFiles ?? [],
40
+ afterFiles: routesManifest.rewrites.afterFiles ?? [],
41
+ fallback: routesManifest.rewrites.fallback ?? [],
42
+ },
43
+ redirects: routesManifest.redirects ?? [],
44
+ routes: {
45
+ static: routesManifest.staticRoutes ?? [],
46
+ dynamic: routesManifest.dynamicRoutes ?? [],
47
+ data: dataRoutes,
48
+ },
49
+ locales: routesManifest.i18n?.locales ?? [],
50
+ };
51
+ }
52
+ export function loadConfigHeaders(nextDir) {
53
+ const filePath = path.join(nextDir, "routes-manifest.json");
54
+ const json = fs.readFileSync(filePath, "utf-8");
55
+ const routesManifest = JSON.parse(json);
56
+ return routesManifest.headers;
57
+ }
58
+ export function loadPrerenderManifest(nextDir) {
59
+ const filePath = path.join(nextDir, "prerender-manifest.json");
60
+ const json = fs.readFileSync(filePath, "utf-8");
61
+ return JSON.parse(json);
62
+ }
63
+ export function loadAppPathsManifestKeys(nextDir) {
64
+ const appPathsManifestPath = path.join(nextDir, "server", "app-paths-manifest.json");
65
+ const appPathsManifestJson = fs.existsSync(appPathsManifestPath)
66
+ ? fs.readFileSync(appPathsManifestPath, "utf-8")
67
+ : "{}";
68
+ const appPathsManifest = JSON.parse(appPathsManifestJson);
69
+ return Object.keys(appPathsManifest).map((key) => {
70
+ // Remove parallel route
71
+ let cleanedKey = key.replace(/\/@[^\/]+/g, "");
72
+ // Remove group routes
73
+ cleanedKey = cleanedKey.replace(/\/\((?!\.)[^\)]*\)/g, "");
74
+ // Remove /page suffix
75
+ cleanedKey = cleanedKey.replace(/\/page$/g, "");
76
+ // We need to check if the cleaned key is empty because it means it's the root path
77
+ return cleanedKey === "" ? "/" : cleanedKey;
78
+ });
79
+ }
80
+ export function loadMiddlewareManifest(nextDir) {
81
+ const filePath = path.join(nextDir, "server", "middleware-manifest.json");
82
+ const json = fs.readFileSync(filePath, "utf-8");
83
+ return JSON.parse(json);
84
+ }
@@ -0,0 +1,8 @@
1
+ declare const PHYSICAL_RESOURCE_ID: "dynamodb-cache";
2
+ export interface InitializationFunctionEvent {
3
+ type: "initializationFunction";
4
+ requestType: "create" | "update" | "delete";
5
+ resourceId: typeof PHYSICAL_RESOURCE_ID;
6
+ }
7
+ export declare const handler: (...args: any[]) => any;
8
+ export {};
@@ -0,0 +1,42 @@
1
+ import { readFileSync } from "fs";
2
+ import { createGenericHandler } from "../core/createGenericHandler.js";
3
+ import { resolveTagCache } from "../core/resolve.js";
4
+ const PHYSICAL_RESOURCE_ID = "dynamodb-cache";
5
+ const tagCache = await resolveTagCache(globalThis.openNextConfig?.initializationFunction?.tagCache);
6
+ export const handler = await createGenericHandler({
7
+ handler: defaultHandler,
8
+ type: "initializationFunction",
9
+ });
10
+ async function defaultHandler(event) {
11
+ switch (event.requestType) {
12
+ case "delete":
13
+ return remove();
14
+ case "create":
15
+ case "update":
16
+ default:
17
+ return insert(event.requestType);
18
+ }
19
+ }
20
+ async function insert(requestType) {
21
+ const file = readFileSync(`dynamodb-cache.json`, "utf8");
22
+ const data = JSON.parse(file);
23
+ const parsedData = data.map((item) => ({
24
+ tag: item.tag.S,
25
+ path: item.path.S,
26
+ revalidatedAt: parseInt(item.revalidatedAt.N),
27
+ }));
28
+ await tagCache.writeTags(parsedData);
29
+ return {
30
+ type: "initializationFunction",
31
+ requestType,
32
+ resourceId: PHYSICAL_RESOURCE_ID,
33
+ };
34
+ }
35
+ async function remove() {
36
+ // Do we want to actually delete anything here?
37
+ return {
38
+ type: "initializationFunction",
39
+ requestType: "delete",
40
+ resourceId: PHYSICAL_RESOURCE_ID,
41
+ };
42
+ }
@@ -0,0 +1,8 @@
1
+ declare global {
2
+ var isEdgeRuntime: true;
3
+ }
4
+ export declare const handler: (...args: any[]) => any;
5
+ declare const _default: {
6
+ fetch: (...args: any[]) => any;
7
+ };
8
+ export default _default;
@@ -0,0 +1,54 @@
1
+ import { emptyReadableStream } from "../utils/stream";
2
+ // We import it like that so that the edge plugin can replace it
3
+ import { NextConfig } from "../adapters/config";
4
+ import { createGenericHandler } from "../core/createGenericHandler";
5
+ import { convertBodyToReadableStream, convertToQueryString, } from "../core/routing/util";
6
+ const defaultHandler = async (internalEvent) => {
7
+ globalThis.isEdgeRuntime = true;
8
+ const host = internalEvent.headers.host
9
+ ? `https://${internalEvent.headers.host}`
10
+ : "http://localhost:3000";
11
+ const initialUrl = new URL(internalEvent.rawPath, host);
12
+ initialUrl.search = convertToQueryString(internalEvent.query);
13
+ const url = initialUrl.toString();
14
+ // @ts-expect-error - This is bundled
15
+ const handler = await import(`./middleware.mjs`);
16
+ const response = await handler.default({
17
+ headers: internalEvent.headers,
18
+ method: internalEvent.method || "GET",
19
+ nextConfig: {
20
+ basePath: NextConfig.basePath,
21
+ i18n: NextConfig.i18n,
22
+ trailingSlash: NextConfig.trailingSlash,
23
+ },
24
+ url,
25
+ body: convertBodyToReadableStream(internalEvent.method, internalEvent.body),
26
+ });
27
+ const responseHeaders = {};
28
+ response.headers.forEach((value, key) => {
29
+ if (key.toLowerCase() === "set-cookie") {
30
+ responseHeaders[key] = responseHeaders[key]
31
+ ? [...responseHeaders[key], value]
32
+ : [value];
33
+ }
34
+ else {
35
+ responseHeaders[key] = value;
36
+ }
37
+ });
38
+ const body = response.body ?? emptyReadableStream();
39
+ return {
40
+ type: "core",
41
+ statusCode: response.status,
42
+ headers: responseHeaders,
43
+ body: body,
44
+ // Do we need to handle base64 encoded response?
45
+ isBase64Encoded: false,
46
+ };
47
+ };
48
+ export const handler = await createGenericHandler({
49
+ handler: defaultHandler,
50
+ type: "middleware",
51
+ });
52
+ export default {
53
+ fetch: handler,
54
+ };
@@ -0,0 +1,4 @@
1
+ import { StreamCreator } from "../http/openNextResponse.js";
2
+ import { InternalEvent, InternalResult } from "../types/open-next.js";
3
+ export declare const handler: (...args: any[]) => any;
4
+ export declare function defaultHandler(event: InternalEvent, streamCreator?: StreamCreator): Promise<InternalResult>;
@@ -0,0 +1,193 @@
1
+ import { createHash } from "node:crypto";
2
+ import https from "node:https";
3
+ import path from "node:path";
4
+ import { loadBuildId, loadConfig } from "./config/util.js";
5
+ import { OpenNextNodeResponse } from "../http/openNextResponse.js";
6
+ // @ts-ignore
7
+ import { defaultConfig } from "next/dist/server/config-shared";
8
+ import { ImageOptimizerCache,
9
+ // @ts-ignore
10
+ } from "next/dist/server/image-optimizer";
11
+ import { emptyReadableStream, toReadableStream } from "../utils/stream.js";
12
+ import { createGenericHandler } from "../core/createGenericHandler.js";
13
+ import { resolveImageLoader } from "../core/resolve.js";
14
+ import { debug, error } from "./logger.js";
15
+ import { optimizeImage } from "./plugins/image-optimization/image-optimization.js";
16
+ import { setNodeEnv } from "./util.js";
17
+ setNodeEnv();
18
+ const nextDir = path.join(__dirname, ".next");
19
+ const config = loadConfig(nextDir);
20
+ const buildId = loadBuildId(nextDir);
21
+ const nextConfig = {
22
+ ...defaultConfig,
23
+ images: {
24
+ ...defaultConfig.images,
25
+ ...config.images,
26
+ },
27
+ };
28
+ debug("Init config", {
29
+ nextDir,
30
+ nextConfig,
31
+ });
32
+ /////////////
33
+ // Handler //
34
+ /////////////
35
+ export const handler = await createGenericHandler({
36
+ handler: defaultHandler,
37
+ type: "imageOptimization",
38
+ });
39
+ export async function defaultHandler(event, streamCreator) {
40
+ // Images are handled via header and query param information.
41
+ debug("handler event", event);
42
+ const { headers, query: queryString } = event;
43
+ try {
44
+ // Set the HOST environment variable to the host header if it is not set
45
+ // If it is set it is assumed to be set by the user and should be used instead
46
+ // It might be useful for cases where the user wants to use a different host than the one in the request
47
+ // It could even allow to have multiple hosts for the image optimization by setting the HOST environment variable in the wrapper for example
48
+ if (!process.env.HOST) {
49
+ const headersHost = headers["x-forwarded-host"] || headers["host"];
50
+ process.env.HOST = headersHost;
51
+ }
52
+ const imageParams = validateImageParams(headers, queryString === null ? undefined : queryString);
53
+ let etag;
54
+ // We don't cache any images, so in order to be able to return 304 responses, we compute an ETag from what is assumed to be static
55
+ if (process.env.OPENNEXT_STATIC_ETAG) {
56
+ etag = computeEtag(imageParams);
57
+ }
58
+ if (etag && headers["if-none-match"] === etag) {
59
+ return {
60
+ statusCode: 304,
61
+ headers: {},
62
+ body: emptyReadableStream(),
63
+ isBase64Encoded: false,
64
+ type: "core",
65
+ };
66
+ }
67
+ const result = await optimizeImage(headers, imageParams, nextConfig, downloadHandler);
68
+ return buildSuccessResponse(result, streamCreator, etag);
69
+ }
70
+ catch (e) {
71
+ return buildFailureResponse(e, streamCreator);
72
+ }
73
+ }
74
+ //////////////////////
75
+ // Helper functions //
76
+ //////////////////////
77
+ function validateImageParams(headers, query) {
78
+ // Next.js checks if external image URL matches the
79
+ // `images.remotePatterns`
80
+ const imageParams = ImageOptimizerCache.validateParams(
81
+ // @ts-ignore
82
+ { headers }, query, nextConfig, false);
83
+ debug("image params", imageParams);
84
+ if ("errorMessage" in imageParams) {
85
+ throw new Error(imageParams.errorMessage);
86
+ }
87
+ return imageParams;
88
+ }
89
+ function computeEtag(imageParams) {
90
+ return createHash("sha1")
91
+ .update(JSON.stringify({
92
+ href: imageParams.href,
93
+ width: imageParams.width,
94
+ quality: imageParams.quality,
95
+ buildId,
96
+ }))
97
+ .digest("base64");
98
+ }
99
+ function buildSuccessResponse(result, streamCreator, etag) {
100
+ const headers = {
101
+ Vary: "Accept",
102
+ "Content-Type": result.contentType,
103
+ "Cache-Control": `public,max-age=${result.maxAge},immutable`,
104
+ };
105
+ debug("result", result);
106
+ if (etag) {
107
+ headers["ETag"] = etag;
108
+ }
109
+ if (streamCreator) {
110
+ const response = new OpenNextNodeResponse(() => void 0, async () => void 0, streamCreator);
111
+ response.writeHead(200, headers);
112
+ response.end(result.buffer);
113
+ }
114
+ return {
115
+ type: "core",
116
+ statusCode: 200,
117
+ body: toReadableStream(result.buffer, true),
118
+ isBase64Encoded: true,
119
+ headers,
120
+ };
121
+ }
122
+ function buildFailureResponse(e, streamCreator) {
123
+ debug(e);
124
+ if (streamCreator) {
125
+ const response = new OpenNextNodeResponse(() => void 0, async () => void 0, streamCreator);
126
+ response.writeHead(500, {
127
+ Vary: "Accept",
128
+ "Cache-Control": `public,max-age=60,immutable`,
129
+ "Content-Type": "application/json",
130
+ });
131
+ response.end(e?.message || e?.toString() || "An error occurred");
132
+ }
133
+ return {
134
+ type: "core",
135
+ isBase64Encoded: false,
136
+ statusCode: 500,
137
+ headers: {
138
+ Vary: "Accept",
139
+ // For failed images, allow client to retry after 1 minute.
140
+ "Cache-Control": `public,max-age=60,immutable`,
141
+ "Content-Type": "application/json",
142
+ },
143
+ body: toReadableStream(e?.message || e?.toString() || "An error occurred"),
144
+ };
145
+ }
146
+ const loader = await resolveImageLoader(globalThis.openNextConfig.imageOptimization?.loader ?? "s3");
147
+ async function downloadHandler(_req, res, url) {
148
+ // downloadHandler is called by Next.js. We don't call this function
149
+ // directly.
150
+ debug("downloadHandler url", url);
151
+ // Reads the output from the Writable and writes to the response
152
+ const pipeRes = (w, res) => {
153
+ w.pipe(res)
154
+ .once("close", () => {
155
+ res.statusCode = 200;
156
+ res.end();
157
+ })
158
+ .once("error", (err) => {
159
+ error("Failed to get image", err);
160
+ res.statusCode = 400;
161
+ res.end();
162
+ });
163
+ };
164
+ try {
165
+ // Case 1: remote image URL => download the image from the URL
166
+ if (url.href.toLowerCase().match(/^https?:\/\//)) {
167
+ pipeRes(https.get(url), res);
168
+ }
169
+ // Case 2: local image => download the image from S3
170
+ else {
171
+ // Download image from S3
172
+ // note: S3 expects keys without leading `/`
173
+ const response = await loader.load(url.href);
174
+ if (!response.body) {
175
+ throw new Error("Empty response body from the S3 request.");
176
+ }
177
+ // @ts-ignore
178
+ pipeRes(response.body, res);
179
+ // Respect the bucket file's content-type and cache-control
180
+ // imageOptimizer will use this to set the results.maxAge
181
+ if (response.contentType) {
182
+ res.setHeader("Content-Type", response.contentType);
183
+ }
184
+ if (response.cacheControl) {
185
+ res.setHeader("Cache-Control", response.cacheControl);
186
+ }
187
+ }
188
+ }
189
+ catch (e) {
190
+ error("Failed to download image", e);
191
+ throw e;
192
+ }
193
+ }
@@ -0,0 +1,13 @@
1
+ declare global {
2
+ var openNextDebug: boolean;
3
+ }
4
+ export declare function debug(...args: any[]): void;
5
+ export declare function warn(...args: any[]): void;
6
+ export declare function error(...args: any[]): void;
7
+ export declare const awsLogger: {
8
+ trace: () => void;
9
+ debug: () => void;
10
+ info: typeof debug;
11
+ warn: typeof warn;
12
+ error: typeof error;
13
+ };
@@ -0,0 +1,51 @@
1
+ export function debug(...args) {
2
+ if (globalThis.openNextDebug) {
3
+ console.log(...args);
4
+ }
5
+ }
6
+ export function warn(...args) {
7
+ console.warn(...args);
8
+ }
9
+ const DOWNPLAYED_ERROR_LOGS = [
10
+ {
11
+ clientName: "S3Client",
12
+ commandName: "GetObjectCommand",
13
+ errorName: "NoSuchKey",
14
+ },
15
+ ];
16
+ const isDownplayedErrorLog = (errorLog) => DOWNPLAYED_ERROR_LOGS.some((downplayedInput) => downplayedInput.clientName === errorLog?.clientName &&
17
+ downplayedInput.commandName === errorLog?.commandName &&
18
+ (downplayedInput.errorName === errorLog?.error?.name ||
19
+ downplayedInput.errorName === errorLog?.error?.Code));
20
+ export function error(...args) {
21
+ // we try to catch errors from the aws-sdk client and downplay some of them
22
+ if (args.some((arg) => isDownplayedErrorLog(arg))) {
23
+ debug(...args);
24
+ }
25
+ else if (args.some((arg) => arg.__openNextInternal)) {
26
+ // In case of an internal error, we log it with the appropriate log level
27
+ const error = args.find((arg) => arg.__openNextInternal);
28
+ if (error.logLevel === 0) {
29
+ debug(...args);
30
+ return;
31
+ }
32
+ else if (error.logLevel === 1) {
33
+ warn(...args);
34
+ return;
35
+ }
36
+ else {
37
+ console.error(...args);
38
+ return;
39
+ }
40
+ }
41
+ else {
42
+ console.error(...args);
43
+ }
44
+ }
45
+ export const awsLogger = {
46
+ trace: () => { },
47
+ debug: () => { },
48
+ info: debug,
49
+ warn,
50
+ error,
51
+ };
@@ -0,0 +1,5 @@
1
+ export declare const handler: (...args: any[]) => any;
2
+ declare const _default: {
3
+ fetch: (...args: any[]) => any;
4
+ };
5
+ export default _default;
@@ -0,0 +1,84 @@
1
+ import { debug, error } from "../adapters/logger";
2
+ import { createGenericHandler } from "../core/createGenericHandler";
3
+ import { resolveIncrementalCache, resolveQueue, resolveTagCache, } from "../core/resolve";
4
+ import routingHandler from "../core/routingHandler";
5
+ const resolveOriginResolver = () => {
6
+ const openNextParams = globalThis.openNextConfig.middleware;
7
+ if (typeof openNextParams?.originResolver === "function") {
8
+ return openNextParams.originResolver();
9
+ }
10
+ else {
11
+ return Promise.resolve({
12
+ name: "env",
13
+ resolve: async (_path) => {
14
+ try {
15
+ const origin = JSON.parse(process.env.OPEN_NEXT_ORIGIN ?? "{}");
16
+ for (const [key, value] of Object.entries(globalThis.openNextConfig.functions ?? {}).filter(([key]) => key !== "default")) {
17
+ if (value.patterns.some((pattern) => {
18
+ // Convert cloudfront pattern to regex
19
+ return new RegExp(
20
+ // transform glob pattern to regex
21
+ "/" +
22
+ pattern
23
+ .replace(/\*\*/g, "(.*)")
24
+ .replace(/\*/g, "([^/]*)")
25
+ .replace(/\//g, "\\/")
26
+ .replace(/\?/g, ".")).test(_path);
27
+ })) {
28
+ debug("Using origin", key, value.patterns);
29
+ return origin[key];
30
+ }
31
+ }
32
+ if (_path.startsWith("/_next/image") && origin["imageOptimizer"]) {
33
+ debug("Using origin", "imageOptimizer", _path);
34
+ return origin["imageOptimizer"];
35
+ }
36
+ if (origin["default"]) {
37
+ debug("Using default origin", origin["default"], _path);
38
+ return origin["default"];
39
+ }
40
+ return false;
41
+ }
42
+ catch (e) {
43
+ error("Error while resolving origin", e);
44
+ return false;
45
+ }
46
+ },
47
+ });
48
+ }
49
+ };
50
+ globalThis.internalFetch = fetch;
51
+ const defaultHandler = async (internalEvent) => {
52
+ const originResolver = await resolveOriginResolver();
53
+ //#override includeCacheInMiddleware
54
+ globalThis.tagCache = await resolveTagCache(globalThis.openNextConfig.middleware?.override?.tagCache);
55
+ globalThis.queue = await resolveQueue(globalThis.openNextConfig.middleware?.override?.queue);
56
+ globalThis.incrementalCache = await resolveIncrementalCache(globalThis.openNextConfig.middleware?.override?.incrementalCache);
57
+ //#endOverride
58
+ const result = await routingHandler(internalEvent);
59
+ if ("internalEvent" in result) {
60
+ debug("Middleware intercepted event", internalEvent);
61
+ let origin = false;
62
+ if (!result.isExternalRewrite) {
63
+ origin = await originResolver.resolve(result.internalEvent.rawPath);
64
+ }
65
+ return {
66
+ type: "middleware",
67
+ internalEvent: result.internalEvent,
68
+ isExternalRewrite: result.isExternalRewrite,
69
+ origin,
70
+ isISR: result.isISR,
71
+ };
72
+ }
73
+ else {
74
+ debug("Middleware response", result);
75
+ return result;
76
+ }
77
+ };
78
+ export const handler = await createGenericHandler({
79
+ handler: defaultHandler,
80
+ type: "middleware",
81
+ });
82
+ export default {
83
+ fetch: handler,
84
+ };
@@ -0,0 +1 @@
1
+ export declare const requestHandler: any;
@@ -0,0 +1,29 @@
1
+ import { NextConfig } from "../../config";
2
+ import { debug } from "../../logger.js";
3
+ //#override requestHandler
4
+ // @ts-ignore
5
+ export const requestHandler = new NextServer.default({
6
+ conf: {
7
+ ...NextConfig,
8
+ // Next.js compression should be disabled because of a bug in the bundled
9
+ // `compression` package — https://github.com/vercel/next.js/issues/11669
10
+ compress: false,
11
+ // By default, Next.js uses local disk to store ISR cache. We will use
12
+ // our own cache handler to store the cache on S3.
13
+ cacheHandler: `${process.env.LAMBDA_TASK_ROOT}/cache.cjs`,
14
+ cacheMaxMemorySize: 0,
15
+ experimental: {
16
+ ...NextConfig.experimental,
17
+ // This uses the request.headers.host as the URL
18
+ // https://github.com/vercel/next.js/blob/canary/packages/next/src/server/next-server.ts#L1749-L1754
19
+ trustHostHeader: true,
20
+ },
21
+ },
22
+ customServer: false,
23
+ dev: false,
24
+ dir: __dirname,
25
+ }).getRequestHandler();
26
+ //#endOverride
27
+ //#override requireHooks
28
+ debug("No need to override require hooks with next 13.4.20+");
29
+ //#endOverride
@@ -0,0 +1,11 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import { IncomingMessage, ServerResponse } from "node:http";
4
+ import { APIGatewayProxyEventHeaders } from "aws-lambda";
5
+ import { NextConfig } from "next/dist/server/config-shared";
6
+ import { NextUrlWithParsedQuery } from "next/dist/server/request-meta";
7
+ export declare function optimizeImage(headers: APIGatewayProxyEventHeaders, imageParams: any, nextConfig: NextConfig, handleRequest: (newReq: IncomingMessage, newRes: ServerResponse, newParsedUrl: NextUrlWithParsedQuery) => Promise<void>): Promise<{
8
+ buffer: Buffer;
9
+ contentType: string;
10
+ maxAge: number;
11
+ }>;
@@ -0,0 +1,14 @@
1
+ //#override imports
2
+ import { imageOptimizer } from "next/dist/server/image-optimizer";
3
+ import { debug } from "../../logger.js";
4
+ //#override optimizeImage
5
+ export async function optimizeImage(headers, imageParams, nextConfig, handleRequest) {
6
+ const result = await imageOptimizer(
7
+ // @ts-ignore
8
+ { headers }, {}, // res object is not necessary as it's not actually used.
9
+ imageParams, nextConfig, false, // not in dev mode
10
+ handleRequest);
11
+ debug("optimized result", result);
12
+ return result;
13
+ }
14
+ //#endOverride
@@ -0,0 +1,11 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import type { IncomingMessage, ServerResponse } from "node:http";
4
+ import type { APIGatewayProxyEventHeaders } from "aws-lambda";
5
+ import type { NextConfig } from "next/dist/server/config-shared";
6
+ import type { NextUrlWithParsedQuery } from "next/dist/server/request-meta";
7
+ export declare function optimizeImage(headers: APIGatewayProxyEventHeaders, imageParams: any, nextConfig: NextConfig, handleRequest: (newReq: IncomingMessage, newRes: ServerResponse, newParsedUrl?: NextUrlWithParsedQuery) => Promise<void>): Promise<{
8
+ buffer: Buffer;
9
+ contentType: string;
10
+ maxAge: number;
11
+ }>;
@@ -0,0 +1,22 @@
1
+ //#override imports
2
+ import {
3
+ // @ts-ignore
4
+ fetchExternalImage,
5
+ // @ts-ignore
6
+ fetchInternalImage, imageOptimizer, } from "next/dist/server/image-optimizer";
7
+ import { debug } from "../../logger.js";
8
+ //#override optimizeImage
9
+ export async function optimizeImage(headers, imageParams, nextConfig, handleRequest) {
10
+ const { isAbsolute, href } = imageParams;
11
+ const imageUpstream = isAbsolute
12
+ ? await fetchExternalImage(href)
13
+ : await fetchInternalImage(href,
14
+ // @ts-ignore
15
+ { headers }, {}, // res object is not necessary as it's not actually used.
16
+ handleRequest);
17
+ // @ts-ignore
18
+ const result = await imageOptimizer(imageUpstream, imageParams, nextConfig, false);
19
+ debug("optimized result", result);
20
+ return result;
21
+ }
22
+ //#endOverride
@@ -0,0 +1,2 @@
1
+ declare const _default: {};
2
+ export default _default;
@@ -0,0 +1,10 @@
1
+ //#override withRouting
2
+ const preprocessResult = {
3
+ internalEvent: internalEvent,
4
+ isExternalRewrite: false,
5
+ origin: false,
6
+ isISR: false,
7
+ };
8
+ //#endOverride
9
+ // We need to export something otherwise when compiled in js it creates an empty export {} inside the override
10
+ export default {};