@react-router/architect 0.0.0-nightly-a5f191b5e-20240820

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.md ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) React Training LLC 2015-2019
4
+ Copyright (c) Remix Software Inc. 2020-2021
5
+ Copyright (c) Shopify Inc. 2022-2023
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # React Router Architect
2
+
3
+ Architect server request handler for React Router.
4
+
5
+ ```bash
6
+ npm install @react-router/architect
7
+ ```
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare function isBinaryType(contentType: string | null | undefined): boolean;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @react-router/architect v0.0.0-nightly-a5f191b5e-20240820
3
+ *
4
+ * Copyright (c) Remix Software Inc.
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
+
13
+ Object.defineProperty(exports, '__esModule', { value: true });
14
+
15
+ /**
16
+ * Common binary MIME types
17
+ * @see https://github.com/architect/functions/blob/45254fc1936a1794c185aac07e9889b241a2e5c6/src/http/helpers/binary-types.js
18
+ */
19
+ const binaryTypes = ["application/octet-stream",
20
+ // Docs
21
+ "application/epub+zip", "application/msword", "application/pdf", "application/rtf", "application/vnd.amazon.ebook", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
22
+ // Fonts
23
+ "font/otf", "font/woff", "font/woff2",
24
+ // Images
25
+ "image/avif", "image/bmp", "image/gif", "image/jpeg", "image/png", "image/tiff", "image/vnd.microsoft.icon", "image/webp",
26
+ // Audio
27
+ "audio/3gpp", "audio/aac", "audio/basic", "audio/mpeg", "audio/ogg", "audio/wav", "audio/webm", "audio/x-aiff", "audio/x-midi", "audio/x-wav",
28
+ // Video
29
+ "video/3gpp", "video/mp2t", "video/mpeg", "video/ogg", "video/quicktime", "video/webm", "video/x-msvideo",
30
+ // Archives
31
+ "application/java-archive", "application/vnd.apple.installer+xml", "application/x-7z-compressed", "application/x-apple-diskimage", "application/x-bzip", "application/x-bzip2", "application/x-gzip", "application/x-java-archive", "application/x-rar-compressed", "application/x-tar", "application/x-zip", "application/zip"];
32
+ function isBinaryType(contentType) {
33
+ if (!contentType) return false;
34
+ let [test] = contentType.split(";");
35
+ return binaryTypes.includes(test);
36
+ }
37
+
38
+ exports.isBinaryType = isBinaryType;
@@ -0,0 +1,3 @@
1
+ export { createArcTableSessionStorage } from "./sessions/arcTableSessionStorage";
2
+ export type { GetLoadContextFunction, RequestHandler } from "./server";
3
+ export { createRequestHandler } from "./server";
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @react-router/architect v0.0.0-nightly-a5f191b5e-20240820
3
+ *
4
+ * Copyright (c) Remix Software Inc.
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
+
13
+ Object.defineProperty(exports, '__esModule', { value: true });
14
+
15
+ var arcTableSessionStorage = require('./sessions/arcTableSessionStorage.js');
16
+ var server = require('./server.js');
17
+
18
+
19
+
20
+ exports.createArcTableSessionStorage = arcTableSessionStorage.createArcTableSessionStorage;
21
+ exports.createRequestHandler = server.createRequestHandler;
@@ -0,0 +1,23 @@
1
+ import type { AppLoadContext, ServerBuild } from "react-router";
2
+ import type { APIGatewayProxyEventHeaders, APIGatewayProxyEventV2, APIGatewayProxyHandlerV2, APIGatewayProxyStructuredResultV2 } from "aws-lambda";
3
+ /**
4
+ * A function that returns the value to use as `context` in route `loader` and
5
+ * `action` functions.
6
+ *
7
+ * You can think of this as an escape hatch that allows you to pass
8
+ * environment/platform-specific values through to your loader/action.
9
+ */
10
+ export type GetLoadContextFunction = (event: APIGatewayProxyEventV2) => Promise<AppLoadContext> | AppLoadContext;
11
+ export type RequestHandler = APIGatewayProxyHandlerV2;
12
+ /**
13
+ * Returns a request handler for Architect that serves the response using
14
+ * React Router.
15
+ */
16
+ export declare function createRequestHandler({ build, getLoadContext, mode, }: {
17
+ build: ServerBuild;
18
+ getLoadContext?: GetLoadContextFunction;
19
+ mode?: string;
20
+ }): RequestHandler;
21
+ export declare function createReactRouterRequest(event: APIGatewayProxyEventV2): Request;
22
+ export declare function createReactRouterHeaders(requestHeaders: APIGatewayProxyEventHeaders, requestCookies?: string[]): Headers;
23
+ export declare function sendReactRouterResponse(nodeResponse: Response): Promise<APIGatewayProxyStructuredResultV2>;
package/dist/server.js ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @react-router/architect v0.0.0-nightly-a5f191b5e-20240820
3
+ *
4
+ * Copyright (c) Remix Software Inc.
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
+
13
+ Object.defineProperty(exports, '__esModule', { value: true });
14
+
15
+ var reactRouter = require('react-router');
16
+ var node = require('@react-router/node');
17
+ var binaryTypes = require('./binaryTypes.js');
18
+
19
+ /**
20
+ * Returns a request handler for Architect that serves the response using
21
+ * React Router.
22
+ */
23
+ function createRequestHandler({
24
+ build,
25
+ getLoadContext,
26
+ mode = process.env.NODE_ENV
27
+ }) {
28
+ let handleRequest = reactRouter.createRequestHandler(build, mode);
29
+ return async event => {
30
+ let request = createReactRouterRequest(event);
31
+ let loadContext = await getLoadContext?.(event);
32
+ let response = await handleRequest(request, loadContext);
33
+ return sendReactRouterResponse(response);
34
+ };
35
+ }
36
+ function createReactRouterRequest(event) {
37
+ let host = event.headers["x-forwarded-host"] || event.headers.host;
38
+ let search = event.rawQueryString.length ? `?${event.rawQueryString}` : "";
39
+ let scheme = process.env.ARC_SANDBOX ? "http" : "https";
40
+ let url = new URL(`${scheme}://${host}${event.rawPath}${search}`);
41
+ let isFormData = event.headers["content-type"]?.includes("multipart/form-data");
42
+ // Note: No current way to abort these for Architect, but our router expects
43
+ // requests to contain a signal, so it can detect aborted requests
44
+ let controller = new AbortController();
45
+ return new Request(url.href, {
46
+ method: event.requestContext.http.method,
47
+ headers: createReactRouterHeaders(event.headers, event.cookies),
48
+ signal: controller.signal,
49
+ body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body
50
+ });
51
+ }
52
+ function createReactRouterHeaders(requestHeaders, requestCookies) {
53
+ let headers = new Headers();
54
+ for (let [header, value] of Object.entries(requestHeaders)) {
55
+ if (value) {
56
+ headers.append(header, value);
57
+ }
58
+ }
59
+ if (requestCookies) {
60
+ headers.append("Cookie", requestCookies.join("; "));
61
+ }
62
+ return headers;
63
+ }
64
+ async function sendReactRouterResponse(nodeResponse) {
65
+ let cookies = [];
66
+ // Arc/AWS API Gateway will send back set-cookies outside of response headers.
67
+ for (let [key, value] of nodeResponse.headers.entries()) {
68
+ if (key.toLowerCase() === "set-cookie") {
69
+ cookies.push(value);
70
+ }
71
+ }
72
+ if (cookies.length) {
73
+ nodeResponse.headers.delete("Set-Cookie");
74
+ }
75
+ let contentType = nodeResponse.headers.get("Content-Type");
76
+ let isBase64Encoded = binaryTypes.isBinaryType(contentType);
77
+ let body;
78
+ if (nodeResponse.body) {
79
+ if (isBase64Encoded) {
80
+ body = await node.readableStreamToString(nodeResponse.body, "base64");
81
+ } else {
82
+ body = await nodeResponse.text();
83
+ }
84
+ }
85
+ return {
86
+ statusCode: nodeResponse.status,
87
+ headers: Object.fromEntries(nodeResponse.headers.entries()),
88
+ cookies,
89
+ body,
90
+ isBase64Encoded
91
+ };
92
+ }
93
+
94
+ exports.createReactRouterHeaders = createReactRouterHeaders;
95
+ exports.createReactRouterRequest = createReactRouterRequest;
96
+ exports.createRequestHandler = createRequestHandler;
97
+ exports.sendReactRouterResponse = sendReactRouterResponse;
@@ -0,0 +1,36 @@
1
+ import type { SessionData, SessionStorage, SessionIdStorageStrategy } from "react-router";
2
+ import type { ArcTable } from "@architect/functions/types/tables";
3
+ interface ArcTableSessionStorageOptions {
4
+ /**
5
+ * The Cookie used to store the session id on the client, or options used
6
+ * to automatically create one.
7
+ */
8
+ cookie?: SessionIdStorageStrategy["cookie"];
9
+ /**
10
+ * The table used to store sessions, or its name as it appears in your
11
+ * project's app.arc file.
12
+ */
13
+ table: ArcTable<SessionData> | string;
14
+ /**
15
+ * The name of the DynamoDB attribute used to store the session ID.
16
+ * This should be the table's partition key.
17
+ */
18
+ idx: string;
19
+ /**
20
+ * The name of the DynamoDB attribute used to store the expiration time.
21
+ * If absent, then no TTL will be stored and session records will not expire.
22
+ */
23
+ ttl?: string;
24
+ }
25
+ /**
26
+ * Session storage using a DynamoDB table managed by Architect.
27
+ *
28
+ * Add the following lines to your project's `app.arc` file:
29
+ *
30
+ * @tables
31
+ * arc-sessions
32
+ * _idx *String
33
+ * _ttl TTL
34
+ */
35
+ export declare function createArcTableSessionStorage<Data = SessionData, FlashData = Data>({ cookie, ...props }: ArcTableSessionStorageOptions): SessionStorage<Data, FlashData>;
36
+ export {};
@@ -0,0 +1,102 @@
1
+ /**
2
+ * @react-router/architect v0.0.0-nightly-a5f191b5e-20240820
3
+ *
4
+ * Copyright (c) Remix Software Inc.
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
+
13
+ Object.defineProperty(exports, '__esModule', { value: true });
14
+
15
+ var reactRouter = require('react-router');
16
+ var arc = require('@architect/functions');
17
+
18
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
19
+
20
+ var arc__default = /*#__PURE__*/_interopDefaultLegacy(arc);
21
+
22
+ /**
23
+ * Session storage using a DynamoDB table managed by Architect.
24
+ *
25
+ * Add the following lines to your project's `app.arc` file:
26
+ *
27
+ * @tables
28
+ * arc-sessions
29
+ * _idx *String
30
+ * _ttl TTL
31
+ */
32
+ function createArcTableSessionStorage({
33
+ cookie,
34
+ ...props
35
+ }) {
36
+ async function getTable() {
37
+ if (typeof props.table === "string") {
38
+ let tables = await arc__default["default"].tables();
39
+ return tables[props.table];
40
+ } else {
41
+ return props.table;
42
+ }
43
+ }
44
+ return reactRouter.createSessionStorage({
45
+ cookie,
46
+ async createData(data, expires) {
47
+ let table = await getTable();
48
+ while (true) {
49
+ let randomBytes = crypto.getRandomValues(new Uint8Array(8));
50
+ // This storage manages an id space of 2^64 ids, which is far greater
51
+ // than the maximum number of files allowed on an NTFS or ext4 volume
52
+ // (2^32). However, the larger id space should help to avoid collisions
53
+ // with existing ids when creating new sessions, which speeds things up.
54
+ let id = [...randomBytes].map(x => x.toString(16).padStart(2, "0")).join("");
55
+ if (await table.get({
56
+ [props.idx]: id
57
+ })) {
58
+ continue;
59
+ }
60
+ let params = {
61
+ [props.idx]: id,
62
+ ...data
63
+ };
64
+ if (props.ttl) {
65
+ params[props.ttl] = expires ? Math.round(expires.getTime() / 1000) : undefined;
66
+ }
67
+ await table.put(params);
68
+ return id;
69
+ }
70
+ },
71
+ async readData(id) {
72
+ let table = await getTable();
73
+ let data = await table.get({
74
+ [props.idx]: id
75
+ });
76
+ if (data) {
77
+ delete data[props.idx];
78
+ if (props.ttl) delete data[props.ttl];
79
+ }
80
+ return data;
81
+ },
82
+ async updateData(id, data, expires) {
83
+ let table = await getTable();
84
+ let params = {
85
+ [props.idx]: id,
86
+ ...data
87
+ };
88
+ if (props.ttl) {
89
+ params[props.ttl] = expires ? Math.round(expires.getTime() / 1000) : undefined;
90
+ }
91
+ await table.put(params);
92
+ },
93
+ async deleteData(id) {
94
+ let table = await getTable();
95
+ await table.delete({
96
+ [props.idx]: id
97
+ });
98
+ }
99
+ });
100
+ }
101
+
102
+ exports.createArcTableSessionStorage = createArcTableSessionStorage;
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@react-router/architect",
3
+ "version": "0.0.0-nightly-a5f191b5e-20240820",
4
+ "description": "Architect server request handler for React Router",
5
+ "bugs": {
6
+ "url": "https://github.com/remix-run/react-router/issues"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/remix-run/react-router",
11
+ "directory": "packages/react-router-architect"
12
+ },
13
+ "license": "MIT",
14
+ "main": "dist/index.js",
15
+ "typings": "dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "dependencies": {
24
+ "@architect/functions": "^5.2.0",
25
+ "@types/aws-lambda": "^8.10.82"
26
+ },
27
+ "devDependencies": {
28
+ "@types/lambda-tester": "^3.6.1",
29
+ "@types/node": "^18.17.1",
30
+ "lambda-tester": "^4.0.1",
31
+ "react": "^18.2.0",
32
+ "react-dom": "^18.2.0",
33
+ "typescript": "^5.1.0",
34
+ "@react-router/node": "0.0.0-nightly-a5f191b5e-20240820",
35
+ "react-router": "0.0.0-nightly-a5f191b5e-20240820"
36
+ },
37
+ "peerDependencies": {
38
+ "typescript": "^5.1.0",
39
+ "@react-router/node": "^0.0.0-nightly-a5f191b5e-20240820",
40
+ "react-router": "^0.0.0-nightly-a5f191b5e-20240820"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "typescript": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "engines": {
48
+ "node": ">=18.0.0"
49
+ },
50
+ "files": [
51
+ "dist/",
52
+ "CHANGELOG.md",
53
+ "LICENSE.md",
54
+ "README.md"
55
+ ],
56
+ "scripts": {
57
+ "tsc": "tsc"
58
+ }
59
+ }