[aws-lambda] Some docs, split up types and tests (#42080)

* [aws-lambda] Some docs, split up index.d.ts into multiple files.

Documents handler type and conventions for adding triggers more
explicitly. The same index.d.ts docs should explain the thinking for the
new layout convention.

No changes to the type tests in this first commit, to show that the tests
still passs, and because I think they deserve more attention (and I need
lunch right now).

Most event structures have little to no changes other than re-ordering or removing
inaccurately copy/pasted comments in a case or two.

Loses history, but github doesn't support rename history anyway, and
it's even more ugly to get git to track file splits even for local
usage. Apologies for the huge diff.

* [aws-lambda] Split tests to per-service files, add contributor README.md

Updates most of the files to a consistent style.
This commit is contained in:
Simon Buchan
2020-02-14 09:18:39 -08:00
committed by GitHub
parent 4b76dba9a1
commit 186ed7ba26
43 changed files with 2863 additions and 2485 deletions
+189
View File
@@ -0,0 +1,189 @@
Types helpful for implementing handlers in the AWS Lambda NodeJS runtimes,
the handler interface and types for AWS-defined trigger sources.
Unrelated to the npm package `aws-lambda`, a CLI tool.
## Contributing
Follow all the rules for [modifying a type package](../../README.md#edit-an-existing-package),
of course, but as this package has gotten quite large, please
also follow the established conventions to keep things simple
for future contributors:
### Common types
The main entry point, [index.d.ts]() simply does `export * from "..."`
for all type declaration files in the package. Make sure if you are
adding any files for new trigger sources that you add the
re-export here; the user should only need to import from `"aws-lambda"`.
Similarly, [aws-lambda-tests.ts]() has declarations for the common type and tests
for [handler.d.ts](), while the actual service specific tests are all in [test/]()
The mentioned [handler.d.ts]() contains definitions for `Handler<TEvent, TResult>`
and its associated types like `Context` and `Callback<TResult>`,
which describe the Lambda NodeJS runtime API.
### Triggers
Each trigger-specific event structure should have a separate file in [trigger/]() based
on the service name and optionally the trigger type, if it's not a clear "default".
If multiple triggers for a service share types, the common types
should be in a file in [common/]() named for the containing service.
For a service `foo` and trigger `bar`, there should ideally be
a file `trigger/foo-bar.d.ts` containing something like:
```ts
import { Callback, Handler } from "../handler";
import { FooCommonType } from "../common/foo";
export type FooBarHandler = Handler<FooBarEvent, FooBarResult>;
export type FooBarCallback = Callback<FooBarResult>;
// or, if there is no FooBarResult:
export type FooBarHandler = Handler<FooBarEvent, void>;
export interface FooBarEvent {
// ...
}
export interface FooBarEventSpecificType {
// ...
}
export interface FooBarResult {
// ...
}
export interface FooBarResultSpecificType {
// ...
}
export interface FooBarCommonType {
// ...
}
// ...
```
As implied, all names are exported flat, try to ensure that it's clear what service
or trigger a type is for. (Note that especially the earlier types are not always
consistent with this)
### Tests
Each trigger should have a type test that exercises the type roughly as the user
would, in particular reading properties from the event, and creating each
valid result structure in general. When making any change: adding a property,
to a new trigger, also add the change to the tests.
Tests are grouped by each service in [test/](), and must also be explicitly
added to `tsconfig.json`'s `files` list (use of `include` is banned by
DefinitelyTyped at the moment).
The test file for a service `foo` with two triggers `bar` and `baz` may look like:
```ts
import {
FooBarHandler,
FooBarResult,
// ...
} from "aws-lambda";
const barHandler: FooBarHandler = async (event, context, callback) => {
// Check event type
// Declarations for e.g. strOrNull, bool are in aws-lambda-tests.ts
strOrNull = event.body;
str = event.headers[str];
str = event.multiValueHeaders[str][num];
str = event.httpMethod;
bool = event.isBase64Encoded;
// this property is of a named type, validate that:
let requestContext: FooBarEventRequestContext;
requestContext = event.requestContext;
// for each accessible property declared in FooBarEvent...
// recurse into each declared type
str = requestContext.accountId;
str = requestContext.apiId;
const authContext: AuthResponseContext | null | undefined = requestContext.authorizer;
numOrUndefined = requestContext.connectedAt;
strOrUndefined = requestContext.connectionId;
// ...
// Check result type
let result: FooBarResult;
// check minimally assignable case
result = {
statusCode: num,
body: str,
};
// check maximally assignable case
result = {
statusCode: num,
headers: {
[str]: str,
[str]: bool,
[str]: num,
},
multiValueHeaders: {
[str]: [str, bool, num],
},
isBase64Encoded: true,
body: str,
};
// check reasonable result-returning styles
callback(new Error());
callback(null, result);
return result;
};
const bazHandler: FooBazHandler = async (event, context, callback) => {
// ... as above, for each untested type
// for handlers without a result
callback();
callback(new Error());
};
...
```
Not that currently many tests have not been updated to this style.
As always, PRs welcome, but simply adding your change in the new style
is a start.
Ideally the existing test should still pass with your new change: if it doesn't that
implies that your change is incompatible with existing user code (if the
test is done correctly) This isn't always the wrong thing to do, but be
prepared to make a decently strong case for why this is an exception.
## Future ideas
* Adding JSDocs for types and properties (copied from AWS docs?). Many
triggers have unintuitive formats and requirements.
* Splitting `import { Context, FooBarHandler, FooCommonType } from "aws-lambda"` into
* `import { Context } from "@aws-lambda/runtime"` and
* `import { BarHandler, CommonType } from "@aws-lambda/foo"`
With forwarding from the current package to preserve back-compat.
This would allow not only more fine-grained dependencies, but also
support backward-incompatible changes to triggers as they could be
independently major versioned.
It's a lot of busywork to do all that renaming though, and ensuring
compatibility is kept.
* Possibly related to the above, migrating this to, or somehow in support of,
an npm package with runtime support for implementing handlers correctly.
For example, catching and formatting `ClientError` into an API Gateway
400 error, or parsing CloudWatch log payloads.
This one is much more fraught, as it by default loses all the existing
DefinitelyTyped tooling and community support (e.g. cross package typing).
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
// Used by both APIGatewayPraxyEvent and APIGatewayAuthorizerEvent
export interface APIGatewayEventRequestContext {
accountId: string;
apiId: string;
authorizer?: AuthResponseContext | null;
connectedAt?: number;
connectionId?: string;
domainName?: string;
domainPrefix?: string;
eventType?: string;
extendedRequestId?: string;
httpMethod: string;
identity: {
accessKey: string | null;
accountId: string | null;
apiKey: string | null;
apiKeyId: string | null;
caller: string | null;
cognitoAuthenticationProvider: string | null;
cognitoAuthenticationType: string | null;
cognitoIdentityId: string | null;
cognitoIdentityPoolId: string | null;
principalOrgId: string | null;
sourceIp: string;
user: string | null;
userAgent: string | null;
userArn: string | null;
};
messageDirection?: string;
messageId?: string | null;
path: string;
stage: string;
requestId: string;
requestTime?: string;
requestTimeEpoch: number;
resourceId: string;
resourcePath: string;
routeKey?: string;
}
/**
* http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html#api-gateway-custom-authorizer-output
*/
export interface AuthResponseContext {
[name: string]: any;
}
+79
View File
@@ -0,0 +1,79 @@
/**
* CloudFront events
* http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html
* Bear in mind that the "example" event structure in the page above includes
* both an S3 and a Custom origin, which is not strictly allowed. Only one
* of these per event may be present.
*/
export interface CloudFrontHeaders {
[name: string]: Array<{
key?: string;
value: string;
}>;
}
export type CloudFrontOrigin =
| { s3: CloudFrontS3Origin; custom?: never }
| { custom: CloudFrontCustomOrigin; s3?: never };
export interface CloudFrontCustomOrigin {
customHeaders: CloudFrontHeaders;
domainName: string;
keepaliveTimeout: number;
path: string;
port: number;
protocol: 'http' | 'https';
readTimeout: number;
sslProtocols: string[];
}
export interface CloudFrontS3Origin {
authMethod: 'origin-access-identity' | 'none';
customHeaders: CloudFrontHeaders;
domainName: string;
path: string;
region: string;
}
export interface CloudFrontResponse {
status: string;
statusDescription: string;
headers: CloudFrontHeaders;
}
export interface CloudFrontRequest {
body?: {
action: 'read-only' | 'replace';
data: string;
encoding: 'base64' | 'text';
readonly inputTruncated: boolean;
};
readonly clientIp: string;
readonly method: string;
uri: string;
querystring: string;
headers: CloudFrontHeaders;
origin?: CloudFrontOrigin;
}
export interface CloudFrontEvent {
config: {
readonly distributionDomainName: string;
readonly distributionId: string;
} & (
| { readonly eventType: 'origin-request' | 'origin-response' }
| { readonly eventType: 'viewer-request' | 'viewer-response'; readonly requestId: string });
}
/**
* Generated HTTP response in viewer request event or origin request event
*
* https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-generating-http-responses-in-requests.html#lambda-generating-http-responses-object
*/
export interface CloudFrontResultResponse {
status: string;
statusDescription?: string;
headers?: CloudFrontHeaders;
bodyEncoding?: 'text' | 'base64';
body?: string;
}
+171
View File
@@ -0,0 +1,171 @@
/**
* The interface that AWS Lambda will invoke your handler with.
* There are more specialized types for many cases where AWS services
* invoke your lambda, but you can directly use this type for when you are invoking
* your lambda directly.
*
* See tme {@link http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html AWS documentation}
* for more information about the runtime behavior, and the
* {@link https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/ AWS Blog post}
* introducing the async handler behavior in the 8.10 runtime.
*
* @example <caption>Defining a custom handler type</caption>
* import { Handler } from 'aws-lambda'
*
* interface NameEvent {
* fullName: string
* }
* interface NameResult {
* firstName: string
* middleNames: string
* lastName: string
* }
* type PersonHandler = Handler<NameEvent, NameResult>
*
* export const handler: PersonHandler = async (event) => {
* const names = event.fullName.split(' ')
* const firstName = names.shift()
* const lastName = names.pop()
* return { firstName, middleNames: names, lastName }
* }
*
* @example <caption>Logs the contents of the event object and returns the location of the logs</caption>
* import { Handler } from 'aws-lambda'
*
* export const handler: Handler = async (event, context) => {
* console.log("EVENT: \n" + JSON.stringify(event, null, 2))
* return context.logStreamName
* }
*
* @example <caption>AWS SDK with Async Function and Promises</caption>
* import { Handler } from 'aws-lambda'
* import AWS from 'aws-sdk'
*
* const s3 = new AWS.S3()
*
* export const handler: Handler = async (event) => {
* const response = await s3.listBuckets().promise()
* return response?.Buckets.map((bucket) => bucket.Name)
* }
*
* @example <caption>HTTP Request with Callback</caption>
* import { Handler } from 'aws-lambda'
* import https from 'https'
*
* let url = "https://docs.aws.amazon.com/lambda/latest/dg/welcome.html"
*
* export const handler: Handler<void, number> = (event, context, callback) => {
* https.get(url, (res) => {
* callback(null, res.statusCode)
* }).on('error', (e) => {
* callback(Error(e))
* })
* }
*
* @param event
* Parsed JSON data in the lambda request payload. For an AWS service triggered
* lambda this should be in the format of a type ending in Event, for example the
* S3Handler receives an event of type S3Event.
* @param context
* Runtime contextual information of the current invocation, for example the caller
* identity, available memory and time remaining, legacy completion callbacks, and
* a mutable property controlling when the lambda execution completes.
* @param callback
* NodeJS-style completion callback that the AWS Lambda runtime will provide that can
* be used to provide the lambda result payload value, or any execution error. Can
* instead return a promise that resolves with the result payload value or rejects
* with the execution error.
* @return
* A promise that resolves with the lambda result payload value, or rejects with the
* execution error. Note that if you implement your handler as an async function,
* you will automatically return a promise that will resolve with a returned value,
* or reject with a thrown value.
*/
export type Handler<TEvent = any, TResult = any> = (
event: TEvent,
context: Context,
callback: Callback<TResult>,
) => void | Promise<TResult>;
/**
* {@link Handler} context parameter.
* See {@link https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html AWS documentation}.
*/
export interface Context {
callbackWaitsForEmptyEventLoop: boolean;
functionName: string;
functionVersion: string;
invokedFunctionArn: string;
memoryLimitInMB: string;
awsRequestId: string;
logGroupName: string;
logStreamName: string;
identity?: CognitoIdentity;
clientContext?: ClientContext;
getRemainingTimeInMillis(): number;
// Functions for compatibility with earlier Node.js Runtime v0.10.42
// No longer documented, so they are deprecated, but they still work
// as of the 12.x runtime, so they are not removed from the types.
/** @deprecated Use handler callback or promise result */
done(error?: Error, result?: any): void;
/** @deprecated Use handler callback with first argument or reject a promise result */
fail(error: Error | string): void;
/** @deprecated Use handler callback with second argument or resolve a promise result */
succeed(messageOrObject: any): void;
// Unclear what behavior this is supposed to have, I couldn't find any still extant reference,
// and it behaves like the above, ignoring the object parameter.
/** @deprecated Use handler callback or promise result */
succeed(message: string, object: any): void;
}
export interface CognitoIdentity {
cognitoIdentityId: string;
cognitoIdentityPoolId: string;
}
export interface ClientContext {
client: ClientContextClient;
Custom?: any;
env: ClientContextEnv;
}
export interface ClientContextClient {
installationId: string;
appTitle: string;
appVersionName: string;
appVersionCode: string;
appPackageName: string;
}
export interface ClientContextEnv {
platformVersion: string;
platform: string;
make: string;
model: string;
locale: string;
}
/**
* NodeJS-style callback parameter for the {@link Handler} type.
* Can be used instead of returning a promise, see the
* {@link https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html AWS documentation}
* for the handler programming model.
*
* @param error
* Parameter to use to provide the error payload for a failed lambda execution.
* See {@link https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-mode-exceptions.html AWS documentation}
* for error handling.
* If an Error instance is passed, the error payload uses the `name` property as the `errorType`,
* the `message` property as the `errorMessage`, and parses the `stack` property string into
* the `trace` array.
* For other values, the `errorType` is `typeof value`, the `errorMessage` is `String(value)`, and
* `trace` is an empty array.
*
* @param result
* Parameter to use to provide the result payload for a successful lambda execution.
* Pass `null` or `undefined` for the `error` parameter to use this parameter.
*/
export type Callback<TResult = any> = (error?: Error | string | null, result?: TResult) => void;
+37 -1167
View File
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
import { ALBHandler, ALBResult } from "aws-lambda";
const handler: ALBHandler = async (event, context, callback) => {
str = event.httpMethod;
str = event.path;
str = event.queryStringParameters![str];
str = event.headers![str];
str = event.multiValueQueryStringParameters![str][num];
str = event.multiValueHeaders![str][num];
strOrNull = event.body;
bool = event.isBase64Encoded;
str = event.requestContext.elb.targetGroupArn;
let result: ALBResult = {
statusCode: num,
statusDescription: str,
isBase64Encoded: bool,
};
result = {
statusCode: num,
statusDescription: str,
headers: { [str]: boolOrNumOrStr },
multiValueHeaders: { [str]: [boolOrNumOrStr] },
body: str,
isBase64Encoded: bool,
};
callback(new Error());
callback(null, result);
return result;
};
+186
View File
@@ -0,0 +1,186 @@
import {
APIGatewayEvent,
APIGatewayEventRequestContext,
APIGatewayProxyHandler,
APIGatewayProxyResult,
AuthResponseContext,
Context,
CustomAuthorizerHandler,
CustomAuthorizerResult,
PolicyDocument,
ProxyHandler,
ProxyCallback,
Statement,
} from "aws-lambda";
let proxyHandler: APIGatewayProxyHandler = async (event, context, callback) => {
strOrNull = event.body;
str = event.headers['example'];
str = event.multiValueHeaders['example'][0];
str = event.httpMethod;
bool = event.isBase64Encoded;
str = event.path;
str = event.pathParameters!['example'];
str = event.queryStringParameters!['example'];
str = event.multiValueQueryStringParameters!['example'][0];
str = event.stageVariables!['example'];
let requestContext: APIGatewayEventRequestContext;
requestContext = event.requestContext;
str = event.resource;
str = requestContext.accountId;
str = requestContext.apiId;
const authContext: AuthResponseContext | null | undefined = requestContext.authorizer;
numOrUndefined = requestContext.connectedAt;
strOrUndefined = requestContext.connectionId;
strOrUndefined = requestContext.domainName;
strOrUndefined = requestContext.eventType;
strOrUndefined = requestContext.extendedRequestId;
str = requestContext.httpMethod;
strOrNull = requestContext.identity.accessKey;
strOrNull = requestContext.identity.accountId;
strOrNull = requestContext.identity.apiKey;
strOrNull = requestContext.identity.apiKeyId;
strOrNull = requestContext.identity.caller;
strOrNull = requestContext.identity.cognitoAuthenticationProvider;
strOrNull = requestContext.identity.cognitoAuthenticationType;
strOrNull = requestContext.identity.cognitoIdentityId;
strOrNull = requestContext.identity.cognitoIdentityPoolId;
strOrNull = requestContext.identity.principalOrgId;
str = requestContext.identity.sourceIp;
strOrNull = requestContext.identity.user;
strOrNull = requestContext.identity.userAgent;
strOrNull = requestContext.identity.userArn;
strOrUndefined = requestContext.messageDirection;
strOrUndefinedOrNull = requestContext.messageId;
str = requestContext.path;
str = requestContext.stage;
str = requestContext.requestId;
strOrUndefined = requestContext.requestTime;
str = requestContext.resourceId;
str = requestContext.resourcePath;
strOrUndefined = requestContext.routeKey;
let result: APIGatewayProxyResult = {
statusCode: num,
body: str,
};
result = {
statusCode: num,
headers: {
[str]: str,
[str]: bool,
[str]: num,
},
multiValueHeaders: {
[str]: [str, bool, num],
},
isBase64Encoded: true,
body: str,
};
callback(new Error());
callback(null, result);
return result;
};
const authorizerHandler: CustomAuthorizerHandler = async (event, context, callback) => {
str = event.type;
str = event.methodArn;
strOrUndefined = event.authorizationToken;
strOrUndefined = event.resource;
strOrUndefined = event.path;
strOrUndefined = event.httpMethod;
str = event.headers![str];
str = event.multiValueHeaders![str][num];
str = event.pathParameters![str];
str = event.queryStringParameters![str];
str = event.multiValueQueryStringParameters![str][num];
str = event.stageVariables![str];
let requestContext: APIGatewayEventRequestContext;
requestContext = event.requestContext!;
strOrUndefined = event.domainName;
strOrUndefined = event.apiId;
let statement: Statement = {
Action: str,
Effect: str,
Resource: str,
};
// $ExpectError
statement = { Effect: str, Action: str, Principal: 123, };
// Bad Resource
// $ExpectError
statement = { Effect: str, Action: str, Resource: 123, };
// Bad Resource with valid Principal
// $ExpectError
statement = { Effect: str, Action: str, Principal: { Service: str }, Resource: 123, };
// Bad principal with valid Resource
// $ExpectError
statement = { Effect: str, Action: str, Principal: 123, Resource: str, };
// No Effect
// $ExpectError
statement = { Action: str, Principal: str };
statement = {
Sid: str,
Action: [str, str],
Effect: str,
Resource: [str, str],
Condition: {
condition1: { key: 'value' },
condition2: [
{
key1: 'value',
key2: 'value',
},
{
key3: 'value',
},
],
},
Principal: [str, str],
NotPrincipal: [str, str],
};
statement = { Action: str, Principal: str, Effect: str };
statement = { Action: str, NotPrincipal: { Service: str }, Effect: str };
statement = { Effect: str, NotAction: str, NotResource: str };
let policyDocument: PolicyDocument = { Version: str, Statement: [statement] };
policyDocument = { Version: str, Statement: [statement, statement] };
const authResponseContext: AuthResponseContext = {
stringKey: str,
numberKey: num,
booleanKey: bool,
};
let result: CustomAuthorizerResult = {
principalId: str,
policyDocument,
context: authResponseContext,
};
result = {
principalId: str,
policyDocument,
};
callback(new Error());
callback(null, result);
return result;
};
// Test old names
const oldNameProxyHandler: ProxyHandler = (event: APIGatewayEvent, context: Context, cb: ProxyCallback) => {};
proxyHandler = oldNameProxyHandler;
@@ -0,0 +1,74 @@
import {
CloudFormationCustomResourceFailedResponse,
CloudFormationCustomResourceHandler,
CloudFormationCustomResourceResponse, CloudFormationCustomResourceSuccessResponse,
} from "aws-lambda";
const handler: CloudFormationCustomResourceHandler = async (event, context, callback) => {
switch (event.RequestType) {
case 'Create':
str = event.LogicalResourceId;
str = event.RequestId;
anyObj = event.ResourceProperties;
str = event.ResourceProperties.ServiceToken;
str = event.ResourceType;
str = event.ResponseURL;
str = event.ServiceToken;
str = event.StackId;
break;
case 'Update':
anyObj = event.OldResourceProperties;
break;
case 'Delete':
str = event.PhysicalResourceId;
break;
}
let response: CloudFormationCustomResourceResponse;
response = {
Data: {
[str]: anyObj,
},
LogicalResourceId: str,
PhysicalResourceId: str,
Reason: strOrUndefined,
RequestId: str,
StackId: str,
Status: "SUCCESS",
NoEcho: boolOrUndefined,
};
let successResponse: CloudFormationCustomResourceSuccessResponse;
let failedResponse: CloudFormationCustomResourceFailedResponse;
successResponse = {
LogicalResourceId: str,
PhysicalResourceId: str,
RequestId: str,
StackId: str,
Status: "SUCCESS",
};
successResponse = {
Data: anyObj,
LogicalResourceId: str,
PhysicalResourceId: str,
Reason: strOrUndefined,
RequestId: str,
StackId: str,
Status: "SUCCESS",
NoEcho: boolOrUndefined,
};
failedResponse = {
Data: anyObj,
LogicalResourceId: str,
PhysicalResourceId: str,
Reason: str,
RequestId: str,
StackId: str,
Status: "FAILED",
};
response = successResponse;
response = failedResponse;
callback();
callback(new Error());
};
+279
View File
@@ -0,0 +1,279 @@
import {
CloudFrontHeaders,
CloudFrontRequestEvent,
CloudFrontRequestHandler,
CloudFrontRequestResult,
CloudFrontResponseEvent,
CloudFrontResponseHandler,
CloudFrontResponseResult,
CloudFrontS3Origin,
CloudFrontCustomOrigin,
} from "aws-lambda";
// TODO: Update test to read all event properties, and write all result
// properties, like the user will.
const cloudFrontHeaders: CloudFrontHeaders = {
'content-type': [{ value: 'text/plain' }],
'x-foo-bar': [{ key: 'X-Foo-Bar', value: 'example' }],
};
const requestHandler: CloudFrontRequestHandler = async (event, context, cb) => {
event = requestWithCustomOriginEvent;
// $ExpectType CloudFrontRequestEvent
event;
let request = event.Records[0].cf.request;
let s3Origin: CloudFrontS3Origin = {
authMethod: 'none',
customHeaders: {},
domainName: 'example.com',
path: '/',
region: 'us-east-1',
};
if (request.origin && request.origin.custom) {
request.origin.custom.domainName;
request.origin.custom.domainName = 'example2.com';
// $ExpectError
s3Origin = request.origin.s3;
// $ExpectError
request.origin.s3.path = '/';
}
let customOrigin: CloudFrontCustomOrigin = {
customHeaders: {},
domainName: 'example.com',
keepaliveTimeout: 60,
path: '/',
port: 80,
protocol: 'http',
readTimeout: 30,
sslProtocols: [],
};
event = requestWithS3OriginEvent;
// $ExpectType CloudFrontRequestEvent
event;
request = event.Records[0].cf.request;
if (request.origin && request.origin.s3) {
request.origin.s3.path;
request.origin.s3.path = '/new_path';
// $ExpectError
customOrigin = request.origin.custom;
// $ExpectError
request.origin.custom.path = '/';
}
let result: CloudFrontRequestResult;
// Result can be either nullish (use current request), a replaced request, or an immediate response
result = undefined;
result = null;
result = { clientIp: str, method: str, uri: str, querystring: str, headers: cloudFrontHeaders };
result = { status: str };
result = { status: str, statusDescription: str, headers: cloudFrontHeaders, bodyEncoding: "text", body: str };
// $ExpectError
result = {};
cb(new Error());
cb(null, result);
return result;
};
const responseHandler: CloudFrontResponseHandler = async (event, context, callback) => {
let result: CloudFrontResponseResult;
// Result can be either nullish (use current response) or a replaced response, but not a request
result = undefined;
result = null;
result = { status: str };
// $ExpectError
result = { clientIp: str, method: str, uri: str, querystring: str, headers: cloudFrontHeaders };
result = { status: str, statusDescription: str, headers: cloudFrontHeaders, bodyEncoding: "text", body: str };
result = { status: str, bodyEncoding: "base64", body: str };
// $ExpectError
result = { status: str, bodyEncoding: "invalid-encoding", body: str };
callback(new Error());
callback(null, result);
return result;
};
/* CloudFront events, see http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html */
const requestWithCustomOriginEvent: CloudFrontRequestEvent = {
Records: [
{
cf: {
config: {
distributionDomainName: 'd123.cloudfront.net',
distributionId: 'EDFDVBD6EXAMPLE',
eventType: 'viewer-request',
requestId: 'MRVMF7KydIvxMWfJIglgwHQwZsbG2IhRJ07sn9AkKUFSHS9EXAMPLE==',
},
request: {
body: {
action: 'read-only',
data: 'eyJ1c2VybmFtZSI6IkxhbWJkYUBFZGdlIiwiY29tbWVudCI6IlRoaXMgaXMgcmVxdWVzdCBib2R5In0=',
encoding: 'base64',
inputTruncated: false,
},
clientIp: '2001:0db8:85a3:0:0:8a2e:0370:7334',
querystring: 'size=large',
uri: '/picture.jpg',
method: 'GET',
headers: {
host: [
{
key: 'Host',
value: 'd111111abcdef8.cloudfront.net',
},
],
'user-agent': [
{
key: 'User-Agent',
value: 'curl/7.51.0',
},
],
},
origin: {
custom: {
customHeaders: {
'my-origin-custom-header': [
{
key: 'My-Origin-Custom-Header',
value: 'Test',
},
],
},
domainName: 'example.com',
keepaliveTimeout: 5,
path: '/custom_path',
port: 443,
protocol: 'https',
readTimeout: 5,
sslProtocols: ['TLSv1', 'TLSv1.1'],
},
},
},
},
},
],
};
const requestWithS3OriginEvent: CloudFrontRequestEvent = {
Records: [
{
cf: {
config: {
distributionDomainName: 'd123.cloudfront.net',
distributionId: 'EDFDVBD6EXAMPLE',
eventType: 'viewer-request',
requestId: 'MRVMF7KydIvxMWfJIglgwHQwZsbG2IhRJ07sn9AkKUFSHS9EXAMPLE==',
},
request: {
body: {
action: 'read-only',
data: 'eyJ1c2VybmFtZSI6IkxhbWJkYUBFZGdlIiwiY29tbWVudCI6IlRoaXMgaXMgcmVxdWVzdCBib2R5In0=',
encoding: 'base64',
inputTruncated: false,
},
clientIp: '2001:0db8:85a3:0:0:8a2e:0370:7334',
querystring: 'size=large',
uri: '/picture.jpg',
method: 'GET',
headers: {
host: [
{
key: 'Host',
value: 'd111111abcdef8.cloudfront.net',
},
],
'user-agent': [
{
key: 'User-Agent',
value: 'curl/7.51.0',
},
],
},
origin: {
s3: {
authMethod: 'origin-access-identity',
customHeaders: {
'my-origin-custom-header': [
{
key: 'My-Origin-Custom-Header',
value: 'Test',
},
],
},
domainName: 'my-bucket.s3.amazonaws.com',
path: '/s3_path',
region: 'us-east-1',
},
},
},
},
},
],
};
const responseEvent: CloudFrontResponseEvent = {
Records: [
{
cf: {
config: {
distributionDomainName: 'd123.cloudfront.net',
distributionId: 'EDFDVBD6EXAMPLE',
eventType: 'viewer-response',
requestId: 'xGN7KWpVEmB9Dp7ctcVFQC4E-nrcOcEKS3QyAez--06dV7TEXAMPLE==',
},
request: {
clientIp: '2001:0db8:85a3:0:0:8a2e:0370:7334',
method: 'GET',
uri: '/picture.jpg',
querystring: 'size=large',
headers: {
host: [
{
key: 'Host',
value: 'd111111abcdef8.cloudfront.net',
},
],
'user-agent': [
{
key: 'User-Agent',
value: 'curl/7.18.1',
},
],
},
},
response: {
status: '200',
statusDescription: 'OK',
headers: {
server: [
{
key: 'Server',
value: 'MyCustomOrigin',
},
],
'set-cookie': [
{
key: 'Set-Cookie',
value: 'theme=light',
},
{
key: 'Set-Cookie',
value: 'sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT',
},
],
},
},
},
},
],
};
+45
View File
@@ -0,0 +1,45 @@
/// <reference types="node" />
import {
CloudWatchLogsDecodedData,
CloudWatchLogsHandler,
CloudWatchLogsLogEvent,
ScheduledHandler,
} from "aws-lambda";
import { gunzipSync } from "zlib";
const logsHandler: CloudWatchLogsHandler = async (event, context, callback) => {
const data: CloudWatchLogsDecodedData = JSON.parse(
gunzipSync(Buffer.from(event.awslogs.data, "base64")).toString()
);
str = data.owner;
str = data.logGroup;
str = data.logStream;
str = data.subscriptionFilters[0];
str = data.messageType;
const logEvent: CloudWatchLogsLogEvent = data.logEvents[0];
str = logEvent.id;
num = logEvent.timestamp;
str = logEvent.message;
str = logEvent.extractedFields!['example'];
callback();
callback(new Error());
};
// Technically part of cloudwatch
const scheduledHandler: ScheduledHandler = async (event, context, callback) => {
str = event.account;
anyObj = event.detail;
str = event.id;
str = event.region;
str = event.resources[0];
str = event.source;
str = event.time;
callback();
callback(new Error());
};
@@ -0,0 +1,77 @@
import { CodePipelineCloudWatchEvent, CodePipelineEvent } from "aws-lambda";
// TODO
/* CodePipeline events https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html#actions-invoke-lambda-function-json-event-example */
const CodePipelineEvent: CodePipelineEvent = {
'CodePipeline.job': {
id: '11111111-abcd-1111-abcd-111111abcdef',
accountId: '111111111111',
data: {
actionConfiguration: {
configuration: {
FunctionName: 'MyLambdaFunctionForAWSCodePipeline',
UserParameters: 'some-input-such-as-a-URL',
},
},
inputArtifacts: [
{
location: {
s3Location: {
bucketName:
'the name of the bucket configured as the pipeline artifact store in Amazon S3, for example codepipeline-us-east-2-1234567890',
objectKey: 'the name of the application, for example CodePipelineDemoApplication.zip',
},
type: 'S3',
},
revision: null,
name: 'ArtifactName',
},
],
outputArtifacts: [],
artifactCredentials: {
secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
sessionToken: `MIICiTCCAfICCQD6m7oRw0uXOjANBgkqhkiG9w
0BAQUFADCBiDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZ
WF0dGxlMQ8wDQYDVQQKEwZBbWF6b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIw
EAYDVQQDEwlUZXN0Q2lsYWMxHzAdBgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5
jb20wHhcNMTEwNDI1MjA0NTIxWhcNMTIwNDI0MjA0NTIxWjCBiDELMAkGA1UEBh
MCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBb
WF6b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMx
HzAdBgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5jb20wgZ8wDQYJKoZIhvcNAQE
BBQADgY0AMIGJAoGBAMaK0dn+a4GmWIWJ21uUSfwfEvySWtC2XADZ4nB+BLYgVI
k60CpiwsZ3G93vUEIO3IyNoH/f0wYK8m9TrDHudUZg3qX4waLG5M43q7Wgc/MbQ
ITxOUSQv7c7ugFFDzQGBzZswY6786m86gpEIbb3OhjZnzcvQAaRHhdlQWIMm2nr
AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAtCu4nUhVVxYUntneD9+h8Mg9q6q+auN
KyExzyLwaxlAoo7TJHidbtS4J5iNmZgXL0FkbFFBjvSfpJIlJ00zbhNYS5f6Guo
EDmFJl0ZxBHjJnyp378OD8uTs7fLvjx79LjSTbNYiytVbZPQUQ5Yaxu2jXnimvw
3rrszlaEXAMPLE=`,
accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
},
continuationToken: 'A continuation token if continuing job',
},
},
};
CodePipelineEvent['CodePipeline.job'].data.encryptionKey = { type: 'KMS', id: 'key' };
/* CodePipeline CloudWatch Events
* see https://docs.aws.amazon.com/codepipeline/latest/userguide/detect-state-changes-cloudwatch-events.html
* Their documentation says that detail.version is a string, but it is actually an integer
*/
const CodePipelineCloudWatchEvent: CodePipelineCloudWatchEvent = {
version: '0',
id: 'event_Id',
'detail-type': 'CodePipeline Pipeline Execution State Change',
source: 'aws.codepipeline',
account: 'Pipeline_Account',
time: 'TimeStamp',
region: 'us-east-1',
resources: ['arn:aws:codepipeline:us-east-1:account_ID:myPipeline'],
detail: {
pipeline: 'myPipeline',
version: 1,
state: 'STARTED',
'execution-id': 'execution_Id',
},
};
+114
View File
@@ -0,0 +1,114 @@
// TODO: Update test to read all event properties, and write all result
// properties, like the user will.
import { CognitoUserPoolTriggerHandler } from "aws-lambda";
const handler: CognitoUserPoolTriggerHandler = async (event, context, callback) => {
num = event.version;
event.triggerSource === 'PreSignUp_SignUp';
event.triggerSource === 'PreSignUp_ExternalProvider';
event.triggerSource === 'PostConfirmation_ConfirmSignUp';
event.triggerSource === 'PreAuthentication_Authentication';
event.triggerSource === 'PostAuthentication_Authentication';
event.triggerSource === 'CustomMessage_SignUp';
event.triggerSource === 'CustomMessage_AdminCreateUser';
event.triggerSource === 'CustomMessage_ResendCode';
event.triggerSource === 'CustomMessage_ForgotPassword';
event.triggerSource === 'CustomMessage_UpdateUserAttribute';
event.triggerSource === 'CustomMessage_VerifyUserAttribute';
event.triggerSource === 'CustomMessage_Authentication';
event.triggerSource === 'DefineAuthChallenge_Authentication';
event.triggerSource === 'CreateAuthChallenge_Authentication';
event.triggerSource === 'VerifyAuthChallengeResponse_Authentication';
event.triggerSource === 'PreSignUp_AdminCreateUser';
event.triggerSource === 'PostConfirmation_ConfirmForgotPassword';
event.triggerSource === 'TokenGeneration_HostedAuth';
event.triggerSource === 'TokenGeneration_Authentication';
event.triggerSource === 'TokenGeneration_NewPasswordChallenge';
event.triggerSource === 'TokenGeneration_AuthenticateDevice';
event.triggerSource === 'TokenGeneration_RefreshTokens';
event.triggerSource === 'UserMigration_Authentication';
event.triggerSource === 'UserMigration_ForgotPassword';
// $ExpectError
event.triggerSource === 'NoSuch_Trigger';
str = event.region;
str = event.userPoolId;
strOrUndefined = event.userName;
str = event.callerContext.awsSdkVersion;
str = event.callerContext.clientId;
str = event.request.userAttributes['email'];
str = event.request.validationData!['k1'];
strOrUndefined = event.request.codeParameter;
strOrUndefined = event.request.linkParameter;
strOrUndefined = event.request.usernameParameter;
boolOrUndefined = event.request.newDeviceUsed;
event.request.session![0].challengeName === 'CUSTOM_CHALLENGE';
event.request.session![0].challengeName === 'PASSWORD_VERIFIER';
event.request.session![0].challengeName === 'SMS_MFA';
event.request.session![0].challengeName === 'DEVICE_SRP_AUTH';
event.request.session![0].challengeName === 'DEVICE_PASSWORD_VERIFIER';
event.request.session![0].challengeName === 'ADMIN_NO_SRP_AUTH';
bool = event.request.session![0].challengeResult;
strOrUndefined = event.request.session![0].challengeMetadata;
strOrUndefined = event.request.challengeName;
str = event.request.privateChallengeParameters!['answer'];
str = event.request.challengeAnswer!;
strOrUndefined = event.request.password;
boolOrUndefined = event.response.answerCorrect;
strOrUndefined = event.response.smsMessage;
strOrUndefined = event.response.emailMessage;
strOrUndefined = event.response.emailSubject;
strOrUndefined = event.response.challengeName;
boolOrUndefined = event.response.issueTokens;
boolOrUndefined = event.response.failAuthentication;
str = event.response.publicChallengeParameters!['captchaUrl'];
str = event.response.privateChallengeParameters!['answer'];
strOrUndefined = event.response.challengeMetadata;
boolOrUndefined = event.response.answerCorrect;
str = event.response.userAttributes!['username'];
event.response.finalUserStatus === 'CONFIRMED';
event.response.finalUserStatus === 'RESET_REQUIRED';
event.response.messageAction === 'SUPPRESS';
event.response.desiredDeliveryMediums === ['EMAIL'];
event.response.desiredDeliveryMediums === ['SMS'];
event.response.desiredDeliveryMediums === ['SMS', 'EMAIL'];
boolOrUndefined = event.response.forceAliasCreation;
// From AWS examples
event.response = {
claimsOverrideDetails: {
claimsToAddOrOverride: {
attribute_key2: 'attribute_value2',
attribute_key: 'attribute_value',
},
claimsToSuppress: ['email'],
},
};
event.response = {
claimsOverrideDetails: {
claimsToAddOrOverride: {
attribute_key2: 'attribute_value2',
attribute_key: 'attribute_value',
},
claimsToSuppress: ['email'],
groupOverrideDetails: {
groupsToOverride: ['group-A', 'group-B', 'group-C'],
iamRolesToOverride: [
'arn:aws:iam::XXXXXXXXXXXX:role/sns_callerA',
'arn:aws:iam::XXXXXXXXX:role/sns_callerB',
'arn:aws:iam::XXXXXXXXXX:role/sns_callerC',
],
preferredRole: 'arn:aws:iam::XXXXXXXXXXX:role/sns_caller',
},
},
};
event.response.claimsOverrideDetails!.groupOverrideDetails = null;
callback(new Error());
callback(null, event);
callback(null, {
response: event.response,
});
return event;
};
+98
View File
@@ -0,0 +1,98 @@
import { DynamoDBStreamEvent } from "aws-lambda";
// TODO: Update test to read all event properties, and write all result
// properties, like the user will.
const event: DynamoDBStreamEvent = {
Records: [
{
eventID: '1',
eventVersion: '1.0',
dynamodb: {
Keys: {
Id: {
N: '101',
},
},
NewImage: {
Message: {
S: 'New item!',
},
Id: {
N: '101',
},
},
StreamViewType: 'NEW_AND_OLD_IMAGES',
SequenceNumber: '111',
SizeBytes: 26,
},
awsRegion: 'us-west-2',
eventName: 'INSERT',
eventSourceARN:
'arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899',
eventSource: 'aws:dynamodb',
},
{
eventID: '2',
eventVersion: '1.0',
dynamodb: {
OldImage: {
Message: {
S: 'New item!',
},
Id: {
N: '101',
},
},
SequenceNumber: '222',
Keys: {
Id: {
N: '101',
},
},
SizeBytes: 59,
NewImage: {
Message: {
S: 'This item has changed',
},
Id: {
N: '101',
},
},
StreamViewType: 'NEW_AND_OLD_IMAGES',
},
awsRegion: 'us-west-2',
eventName: 'MODIFY',
eventSourceARN:
'arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899',
eventSource: 'aws:dynamodb',
},
{
eventID: '3',
eventVersion: '1.0',
dynamodb: {
Keys: {
Id: {
N: '101',
},
},
SizeBytes: 38,
SequenceNumber: '333',
OldImage: {
Message: {
S: 'This item has changed',
},
Id: {
N: '101',
},
},
StreamViewType: 'NEW_AND_OLD_IMAGES',
},
awsRegion: 'us-west-2',
eventName: 'REMOVE',
eventSourceARN:
'arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899',
eventSource: 'aws:dynamodb',
},
],
};
+50
View File
@@ -0,0 +1,50 @@
import {
FirehoseRecordTransformationStatus,
FirehoseTransformationHandler, FirehoseTransformationResult,
KinesisStreamHandler,
KinesisStreamRecord,
KinesisStreamRecordPayload,
} from "aws-lambda";
const handler: KinesisStreamHandler = async (event, context, callback) => {
let kinesisStreamRecord: KinesisStreamRecord;
let kinesisStreamRecordPayload: KinesisStreamRecordPayload;
kinesisStreamRecord = event.Records[num];
str = kinesisStreamRecord.awsRegion;
str = kinesisStreamRecord.eventID;
str = kinesisStreamRecord.eventName;
str = kinesisStreamRecord.eventSource;
str = kinesisStreamRecord.eventSourceARN;
str = kinesisStreamRecord.eventVersion;
str = kinesisStreamRecord.invokeIdentityArn;
kinesisStreamRecordPayload = kinesisStreamRecord.kinesis;
num = kinesisStreamRecordPayload.approximateArrivalTimestamp;
str = kinesisStreamRecordPayload.data;
str = kinesisStreamRecordPayload.kinesisSchemaVersion;
str = kinesisStreamRecordPayload.partitionKey;
str = kinesisStreamRecordPayload.sequenceNumber;
callback();
callback(new Error());
};
const firehoseHandler: FirehoseTransformationHandler = async (event, context, callback) => {
str = event.records[0].recordId;
const result: FirehoseTransformationResult = {
records: [
{
recordId: event.records[0].recordId,
result: 'Ok' as FirehoseRecordTransformationStatus,
data: 'eyJmb28iOiJiYXIifQ==',
},
],
};
callback(new Error());
callback(null, result);
return result;
};
+122
View File
@@ -0,0 +1,122 @@
import {
LexDialogAction,
LexDialogActionBase,
LexDialogActionClose,
LexDialogActionConfirmIntent,
LexDialogActionDelegate,
LexDialogActionElicitIntent,
LexDialogActionElicitSlot,
LexEvent,
LexGenericAttachment,
LexHandler,
LexResult,
} from "aws-lambda";
// TODO: Update test to read all event properties, and write all result
// properties, like the user will.
const handler: LexHandler = async (event, context, callback) => {
lexEvent = event;
let result: LexResult;
result = {
dialogAction: lexDialogAction,
};
result = {
sessionAttributes: {
attrib1: 'Value One',
},
dialogAction: {
type: 'Close',
fulfillmentState: 'Failed',
},
};
callback(new Error());
callback(null, result);
return result;
};
declare let lexEvent: LexEvent;
lexEvent = {
currentIntent: {
name: 'intent-name',
slots: {
slot1: null,
slot2: 'value2',
},
slotDetails: {
slot1: {
resolutions: [{ value: 'value1' }],
originalValue: 'originalValue',
},
},
confirmationStatus: 'None',
},
bot: {
name: 'bot name',
alias: 'bot alias',
version: 'bot version',
},
userId: 'User ID specified in the POST request to Amazon Lex.',
inputTranscript: 'Text used to process the request',
invocationSource: 'FulfillmentCodeHook',
outputDialogMode: 'Text',
messageVersion: '1.0',
sessionAttributes: {
key1: 'value1',
key2: 'value2',
},
requestAttributes: {
key1: 'value1',
key2: 'value2',
},
};
declare let lexDialogAction: LexDialogAction;
declare let lexDialogActionBase: LexDialogActionBase;
declare let lexDialogActionClose: LexDialogActionClose;
declare let lexDialogActionConfirmIntent: LexDialogActionConfirmIntent;
declare let lexDialogActionDelegate: LexDialogActionDelegate;
declare let lexDialogActionElicitIntent: LexDialogActionElicitIntent;
declare let lexDialogActionElicitSlot: LexDialogActionElicitSlot;
declare let lexGenericAttachment: LexGenericAttachment;
str = lexGenericAttachment.title;
str = lexGenericAttachment.subTitle;
str = lexGenericAttachment.imageUrl;
str = lexGenericAttachment.attachmentLinkUrl;
str = lexGenericAttachment.buttons[0].text;
str = lexGenericAttachment.buttons[0].value;
lexDialogAction.type === 'Close';
lexDialogAction.type === 'ConfirmIntent';
lexDialogAction.type === 'Delegate';
lexDialogAction.type === 'ElicitIntent';
lexDialogAction.type === 'ElicitSlot';
lexDialogActionBase.message!.contentType === 'CustomPayload';
lexDialogActionBase.message!.contentType === 'PlainText';
lexDialogActionBase.message!.contentType === 'SSML';
str = lexDialogActionBase.message!.content;
num = lexDialogActionBase.responseCard!.version;
lexDialogActionBase.responseCard!.contentType === 'application/vnd.amazonaws.card.generic';
// $ExpectType LexGenericAttachment
lexDialogActionBase.responseCard!.genericAttachments[0];
lexDialogActionClose.type === 'Close';
lexDialogActionClose.fulfillmentState === 'Failed';
lexDialogActionClose.fulfillmentState === 'Fulfilled';
lexDialogActionConfirmIntent.type === 'ConfirmIntent';
str = lexDialogActionConfirmIntent.intentName;
strOrNull = lexDialogActionConfirmIntent.slots['example'];
lexDialogActionDelegate.type === 'Delegate';
strOrNull = lexDialogActionDelegate.slots['example'];
lexDialogActionElicitIntent.type === 'ElicitIntent';
lexDialogActionElicitSlot.type === 'ElicitSlot';
strOrNull = lexDialogActionElicitSlot.slots['example'];
str = lexDialogActionElicitSlot.slotToElicit;
str = lexDialogActionElicitSlot.intentName;
+102
View File
@@ -0,0 +1,102 @@
import { Callback, Context, S3BatchEvent, S3BatchResult, S3CreateEvent, S3EventRecord, S3Handler } from "aws-lambda";
// TODO: Update test to read event properties, like the user will
let handler: S3Handler = async (event, context, callback) => {
callback(new Error());
};
// Test old event name
handler = (event: S3CreateEvent, context: Context, cb: Callback<void>) => {};
const record: S3EventRecord = {
eventVersion: '2.1',
eventSource: 'aws:s3',
awsRegion: 'us-east-1',
eventTime: '1970-01-01T00:00:00.000Z',
eventName: 'ObjectRestore:Completed',
userIdentity: {
principalId: 'AIDAJDPLRKLG7UEXAMPLE',
},
requestParameters: {
sourceIPAddress: '127.0.0.1',
},
responseElements: {
'x-amz-request-id': 'C3D13FE58DE4C810',
'x-amz-id-2': 'FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD',
},
s3: {
s3SchemaVersion: '1.0',
configurationId: 'testConfigRule',
bucket: {
name: 'mybucket',
ownerIdentity: {
principalId: 'A3NL1KOZZKExample',
},
arn: 'arn:aws:s3:::mybucket',
},
object: {
key: 'HappyFace.jpg',
size: 1024,
eTag: 'd41d8cd98f00b204e9800998ecf8427e',
versionId: '096fKKXTRTtl3on89fVO.nfljtsv6qko',
sequencer: '0055AED6DCD90281E5',
},
},
glacierEventData: {
restoreEventData: {
lifecycleRestorationExpiryTime: '1970-01-01T00:00:00.000Z',
lifecycleRestoreStorageClass: 'glacier-deep-archive',
},
},
};
const event: S3CreateEvent = {
Records: [record],
};
/**
* S3 Batch Operations event
* https://docs.aws.amazon.com/AmazonS3/latest/dev/batch-ops-invoke-lambda.html
*/
const batchEvent: S3BatchEvent = {
invocationSchemaVersion: '1.0',
invocationId: 'foo_invocation_id',
job: { id: 'foo_job_id' },
tasks: [
{
taskId: '11111',
s3Key: 'example.json',
s3BucketArn: 'arn:aws:s3:::foo-bucket',
s3VersionId: null,
},
{
taskId: '11111',
s3Key: 'example.json',
s3BucketArn: 'arn:aws:s3:::foo-bucket',
s3VersionId: 'asdf',
},
],
};
const batchResult: S3BatchResult = {
invocationSchemaVersion: '1.0',
treatMissingKeysAs: 'PermanentFailure',
invocationId: 'foo_invocation_id',
results: [
{
taskId: '11111',
resultCode: 'Succeeded',
resultString: 'foo',
},
{
taskId: '22222',
resultCode: 'TemporaryFailure',
resultString: 'Error: failure',
},
{
taskId: '33333',
resultCode: 'PermanentFailure',
resultString: 'Error: failure',
},
],
};
+29
View File
@@ -0,0 +1,29 @@
import { SNSEventRecord, SNSHandler, SNSMessage, SNSMessageAttribute, SNSMessageAttributes } from "aws-lambda";
const handler: SNSHandler = async (event, context, callback) => {
const record: SNSEventRecord = event.Records[num];
str = record.EventSource;
str = record.EventSubscriptionArn;
str = record.EventVersion;
const message: SNSMessage = record.Sns;
str = message.SignatureVersion;
str = message.Timestamp;
str = message.Signature;
str = message.SigningCertUrl;
str = message.MessageId;
str = message.Message;
const attributes: SNSMessageAttributes = message.MessageAttributes;
str = message.Type;
str = message.UnsubscribeUrl;
str = message.TopicArn;
str = message.Subject;
const attribute: SNSMessageAttribute = attributes[str];
str = attribute.Type;
str = attribute.Value;
callback();
callback(new Error());
};
+44
View File
@@ -0,0 +1,44 @@
import { SQSEvent, SQSHandler } from "aws-lambda";
// TODO: Update test to read all event properties, like the user will.
const handler: SQSHandler = async (event, context, callback) => {
str = event.Records[0].messageId;
anyObj = event.Records[0].body;
strOrUndefined = event.Records[0].messageAttributes.testAttr.stringValue;
strOrUndefined = event.Records[0].messageAttributes.testAttr.binaryValue;
str = event.Records[0].messageAttributes.testAttr.dataType;
callback();
callback(new Error());
};
// See https://docs.aws.amazon.com/lambda/latest/dg/eventsources.html#eventsources-sqs
const event: SQSEvent = {
Records: [
{
messageId: 'c80e8021-a70a-42c7-a470-796e1186f753',
receiptHandle: 'AQEBJQ+/u6NsnT5t8Q/VbVxgdUl4TMKZ5FqhksRdIQvLBhwNvADoBxYSOVeCBXdnS9P+',
body: '{"foo":"bar"}',
attributes: {
ApproximateReceiveCount: '3',
SentTimestamp: '1529104986221',
SenderId: '594035263019',
ApproximateFirstReceiveTimestamp: '1529104986230',
},
messageAttributes: {
testAttr: {
stringValue: '100',
binaryValue: 'base64Str',
stringListValues: [],
binaryListValues: [],
dataType: 'Number',
},
},
md5OfBody: '9bb58f26192e4ba00f01e2e7b136bbd8',
eventSource: 'aws:sqs',
eventSourceARN: 'arn:aws:sqs:us-west-2:594035263019:NOTFIFOQUEUE',
awsRegion: 'us-west-2',
},
],
};
+32
View File
@@ -0,0 +1,32 @@
import { Handler, Callback } from "../hander";
export type ALBHandler = Handler<ALBEvent, ALBResult>;
export type ALBCallback = Callback<ALBResult>;
// https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html
export interface ALBEventRequestContext {
elb: {
targetGroupArn: string;
};
}
export interface ALBEvent {
requestContext: ALBEventRequestContext;
httpMethod: string;
path: string;
queryStringParameters?: { [parameter: string]: string }; // URL encoded
headers?: { [header: string]: string };
multiValueQueryStringParameters?: { [parameter: string]: string[] }; // URL encoded
multiValueHeaders?: { [header: string]: string[] };
body: string | null;
isBase64Encoded: boolean;
}
export interface ALBResult {
statusCode: number;
statusDescription: string;
headers?: { [header: string]: boolean | number | string };
multiValueHeaders?: { [header: string]: Array<boolean | number | string> };
body?: string;
isBase64Encoded: boolean;
}
+88
View File
@@ -0,0 +1,88 @@
import { APIGatewayEventRequestContext, AuthResponseContext } from "../common/api-gateway";
import { Callback, Handler } from "../hander";
export type CustomAuthorizerHandler = Handler<CustomAuthorizerEvent, CustomAuthorizerResult>;
export type CustomAuthorizerCallback = Callback<CustomAuthorizerResult>;
// API Gateway CustomAuthorizer "event"
export interface CustomAuthorizerEvent {
type: string;
methodArn: string;
authorizationToken?: string;
resource?: string;
path?: string;
httpMethod?: string;
headers?: { [name: string]: string };
multiValueHeaders?: { [name: string]: string[] };
pathParameters?: { [name: string]: string } | null;
queryStringParameters?: { [name: string]: string } | null;
multiValueQueryStringParameters?: { [name: string]: string[] } | null;
stageVariables?: { [name: string]: string };
requestContext?: APIGatewayEventRequestContext;
domainName?: string;
apiId?: string;
}
/**
* API Gateway CustomAuthorizer AuthResponse.
* http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html#api-gateway-custom-authorizer-output
*/
export interface CustomAuthorizerResult {
principalId: string;
policyDocument: PolicyDocument;
context?: AuthResponseContext;
usageIdentifierKey?: string;
}
export type AuthResponse = CustomAuthorizerResult;
/**
* API Gateway CustomAuthorizer AuthResponse.PolicyDocument.
* https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html
* https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Condition
*/
export interface PolicyDocument {
Version: string;
Id?: string;
Statement: Statement[];
}
/**
* API Gateway CustomAuthorizer AuthResponse.PolicyDocument.Condition.
* https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-policy-language-overview.html
* https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html
*/
export interface ConditionBlock {
[condition: string]: Condition | Condition[];
}
export interface Condition {
[key: string]: string | string[];
}
/**
* API Gateway CustomAuthorizer AuthResponse.PolicyDocument.Statement.
* https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-policy-language-overview.html
* https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html
*/
export type Statement = BaseStatement & StatementAction & (StatementResource | StatementPrincipal);
export interface BaseStatement {
Effect: string;
Sid?: string;
Condition?: ConditionBlock;
}
export type PrincipalValue = { [key: string]: string | string[] } | string | string[];
export interface MaybeStatementPrincipal {
Principal?: PrincipalValue;
NotPrincipal?: PrincipalValue;
}
export interface MaybeStatementResource {
Resource?: string | string[];
NotResource?: string | string[];
}
export type StatementAction = { Action: string | string[] } | { NotAction: string | string[] };
export type StatementResource = MaybeStatementPrincipal &
({ Resource: string | string[] } | { NotResource: string | string[] });
export type StatementPrincipal = MaybeStatementResource &
({ Principal: PrincipalValue } | { NotPrincipal: PrincipalValue });
+38
View File
@@ -0,0 +1,38 @@
import { APIGatewayEventRequestContext } from "../common/api-gateway";
import { Callback, Handler } from "../hander";
export type APIGatewayProxyHandler = Handler<APIGatewayProxyEvent, APIGatewayProxyResult>;
export type APIGatewayProxyCallback = Callback<APIGatewayProxyResult>;
export type ProxyHandler = APIGatewayProxyHandler; // Old name
export type ProxyCallback = APIGatewayProxyCallback; // Old name
export type APIGatewayEvent = APIGatewayProxyEvent; // Old name
export type ProxyResult = APIGatewayProxyResult; // Old name
// API Gateway "event"
export interface APIGatewayProxyEvent {
body: string | null;
headers: { [name: string]: string };
multiValueHeaders: { [name: string]: string[] };
httpMethod: string;
isBase64Encoded: boolean;
path: string;
pathParameters: { [name: string]: string } | null;
queryStringParameters: { [name: string]: string } | null;
multiValueQueryStringParameters: { [name: string]: string[] } | null;
stageVariables: { [name: string]: string } | null;
requestContext: APIGatewayEventRequestContext;
resource: string;
}
export interface APIGatewayProxyResult {
statusCode: number;
headers?: {
[header: string]: boolean | number | string;
};
multiValueHeaders?: {
[header: string]: Array<boolean | number | string>;
};
body: string;
isBase64Encoded?: boolean;
}
@@ -0,0 +1,68 @@
import { Handler } from "../hander";
// Note, responses are *not* lambda results, they are sent to the event ResponseURL.
export type CloudFormationCustomResourceHandler = Handler<CloudFormationCustomResourceEvent, void>;
export type CloudFormationCustomResourceEvent =
| CloudFormationCustomResourceCreateEvent
| CloudFormationCustomResourceUpdateEvent
| CloudFormationCustomResourceDeleteEvent;
export type CloudFormationCustomResourceResponse =
| CloudFormationCustomResourceSuccessResponse
| CloudFormationCustomResourceFailedResponse;
/**
* CloudFormation Custom Resource event and response
* http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref.html
*/
export interface CloudFormationCustomResourceEventCommon {
ServiceToken: string;
ResponseURL: string;
StackId: string;
RequestId: string;
LogicalResourceId: string;
ResourceType: string;
ResourceProperties: {
ServiceToken: string;
[Key: string]: any;
};
}
export interface CloudFormationCustomResourceCreateEvent extends CloudFormationCustomResourceEventCommon {
RequestType: 'Create';
}
export interface CloudFormationCustomResourceUpdateEvent extends CloudFormationCustomResourceEventCommon {
RequestType: 'Update';
PhysicalResourceId: string;
OldResourceProperties: {
[Key: string]: any;
};
}
export interface CloudFormationCustomResourceDeleteEvent extends CloudFormationCustomResourceEventCommon {
RequestType: 'Delete';
PhysicalResourceId: string;
}
export interface CloudFormationCustomResourceResponseCommon {
PhysicalResourceId: string;
StackId: string;
RequestId: string;
LogicalResourceId: string;
Data?: {
[Key: string]: any;
};
NoEcho?: boolean;
}
export interface CloudFormationCustomResourceSuccessResponse extends CloudFormationCustomResourceResponseCommon {
Status: 'SUCCESS';
Reason?: string;
}
export interface CloudFormationCustomResourceFailedResponse extends CloudFormationCustomResourceResponseCommon {
Status: 'FAILED';
Reason: string;
}
+20
View File
@@ -0,0 +1,20 @@
import { CloudFrontEvent, CloudFrontRequest, CloudFrontResultResponse } from "../common/cloudfront";
import { Handler, Callback } from "../hander";
export type CloudFrontRequestHandler = Handler<CloudFrontRequestEvent, CloudFrontRequestResult>;
export type CloudFrontRequestCallback = Callback<CloudFrontRequestResult>;
/**
* CloudFront viewer request or origin request event
*
* https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#lambda-event-structure-request
*/
export interface CloudFrontRequestEvent {
Records: Array<{
cf: CloudFrontEvent & {
request: CloudFrontRequest;
};
}>;
}
export type CloudFrontRequestResult = undefined | null | CloudFrontResultResponse | CloudFrontRequest;
+21
View File
@@ -0,0 +1,21 @@
import { CloudFrontEvent, CloudFrontRequest, CloudFrontResponse, CloudFrontResultResponse } from "../common/cloudfront";
import { Callback, Handler } from "../hander";
export type CloudFrontResponseHandler = Handler<CloudFrontResponseEvent, CloudFrontResponseResult>;
export type CloudFrontResponseCallback = Callback<CloudFrontResponseResult>;
/**
* CloudFront viewer response or origin response event
*
* https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#lambda-event-structure-response
*/
export interface CloudFrontResponseEvent {
Records: Array<{
cf: CloudFrontEvent & {
readonly request: Pick<CloudFrontRequest, Exclude<keyof CloudFrontRequest, 'body'>>;
response: CloudFrontResponse;
};
}>;
}
export type CloudFrontResponseResult = undefined | null | CloudFrontResultResponse;
+19
View File
@@ -0,0 +1,19 @@
import { Handler } from "../hander";
export type ScheduledHandler = Handler<ScheduledEvent, void>;
// TODO: generic cloudwatch event types.
/**
* https://docs.aws.amazon.com/lambda/latest/dg/with-scheduled-events.html
*/
export interface ScheduledEvent {
account: string;
region: string;
detail: any;
'detail-type': string;
source: string;
time: string;
id: string;
resources: string[];
}
+33
View File
@@ -0,0 +1,33 @@
import { Handler } from "../hander";
export type CloudWatchLogsHandler = Handler<CloudWatchLogsEvent, void>;
/**
* See http://docs.aws.amazon.com/lambda/latest/dg/eventsources.html#eventsources-cloudwatch-logs
*/
export interface CloudWatchLogsEvent {
awslogs: CloudWatchLogsEventData;
}
export interface CloudWatchLogsEventData {
data: string;
}
export interface CloudWatchLogsDecodedData {
owner: string;
logGroup: string;
logStream: string;
subscriptionFilters: string[];
messageType: string;
logEvents: CloudWatchLogsLogEvent[];
}
/**
* See http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#LambdaFunctionExample
*/
export interface CloudWatchLogsLogEvent {
id: string;
timestamp: number;
message: string;
extractedFields?: { [key: string]: string };
}
@@ -0,0 +1,31 @@
import { Handler } from "../hander";
export type CodePipelineCloudWatchActionHandler = Handler<CodePipelineCloudWatchActionEvent, void>;
export type CodePipelineActionCategory = 'Approval' | 'Build' | 'Deploy' | 'Invoke' | 'Source' | 'Test';
export type CodePipelineActionState = 'STARTED' | 'SUCCEEDED' | 'FAILED' | 'CANCELED';
export interface CodePipelineCloudWatchActionEvent {
version: string;
id: string;
'detail-type': 'CodePipeline Action Execution State Change';
source: 'aws.codepipeline';
account: string;
time: string;
region: string;
resources: string[];
detail: {
pipeline: string;
version: number;
'execution-id': string;
stage: string;
action: string;
state: CodePipelineActionState;
type: {
owner: 'AWS' | 'Custom' | 'ThirdParty';
category: CodePipelineActionCategory;
provider: string;
version: number;
};
};
}
@@ -0,0 +1,32 @@
import { Handler } from "../hander";
export type CodePipelineCloudWatchPipelineHandler = Handler<CodePipelineCloudWatchPipelineEvent, void>;
export type CodePipelineState = 'STARTED' | 'SUCCEEDED' | 'RESUMED' | 'FAILED' | 'CANCELED' | 'SUPERSEDED';
/**
* CodePipeline CloudWatch Events
* https://docs.aws.amazon.com/codepipeline/latest/userguide/detect-state-changes-cloudwatch-events.html
*
* The above CodePipelineEvent is when a lambda is invoked by a CodePipeline.
* These events are when you subscribe to CodePipeline events in CloudWatch.
*
* Their documentation says that detail.version is a string, but it is actually an integer
*/
export interface CodePipelineCloudWatchPipelineEvent {
version: string;
id: string;
'detail-type': 'CodePipeline Pipeline Execution State Change';
source: 'aws.codepipeline';
account: string;
time: string;
region: string;
resources: string[];
detail: {
pipeline: string;
version: number;
state: CodePipelineState;
'execution-id': string;
};
}
@@ -0,0 +1,23 @@
import { Handler } from "../hander";
export type CodePipelineCloudWatchStageHandler = Handler<CodePipelineCloudWatchStageEvent, void>;
export type CodePipelineStageState = 'STARTED' | 'SUCCEEDED' | 'RESUMED' | 'FAILED' | 'CANCELED';
export interface CodePipelineCloudWatchStageEvent {
version: string;
id: string;
'detail-type': 'CodePipeline Stage Execution State Change';
source: 'aws.codepipeline';
account: string;
time: string;
region: string;
resources: string[];
detail: {
pipeline: string;
version: number;
'execution-id': string;
stage: string;
state: CodePipelineStageState;
};
}
+11
View File
@@ -0,0 +1,11 @@
import { Handler } from "../hander";
import { CodePipelineCloudWatchActionEvent } from "./codepipeline-cloudwatch-action";
import { CodePipelineCloudWatchPipelineEvent } from "./codepipeline-cloudwatch-pipeline";
import { CodePipelineCloudWatchStageEvent } from "./codepipeline-cloudwatch-stage";
export type CodePipelineCloudWatchHandler = Handler<CodePipelineCloudWatchEvent, void>;
export type CodePipelineCloudWatchEvent =
| CodePipelineCloudWatchPipelineEvent
| CodePipelineCloudWatchStageEvent
| CodePipelineCloudWatchActionEvent;
+55
View File
@@ -0,0 +1,55 @@
import { Handler } from "../hander";
export type CodePipelineHandler = Handler<CodePipelineEvent, void>;
/**
* CodePipeline events
* https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html
*/
export interface S3ArtifactLocation {
bucketName: string;
objectKey: string;
}
export interface S3ArtifactStore {
type: 'S3';
s3Location: S3ArtifactLocation;
}
export type ArtifactLocation = S3ArtifactStore;
export interface Artifact {
name: string;
revision: string | null;
location: ArtifactLocation;
}
export interface Credentials {
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
}
export interface EncryptionKey {
type: string;
id: string;
}
export interface CodePipelineEvent {
'CodePipeline.job': {
id: string;
accountId: string;
data: {
actionConfiguration: {
configuration: {
FunctionName: string;
UserParameters: string;
};
};
inputArtifacts: Artifact[];
outputArtifacts: Artifact[];
artifactCredentials: Credentials;
encryptionKey?: EncryptionKey & { type: 'KMS' };
continuationToken?: string;
};
};
}
+99
View File
@@ -0,0 +1,99 @@
import { Handler } from "../hander";
// Result type is weird: docs and samples say to return the mutated event, but it only requires an object
// with a "response" field, the type of which is specific to the event.triggerType. Leave as any for now.
export type CognitoUserPoolTriggerHandler = Handler<CognitoUserPoolTriggerEvent>;
// TODO: Different event/handler types for each event trigger so we can type the result?
/**
* Cognito User Pool event
* http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html
*/
export interface CognitoUserPoolTriggerEvent {
version: number;
triggerSource:
| 'PreSignUp_SignUp'
| 'PreSignUp_ExternalProvider'
| 'PostConfirmation_ConfirmSignUp'
| 'PreAuthentication_Authentication'
| 'PostAuthentication_Authentication'
| 'CustomMessage_SignUp'
| 'CustomMessage_AdminCreateUser'
| 'CustomMessage_ResendCode'
| 'CustomMessage_ForgotPassword'
| 'CustomMessage_UpdateUserAttribute'
| 'CustomMessage_VerifyUserAttribute'
| 'CustomMessage_Authentication'
| 'DefineAuthChallenge_Authentication'
| 'CreateAuthChallenge_Authentication'
| 'VerifyAuthChallengeResponse_Authentication'
| 'PreSignUp_AdminCreateUser'
| 'PostConfirmation_ConfirmForgotPassword'
| 'TokenGeneration_HostedAuth'
| 'TokenGeneration_Authentication'
| 'TokenGeneration_NewPasswordChallenge'
| 'TokenGeneration_AuthenticateDevice'
| 'TokenGeneration_RefreshTokens'
| 'UserMigration_Authentication'
| 'UserMigration_ForgotPassword';
region: string;
userPoolId: string;
userName?: string;
callerContext: {
awsSdkVersion: string;
clientId: string;
};
request: {
userAttributes: { [key: string]: string };
validationData?: { [key: string]: string };
codeParameter?: string;
linkParameter?: string;
usernameParameter?: string;
newDeviceUsed?: boolean;
session?: Array<{
challengeName:
| 'CUSTOM_CHALLENGE'
| 'PASSWORD_VERIFIER'
| 'SMS_MFA'
| 'DEVICE_SRP_AUTH'
| 'DEVICE_PASSWORD_VERIFIER'
| 'ADMIN_NO_SRP_AUTH';
challengeResult: boolean;
challengeMetadata?: string;
}>;
challengeName?: string;
privateChallengeParameters?: { [key: string]: string };
challengeAnswer?: string;
password?: string;
};
response: {
autoConfirmUser?: boolean;
autoVerifyPhone?: boolean;
autoVerifyEmail?: boolean;
smsMessage?: string;
emailMessage?: string;
emailSubject?: string;
challengeName?: string;
issueTokens?: boolean;
failAuthentication?: boolean;
publicChallengeParameters?: { [key: string]: string };
privateChallengeParameters?: { [key: string]: string };
challengeMetadata?: string;
answerCorrect?: boolean;
userAttributes?: { [key: string]: string };
finalUserStatus?: 'CONFIRMED' | 'RESET_REQUIRED';
messageAction?: 'SUPPRESS';
desiredDeliveryMediums?: Array<'EMAIL' | 'SMS'>;
forceAliasCreation?: boolean;
claimsOverrideDetails?: {
claimsToAddOrOverride?: { [key: string]: string };
claimsToSuppress?: string[];
groupOverrideDetails?: null | {
groupsToOverride?: string[];
iamRolesToOverride?: string[];
preferredRole?: string;
};
};
};
}
export type CognitoUserPoolEvent = CognitoUserPoolTriggerEvent;
+45
View File
@@ -0,0 +1,45 @@
import { Handler } from "../hander";
export type DynamoDBStreamHandler = Handler<DynamoDBStreamEvent, void>;
// http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_AttributeValue.html
export interface AttributeValue {
B?: string;
BS?: string[];
BOOL?: boolean;
L?: AttributeValue[];
M?: { [id: string]: AttributeValue };
N?: string;
NS?: string[];
NULL?: boolean;
S?: string;
SS?: string[];
}
// http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_StreamRecord.html
export interface StreamRecord {
ApproximateCreationDateTime?: number;
Keys?: { [key: string]: AttributeValue };
NewImage?: { [key: string]: AttributeValue };
OldImage?: { [key: string]: AttributeValue };
SequenceNumber?: string;
SizeBytes?: number;
StreamViewType?: 'KEYS_ONLY' | 'NEW_IMAGE' | 'OLD_IMAGE' | 'NEW_AND_OLD_IMAGES';
}
// http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_Record.html
export interface DynamoDBRecord {
awsRegion?: string;
dynamodb?: StreamRecord;
eventID?: string;
eventName?: 'INSERT' | 'MODIFY' | 'REMOVE';
eventSource?: string;
eventSourceARN?: string;
eventVersion?: string;
userIdentity?: any;
}
// http://docs.aws.amazon.com/lambda/latest/dg/eventsources.html#eventsources-ddb-update
export interface DynamoDBStreamEvent {
Records: DynamoDBRecord[];
}
@@ -0,0 +1,45 @@
import { Callback, Handler } from "../hander";
export type FirehoseTransformationHandler = Handler<FirehoseTransformationEvent, FirehoseTransformationResult>;
export type FirehoseTransformationCallback = Callback<FirehoseTransformationResult>;
// Kinesis Data Firehose Event
// https://docs.aws.amazon.com/lambda/latest/dg/eventsources.html#eventsources-kinesis-firehose
// https://docs.aws.amazon.com/firehose/latest/dev/data-transformation.html
// https://aws.amazon.com/blogs/compute/amazon-kinesis-firehose-data-transformation-with-aws-lambda/
// Examples in the lambda blueprints
export interface FirehoseTransformationEvent {
invocationId: string;
deliveryStreamArn: string;
region: string;
records: FirehoseTransformationEventRecord[];
}
export interface FirehoseTransformationEventRecord {
recordId: string;
approximateArrivalTimestamp: number;
/** Base64 encoded */
data: string;
kinesisRecordMetadata?: FirehoseRecordMetadata;
}
export interface FirehoseRecordMetadata {
shardId: string;
partitionKey: string;
approximateArrivalTimestamp: string;
sequenceNumber: string;
subsequenceNumber: string;
}
export type FirehoseRecordTransformationStatus = 'Ok' | 'Dropped' | 'ProcessingFailed';
export interface FirehoseTransformationResultRecord {
recordId: string;
result: FirehoseRecordTransformationStatus;
/** Encode in Base64 */
data: string;
}
export interface FirehoseTransformationResult {
records: FirehoseTransformationResultRecord[];
}
+28
View File
@@ -0,0 +1,28 @@
import { Handler } from "../hander";
export type KinesisStreamHandler = Handler<KinesisStreamEvent, void>;
// Kinesis Streams
// https://docs.aws.amazon.com/lambda/latest/dg/eventsources.html#eventsources-kinesis-streams
export interface KinesisStreamRecordPayload {
approximateArrivalTimestamp: number;
data: string;
kinesisSchemaVersion: string;
partitionKey: string;
sequenceNumber: string;
}
export interface KinesisStreamRecord {
awsRegion: string;
eventID: string;
eventName: string;
eventSource: string;
eventSourceARN: string;
eventVersion: string;
invokeIdentityArn: string;
kinesis: KinesisStreamRecordPayload;
}
export interface KinesisStreamEvent {
Records: KinesisStreamRecord[];
}
+103
View File
@@ -0,0 +1,103 @@
import { Callback, Handler } from "../hander";
export type LexHandler = Handler<LexEvent, LexResult>;
export type LexCallback = Callback<LexResult>;
// Lex
// https://docs.aws.amazon.com/lambda/latest/dg/invoking-lambda-function.html#supported-event-source-lex
export interface LexEvent {
currentIntent: {
name: string;
slots: { [name: string]: string | null };
slotDetails: LexSlotDetails;
confirmationStatus: 'None' | 'Confirmed' | 'Denied';
};
bot: {
name: string;
alias: string;
version: string;
};
userId: string;
inputTranscript: string;
invocationSource: 'DialogCodeHook' | 'FulfillmentCodeHook';
outputDialogMode: 'Text' | 'Voice';
messageVersion: '1.0';
sessionAttributes: { [key: string]: string };
requestAttributes: { [key: string]: string } | null;
}
export interface LexSlotResolution {
value: string;
}
export interface LexSlotDetails {
[name: string]: {
// The following line only works in TypeScript Version: 3.0, The array should have at least 1 and no more than 5 items
// resolutions: [LexSlotResolution, LexSlotResolution?, LexSlotResolution?, LexSlotResolution?, LexSlotResolution?];
resolutions: LexSlotResolution[];
originalValue: string;
};
}
export interface LexGenericAttachment {
title: string;
subTitle: string;
imageUrl: string;
attachmentLinkUrl: string;
buttons: Array<{
text: string;
value: string;
}>;
}
export interface LexDialogActionBase {
type: 'Close' | 'ElicitIntent' | 'ElicitSlot' | 'ConfirmIntent';
message?: {
contentType: 'PlainText' | 'SSML' | 'CustomPayload';
content: string;
};
responseCard?: {
version: number;
contentType: 'application/vnd.amazonaws.card.generic';
genericAttachments: LexGenericAttachment[];
};
}
export interface LexDialogActionClose extends LexDialogActionBase {
type: 'Close';
fulfillmentState: 'Fulfilled' | 'Failed';
}
export interface LexDialogActionElicitIntent extends LexDialogActionBase {
type: 'ElicitIntent';
}
export interface LexDialogActionElicitSlot extends LexDialogActionBase {
type: 'ElicitSlot';
intentName: string;
slots: { [name: string]: string | null };
slotToElicit: string;
}
export interface LexDialogActionConfirmIntent extends LexDialogActionBase {
type: 'ConfirmIntent';
intentName: string;
slots: { [name: string]: string | null };
}
export interface LexDialogActionDelegate {
type: 'Delegate';
slots: { [name: string]: string | null };
}
export type LexDialogAction =
| LexDialogActionClose
| LexDialogActionElicitIntent
| LexDialogActionElicitSlot
| LexDialogActionConfirmIntent
| LexDialogActionDelegate;
export interface LexResult {
sessionAttributes?: { [key: string]: string };
dialogAction: LexDialogAction;
}
+41
View File
@@ -0,0 +1,41 @@
import { Handler, Callback } from "../hander";
/**
* S3 Batch Operations event
* https://docs.aws.amazon.com/AmazonS3/latest/dev/batch-ops-invoke-lambda.html
*/
export type S3BatchHandler = Handler<S3BatchEvent, S3BatchResult>;
export type S3BatchCallback = Callback<S3BatchResult>;
export interface S3BatchEvent {
invocationSchemaVersion: string;
invocationId: string;
job: S3BatchEventJob;
tasks: S3BatchEventTask[];
}
export interface S3BatchEventJob {
id: string;
}
export interface S3BatchEventTask {
taskId: string;
s3Key: string;
s3VersionId: string | null;
s3BucketArn: string;
}
export interface S3BatchResult {
invocationSchemaVersion: string;
treatMissingKeysAs: S3BatchResultResultCode;
invocationId: string;
results: S3BatchResultResult[];
}
export type S3BatchResultResultCode = 'Succeeded' | 'TemporaryFailure' | 'PermanentFailure';
export interface S3BatchResultResult {
taskId: string;
resultCode: S3BatchResultResultCode;
resultString: string;
}
+60
View File
@@ -0,0 +1,60 @@
import { Handler } from "../hander";
export type S3Handler = Handler<S3Event, void>;
/**
* S3Create event
* https://docs.aws.amazon.com/AmazonS3/latest/dev/notification-content-structure.html
*/
export interface S3EventRecordGlacierRestoreEventData {
lifecycleRestorationExpiryTime: string;
lifecycleRestoreStorageClass: string;
}
export interface S3EventRecordGlacierEventData {
restoreEventData: S3EventRecordGlacierRestoreEventData;
}
export interface S3EventRecord {
eventVersion: string;
eventSource: string;
awsRegion: string;
eventTime: string;
eventName: string;
userIdentity: {
principalId: string;
};
requestParameters: {
sourceIPAddress: string;
};
responseElements: {
'x-amz-request-id': string;
'x-amz-id-2': string;
};
s3: {
s3SchemaVersion: string;
configurationId: string;
bucket: {
name: string;
ownerIdentity: {
principalId: string;
};
arn: string;
};
object: {
key: string;
size: number;
eTag: string;
versionId?: string;
sequencer: string;
};
};
glacierEventData?: S3EventRecordGlacierEventData;
}
export interface S3Event {
Records: S3EventRecord[];
}
export type S3CreateEvent = S3Event; // old name
+38
View File
@@ -0,0 +1,38 @@
import { Handler } from "../hander";
export type SNSHandler = Handler<SNSEvent, void>;
// SNS "event"
export interface SNSMessageAttribute {
Type: string;
Value: string;
}
export interface SNSMessageAttributes {
[name: string]: SNSMessageAttribute;
}
export interface SNSMessage {
SignatureVersion: string;
Timestamp: string;
Signature: string;
SigningCertUrl: string;
MessageId: string;
Message: string;
MessageAttributes: SNSMessageAttributes;
Type: string;
UnsubscribeUrl: string;
TopicArn: string;
Subject: string;
}
export interface SNSEventRecord {
EventVersion: string;
EventSubscriptionArn: string;
EventSource: string;
Sns: SNSMessage;
}
export interface SNSEvent {
Records: SNSEventRecord[];
}
+42
View File
@@ -0,0 +1,42 @@
import { Handler } from "../hander";
export type SQSHandler = Handler<SQSEvent, void>;
// SQS
// https://docs.aws.amazon.com/lambda/latest/dg/invoking-lambda-function.html#supported-event-source-sqs
export interface SQSRecord {
messageId: string;
receiptHandle: string;
body: string;
attributes: SQSRecordAttributes;
messageAttributes: SQSMessageAttributes;
md5OfBody: string;
eventSource: string;
eventSourceARN: string;
awsRegion: string;
}
export interface SQSEvent {
Records: SQSRecord[];
}
export interface SQSRecordAttributes {
ApproximateReceiveCount: string;
SentTimestamp: string;
SenderId: string;
ApproximateFirstReceiveTimestamp: string;
}
export type SQSMessageAttributeDataType = 'String' | 'Number' | 'Binary' | string;
export interface SQSMessageAttribute {
stringValue?: string;
binaryValue?: string;
stringListValues: never[]; // Not implemented. Reserved for future use.
binaryListValues: never[]; // Not implemented. Reserved for future use.
dataType: SQSMessageAttributeDataType;
}
export interface SQSMessageAttributes {
[name: string]: SQSMessageAttribute;
}
+15 -2
View File
@@ -18,6 +18,19 @@
},
"files": [
"index.d.ts",
"aws-lambda-tests.ts"
"aws-lambda-tests.ts",
"test/alb-tests.ts",
"test/api-gateway-tests.ts",
"test/cloudformation-tests.ts",
"test/cloudfront-tests.ts",
"test/cloudwatch-tests.ts",
"test/codepipeline-tests.ts",
"test/cognito-tests.ts",
"test/dynamodb-tests.ts",
"test/kinesis-tests.ts",
"test/lex-tests.ts",
"test/s3-tests.ts",
"test/sns-tests.ts",
"test/sqs-tests.ts"
]
}
}
+3 -3
View File
@@ -1,8 +1,8 @@
{
"extends": "dtslint/dt.json",
"rules": {
// TODO
"npm-naming": false,
"dt-header": false
// This is needed because there's an unrelated aws-lambda package on NPM,
// and DTS is complaining that we're referring to a non-existing version.
"npm-naming": false
}
}