@kleanjs/aws-lambda 0.1.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 +103 -0
- package/dist/apigateway/index.cjs +1 -0
- package/dist/apigateway/index.d.ts +174 -0
- package/dist/apigateway/index.d.ts.map +1 -0
- package/dist/apigateway/index.mjs +1 -0
- package/dist/handler.d-CkaE-Brj.d.ts +160 -0
- package/dist/handler.d-CkaE-Brj.d.ts.map +1 -0
- package/dist/sqs/index.cjs +1 -0
- package/dist/sqs/index.d.ts +64 -0
- package/dist/sqs/index.d.ts.map +1 -0
- package/dist/sqs/index.mjs +1 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# @kleanjs/aws-lambda
|
|
2
|
+
|
|
3
|
+
High-performance adapters for AWS Lambda. This package provides specialized wrappers for API Gateway and SQS, integrating seamlessly with the `@kleanjs/core` middleware engine.
|
|
4
|
+
|
|
5
|
+
## Key Features
|
|
6
|
+
|
|
7
|
+
* **Service-Specific Wrappers**: Specialized middlewares for API Gateway (REST/HTTP) and SQS (Parallel or Serial).
|
|
8
|
+
* **Automatic Response Formatting**: Built-in handlers to transform business objects into AWS-compliant responses.
|
|
9
|
+
* **Partial Batch Support**: Native handling of SQS `batchItemFailures` to optimize queue processing and costs.
|
|
10
|
+
* **Type Injection**: Pre-configured infrastructure types (Events, Context, Results) for a zero-boilerplate experience.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @kleanjs/aws-lambda @kleanjs/core ajv ajv-formats
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## API Gateway Reference
|
|
21
|
+
|
|
22
|
+
The `apiGatewayMiddleware` is pre-configured to handle HTTP requests. It automatically injects `APIGatewayProxyEvent` and `APIGatewayProxyResult` types.
|
|
23
|
+
|
|
24
|
+
### Configuration Extensions
|
|
25
|
+
While it inherits from `HandlerConfig`, it provides sensible defaults:
|
|
26
|
+
- **Default Result**: `APIGatewayProxyResult`.
|
|
27
|
+
- **Default Response**: `responseJSON()` (Content-Type: application/json).
|
|
28
|
+
- **Default Error Handler**: Automatically maps `EventError` properties to the response body and status code.
|
|
29
|
+
|
|
30
|
+
### Example
|
|
31
|
+
```typescript
|
|
32
|
+
import { apiGatewayMiddleware, responseJSON, Use } from "@kleanjs/aws-lambda";
|
|
33
|
+
|
|
34
|
+
export const handler = apiGatewayMiddleware(
|
|
35
|
+
async (event) => {
|
|
36
|
+
return { id: event.body.id, status: "active" };
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
validators: {
|
|
40
|
+
body: Use<{ id: string }>()
|
|
41
|
+
},
|
|
42
|
+
customResponse: responseJSON({ statusCode: 201 })
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## SQS Reference
|
|
50
|
+
|
|
51
|
+
SQS processing is divided into two execution modes. Both modes isolate the logic to a single `SQSRecord`, abstracting the `Records` array iteration.
|
|
52
|
+
|
|
53
|
+
### 1. Parallel Processing (`sqsMiddlewareParallel`)
|
|
54
|
+
Processes all records in the batch simultaneously using `Promise.allSettled`. This is ideal for high-throughput tasks.
|
|
55
|
+
|
|
56
|
+
### 2. Serial Processing (`sqsMiddlewareSeries`)
|
|
57
|
+
Processes records one by one. Use this when the processing order is critical or to prevent race conditions.
|
|
58
|
+
|
|
59
|
+
### Batch Error Handling
|
|
60
|
+
If a record throws an `EventError` or fails validation, the middleware catches it and adds its `messageId` to the `batchItemFailures` array. AWS will then retry only the failed messages.
|
|
61
|
+
|
|
62
|
+
### Example
|
|
63
|
+
```typescript
|
|
64
|
+
import { sqsMiddlewareParallel, Use } from "@kleanjs/aws-lambda";
|
|
65
|
+
|
|
66
|
+
export const handler = sqsMiddlewareParallel(
|
|
67
|
+
async (record) => {
|
|
68
|
+
// 'record' is a single SQSRecord with typed body
|
|
69
|
+
await processOrder(record.body.orderId);
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
validators: {
|
|
73
|
+
body: Use<{ orderId: string }>()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Technical Interfaces
|
|
82
|
+
|
|
83
|
+
### `SQSOptions`
|
|
84
|
+
```typescript
|
|
85
|
+
export type SQSOptions<TValidators extends TSchemaMap, TContext = Context> =
|
|
86
|
+
Omit<HandlerConfig<any, any, TContext, TValidators>, "customResponse" | "event" | "result" | "context">;
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Error Mapping Logic
|
|
92
|
+
|
|
93
|
+
The adapters catch any `EventError` (including `AJVSimpleError` or `AJVFullError`) and transform them as follows:
|
|
94
|
+
|
|
95
|
+
### API Gateway Mapping
|
|
96
|
+
- **Status Code**: Taken from `error.statusCode`.
|
|
97
|
+
- **Body**: Standardized JSON with `type`, `message`, and `details`.
|
|
98
|
+
|
|
99
|
+
### SQS Mapping
|
|
100
|
+
Any error thrown within the record handler marks that specific message as failed. The adapter returns the `batchItemFailures` object required by AWS.
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
GPLv3
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var T=Object.defineProperty;var n=(e,t)=>T(e,"name",{value:t,configurable:!0});var a=require("@kleanjs/core");const d={"Content-Type":"application/json"},i={"Content-Type":"text/html"},l={"Content-Type":"application/octet-stream"},y={"Content-Type":"text/plain"},f="application/json",_="application/x-www-form-urlencoded",u=n(e=>{if(!e.body)return{};const t=e.headers["content-type"]||e.headers["Content-Type"]||"",r=e.isBase64Encoded?Buffer.from(e.body,"base64").toString("utf8"):e.body;if(t.includes(_))return Object.fromEntries(new URLSearchParams(r));if(t.includes(f))try{return JSON.parse(r)}catch{return r}return r},"getBody"),E=n((e={})=>{const{statusCode:t=200,headers:r,...s}=e,o={...d,...r};return c=>({statusCode:t,headers:o,body:JSON.stringify(c??null),...s})},"responseJSON"),m=n((e={})=>{const{statusCode:t=200,headers:r,...s}=e,o={...i,...r};return c=>({statusCode:t,headers:o,body:c,...s})},"responseHTML"),b=n((e={})=>{const{statusCode:t=200,contentType:r="application/octet-stream",headers:s,...o}=e,c={"Content-Type":r,...s};return p=>({statusCode:t,headers:c,body:p,isBase64Encoded:!0,...o})},"responseMediaFile"),O=n((e={})=>{const{statusCode:t=302,headers:r,...s}=e;return o=>({statusCode:t,headers:{Location:o,...r},body:"",...s})},"responseRedirect"),P=n((e,t={})=>{const r={body:u,...t.transformers};return a.middleware(e,{event:a.Use(),result:a.Use(),context:a.Use(),...t,transformers:r,customResponse:t.customResponse??E()})},"middleware");Object.defineProperty(exports,"AJVError",{enumerable:!0,get:n(function(){return a.AJVError},"get")}),Object.defineProperty(exports,"EventError",{enumerable:!0,get:n(function(){return a.EventError},"get")}),Object.defineProperty(exports,"Use",{enumerable:!0,get:n(function(){return a.Use},"get")}),exports.HEADER_TYPE_HTML=i,exports.HEADER_TYPE_JSON=d,exports.HEADER_TYPE_OCTET=l,exports.HEADER_TYPE_PLAIN=y,exports.getBody=u,exports.middleware=P,exports.responseHTML=m,exports.responseJSON=E,exports.responseMediaFile=b,exports.responseRedirect=O;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { C as Context } from '../handler.d-CkaE-Brj.js';
|
|
2
|
+
import { TSchemaMap, TCombinedEvent, HandlerConfig } from '@kleanjs/core';
|
|
3
|
+
export { AJVError, EventError, Use } from '@kleanjs/core';
|
|
4
|
+
import 'node:stream';
|
|
5
|
+
|
|
6
|
+
// Default authorizer type, prefer using a specific type with the "...WithAuthorizer..." variant types.
|
|
7
|
+
// Note that this doesn't have to be a context from a custom lambda outhorizer, AWS also has a cognito
|
|
8
|
+
// authorizer type and could add more, so the property won't always be a string.
|
|
9
|
+
type APIGatewayEventDefaultAuthorizerContext =
|
|
10
|
+
| undefined
|
|
11
|
+
| null
|
|
12
|
+
| {
|
|
13
|
+
[name: string]: any;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// The requestContext property of both request authorizer and proxy integration events.
|
|
17
|
+
interface APIGatewayEventRequestContextWithAuthorizer<TAuthorizerContext> {
|
|
18
|
+
accountId: string;
|
|
19
|
+
apiId: string;
|
|
20
|
+
// This one is a bit confusing: it is not actually present in authorizer calls
|
|
21
|
+
// and proxy calls without an authorizer. We model this by allowing undefined in the type,
|
|
22
|
+
// since it ends up the same and avoids breaking users that are testing the property.
|
|
23
|
+
// This lets us allow parameterizing the authorizer for proxy events that know what authorizer
|
|
24
|
+
// context values they have.
|
|
25
|
+
authorizer: TAuthorizerContext;
|
|
26
|
+
connectedAt?: number | undefined;
|
|
27
|
+
connectionId?: string | undefined;
|
|
28
|
+
domainName?: string | undefined;
|
|
29
|
+
domainPrefix?: string | undefined;
|
|
30
|
+
eventType?: string | undefined;
|
|
31
|
+
extendedRequestId?: string | undefined;
|
|
32
|
+
protocol: string;
|
|
33
|
+
httpMethod: string;
|
|
34
|
+
identity: APIGatewayEventIdentity;
|
|
35
|
+
messageDirection?: string | undefined;
|
|
36
|
+
messageId?: string | null | undefined;
|
|
37
|
+
path: string;
|
|
38
|
+
stage: string;
|
|
39
|
+
requestId: string;
|
|
40
|
+
requestTime?: string | undefined;
|
|
41
|
+
requestTimeEpoch: number;
|
|
42
|
+
resourceId: string;
|
|
43
|
+
resourcePath: string;
|
|
44
|
+
routeKey?: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface APIGatewayEventClientCertificate {
|
|
48
|
+
clientCertPem: string;
|
|
49
|
+
serialNumber: string;
|
|
50
|
+
subjectDN: string;
|
|
51
|
+
issuerDN: string;
|
|
52
|
+
validity: {
|
|
53
|
+
notAfter: string;
|
|
54
|
+
notBefore: string;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface APIGatewayEventIdentity {
|
|
59
|
+
accessKey: string | null;
|
|
60
|
+
accountId: string | null;
|
|
61
|
+
apiKey: string | null;
|
|
62
|
+
apiKeyId: string | null;
|
|
63
|
+
caller: string | null;
|
|
64
|
+
clientCert: APIGatewayEventClientCertificate | null;
|
|
65
|
+
cognitoAuthenticationProvider: string | null;
|
|
66
|
+
cognitoAuthenticationType: string | null;
|
|
67
|
+
cognitoIdentityId: string | null;
|
|
68
|
+
cognitoIdentityPoolId: string | null;
|
|
69
|
+
principalOrgId: string | null;
|
|
70
|
+
sourceIp: string;
|
|
71
|
+
user: string | null;
|
|
72
|
+
userAgent: string | null;
|
|
73
|
+
userArn: string | null;
|
|
74
|
+
vpcId?: string | undefined;
|
|
75
|
+
vpceId?: string | undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Works with Lambda Proxy Integration for Rest API or HTTP API integration Payload Format version 1.0
|
|
80
|
+
* @see - https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
|
|
81
|
+
*/
|
|
82
|
+
type APIGatewayProxyEvent = APIGatewayProxyEventBase<APIGatewayEventDefaultAuthorizerContext>;
|
|
83
|
+
|
|
84
|
+
interface APIGatewayProxyEventHeaders {
|
|
85
|
+
[name: string]: string | undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface APIGatewayProxyEventMultiValueHeaders {
|
|
89
|
+
[name: string]: string[] | undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface APIGatewayProxyEventPathParameters {
|
|
93
|
+
[name: string]: string | undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface APIGatewayProxyEventQueryStringParameters {
|
|
97
|
+
[name: string]: string | undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface APIGatewayProxyEventMultiValueQueryStringParameters {
|
|
101
|
+
[name: string]: string[] | undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface APIGatewayProxyEventStageVariables {
|
|
105
|
+
[name: string]: string | undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface APIGatewayProxyEventBase<TAuthorizerContext> {
|
|
109
|
+
body: string | null;
|
|
110
|
+
headers: APIGatewayProxyEventHeaders;
|
|
111
|
+
multiValueHeaders: APIGatewayProxyEventMultiValueHeaders;
|
|
112
|
+
httpMethod: string;
|
|
113
|
+
isBase64Encoded: boolean;
|
|
114
|
+
path: string;
|
|
115
|
+
pathParameters: APIGatewayProxyEventPathParameters | null;
|
|
116
|
+
queryStringParameters: APIGatewayProxyEventQueryStringParameters | null;
|
|
117
|
+
multiValueQueryStringParameters: APIGatewayProxyEventMultiValueQueryStringParameters | null;
|
|
118
|
+
stageVariables: APIGatewayProxyEventStageVariables | null;
|
|
119
|
+
requestContext: APIGatewayEventRequestContextWithAuthorizer<TAuthorizerContext>;
|
|
120
|
+
resource: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Works with Lambda Proxy Integration for Rest API or HTTP API integration Payload Format version 1.0
|
|
125
|
+
* @see - https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
|
|
126
|
+
*/
|
|
127
|
+
interface APIGatewayProxyResult {
|
|
128
|
+
statusCode: number;
|
|
129
|
+
headers?:
|
|
130
|
+
| {
|
|
131
|
+
[header: string]: boolean | number | string;
|
|
132
|
+
}
|
|
133
|
+
| undefined;
|
|
134
|
+
multiValueHeaders?:
|
|
135
|
+
| {
|
|
136
|
+
[header: string]: Array<boolean | number | string>;
|
|
137
|
+
}
|
|
138
|
+
| undefined;
|
|
139
|
+
body: string;
|
|
140
|
+
isBase64Encoded?: boolean | undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
declare const HEADER_TYPE_JSON: {
|
|
144
|
+
"Content-Type": string;
|
|
145
|
+
};
|
|
146
|
+
declare const HEADER_TYPE_HTML: {
|
|
147
|
+
"Content-Type": string;
|
|
148
|
+
};
|
|
149
|
+
declare const HEADER_TYPE_OCTET: {
|
|
150
|
+
"Content-Type": string;
|
|
151
|
+
};
|
|
152
|
+
declare const HEADER_TYPE_PLAIN: {
|
|
153
|
+
"Content-Type": string;
|
|
154
|
+
};
|
|
155
|
+
interface ResponseOptions {
|
|
156
|
+
statusCode?: number;
|
|
157
|
+
headers?: Record<string, string | boolean | number>;
|
|
158
|
+
multiValueHeaders?: Record<string, (string | boolean | number)[]>;
|
|
159
|
+
isBase64Encoded?: boolean;
|
|
160
|
+
cookies?: string[];
|
|
161
|
+
}
|
|
162
|
+
declare const getBody: <T = unknown>(event: APIGatewayProxyEvent) => T;
|
|
163
|
+
declare const responseJSON: (options?: ResponseOptions) => (data: any) => APIGatewayProxyResult;
|
|
164
|
+
declare const responseHTML: (options?: ResponseOptions) => (html: string) => APIGatewayProxyResult;
|
|
165
|
+
declare const responseMediaFile: (options?: ResponseOptions & {
|
|
166
|
+
contentType?: string;
|
|
167
|
+
}) => (base64: string) => APIGatewayProxyResult;
|
|
168
|
+
declare const responseRedirect: (options?: ResponseOptions) => (url: string) => APIGatewayProxyResult;
|
|
169
|
+
|
|
170
|
+
declare const middleware: <TEvent = APIGatewayProxyEvent, TResult = APIGatewayProxyResult, TContext = Context, TValidators extends TSchemaMap = TSchemaMap>(handler: (event: TCombinedEvent<TEvent, TValidators>, context?: TContext) => any, options?: HandlerConfig<TEvent, TResult, TContext, TValidators>) => (rawEvent: TEvent, context?: TContext | undefined) => Promise<TResult>;
|
|
171
|
+
|
|
172
|
+
export { HEADER_TYPE_HTML, HEADER_TYPE_JSON, HEADER_TYPE_OCTET, HEADER_TYPE_PLAIN, getBody, middleware, responseHTML, responseJSON, responseMediaFile, responseRedirect };
|
|
173
|
+
export type { ResponseOptions };
|
|
174
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sources":["../../../../node_modules/@types/aws-lambda/common/api-gateway.d.ts","../../../../node_modules/@types/aws-lambda/trigger/api-gateway-proxy.d.ts","../../src/apigateway/utils.ts","../../src/apigateway/index.ts"],"mappings":";;;;;AAUA;AACA;AACA;AACO,KAAK,uCAAuC;AACnD;AACA;AACA;AACA;AACA;;AAMA;AACO,UAAU,2CAA2C;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,uBAAuB;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,UAAU,gCAAgC;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,UAAU,uBAAuB;AACxC;AACA;AACA;AACA;AACA;AACA,gBAAgB,gCAAgC;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACO,KAAK,oBAAoB,GAAG,wBAAwB,CAAC,uCAAuC;;AAuC5F,UAAU,2BAA2B;AAC5C;AACA;;AAEO,UAAU,qCAAqC;AACtD;AACA;;AAEO,UAAU,kCAAkC;AACnD;AACA;;AAEO,UAAU,yCAAyC;AAC1D;AACA;;AAEO,UAAU,mDAAmD;AACpE;AACA;;AAEO,UAAU,kCAAkC;AACnD;AACA;;AAEO,UAAU,wBAAwB;AACzC;AACA,aAAa,2BAA2B;AACxC,uBAAuB,qCAAqC;AAC5D;AACA;AACA;AACA,oBAAoB,kCAAkC;AACtD,2BAA2B,yCAAyC;AACpE,qCAAqC,mDAAmD;AACxF,oBAAoB,kCAAkC;AACtD,oBAAoB,2CAA2C;AAC/D;AACA;;AAEA;AACA;AACA;AACA;AACO,UAAU,qBAAqB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B,KAAK;AACnC;AACA;AACA;AACA;AACA;;ACrKA,cAAa,gBAAgB;;;AAC7B,cAAa,gBAAgB;;;AAC7B,cAAa,iBAAiB;;;AAC9B,cAAa,iBAAiB;;;AAKxB,UAAW,eAAe;;cAEpB,MAAM;wBACI,MAAM;;;;AAK5B,cAAa,OAAO,uBAAwB,oBAAoB;AAuBhE,cAAa,YAAY,aAAa,eAAoB,oBAIpC,qBAMrB;AAED,cAAa,YAAY,aAAa,eAAoB,uBAIjC,qBAMxB;AAED,cAAa,iBAAiB,aAAa,eAAe;;0BAI/B,qBAO1B;AAED,cAAa,gBAAgB,aAAa,eAAoB,sBAGtC,qBAMvB;;AClFD,cAAa,UAAU,YACZ,oBAAoB,YACnB,qBAAqB,aACpB,OAAO,sBACE,UAAU,GAAG,UAAU,mBAE1B,cAAc,6DACtB,aAAa,mGAA6C","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var T=Object.defineProperty;var n=(e,t)=>T(e,"name",{value:t,configurable:!0});import{middleware as l,Use as c}from"@kleanjs/core";import{AJVError as w,EventError as S,Use as x}from"@kleanjs/core";const d={"Content-Type":"application/json"},i={"Content-Type":"text/html"},y={"Content-Type":"application/octet-stream"},m={"Content-Type":"text/plain"},f="application/json",h="application/x-www-form-urlencoded",p=n(e=>{if(!e.body)return{};const t=e.headers["content-type"]||e.headers["Content-Type"]||"",s=e.isBase64Encoded?Buffer.from(e.body,"base64").toString("utf8"):e.body;if(t.includes(h))return Object.fromEntries(new URLSearchParams(s));if(t.includes(f))try{return JSON.parse(s)}catch{return s}return s},"getBody"),u=n((e={})=>{const{statusCode:t=200,headers:s,...r}=e,o={...d,...s};return a=>({statusCode:t,headers:o,body:JSON.stringify(a??null),...r})},"responseJSON"),C=n((e={})=>{const{statusCode:t=200,headers:s,...r}=e,o={...i,...s};return a=>({statusCode:t,headers:o,body:a,...r})},"responseHTML"),_=n((e={})=>{const{statusCode:t=200,contentType:s="application/octet-stream",headers:r,...o}=e,a={"Content-Type":s,...r};return E=>({statusCode:t,headers:a,body:E,isBase64Encoded:!0,...o})},"responseMediaFile"),b=n((e={})=>{const{statusCode:t=302,headers:s,...r}=e;return o=>({statusCode:t,headers:{Location:o,...s},body:"",...r})},"responseRedirect"),N=n((e,t={})=>{const s={body:p,...t.transformers};return l(e,{event:c(),result:c(),context:c(),...t,transformers:s,customResponse:t.customResponse??u()})},"middleware");export{w as AJVError,S as EventError,i as HEADER_TYPE_HTML,d as HEADER_TYPE_JSON,y as HEADER_TYPE_OCTET,m as HEADER_TYPE_PLAIN,x as Use,p as getBody,N as middleware,C as responseHTML,u as responseJSON,_ as responseMediaFile,b as responseRedirect};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* {@link Handler} context parameter.
|
|
5
|
+
* See {@link https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html AWS documentation}.
|
|
6
|
+
*/
|
|
7
|
+
interface Context {
|
|
8
|
+
callbackWaitsForEmptyEventLoop: boolean;
|
|
9
|
+
functionName: string;
|
|
10
|
+
functionVersion: string;
|
|
11
|
+
invokedFunctionArn: string;
|
|
12
|
+
memoryLimitInMB: string;
|
|
13
|
+
awsRequestId: string;
|
|
14
|
+
logGroupName: string;
|
|
15
|
+
logStreamName: string;
|
|
16
|
+
identity?: CognitoIdentity | undefined;
|
|
17
|
+
clientContext?: ClientContext | undefined;
|
|
18
|
+
tenantId?: string | undefined;
|
|
19
|
+
|
|
20
|
+
getRemainingTimeInMillis(): number;
|
|
21
|
+
|
|
22
|
+
// Functions for compatibility with earlier Node.js Runtime v0.10.42
|
|
23
|
+
// No longer documented, so they are deprecated, but they still work
|
|
24
|
+
// as of the 12.x runtime, so they are not removed from the types.
|
|
25
|
+
|
|
26
|
+
/** @deprecated Use handler callback or promise result */
|
|
27
|
+
done(error?: Error, result?: any): void;
|
|
28
|
+
/** @deprecated Use handler callback with first argument or reject a promise result */
|
|
29
|
+
fail(error: Error | string): void;
|
|
30
|
+
/** @deprecated Use handler callback with second argument or resolve a promise result */
|
|
31
|
+
succeed(messageOrObject: any): void;
|
|
32
|
+
// Unclear what behavior this is supposed to have, I couldn't find any still extant reference,
|
|
33
|
+
// and it behaves like the above, ignoring the object parameter.
|
|
34
|
+
/** @deprecated Use handler callback or promise result */
|
|
35
|
+
succeed(message: string, object: any): void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface CognitoIdentity {
|
|
39
|
+
cognitoIdentityId: string;
|
|
40
|
+
cognitoIdentityPoolId: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ClientContext {
|
|
44
|
+
client: ClientContextClient;
|
|
45
|
+
custom?: any;
|
|
46
|
+
env: ClientContextEnv;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface ClientContextClient {
|
|
50
|
+
installationId: string;
|
|
51
|
+
appTitle: string;
|
|
52
|
+
appVersionName: string;
|
|
53
|
+
appVersionCode: string;
|
|
54
|
+
appPackageName: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface ClientContextEnv {
|
|
58
|
+
platformVersion: string;
|
|
59
|
+
platform: string;
|
|
60
|
+
make: string;
|
|
61
|
+
model: string;
|
|
62
|
+
locale: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Interface for using response streaming from AWS Lambda.
|
|
67
|
+
* To indicate to the runtime that Lambda should stream your function’s responses, you must wrap your function handler with the `awslambda.streamifyResponse()` decorator.
|
|
68
|
+
*
|
|
69
|
+
* The `streamifyResponse` decorator accepts the following additional parameter, `responseStream`, besides the default node handler parameters, `event`, and `context`.
|
|
70
|
+
* The new `responseStream` object provides a stream object that your function can write data to. Data written to this stream is sent immediately to the client. You can optionally set the Content-Type header of the response to pass additional metadata to your client about the contents of the stream.
|
|
71
|
+
*
|
|
72
|
+
* {@link https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/ AWS blog post}
|
|
73
|
+
* {@link https://docs.aws.amazon.com/lambda/latest/dg/config-rs-write-functions.html AWS documentation}
|
|
74
|
+
*
|
|
75
|
+
* @example <caption>Writing to the response stream</caption>
|
|
76
|
+
* import 'aws-lambda';
|
|
77
|
+
*
|
|
78
|
+
* export const handler = awslambda.streamifyResponse(
|
|
79
|
+
* async (event, responseStream, context) => {
|
|
80
|
+
* responseStream.setContentType("text/plain");
|
|
81
|
+
* responseStream.write("Hello, world!");
|
|
82
|
+
* responseStream.end();
|
|
83
|
+
* }
|
|
84
|
+
* );
|
|
85
|
+
*
|
|
86
|
+
* @example <caption>Using pipeline</caption>
|
|
87
|
+
* import 'aws-lambda';
|
|
88
|
+
* import { Readable } from 'stream';
|
|
89
|
+
* import { pipeline } from 'stream/promises';
|
|
90
|
+
* import zlib from 'zlib';
|
|
91
|
+
*
|
|
92
|
+
* export const handler = awslambda.streamifyResponse(
|
|
93
|
+
* async (event, responseStream, context) => {
|
|
94
|
+
* // As an example, convert event to a readable stream.
|
|
95
|
+
* const requestStream = Readable.from(Buffer.from(JSON.stringify(event)));
|
|
96
|
+
*
|
|
97
|
+
* await pipeline(requestStream, zlib.createGzip(), responseStream);
|
|
98
|
+
* }
|
|
99
|
+
* );
|
|
100
|
+
*/
|
|
101
|
+
type StreamifyHandler<TEvent = any, TResult = any> = (
|
|
102
|
+
event: TEvent,
|
|
103
|
+
responseStream: awslambda.HttpResponseStream,
|
|
104
|
+
context: Context,
|
|
105
|
+
) => TResult | Promise<TResult>;
|
|
106
|
+
|
|
107
|
+
declare global {
|
|
108
|
+
namespace awslambda {
|
|
109
|
+
class HttpResponseStream extends Writable {
|
|
110
|
+
static from(
|
|
111
|
+
writable: Writable,
|
|
112
|
+
metadata: Record<string, unknown>,
|
|
113
|
+
): HttpResponseStream;
|
|
114
|
+
setContentType: (contentType: string) => void;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Decorator for using response streaming from AWS Lambda.
|
|
119
|
+
* To indicate to the runtime that Lambda should stream your function’s responses, you must wrap your function handler with the `awslambda.streamifyResponse()` decorator.
|
|
120
|
+
*
|
|
121
|
+
* The `streamifyResponse` decorator accepts the following additional parameter, `responseStream`, besides the default node handler parameters, `event`, and `context`.
|
|
122
|
+
* The new `responseStream` object provides a stream object that your function can write data to. Data written to this stream is sent immediately to the client. You can optionally set the Content-Type header of the response to pass additional metadata to your client about the contents of the stream.
|
|
123
|
+
*
|
|
124
|
+
* {@link https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/ AWS blog post}
|
|
125
|
+
* {@link https://docs.aws.amazon.com/lambda/latest/dg/config-rs-write-functions.html AWS documentation}
|
|
126
|
+
*
|
|
127
|
+
* @example <caption>Writing to the response stream</caption>
|
|
128
|
+
* import 'aws-lambda';
|
|
129
|
+
*
|
|
130
|
+
* export const handler = awslambda.streamifyResponse(
|
|
131
|
+
* async (event, responseStream, context) => {
|
|
132
|
+
* responseStream.setContentType("text/plain");
|
|
133
|
+
* responseStream.write("Hello, world!");
|
|
134
|
+
* responseStream.end();
|
|
135
|
+
* }
|
|
136
|
+
* );
|
|
137
|
+
*
|
|
138
|
+
* @example <caption>Using pipeline</caption>
|
|
139
|
+
* import 'aws-lambda';
|
|
140
|
+
* import { Readable } from 'stream';
|
|
141
|
+
* import { pipeline } from 'stream/promises';
|
|
142
|
+
* import zlib from 'zlib';
|
|
143
|
+
*
|
|
144
|
+
* export const handler = awslambda.streamifyResponse(
|
|
145
|
+
* async (event, responseStream, context) => {
|
|
146
|
+
* // As an example, convert event to a readable stream.
|
|
147
|
+
* const requestStream = Readable.from(Buffer.from(JSON.stringify(event)));
|
|
148
|
+
*
|
|
149
|
+
* await pipeline(requestStream, zlib.createGzip(), responseStream);
|
|
150
|
+
* }
|
|
151
|
+
* );
|
|
152
|
+
*/
|
|
153
|
+
function streamifyResponse<TEvent = any, TResult = void>(
|
|
154
|
+
handler: StreamifyHandler<TEvent, TResult>,
|
|
155
|
+
): StreamifyHandler<TEvent, TResult>;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export type { Context as C };
|
|
160
|
+
//# sourceMappingURL=handler.d-CkaE-Brj.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d-CkaE-Brj.d.ts","sources":["../../../node_modules/@types/aws-lambda/handler.d.ts"],"mappings":";;AA2FA;AACA;AACA;AACA;AACO,UAAU,OAAO;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,eAAe;AAC9B,oBAAoB,aAAa;AACjC;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA,iBAAiB,KAAK;AACtB;AACA,gBAAgB,KAAK;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,UAAU,eAAe;AAChC;AACA;AACA;;AAEO,UAAU,aAAa;AAC9B,YAAY,mBAAmB;AAC/B;AACA,SAAS,gBAAgB;AACzB;;AAEO,UAAU,mBAAmB;AACpC;AACA;AACA;AACA;AACA;AACA;;AAEO,UAAU,gBAAgB;AACjC;AACA;AACA;AACA;AACA;AACA;;AAwBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAK,gBAAgB;AAC5B;AACA,oBAAoB,SAAS,CAAC,kBAAkB;AAChD,aAAa,OAAO;AACpB,eAAe,OAAO;;AAEtB;AACA;AACA,yCAAyC,QAAQ;AACjD;AACA,0BAA0B,QAAQ;AAClC,0BAA0B,MAAM;AAChC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,gBAAgB;AACrC,WAAW,gBAAgB;AAC3B;AACA;;;;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var m=Object.defineProperty;var t=(r,e)=>m(r,"name",{value:e,configurable:!0});var s=require("@kleanjs/core");const f=t(r=>{const e=r.body;if(!e)return{};try{return JSON.parse(e)}catch{return e}},"getBody"),l=t((r,e)=>s.middleware(r,{event:s.Use(),context:s.Use(),...e,transformers:{body:f,...e.transformers},errorHandler:t(n=>{throw n},"errorHandler")}),"createProcessor"),y=t((r,e={})=>{const n=l(r,e);return async(a,c)=>({batchItemFailures:(await Promise.allSettled(a.Records.map(o=>n(o,c)))).map((o,d)=>o.status==="rejected"?{itemIdentifier:a.Records[d].messageId}:null).filter(o=>o!==null)})},"middlewareParallel"),b=t((r,e={})=>{const n=l(r,e);return async(a,c)=>{const i=[];for(const u of a.Records)try{await n(u,c)}catch{i.push({itemIdentifier:u.messageId})}return{batchItemFailures:i}}},"middlewareSeries");Object.defineProperty(exports,"AJVError",{enumerable:!0,get:t(function(){return s.AJVError},"get")}),Object.defineProperty(exports,"EventError",{enumerable:!0,get:t(function(){return s.EventError},"get")}),Object.defineProperty(exports,"Use",{enumerable:!0,get:t(function(){return s.Use},"get")}),exports.middlewareParallel=y,exports.middlewareSeries=b;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { C as Context } from '../handler.d-CkaE-Brj.js';
|
|
2
|
+
import { TSchemaMap, TCombinedEvent, HandlerConfig } from '@kleanjs/core';
|
|
3
|
+
export { AJVError, EventError, Use } from '@kleanjs/core';
|
|
4
|
+
import 'node:stream';
|
|
5
|
+
|
|
6
|
+
// SQS
|
|
7
|
+
// https://docs.aws.amazon.com/lambda/latest/dg/invoking-lambda-function.html#supported-event-source-sqs
|
|
8
|
+
interface SQSRecord {
|
|
9
|
+
messageId: string;
|
|
10
|
+
receiptHandle: string;
|
|
11
|
+
body: string;
|
|
12
|
+
attributes: SQSRecordAttributes;
|
|
13
|
+
messageAttributes: SQSMessageAttributes;
|
|
14
|
+
md5OfBody: string;
|
|
15
|
+
md5OfMessageAttributes?: string;
|
|
16
|
+
eventSource: string;
|
|
17
|
+
eventSourceARN: string;
|
|
18
|
+
awsRegion: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface SQSEvent {
|
|
22
|
+
Records: SQSRecord[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface SQSRecordAttributes {
|
|
26
|
+
AWSTraceHeader?: string | undefined;
|
|
27
|
+
ApproximateReceiveCount: string;
|
|
28
|
+
SentTimestamp: string;
|
|
29
|
+
SenderId: string;
|
|
30
|
+
ApproximateFirstReceiveTimestamp: string;
|
|
31
|
+
SequenceNumber?: string | undefined;
|
|
32
|
+
MessageGroupId?: string | undefined;
|
|
33
|
+
MessageDeduplicationId?: string | undefined;
|
|
34
|
+
DeadLetterQueueSourceArn?: string | undefined; // Undocumented, but used by AWS to support their re-drive functionality in the console
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type SQSMessageAttributeDataType = "String" | "Number" | "Binary" | string;
|
|
38
|
+
|
|
39
|
+
interface SQSMessageAttribute {
|
|
40
|
+
stringValue?: string | undefined;
|
|
41
|
+
binaryValue?: string | undefined;
|
|
42
|
+
stringListValues?: string[] | undefined; // Not implemented. Reserved for future use.
|
|
43
|
+
binaryListValues?: string[] | undefined; // Not implemented. Reserved for future use.
|
|
44
|
+
dataType: SQSMessageAttributeDataType;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface SQSMessageAttributes {
|
|
48
|
+
[name: string]: SQSMessageAttribute;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html#services-sqs-batchfailurereporting
|
|
52
|
+
interface SQSBatchResponse {
|
|
53
|
+
batchItemFailures: SQSBatchItemFailure[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface SQSBatchItemFailure {
|
|
57
|
+
itemIdentifier: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
declare const middlewareParallel: <TEvent = SQSRecord, TContext = Context, TValidators extends TSchemaMap = TSchemaMap>(handler: (record: TCombinedEvent<TEvent, TValidators>, context?: TContext) => any, options?: HandlerConfig<TEvent, any, TContext, TValidators>) => (event: SQSEvent, context?: TContext) => Promise<SQSBatchResponse>;
|
|
61
|
+
declare const middlewareSeries: <TEvent = SQSRecord, TContext = Context, TValidators extends TSchemaMap = TSchemaMap>(handler: (record: TCombinedEvent<TEvent, TValidators>, context?: TContext) => any, options?: HandlerConfig<TEvent, any, TContext, TValidators>) => (event: SQSEvent, context?: TContext) => Promise<SQSBatchResponse>;
|
|
62
|
+
|
|
63
|
+
export { middlewareParallel, middlewareSeries };
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sources":["../../../../node_modules/@types/aws-lambda/trigger/sqs.d.ts","../../src/sqs/index.ts"],"mappings":";;;;;AAKA;AACA;AACO,UAAU,SAAS;AAC1B;AACA;AACA;AACA,gBAAgB,mBAAmB;AACnC,uBAAuB,oBAAoB;AAC3C;AACA;AACA;AACA;AACA;AACA;;AAEO,UAAU,QAAQ;AACzB,aAAa,SAAS;AACtB;;AAEO,UAAU,mBAAmB;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,KAAK,2BAA2B;;AAEhC,UAAU,mBAAmB;AACpC;AACA;AACA;AACA;AACA,cAAc,2BAA2B;AACzC;;AAEO,UAAU,oBAAoB;AACrC,oBAAoB,mBAAmB;AACvC;;AAEA;AACO,UAAU,gBAAgB;AACjC,uBAAuB,mBAAmB;AAC1C;;AAEO,UAAU,mBAAmB;AACpC;AACA;;ACzCA,cAAa,kBAAkB,YACpB,SAAS,aACP,OAAO,sBACE,UAAU,GAAG,UAAU,oBAEzB,cAAc,6DACvB,aAAa,iDAID,QAAQ,yBAAuB,OAAO,CAAC,gBAAgB;AAa9E,cAAa,gBAAgB,YAClB,SAAS,aACP,OAAO,sBACE,UAAU,GAAG,UAAU,oBAEzB,cAAc,6DACvB,aAAa,iDAID,QAAQ,yBAAuB,OAAO,CAAC,gBAAgB","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var u=Object.defineProperty;var t=(e,r)=>u(e,"name",{value:r,configurable:!0});import{middleware as f,Use as i}from"@kleanjs/core";import{AJVError as b,EventError as g,Use as x}from"@kleanjs/core";const p=t(e=>{const r=e.body;if(!r)return{};try{return JSON.parse(r)}catch{return r}},"getBody"),l=t((e,r)=>f(e,{event:i(),context:i(),...r,transformers:{body:p,...r.transformers},errorHandler:t(s=>{throw s},"errorHandler")}),"createProcessor"),y=t((e,r={})=>{const s=l(e,r);return async(a,c)=>({batchItemFailures:(await Promise.allSettled(a.Records.map(o=>s(o,c)))).map((o,m)=>o.status==="rejected"?{itemIdentifier:a.Records[m].messageId}:null).filter(o=>o!==null)})},"middlewareParallel"),h=t((e,r={})=>{const s=l(e,r);return async(a,c)=>{const n=[];for(const d of a.Records)try{await s(d,c)}catch{n.push({itemIdentifier:d.messageId})}return{batchItemFailures:n}}},"middlewareSeries");export{b as AJVError,g as EventError,x as Use,y as middlewareParallel,h as middlewareSeries};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kleanjs/aws-lambda",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"files": [
|
|
5
|
+
"dist"
|
|
6
|
+
],
|
|
7
|
+
"exports": {
|
|
8
|
+
"./apigateway": {
|
|
9
|
+
"types": "./dist/apigateway/index.d.ts",
|
|
10
|
+
"import": "./dist/apigateway/index.mjs",
|
|
11
|
+
"require": "./dist/apigateway/index.cjs"
|
|
12
|
+
},
|
|
13
|
+
"./sqs": {
|
|
14
|
+
"types": "./dist/sqs/index.d.ts",
|
|
15
|
+
"import": "./dist/sqs/index.mjs",
|
|
16
|
+
"require": "./dist/sqs/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "pkgroll --minify"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@kleanjs/core": "0.4.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/aws-lambda": "^8.10.159",
|
|
27
|
+
"pkgroll": "^2.21.4",
|
|
28
|
+
"typescript": "^5.9.3"
|
|
29
|
+
}
|
|
30
|
+
}
|