@vyriy/handler 0.7.8 → 0.8.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 +375 -253
- package/api/api.d.ts +10 -0
- package/api/api.js +19 -0
- package/api/http/compose/compose.d.ts +2 -0
- package/api/http/compose/compose.js +1 -0
- package/api/http/compose/index.d.ts +1 -0
- package/api/http/compose/index.js +1 -0
- package/api/http/factory/factory.d.ts +2 -0
- package/api/http/factory/factory.js +1 -0
- package/api/http/factory/index.d.ts +1 -0
- package/api/http/factory/index.js +1 -0
- package/api/http/http.d.ts +3 -0
- package/api/http/http.js +14 -0
- package/api/http/index.d.ts +3 -0
- package/api/http/index.js +2 -0
- package/api/http/types.d.ts +18 -0
- package/api/http/wrappers/cors.d.ts +1 -0
- package/api/http/wrappers/cors.js +9 -0
- package/api/http/wrappers/error.d.ts +3 -0
- package/api/http/wrappers/error.js +21 -0
- package/api/http/wrappers/headers.d.ts +1 -0
- package/api/http/wrappers/headers.js +8 -0
- package/api/http/wrappers/healthcheck.d.ts +5 -0
- package/api/http/wrappers/healthcheck.js +19 -0
- package/api/http/wrappers/index.d.ts +5 -0
- package/api/http/wrappers/index.js +5 -0
- package/api/http/wrappers/logger.d.ts +2 -0
- package/api/http/wrappers/logger.js +28 -0
- package/api/index.d.ts +3 -0
- package/api/index.js +2 -0
- package/api/stream/compose/compose.d.ts +2 -0
- package/api/stream/compose/compose.js +1 -0
- package/api/stream/compose/index.d.ts +1 -0
- package/api/stream/compose/index.js +1 -0
- package/api/stream/factory/factory.d.ts +5 -0
- package/api/stream/factory/factory.js +3 -0
- package/api/stream/factory/index.d.ts +1 -0
- package/api/stream/factory/index.js +1 -0
- package/api/stream/index.d.ts +3 -0
- package/api/stream/index.js +2 -0
- package/api/stream/stream.d.ts +3 -0
- package/api/stream/stream.js +13 -0
- package/api/stream/types.d.ts +36 -0
- package/api/stream/wrappers/chaos.d.ts +2 -0
- package/{wrapper → api/stream/wrappers}/chaos.js +1 -12
- package/api/stream/wrappers/context.d.ts +1 -0
- package/api/stream/wrappers/context.js +6 -0
- package/api/stream/wrappers/cors.d.ts +1 -0
- package/api/stream/wrappers/cors.js +10 -0
- package/api/stream/wrappers/error.d.ts +3 -0
- package/api/stream/wrappers/error.js +25 -0
- package/api/stream/wrappers/headers.d.ts +1 -0
- package/api/stream/wrappers/headers.js +7 -0
- package/api/stream/wrappers/healthcheck.d.ts +2 -0
- package/api/stream/wrappers/healthcheck.js +27 -0
- package/api/stream/wrappers/index.d.ts +10 -0
- package/api/stream/wrappers/index.js +10 -0
- package/api/stream/wrappers/logger.d.ts +2 -0
- package/api/stream/wrappers/logger.js +20 -0
- package/api/stream/wrappers/smoke.d.ts +2 -0
- package/{wrapper → api/stream/wrappers}/smoke.js +1 -5
- package/api/stream/wrappers/timeout.d.ts +1 -0
- package/api/stream/wrappers/timeout.js +6 -0
- package/api/types.d.ts +17 -0
- package/api/wrappers/chaos.d.ts +1 -0
- package/api/wrappers/chaos.js +1 -0
- package/api/wrappers/cors.d.ts +1 -0
- package/api/wrappers/cors.js +11 -0
- package/api/wrappers/error.d.ts +4 -0
- package/api/wrappers/error.js +18 -0
- package/api/wrappers/headers.d.ts +1 -0
- package/api/wrappers/headers.js +13 -0
- package/api/wrappers/healthcheck.d.ts +8 -0
- package/api/wrappers/healthcheck.js +22 -0
- package/api/wrappers/index.d.ts +5 -0
- package/api/wrappers/index.js +5 -0
- package/compose/compose.d.ts +2 -0
- package/compose/compose.js +1 -0
- package/compose/index.d.ts +1 -0
- package/compose/index.js +1 -0
- package/create/create.d.ts +12 -0
- package/create/create.js +22 -0
- package/create/index.d.ts +1 -0
- package/create/index.js +1 -0
- package/dynamodb/dynamodb.d.ts +4 -0
- package/dynamodb/dynamodb.js +8 -0
- package/dynamodb/index.d.ts +1 -0
- package/dynamodb/index.js +1 -0
- package/eventBridge/eventBridge.d.ts +4 -0
- package/eventBridge/eventBridge.js +8 -0
- package/eventBridge/index.d.ts +1 -0
- package/eventBridge/index.js +1 -0
- package/factory/factory.d.ts +4 -0
- package/factory/factory.js +2 -0
- package/factory/index.d.ts +1 -0
- package/factory/index.js +1 -0
- package/index.d.ts +21 -19
- package/index.js +21 -19
- package/package.json +731 -185
- package/s3/index.d.ts +1 -0
- package/s3/index.js +1 -0
- package/s3/s3.d.ts +4 -0
- package/s3/s3.js +8 -0
- package/schedule/index.d.ts +1 -0
- package/schedule/index.js +1 -0
- package/schedule/schedule.d.ts +4 -0
- package/schedule/schedule.js +8 -0
- package/ses/index.d.ts +1 -0
- package/ses/index.js +1 -0
- package/ses/ses.d.ts +4 -0
- package/ses/ses.js +8 -0
- package/sns/index.d.ts +1 -0
- package/sns/index.js +1 -0
- package/sns/sns.d.ts +4 -0
- package/sns/sns.js +8 -0
- package/sqs/index.d.ts +1 -0
- package/sqs/index.js +1 -0
- package/sqs/sqs.d.ts +4 -0
- package/sqs/sqs.js +8 -0
- package/types.d.ts +12 -29
- package/{wrapper → wrappers}/chaos.d.ts +0 -1
- package/wrappers/chaos.js +35 -0
- package/{wrapper → wrappers}/context.d.ts +0 -1
- package/wrappers/context.js +6 -0
- package/{wrapper → wrappers}/error.d.ts +1 -4
- package/wrappers/error.js +9 -0
- package/wrappers/index.d.ts +6 -0
- package/wrappers/index.js +6 -0
- package/wrappers/logger.d.ts +4 -0
- package/wrappers/logger.js +21 -0
- package/wrappers/smoke.d.ts +2 -0
- package/wrappers/smoke.js +5 -0
- package/{wrapper → wrappers}/timeout.d.ts +0 -1
- package/wrappers/timeout.js +6 -0
- package/api.d.ts +0 -3
- package/api.js +0 -30
- package/compose.d.ts +0 -4
- package/compose.js +0 -3
- package/dynamodb.d.ts +0 -2
- package/dynamodb.js +0 -7
- package/eventBridge.d.ts +0 -2
- package/eventBridge.js +0 -7
- package/factory.d.ts +0 -8
- package/factory.js +0 -6
- package/s3.d.ts +0 -2
- package/s3.js +0 -7
- package/schedule.d.ts +0 -2
- package/schedule.js +0 -7
- package/ses.d.ts +0 -2
- package/ses.js +0 -7
- package/sns.d.ts +0 -2
- package/sns.js +0 -7
- package/sqs.d.ts +0 -2
- package/sqs.js +0 -7
- package/wrapper/context.js +0 -11
- package/wrapper/cors.d.ts +0 -3
- package/wrapper/cors.js +0 -28
- package/wrapper/error.js +0 -62
- package/wrapper/headers.d.ts +0 -3
- package/wrapper/headers.js +0 -25
- package/wrapper/healthcheck.d.ts +0 -13
- package/wrapper/healthcheck.js +0 -49
- package/wrapper/logger.d.ts +0 -6
- package/wrapper/logger.js +0 -65
- package/wrapper/smoke.d.ts +0 -3
- package/wrapper/timeout.js +0 -10
- /package/{wrapper → api/stream/wrappers}/stream.d.ts +0 -0
- /package/{wrapper → api/stream/wrappers}/stream.js +0 -0
package/api/api.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Api } from './types.js';
|
|
2
|
+
export declare const API_HEADERS: {
|
|
3
|
+
'access-control-allow-origin': string;
|
|
4
|
+
'access-control-allow-methods': string;
|
|
5
|
+
'access-control-allow-headers': string;
|
|
6
|
+
'content-type': string;
|
|
7
|
+
'x-robots-tag': string;
|
|
8
|
+
};
|
|
9
|
+
export declare const createApi: Api;
|
|
10
|
+
export declare const api: import("./types.js").Decorator<import("aws-lambda").APIGatewayProxyEvent, import("aws-lambda").APIGatewayProxyResult>;
|
package/api/api.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { compose } from '../compose/index.js';
|
|
2
|
+
import { withChaos } from './wrappers/chaos.js';
|
|
3
|
+
import { withCors } from './wrappers/cors.js';
|
|
4
|
+
import { withApiError } from './wrappers/error.js';
|
|
5
|
+
import { withHealthcheck } from './wrappers/healthcheck.js';
|
|
6
|
+
import { withHeaders } from './wrappers/headers.js';
|
|
7
|
+
import { withContext } from '../wrappers/context.js';
|
|
8
|
+
import { withLogger } from '../wrappers/logger.js';
|
|
9
|
+
import { withSmoke } from '../wrappers/smoke.js';
|
|
10
|
+
import { withTimeout } from '../wrappers/timeout.js';
|
|
11
|
+
export const API_HEADERS = {
|
|
12
|
+
'access-control-allow-origin': '*',
|
|
13
|
+
'access-control-allow-methods': 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
|
|
14
|
+
'access-control-allow-headers': 'Content-Type, Authorization, X-Requested-With, X-Api-Key, Accept, User-Agent, X-CSRF-Token',
|
|
15
|
+
'content-type': 'application/json',
|
|
16
|
+
'x-robots-tag': 'noindex, nofollow',
|
|
17
|
+
};
|
|
18
|
+
export const createApi = (options = {}) => compose(withApiError(options.error), withLogger(options.logger), withTimeout(), withContext(), withSmoke(), withHealthcheck(options.healthcheck), withHeaders(options.headers ?? API_HEADERS), withCors(), withChaos(options.chaos));
|
|
19
|
+
export const api = createApi();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const compose = (...fns) => fns.reduceRight((prevDecorator, nextDecorator) => (handler) => nextDecorator(prevDecorator(handler)));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { compose } from './compose.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { compose } from './compose.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const factory = (wrapper) => (options) => (handler) => async (request, response) => wrapper(handler, [request, response], options);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { factory } from './factory.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { factory } from './factory.js';
|
package/api/http/http.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { compose } from './compose/index.js';
|
|
2
|
+
import { withCors } from './wrappers/cors.js';
|
|
3
|
+
import { withError } from './wrappers/error.js';
|
|
4
|
+
import { withHeaders } from './wrappers/headers.js';
|
|
5
|
+
import { withHealthcheck } from './wrappers/healthcheck.js';
|
|
6
|
+
import { withLogger } from './wrappers/logger.js';
|
|
7
|
+
const API_HEADERS = {
|
|
8
|
+
'access-control-allow-origin': '*',
|
|
9
|
+
'access-control-allow-methods': 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
|
|
10
|
+
'access-control-allow-headers': 'Content-Type, Authorization, X-Requested-With, X-Api-Key, Accept, User-Agent, X-CSRF-Token',
|
|
11
|
+
'x-robots-tag': 'noindex, nofollow',
|
|
12
|
+
};
|
|
13
|
+
export const createApi = (options = {}) => compose(withError(options.error), withLogger(options.logger), withHealthcheck(options.healthcheck), withHeaders(options.headers ?? API_HEADERS), withCors());
|
|
14
|
+
export const api = createApi();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { HealthcheckOptions } from './wrappers/healthcheck.js';
|
|
3
|
+
import type { Response } from '../../types.js';
|
|
4
|
+
import type { ErrorOptions } from '../../wrappers/error.js';
|
|
5
|
+
import type { LoggerOptions } from '../../wrappers/logger.js';
|
|
6
|
+
export type Handler = (request: IncomingMessage, response: ServerResponse) => Promise<void> | void;
|
|
7
|
+
export type HandlerParams = [request: IncomingMessage, response: ServerResponse];
|
|
8
|
+
export type Decorator = (handler: Handler) => Handler;
|
|
9
|
+
export type Compose = (...decorators: Array<Decorator>) => Decorator;
|
|
10
|
+
export type Wrapper<Options> = (handler: Handler, args: HandlerParams, options?: Options) => Response<void>;
|
|
11
|
+
export type Factory = <Options = undefined>(wrapper: Wrapper<Options>) => (options?: Options) => Decorator;
|
|
12
|
+
export type ApiOptions = {
|
|
13
|
+
error?: ErrorOptions<HandlerParams>;
|
|
14
|
+
healthcheck?: HealthcheckOptions;
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
logger?: LoggerOptions;
|
|
17
|
+
};
|
|
18
|
+
export type Api = (options?: ApiOptions) => Decorator;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const withCors: (options?: undefined) => import("../types.js").Decorator;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { STATUS_CODES } from 'node:http';
|
|
2
|
+
export const withError = (options = {}) => (handler) => async (request, response) => {
|
|
3
|
+
try {
|
|
4
|
+
await handler(request, response);
|
|
5
|
+
}
|
|
6
|
+
catch (err) {
|
|
7
|
+
await options.errorHandler?.(err, [request, response]);
|
|
8
|
+
if (response.writableEnded) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (response.headersSent) {
|
|
12
|
+
response.end();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
response
|
|
16
|
+
.writeHead(500, {
|
|
17
|
+
'content-type': 'application/json',
|
|
18
|
+
})
|
|
19
|
+
.end(JSON.stringify({ message: STATUS_CODES[500] }));
|
|
20
|
+
}
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const withHeaders: (options?: Record<string, string> | undefined) => import("../types.js").Decorator;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { factory } from '../factory/index.js';
|
|
2
|
+
export const withHeaders = factory(async (handler, args, options = {}) => {
|
|
3
|
+
const [request, response] = args;
|
|
4
|
+
for (const [name, value] of Object.entries(options)) {
|
|
5
|
+
response.setHeader(name.toLowerCase(), value);
|
|
6
|
+
}
|
|
7
|
+
await handler(request, response);
|
|
8
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { HealthcheckOptions as BaseHealthcheckOptions } from '../../wrappers/healthcheck.js';
|
|
2
|
+
export type HealthcheckOptions = BaseHealthcheckOptions & {
|
|
3
|
+
body?: unknown;
|
|
4
|
+
};
|
|
5
|
+
export declare const withHealthcheck: (options?: HealthcheckOptions | undefined) => import("../types.js").Decorator;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { STATUS_CODES } from 'node:http';
|
|
2
|
+
import { factory } from '../factory/index.js';
|
|
3
|
+
export const withHealthcheck = factory(async (handler, args, options = {}) => {
|
|
4
|
+
const { path = '/healthcheck', action, body } = options;
|
|
5
|
+
const [request, response] = args;
|
|
6
|
+
const pathname = (request.url ?? '').split('?')[0];
|
|
7
|
+
if (pathname !== path) {
|
|
8
|
+
await handler(...args);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (action) {
|
|
12
|
+
await action();
|
|
13
|
+
}
|
|
14
|
+
response
|
|
15
|
+
.writeHead(200, {
|
|
16
|
+
'content-type': 'application/json',
|
|
17
|
+
})
|
|
18
|
+
.end(JSON.stringify(body ?? { message: STATUS_CODES[200] }));
|
|
19
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createLogger } from '@vyriy/logger';
|
|
2
|
+
import { factory } from '../factory/index.js';
|
|
3
|
+
export const withLogger = factory(async (handler, args, options = {}) => {
|
|
4
|
+
const { logger = createLogger() } = options;
|
|
5
|
+
const [request, response] = args;
|
|
6
|
+
logger.info('Request:', request.method, request.url);
|
|
7
|
+
const cleanup = () => {
|
|
8
|
+
response.off('close', logResult);
|
|
9
|
+
response.off('finish', logResult);
|
|
10
|
+
};
|
|
11
|
+
const logResult = () => {
|
|
12
|
+
cleanup();
|
|
13
|
+
logger.info('Result:', response.statusCode);
|
|
14
|
+
};
|
|
15
|
+
response.once('close', logResult);
|
|
16
|
+
response.once('finish', logResult);
|
|
17
|
+
try {
|
|
18
|
+
await handler(...args);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
cleanup();
|
|
22
|
+
if (error instanceof Error) {
|
|
23
|
+
logger.error('Error:', error.message);
|
|
24
|
+
}
|
|
25
|
+
logger.error(error);
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
});
|
package/api/index.d.ts
ADDED
package/api/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const compose = (...fns) => fns.reduceRight((prevDecorator, nextDecorator) => (handler) => nextDecorator(prevDecorator(handler)));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { compose } from './compose.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { compose } from './compose.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Context } from 'aws-lambda';
|
|
2
|
+
import type { ResponseStream, Factory, HandlerParams } from '../types.js';
|
|
3
|
+
export declare const getResponseStream: <Event>(args: HandlerParams<Event>) => ResponseStream;
|
|
4
|
+
export declare const getContext: <Event>(args: HandlerParams<Event>) => Context;
|
|
5
|
+
export declare const factory: Factory;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { factory, getContext, getResponseStream } from './factory.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { factory, getContext, getResponseStream } from './factory.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { compose } from './compose/index.js';
|
|
2
|
+
import { API_HEADERS } from '../api.js';
|
|
3
|
+
import { withChaos } from './wrappers/chaos.js';
|
|
4
|
+
import { withContext } from './wrappers/context.js';
|
|
5
|
+
import { withCors } from './wrappers/cors.js';
|
|
6
|
+
import { withApiError } from './wrappers/error.js';
|
|
7
|
+
import { withHeaders } from './wrappers/headers.js';
|
|
8
|
+
import { withHealthcheck } from './wrappers/healthcheck.js';
|
|
9
|
+
import { withLogger } from './wrappers/logger.js';
|
|
10
|
+
import { withSmoke } from './wrappers/smoke.js';
|
|
11
|
+
import { withTimeout } from './wrappers/timeout.js';
|
|
12
|
+
export const createApi = (options = {}) => compose(withApiError(options.error), withLogger(options.logger), withTimeout(), withContext(), withSmoke(), withHealthcheck(options.healthcheck), withHeaders(options.headers ?? API_HEADERS), withCors(), withChaos(options.chaos));
|
|
13
|
+
export const api = createApi();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Context } from 'aws-lambda';
|
|
2
|
+
import type { ChaosOptions } from '@vyriy/chaos';
|
|
3
|
+
import type { ApiEvent, ApiResult } from '../types.js';
|
|
4
|
+
import type { ApiErrorOptions } from '../wrappers/error.js';
|
|
5
|
+
import type { HealthcheckOptions } from '../wrappers/healthcheck.js';
|
|
6
|
+
import type { Response } from '../../types.js';
|
|
7
|
+
import type { LoggerOptions } from '../../wrappers/logger.js';
|
|
8
|
+
export type { Context } from 'aws-lambda';
|
|
9
|
+
export type { ApiEvent, ApiResult } from '../types.js';
|
|
10
|
+
export type ResponseStream = {
|
|
11
|
+
end: {
|
|
12
|
+
(): unknown;
|
|
13
|
+
(chunk: string | Buffer | Uint8Array): unknown;
|
|
14
|
+
};
|
|
15
|
+
setContentType?: (contentType: string) => unknown;
|
|
16
|
+
writableEnded?: boolean;
|
|
17
|
+
write(chunk: string | Buffer | Uint8Array): unknown;
|
|
18
|
+
};
|
|
19
|
+
export type HandlerParams<Event> = [event: Event, responseStream: ResponseStream, context: Context];
|
|
20
|
+
export type Handler<Event> = (event: Event, responseStream: ResponseStream, context: Context) => Response<void>;
|
|
21
|
+
export type Decorator<Event> = (handler: Handler<Event>) => Handler<Event>;
|
|
22
|
+
export type Compose = <Event>(...decorators: Array<Decorator<Event>>) => Decorator<Event>;
|
|
23
|
+
export type Wrapper<Options> = <Event>(handler: Handler<Event>, args: HandlerParams<Event>, options?: Options) => Response<void>;
|
|
24
|
+
export type TypedWrapper<Event, Options> = (handler: Handler<Event>, args: HandlerParams<Event>, options?: Options) => Response<void>;
|
|
25
|
+
export type Factory = {
|
|
26
|
+
<Options = undefined>(wrapper: Wrapper<Options>): <Event>(options?: Options) => Decorator<Event>;
|
|
27
|
+
<Options, Event>(wrapper: TypedWrapper<Event, Options>): (options?: Options) => Decorator<Event>;
|
|
28
|
+
};
|
|
29
|
+
export type ApiOptions = {
|
|
30
|
+
chaos?: ChaosOptions;
|
|
31
|
+
error?: ApiErrorOptions<HandlerParams<ApiEvent>, ApiResult | void>;
|
|
32
|
+
healthcheck?: HealthcheckOptions;
|
|
33
|
+
headers?: Record<string, string>;
|
|
34
|
+
logger?: LoggerOptions;
|
|
35
|
+
};
|
|
36
|
+
export type Api = (options?: ApiOptions) => Decorator<ApiEvent>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { chaos } from '@vyriy/chaos';
|
|
2
2
|
import { getConfig } from '@vyriy/config';
|
|
3
|
-
import { factory
|
|
3
|
+
import { factory } from '../factory/index.js';
|
|
4
4
|
const getChaosEnabled = () => getConfig('CHAOS_ENABLED', false, 'boolean');
|
|
5
5
|
const getChaosErrorEnabled = () => getConfig('CHAOS_ERROR_ENABLED', true, 'boolean');
|
|
6
6
|
const getChaosTimeoutEnabled = () => getConfig('CHAOS_TIMEOUT_ENABLED', true, 'boolean');
|
|
@@ -33,14 +33,3 @@ export const withChaos = factory(async (handler, args, options = {}) => {
|
|
|
33
33
|
});
|
|
34
34
|
return handler(...args);
|
|
35
35
|
});
|
|
36
|
-
export const streamWithChaos = streamFactory(async (handler, args, options = {}) => {
|
|
37
|
-
const enabled = options.enabled ?? getChaosEnabled();
|
|
38
|
-
const strategy = getStrategy(options);
|
|
39
|
-
await chaos({
|
|
40
|
-
...options,
|
|
41
|
-
enabled: enabled && (strategy !== 'random' || getChaosErrorEnabled() || getChaosTimeoutEnabled()),
|
|
42
|
-
strategy,
|
|
43
|
-
timeoutMs: options.timeoutMs ?? getChaosTimeoutMs(),
|
|
44
|
-
});
|
|
45
|
-
return handler(...args);
|
|
46
|
-
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const withContext: <Event>(options?: undefined) => import("../types.js").Decorator<Event>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const withCors: (options?: unknown) => import("../types.js").Decorator<import("aws-lambda").APIGatewayProxyEvent>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { factory } from '../factory/index.js';
|
|
2
|
+
import { responseStream } from './stream.js';
|
|
3
|
+
export const withCors = factory(async (handler, args) => {
|
|
4
|
+
const [request, stream] = args;
|
|
5
|
+
if (request.httpMethod === 'OPTIONS') {
|
|
6
|
+
responseStream(stream, { statusCode: 204 }).end();
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
await handler(...args);
|
|
10
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ApiEvent, ApiResult, Decorator, HandlerParams } from '../types.js';
|
|
2
|
+
import type { ApiErrorOptions } from '../../wrappers/error.js';
|
|
3
|
+
export declare const withApiError: (options?: ApiErrorOptions<HandlerParams<ApiEvent>, ApiResult | void>) => Decorator<ApiEvent>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { STATUS_CODES } from 'node:http';
|
|
2
|
+
import { responseStream } from './stream.js';
|
|
3
|
+
const defaultErrorResult = () => ({
|
|
4
|
+
statusCode: 500,
|
|
5
|
+
headers: {
|
|
6
|
+
'content-type': 'application/json',
|
|
7
|
+
},
|
|
8
|
+
body: JSON.stringify({
|
|
9
|
+
message: STATUS_CODES[500],
|
|
10
|
+
}),
|
|
11
|
+
});
|
|
12
|
+
export const withApiError = (options = {}) => (handler) => async (event, stream, context) => {
|
|
13
|
+
try {
|
|
14
|
+
await handler(event, stream, context);
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
const result = (await options.errorHandler?.(err, [event, stream, context])) ?? defaultErrorResult();
|
|
18
|
+
if (result) {
|
|
19
|
+
responseStream(stream, {
|
|
20
|
+
headers: result.headers,
|
|
21
|
+
statusCode: result.statusCode,
|
|
22
|
+
}).end(result.body);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const withHeaders: (options?: Record<string, string> | undefined) => import("../types.js").Decorator<import("aws-lambda").APIGatewayProxyEvent>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { factory } from '../factory/index.js';
|
|
2
|
+
import { responseStream } from './stream.js';
|
|
3
|
+
const normalizeHeaders = (headers) => Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]));
|
|
4
|
+
export const withHeaders = factory(async (handler, args, options = {}) => {
|
|
5
|
+
const [event, stream, context] = args;
|
|
6
|
+
await handler(event, responseStream(stream, { headers: normalizeHeaders(options) }), context);
|
|
7
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { STATUS_CODES } from 'node:http';
|
|
2
|
+
import { factory } from '../factory/index.js';
|
|
3
|
+
import { responseStream } from './stream.js';
|
|
4
|
+
const getHealthcheckResult = async (event, options = {}) => {
|
|
5
|
+
const { path = '/healthcheck', action } = options;
|
|
6
|
+
if (event.path !== path) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
if (action) {
|
|
10
|
+
await action();
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
statusCode: 200,
|
|
14
|
+
body: JSON.stringify({
|
|
15
|
+
message: STATUS_CODES[200],
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export const withHealthcheck = factory(async (handler, args, options = {}) => {
|
|
20
|
+
const [event, stream] = args;
|
|
21
|
+
const result = await getHealthcheckResult(event, options);
|
|
22
|
+
if (result) {
|
|
23
|
+
responseStream(stream, { statusCode: result.statusCode }).end(result.body);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
await handler(...args);
|
|
27
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './chaos.js';
|
|
2
|
+
export * from './context.js';
|
|
3
|
+
export * from './cors.js';
|
|
4
|
+
export * from './error.js';
|
|
5
|
+
export * from './headers.js';
|
|
6
|
+
export * from './healthcheck.js';
|
|
7
|
+
export * from './logger.js';
|
|
8
|
+
export * from './smoke.js';
|
|
9
|
+
export * from './stream.js';
|
|
10
|
+
export * from './timeout.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './chaos.js';
|
|
2
|
+
export * from './context.js';
|
|
3
|
+
export * from './cors.js';
|
|
4
|
+
export * from './error.js';
|
|
5
|
+
export * from './headers.js';
|
|
6
|
+
export * from './healthcheck.js';
|
|
7
|
+
export * from './logger.js';
|
|
8
|
+
export * from './smoke.js';
|
|
9
|
+
export * from './stream.js';
|
|
10
|
+
export * from './timeout.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createLogger } from '@vyriy/logger';
|
|
2
|
+
import { factory, getContext } from '../factory/index.js';
|
|
3
|
+
export const withLogger = factory(async (handler, args, options = {}) => {
|
|
4
|
+
const { logger = createLogger() } = options;
|
|
5
|
+
const [event] = args;
|
|
6
|
+
const context = getContext(args);
|
|
7
|
+
logger.info('Event:', event);
|
|
8
|
+
logger.info('Context:', context);
|
|
9
|
+
try {
|
|
10
|
+
await handler(...args);
|
|
11
|
+
logger.info('Result:', undefined);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (error instanceof Error) {
|
|
15
|
+
logger.error('Error:', error.message);
|
|
16
|
+
}
|
|
17
|
+
logger.error(error);
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { smoke } from '@vyriy/smoke';
|
|
2
2
|
import { responseStream } from './stream.js';
|
|
3
|
-
export const withSmoke = () => (handler) => async (event, context) => {
|
|
4
|
-
const result = smoke(event);
|
|
5
|
-
return (result || (await handler(event, context)));
|
|
6
|
-
};
|
|
7
|
-
export const streamWithSmoke = () => (handler) => async (event, stream, context) => {
|
|
3
|
+
export const withSmoke = () => (handler) => async (event, stream, context) => {
|
|
8
4
|
const result = smoke(event);
|
|
9
5
|
if (result) {
|
|
10
6
|
responseStream(stream, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const withTimeout: <Event>(options?: undefined) => import("../types.js").Decorator<Event>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { timeout as error } from '@vyriy/timeout';
|
|
2
|
+
import { factory, getContext } from '../factory/index.js';
|
|
3
|
+
export const withTimeout = factory(async (handler, args) => Promise.race([
|
|
4
|
+
error(getContext(args).getRemainingTimeInMillis() - 1000),
|
|
5
|
+
handler(...args),
|
|
6
|
+
]));
|
package/api/types.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
|
2
|
+
import type { ChaosOptions } from '@vyriy/chaos';
|
|
3
|
+
import type { Decorator, HandlerParams } from '../types.js';
|
|
4
|
+
import type { ApiErrorOptions } from './wrappers/error.js';
|
|
5
|
+
import type { HealthcheckOptions } from './wrappers/healthcheck.js';
|
|
6
|
+
import type { LoggerOptions } from '../wrappers/logger.js';
|
|
7
|
+
export type { Decorator, Handler, HandlerParams } from '../types.js';
|
|
8
|
+
export type ApiResult = APIGatewayProxyResult;
|
|
9
|
+
export type ApiEvent = APIGatewayProxyEvent;
|
|
10
|
+
export type ApiOptions = {
|
|
11
|
+
chaos?: ChaosOptions;
|
|
12
|
+
error?: ApiErrorOptions<HandlerParams<ApiEvent>, ApiResult>;
|
|
13
|
+
healthcheck?: HealthcheckOptions;
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
logger?: LoggerOptions;
|
|
16
|
+
};
|
|
17
|
+
export type Api = (options?: ApiOptions) => Decorator<ApiEvent, ApiResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { withChaos } from '../../wrappers/chaos.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { withChaos } from '../../wrappers/chaos.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const withCors: (options?: unknown) => import("../types.js").Decorator<import("aws-lambda").APIGatewayProxyEvent, import("aws-lambda").APIGatewayProxyResult>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { factory } from '../../factory/index.js';
|
|
2
|
+
export const withCors = factory(async (handler, args) => {
|
|
3
|
+
const [request] = args;
|
|
4
|
+
if (request.httpMethod === 'OPTIONS') {
|
|
5
|
+
return {
|
|
6
|
+
body: '',
|
|
7
|
+
statusCode: 204,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
return handler(...args);
|
|
11
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ApiEvent, ApiResult, Decorator, HandlerParams } from '../types.js';
|
|
2
|
+
import type { ApiErrorOptions } from '../../wrappers/error.js';
|
|
3
|
+
export declare const withApiError: (options?: ApiErrorOptions<HandlerParams<ApiEvent>, ApiResult>) => Decorator<ApiEvent, ApiResult>;
|
|
4
|
+
export type { ApiErrorHandler, ApiErrorOptions } from '../../wrappers/error.js';
|