@react-router/architect 7.16.0 → 8.0.0-pre.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/dist/index.d.ts +42 -32
- package/dist/index.js +161 -235
- package/package.json +21 -29
- package/dist/index.d.mts +0 -59
- package/dist/index.mjs +0 -218
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
import { SessionData, SessionIdStorageStrategy, SessionStorage, UNSAFE_MiddlewareEnabled, RouterContextProvider, AppLoadContext, ServerBuild } from 'react-router';
|
|
2
|
-
import { ArcTable } from '@architect/functions/types/tables';
|
|
3
|
-
import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from 'aws-lambda';
|
|
4
1
|
|
|
2
|
+
import { RouterContextProvider, ServerBuild, SessionData, SessionIdStorageStrategy, SessionStorage } from "react-router";
|
|
3
|
+
import { ArcTable } from "@architect/functions/types/tables";
|
|
4
|
+
import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from "aws-lambda";
|
|
5
|
+
|
|
6
|
+
//#region sessions/arcTableSessionStorage.d.ts
|
|
5
7
|
interface ArcTableSessionStorageOptions {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The Cookie used to store the session id on the client, or options used
|
|
10
|
+
* to automatically create one.
|
|
11
|
+
*/
|
|
12
|
+
cookie?: SessionIdStorageStrategy["cookie"];
|
|
13
|
+
/**
|
|
14
|
+
* The table used to store sessions, or its name as it appears in your
|
|
15
|
+
* project's app.arc file.
|
|
16
|
+
*/
|
|
17
|
+
table: ArcTable<SessionData> | string;
|
|
18
|
+
/**
|
|
19
|
+
* The name of the DynamoDB attribute used to store the session ID.
|
|
20
|
+
* This should be the table's partition key.
|
|
21
|
+
*/
|
|
22
|
+
idx: string;
|
|
23
|
+
/**
|
|
24
|
+
* The name of the DynamoDB attribute used to store the expiration time.
|
|
25
|
+
* If absent, then no TTL will be stored and session records will not expire.
|
|
26
|
+
*/
|
|
27
|
+
ttl?: string;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Session storage using a DynamoDB table managed by Architect.
|
|
@@ -34,8 +36,12 @@ interface ArcTableSessionStorageOptions {
|
|
|
34
36
|
* _idx *String
|
|
35
37
|
* _ttl TTL
|
|
36
38
|
*/
|
|
37
|
-
declare function createArcTableSessionStorage<Data = SessionData, FlashData = Data>({
|
|
38
|
-
|
|
39
|
+
declare function createArcTableSessionStorage<Data = SessionData, FlashData = Data>({
|
|
40
|
+
cookie,
|
|
41
|
+
...props
|
|
42
|
+
}: ArcTableSessionStorageOptions): SessionStorage<Data, FlashData>;
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region server.d.ts
|
|
39
45
|
type MaybePromise<T> = T | Promise<T>;
|
|
40
46
|
/**
|
|
41
47
|
* A function that returns the value to use as `context` in route `loader` and
|
|
@@ -44,16 +50,20 @@ type MaybePromise<T> = T | Promise<T>;
|
|
|
44
50
|
* You can think of this as an escape hatch that allows you to pass
|
|
45
51
|
* environment/platform-specific values through to your loader/action.
|
|
46
52
|
*/
|
|
47
|
-
type GetLoadContextFunction = (event: APIGatewayProxyEventV2) =>
|
|
53
|
+
type GetLoadContextFunction = (event: APIGatewayProxyEventV2) => MaybePromise<RouterContextProvider>;
|
|
48
54
|
type RequestHandler = APIGatewayProxyHandlerV2;
|
|
49
55
|
/**
|
|
50
56
|
* Returns a request handler for Architect that serves the response using
|
|
51
57
|
* React Router.
|
|
52
58
|
*/
|
|
53
|
-
declare function createRequestHandler({
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
declare function createRequestHandler({
|
|
60
|
+
build,
|
|
61
|
+
getLoadContext,
|
|
62
|
+
mode
|
|
63
|
+
}: {
|
|
64
|
+
build: ServerBuild;
|
|
65
|
+
getLoadContext?: GetLoadContextFunction;
|
|
66
|
+
mode?: string;
|
|
57
67
|
}): RequestHandler;
|
|
58
|
-
|
|
59
|
-
export { type GetLoadContextFunction, type RequestHandler, createArcTableSessionStorage, createRequestHandler };
|
|
68
|
+
//#endregion
|
|
69
|
+
export { type GetLoadContextFunction, type RequestHandler, createArcTableSessionStorage, createRequestHandler };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/architect
|
|
2
|
+
* @react-router/architect v8.0.0-pre.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,248 +8,174 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
while (true) {
|
|
68
|
-
let randomBytes = crypto.getRandomValues(new Uint8Array(8));
|
|
69
|
-
let id = [...randomBytes].map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
70
|
-
if (await table.get({ [props.idx]: id })) {
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
let params = {
|
|
74
|
-
[props.idx]: id,
|
|
75
|
-
...data
|
|
76
|
-
};
|
|
77
|
-
if (props.ttl) {
|
|
78
|
-
params[props.ttl] = expires ? Math.round(expires.getTime() / 1e3) : void 0;
|
|
79
|
-
}
|
|
80
|
-
await table.put(params);
|
|
81
|
-
return id;
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
async readData(id) {
|
|
85
|
-
let table = await getTable();
|
|
86
|
-
let data = await table.get({ [props.idx]: id });
|
|
87
|
-
if (data) {
|
|
88
|
-
delete data[props.idx];
|
|
89
|
-
if (props.ttl) delete data[props.ttl];
|
|
90
|
-
}
|
|
91
|
-
return data;
|
|
92
|
-
},
|
|
93
|
-
async updateData(id, data, expires) {
|
|
94
|
-
let table = await getTable();
|
|
95
|
-
let params = {
|
|
96
|
-
[props.idx]: id,
|
|
97
|
-
...data
|
|
98
|
-
};
|
|
99
|
-
if (props.ttl) {
|
|
100
|
-
params[props.ttl] = expires ? Math.round(expires.getTime() / 1e3) : void 0;
|
|
101
|
-
}
|
|
102
|
-
await table.put(params);
|
|
103
|
-
},
|
|
104
|
-
async deleteData(id) {
|
|
105
|
-
let table = await getTable();
|
|
106
|
-
await table.delete({ [props.idx]: id });
|
|
107
|
-
}
|
|
108
|
-
});
|
|
11
|
+
import { createRequestHandler as createRequestHandler$1, createSessionStorage } from "react-router";
|
|
12
|
+
import arc from "@architect/functions";
|
|
13
|
+
import { readableStreamToString } from "@react-router/node";
|
|
14
|
+
//#region sessions/arcTableSessionStorage.ts
|
|
15
|
+
/**
|
|
16
|
+
* Session storage using a DynamoDB table managed by Architect.
|
|
17
|
+
*
|
|
18
|
+
* Add the following lines to your project's `app.arc` file:
|
|
19
|
+
*
|
|
20
|
+
* @tables
|
|
21
|
+
* arc-sessions
|
|
22
|
+
* _idx *String
|
|
23
|
+
* _ttl TTL
|
|
24
|
+
*/
|
|
25
|
+
function createArcTableSessionStorage({ cookie, ...props }) {
|
|
26
|
+
async function getTable() {
|
|
27
|
+
if (typeof props.table === "string") return (await arc.tables())[props.table];
|
|
28
|
+
else return props.table;
|
|
29
|
+
}
|
|
30
|
+
return createSessionStorage({
|
|
31
|
+
cookie,
|
|
32
|
+
async createData(data, expires) {
|
|
33
|
+
let table = await getTable();
|
|
34
|
+
while (true) {
|
|
35
|
+
let id = [...crypto.getRandomValues(new Uint8Array(8))].map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
36
|
+
if (await table.get({ [props.idx]: id })) continue;
|
|
37
|
+
let params = {
|
|
38
|
+
[props.idx]: id,
|
|
39
|
+
...data
|
|
40
|
+
};
|
|
41
|
+
if (props.ttl) params[props.ttl] = expires ? Math.round(expires.getTime() / 1e3) : void 0;
|
|
42
|
+
await table.put(params);
|
|
43
|
+
return id;
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
async readData(id) {
|
|
47
|
+
let data = await (await getTable()).get({ [props.idx]: id });
|
|
48
|
+
if (data) {
|
|
49
|
+
delete data[props.idx];
|
|
50
|
+
if (props.ttl) delete data[props.ttl];
|
|
51
|
+
}
|
|
52
|
+
return data;
|
|
53
|
+
},
|
|
54
|
+
async updateData(id, data, expires) {
|
|
55
|
+
let table = await getTable();
|
|
56
|
+
let params = {
|
|
57
|
+
[props.idx]: id,
|
|
58
|
+
...data
|
|
59
|
+
};
|
|
60
|
+
if (props.ttl) params[props.ttl] = expires ? Math.round(expires.getTime() / 1e3) : void 0;
|
|
61
|
+
await table.put(params);
|
|
62
|
+
},
|
|
63
|
+
async deleteData(id) {
|
|
64
|
+
await (await getTable()).delete({ [props.idx]: id });
|
|
65
|
+
}
|
|
66
|
+
});
|
|
109
67
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
"application/x-gzip",
|
|
169
|
-
"application/x-java-archive",
|
|
170
|
-
"application/x-rar-compressed",
|
|
171
|
-
"application/x-tar",
|
|
172
|
-
"application/x-zip",
|
|
173
|
-
"application/zip"
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region binaryTypes.ts
|
|
70
|
+
/**
|
|
71
|
+
* Common binary MIME types
|
|
72
|
+
* @see https://github.com/architect/functions/blob/45254fc1936a1794c185aac07e9889b241a2e5c6/src/http/helpers/binary-types.js
|
|
73
|
+
*/
|
|
74
|
+
const binaryTypes = [
|
|
75
|
+
"application/octet-stream",
|
|
76
|
+
"application/epub+zip",
|
|
77
|
+
"application/msword",
|
|
78
|
+
"application/pdf",
|
|
79
|
+
"application/rtf",
|
|
80
|
+
"application/vnd.amazon.ebook",
|
|
81
|
+
"application/vnd.ms-excel",
|
|
82
|
+
"application/vnd.ms-powerpoint",
|
|
83
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
84
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
85
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
86
|
+
"font/otf",
|
|
87
|
+
"font/woff",
|
|
88
|
+
"font/woff2",
|
|
89
|
+
"image/avif",
|
|
90
|
+
"image/bmp",
|
|
91
|
+
"image/gif",
|
|
92
|
+
"image/jpeg",
|
|
93
|
+
"image/png",
|
|
94
|
+
"image/tiff",
|
|
95
|
+
"image/vnd.microsoft.icon",
|
|
96
|
+
"image/webp",
|
|
97
|
+
"audio/3gpp",
|
|
98
|
+
"audio/aac",
|
|
99
|
+
"audio/basic",
|
|
100
|
+
"audio/mpeg",
|
|
101
|
+
"audio/ogg",
|
|
102
|
+
"audio/wav",
|
|
103
|
+
"audio/webm",
|
|
104
|
+
"audio/x-aiff",
|
|
105
|
+
"audio/x-midi",
|
|
106
|
+
"audio/x-wav",
|
|
107
|
+
"video/3gpp",
|
|
108
|
+
"video/mp2t",
|
|
109
|
+
"video/mpeg",
|
|
110
|
+
"video/ogg",
|
|
111
|
+
"video/quicktime",
|
|
112
|
+
"video/webm",
|
|
113
|
+
"video/x-msvideo",
|
|
114
|
+
"application/java-archive",
|
|
115
|
+
"application/vnd.apple.installer+xml",
|
|
116
|
+
"application/x-7z-compressed",
|
|
117
|
+
"application/x-apple-diskimage",
|
|
118
|
+
"application/x-bzip",
|
|
119
|
+
"application/x-bzip2",
|
|
120
|
+
"application/x-gzip",
|
|
121
|
+
"application/x-java-archive",
|
|
122
|
+
"application/x-rar-compressed",
|
|
123
|
+
"application/x-tar",
|
|
124
|
+
"application/x-zip",
|
|
125
|
+
"application/zip"
|
|
174
126
|
];
|
|
175
127
|
function isBinaryType(contentType) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
128
|
+
if (!contentType) return false;
|
|
129
|
+
let [test] = contentType.split(";");
|
|
130
|
+
return binaryTypes.includes(test);
|
|
179
131
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
let response = await handleRequest(request, loadContext);
|
|
192
|
-
return sendReactRouterResponse(response);
|
|
193
|
-
};
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region server.ts
|
|
134
|
+
/**
|
|
135
|
+
* Returns a request handler for Architect that serves the response using
|
|
136
|
+
* React Router.
|
|
137
|
+
*/
|
|
138
|
+
function createRequestHandler({ build, getLoadContext, mode = process.env.NODE_ENV }) {
|
|
139
|
+
let handleRequest = createRequestHandler$1(build, mode);
|
|
140
|
+
return async (event) => {
|
|
141
|
+
return sendReactRouterResponse(await handleRequest(createReactRouterRequest(event), await getLoadContext?.(event)));
|
|
142
|
+
};
|
|
194
143
|
}
|
|
195
144
|
function createReactRouterRequest(event) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body
|
|
209
|
-
});
|
|
145
|
+
let host = event.headers["x-forwarded-host"] || event.headers.host;
|
|
146
|
+
let search = event.rawQueryString.length ? `?${event.rawQueryString}` : "";
|
|
147
|
+
let scheme = process.env.ARC_SANDBOX ? "http" : "https";
|
|
148
|
+
let url = new URL(`${scheme}://${host}${event.rawPath}${search}`);
|
|
149
|
+
let isFormData = event.headers["content-type"]?.includes("multipart/form-data");
|
|
150
|
+
let controller = new AbortController();
|
|
151
|
+
return new Request(url.href, {
|
|
152
|
+
method: event.requestContext.http.method,
|
|
153
|
+
headers: createReactRouterHeaders(event.headers, event.cookies),
|
|
154
|
+
signal: controller.signal,
|
|
155
|
+
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body
|
|
156
|
+
});
|
|
210
157
|
}
|
|
211
158
|
function createReactRouterHeaders(requestHeaders, requestCookies) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
if (requestCookies) {
|
|
219
|
-
headers.append("Cookie", requestCookies.join("; "));
|
|
220
|
-
}
|
|
221
|
-
return headers;
|
|
159
|
+
let headers = new Headers();
|
|
160
|
+
for (let [header, value] of Object.entries(requestHeaders)) if (value) headers.append(header, value);
|
|
161
|
+
if (requestCookies) headers.append("Cookie", requestCookies.join("; "));
|
|
162
|
+
return headers;
|
|
222
163
|
}
|
|
223
164
|
async function sendReactRouterResponse(nodeResponse) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
body = await (0, import_node.readableStreamToString)(nodeResponse.body, "base64");
|
|
239
|
-
} else {
|
|
240
|
-
body = await nodeResponse.text();
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return {
|
|
244
|
-
statusCode: nodeResponse.status,
|
|
245
|
-
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
246
|
-
cookies,
|
|
247
|
-
body,
|
|
248
|
-
isBase64Encoded
|
|
249
|
-
};
|
|
165
|
+
let cookies = [];
|
|
166
|
+
for (let [key, value] of nodeResponse.headers.entries()) if (key.toLowerCase() === "set-cookie") cookies.push(value);
|
|
167
|
+
if (cookies.length) nodeResponse.headers.delete("Set-Cookie");
|
|
168
|
+
let isBase64Encoded = isBinaryType(nodeResponse.headers.get("Content-Type"));
|
|
169
|
+
let body;
|
|
170
|
+
if (nodeResponse.body) if (isBase64Encoded) body = await readableStreamToString(nodeResponse.body, "base64");
|
|
171
|
+
else body = await nodeResponse.text();
|
|
172
|
+
return {
|
|
173
|
+
statusCode: nodeResponse.status,
|
|
174
|
+
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
175
|
+
cookies,
|
|
176
|
+
body,
|
|
177
|
+
isBase64Encoded
|
|
178
|
+
};
|
|
250
179
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
createArcTableSessionStorage,
|
|
254
|
-
createRequestHandler
|
|
255
|
-
});
|
|
180
|
+
//#endregion
|
|
181
|
+
export { createArcTableSessionStorage, createRequestHandler };
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-router/architect",
|
|
3
|
-
"
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "8.0.0-pre.0",
|
|
4
5
|
"description": "Architect server request handler for React Router",
|
|
5
6
|
"bugs": {
|
|
6
7
|
"url": "https://github.com/remix-run/react-router/issues"
|
|
@@ -15,25 +16,15 @@
|
|
|
15
16
|
"typings": "dist/index.d.ts",
|
|
16
17
|
"exports": {
|
|
17
18
|
".": {
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"default": "./dist/index.js"
|
|
22
|
-
},
|
|
23
|
-
"import": {
|
|
24
|
-
"types": "./dist/index.d.mts",
|
|
25
|
-
"default": "./dist/index.mjs"
|
|
26
|
-
},
|
|
27
|
-
"default": {
|
|
28
|
-
"types": "./dist/index.d.ts",
|
|
29
|
-
"default": "./dist/index.js"
|
|
30
|
-
}
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"module-sync": "./dist/index.js",
|
|
21
|
+
"default": "./dist/index.js"
|
|
31
22
|
},
|
|
32
23
|
"./package.json": "./package.json"
|
|
33
24
|
},
|
|
34
25
|
"wireit": {
|
|
35
26
|
"build": {
|
|
36
|
-
"command": "
|
|
27
|
+
"command": "tsdown",
|
|
37
28
|
"files": [
|
|
38
29
|
"../../pnpm-workspace.yaml",
|
|
39
30
|
"sessions/**",
|
|
@@ -47,25 +38,26 @@
|
|
|
47
38
|
}
|
|
48
39
|
},
|
|
49
40
|
"dependencies": {
|
|
50
|
-
"@architect/functions": "^
|
|
51
|
-
"@types/aws-lambda": "^8.10.
|
|
41
|
+
"@architect/functions": "^8.1.9",
|
|
42
|
+
"@types/aws-lambda": "^8.10.161"
|
|
52
43
|
},
|
|
53
44
|
"devDependencies": {
|
|
54
|
-
"@types/
|
|
55
|
-
"@types/
|
|
45
|
+
"@types/jest": "^30.0.0",
|
|
46
|
+
"@types/lambda-tester": "^4.0.3",
|
|
47
|
+
"@types/node": "^22.19.19",
|
|
56
48
|
"lambda-tester": "^4.0.1",
|
|
57
|
-
"react": "^19.2.
|
|
58
|
-
"react-dom": "^19.2.
|
|
59
|
-
"
|
|
60
|
-
"typescript": "^
|
|
61
|
-
"wireit": "0.14.
|
|
62
|
-
"@react-router/node": "
|
|
63
|
-
"react-router": "
|
|
49
|
+
"react": "^19.2.6",
|
|
50
|
+
"react-dom": "^19.2.6",
|
|
51
|
+
"tsdown": "^0.22.0",
|
|
52
|
+
"typescript": "^6.0.3",
|
|
53
|
+
"wireit": "0.14.12",
|
|
54
|
+
"@react-router/node": "8.0.0-pre.0",
|
|
55
|
+
"react-router": "8.0.0-pre.0"
|
|
64
56
|
},
|
|
65
57
|
"peerDependencies": {
|
|
66
58
|
"typescript": "^5.1.0 || ^6.0.0",
|
|
67
|
-
"@react-router/node": "^
|
|
68
|
-
"react-router": "^
|
|
59
|
+
"@react-router/node": "^8.0.0-pre.0",
|
|
60
|
+
"react-router": "^8.0.0-pre.0"
|
|
69
61
|
},
|
|
70
62
|
"peerDependenciesMeta": {
|
|
71
63
|
"typescript": {
|
|
@@ -73,7 +65,7 @@
|
|
|
73
65
|
}
|
|
74
66
|
},
|
|
75
67
|
"engines": {
|
|
76
|
-
"node": ">=
|
|
68
|
+
"node": ">=22.12.0"
|
|
77
69
|
},
|
|
78
70
|
"files": [
|
|
79
71
|
"dist/",
|
package/dist/index.d.mts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { SessionData, SessionIdStorageStrategy, SessionStorage, UNSAFE_MiddlewareEnabled, RouterContextProvider, AppLoadContext, ServerBuild } from 'react-router';
|
|
2
|
-
import { ArcTable } from '@architect/functions/types/tables';
|
|
3
|
-
import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from 'aws-lambda';
|
|
4
|
-
|
|
5
|
-
interface ArcTableSessionStorageOptions {
|
|
6
|
-
/**
|
|
7
|
-
* The Cookie used to store the session id on the client, or options used
|
|
8
|
-
* to automatically create one.
|
|
9
|
-
*/
|
|
10
|
-
cookie?: SessionIdStorageStrategy["cookie"];
|
|
11
|
-
/**
|
|
12
|
-
* The table used to store sessions, or its name as it appears in your
|
|
13
|
-
* project's app.arc file.
|
|
14
|
-
*/
|
|
15
|
-
table: ArcTable<SessionData> | string;
|
|
16
|
-
/**
|
|
17
|
-
* The name of the DynamoDB attribute used to store the session ID.
|
|
18
|
-
* This should be the table's partition key.
|
|
19
|
-
*/
|
|
20
|
-
idx: string;
|
|
21
|
-
/**
|
|
22
|
-
* The name of the DynamoDB attribute used to store the expiration time.
|
|
23
|
-
* If absent, then no TTL will be stored and session records will not expire.
|
|
24
|
-
*/
|
|
25
|
-
ttl?: string;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Session storage using a DynamoDB table managed by Architect.
|
|
29
|
-
*
|
|
30
|
-
* Add the following lines to your project's `app.arc` file:
|
|
31
|
-
*
|
|
32
|
-
* @tables
|
|
33
|
-
* arc-sessions
|
|
34
|
-
* _idx *String
|
|
35
|
-
* _ttl TTL
|
|
36
|
-
*/
|
|
37
|
-
declare function createArcTableSessionStorage<Data = SessionData, FlashData = Data>({ cookie, ...props }: ArcTableSessionStorageOptions): SessionStorage<Data, FlashData>;
|
|
38
|
-
|
|
39
|
-
type MaybePromise<T> = T | Promise<T>;
|
|
40
|
-
/**
|
|
41
|
-
* A function that returns the value to use as `context` in route `loader` and
|
|
42
|
-
* `action` functions.
|
|
43
|
-
*
|
|
44
|
-
* You can think of this as an escape hatch that allows you to pass
|
|
45
|
-
* environment/platform-specific values through to your loader/action.
|
|
46
|
-
*/
|
|
47
|
-
type GetLoadContextFunction = (event: APIGatewayProxyEventV2) => UNSAFE_MiddlewareEnabled extends true ? MaybePromise<RouterContextProvider> : MaybePromise<AppLoadContext>;
|
|
48
|
-
type RequestHandler = APIGatewayProxyHandlerV2;
|
|
49
|
-
/**
|
|
50
|
-
* Returns a request handler for Architect that serves the response using
|
|
51
|
-
* React Router.
|
|
52
|
-
*/
|
|
53
|
-
declare function createRequestHandler({ build, getLoadContext, mode, }: {
|
|
54
|
-
build: ServerBuild;
|
|
55
|
-
getLoadContext?: GetLoadContextFunction;
|
|
56
|
-
mode?: string;
|
|
57
|
-
}): RequestHandler;
|
|
58
|
-
|
|
59
|
-
export { type GetLoadContextFunction, type RequestHandler, createArcTableSessionStorage, createRequestHandler };
|
package/dist/index.mjs
DELETED
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @react-router/architect v7.16.0
|
|
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
|
-
|
|
12
|
-
// sessions/arcTableSessionStorage.ts
|
|
13
|
-
import { createSessionStorage } from "react-router";
|
|
14
|
-
import arc from "@architect/functions";
|
|
15
|
-
function createArcTableSessionStorage({
|
|
16
|
-
cookie,
|
|
17
|
-
...props
|
|
18
|
-
}) {
|
|
19
|
-
async function getTable() {
|
|
20
|
-
if (typeof props.table === "string") {
|
|
21
|
-
let tables = await arc.tables();
|
|
22
|
-
return tables[props.table];
|
|
23
|
-
} else {
|
|
24
|
-
return props.table;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return createSessionStorage({
|
|
28
|
-
cookie,
|
|
29
|
-
async createData(data, expires) {
|
|
30
|
-
let table = await getTable();
|
|
31
|
-
while (true) {
|
|
32
|
-
let randomBytes = crypto.getRandomValues(new Uint8Array(8));
|
|
33
|
-
let id = [...randomBytes].map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
34
|
-
if (await table.get({ [props.idx]: id })) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
let params = {
|
|
38
|
-
[props.idx]: id,
|
|
39
|
-
...data
|
|
40
|
-
};
|
|
41
|
-
if (props.ttl) {
|
|
42
|
-
params[props.ttl] = expires ? Math.round(expires.getTime() / 1e3) : void 0;
|
|
43
|
-
}
|
|
44
|
-
await table.put(params);
|
|
45
|
-
return id;
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
async readData(id) {
|
|
49
|
-
let table = await getTable();
|
|
50
|
-
let data = await table.get({ [props.idx]: id });
|
|
51
|
-
if (data) {
|
|
52
|
-
delete data[props.idx];
|
|
53
|
-
if (props.ttl) delete data[props.ttl];
|
|
54
|
-
}
|
|
55
|
-
return data;
|
|
56
|
-
},
|
|
57
|
-
async updateData(id, data, expires) {
|
|
58
|
-
let table = await getTable();
|
|
59
|
-
let params = {
|
|
60
|
-
[props.idx]: id,
|
|
61
|
-
...data
|
|
62
|
-
};
|
|
63
|
-
if (props.ttl) {
|
|
64
|
-
params[props.ttl] = expires ? Math.round(expires.getTime() / 1e3) : void 0;
|
|
65
|
-
}
|
|
66
|
-
await table.put(params);
|
|
67
|
-
},
|
|
68
|
-
async deleteData(id) {
|
|
69
|
-
let table = await getTable();
|
|
70
|
-
await table.delete({ [props.idx]: id });
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// server.ts
|
|
76
|
-
import { createRequestHandler as createReactRouterRequestHandler } from "react-router";
|
|
77
|
-
import { readableStreamToString } from "@react-router/node";
|
|
78
|
-
|
|
79
|
-
// binaryTypes.ts
|
|
80
|
-
var binaryTypes = [
|
|
81
|
-
"application/octet-stream",
|
|
82
|
-
// Docs
|
|
83
|
-
"application/epub+zip",
|
|
84
|
-
"application/msword",
|
|
85
|
-
"application/pdf",
|
|
86
|
-
"application/rtf",
|
|
87
|
-
"application/vnd.amazon.ebook",
|
|
88
|
-
"application/vnd.ms-excel",
|
|
89
|
-
"application/vnd.ms-powerpoint",
|
|
90
|
-
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
91
|
-
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
92
|
-
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
93
|
-
// Fonts
|
|
94
|
-
"font/otf",
|
|
95
|
-
"font/woff",
|
|
96
|
-
"font/woff2",
|
|
97
|
-
// Images
|
|
98
|
-
"image/avif",
|
|
99
|
-
"image/bmp",
|
|
100
|
-
"image/gif",
|
|
101
|
-
"image/jpeg",
|
|
102
|
-
"image/png",
|
|
103
|
-
"image/tiff",
|
|
104
|
-
"image/vnd.microsoft.icon",
|
|
105
|
-
"image/webp",
|
|
106
|
-
// Audio
|
|
107
|
-
"audio/3gpp",
|
|
108
|
-
"audio/aac",
|
|
109
|
-
"audio/basic",
|
|
110
|
-
"audio/mpeg",
|
|
111
|
-
"audio/ogg",
|
|
112
|
-
"audio/wav",
|
|
113
|
-
"audio/webm",
|
|
114
|
-
"audio/x-aiff",
|
|
115
|
-
"audio/x-midi",
|
|
116
|
-
"audio/x-wav",
|
|
117
|
-
// Video
|
|
118
|
-
"video/3gpp",
|
|
119
|
-
"video/mp2t",
|
|
120
|
-
"video/mpeg",
|
|
121
|
-
"video/ogg",
|
|
122
|
-
"video/quicktime",
|
|
123
|
-
"video/webm",
|
|
124
|
-
"video/x-msvideo",
|
|
125
|
-
// Archives
|
|
126
|
-
"application/java-archive",
|
|
127
|
-
"application/vnd.apple.installer+xml",
|
|
128
|
-
"application/x-7z-compressed",
|
|
129
|
-
"application/x-apple-diskimage",
|
|
130
|
-
"application/x-bzip",
|
|
131
|
-
"application/x-bzip2",
|
|
132
|
-
"application/x-gzip",
|
|
133
|
-
"application/x-java-archive",
|
|
134
|
-
"application/x-rar-compressed",
|
|
135
|
-
"application/x-tar",
|
|
136
|
-
"application/x-zip",
|
|
137
|
-
"application/zip"
|
|
138
|
-
];
|
|
139
|
-
function isBinaryType(contentType) {
|
|
140
|
-
if (!contentType) return false;
|
|
141
|
-
let [test] = contentType.split(";");
|
|
142
|
-
return binaryTypes.includes(test);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// server.ts
|
|
146
|
-
function createRequestHandler({
|
|
147
|
-
build,
|
|
148
|
-
getLoadContext,
|
|
149
|
-
mode = process.env.NODE_ENV
|
|
150
|
-
}) {
|
|
151
|
-
let handleRequest = createReactRouterRequestHandler(build, mode);
|
|
152
|
-
return async (event) => {
|
|
153
|
-
let request = createReactRouterRequest(event);
|
|
154
|
-
let loadContext = await getLoadContext?.(event);
|
|
155
|
-
let response = await handleRequest(request, loadContext);
|
|
156
|
-
return sendReactRouterResponse(response);
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
function createReactRouterRequest(event) {
|
|
160
|
-
let host = event.headers["x-forwarded-host"] || event.headers.host;
|
|
161
|
-
let search = event.rawQueryString.length ? `?${event.rawQueryString}` : "";
|
|
162
|
-
let scheme = process.env.ARC_SANDBOX ? "http" : "https";
|
|
163
|
-
let url = new URL(`${scheme}://${host}${event.rawPath}${search}`);
|
|
164
|
-
let isFormData = event.headers["content-type"]?.includes(
|
|
165
|
-
"multipart/form-data"
|
|
166
|
-
);
|
|
167
|
-
let controller = new AbortController();
|
|
168
|
-
return new Request(url.href, {
|
|
169
|
-
method: event.requestContext.http.method,
|
|
170
|
-
headers: createReactRouterHeaders(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 createReactRouterHeaders(requestHeaders, requestCookies) {
|
|
176
|
-
let headers = new Headers();
|
|
177
|
-
for (let [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 sendReactRouterResponse(nodeResponse) {
|
|
188
|
-
let cookies = [];
|
|
189
|
-
for (let [key, value] of nodeResponse.headers.entries()) {
|
|
190
|
-
if (key.toLowerCase() === "set-cookie") {
|
|
191
|
-
cookies.push(value);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
if (cookies.length) {
|
|
195
|
-
nodeResponse.headers.delete("Set-Cookie");
|
|
196
|
-
}
|
|
197
|
-
let contentType = nodeResponse.headers.get("Content-Type");
|
|
198
|
-
let isBase64Encoded = isBinaryType(contentType);
|
|
199
|
-
let body;
|
|
200
|
-
if (nodeResponse.body) {
|
|
201
|
-
if (isBase64Encoded) {
|
|
202
|
-
body = await readableStreamToString(nodeResponse.body, "base64");
|
|
203
|
-
} else {
|
|
204
|
-
body = await nodeResponse.text();
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return {
|
|
208
|
-
statusCode: nodeResponse.status,
|
|
209
|
-
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
210
|
-
cookies,
|
|
211
|
-
body,
|
|
212
|
-
isBase64Encoded
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
export {
|
|
216
|
-
createArcTableSessionStorage,
|
|
217
|
-
createRequestHandler
|
|
218
|
-
};
|