@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.
- package/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/adapters/binary.d.ts +1 -0
- package/dist/adapters/binary.js +63 -0
- package/dist/adapters/cache.d.ts +96 -0
- package/dist/adapters/cache.js +278 -0
- package/dist/adapters/config/index.d.ts +27 -0
- package/dist/adapters/config/index.js +21 -0
- package/dist/adapters/config/util.d.ts +28 -0
- package/dist/adapters/config/util.js +84 -0
- package/dist/adapters/dynamo-provider.d.ts +8 -0
- package/dist/adapters/dynamo-provider.js +42 -0
- package/dist/adapters/edge-adapter.d.ts +8 -0
- package/dist/adapters/edge-adapter.js +54 -0
- package/dist/adapters/image-optimization-adapter.d.ts +4 -0
- package/dist/adapters/image-optimization-adapter.js +193 -0
- package/dist/adapters/logger.d.ts +13 -0
- package/dist/adapters/logger.js +51 -0
- package/dist/adapters/middleware.d.ts +5 -0
- package/dist/adapters/middleware.js +84 -0
- package/dist/adapters/plugins/14.1/util.d.ts +1 -0
- package/dist/adapters/plugins/14.1/util.js +29 -0
- package/dist/adapters/plugins/image-optimization/image-optimization.d.ts +11 -0
- package/dist/adapters/plugins/image-optimization/image-optimization.js +14 -0
- package/dist/adapters/plugins/image-optimization/image-optimization.replacement.d.ts +11 -0
- package/dist/adapters/plugins/image-optimization/image-optimization.replacement.js +22 -0
- package/dist/adapters/plugins/without-routing/requestHandler.d.ts +2 -0
- package/dist/adapters/plugins/without-routing/requestHandler.js +10 -0
- package/dist/adapters/revalidate.d.ts +9 -0
- package/dist/adapters/revalidate.js +71 -0
- package/dist/adapters/server-adapter.d.ts +4 -0
- package/dist/adapters/server-adapter.js +27 -0
- package/dist/adapters/util.d.ts +10 -0
- package/dist/adapters/util.js +28 -0
- package/dist/adapters/warmer-function.d.ts +12 -0
- package/dist/adapters/warmer-function.js +80 -0
- package/dist/build/bundleNextServer.d.ts +1 -0
- package/dist/build/bundleNextServer.js +87 -0
- package/dist/build/compileConfig.d.ts +3 -0
- package/dist/build/compileConfig.js +64 -0
- package/dist/build/copyTracedFiles.d.ts +1 -0
- package/dist/build/copyTracedFiles.js +207 -0
- package/dist/build/createServerBundle.d.ts +3 -0
- package/dist/build/createServerBundle.js +228 -0
- package/dist/build/edge/createEdgeBundle.d.ts +20 -0
- package/dist/build/edge/createEdgeBundle.js +149 -0
- package/dist/build/generateOutput.d.ts +2 -0
- package/dist/build/generateOutput.js +239 -0
- package/dist/build/helper.d.ts +33 -0
- package/dist/build/helper.js +193 -0
- package/dist/build/patch/patchedAsyncStorage.d.ts +5 -0
- package/dist/build/patch/patchedAsyncStorage.js +16 -0
- package/dist/build/validateConfig.d.ts +2 -0
- package/dist/build/validateConfig.js +76 -0
- package/dist/build.d.ts +7 -0
- package/dist/build.js +533 -0
- package/dist/cache/incremental/s3-lite.d.ts +3 -0
- package/dist/cache/incremental/s3-lite.js +72 -0
- package/dist/cache/incremental/s3.d.ts +3 -0
- package/dist/cache/incremental/s3.js +44 -0
- package/dist/cache/incremental/types.d.ts +34 -0
- package/dist/cache/incremental/types.js +1 -0
- package/dist/cache/next-types.d.ts +62 -0
- package/dist/cache/next-types.js +1 -0
- package/dist/cache/tag/constants.d.ts +2 -0
- package/dist/cache/tag/constants.js +17 -0
- package/dist/cache/tag/dynamodb-lite.d.ts +3 -0
- package/dist/cache/tag/dynamodb-lite.js +174 -0
- package/dist/cache/tag/dynamodb.d.ts +3 -0
- package/dist/cache/tag/dynamodb.js +129 -0
- package/dist/cache/tag/types.d.ts +11 -0
- package/dist/cache/tag/types.js +1 -0
- package/dist/converters/aws-apigw-v1.d.ts +3 -0
- package/dist/converters/aws-apigw-v1.js +89 -0
- package/dist/converters/aws-apigw-v2.d.ts +3 -0
- package/dist/converters/aws-apigw-v2.js +99 -0
- package/dist/converters/aws-cloudfront.d.ts +3 -0
- package/dist/converters/aws-cloudfront.js +170 -0
- package/dist/converters/dummy.d.ts +7 -0
- package/dist/converters/dummy.js +16 -0
- package/dist/converters/edge.d.ts +6 -0
- package/dist/converters/edge.js +88 -0
- package/dist/converters/node.d.ts +3 -0
- package/dist/converters/node.js +45 -0
- package/dist/converters/sqs-revalidate.d.ts +4 -0
- package/dist/converters/sqs-revalidate.js +22 -0
- package/dist/converters/utils.d.ts +1 -0
- package/dist/converters/utils.js +9 -0
- package/dist/core/createGenericHandler.d.ts +11 -0
- package/dist/core/createGenericHandler.js +16 -0
- package/dist/core/createMainHandler.d.ts +18 -0
- package/dist/core/createMainHandler.js +24 -0
- package/dist/core/edgeFunctionHandler.d.ts +54 -0
- package/dist/core/edgeFunctionHandler.js +21 -0
- package/dist/core/patchAsyncStorage.d.ts +1 -0
- package/dist/core/patchAsyncStorage.js +16 -0
- package/dist/core/requestHandler.d.ts +3 -0
- package/dist/core/requestHandler.js +162 -0
- package/dist/core/require-hooks.d.ts +3 -0
- package/dist/core/require-hooks.js +102 -0
- package/dist/core/resolve.d.ts +31 -0
- package/dist/core/resolve.js +81 -0
- package/dist/core/routing/cacheInterceptor.d.ts +2 -0
- package/dist/core/routing/cacheInterceptor.js +162 -0
- package/dist/core/routing/i18n/accept-header.d.ts +1 -0
- package/dist/core/routing/i18n/accept-header.js +101 -0
- package/dist/core/routing/i18n/index.d.ts +2 -0
- package/dist/core/routing/i18n/index.js +36 -0
- package/dist/core/routing/matcher.d.ts +25 -0
- package/dist/core/routing/matcher.js +294 -0
- package/dist/core/routing/middleware.d.ts +7 -0
- package/dist/core/routing/middleware.js +167 -0
- package/dist/core/routing/util.d.ts +105 -0
- package/dist/core/routing/util.js +415 -0
- package/dist/core/routingHandler.d.ts +8 -0
- package/dist/core/routingHandler.js +127 -0
- package/dist/core/util.d.ts +5 -0
- package/dist/core/util.js +84 -0
- package/dist/helpers/withCloudflare.d.ts +65 -0
- package/dist/helpers/withCloudflare.js +58 -0
- package/dist/helpers/withSST.d.ts +54 -0
- package/dist/helpers/withSST.js +28 -0
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +4 -0
- package/dist/http/openNextResponse.d.ts +78 -0
- package/dist/http/openNextResponse.js +281 -0
- package/dist/http/request.d.ts +12 -0
- package/dist/http/request.js +35 -0
- package/dist/http/util.d.ts +4 -0
- package/dist/http/util.js +34 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +37 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +13 -0
- package/dist/minimize-js.d.ts +1 -0
- package/dist/minimize-js.js +101 -0
- package/dist/overrides/imageLoader/host.d.ts +3 -0
- package/dist/overrides/imageLoader/host.js +29 -0
- package/dist/overrides/imageLoader/s3.d.ts +3 -0
- package/dist/overrides/imageLoader/s3.js +33 -0
- package/dist/plugins/edge.d.ts +15 -0
- package/dist/plugins/edge.js +157 -0
- package/dist/plugins/replacement.d.ts +42 -0
- package/dist/plugins/replacement.js +74 -0
- package/dist/plugins/resolve.d.ts +18 -0
- package/dist/plugins/resolve.js +45 -0
- package/dist/queue/sqs-lite.d.ts +3 -0
- package/dist/queue/sqs-lite.js +52 -0
- package/dist/queue/sqs.d.ts +3 -0
- package/dist/queue/sqs.js +20 -0
- package/dist/queue/types.d.ts +12 -0
- package/dist/queue/types.js +1 -0
- package/dist/types/aws-lambda.d.ts +22 -0
- package/dist/types/aws-lambda.js +1 -0
- package/dist/types/next-types.d.ts +155 -0
- package/dist/types/next-types.js +2 -0
- package/dist/types/open-next.d.ts +303 -0
- package/dist/types/open-next.js +1 -0
- package/dist/utils/error.d.ts +23 -0
- package/dist/utils/error.js +32 -0
- package/dist/utils/fetch.d.ts +2 -0
- package/dist/utils/fetch.js +23 -0
- package/dist/utils/promise.d.ts +18 -0
- package/dist/utils/promise.js +48 -0
- package/dist/utils/stream.d.ts +5 -0
- package/dist/utils/stream.js +30 -0
- package/dist/wrappers/aws-lambda-streaming.d.ts +7 -0
- package/dist/wrappers/aws-lambda-streaming.js +88 -0
- package/dist/wrappers/aws-lambda.d.ts +7 -0
- package/dist/wrappers/aws-lambda.js +39 -0
- package/dist/wrappers/cloudflare.d.ts +11 -0
- package/dist/wrappers/cloudflare.js +20 -0
- package/dist/wrappers/node.d.ts +7 -0
- package/dist/wrappers/node.js +57 -0
- 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,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
|
+
}
|
package/dist/index.d.ts
ADDED