itty-lambda 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/build/cjs/ag.js +43 -0
- package/build/cjs/alb.js +43 -0
- package/build/cjs/common.js +219 -0
- package/build/cjs/index.js +32 -0
- package/build/cjs/url.js +43 -0
- package/build/esm/ag.js +43 -0
- package/build/esm/alb.js +43 -0
- package/build/esm/common.js +219 -0
- package/build/esm/index.js +32 -0
- package/build/esm/url.js +43 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Evan Kaufman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# `itty-lambda` - AWS Lambda support for [itty-router]
|
|
2
|
+
|
|
3
|
+
[
|
|
4
|
+

|
|
5
|
+
](https://github.com/EvanK/itty-lambda/actions/workflows/ci.yaml)
|
|
6
|
+
[
|
|
7
|
+

|
|
8
|
+
](https://nodejs.org/docs/latest-v20.x/api/)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
AWS Lambda functions can respond to HTTP requests via one of the following invocation types:
|
|
12
|
+
- [Function urls][lambda-function-urls]
|
|
13
|
+
- [API gateways][api-gateways]
|
|
14
|
+
- [Application load balancers][albs].
|
|
15
|
+
|
|
16
|
+
This library aims to maintain support for running [itty-router] in any such environment.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
// supports CJS -or- ESM
|
|
23
|
+
// const { url, ag, alb } = require('itty-lambda');
|
|
24
|
+
// import { url, ag, alb } from 'itty-lambda';
|
|
25
|
+
|
|
26
|
+
// for just API Gateway support, use 'itty-lambda/ag'
|
|
27
|
+
// for just Application Load Balancer support, use 'itty-lambda/alb'
|
|
28
|
+
// for just Lambda function url support, use 'itty-lambda/url'
|
|
29
|
+
|
|
30
|
+
import { AutoRouter } from 'itty-router';
|
|
31
|
+
|
|
32
|
+
// using an app load balancer...
|
|
33
|
+
import { eventToRequest, responseToResult } from 'itty-lambda/alb';
|
|
34
|
+
|
|
35
|
+
export async function handler (event) {
|
|
36
|
+
const router = AutoRouter();
|
|
37
|
+
router.get('/foo', () => ({ success: true }));
|
|
38
|
+
|
|
39
|
+
const request = await eventToRequest(event);
|
|
40
|
+
// { path: string, httpMethod: string, headers: object, ... }
|
|
41
|
+
// ->
|
|
42
|
+
// { url: string, method: string, headers: Headers, ... }
|
|
43
|
+
|
|
44
|
+
const response = await router.fetch(request);
|
|
45
|
+
|
|
46
|
+
const result = await responseToResult(response);
|
|
47
|
+
// { status: number, headers: Headers, body: ReadableStream, ... }
|
|
48
|
+
// ->
|
|
49
|
+
// { statusCode: number, body: string, headers: object, ... }
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Each implementation provides these two named exports, for you to plug in before and after routing...
|
|
56
|
+
|
|
57
|
+
For more information, see [the documentation](https://EvanK.github.io/itty-lambda/).
|
|
58
|
+
|
|
59
|
+
## eventToRequest
|
|
60
|
+
|
|
61
|
+
Accepts an AWS Lambda event for the invocation type, and resolves to a well formed `RequestLike`.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
eventToRequest(
|
|
65
|
+
event: APIGatewayProxyEvent | ALBEvent | LambdaFunctionURLEvent,
|
|
66
|
+
options: EventOptions | undefined
|
|
67
|
+
) : Promise<RequestLike>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### EventOptions
|
|
71
|
+
|
|
72
|
+
| Name | Type(s) | Default Value | Description |
|
|
73
|
+
| -- | -- | -- | -- |
|
|
74
|
+
| **defaultMethod** | `string` | `GET` | HTTP method if none provided from event |
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
## responseToResult
|
|
78
|
+
|
|
79
|
+
Accepts a router `Response`, and resolves to a result for the invocation type.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
responseToResult(
|
|
83
|
+
response: Response | undefined,
|
|
84
|
+
options : ResponseOptions | undefined
|
|
85
|
+
) : Promise<APIGatewayProxyResult | ALBResult | LambdaFunctionURLResult>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### ResponseOptions
|
|
89
|
+
|
|
90
|
+
| Name | Type(s) | Default Value | Description |
|
|
91
|
+
| -- | -- | -- | -- |
|
|
92
|
+
| **base64Encode** | `boolean` | `false` | Encode response body |
|
|
93
|
+
| **fallbackStatus** | `number` | `404` | Status if no response provided from router |
|
|
94
|
+
| **multiValueHeaders** | `boolean` | `false` | Split response headers with multiple values |
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
<!-- footnotes and urls -->
|
|
98
|
+
[itty-router]: https://itty.dev/itty-router/
|
|
99
|
+
[lambda-function-urls]: https://docs.aws.amazon.com/lambda/latest/dg/urls-invocation.html
|
|
100
|
+
[api-gateways]: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-integrations.html
|
|
101
|
+
[albs]: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html
|
package/build/cjs/ag.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* API gateway implemention
|
|
4
|
+
*
|
|
5
|
+
* @module ag
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { eventToRequest, responseToResult } from 'itty-lambda/ag';
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.eventToRequest = eventToRequest;
|
|
12
|
+
exports.responseToResult = responseToResult;
|
|
13
|
+
const common_1 = require("./common");
|
|
14
|
+
/**
|
|
15
|
+
* Accepts an event from an AWS Lambda function invocation by way of an
|
|
16
|
+
* API gateway proxy integration, and formats it into a request suitable
|
|
17
|
+
* for routing through itty-router.
|
|
18
|
+
*
|
|
19
|
+
* @param event
|
|
20
|
+
* @param options
|
|
21
|
+
*/
|
|
22
|
+
async function eventToRequest(event, options) {
|
|
23
|
+
return await (0, common_1.eventToRequest)(common_1.RoutingMode.Ag, event, options);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Accepts a response from itty-router (or undefined if no route was matched),
|
|
27
|
+
* and formats it into a result suitable to return to the Lambda service and
|
|
28
|
+
* subsequently to an API gateway proxy integration.
|
|
29
|
+
*
|
|
30
|
+
* If no response was provided, an error response is built with the given
|
|
31
|
+
* fallback HTTP status, defaulting to 404.
|
|
32
|
+
*
|
|
33
|
+
* @param response
|
|
34
|
+
* @param options
|
|
35
|
+
*/
|
|
36
|
+
async function responseToResult(response, options) {
|
|
37
|
+
return (await (0, common_1.responseToResult)(common_1.RoutingMode.Ag, response, options));
|
|
38
|
+
}
|
|
39
|
+
/** @ignore */
|
|
40
|
+
exports.default = {
|
|
41
|
+
eventToRequest,
|
|
42
|
+
responseToResult,
|
|
43
|
+
};
|
package/build/cjs/alb.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Application load balancer implemention
|
|
4
|
+
*
|
|
5
|
+
* @module alb
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { eventToRequest, responseToResult } from 'itty-lambda/alb';
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.eventToRequest = eventToRequest;
|
|
12
|
+
exports.responseToResult = responseToResult;
|
|
13
|
+
const common_1 = require("./common");
|
|
14
|
+
/**
|
|
15
|
+
* Accepts an event from an AWS Lambda function invocation by way of an
|
|
16
|
+
* application load balancer target, and formats it into a request
|
|
17
|
+
* suitable for routing through itty-router.
|
|
18
|
+
*
|
|
19
|
+
* @param event
|
|
20
|
+
* @param options
|
|
21
|
+
*/
|
|
22
|
+
async function eventToRequest(event, options) {
|
|
23
|
+
return await (0, common_1.eventToRequest)(common_1.RoutingMode.Alb, event, options);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Accepts a response from itty-router (or undefined if no route was matched),
|
|
27
|
+
* and formats it into a result suitable to return to the Lambda service and
|
|
28
|
+
* subsequently to an application load balancer.
|
|
29
|
+
*
|
|
30
|
+
* If no response was provided, an error response is built with the given
|
|
31
|
+
* fallback HTTP status, defaulting to 404.
|
|
32
|
+
*
|
|
33
|
+
* @param response
|
|
34
|
+
* @param options
|
|
35
|
+
*/
|
|
36
|
+
async function responseToResult(response, options) {
|
|
37
|
+
return (await (0, common_1.responseToResult)(common_1.RoutingMode.Alb, response, options));
|
|
38
|
+
}
|
|
39
|
+
/** @ignore */
|
|
40
|
+
exports.default = {
|
|
41
|
+
eventToRequest,
|
|
42
|
+
responseToResult,
|
|
43
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Common shared functionality between implementations.
|
|
4
|
+
*
|
|
5
|
+
* @module common
|
|
6
|
+
* @protected
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.RoutingMode = void 0;
|
|
10
|
+
exports.eventToRequest = eventToRequest;
|
|
11
|
+
exports.responseToResult = responseToResult;
|
|
12
|
+
const consumers_1 = require("node:stream/consumers");
|
|
13
|
+
const itty_router_1 = require("itty-router");
|
|
14
|
+
/** @ignore */
|
|
15
|
+
var RoutingMode;
|
|
16
|
+
(function (RoutingMode) {
|
|
17
|
+
RoutingMode["Ag"] = "api-gateway";
|
|
18
|
+
RoutingMode["Alb"] = "application-load-balancer";
|
|
19
|
+
RoutingMode["Url"] = "lambda-function-url";
|
|
20
|
+
})(RoutingMode || (exports.RoutingMode = RoutingMode = {}));
|
|
21
|
+
/** @ignore */
|
|
22
|
+
async function eventToRequest(mode, event, options) {
|
|
23
|
+
const output = { method: '', url: '' };
|
|
24
|
+
output.headers = objectsToHeaders(event?.headers,
|
|
25
|
+
// account for lambda function urls not supporting multi values
|
|
26
|
+
(mode != RoutingMode.Url ? event.multiValueHeaders : undefined));
|
|
27
|
+
// infer protocol from headers when available
|
|
28
|
+
const proto = output.headers.get('x-forwarded-proto')
|
|
29
|
+
?? output.headers.get('forwarded')?.match(/proto=(\w+)/)?.[1]
|
|
30
|
+
?? 'http';
|
|
31
|
+
// infer host when available
|
|
32
|
+
const host = (
|
|
33
|
+
// ag or url may have requestContext.domainName
|
|
34
|
+
(mode != RoutingMode.Alb ? event.requestContext?.domainName : undefined))
|
|
35
|
+
?? output.headers.get('host')
|
|
36
|
+
?? output.headers.get('x-forwarded-host')
|
|
37
|
+
?? output.headers.get('forwarded')?.match(/host=([^;]+)/)?.[1]
|
|
38
|
+
?? 'localhost.localdomain';
|
|
39
|
+
// infer path when available
|
|
40
|
+
const path = (
|
|
41
|
+
// ag or alb may have path
|
|
42
|
+
(mode != RoutingMode.Url ? event.path : undefined))
|
|
43
|
+
?? (
|
|
44
|
+
// url may have rawPath
|
|
45
|
+
(mode == RoutingMode.Url ? event.rawPath : undefined))
|
|
46
|
+
?? (
|
|
47
|
+
// ag may have requestContext.path
|
|
48
|
+
(mode == RoutingMode.Ag ? event.requestContext?.path : undefined))
|
|
49
|
+
?? (
|
|
50
|
+
// url may have requestContext.http.path
|
|
51
|
+
(mode == RoutingMode.Url ? event.requestContext?.http?.path : undefined))
|
|
52
|
+
?? '';
|
|
53
|
+
// infer querystring and convert to string as necessary
|
|
54
|
+
const queryString = (
|
|
55
|
+
// url may have rawQueryString
|
|
56
|
+
(mode == RoutingMode.Url ? event.rawQueryString : undefined))
|
|
57
|
+
?? objectsToQueryString(event?.queryStringParameters, (
|
|
58
|
+
// ag or alb may have multiValueQueryStringParameters
|
|
59
|
+
(mode != RoutingMode.Url ? event.multiValueQueryStringParameters : undefined)));
|
|
60
|
+
// assemble well-formed url from inferred values above
|
|
61
|
+
output.url = `${proto}://${host}${path}?${queryString}`;
|
|
62
|
+
// infer or default http method
|
|
63
|
+
output.method =
|
|
64
|
+
(
|
|
65
|
+
// ag or alb may have httpMethod
|
|
66
|
+
(mode != RoutingMode.Url ? event.httpMethod : undefined))
|
|
67
|
+
?? (
|
|
68
|
+
// ag may have requestContext.httpMethod
|
|
69
|
+
(mode != RoutingMode.Ag ? event.requestContext?.httpMethod : undefined))
|
|
70
|
+
?? (
|
|
71
|
+
// url may have requestContext.http.method
|
|
72
|
+
(mode == RoutingMode.Url ? event.requestContext?.http?.method : undefined))
|
|
73
|
+
?? options?.defaultMethod
|
|
74
|
+
?? 'GET';
|
|
75
|
+
// get and decode as necessary any request body
|
|
76
|
+
if (event?.body) {
|
|
77
|
+
output.body = event?.isBase64Encoded
|
|
78
|
+
? Buffer.from(`${event?.body}`, 'base64').toString('ascii')
|
|
79
|
+
: event?.body;
|
|
80
|
+
}
|
|
81
|
+
return output;
|
|
82
|
+
}
|
|
83
|
+
/** @ignore */
|
|
84
|
+
async function responseToResult(mode, response, options) {
|
|
85
|
+
options = Object.assign({ base64Encode: false, fallbackStatus: 404, multiValueHeaders: false }, options);
|
|
86
|
+
// function urls do not support multi values
|
|
87
|
+
if (options && mode === RoutingMode.Url) {
|
|
88
|
+
options.multiValueHeaders = false;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
return await parseResponseOrError(mode, response ?? (0, itty_router_1.error)(options.fallbackStatus, 'Response not found'), options);
|
|
92
|
+
}
|
|
93
|
+
catch (err) { // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
94
|
+
return await parseResponseOrError(mode, (0, itty_router_1.error)(err), options);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function parseResponseOrError(mode, input, options) {
|
|
98
|
+
let output;
|
|
99
|
+
switch (mode) {
|
|
100
|
+
case RoutingMode.Ag:
|
|
101
|
+
output = { statusCode: 200, isBase64Encoded: !!options.base64Encode, body: '' };
|
|
102
|
+
break;
|
|
103
|
+
case RoutingMode.Alb:
|
|
104
|
+
output = { statusCode: 200, isBase64Encoded: !!options.base64Encode };
|
|
105
|
+
break;
|
|
106
|
+
case RoutingMode.Url:
|
|
107
|
+
output = { statusCode: 200, isBase64Encoded: !!options.base64Encode };
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
// destructure just what we need
|
|
111
|
+
const { status, headers, body } = input;
|
|
112
|
+
output.statusCode = status;
|
|
113
|
+
// handle single or multi headers
|
|
114
|
+
const { headers: singleHeaders, multiValueHeaders } = headersToObjects(headers, options.multiValueHeaders);
|
|
115
|
+
output.headers = {};
|
|
116
|
+
for (const [key, value] of Object.entries(singleHeaders)) {
|
|
117
|
+
if (undefined !== value)
|
|
118
|
+
output.headers[key] = value;
|
|
119
|
+
}
|
|
120
|
+
if (mode !== RoutingMode.Url) {
|
|
121
|
+
output.multiValueHeaders = {};
|
|
122
|
+
if ('multiValueHeaders' in output && output.multiValueHeaders) {
|
|
123
|
+
for (const [key, value] of Object.entries(multiValueHeaders)) {
|
|
124
|
+
if (undefined !== value)
|
|
125
|
+
output.multiValueHeaders[key] = value;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// un-streamify body as necessary
|
|
130
|
+
if (body) {
|
|
131
|
+
output.body = await (0, consumers_1.text)(body);
|
|
132
|
+
if (options.base64Encode) {
|
|
133
|
+
output.body = Buffer.from(output.body, 'utf-8').toString('base64');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return output;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Combine single and multi value header objects and convert to standardized
|
|
140
|
+
* Headers instance.
|
|
141
|
+
*/
|
|
142
|
+
function objectsToHeaders(single, multi) {
|
|
143
|
+
const input = {};
|
|
144
|
+
// add each single value header, wrapped in array
|
|
145
|
+
if (single) {
|
|
146
|
+
for (const [key, value] of Object.entries(single)) {
|
|
147
|
+
if (value)
|
|
148
|
+
input[key] = [value];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// and each multi value header
|
|
152
|
+
if (multi) {
|
|
153
|
+
for (const [key, values] of Object.entries(multi)) {
|
|
154
|
+
if (values) {
|
|
155
|
+
// merge with any existing arrays of values
|
|
156
|
+
if (undefined === input?.[key]) {
|
|
157
|
+
input[key] = values;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
for (const value of values) {
|
|
161
|
+
if (!input[key].includes(value))
|
|
162
|
+
input[key].push(value);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// append each normalized array to new Headers instance
|
|
169
|
+
const output = new Headers();
|
|
170
|
+
for (const [key, values] of Object.entries(input)) {
|
|
171
|
+
for (const value of values) {
|
|
172
|
+
output.append(key, value);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return output;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Split Headers instance into single and (when explicitly enabled) multi value
|
|
179
|
+
* header objects.
|
|
180
|
+
*/
|
|
181
|
+
function headersToObjects(headers, splitIntoMultiValues = false) {
|
|
182
|
+
const single = {};
|
|
183
|
+
const multi = {};
|
|
184
|
+
for (const [key, value] of headers.entries()) {
|
|
185
|
+
if (splitIntoMultiValues && value.includes(',')) {
|
|
186
|
+
multi[key] = value.split(/\s*,\s*/);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
single[key] = value;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return { headers: single, multiValueHeaders: multi };
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Combine single and multi value query string parameters into a well formed
|
|
196
|
+
* query string, as produced by the URLSearchParams global.
|
|
197
|
+
*/
|
|
198
|
+
function objectsToQueryString(single, multi) {
|
|
199
|
+
const output = new URLSearchParams();
|
|
200
|
+
// include all single value query params by default
|
|
201
|
+
if (single) {
|
|
202
|
+
for (const [key, value] of Object.entries(single)) {
|
|
203
|
+
if (undefined !== value)
|
|
204
|
+
output.append(key, value);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// and all multi value query params that don't already contain same value
|
|
208
|
+
if (multi) {
|
|
209
|
+
for (const [key, value] of Object.entries(multi)) {
|
|
210
|
+
if (Array.isArray(value)) {
|
|
211
|
+
for (const v of value) {
|
|
212
|
+
if (!output.has(key, v))
|
|
213
|
+
output.append(key, v);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return output.toString();
|
|
219
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Each implements the following functions:
|
|
4
|
+
*
|
|
5
|
+
* @see eventToRequest
|
|
6
|
+
* Expects an event as provided by the AWS Lambda service to an invoked
|
|
7
|
+
* function, and returns a request-like object for use by itty-router.
|
|
8
|
+
*
|
|
9
|
+
* @see responseToResult
|
|
10
|
+
* Expects a response as returned by itty-router (or undefined if no route
|
|
11
|
+
* match found), and returns a result as expected by the Lambda service.
|
|
12
|
+
*
|
|
13
|
+
* The format of each incoming event and outgoing result vary depending on
|
|
14
|
+
* how the Lambda has been invoked, hence the multiple implementations.
|
|
15
|
+
*
|
|
16
|
+
* @module index
|
|
17
|
+
* @ignore
|
|
18
|
+
*/
|
|
19
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.url = exports.alb = exports.ag = void 0;
|
|
24
|
+
// API Gateways
|
|
25
|
+
const ag_1 = __importDefault(require("./ag"));
|
|
26
|
+
exports.ag = ag_1.default;
|
|
27
|
+
// Application Load Balancers
|
|
28
|
+
const alb_1 = __importDefault(require("./alb"));
|
|
29
|
+
exports.alb = alb_1.default;
|
|
30
|
+
// Lambda function urls
|
|
31
|
+
const url_1 = __importDefault(require("./url"));
|
|
32
|
+
exports.url = url_1.default;
|
package/build/cjs/url.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Lambda function url implemention
|
|
4
|
+
*
|
|
5
|
+
* @module url
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { eventToRequest, responseToResult } from 'itty-lambda/url';
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.eventToRequest = eventToRequest;
|
|
12
|
+
exports.responseToResult = responseToResult;
|
|
13
|
+
const common_1 = require("./common");
|
|
14
|
+
/**
|
|
15
|
+
* Accepts an event from an AWS Lambda function invocation by way of a
|
|
16
|
+
* function url, and formats it into a request suitable for routing through
|
|
17
|
+
* itty-router.
|
|
18
|
+
*
|
|
19
|
+
* @param event
|
|
20
|
+
* @param options
|
|
21
|
+
*/
|
|
22
|
+
async function eventToRequest(event, options) {
|
|
23
|
+
return await (0, common_1.eventToRequest)(common_1.RoutingMode.Url, event, options);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Accepts a response from itty-router (or undefined if no route was matched),
|
|
27
|
+
* and formats it into a result suitable to return to the Lambda service and
|
|
28
|
+
* subsequently to the client invoking the function url.
|
|
29
|
+
*
|
|
30
|
+
* If no response was provided, an error response is built with the given
|
|
31
|
+
* fallback HTTP status, defaulting to 404.
|
|
32
|
+
*
|
|
33
|
+
* @param response
|
|
34
|
+
* @param options
|
|
35
|
+
*/
|
|
36
|
+
async function responseToResult(response, options) {
|
|
37
|
+
return (await (0, common_1.responseToResult)(common_1.RoutingMode.Url, response, options));
|
|
38
|
+
}
|
|
39
|
+
/** @ignore */
|
|
40
|
+
exports.default = {
|
|
41
|
+
eventToRequest,
|
|
42
|
+
responseToResult,
|
|
43
|
+
};
|
package/build/esm/ag.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* API gateway implemention
|
|
4
|
+
*
|
|
5
|
+
* @module ag
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { eventToRequest, responseToResult } from 'itty-lambda/ag';
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.eventToRequest = eventToRequest;
|
|
12
|
+
exports.responseToResult = responseToResult;
|
|
13
|
+
const common_1 = require("./common");
|
|
14
|
+
/**
|
|
15
|
+
* Accepts an event from an AWS Lambda function invocation by way of an
|
|
16
|
+
* API gateway proxy integration, and formats it into a request suitable
|
|
17
|
+
* for routing through itty-router.
|
|
18
|
+
*
|
|
19
|
+
* @param event
|
|
20
|
+
* @param options
|
|
21
|
+
*/
|
|
22
|
+
async function eventToRequest(event, options) {
|
|
23
|
+
return await (0, common_1.eventToRequest)(common_1.RoutingMode.Ag, event, options);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Accepts a response from itty-router (or undefined if no route was matched),
|
|
27
|
+
* and formats it into a result suitable to return to the Lambda service and
|
|
28
|
+
* subsequently to an API gateway proxy integration.
|
|
29
|
+
*
|
|
30
|
+
* If no response was provided, an error response is built with the given
|
|
31
|
+
* fallback HTTP status, defaulting to 404.
|
|
32
|
+
*
|
|
33
|
+
* @param response
|
|
34
|
+
* @param options
|
|
35
|
+
*/
|
|
36
|
+
async function responseToResult(response, options) {
|
|
37
|
+
return (await (0, common_1.responseToResult)(common_1.RoutingMode.Ag, response, options));
|
|
38
|
+
}
|
|
39
|
+
/** @ignore */
|
|
40
|
+
exports.default = {
|
|
41
|
+
eventToRequest,
|
|
42
|
+
responseToResult,
|
|
43
|
+
};
|
package/build/esm/alb.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Application load balancer implemention
|
|
4
|
+
*
|
|
5
|
+
* @module alb
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { eventToRequest, responseToResult } from 'itty-lambda/alb';
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.eventToRequest = eventToRequest;
|
|
12
|
+
exports.responseToResult = responseToResult;
|
|
13
|
+
const common_1 = require("./common");
|
|
14
|
+
/**
|
|
15
|
+
* Accepts an event from an AWS Lambda function invocation by way of an
|
|
16
|
+
* application load balancer target, and formats it into a request
|
|
17
|
+
* suitable for routing through itty-router.
|
|
18
|
+
*
|
|
19
|
+
* @param event
|
|
20
|
+
* @param options
|
|
21
|
+
*/
|
|
22
|
+
async function eventToRequest(event, options) {
|
|
23
|
+
return await (0, common_1.eventToRequest)(common_1.RoutingMode.Alb, event, options);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Accepts a response from itty-router (or undefined if no route was matched),
|
|
27
|
+
* and formats it into a result suitable to return to the Lambda service and
|
|
28
|
+
* subsequently to an application load balancer.
|
|
29
|
+
*
|
|
30
|
+
* If no response was provided, an error response is built with the given
|
|
31
|
+
* fallback HTTP status, defaulting to 404.
|
|
32
|
+
*
|
|
33
|
+
* @param response
|
|
34
|
+
* @param options
|
|
35
|
+
*/
|
|
36
|
+
async function responseToResult(response, options) {
|
|
37
|
+
return (await (0, common_1.responseToResult)(common_1.RoutingMode.Alb, response, options));
|
|
38
|
+
}
|
|
39
|
+
/** @ignore */
|
|
40
|
+
exports.default = {
|
|
41
|
+
eventToRequest,
|
|
42
|
+
responseToResult,
|
|
43
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Common shared functionality between implementations.
|
|
4
|
+
*
|
|
5
|
+
* @module common
|
|
6
|
+
* @protected
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.RoutingMode = void 0;
|
|
10
|
+
exports.eventToRequest = eventToRequest;
|
|
11
|
+
exports.responseToResult = responseToResult;
|
|
12
|
+
const consumers_1 = require("node:stream/consumers");
|
|
13
|
+
const itty_router_1 = require("itty-router");
|
|
14
|
+
/** @ignore */
|
|
15
|
+
var RoutingMode;
|
|
16
|
+
(function (RoutingMode) {
|
|
17
|
+
RoutingMode["Ag"] = "api-gateway";
|
|
18
|
+
RoutingMode["Alb"] = "application-load-balancer";
|
|
19
|
+
RoutingMode["Url"] = "lambda-function-url";
|
|
20
|
+
})(RoutingMode || (exports.RoutingMode = RoutingMode = {}));
|
|
21
|
+
/** @ignore */
|
|
22
|
+
async function eventToRequest(mode, event, options) {
|
|
23
|
+
const output = { method: '', url: '' };
|
|
24
|
+
output.headers = objectsToHeaders(event?.headers,
|
|
25
|
+
// account for lambda function urls not supporting multi values
|
|
26
|
+
(mode != RoutingMode.Url ? event.multiValueHeaders : undefined));
|
|
27
|
+
// infer protocol from headers when available
|
|
28
|
+
const proto = output.headers.get('x-forwarded-proto')
|
|
29
|
+
?? output.headers.get('forwarded')?.match(/proto=(\w+)/)?.[1]
|
|
30
|
+
?? 'http';
|
|
31
|
+
// infer host when available
|
|
32
|
+
const host = (
|
|
33
|
+
// ag or url may have requestContext.domainName
|
|
34
|
+
(mode != RoutingMode.Alb ? event.requestContext?.domainName : undefined))
|
|
35
|
+
?? output.headers.get('host')
|
|
36
|
+
?? output.headers.get('x-forwarded-host')
|
|
37
|
+
?? output.headers.get('forwarded')?.match(/host=([^;]+)/)?.[1]
|
|
38
|
+
?? 'localhost.localdomain';
|
|
39
|
+
// infer path when available
|
|
40
|
+
const path = (
|
|
41
|
+
// ag or alb may have path
|
|
42
|
+
(mode != RoutingMode.Url ? event.path : undefined))
|
|
43
|
+
?? (
|
|
44
|
+
// url may have rawPath
|
|
45
|
+
(mode == RoutingMode.Url ? event.rawPath : undefined))
|
|
46
|
+
?? (
|
|
47
|
+
// ag may have requestContext.path
|
|
48
|
+
(mode == RoutingMode.Ag ? event.requestContext?.path : undefined))
|
|
49
|
+
?? (
|
|
50
|
+
// url may have requestContext.http.path
|
|
51
|
+
(mode == RoutingMode.Url ? event.requestContext?.http?.path : undefined))
|
|
52
|
+
?? '';
|
|
53
|
+
// infer querystring and convert to string as necessary
|
|
54
|
+
const queryString = (
|
|
55
|
+
// url may have rawQueryString
|
|
56
|
+
(mode == RoutingMode.Url ? event.rawQueryString : undefined))
|
|
57
|
+
?? objectsToQueryString(event?.queryStringParameters, (
|
|
58
|
+
// ag or alb may have multiValueQueryStringParameters
|
|
59
|
+
(mode != RoutingMode.Url ? event.multiValueQueryStringParameters : undefined)));
|
|
60
|
+
// assemble well-formed url from inferred values above
|
|
61
|
+
output.url = `${proto}://${host}${path}?${queryString}`;
|
|
62
|
+
// infer or default http method
|
|
63
|
+
output.method =
|
|
64
|
+
(
|
|
65
|
+
// ag or alb may have httpMethod
|
|
66
|
+
(mode != RoutingMode.Url ? event.httpMethod : undefined))
|
|
67
|
+
?? (
|
|
68
|
+
// ag may have requestContext.httpMethod
|
|
69
|
+
(mode != RoutingMode.Ag ? event.requestContext?.httpMethod : undefined))
|
|
70
|
+
?? (
|
|
71
|
+
// url may have requestContext.http.method
|
|
72
|
+
(mode == RoutingMode.Url ? event.requestContext?.http?.method : undefined))
|
|
73
|
+
?? options?.defaultMethod
|
|
74
|
+
?? 'GET';
|
|
75
|
+
// get and decode as necessary any request body
|
|
76
|
+
if (event?.body) {
|
|
77
|
+
output.body = event?.isBase64Encoded
|
|
78
|
+
? Buffer.from(`${event?.body}`, 'base64').toString('ascii')
|
|
79
|
+
: event?.body;
|
|
80
|
+
}
|
|
81
|
+
return output;
|
|
82
|
+
}
|
|
83
|
+
/** @ignore */
|
|
84
|
+
async function responseToResult(mode, response, options) {
|
|
85
|
+
options = Object.assign({ base64Encode: false, fallbackStatus: 404, multiValueHeaders: false }, options);
|
|
86
|
+
// function urls do not support multi values
|
|
87
|
+
if (options && mode === RoutingMode.Url) {
|
|
88
|
+
options.multiValueHeaders = false;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
return await parseResponseOrError(mode, response ?? (0, itty_router_1.error)(options.fallbackStatus, 'Response not found'), options);
|
|
92
|
+
}
|
|
93
|
+
catch (err) { // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
94
|
+
return await parseResponseOrError(mode, (0, itty_router_1.error)(err), options);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function parseResponseOrError(mode, input, options) {
|
|
98
|
+
let output;
|
|
99
|
+
switch (mode) {
|
|
100
|
+
case RoutingMode.Ag:
|
|
101
|
+
output = { statusCode: 200, isBase64Encoded: !!options.base64Encode, body: '' };
|
|
102
|
+
break;
|
|
103
|
+
case RoutingMode.Alb:
|
|
104
|
+
output = { statusCode: 200, isBase64Encoded: !!options.base64Encode };
|
|
105
|
+
break;
|
|
106
|
+
case RoutingMode.Url:
|
|
107
|
+
output = { statusCode: 200, isBase64Encoded: !!options.base64Encode };
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
// destructure just what we need
|
|
111
|
+
const { status, headers, body } = input;
|
|
112
|
+
output.statusCode = status;
|
|
113
|
+
// handle single or multi headers
|
|
114
|
+
const { headers: singleHeaders, multiValueHeaders } = headersToObjects(headers, options.multiValueHeaders);
|
|
115
|
+
output.headers = {};
|
|
116
|
+
for (const [key, value] of Object.entries(singleHeaders)) {
|
|
117
|
+
if (undefined !== value)
|
|
118
|
+
output.headers[key] = value;
|
|
119
|
+
}
|
|
120
|
+
if (mode !== RoutingMode.Url) {
|
|
121
|
+
output.multiValueHeaders = {};
|
|
122
|
+
if ('multiValueHeaders' in output && output.multiValueHeaders) {
|
|
123
|
+
for (const [key, value] of Object.entries(multiValueHeaders)) {
|
|
124
|
+
if (undefined !== value)
|
|
125
|
+
output.multiValueHeaders[key] = value;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// un-streamify body as necessary
|
|
130
|
+
if (body) {
|
|
131
|
+
output.body = await (0, consumers_1.text)(body);
|
|
132
|
+
if (options.base64Encode) {
|
|
133
|
+
output.body = Buffer.from(output.body, 'utf-8').toString('base64');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return output;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Combine single and multi value header objects and convert to standardized
|
|
140
|
+
* Headers instance.
|
|
141
|
+
*/
|
|
142
|
+
function objectsToHeaders(single, multi) {
|
|
143
|
+
const input = {};
|
|
144
|
+
// add each single value header, wrapped in array
|
|
145
|
+
if (single) {
|
|
146
|
+
for (const [key, value] of Object.entries(single)) {
|
|
147
|
+
if (value)
|
|
148
|
+
input[key] = [value];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// and each multi value header
|
|
152
|
+
if (multi) {
|
|
153
|
+
for (const [key, values] of Object.entries(multi)) {
|
|
154
|
+
if (values) {
|
|
155
|
+
// merge with any existing arrays of values
|
|
156
|
+
if (undefined === input?.[key]) {
|
|
157
|
+
input[key] = values;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
for (const value of values) {
|
|
161
|
+
if (!input[key].includes(value))
|
|
162
|
+
input[key].push(value);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// append each normalized array to new Headers instance
|
|
169
|
+
const output = new Headers();
|
|
170
|
+
for (const [key, values] of Object.entries(input)) {
|
|
171
|
+
for (const value of values) {
|
|
172
|
+
output.append(key, value);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return output;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Split Headers instance into single and (when explicitly enabled) multi value
|
|
179
|
+
* header objects.
|
|
180
|
+
*/
|
|
181
|
+
function headersToObjects(headers, splitIntoMultiValues = false) {
|
|
182
|
+
const single = {};
|
|
183
|
+
const multi = {};
|
|
184
|
+
for (const [key, value] of headers.entries()) {
|
|
185
|
+
if (splitIntoMultiValues && value.includes(',')) {
|
|
186
|
+
multi[key] = value.split(/\s*,\s*/);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
single[key] = value;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return { headers: single, multiValueHeaders: multi };
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Combine single and multi value query string parameters into a well formed
|
|
196
|
+
* query string, as produced by the URLSearchParams global.
|
|
197
|
+
*/
|
|
198
|
+
function objectsToQueryString(single, multi) {
|
|
199
|
+
const output = new URLSearchParams();
|
|
200
|
+
// include all single value query params by default
|
|
201
|
+
if (single) {
|
|
202
|
+
for (const [key, value] of Object.entries(single)) {
|
|
203
|
+
if (undefined !== value)
|
|
204
|
+
output.append(key, value);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// and all multi value query params that don't already contain same value
|
|
208
|
+
if (multi) {
|
|
209
|
+
for (const [key, value] of Object.entries(multi)) {
|
|
210
|
+
if (Array.isArray(value)) {
|
|
211
|
+
for (const v of value) {
|
|
212
|
+
if (!output.has(key, v))
|
|
213
|
+
output.append(key, v);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return output.toString();
|
|
219
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Each implements the following functions:
|
|
4
|
+
*
|
|
5
|
+
* @see eventToRequest
|
|
6
|
+
* Expects an event as provided by the AWS Lambda service to an invoked
|
|
7
|
+
* function, and returns a request-like object for use by itty-router.
|
|
8
|
+
*
|
|
9
|
+
* @see responseToResult
|
|
10
|
+
* Expects a response as returned by itty-router (or undefined if no route
|
|
11
|
+
* match found), and returns a result as expected by the Lambda service.
|
|
12
|
+
*
|
|
13
|
+
* The format of each incoming event and outgoing result vary depending on
|
|
14
|
+
* how the Lambda has been invoked, hence the multiple implementations.
|
|
15
|
+
*
|
|
16
|
+
* @module index
|
|
17
|
+
* @ignore
|
|
18
|
+
*/
|
|
19
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.url = exports.alb = exports.ag = void 0;
|
|
24
|
+
// API Gateways
|
|
25
|
+
const ag_1 = __importDefault(require("./ag"));
|
|
26
|
+
exports.ag = ag_1.default;
|
|
27
|
+
// Application Load Balancers
|
|
28
|
+
const alb_1 = __importDefault(require("./alb"));
|
|
29
|
+
exports.alb = alb_1.default;
|
|
30
|
+
// Lambda function urls
|
|
31
|
+
const url_1 = __importDefault(require("./url"));
|
|
32
|
+
exports.url = url_1.default;
|
package/build/esm/url.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Lambda function url implemention
|
|
4
|
+
*
|
|
5
|
+
* @module url
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { eventToRequest, responseToResult } from 'itty-lambda/url';
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.eventToRequest = eventToRequest;
|
|
12
|
+
exports.responseToResult = responseToResult;
|
|
13
|
+
const common_1 = require("./common");
|
|
14
|
+
/**
|
|
15
|
+
* Accepts an event from an AWS Lambda function invocation by way of a
|
|
16
|
+
* function url, and formats it into a request suitable for routing through
|
|
17
|
+
* itty-router.
|
|
18
|
+
*
|
|
19
|
+
* @param event
|
|
20
|
+
* @param options
|
|
21
|
+
*/
|
|
22
|
+
async function eventToRequest(event, options) {
|
|
23
|
+
return await (0, common_1.eventToRequest)(common_1.RoutingMode.Url, event, options);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Accepts a response from itty-router (or undefined if no route was matched),
|
|
27
|
+
* and formats it into a result suitable to return to the Lambda service and
|
|
28
|
+
* subsequently to the client invoking the function url.
|
|
29
|
+
*
|
|
30
|
+
* If no response was provided, an error response is built with the given
|
|
31
|
+
* fallback HTTP status, defaulting to 404.
|
|
32
|
+
*
|
|
33
|
+
* @param response
|
|
34
|
+
* @param options
|
|
35
|
+
*/
|
|
36
|
+
async function responseToResult(response, options) {
|
|
37
|
+
return (await (0, common_1.responseToResult)(common_1.RoutingMode.Url, response, options));
|
|
38
|
+
}
|
|
39
|
+
/** @ignore */
|
|
40
|
+
exports.default = {
|
|
41
|
+
eventToRequest,
|
|
42
|
+
responseToResult,
|
|
43
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "itty-lambda",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "AWS Lambda support for itty-router",
|
|
5
|
+
"author": "Evan Kaufman <evan@evanskaufman.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/EvanK/itty-lambda.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/EvanK/itty-lambda/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/EvanK/itty-lambda",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"itty-router",
|
|
17
|
+
"router",
|
|
18
|
+
"aws-lambda"
|
|
19
|
+
],
|
|
20
|
+
"files": [
|
|
21
|
+
"build/**/*.js"
|
|
22
|
+
],
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"require": "./build/cjs/index.js",
|
|
26
|
+
"import": "./build/esm/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./url": {
|
|
29
|
+
"require": "./build/cjs/url.js",
|
|
30
|
+
"import": "./build/esm/url.js"
|
|
31
|
+
},
|
|
32
|
+
"./ag": {
|
|
33
|
+
"require": "./build/cjs/ag.js",
|
|
34
|
+
"import": "./build/esm/ag.js"
|
|
35
|
+
},
|
|
36
|
+
"./alb": {
|
|
37
|
+
"require": "./build/cjs/alb.js",
|
|
38
|
+
"import": "./build/esm/alb.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"docs": "npm run docs-html && npm run docs-md",
|
|
43
|
+
"docs-html": "typedoc --options typedoc.html.json",
|
|
44
|
+
"docs-md": "typedoc --options typedoc.md.json",
|
|
45
|
+
"link": "npm link && npm link itty-lambda",
|
|
46
|
+
"lint": "eslint ./src/",
|
|
47
|
+
"test": "nyc mocha ./test/unit/*.test.*js",
|
|
48
|
+
"tsc": "npm run tsc-cjs && npm run tsc-esm",
|
|
49
|
+
"tsc-cjs": "tsc --module commonjs --outDir ./build/cjs/",
|
|
50
|
+
"tsc-esm": "tsc --module nodenext --outDir ./build/esm/"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@eslint/js": "^9.29.0",
|
|
54
|
+
"@types/aws-lambda": "^8.10.150",
|
|
55
|
+
"@types/node": "^24.2.0",
|
|
56
|
+
"chai": "^5.2.1",
|
|
57
|
+
"eslint": "^9.29.0",
|
|
58
|
+
"mocha": "^11.7.1",
|
|
59
|
+
"nyc": "^17.1.0",
|
|
60
|
+
"sinon": "^21.0.0",
|
|
61
|
+
"typedoc": "^0.28.8",
|
|
62
|
+
"typedoc-github-theme": "^0.3.0",
|
|
63
|
+
"typedoc-plugin-markdown": "^4.8.0",
|
|
64
|
+
"typedoc-plugin-mdn-links": "^5.0.7",
|
|
65
|
+
"typescript": "^5.8.3",
|
|
66
|
+
"typescript-eslint": "^8.34.1"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"itty-router": "^5.0.0"
|
|
70
|
+
}
|
|
71
|
+
}
|