@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,65 @@
1
+ import { FunctionOptions, OpenNextConfig, RouteTemplate, SplittedFunctionOptions } from "../types/open-next";
2
+ type CloudflareCompatibleFunction<Placement extends "regional" | "global"> = Placement extends "regional" ? FunctionOptions & {
3
+ placement: "regional";
4
+ } : {
5
+ placement: "global";
6
+ };
7
+ type CloudflareCompatibleRoutes<Placement extends "regional" | "global"> = Placement extends "regional" ? {
8
+ placement: "regional";
9
+ routes: RouteTemplate[];
10
+ patterns: string[];
11
+ } : {
12
+ placement: "global";
13
+ routes: `app/${string}/route`;
14
+ patterns: string;
15
+ };
16
+ type CloudflareCompatibleSplittedFunction<Placement extends "regional" | "global" = "regional"> = CloudflareCompatibleRoutes<Placement> & CloudflareCompatibleFunction<Placement>;
17
+ type CloudflareConfig<Fn extends Record<string, CloudflareCompatibleSplittedFunction<"global" | "regional">>> = {
18
+ default: CloudflareCompatibleFunction<"regional">;
19
+ functions?: Fn;
20
+ } & Omit<OpenNextConfig, "default" | "functions" | "middleware">;
21
+ type InterpolatedSplittedFunctionOptions<Fn extends Record<string, CloudflareCompatibleSplittedFunction<"global" | "regional">>> = {
22
+ [K in keyof Fn]: SplittedFunctionOptions;
23
+ };
24
+ /**
25
+ * This function makes it easier to use Cloudflare with OpenNext.
26
+ * All options are already restricted to Cloudflare compatible options.
27
+ * @example
28
+ * ```ts
29
+ export default withCloudflare({
30
+ default: {
31
+ placement: "regional",
32
+ runtime: "node",
33
+ },
34
+ functions: {
35
+ api: {
36
+ placement: "regional",
37
+ runtime: "node",
38
+ routes: ["app/api/test/route", "page/api/otherApi"],
39
+ patterns: ["/api/*"],
40
+ },
41
+ global: {
42
+ placement: "global",
43
+ runtime: "edge",
44
+ routes: "app/test/page",
45
+ patterns: "/page",
46
+ },
47
+ },
48
+ });
49
+ * ```
50
+ */
51
+ export declare function withCloudflare<Fn extends Record<string, CloudflareCompatibleSplittedFunction<"global" | "regional">>, Key extends keyof Fn>(config: CloudflareConfig<Fn>): {
52
+ default: FunctionOptions & {
53
+ placement: "regional";
54
+ };
55
+ functions: InterpolatedSplittedFunctionOptions<Fn>;
56
+ middleware: {
57
+ external: true;
58
+ originResolver: "pattern-env";
59
+ override: {
60
+ wrapper: "cloudflare";
61
+ converter: "edge";
62
+ };
63
+ };
64
+ };
65
+ export {};
@@ -0,0 +1,58 @@
1
+ /**
2
+ * This function makes it easier to use Cloudflare with OpenNext.
3
+ * All options are already restricted to Cloudflare compatible options.
4
+ * @example
5
+ * ```ts
6
+ export default withCloudflare({
7
+ default: {
8
+ placement: "regional",
9
+ runtime: "node",
10
+ },
11
+ functions: {
12
+ api: {
13
+ placement: "regional",
14
+ runtime: "node",
15
+ routes: ["app/api/test/route", "page/api/otherApi"],
16
+ patterns: ["/api/*"],
17
+ },
18
+ global: {
19
+ placement: "global",
20
+ runtime: "edge",
21
+ routes: "app/test/page",
22
+ patterns: "/page",
23
+ },
24
+ },
25
+ });
26
+ * ```
27
+ */
28
+ export function withCloudflare(config) {
29
+ const functions = Object.entries(config.functions ?? {}).reduce((acc, [name, fn]) => {
30
+ const _name = name;
31
+ acc[_name] =
32
+ fn.placement === "global"
33
+ ? {
34
+ placement: "global",
35
+ runtime: "edge",
36
+ routes: [fn.routes],
37
+ patterns: [fn.patterns],
38
+ override: {
39
+ wrapper: "cloudflare",
40
+ converter: "edge",
41
+ },
42
+ }
43
+ : { ...fn, placement: "regional" };
44
+ return acc;
45
+ }, {});
46
+ return {
47
+ default: config.default,
48
+ functions: functions,
49
+ middleware: {
50
+ external: true,
51
+ originResolver: "pattern-env",
52
+ override: {
53
+ wrapper: "cloudflare",
54
+ converter: "edge",
55
+ },
56
+ },
57
+ };
58
+ }
@@ -0,0 +1,54 @@
1
+ import { FunctionOptions, OpenNextConfig, RouteTemplate } from "../types/open-next";
2
+ type SSTCompatibleFunction = FunctionOptions & {
3
+ override?: {
4
+ wrapper?: "aws-lambda-streaming" | "aws-lambda";
5
+ converter?: "aws-apigw-v2" | "aws-apigw-v1" | "aws-cloudfront";
6
+ };
7
+ };
8
+ type SSTCompatibleSplittedFunction = {
9
+ routes: RouteTemplate[];
10
+ patterns: string[];
11
+ } & SSTCompatibleFunction;
12
+ type SSTCompatibleConfig<Fn extends Record<string, SSTCompatibleSplittedFunction>> = {
13
+ default: SSTCompatibleFunction;
14
+ functions?: Fn;
15
+ middleware?: {
16
+ external: true;
17
+ };
18
+ } & Pick<OpenNextConfig, "dangerous" | "appPath" | "buildCommand" | "buildOutputPath" | "packageJsonPath">;
19
+ /**
20
+ * This function makes it more straightforward to use SST with OpenNext.
21
+ * All options are already restricted to SST compatible options only.
22
+ * Some options not present here can be used in SST, but it's an advanced use case that
23
+ * can easily break the deployment. If you need to use those options, you should just provide a
24
+ * compatible OpenNextConfig inside your `open-next.config.ts` file.
25
+ * @example
26
+ * ```ts
27
+ export default withSST({
28
+ default: {
29
+ override: {
30
+ wrapper: "aws-lambda-streaming",
31
+ },
32
+ },
33
+ functions: {
34
+ "api/*": {
35
+ routes: ["app/api/test/route", "page/api/otherApi"],
36
+ patterns: ["/api/*"],
37
+ },
38
+ },
39
+ });
40
+ * ```
41
+ */
42
+ export declare function withSST<Fn extends Record<string, SSTCompatibleSplittedFunction>>(config: SSTCompatibleConfig<Fn>): {
43
+ default: SSTCompatibleFunction;
44
+ functions?: Fn | undefined;
45
+ middleware?: {
46
+ external: true;
47
+ } | undefined;
48
+ dangerous?: import("../types/open-next").DangerousOptions | undefined;
49
+ buildCommand?: string | undefined;
50
+ buildOutputPath?: string | undefined;
51
+ appPath?: string | undefined;
52
+ packageJsonPath?: string | undefined;
53
+ };
54
+ export {};
@@ -0,0 +1,28 @@
1
+ /**
2
+ * This function makes it more straightforward to use SST with OpenNext.
3
+ * All options are already restricted to SST compatible options only.
4
+ * Some options not present here can be used in SST, but it's an advanced use case that
5
+ * can easily break the deployment. If you need to use those options, you should just provide a
6
+ * compatible OpenNextConfig inside your `open-next.config.ts` file.
7
+ * @example
8
+ * ```ts
9
+ export default withSST({
10
+ default: {
11
+ override: {
12
+ wrapper: "aws-lambda-streaming",
13
+ },
14
+ },
15
+ functions: {
16
+ "api/*": {
17
+ routes: ["app/api/test/route", "page/api/otherApi"],
18
+ patterns: ["/api/*"],
19
+ },
20
+ },
21
+ });
22
+ * ```
23
+ */
24
+ export function withSST(config) {
25
+ return {
26
+ ...config,
27
+ };
28
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./openNextResponse.js";
2
+ export * from "./request.js";
@@ -0,0 +1,4 @@
1
+ // @__PURE__
2
+ export * from "./openNextResponse.js";
3
+ // @__PURE__
4
+ export * from "./request.js";
@@ -0,0 +1,78 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ /// <reference types="node" />
5
+ import type { IncomingMessage, OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from "http";
6
+ import { Socket } from "net";
7
+ import { Transform, TransformCallback, Writable } from "stream";
8
+ export interface StreamCreator {
9
+ writeHeaders(prelude: {
10
+ statusCode: number;
11
+ cookies: string[];
12
+ headers: Record<string, string>;
13
+ }): Writable;
14
+ onWrite?: () => void;
15
+ onFinish: (length: number) => void;
16
+ }
17
+ export declare class OpenNextNodeResponse extends Transform implements ServerResponse {
18
+ private fixHeaders;
19
+ private streamCreator?;
20
+ private initialHeaders?;
21
+ statusCode: number;
22
+ statusMessage: string;
23
+ headers: OutgoingHttpHeaders;
24
+ private _cookies;
25
+ private responseStream?;
26
+ headersSent: boolean;
27
+ _chunks: Buffer[];
28
+ strictContentLength: boolean;
29
+ assignSocket(_socket: Socket): void;
30
+ detachSocket(_socket: Socket): void;
31
+ writeContinue(_callback?: (() => void) | undefined): void;
32
+ writeEarlyHints(_hints: Record<string, string | string[]>, _callback?: (() => void) | undefined): void;
33
+ writeProcessing(): void;
34
+ /**
35
+ * This is a dummy request object to comply with the ServerResponse interface
36
+ * It will never be defined
37
+ */
38
+ req: IncomingMessage;
39
+ chunkedEncoding: boolean;
40
+ shouldKeepAlive: boolean;
41
+ useChunkedEncodingByDefault: boolean;
42
+ sendDate: boolean;
43
+ connection: Socket | null;
44
+ socket: Socket | null;
45
+ setTimeout(_msecs: number, _callback?: (() => void) | undefined): this;
46
+ addTrailers(_headers: OutgoingHttpHeaders | readonly [string, string][]): void;
47
+ constructor(fixHeaders: (headers: OutgoingHttpHeaders) => void, onEnd: (headers: OutgoingHttpHeaders) => Promise<void>, streamCreator?: StreamCreator | undefined, initialHeaders?: OutgoingHttpHeaders | undefined);
48
+ get originalResponse(): this;
49
+ get finished(): boolean;
50
+ setHeader(name: string, value: string | string[]): this;
51
+ removeHeader(name: string): this;
52
+ hasHeader(name: string): boolean;
53
+ getHeaders(): OutgoingHttpHeaders;
54
+ getHeader(name: string): OutgoingHttpHeader | undefined;
55
+ getHeaderNames(): string[];
56
+ flushHeaders(): void;
57
+ appendHeader(name: string, value: string | string[]): this;
58
+ writeHead(statusCode: number, statusMessage?: string | undefined, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[] | undefined): this;
59
+ writeHead(statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[] | undefined): this;
60
+ /**
61
+ * OpenNext specific method
62
+ */
63
+ getFixedHeaders(): OutgoingHttpHeaders;
64
+ getBody(): Buffer;
65
+ private _internalWrite;
66
+ _transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback): void;
67
+ _flush(callback: TransformCallback): void;
68
+ /**
69
+ * Next specific methods
70
+ * On earlier versions of next.js, those methods are mandatory to make everything work
71
+ */
72
+ get sent(): boolean;
73
+ getHeaderValues(name: string): string[] | undefined;
74
+ send(): void;
75
+ body(value: string): this;
76
+ onClose(callback: () => void): void;
77
+ redirect(destination: string, statusCode: number): this;
78
+ }
@@ -0,0 +1,281 @@
1
+ import { Transform } from "stream";
2
+ import { debug } from "../adapters/logger";
3
+ import { parseCookies, parseHeaders } from "./util";
4
+ const SET_COOKIE_HEADER = "set-cookie";
5
+ const CANNOT_BE_USED = "This cannot be used in OpenNext";
6
+ // We only need to implement the methods that are used by next.js
7
+ export class OpenNextNodeResponse extends Transform {
8
+ fixHeaders;
9
+ streamCreator;
10
+ initialHeaders;
11
+ statusCode;
12
+ statusMessage = "";
13
+ headers = {};
14
+ _cookies = [];
15
+ responseStream;
16
+ headersSent = false;
17
+ _chunks = [];
18
+ // To comply with the ServerResponse interface :
19
+ strictContentLength = false;
20
+ assignSocket(_socket) {
21
+ throw new Error(CANNOT_BE_USED);
22
+ }
23
+ detachSocket(_socket) {
24
+ throw new Error(CANNOT_BE_USED);
25
+ }
26
+ // We might have to revisit those 3 in the future
27
+ writeContinue(_callback) {
28
+ throw new Error(CANNOT_BE_USED);
29
+ }
30
+ writeEarlyHints(_hints, _callback) {
31
+ throw new Error(CANNOT_BE_USED);
32
+ }
33
+ writeProcessing() {
34
+ throw new Error(CANNOT_BE_USED);
35
+ }
36
+ /**
37
+ * This is a dummy request object to comply with the ServerResponse interface
38
+ * It will never be defined
39
+ */
40
+ req;
41
+ chunkedEncoding = false;
42
+ shouldKeepAlive = true;
43
+ useChunkedEncodingByDefault = true;
44
+ sendDate = false;
45
+ connection = null;
46
+ socket = null;
47
+ setTimeout(_msecs, _callback) {
48
+ throw new Error(CANNOT_BE_USED);
49
+ }
50
+ addTrailers(_headers) {
51
+ throw new Error(CANNOT_BE_USED);
52
+ }
53
+ constructor(fixHeaders, onEnd, streamCreator, initialHeaders) {
54
+ super();
55
+ this.fixHeaders = fixHeaders;
56
+ this.streamCreator = streamCreator;
57
+ this.initialHeaders = initialHeaders;
58
+ this.once("finish", () => {
59
+ if (!this.headersSent) {
60
+ this.flushHeaders();
61
+ }
62
+ // In some cases we might not have a store i.e. for example in the image optimization function
63
+ // We may want to reconsider this in the future, it might be intersting to have access to this store everywhere
64
+ globalThis.__als
65
+ ?.getStore()
66
+ ?.pendingPromiseRunner.add(onEnd(this.headers));
67
+ const bodyLength = this.getBody().length;
68
+ this.streamCreator?.onFinish(bodyLength);
69
+ });
70
+ }
71
+ // Necessary for next 12
72
+ // We might have to implement all the methods here
73
+ get originalResponse() {
74
+ return this;
75
+ }
76
+ get finished() {
77
+ return Boolean(this.writableFinished && this.responseStream?.writableFinished);
78
+ }
79
+ setHeader(name, value) {
80
+ const key = name.toLowerCase();
81
+ if (key === SET_COOKIE_HEADER) {
82
+ if (Array.isArray(value)) {
83
+ this._cookies = value;
84
+ }
85
+ else {
86
+ this._cookies = [value];
87
+ }
88
+ }
89
+ // We should always replace the header
90
+ // See https://nodejs.org/docs/latest-v18.x/api/http.html#responsesetheadername-value
91
+ this.headers[key] = value;
92
+ return this;
93
+ }
94
+ removeHeader(name) {
95
+ const key = name.toLowerCase();
96
+ if (key === SET_COOKIE_HEADER) {
97
+ this._cookies = [];
98
+ }
99
+ else {
100
+ delete this.headers[key];
101
+ }
102
+ return this;
103
+ }
104
+ hasHeader(name) {
105
+ const key = name.toLowerCase();
106
+ if (key === SET_COOKIE_HEADER) {
107
+ return this._cookies.length > 0;
108
+ }
109
+ return this.headers[key] !== undefined;
110
+ }
111
+ getHeaders() {
112
+ return this.headers;
113
+ }
114
+ getHeader(name) {
115
+ return this.headers[name.toLowerCase()];
116
+ }
117
+ getHeaderNames() {
118
+ return Object.keys(this.headers);
119
+ }
120
+ // Only used directly in next@14+
121
+ flushHeaders() {
122
+ this.headersSent = true;
123
+ // Initial headers should be merged with the new headers
124
+ // These initial headers are the one created either in the middleware or in next.config.js
125
+ const mergeHeadersPriority = globalThis.__als?.getStore()?.mergeHeadersPriority ?? "middleware";
126
+ if (this.initialHeaders) {
127
+ this.headers =
128
+ mergeHeadersPriority === "middleware"
129
+ ? {
130
+ ...this.headers,
131
+ ...this.initialHeaders,
132
+ }
133
+ : {
134
+ ...this.initialHeaders,
135
+ ...this.headers,
136
+ };
137
+ const initialCookies = parseCookies(this.initialHeaders[SET_COOKIE_HEADER] ?? []);
138
+ this._cookies =
139
+ mergeHeadersPriority === "middleware"
140
+ ? [...this._cookies, ...initialCookies]
141
+ : [...initialCookies, ...this._cookies];
142
+ }
143
+ this.fixHeaders(this.headers);
144
+ // We need to fix the set-cookie header here
145
+ this.headers[SET_COOKIE_HEADER] = this._cookies;
146
+ const parsedHeaders = parseHeaders(this.headers);
147
+ // We need to remove the set-cookie header from the parsed headers because
148
+ // it does not handle multiple set-cookie headers properly
149
+ delete parsedHeaders[SET_COOKIE_HEADER];
150
+ if (this.streamCreator) {
151
+ this.responseStream = this.streamCreator?.writeHeaders({
152
+ statusCode: this.statusCode ?? 200,
153
+ cookies: this._cookies,
154
+ headers: parsedHeaders,
155
+ });
156
+ this.pipe(this.responseStream);
157
+ }
158
+ }
159
+ appendHeader(name, value) {
160
+ const key = name.toLowerCase();
161
+ if (!this.hasHeader(key)) {
162
+ return this.setHeader(key, value);
163
+ }
164
+ else {
165
+ const existingHeader = this.getHeader(key);
166
+ const toAppend = Array.isArray(value) ? value : [value];
167
+ const newValue = Array.isArray(existingHeader)
168
+ ? [...existingHeader, ...toAppend]
169
+ : [existingHeader, ...toAppend];
170
+ return this.setHeader(key, newValue);
171
+ }
172
+ }
173
+ writeHead(statusCode, statusMessage, headers) {
174
+ let _headers = headers;
175
+ let _statusMessage;
176
+ if (typeof statusMessage === "string") {
177
+ _statusMessage = statusMessage;
178
+ }
179
+ else {
180
+ _headers = statusMessage;
181
+ }
182
+ const finalHeaders = this.headers;
183
+ if (_headers) {
184
+ if (Array.isArray(_headers)) {
185
+ // headers may be an Array where the keys and values are in the same list. It is not a list of tuples. So, the even-numbered offsets are key values, and the odd-numbered offsets are the associated values.
186
+ for (let i = 0; i < _headers.length; i += 2) {
187
+ finalHeaders[_headers[i]] = _headers[i + 1];
188
+ }
189
+ }
190
+ else {
191
+ for (const key of Object.keys(_headers)) {
192
+ finalHeaders[key] = _headers[key];
193
+ }
194
+ }
195
+ }
196
+ this.statusCode = statusCode;
197
+ if (headers) {
198
+ this.headers = finalHeaders;
199
+ }
200
+ this.flushHeaders();
201
+ return this;
202
+ }
203
+ /**
204
+ * OpenNext specific method
205
+ */
206
+ getFixedHeaders() {
207
+ // Do we want to apply this on writeHead?
208
+ this.fixHeaders(this.headers);
209
+ // This way we ensure that the cookies are correct
210
+ this.headers[SET_COOKIE_HEADER] = this._cookies;
211
+ return this.headers;
212
+ }
213
+ getBody() {
214
+ return Buffer.concat(this._chunks);
215
+ }
216
+ _internalWrite(chunk, encoding) {
217
+ this._chunks.push(Buffer.from(chunk, encoding));
218
+ this.push(chunk, encoding);
219
+ this.streamCreator?.onWrite?.();
220
+ }
221
+ _transform(chunk, encoding, callback) {
222
+ if (!this.headersSent) {
223
+ this.flushHeaders();
224
+ }
225
+ this._internalWrite(chunk, encoding);
226
+ callback();
227
+ }
228
+ //This is only here because of aws broken streaming implementation.
229
+ //Hopefully one day they will be able to give us a working streaming implementation in lambda for everyone
230
+ //If you're lucky you have a working streaming implementation in your aws account and don't need this
231
+ //If not you can set the OPEN_NEXT_FORCE_NON_EMPTY_RESPONSE env variable to true
232
+ //BE CAREFUL: Aws keeps rolling out broken streaming implementations even on accounts that had working ones before
233
+ //This is not dependent on the node runtime used
234
+ //There is another known issue with aws lambda streaming where the request reach the lambda only way after the request has been sent by the client. For this there is absolutely nothing we can do, contact aws support if that's your case
235
+ _flush(callback) {
236
+ if (this.getBody().length < 1 &&
237
+ // We use an env variable here because not all aws account have the same behavior
238
+ // On some aws accounts the response will hang if the body is empty
239
+ // We are modifying the response body here, this is not a good practice
240
+ process.env.OPEN_NEXT_FORCE_NON_EMPTY_RESPONSE === "true") {
241
+ debug('Force writing "SOMETHING" to the response body');
242
+ this.push("SOMETHING");
243
+ }
244
+ callback();
245
+ }
246
+ /**
247
+ * Next specific methods
248
+ * On earlier versions of next.js, those methods are mandatory to make everything work
249
+ */
250
+ get sent() {
251
+ return this.finished || this.headersSent;
252
+ }
253
+ getHeaderValues(name) {
254
+ const values = this.getHeader(name);
255
+ if (values === undefined)
256
+ return undefined;
257
+ return (Array.isArray(values) ? values : [values]).map((value) => value.toString());
258
+ }
259
+ send() {
260
+ const body = this.getBody();
261
+ this.end(body);
262
+ }
263
+ body(value) {
264
+ this.write(value);
265
+ return this;
266
+ }
267
+ onClose(callback) {
268
+ this.on("close", callback);
269
+ }
270
+ redirect(destination, statusCode) {
271
+ this.setHeader("Location", destination);
272
+ this.statusCode = statusCode;
273
+ // Since IE11 doesn't support the 308 header add backwards
274
+ // compatibility using refresh header
275
+ if (statusCode === 308) {
276
+ this.setHeader("Refresh", `0;url=${destination}`);
277
+ }
278
+ //TODO: test to see if we need to call end here
279
+ return this;
280
+ }
281
+ }
@@ -0,0 +1,12 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import http from "node:http";
4
+ export declare class IncomingMessage extends http.IncomingMessage {
5
+ constructor({ method, url, headers, body, remoteAddress, }: {
6
+ method: string;
7
+ url: string;
8
+ headers: Record<string, string>;
9
+ body?: Buffer;
10
+ remoteAddress: string;
11
+ });
12
+ }
@@ -0,0 +1,35 @@
1
+ // Copied and modified from serverless-http by Doug Moscrop
2
+ // https://github.com/dougmoscrop/serverless-http/blob/master/lib/request.js
3
+ // Licensed under the MIT License
4
+ // @ts-nocheck
5
+ import http from "node:http";
6
+ export class IncomingMessage extends http.IncomingMessage {
7
+ constructor({ method, url, headers, body, remoteAddress, }) {
8
+ super({
9
+ encrypted: true,
10
+ readable: false,
11
+ remoteAddress,
12
+ address: () => ({ port: 443 }),
13
+ end: Function.prototype,
14
+ destroy: Function.prototype,
15
+ });
16
+ if (typeof headers["content-length"] === "undefined") {
17
+ headers["content-length"] = Buffer.byteLength(body).toString();
18
+ }
19
+ Object.assign(this, {
20
+ ip: remoteAddress,
21
+ complete: true,
22
+ httpVersion: "1.1",
23
+ httpVersionMajor: "1",
24
+ httpVersionMinor: "1",
25
+ method,
26
+ headers,
27
+ body,
28
+ url,
29
+ });
30
+ this._read = () => {
31
+ this.push(body);
32
+ this.push(null);
33
+ };
34
+ }
35
+ }
@@ -0,0 +1,4 @@
1
+ import http from "node:http";
2
+ export declare const parseHeaders: (headers?: http.OutgoingHttpHeader[] | http.OutgoingHttpHeaders) => Record<string, string>;
3
+ export declare const convertHeader: (header: http.OutgoingHttpHeader) => string;
4
+ export declare function parseCookies(cookies?: string | string[]): string[] | undefined;
@@ -0,0 +1,34 @@
1
+ export const parseHeaders = (headers) => {
2
+ const result = {};
3
+ if (!headers) {
4
+ return result;
5
+ }
6
+ for (const [key, value] of Object.entries(headers)) {
7
+ if (value === undefined) {
8
+ continue;
9
+ }
10
+ else {
11
+ result[key.toLowerCase()] = convertHeader(value);
12
+ }
13
+ }
14
+ return result;
15
+ };
16
+ export const convertHeader = (header) => {
17
+ if (typeof header === "string") {
18
+ return header;
19
+ }
20
+ else if (Array.isArray(header)) {
21
+ return header.join(",");
22
+ }
23
+ else {
24
+ return String(header);
25
+ }
26
+ };
27
+ export function parseCookies(cookies) {
28
+ if (!cookies)
29
+ return;
30
+ if (typeof cookies === "string") {
31
+ return cookies.split(/(?<!Expires=\w+),/i).map((c) => c.trim());
32
+ }
33
+ return cookies;
34
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};