@geostrategists/react-router-aws 2.0.0
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 +7 -0
- package/README.md +76 -0
- package/dist/index.d.mts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +313 -0
- package/dist/index.mjs +286 -0
- package/eslint.config.mjs +12 -0
- package/package.json +104 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) React Training LLC 2015-2019 Copyright (c) Remix Software Inc. 2020-2021 Copyright (c) Shopify Inc. 2022-2023 (c) Copyright (c) 2022 Wing Leung Copyright (c) 2025 Geostrategists Consulting GmbH
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @geostrategists/react-router-aws
|
|
2
|
+
|
|
3
|
+
## AWS adapters for React Router v7 (successor to Remix)
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/@geostrategists%2Freact-router-aws)
|
|
6
|
+
[](https://packagephobia.com/result?p=@geostrategists/react-router-aws)
|
|
7
|
+
|
|
8
|
+
Forked from [remix-aws](https://github.com/wingleung/remix-aws) to support React Router v7, which Remix was merged into.
|
|
9
|
+
|
|
10
|
+
## 🚀 support
|
|
11
|
+
|
|
12
|
+
- API gateway v1
|
|
13
|
+
- API gateway v2
|
|
14
|
+
- Application load balancer
|
|
15
|
+
|
|
16
|
+
## Getting started
|
|
17
|
+
|
|
18
|
+
```shell
|
|
19
|
+
npm install --save @geostrategists/react-router-aws
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
// server.js
|
|
24
|
+
import * as build from "virtual:react-router/server-build";
|
|
25
|
+
import { AWSProxy, createRequestHandler } from "@geostrategists/react-router-aws";
|
|
26
|
+
|
|
27
|
+
export const handler = createRequestHandler({
|
|
28
|
+
build,
|
|
29
|
+
mode: process.env.NODE_ENV,
|
|
30
|
+
awsProxy: AWSProxy.APIGatewayV2,
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `awsProxy`
|
|
35
|
+
|
|
36
|
+
By default, the `awsProxy` is set to `AWSProxy.APIGatewayV2`.
|
|
37
|
+
|
|
38
|
+
#### Options
|
|
39
|
+
|
|
40
|
+
- `AWSProxy.APIGatewayV1`
|
|
41
|
+
- `AWSProxy.APIGatewayV2`
|
|
42
|
+
- `AWSProxy.ALB`
|
|
43
|
+
- `AWSProxy.FunctionURL`
|
|
44
|
+
|
|
45
|
+
## Deployment recommendation
|
|
46
|
+
|
|
47
|
+
Since Vite already bundles the project into a single entry point, there is no need to further
|
|
48
|
+
bundle the lambda code.
|
|
49
|
+
For example, when using AWS CDK, we recommend using lambda.Function directly instead of lambda.NodeJsFunction.
|
|
50
|
+
|
|
51
|
+
Dependencies can be provided using a layer, for example.
|
|
52
|
+
|
|
53
|
+
We recommend setting the `serverModuleFormat` to ESM.
|
|
54
|
+
However, to ensure that AWS lambda correctly interprets the output file as an ES module, you need to take additional steps.
|
|
55
|
+
|
|
56
|
+
There are two primary methods to achieve this:
|
|
57
|
+
|
|
58
|
+
- Specify the module type in package.json:
|
|
59
|
+
Add `"type": "module"` to your package.json file and ensure that this file is included in the deployment package sent to AWS Lambda.
|
|
60
|
+
|
|
61
|
+
- Use the .mjs extension:
|
|
62
|
+
Alternatively, you can change the file extension to `.mjs`. For example, you can configure the React Router `serverBuildFile` setting to output `index.mjs`.
|
|
63
|
+
|
|
64
|
+
more info: [AWS docs on ES module support in AWS lambdas](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html#designate-es-module)
|
|
65
|
+
|
|
66
|
+
## Notes
|
|
67
|
+
|
|
68
|
+
### split from @remix/architect
|
|
69
|
+
|
|
70
|
+
As mentioned in [#3173](https://github.com/remix-run/remix/pull/3173) the goal would be to provide an AWS adapter for
|
|
71
|
+
the community by the community.
|
|
72
|
+
In doing so the focus will be on AWS integrations and less on Architect. I do think it's added value to provide examples
|
|
73
|
+
for Architect, AWS SAM, AWS CDK, Serverless,...
|
|
74
|
+
|
|
75
|
+
**info:** [ALB types](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/aws-lambda/trigger/alb.d.ts#L29-L48)
|
|
76
|
+
vs [API gateway v1 types](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/aws-lambda/trigger/api-gateway-proxy.d.ts#L116-L145)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { APIGatewayProxyEventV2, APIGatewayProxyEvent, ALBEvent, APIGatewayProxyHandlerV2, APIGatewayProxyHandler, ALBHandler } from 'aws-lambda';
|
|
2
|
+
import { UNSAFE_MiddlewareEnabled, unstable_InitialContext, AppLoadContext, ServerBuild } from 'react-router';
|
|
3
|
+
|
|
4
|
+
declare enum AWSProxy {
|
|
5
|
+
APIGatewayV1 = "APIGatewayV1",
|
|
6
|
+
APIGatewayV2 = "APIGatewayV2",
|
|
7
|
+
ALB = "ALB",
|
|
8
|
+
FunctionURL = "FunctionURL"
|
|
9
|
+
}
|
|
10
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
11
|
+
/**
|
|
12
|
+
* A function that returns the value to use as `context` in route `loader` and
|
|
13
|
+
* `action` functions.
|
|
14
|
+
*
|
|
15
|
+
* You can think of this as an escape hatch that allows you to pass
|
|
16
|
+
* environment/platform-specific values through to your loader/action.
|
|
17
|
+
*/
|
|
18
|
+
type GetLoadContextFunction = (event: APIGatewayProxyEventV2 | APIGatewayProxyEvent | ALBEvent) => UNSAFE_MiddlewareEnabled extends true ? MaybePromise<unstable_InitialContext> : MaybePromise<AppLoadContext>;
|
|
19
|
+
type RequestHandler = APIGatewayProxyHandlerV2 | APIGatewayProxyHandler | ALBHandler;
|
|
20
|
+
/**
|
|
21
|
+
* Returns a request handler for AWS that serves the response using
|
|
22
|
+
* React Router.
|
|
23
|
+
*/
|
|
24
|
+
declare function createRequestHandler({ build, getLoadContext, mode, awsProxy, }: {
|
|
25
|
+
build: ServerBuild;
|
|
26
|
+
getLoadContext?: GetLoadContextFunction;
|
|
27
|
+
mode?: string;
|
|
28
|
+
awsProxy?: AWSProxy;
|
|
29
|
+
}): RequestHandler;
|
|
30
|
+
|
|
31
|
+
export { AWSProxy, type GetLoadContextFunction, type RequestHandler, createRequestHandler };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { APIGatewayProxyEventV2, APIGatewayProxyEvent, ALBEvent, APIGatewayProxyHandlerV2, APIGatewayProxyHandler, ALBHandler } from 'aws-lambda';
|
|
2
|
+
import { UNSAFE_MiddlewareEnabled, unstable_InitialContext, AppLoadContext, ServerBuild } from 'react-router';
|
|
3
|
+
|
|
4
|
+
declare enum AWSProxy {
|
|
5
|
+
APIGatewayV1 = "APIGatewayV1",
|
|
6
|
+
APIGatewayV2 = "APIGatewayV2",
|
|
7
|
+
ALB = "ALB",
|
|
8
|
+
FunctionURL = "FunctionURL"
|
|
9
|
+
}
|
|
10
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
11
|
+
/**
|
|
12
|
+
* A function that returns the value to use as `context` in route `loader` and
|
|
13
|
+
* `action` functions.
|
|
14
|
+
*
|
|
15
|
+
* You can think of this as an escape hatch that allows you to pass
|
|
16
|
+
* environment/platform-specific values through to your loader/action.
|
|
17
|
+
*/
|
|
18
|
+
type GetLoadContextFunction = (event: APIGatewayProxyEventV2 | APIGatewayProxyEvent | ALBEvent) => UNSAFE_MiddlewareEnabled extends true ? MaybePromise<unstable_InitialContext> : MaybePromise<AppLoadContext>;
|
|
19
|
+
type RequestHandler = APIGatewayProxyHandlerV2 | APIGatewayProxyHandler | ALBHandler;
|
|
20
|
+
/**
|
|
21
|
+
* Returns a request handler for AWS that serves the response using
|
|
22
|
+
* React Router.
|
|
23
|
+
*/
|
|
24
|
+
declare function createRequestHandler({ build, getLoadContext, mode, awsProxy, }: {
|
|
25
|
+
build: ServerBuild;
|
|
26
|
+
getLoadContext?: GetLoadContextFunction;
|
|
27
|
+
mode?: string;
|
|
28
|
+
awsProxy?: AWSProxy;
|
|
29
|
+
}): RequestHandler;
|
|
30
|
+
|
|
31
|
+
export { AWSProxy, type GetLoadContextFunction, type RequestHandler, createRequestHandler };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @geostrategists/react-router-aws v2.0.0
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Geostrategists Consulting GmbH
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
"use strict";
|
|
12
|
+
var __defProp = Object.defineProperty;
|
|
13
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
14
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
AWSProxy: () => AWSProxy,
|
|
34
|
+
createRequestHandler: () => createRequestHandler
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/server.ts
|
|
39
|
+
var import_react_router = require("react-router");
|
|
40
|
+
|
|
41
|
+
// src/adapters/api-gateway-v1.ts
|
|
42
|
+
var import_node = require("@react-router/node");
|
|
43
|
+
var import_url = require("url");
|
|
44
|
+
|
|
45
|
+
// src/binaryTypes.ts
|
|
46
|
+
var binaryTypes = [
|
|
47
|
+
"application/octet-stream",
|
|
48
|
+
// Docs
|
|
49
|
+
"application/epub+zip",
|
|
50
|
+
"application/msword",
|
|
51
|
+
"application/pdf",
|
|
52
|
+
"application/rtf",
|
|
53
|
+
"application/vnd.amazon.ebook",
|
|
54
|
+
"application/vnd.ms-excel",
|
|
55
|
+
"application/vnd.ms-powerpoint",
|
|
56
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
57
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
58
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
59
|
+
// Fonts
|
|
60
|
+
"font/otf",
|
|
61
|
+
"font/woff",
|
|
62
|
+
"font/woff2",
|
|
63
|
+
// Images
|
|
64
|
+
"image/avif",
|
|
65
|
+
"image/bmp",
|
|
66
|
+
"image/gif",
|
|
67
|
+
"image/jpeg",
|
|
68
|
+
"image/png",
|
|
69
|
+
"image/tiff",
|
|
70
|
+
"image/vnd.microsoft.icon",
|
|
71
|
+
"image/webp",
|
|
72
|
+
// Audio
|
|
73
|
+
"audio/3gpp",
|
|
74
|
+
"audio/aac",
|
|
75
|
+
"audio/basic",
|
|
76
|
+
"audio/mpeg",
|
|
77
|
+
"audio/ogg",
|
|
78
|
+
"audio/wav",
|
|
79
|
+
"audio/webm",
|
|
80
|
+
"audio/x-aiff",
|
|
81
|
+
"audio/x-midi",
|
|
82
|
+
"audio/x-wav",
|
|
83
|
+
// Video
|
|
84
|
+
"video/3gpp",
|
|
85
|
+
"video/mp2t",
|
|
86
|
+
"video/mpeg",
|
|
87
|
+
"video/ogg",
|
|
88
|
+
"video/quicktime",
|
|
89
|
+
"video/webm",
|
|
90
|
+
"video/x-msvideo",
|
|
91
|
+
// Archives
|
|
92
|
+
"application/java-archive",
|
|
93
|
+
"application/vnd.apple.installer+xml",
|
|
94
|
+
"application/x-7z-compressed",
|
|
95
|
+
"application/x-apple-diskimage",
|
|
96
|
+
"application/x-bzip",
|
|
97
|
+
"application/x-bzip2",
|
|
98
|
+
"application/x-gzip",
|
|
99
|
+
"application/x-java-archive",
|
|
100
|
+
"application/x-rar-compressed",
|
|
101
|
+
"application/x-tar",
|
|
102
|
+
"application/x-zip",
|
|
103
|
+
"application/zip"
|
|
104
|
+
];
|
|
105
|
+
function isBinaryType(contentType) {
|
|
106
|
+
if (!contentType) return false;
|
|
107
|
+
const [test] = contentType.split(";");
|
|
108
|
+
return binaryTypes.includes(test);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/adapters/api-gateway-v1.ts
|
|
112
|
+
function createReactRouterRequestAPIGatewayV1(event) {
|
|
113
|
+
const host = event.headers["x-forwarded-host"] || event.headers.Host;
|
|
114
|
+
const scheme = event.headers["x-forwarded-proto"] || "http";
|
|
115
|
+
const rawQueryString = new import_url.URLSearchParams(event.queryStringParameters).toString();
|
|
116
|
+
const search = rawQueryString.length > 0 ? `?${rawQueryString}` : "";
|
|
117
|
+
const url = new URL(event.path + search, `${scheme}://${host}`);
|
|
118
|
+
const isFormData = event.headers["content-type"]?.includes("multipart/form-data");
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
return new Request(url.href, {
|
|
121
|
+
method: event.requestContext.httpMethod,
|
|
122
|
+
headers: createReactRouterHeadersAPIGatewayV1(event.headers),
|
|
123
|
+
signal: controller.signal,
|
|
124
|
+
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body || void 0
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function createReactRouterHeadersAPIGatewayV1(requestHeaders) {
|
|
128
|
+
const headers = new Headers();
|
|
129
|
+
for (const [header, value] of Object.entries(requestHeaders)) {
|
|
130
|
+
if (value) {
|
|
131
|
+
headers.append(header, value);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return headers;
|
|
135
|
+
}
|
|
136
|
+
async function sendReactRouterResponseAPIGatewayV1(nodeResponse) {
|
|
137
|
+
const contentType = nodeResponse.headers.get("Content-Type");
|
|
138
|
+
const isBase64Encoded = isBinaryType(contentType);
|
|
139
|
+
let body;
|
|
140
|
+
if (nodeResponse.body) {
|
|
141
|
+
if (isBase64Encoded) {
|
|
142
|
+
body = await (0, import_node.readableStreamToString)(nodeResponse.body, "base64");
|
|
143
|
+
} else {
|
|
144
|
+
body = await nodeResponse.text();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
statusCode: nodeResponse.status,
|
|
149
|
+
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
150
|
+
body: body || "",
|
|
151
|
+
isBase64Encoded
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
var apiGatewayV1Adapter = {
|
|
155
|
+
createReactRouterRequest: createReactRouterRequestAPIGatewayV1,
|
|
156
|
+
sendReactRouterResponse: sendReactRouterResponseAPIGatewayV1
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// src/adapters/api-gateway-v2.ts
|
|
160
|
+
var import_node2 = require("@react-router/node");
|
|
161
|
+
function createReactRouterRequestAPIGateywayV2(event) {
|
|
162
|
+
const host = event.headers["x-forwarded-host"] || event.headers.host;
|
|
163
|
+
const search = event.rawQueryString.length ? `?${event.rawQueryString}` : "";
|
|
164
|
+
const scheme = event.headers["x-forwarded-proto"] || "http";
|
|
165
|
+
const url = new URL(event.rawPath + search, `${scheme}://${host}`);
|
|
166
|
+
const isFormData = event.headers["content-type"]?.includes("multipart/form-data");
|
|
167
|
+
const controller = new AbortController();
|
|
168
|
+
return new Request(url.href, {
|
|
169
|
+
method: event.requestContext.http.method,
|
|
170
|
+
headers: createReactRouterHeadersAPIGatewayV2(event.headers, event.cookies),
|
|
171
|
+
signal: controller.signal,
|
|
172
|
+
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function createReactRouterHeadersAPIGatewayV2(requestHeaders, requestCookies) {
|
|
176
|
+
const headers = new Headers();
|
|
177
|
+
for (const [header, value] of Object.entries(requestHeaders)) {
|
|
178
|
+
if (value) {
|
|
179
|
+
headers.append(header, value);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (requestCookies) {
|
|
183
|
+
headers.append("Cookie", requestCookies.join("; "));
|
|
184
|
+
}
|
|
185
|
+
return headers;
|
|
186
|
+
}
|
|
187
|
+
async function sendReactRouterResponseAPIGatewayV2(nodeResponse) {
|
|
188
|
+
const cookies = nodeResponse.headers.getSetCookie();
|
|
189
|
+
if (cookies.length) {
|
|
190
|
+
nodeResponse.headers.delete("Set-Cookie");
|
|
191
|
+
}
|
|
192
|
+
const contentType = nodeResponse.headers.get("Content-Type");
|
|
193
|
+
const isBase64Encoded = isBinaryType(contentType);
|
|
194
|
+
let body;
|
|
195
|
+
if (nodeResponse.body) {
|
|
196
|
+
if (isBase64Encoded) {
|
|
197
|
+
body = await (0, import_node2.readableStreamToString)(nodeResponse.body, "base64");
|
|
198
|
+
} else {
|
|
199
|
+
body = await nodeResponse.text();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
statusCode: nodeResponse.status,
|
|
204
|
+
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
205
|
+
cookies,
|
|
206
|
+
body,
|
|
207
|
+
isBase64Encoded
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
var apiGatewayV2Adapter = {
|
|
211
|
+
createReactRouterRequest: createReactRouterRequestAPIGateywayV2,
|
|
212
|
+
sendReactRouterResponse: sendReactRouterResponseAPIGatewayV2
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// src/adapters/application-load-balancer.ts
|
|
216
|
+
var import_node3 = require("@react-router/node");
|
|
217
|
+
var import_url2 = require("url");
|
|
218
|
+
function createReactRouterRequestALB(event) {
|
|
219
|
+
const headers = event?.headers || {};
|
|
220
|
+
const host = headers["x-forwarded-host"] || headers.Host;
|
|
221
|
+
const scheme = headers["x-forwarded-proto"] || "http";
|
|
222
|
+
const rawQueryString = new import_url2.URLSearchParams(event.queryStringParameters).toString();
|
|
223
|
+
const search = rawQueryString.length > 0 ? `?${rawQueryString}` : "";
|
|
224
|
+
const url = new URL(event.path + search, `${scheme}://${host}`);
|
|
225
|
+
const isFormData = headers["content-type"]?.includes("multipart/form-data");
|
|
226
|
+
const controller = new AbortController();
|
|
227
|
+
return new Request(url.href, {
|
|
228
|
+
method: event.httpMethod,
|
|
229
|
+
headers: createReactRouterHeadersALB(headers),
|
|
230
|
+
signal: controller.signal,
|
|
231
|
+
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body || void 0
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function createReactRouterHeadersALB(requestHeaders) {
|
|
235
|
+
const headers = new Headers();
|
|
236
|
+
for (const [header, value] of Object.entries(requestHeaders)) {
|
|
237
|
+
if (value) {
|
|
238
|
+
headers.append(header, value);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return headers;
|
|
242
|
+
}
|
|
243
|
+
async function sendReactRouterResponseALB(nodeResponse) {
|
|
244
|
+
const contentType = nodeResponse.headers.get("Content-Type");
|
|
245
|
+
const isBase64Encoded = isBinaryType(contentType);
|
|
246
|
+
let body;
|
|
247
|
+
if (nodeResponse.body) {
|
|
248
|
+
if (isBase64Encoded) {
|
|
249
|
+
body = await (0, import_node3.readableStreamToString)(nodeResponse.body, "base64");
|
|
250
|
+
} else {
|
|
251
|
+
body = await nodeResponse.text();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
statusCode: nodeResponse.status,
|
|
256
|
+
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
257
|
+
body: body || "",
|
|
258
|
+
isBase64Encoded
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
var applicationLoadBalancerAdapter = {
|
|
262
|
+
createReactRouterRequest: createReactRouterRequestALB,
|
|
263
|
+
sendReactRouterResponse: sendReactRouterResponseALB
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// src/adapters/index.ts
|
|
267
|
+
var createReactRouterAdapter = (awsProxy) => {
|
|
268
|
+
switch (awsProxy) {
|
|
269
|
+
case "APIGatewayV1" /* APIGatewayV1 */:
|
|
270
|
+
return apiGatewayV1Adapter;
|
|
271
|
+
case "APIGatewayV2" /* APIGatewayV2 */:
|
|
272
|
+
case "FunctionURL" /* FunctionURL */:
|
|
273
|
+
return apiGatewayV2Adapter;
|
|
274
|
+
case "ALB" /* ALB */:
|
|
275
|
+
return applicationLoadBalancerAdapter;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// src/server.ts
|
|
280
|
+
var AWSProxy = /* @__PURE__ */ ((AWSProxy2) => {
|
|
281
|
+
AWSProxy2["APIGatewayV1"] = "APIGatewayV1";
|
|
282
|
+
AWSProxy2["APIGatewayV2"] = "APIGatewayV2";
|
|
283
|
+
AWSProxy2["ALB"] = "ALB";
|
|
284
|
+
AWSProxy2["FunctionURL"] = "FunctionURL";
|
|
285
|
+
return AWSProxy2;
|
|
286
|
+
})(AWSProxy || {});
|
|
287
|
+
function createRequestHandler({
|
|
288
|
+
build,
|
|
289
|
+
getLoadContext,
|
|
290
|
+
mode = process.env.NODE_ENV,
|
|
291
|
+
awsProxy = "APIGatewayV2" /* APIGatewayV2 */
|
|
292
|
+
}) {
|
|
293
|
+
const handleRequest = (0, import_react_router.createRequestHandler)(build, mode);
|
|
294
|
+
return async (event) => {
|
|
295
|
+
const awsAdapter = createReactRouterAdapter(awsProxy);
|
|
296
|
+
let request;
|
|
297
|
+
try {
|
|
298
|
+
request = awsAdapter.createReactRouterRequest(event);
|
|
299
|
+
} catch (e) {
|
|
300
|
+
return awsAdapter.sendReactRouterResponse(
|
|
301
|
+
new Response(`Bad Request: ${e instanceof Error ? e.message : e}`, { status: 400 })
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
const loadContext = await getLoadContext?.(event);
|
|
305
|
+
const response = await handleRequest(request, loadContext);
|
|
306
|
+
return awsAdapter.sendReactRouterResponse(response);
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
310
|
+
0 && (module.exports = {
|
|
311
|
+
AWSProxy,
|
|
312
|
+
createRequestHandler
|
|
313
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @geostrategists/react-router-aws v2.0.0
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Geostrategists Consulting GmbH
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// src/server.ts
|
|
13
|
+
import { createRequestHandler as createReactRouterRequestHandler } from "react-router";
|
|
14
|
+
|
|
15
|
+
// src/adapters/api-gateway-v1.ts
|
|
16
|
+
import { readableStreamToString } from "@react-router/node";
|
|
17
|
+
import { URLSearchParams } from "url";
|
|
18
|
+
|
|
19
|
+
// src/binaryTypes.ts
|
|
20
|
+
var binaryTypes = [
|
|
21
|
+
"application/octet-stream",
|
|
22
|
+
// Docs
|
|
23
|
+
"application/epub+zip",
|
|
24
|
+
"application/msword",
|
|
25
|
+
"application/pdf",
|
|
26
|
+
"application/rtf",
|
|
27
|
+
"application/vnd.amazon.ebook",
|
|
28
|
+
"application/vnd.ms-excel",
|
|
29
|
+
"application/vnd.ms-powerpoint",
|
|
30
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
31
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
32
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
33
|
+
// Fonts
|
|
34
|
+
"font/otf",
|
|
35
|
+
"font/woff",
|
|
36
|
+
"font/woff2",
|
|
37
|
+
// Images
|
|
38
|
+
"image/avif",
|
|
39
|
+
"image/bmp",
|
|
40
|
+
"image/gif",
|
|
41
|
+
"image/jpeg",
|
|
42
|
+
"image/png",
|
|
43
|
+
"image/tiff",
|
|
44
|
+
"image/vnd.microsoft.icon",
|
|
45
|
+
"image/webp",
|
|
46
|
+
// Audio
|
|
47
|
+
"audio/3gpp",
|
|
48
|
+
"audio/aac",
|
|
49
|
+
"audio/basic",
|
|
50
|
+
"audio/mpeg",
|
|
51
|
+
"audio/ogg",
|
|
52
|
+
"audio/wav",
|
|
53
|
+
"audio/webm",
|
|
54
|
+
"audio/x-aiff",
|
|
55
|
+
"audio/x-midi",
|
|
56
|
+
"audio/x-wav",
|
|
57
|
+
// Video
|
|
58
|
+
"video/3gpp",
|
|
59
|
+
"video/mp2t",
|
|
60
|
+
"video/mpeg",
|
|
61
|
+
"video/ogg",
|
|
62
|
+
"video/quicktime",
|
|
63
|
+
"video/webm",
|
|
64
|
+
"video/x-msvideo",
|
|
65
|
+
// Archives
|
|
66
|
+
"application/java-archive",
|
|
67
|
+
"application/vnd.apple.installer+xml",
|
|
68
|
+
"application/x-7z-compressed",
|
|
69
|
+
"application/x-apple-diskimage",
|
|
70
|
+
"application/x-bzip",
|
|
71
|
+
"application/x-bzip2",
|
|
72
|
+
"application/x-gzip",
|
|
73
|
+
"application/x-java-archive",
|
|
74
|
+
"application/x-rar-compressed",
|
|
75
|
+
"application/x-tar",
|
|
76
|
+
"application/x-zip",
|
|
77
|
+
"application/zip"
|
|
78
|
+
];
|
|
79
|
+
function isBinaryType(contentType) {
|
|
80
|
+
if (!contentType) return false;
|
|
81
|
+
const [test] = contentType.split(";");
|
|
82
|
+
return binaryTypes.includes(test);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/adapters/api-gateway-v1.ts
|
|
86
|
+
function createReactRouterRequestAPIGatewayV1(event) {
|
|
87
|
+
const host = event.headers["x-forwarded-host"] || event.headers.Host;
|
|
88
|
+
const scheme = event.headers["x-forwarded-proto"] || "http";
|
|
89
|
+
const rawQueryString = new URLSearchParams(event.queryStringParameters).toString();
|
|
90
|
+
const search = rawQueryString.length > 0 ? `?${rawQueryString}` : "";
|
|
91
|
+
const url = new URL(event.path + search, `${scheme}://${host}`);
|
|
92
|
+
const isFormData = event.headers["content-type"]?.includes("multipart/form-data");
|
|
93
|
+
const controller = new AbortController();
|
|
94
|
+
return new Request(url.href, {
|
|
95
|
+
method: event.requestContext.httpMethod,
|
|
96
|
+
headers: createReactRouterHeadersAPIGatewayV1(event.headers),
|
|
97
|
+
signal: controller.signal,
|
|
98
|
+
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body || void 0
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function createReactRouterHeadersAPIGatewayV1(requestHeaders) {
|
|
102
|
+
const headers = new Headers();
|
|
103
|
+
for (const [header, value] of Object.entries(requestHeaders)) {
|
|
104
|
+
if (value) {
|
|
105
|
+
headers.append(header, value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return headers;
|
|
109
|
+
}
|
|
110
|
+
async function sendReactRouterResponseAPIGatewayV1(nodeResponse) {
|
|
111
|
+
const contentType = nodeResponse.headers.get("Content-Type");
|
|
112
|
+
const isBase64Encoded = isBinaryType(contentType);
|
|
113
|
+
let body;
|
|
114
|
+
if (nodeResponse.body) {
|
|
115
|
+
if (isBase64Encoded) {
|
|
116
|
+
body = await readableStreamToString(nodeResponse.body, "base64");
|
|
117
|
+
} else {
|
|
118
|
+
body = await nodeResponse.text();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
statusCode: nodeResponse.status,
|
|
123
|
+
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
124
|
+
body: body || "",
|
|
125
|
+
isBase64Encoded
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
var apiGatewayV1Adapter = {
|
|
129
|
+
createReactRouterRequest: createReactRouterRequestAPIGatewayV1,
|
|
130
|
+
sendReactRouterResponse: sendReactRouterResponseAPIGatewayV1
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// src/adapters/api-gateway-v2.ts
|
|
134
|
+
import { readableStreamToString as readableStreamToString2 } from "@react-router/node";
|
|
135
|
+
function createReactRouterRequestAPIGateywayV2(event) {
|
|
136
|
+
const host = event.headers["x-forwarded-host"] || event.headers.host;
|
|
137
|
+
const search = event.rawQueryString.length ? `?${event.rawQueryString}` : "";
|
|
138
|
+
const scheme = event.headers["x-forwarded-proto"] || "http";
|
|
139
|
+
const url = new URL(event.rawPath + search, `${scheme}://${host}`);
|
|
140
|
+
const isFormData = event.headers["content-type"]?.includes("multipart/form-data");
|
|
141
|
+
const controller = new AbortController();
|
|
142
|
+
return new Request(url.href, {
|
|
143
|
+
method: event.requestContext.http.method,
|
|
144
|
+
headers: createReactRouterHeadersAPIGatewayV2(event.headers, event.cookies),
|
|
145
|
+
signal: controller.signal,
|
|
146
|
+
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function createReactRouterHeadersAPIGatewayV2(requestHeaders, requestCookies) {
|
|
150
|
+
const headers = new Headers();
|
|
151
|
+
for (const [header, value] of Object.entries(requestHeaders)) {
|
|
152
|
+
if (value) {
|
|
153
|
+
headers.append(header, value);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (requestCookies) {
|
|
157
|
+
headers.append("Cookie", requestCookies.join("; "));
|
|
158
|
+
}
|
|
159
|
+
return headers;
|
|
160
|
+
}
|
|
161
|
+
async function sendReactRouterResponseAPIGatewayV2(nodeResponse) {
|
|
162
|
+
const cookies = nodeResponse.headers.getSetCookie();
|
|
163
|
+
if (cookies.length) {
|
|
164
|
+
nodeResponse.headers.delete("Set-Cookie");
|
|
165
|
+
}
|
|
166
|
+
const contentType = nodeResponse.headers.get("Content-Type");
|
|
167
|
+
const isBase64Encoded = isBinaryType(contentType);
|
|
168
|
+
let body;
|
|
169
|
+
if (nodeResponse.body) {
|
|
170
|
+
if (isBase64Encoded) {
|
|
171
|
+
body = await readableStreamToString2(nodeResponse.body, "base64");
|
|
172
|
+
} else {
|
|
173
|
+
body = await nodeResponse.text();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
statusCode: nodeResponse.status,
|
|
178
|
+
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
179
|
+
cookies,
|
|
180
|
+
body,
|
|
181
|
+
isBase64Encoded
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
var apiGatewayV2Adapter = {
|
|
185
|
+
createReactRouterRequest: createReactRouterRequestAPIGateywayV2,
|
|
186
|
+
sendReactRouterResponse: sendReactRouterResponseAPIGatewayV2
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// src/adapters/application-load-balancer.ts
|
|
190
|
+
import { readableStreamToString as readableStreamToString3 } from "@react-router/node";
|
|
191
|
+
import { URLSearchParams as URLSearchParams2 } from "url";
|
|
192
|
+
function createReactRouterRequestALB(event) {
|
|
193
|
+
const headers = event?.headers || {};
|
|
194
|
+
const host = headers["x-forwarded-host"] || headers.Host;
|
|
195
|
+
const scheme = headers["x-forwarded-proto"] || "http";
|
|
196
|
+
const rawQueryString = new URLSearchParams2(event.queryStringParameters).toString();
|
|
197
|
+
const search = rawQueryString.length > 0 ? `?${rawQueryString}` : "";
|
|
198
|
+
const url = new URL(event.path + search, `${scheme}://${host}`);
|
|
199
|
+
const isFormData = headers["content-type"]?.includes("multipart/form-data");
|
|
200
|
+
const controller = new AbortController();
|
|
201
|
+
return new Request(url.href, {
|
|
202
|
+
method: event.httpMethod,
|
|
203
|
+
headers: createReactRouterHeadersALB(headers),
|
|
204
|
+
signal: controller.signal,
|
|
205
|
+
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body || void 0
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function createReactRouterHeadersALB(requestHeaders) {
|
|
209
|
+
const headers = new Headers();
|
|
210
|
+
for (const [header, value] of Object.entries(requestHeaders)) {
|
|
211
|
+
if (value) {
|
|
212
|
+
headers.append(header, value);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return headers;
|
|
216
|
+
}
|
|
217
|
+
async function sendReactRouterResponseALB(nodeResponse) {
|
|
218
|
+
const contentType = nodeResponse.headers.get("Content-Type");
|
|
219
|
+
const isBase64Encoded = isBinaryType(contentType);
|
|
220
|
+
let body;
|
|
221
|
+
if (nodeResponse.body) {
|
|
222
|
+
if (isBase64Encoded) {
|
|
223
|
+
body = await readableStreamToString3(nodeResponse.body, "base64");
|
|
224
|
+
} else {
|
|
225
|
+
body = await nodeResponse.text();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
statusCode: nodeResponse.status,
|
|
230
|
+
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
231
|
+
body: body || "",
|
|
232
|
+
isBase64Encoded
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
var applicationLoadBalancerAdapter = {
|
|
236
|
+
createReactRouterRequest: createReactRouterRequestALB,
|
|
237
|
+
sendReactRouterResponse: sendReactRouterResponseALB
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/adapters/index.ts
|
|
241
|
+
var createReactRouterAdapter = (awsProxy) => {
|
|
242
|
+
switch (awsProxy) {
|
|
243
|
+
case "APIGatewayV1" /* APIGatewayV1 */:
|
|
244
|
+
return apiGatewayV1Adapter;
|
|
245
|
+
case "APIGatewayV2" /* APIGatewayV2 */:
|
|
246
|
+
case "FunctionURL" /* FunctionURL */:
|
|
247
|
+
return apiGatewayV2Adapter;
|
|
248
|
+
case "ALB" /* ALB */:
|
|
249
|
+
return applicationLoadBalancerAdapter;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// src/server.ts
|
|
254
|
+
var AWSProxy = /* @__PURE__ */ ((AWSProxy2) => {
|
|
255
|
+
AWSProxy2["APIGatewayV1"] = "APIGatewayV1";
|
|
256
|
+
AWSProxy2["APIGatewayV2"] = "APIGatewayV2";
|
|
257
|
+
AWSProxy2["ALB"] = "ALB";
|
|
258
|
+
AWSProxy2["FunctionURL"] = "FunctionURL";
|
|
259
|
+
return AWSProxy2;
|
|
260
|
+
})(AWSProxy || {});
|
|
261
|
+
function createRequestHandler({
|
|
262
|
+
build,
|
|
263
|
+
getLoadContext,
|
|
264
|
+
mode = process.env.NODE_ENV,
|
|
265
|
+
awsProxy = "APIGatewayV2" /* APIGatewayV2 */
|
|
266
|
+
}) {
|
|
267
|
+
const handleRequest = createReactRouterRequestHandler(build, mode);
|
|
268
|
+
return async (event) => {
|
|
269
|
+
const awsAdapter = createReactRouterAdapter(awsProxy);
|
|
270
|
+
let request;
|
|
271
|
+
try {
|
|
272
|
+
request = awsAdapter.createReactRouterRequest(event);
|
|
273
|
+
} catch (e) {
|
|
274
|
+
return awsAdapter.sendReactRouterResponse(
|
|
275
|
+
new Response(`Bad Request: ${e instanceof Error ? e.message : e}`, { status: 400 })
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
const loadContext = await getLoadContext?.(event);
|
|
279
|
+
const response = await handleRequest(request, loadContext);
|
|
280
|
+
return awsAdapter.sendReactRouterResponse(response);
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
export {
|
|
284
|
+
AWSProxy,
|
|
285
|
+
createRequestHandler
|
|
286
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@geostrategists/react-router-aws",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "AWS adapter for React Router v7",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/geostrategists/react-router-aws/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/geostrategists/react-router-aws.git"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"node": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"module-sync": "./dist/index.mjs",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/index.d.mts",
|
|
22
|
+
"default": "./dist/index.mjs"
|
|
23
|
+
},
|
|
24
|
+
"default": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"lint": "eslint .",
|
|
33
|
+
"format": "prettier --write .",
|
|
34
|
+
"format:check": "prettier --check .",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"build": "tsc && tsup",
|
|
37
|
+
"prepack": "yarn build && yarn npmignore --auto",
|
|
38
|
+
"prepare": "husky",
|
|
39
|
+
"release": "semantic-release"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@react-router/dev": "^7.3.0",
|
|
43
|
+
"@react-router/node": "^7.3.0",
|
|
44
|
+
"react-router": "^7.3.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@eslint/js": "^9.22.0",
|
|
48
|
+
"@react-router/dev": "^7.3.0",
|
|
49
|
+
"@react-router/node": "^7.3.0",
|
|
50
|
+
"@semantic-release/exec": "^7.0.3",
|
|
51
|
+
"@types/aws-lambda": "^8.10.125",
|
|
52
|
+
"@types/node": "^20",
|
|
53
|
+
"eslint": "^9.22.0",
|
|
54
|
+
"husky": "^9.1.7",
|
|
55
|
+
"lint-staged": "^15.5.0",
|
|
56
|
+
"npmignore": "^0.3.1",
|
|
57
|
+
"prettier": "3.5.3",
|
|
58
|
+
"react-router": "^7.3.0",
|
|
59
|
+
"semantic-release": "^24.2.3",
|
|
60
|
+
"tsup": "^8.4.0",
|
|
61
|
+
"typescript": "^5.8.2",
|
|
62
|
+
"typescript-eslint": "^8.26.1"
|
|
63
|
+
},
|
|
64
|
+
"packageManager": "yarn@4.7.0+sha256.293632d8a095d8ea4786eb2c5798c83c37544abed17ed31186a3ec4549a07c06",
|
|
65
|
+
"release": {
|
|
66
|
+
"plugins": [
|
|
67
|
+
"@semantic-release/commit-analyzer",
|
|
68
|
+
"@semantic-release/release-notes-generator",
|
|
69
|
+
[
|
|
70
|
+
"@semantic-release/exec",
|
|
71
|
+
{
|
|
72
|
+
"verifyConditionsCmd": "echo //npm.pkg.github.com/:_authToken=${process.env.GITHUB_TOKEN} > /tmp/github.npmrc && npm whoami --userconfig /tmp/github.npmrc --registry https://npm.pkg.github.com/",
|
|
73
|
+
"publishCmd": "npm publish --userconfig /tmp/github.npmrc --tag ${nextRelease.channel || 'latest'} --registry https://npm.pkg.github.com/ --no-git-tag-version",
|
|
74
|
+
"successCmd": "rm /tmp/github.npmrc",
|
|
75
|
+
"failCmd": "rm /tmp/github.npmrc"
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"@semantic-release/npm",
|
|
79
|
+
"@semantic-release/github"
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
"publishConfig": {
|
|
83
|
+
"ignore": [
|
|
84
|
+
"!dist/**",
|
|
85
|
+
"src/",
|
|
86
|
+
".*",
|
|
87
|
+
"tsconfig.json",
|
|
88
|
+
"tsup.config.ts"
|
|
89
|
+
],
|
|
90
|
+
"access": "public",
|
|
91
|
+
"provenance": true
|
|
92
|
+
},
|
|
93
|
+
"lint-staged": {
|
|
94
|
+
"*.{ts,tsx,js,cjs,mjs}": [
|
|
95
|
+
"eslint --fix",
|
|
96
|
+
"prettier --write"
|
|
97
|
+
],
|
|
98
|
+
"!(*.ts|*.tsx|*.js|*.cjs|*.mjs)": "prettier --ignore-unknown --write"
|
|
99
|
+
},
|
|
100
|
+
"prettier": {
|
|
101
|
+
"printWidth": 120,
|
|
102
|
+
"trailingComma": "all"
|
|
103
|
+
}
|
|
104
|
+
}
|