@geostrategists/react-router-aws 2.2.0 → 2.3.0-rc.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/README.md +67 -0
- package/dist/index.cjs +352 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +661 -0
- package/dist/index.d.mts +583 -24
- package/dist/index.mjs +302 -305
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -84
- package/biome.json +0 -47
- package/dist/index.d.ts +0 -102
- package/dist/index.js +0 -378
- package/test/alb.test.ts +0 -95
- package/test/apigw-v1.test.ts +0 -101
- package/test/apigw-v2.test.ts +0 -107
- package/test/function-url-streaming.test.ts +0 -107
- package/test/function-url.test.ts +0 -107
- package/test/lambda-stream/HttpResponseStream.ts +0 -34
- package/test/lambda-stream/ResponseStream.ts +0 -44
- package/test/lambda-stream/index.ts +0 -56
- package/test/setup.ts +0 -7
- package/test/utils.ts +0 -69
- package/vitest.config.ts +0 -12
package/dist/index.js
DELETED
|
@@ -1,378 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @geostrategists/react-router-aws v2.2.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
|
-
createALBRequestHandler: () => createALBRequestHandler,
|
|
35
|
-
createAPIGatewayV1RequestHandler: () => createAPIGatewayV1RequestHandler,
|
|
36
|
-
createAPIGatewayV2RequestHandler: () => createAPIGatewayV2RequestHandler,
|
|
37
|
-
createFunctionURLRequestHandler: () => createFunctionURLRequestHandler,
|
|
38
|
-
createFunctionURLStreamingRequestHandler: () => createFunctionURLStreamingRequestHandler,
|
|
39
|
-
createRequestHandler: () => createRequestHandler
|
|
40
|
-
});
|
|
41
|
-
module.exports = __toCommonJS(index_exports);
|
|
42
|
-
|
|
43
|
-
// src/server.ts
|
|
44
|
-
var import_react_router = require("react-router");
|
|
45
|
-
|
|
46
|
-
// src/adapters/api-gateway-v2.ts
|
|
47
|
-
var import_node = require("@react-router/node");
|
|
48
|
-
|
|
49
|
-
// src/binaryTypes.ts
|
|
50
|
-
var binaryTypes = [
|
|
51
|
-
"application/octet-stream",
|
|
52
|
-
// Docs
|
|
53
|
-
"application/epub+zip",
|
|
54
|
-
"application/msword",
|
|
55
|
-
"application/pdf",
|
|
56
|
-
"application/rtf",
|
|
57
|
-
"application/vnd.amazon.ebook",
|
|
58
|
-
"application/vnd.ms-excel",
|
|
59
|
-
"application/vnd.ms-powerpoint",
|
|
60
|
-
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
61
|
-
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
62
|
-
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
63
|
-
// Fonts
|
|
64
|
-
"font/otf",
|
|
65
|
-
"font/woff",
|
|
66
|
-
"font/woff2",
|
|
67
|
-
// Images
|
|
68
|
-
"image/avif",
|
|
69
|
-
"image/bmp",
|
|
70
|
-
"image/gif",
|
|
71
|
-
"image/jpeg",
|
|
72
|
-
"image/png",
|
|
73
|
-
"image/tiff",
|
|
74
|
-
"image/vnd.microsoft.icon",
|
|
75
|
-
"image/webp",
|
|
76
|
-
// Audio
|
|
77
|
-
"audio/3gpp",
|
|
78
|
-
"audio/aac",
|
|
79
|
-
"audio/basic",
|
|
80
|
-
"audio/mpeg",
|
|
81
|
-
"audio/ogg",
|
|
82
|
-
"audio/wav",
|
|
83
|
-
"audio/webm",
|
|
84
|
-
"audio/x-aiff",
|
|
85
|
-
"audio/x-midi",
|
|
86
|
-
"audio/x-wav",
|
|
87
|
-
// Video
|
|
88
|
-
"video/3gpp",
|
|
89
|
-
"video/mp2t",
|
|
90
|
-
"video/mpeg",
|
|
91
|
-
"video/ogg",
|
|
92
|
-
"video/quicktime",
|
|
93
|
-
"video/webm",
|
|
94
|
-
"video/x-msvideo",
|
|
95
|
-
// Archives
|
|
96
|
-
"application/java-archive",
|
|
97
|
-
"application/vnd.apple.installer+xml",
|
|
98
|
-
"application/x-7z-compressed",
|
|
99
|
-
"application/x-apple-diskimage",
|
|
100
|
-
"application/x-bzip",
|
|
101
|
-
"application/x-bzip2",
|
|
102
|
-
"application/x-gzip",
|
|
103
|
-
"application/x-java-archive",
|
|
104
|
-
"application/x-rar-compressed",
|
|
105
|
-
"application/x-tar",
|
|
106
|
-
"application/x-zip",
|
|
107
|
-
"application/zip"
|
|
108
|
-
];
|
|
109
|
-
function isBinaryType(contentType) {
|
|
110
|
-
if (!contentType) return false;
|
|
111
|
-
const [test] = contentType.split(";");
|
|
112
|
-
return binaryTypes.includes(test);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// src/adapters/api-gateway-v2.ts
|
|
116
|
-
function createReactRouterRequestAPIGateywayV2(event) {
|
|
117
|
-
const host = event.headers["x-forwarded-host"] || event.headers.host;
|
|
118
|
-
const search = event.rawQueryString.length ? `?${event.rawQueryString}` : "";
|
|
119
|
-
const scheme = event.headers["x-forwarded-proto"] || "http";
|
|
120
|
-
const url = new URL(event.rawPath + search, `${scheme}://${host}`);
|
|
121
|
-
const isFormData = event.headers["content-type"]?.includes("multipart/form-data");
|
|
122
|
-
const controller = new AbortController();
|
|
123
|
-
return new Request(url.href, {
|
|
124
|
-
method: event.requestContext.http.method,
|
|
125
|
-
headers: createReactRouterHeadersAPIGatewayV2(event.headers, event.cookies),
|
|
126
|
-
signal: controller.signal,
|
|
127
|
-
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
function createReactRouterHeadersAPIGatewayV2(requestHeaders, requestCookies) {
|
|
131
|
-
const headers = new Headers();
|
|
132
|
-
for (const [header, value] of Object.entries(requestHeaders)) {
|
|
133
|
-
if (value) {
|
|
134
|
-
headers.append(header, value);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
if (requestCookies) {
|
|
138
|
-
headers.append("Cookie", requestCookies.join("; "));
|
|
139
|
-
}
|
|
140
|
-
return headers;
|
|
141
|
-
}
|
|
142
|
-
function extractAPIGatewayV2ResponseMetadata(nodeResponse) {
|
|
143
|
-
const cookies = nodeResponse.headers.getSetCookie();
|
|
144
|
-
if (cookies.length) {
|
|
145
|
-
nodeResponse.headers.delete("Set-Cookie");
|
|
146
|
-
}
|
|
147
|
-
return {
|
|
148
|
-
statusCode: nodeResponse.status,
|
|
149
|
-
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
150
|
-
cookies
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
async function sendReactRouterResponseAPIGatewayV2(nodeResponse) {
|
|
154
|
-
const result = extractAPIGatewayV2ResponseMetadata(nodeResponse);
|
|
155
|
-
const contentType = nodeResponse.headers.get("Content-Type");
|
|
156
|
-
result.isBase64Encoded = isBinaryType(contentType);
|
|
157
|
-
if (nodeResponse.body) {
|
|
158
|
-
if (result.isBase64Encoded) {
|
|
159
|
-
result.body = await (0, import_node.readableStreamToString)(nodeResponse.body, "base64");
|
|
160
|
-
} else {
|
|
161
|
-
result.body = await nodeResponse.text();
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return result;
|
|
165
|
-
}
|
|
166
|
-
var apiGatewayV2Adapter = {
|
|
167
|
-
wrapHandler: (handler) => (e) => handler(e),
|
|
168
|
-
createReactRouterRequest: createReactRouterRequestAPIGateywayV2,
|
|
169
|
-
sendReactRouterResponse: sendReactRouterResponseAPIGatewayV2
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
// src/adapters/api-gateway-v1.ts
|
|
173
|
-
var import_node2 = require("@react-router/node");
|
|
174
|
-
var import_url = require("url");
|
|
175
|
-
function createReactRouterRequestAPIGatewayV1(event) {
|
|
176
|
-
const host = event.headers["x-forwarded-host"] || event.headers.Host;
|
|
177
|
-
const scheme = event.headers["x-forwarded-proto"] || "http";
|
|
178
|
-
const rawQueryString = new import_url.URLSearchParams(event.queryStringParameters).toString();
|
|
179
|
-
const search = rawQueryString.length > 0 ? `?${rawQueryString}` : "";
|
|
180
|
-
const url = new URL(event.path + search, `${scheme}://${host}`);
|
|
181
|
-
const isFormData = event.headers["content-type"]?.includes("multipart/form-data");
|
|
182
|
-
const controller = new AbortController();
|
|
183
|
-
return new Request(url.href, {
|
|
184
|
-
method: event.requestContext.httpMethod,
|
|
185
|
-
headers: createReactRouterHeadersAPIGatewayV1(event.headers),
|
|
186
|
-
signal: controller.signal,
|
|
187
|
-
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body || void 0
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
function createReactRouterHeadersAPIGatewayV1(requestHeaders) {
|
|
191
|
-
const headers = new Headers();
|
|
192
|
-
for (const [header, value] of Object.entries(requestHeaders)) {
|
|
193
|
-
if (value) {
|
|
194
|
-
headers.append(header, value);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return headers;
|
|
198
|
-
}
|
|
199
|
-
async function sendReactRouterResponseAPIGatewayV1(nodeResponse) {
|
|
200
|
-
const contentType = nodeResponse.headers.get("Content-Type");
|
|
201
|
-
const isBase64Encoded = isBinaryType(contentType);
|
|
202
|
-
let body;
|
|
203
|
-
if (nodeResponse.body) {
|
|
204
|
-
if (isBase64Encoded) {
|
|
205
|
-
body = await (0, import_node2.readableStreamToString)(nodeResponse.body, "base64");
|
|
206
|
-
} else {
|
|
207
|
-
body = await nodeResponse.text();
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return {
|
|
211
|
-
statusCode: nodeResponse.status,
|
|
212
|
-
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
213
|
-
body: body || "",
|
|
214
|
-
isBase64Encoded
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
var apiGatewayV1Adapter = {
|
|
218
|
-
wrapHandler: (handler) => (e) => handler(e),
|
|
219
|
-
createReactRouterRequest: createReactRouterRequestAPIGatewayV1,
|
|
220
|
-
sendReactRouterResponse: sendReactRouterResponseAPIGatewayV1
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
// src/adapters/application-load-balancer.ts
|
|
224
|
-
var import_node3 = require("@react-router/node");
|
|
225
|
-
var import_url2 = require("url");
|
|
226
|
-
function createReactRouterRequestALB(event) {
|
|
227
|
-
const headers = event?.headers || {};
|
|
228
|
-
const host = headers["x-forwarded-host"] || headers.Host;
|
|
229
|
-
const scheme = headers["x-forwarded-proto"] || "http";
|
|
230
|
-
const rawQueryString = new import_url2.URLSearchParams(event.queryStringParameters).toString();
|
|
231
|
-
const search = rawQueryString.length > 0 ? `?${rawQueryString}` : "";
|
|
232
|
-
const url = new URL(event.path + search, `${scheme}://${host}`);
|
|
233
|
-
const isFormData = headers["content-type"]?.includes("multipart/form-data");
|
|
234
|
-
const controller = new AbortController();
|
|
235
|
-
return new Request(url.href, {
|
|
236
|
-
method: event.httpMethod,
|
|
237
|
-
headers: createReactRouterHeadersALB(headers),
|
|
238
|
-
signal: controller.signal,
|
|
239
|
-
body: event.body && event.isBase64Encoded ? isFormData ? Buffer.from(event.body, "base64") : Buffer.from(event.body, "base64").toString() : event.body || void 0
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
function createReactRouterHeadersALB(requestHeaders) {
|
|
243
|
-
const headers = new Headers();
|
|
244
|
-
for (const [header, value] of Object.entries(requestHeaders)) {
|
|
245
|
-
if (value) {
|
|
246
|
-
headers.append(header, value);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return headers;
|
|
250
|
-
}
|
|
251
|
-
async function sendReactRouterResponseALB(nodeResponse) {
|
|
252
|
-
const contentType = nodeResponse.headers.get("Content-Type");
|
|
253
|
-
const isBase64Encoded = isBinaryType(contentType);
|
|
254
|
-
let body;
|
|
255
|
-
if (nodeResponse.body) {
|
|
256
|
-
if (isBase64Encoded) {
|
|
257
|
-
body = await (0, import_node3.readableStreamToString)(nodeResponse.body, "base64");
|
|
258
|
-
} else {
|
|
259
|
-
body = await nodeResponse.text();
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return {
|
|
263
|
-
statusCode: nodeResponse.status,
|
|
264
|
-
headers: Object.fromEntries(nodeResponse.headers.entries()),
|
|
265
|
-
body: body || "",
|
|
266
|
-
isBase64Encoded
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
var applicationLoadBalancerAdapter = {
|
|
270
|
-
wrapHandler: (handler) => (e) => handler(e),
|
|
271
|
-
createReactRouterRequest: createReactRouterRequestALB,
|
|
272
|
-
sendReactRouterResponse: sendReactRouterResponseALB
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
// src/adapters/function-url-streaming.ts
|
|
276
|
-
var import_node4 = require("@react-router/node");
|
|
277
|
-
var emptyStream = () => new ReadableStream({
|
|
278
|
-
start(controller) {
|
|
279
|
-
controller.enqueue("");
|
|
280
|
-
controller.close();
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
var sendReactRouterResponseFunctionUrlStreaming = async (response, responseStream) => {
|
|
284
|
-
const metadata = extractAPIGatewayV2ResponseMetadata(response);
|
|
285
|
-
let body = response.body;
|
|
286
|
-
if (!body) {
|
|
287
|
-
body = emptyStream();
|
|
288
|
-
}
|
|
289
|
-
const httpResponseStream = awslambda.HttpResponseStream.from(responseStream, metadata);
|
|
290
|
-
await (0, import_node4.writeReadableStreamToWritable)(body, httpResponseStream);
|
|
291
|
-
};
|
|
292
|
-
var functionUrlStreamingAdapter = {
|
|
293
|
-
wrapHandler: awslambda.streamifyResponse,
|
|
294
|
-
createReactRouterRequest: createReactRouterRequestAPIGateywayV2,
|
|
295
|
-
sendReactRouterResponse: sendReactRouterResponseFunctionUrlStreaming
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
// src/server.ts
|
|
299
|
-
function createAPIGatewayV1RequestHandler(options) {
|
|
300
|
-
return createRequestHandlerForAdapter(apiGatewayV1Adapter, options);
|
|
301
|
-
}
|
|
302
|
-
function createAPIGatewayV2RequestHandler(options) {
|
|
303
|
-
return createRequestHandlerForAdapter(apiGatewayV2Adapter, options);
|
|
304
|
-
}
|
|
305
|
-
function createALBRequestHandler(options) {
|
|
306
|
-
return createRequestHandlerForAdapter(applicationLoadBalancerAdapter, options);
|
|
307
|
-
}
|
|
308
|
-
function createFunctionURLRequestHandler(options) {
|
|
309
|
-
return createRequestHandlerForAdapter(apiGatewayV2Adapter, options);
|
|
310
|
-
}
|
|
311
|
-
function createFunctionURLStreamingRequestHandler(options) {
|
|
312
|
-
return createRequestHandlerForAdapter(functionUrlStreamingAdapter, options);
|
|
313
|
-
}
|
|
314
|
-
function createRequestHandlerForAdapter(awsAdapter, { build, getLoadContext, mode = process.env.NODE_ENV }) {
|
|
315
|
-
const handleRequest = (0, import_react_router.createRequestHandler)(build, mode);
|
|
316
|
-
return awsAdapter.wrapHandler(async (event, res) => {
|
|
317
|
-
let request;
|
|
318
|
-
try {
|
|
319
|
-
request = awsAdapter.createReactRouterRequest(event);
|
|
320
|
-
} catch (e) {
|
|
321
|
-
return await awsAdapter.sendReactRouterResponse(
|
|
322
|
-
new Response(`Bad Request: ${e instanceof Error ? e.message : e}`, { status: 400 }),
|
|
323
|
-
res
|
|
324
|
-
);
|
|
325
|
-
}
|
|
326
|
-
const loadContext = await getLoadContext?.(event);
|
|
327
|
-
const response = await handleRequest(request, loadContext);
|
|
328
|
-
return await awsAdapter.sendReactRouterResponse(response, res);
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// src/legacy.ts
|
|
333
|
-
var AWSProxy = /* @__PURE__ */ ((AWSProxy2) => {
|
|
334
|
-
AWSProxy2["APIGatewayV1"] = "APIGatewayV1";
|
|
335
|
-
AWSProxy2["APIGatewayV2"] = "APIGatewayV2";
|
|
336
|
-
AWSProxy2["ALB"] = "ALB";
|
|
337
|
-
AWSProxy2["FunctionURL"] = "FunctionURL";
|
|
338
|
-
AWSProxy2["FunctionURLStreaming"] = "FunctionURLStreaming";
|
|
339
|
-
return AWSProxy2;
|
|
340
|
-
})(AWSProxy || {});
|
|
341
|
-
function createRequestHandler(options) {
|
|
342
|
-
const { awsProxy = "APIGatewayV2" /* APIGatewayV2 */, ...opts } = options;
|
|
343
|
-
switch (awsProxy) {
|
|
344
|
-
case "APIGatewayV1" /* APIGatewayV1 */:
|
|
345
|
-
return createAPIGatewayV1RequestHandler(
|
|
346
|
-
opts
|
|
347
|
-
);
|
|
348
|
-
case "APIGatewayV2" /* APIGatewayV2 */:
|
|
349
|
-
return createAPIGatewayV2RequestHandler(
|
|
350
|
-
opts
|
|
351
|
-
);
|
|
352
|
-
case "ALB" /* ALB */:
|
|
353
|
-
return createALBRequestHandler(opts);
|
|
354
|
-
case "FunctionURL" /* FunctionURL */:
|
|
355
|
-
return createFunctionURLRequestHandler(
|
|
356
|
-
opts
|
|
357
|
-
);
|
|
358
|
-
case "FunctionURLStreaming" /* FunctionURLStreaming */:
|
|
359
|
-
return createFunctionURLStreamingRequestHandler(
|
|
360
|
-
opts
|
|
361
|
-
);
|
|
362
|
-
default:
|
|
363
|
-
return assertNever(awsProxy, `Unsupported buffered AWS Proxy type: ${awsProxy}`);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
function assertNever(_x, message) {
|
|
367
|
-
throw new Error(message);
|
|
368
|
-
}
|
|
369
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
370
|
-
0 && (module.exports = {
|
|
371
|
-
AWSProxy,
|
|
372
|
-
createALBRequestHandler,
|
|
373
|
-
createAPIGatewayV1RequestHandler,
|
|
374
|
-
createAPIGatewayV2RequestHandler,
|
|
375
|
-
createFunctionURLRequestHandler,
|
|
376
|
-
createFunctionURLStreamingRequestHandler,
|
|
377
|
-
createRequestHandler
|
|
378
|
-
});
|
package/test/alb.test.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { htmlResponse, redirectResponse, invokeHandlerWithRRMock } from "./utils";
|
|
3
|
-
import type { ALBEvent } from "aws-lambda";
|
|
4
|
-
|
|
5
|
-
function albEvent(path: string, method = "GET", headers: Record<string, string> = {}): ALBEvent {
|
|
6
|
-
return {
|
|
7
|
-
requestContext: {} as ALBEvent["requestContext"],
|
|
8
|
-
httpMethod: method,
|
|
9
|
-
path,
|
|
10
|
-
queryStringParameters: {},
|
|
11
|
-
headers: {
|
|
12
|
-
Host: "example.com",
|
|
13
|
-
"x-forwarded-proto": "https",
|
|
14
|
-
...headers,
|
|
15
|
-
},
|
|
16
|
-
body: null,
|
|
17
|
-
isBase64Encoded: false,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
describe("ALB request handling", () => {
|
|
22
|
-
it("parses ALB event", async () => {
|
|
23
|
-
await invokeHandlerWithRRMock(
|
|
24
|
-
"createALBRequestHandler",
|
|
25
|
-
async (request: Request) => {
|
|
26
|
-
expect(request.url).toBe("https://example.com/test");
|
|
27
|
-
expect(request.method).toBe("POST");
|
|
28
|
-
expect(request.headers.get("x-custom-header")).toBe("a");
|
|
29
|
-
return new Response("ok");
|
|
30
|
-
},
|
|
31
|
-
albEvent("/test", "POST", { "x-custom-header": "a" }),
|
|
32
|
-
);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe("ALB response handling", () => {
|
|
37
|
-
it("html without cookie", async () => {
|
|
38
|
-
const res = await invokeHandlerWithRRMock("createALBRequestHandler", () => htmlResponse(), albEvent("/html"));
|
|
39
|
-
|
|
40
|
-
expect(res).toStrictEqual({
|
|
41
|
-
statusCode: 200,
|
|
42
|
-
headers: {
|
|
43
|
-
"content-type": "text/html",
|
|
44
|
-
},
|
|
45
|
-
body: "<html>ok</html>",
|
|
46
|
-
isBase64Encoded: false,
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("html with cookie", async () => {
|
|
51
|
-
const res = await invokeHandlerWithRRMock(
|
|
52
|
-
"createALBRequestHandler",
|
|
53
|
-
() => htmlResponse("a=1; Path=/"),
|
|
54
|
-
albEvent("/html"),
|
|
55
|
-
);
|
|
56
|
-
expect(res).toStrictEqual({
|
|
57
|
-
statusCode: 200,
|
|
58
|
-
headers: {
|
|
59
|
-
"content-type": "text/html",
|
|
60
|
-
"set-cookie": "a=1; Path=/",
|
|
61
|
-
},
|
|
62
|
-
body: "<html>ok</html>",
|
|
63
|
-
isBase64Encoded: false,
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("redirect without cookie", async () => {
|
|
68
|
-
const res = await invokeHandlerWithRRMock("createALBRequestHandler", () => redirectResponse(), albEvent("/redir"));
|
|
69
|
-
expect(res).toStrictEqual({
|
|
70
|
-
statusCode: 302,
|
|
71
|
-
headers: {
|
|
72
|
-
location: "https://example.com/next",
|
|
73
|
-
},
|
|
74
|
-
body: "",
|
|
75
|
-
isBase64Encoded: false,
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it("redirect with cookie", async () => {
|
|
80
|
-
const res = await invokeHandlerWithRRMock(
|
|
81
|
-
"createALBRequestHandler",
|
|
82
|
-
() => redirectResponse("b=2; Path=/"),
|
|
83
|
-
albEvent("/redir"),
|
|
84
|
-
);
|
|
85
|
-
expect(res).toStrictEqual({
|
|
86
|
-
statusCode: 302,
|
|
87
|
-
headers: {
|
|
88
|
-
location: "https://example.com/next",
|
|
89
|
-
"set-cookie": "b=2; Path=/",
|
|
90
|
-
},
|
|
91
|
-
body: "",
|
|
92
|
-
isBase64Encoded: false,
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
});
|
package/test/apigw-v1.test.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { htmlResponse, redirectResponse, invokeHandlerWithRRMock } from "./utils";
|
|
3
|
-
import type { APIGatewayProxyEvent } from "aws-lambda";
|
|
4
|
-
|
|
5
|
-
function apiGatewayV1Event(path: string, method = "GET", headers: Record<string, string> = {}): APIGatewayProxyEvent {
|
|
6
|
-
return {
|
|
7
|
-
requestContext: { httpMethod: method } as APIGatewayProxyEvent["requestContext"],
|
|
8
|
-
path,
|
|
9
|
-
queryStringParameters: {},
|
|
10
|
-
headers: {
|
|
11
|
-
Host: "example.com",
|
|
12
|
-
"x-forwarded-proto": "https",
|
|
13
|
-
...headers,
|
|
14
|
-
},
|
|
15
|
-
body: null,
|
|
16
|
-
isBase64Encoded: false,
|
|
17
|
-
} as Partial<APIGatewayProxyEvent> as APIGatewayProxyEvent;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe("API Gateway v1 request handling", () => {
|
|
21
|
-
it("parses API Gateway v1 event", async () => {
|
|
22
|
-
await invokeHandlerWithRRMock(
|
|
23
|
-
"createAPIGatewayV1RequestHandler",
|
|
24
|
-
(request) => {
|
|
25
|
-
expect(request.url).toBe("https://example.com/test");
|
|
26
|
-
expect(request.method).toBe("POST");
|
|
27
|
-
expect(request.headers.get("x-custom-header")).toBe("a");
|
|
28
|
-
return new Response("ok");
|
|
29
|
-
},
|
|
30
|
-
apiGatewayV1Event("/test", "POST", { "x-custom-header": "a" }),
|
|
31
|
-
);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe("API Gateway v1 response handling", () => {
|
|
36
|
-
it("html without cookie", async () => {
|
|
37
|
-
const res = await invokeHandlerWithRRMock(
|
|
38
|
-
"createAPIGatewayV1RequestHandler",
|
|
39
|
-
() => htmlResponse(),
|
|
40
|
-
apiGatewayV1Event("/html"),
|
|
41
|
-
);
|
|
42
|
-
expect(res).toStrictEqual({
|
|
43
|
-
statusCode: 200,
|
|
44
|
-
headers: {
|
|
45
|
-
"content-type": "text/html",
|
|
46
|
-
},
|
|
47
|
-
body: "<html>ok</html>",
|
|
48
|
-
isBase64Encoded: false,
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("html with cookie", async () => {
|
|
53
|
-
const res = await invokeHandlerWithRRMock(
|
|
54
|
-
"createAPIGatewayV1RequestHandler",
|
|
55
|
-
() => htmlResponse("a=1; Path=/"),
|
|
56
|
-
apiGatewayV1Event("/html"),
|
|
57
|
-
);
|
|
58
|
-
expect(res).toStrictEqual({
|
|
59
|
-
statusCode: 200,
|
|
60
|
-
headers: {
|
|
61
|
-
"content-type": "text/html",
|
|
62
|
-
"set-cookie": "a=1; Path=/",
|
|
63
|
-
},
|
|
64
|
-
body: "<html>ok</html>",
|
|
65
|
-
isBase64Encoded: false,
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("redirect without cookie", async () => {
|
|
70
|
-
const res = await invokeHandlerWithRRMock(
|
|
71
|
-
"createAPIGatewayV1RequestHandler",
|
|
72
|
-
() => redirectResponse(),
|
|
73
|
-
apiGatewayV1Event("/redir"),
|
|
74
|
-
);
|
|
75
|
-
expect(res).toStrictEqual({
|
|
76
|
-
statusCode: 302,
|
|
77
|
-
headers: {
|
|
78
|
-
location: "https://example.com/next",
|
|
79
|
-
},
|
|
80
|
-
body: "",
|
|
81
|
-
isBase64Encoded: false,
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it("redirect with cookie", async () => {
|
|
86
|
-
const res = await invokeHandlerWithRRMock(
|
|
87
|
-
"createAPIGatewayV1RequestHandler",
|
|
88
|
-
() => redirectResponse("b=2; Path=/"),
|
|
89
|
-
apiGatewayV1Event("/redir"),
|
|
90
|
-
);
|
|
91
|
-
expect(res).toStrictEqual({
|
|
92
|
-
statusCode: 302,
|
|
93
|
-
headers: {
|
|
94
|
-
location: "https://example.com/next",
|
|
95
|
-
"set-cookie": "b=2; Path=/",
|
|
96
|
-
},
|
|
97
|
-
body: "",
|
|
98
|
-
isBase64Encoded: false,
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
});
|
package/test/apigw-v2.test.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { htmlResponse, invokeHandlerWithRRMock, redirectResponse } from "./utils";
|
|
3
|
-
import type { APIGatewayProxyEventV2 } from "aws-lambda";
|
|
4
|
-
|
|
5
|
-
function apiGatewayV2Event(
|
|
6
|
-
path: string,
|
|
7
|
-
method = "GET",
|
|
8
|
-
headers: Record<string, string> = {},
|
|
9
|
-
cookies?: string[],
|
|
10
|
-
): APIGatewayProxyEventV2 {
|
|
11
|
-
return {
|
|
12
|
-
requestContext: { http: { method } } as APIGatewayProxyEventV2["requestContext"],
|
|
13
|
-
rawPath: path,
|
|
14
|
-
rawQueryString: "",
|
|
15
|
-
headers: {
|
|
16
|
-
host: "example.com",
|
|
17
|
-
"x-forwarded-proto": "https",
|
|
18
|
-
...headers,
|
|
19
|
-
},
|
|
20
|
-
cookies,
|
|
21
|
-
body: undefined,
|
|
22
|
-
isBase64Encoded: false,
|
|
23
|
-
} as Partial<APIGatewayProxyEventV2> as APIGatewayProxyEventV2;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
describe("API Gateway v2 request handling", () => {
|
|
27
|
-
it("parses API Gateway v2 event", async () => {
|
|
28
|
-
await invokeHandlerWithRRMock(
|
|
29
|
-
"createAPIGatewayV2RequestHandler",
|
|
30
|
-
(request) => {
|
|
31
|
-
expect(request.url).toBe("https://example.com/test");
|
|
32
|
-
expect(request.method).toBe("POST");
|
|
33
|
-
expect(request.headers.get("x-custom-header")).toBe("a");
|
|
34
|
-
return new Response("ok");
|
|
35
|
-
},
|
|
36
|
-
apiGatewayV2Event("/test", "POST", { "x-custom-header": "a" }),
|
|
37
|
-
);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
describe("API Gateway v2 response handling", () => {
|
|
42
|
-
it("html without cookie", async () => {
|
|
43
|
-
const res = await invokeHandlerWithRRMock(
|
|
44
|
-
"createAPIGatewayV2RequestHandler",
|
|
45
|
-
() => htmlResponse(),
|
|
46
|
-
apiGatewayV2Event("/html"),
|
|
47
|
-
);
|
|
48
|
-
expect(res).toStrictEqual({
|
|
49
|
-
statusCode: 200,
|
|
50
|
-
headers: {
|
|
51
|
-
"content-type": "text/html",
|
|
52
|
-
},
|
|
53
|
-
body: "<html>ok</html>",
|
|
54
|
-
isBase64Encoded: false,
|
|
55
|
-
cookies: [],
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it("html with cookie", async () => {
|
|
60
|
-
const res = await invokeHandlerWithRRMock(
|
|
61
|
-
"createAPIGatewayV2RequestHandler",
|
|
62
|
-
() => htmlResponse("a=1; Path=/"),
|
|
63
|
-
apiGatewayV2Event("/html"),
|
|
64
|
-
);
|
|
65
|
-
expect(res).toStrictEqual({
|
|
66
|
-
statusCode: 200,
|
|
67
|
-
headers: {
|
|
68
|
-
"content-type": "text/html",
|
|
69
|
-
},
|
|
70
|
-
body: "<html>ok</html>",
|
|
71
|
-
isBase64Encoded: false,
|
|
72
|
-
cookies: ["a=1; Path=/"],
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it("redirect without cookie", async () => {
|
|
77
|
-
const res = await invokeHandlerWithRRMock(
|
|
78
|
-
"createAPIGatewayV2RequestHandler",
|
|
79
|
-
() => redirectResponse(),
|
|
80
|
-
apiGatewayV2Event("/redir"),
|
|
81
|
-
);
|
|
82
|
-
expect(res).toStrictEqual({
|
|
83
|
-
statusCode: 302,
|
|
84
|
-
headers: {
|
|
85
|
-
location: "https://example.com/next",
|
|
86
|
-
},
|
|
87
|
-
isBase64Encoded: false,
|
|
88
|
-
cookies: [],
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it("redirect with cookie", async () => {
|
|
93
|
-
const res = await invokeHandlerWithRRMock(
|
|
94
|
-
"createAPIGatewayV2RequestHandler",
|
|
95
|
-
() => redirectResponse("b=2; Path=/"),
|
|
96
|
-
apiGatewayV2Event("/redir"),
|
|
97
|
-
);
|
|
98
|
-
expect(res).toStrictEqual({
|
|
99
|
-
statusCode: 302,
|
|
100
|
-
headers: {
|
|
101
|
-
location: "https://example.com/next",
|
|
102
|
-
},
|
|
103
|
-
isBase64Encoded: false,
|
|
104
|
-
cookies: ["b=2; Path=/"],
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
});
|