@vyriy/handler 0.7.7 → 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.
Files changed (161) hide show
  1. package/README.md +395 -180
  2. package/api/api.d.ts +10 -0
  3. package/api/api.js +19 -0
  4. package/api/http/compose/compose.d.ts +2 -0
  5. package/api/http/compose/compose.js +1 -0
  6. package/api/http/compose/index.d.ts +1 -0
  7. package/api/http/compose/index.js +1 -0
  8. package/api/http/factory/factory.d.ts +2 -0
  9. package/api/http/factory/factory.js +1 -0
  10. package/api/http/factory/index.d.ts +1 -0
  11. package/api/http/factory/index.js +1 -0
  12. package/api/http/http.d.ts +3 -0
  13. package/api/http/http.js +14 -0
  14. package/api/http/index.d.ts +3 -0
  15. package/api/http/index.js +2 -0
  16. package/api/http/types.d.ts +18 -0
  17. package/api/http/wrappers/cors.d.ts +1 -0
  18. package/api/http/wrappers/cors.js +9 -0
  19. package/api/http/wrappers/error.d.ts +3 -0
  20. package/api/http/wrappers/error.js +21 -0
  21. package/api/http/wrappers/headers.d.ts +1 -0
  22. package/api/http/wrappers/headers.js +8 -0
  23. package/api/http/wrappers/healthcheck.d.ts +5 -0
  24. package/api/http/wrappers/healthcheck.js +19 -0
  25. package/api/http/wrappers/index.d.ts +5 -0
  26. package/api/http/wrappers/index.js +5 -0
  27. package/api/http/wrappers/logger.d.ts +2 -0
  28. package/api/http/wrappers/logger.js +28 -0
  29. package/api/index.d.ts +3 -0
  30. package/api/index.js +2 -0
  31. package/api/stream/compose/compose.d.ts +2 -0
  32. package/api/stream/compose/compose.js +1 -0
  33. package/api/stream/compose/index.d.ts +1 -0
  34. package/api/stream/compose/index.js +1 -0
  35. package/api/stream/factory/factory.d.ts +5 -0
  36. package/api/stream/factory/factory.js +3 -0
  37. package/api/stream/factory/index.d.ts +1 -0
  38. package/api/stream/factory/index.js +1 -0
  39. package/api/stream/index.d.ts +3 -0
  40. package/api/stream/index.js +2 -0
  41. package/api/stream/stream.d.ts +3 -0
  42. package/api/stream/stream.js +13 -0
  43. package/api/stream/types.d.ts +36 -0
  44. package/api/stream/wrappers/chaos.d.ts +2 -0
  45. package/{wrapper → api/stream/wrappers}/chaos.js +1 -12
  46. package/api/stream/wrappers/context.d.ts +1 -0
  47. package/api/stream/wrappers/context.js +6 -0
  48. package/api/stream/wrappers/cors.d.ts +1 -0
  49. package/api/stream/wrappers/cors.js +10 -0
  50. package/api/stream/wrappers/error.d.ts +3 -0
  51. package/{wrapper → api/stream/wrappers}/error.js +1 -18
  52. package/api/stream/wrappers/headers.d.ts +1 -0
  53. package/api/stream/wrappers/headers.js +7 -0
  54. package/api/stream/wrappers/healthcheck.d.ts +2 -0
  55. package/{wrapper → api/stream/wrappers}/healthcheck.js +1 -6
  56. package/api/stream/wrappers/index.d.ts +10 -0
  57. package/api/stream/wrappers/index.js +10 -0
  58. package/api/stream/wrappers/logger.d.ts +2 -0
  59. package/api/stream/wrappers/logger.js +20 -0
  60. package/api/stream/wrappers/smoke.d.ts +2 -0
  61. package/{wrapper → api/stream/wrappers}/smoke.js +1 -5
  62. package/api/stream/wrappers/timeout.d.ts +1 -0
  63. package/api/stream/wrappers/timeout.js +6 -0
  64. package/api/types.d.ts +17 -0
  65. package/api/wrappers/chaos.d.ts +1 -0
  66. package/api/wrappers/chaos.js +1 -0
  67. package/{wrapper → api/wrappers}/cors.d.ts +0 -1
  68. package/api/wrappers/cors.js +11 -0
  69. package/api/wrappers/error.d.ts +4 -0
  70. package/api/wrappers/error.js +18 -0
  71. package/{wrapper → api/wrappers}/headers.d.ts +0 -1
  72. package/{wrapper → api/wrappers}/headers.js +1 -6
  73. package/{wrapper → api/wrappers}/healthcheck.d.ts +0 -1
  74. package/api/wrappers/healthcheck.js +22 -0
  75. package/api/wrappers/index.d.ts +5 -0
  76. package/api/wrappers/index.js +5 -0
  77. package/compose/compose.d.ts +2 -0
  78. package/compose/compose.js +1 -0
  79. package/compose/index.d.ts +1 -0
  80. package/compose/index.js +1 -0
  81. package/create/create.d.ts +12 -0
  82. package/create/create.js +22 -0
  83. package/create/index.d.ts +1 -0
  84. package/create/index.js +1 -0
  85. package/dynamodb/dynamodb.d.ts +4 -0
  86. package/dynamodb/dynamodb.js +8 -0
  87. package/dynamodb/index.d.ts +1 -0
  88. package/dynamodb/index.js +1 -0
  89. package/eventBridge/eventBridge.d.ts +4 -0
  90. package/eventBridge/eventBridge.js +8 -0
  91. package/eventBridge/index.d.ts +1 -0
  92. package/eventBridge/index.js +1 -0
  93. package/factory/factory.d.ts +4 -0
  94. package/factory/factory.js +2 -0
  95. package/factory/index.d.ts +1 -0
  96. package/factory/index.js +1 -0
  97. package/index.d.ts +21 -19
  98. package/index.js +21 -19
  99. package/package.json +731 -185
  100. package/s3/index.d.ts +1 -0
  101. package/s3/index.js +1 -0
  102. package/s3/s3.d.ts +4 -0
  103. package/s3/s3.js +8 -0
  104. package/schedule/index.d.ts +1 -0
  105. package/schedule/index.js +1 -0
  106. package/schedule/schedule.d.ts +4 -0
  107. package/schedule/schedule.js +8 -0
  108. package/ses/index.d.ts +1 -0
  109. package/ses/index.js +1 -0
  110. package/ses/ses.d.ts +4 -0
  111. package/ses/ses.js +8 -0
  112. package/sns/index.d.ts +1 -0
  113. package/sns/index.js +1 -0
  114. package/sns/sns.d.ts +4 -0
  115. package/sns/sns.js +8 -0
  116. package/sqs/index.d.ts +1 -0
  117. package/sqs/index.js +1 -0
  118. package/sqs/sqs.d.ts +4 -0
  119. package/sqs/sqs.js +8 -0
  120. package/types.d.ts +12 -22
  121. package/{wrapper → wrappers}/chaos.d.ts +0 -1
  122. package/wrappers/chaos.js +35 -0
  123. package/{wrapper → wrappers}/context.d.ts +0 -1
  124. package/wrappers/context.js +6 -0
  125. package/{wrapper → wrappers}/error.d.ts +1 -3
  126. package/wrappers/error.js +9 -0
  127. package/wrappers/index.d.ts +6 -0
  128. package/wrappers/index.js +6 -0
  129. package/{wrapper → wrappers}/logger.d.ts +0 -1
  130. package/wrappers/logger.js +21 -0
  131. package/wrappers/smoke.d.ts +2 -0
  132. package/wrappers/smoke.js +5 -0
  133. package/{wrapper → wrappers}/timeout.d.ts +0 -1
  134. package/wrappers/timeout.js +6 -0
  135. package/api.d.ts +0 -2
  136. package/api.js +0 -24
  137. package/compose.d.ts +0 -3
  138. package/compose.js +0 -2
  139. package/dynamodb.d.ts +0 -2
  140. package/dynamodb.js +0 -7
  141. package/eventBridge.d.ts +0 -2
  142. package/eventBridge.js +0 -7
  143. package/factory.d.ts +0 -7
  144. package/factory.js +0 -5
  145. package/s3.d.ts +0 -2
  146. package/s3.js +0 -7
  147. package/schedule.d.ts +0 -2
  148. package/schedule.js +0 -7
  149. package/ses.d.ts +0 -2
  150. package/ses.js +0 -7
  151. package/sns.d.ts +0 -2
  152. package/sns.js +0 -7
  153. package/sqs.d.ts +0 -2
  154. package/sqs.js +0 -7
  155. package/wrapper/context.js +0 -11
  156. package/wrapper/cors.js +0 -20
  157. package/wrapper/logger.js +0 -39
  158. package/wrapper/smoke.d.ts +0 -3
  159. package/wrapper/timeout.js +0 -10
  160. /package/{wrapper → api/stream/wrappers}/stream.d.ts +0 -0
  161. /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,2 @@
1
+ import type { Compose } from '../types.js';
2
+ export declare const compose: Compose;
@@ -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,2 @@
1
+ import type { Factory } from '../types.js';
2
+ export declare const factory: Factory;
@@ -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';
@@ -0,0 +1,3 @@
1
+ import type { Api } from './types.js';
2
+ export declare const createApi: Api;
3
+ export declare const api: import("./types.js").Decorator;
@@ -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,3 @@
1
+ export { api, createApi, createApi as create } from './http.js';
2
+ export * from './wrappers/index.js';
3
+ export type * from './types.js';
@@ -0,0 +1,2 @@
1
+ export { api, createApi, createApi as create } from './http.js';
2
+ export * from './wrappers/index.js';
@@ -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,9 @@
1
+ import { factory } from '../factory/index.js';
2
+ export const withCors = factory(async (handler, args) => {
3
+ const [request, response] = args;
4
+ if (request.method === 'OPTIONS') {
5
+ response.writeHead(204).end();
6
+ return;
7
+ }
8
+ await handler(...args);
9
+ });
@@ -0,0 +1,3 @@
1
+ import type { Decorator, HandlerParams } from '../types.js';
2
+ import type { ErrorOptions } from '../../../wrappers/error.js';
3
+ export declare const withError: (options?: ErrorOptions<HandlerParams>) => 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,5 @@
1
+ export * from './cors.js';
2
+ export * from './error.js';
3
+ export * from './headers.js';
4
+ export * from './healthcheck.js';
5
+ export * from './logger.js';
@@ -0,0 +1,5 @@
1
+ export * from './cors.js';
2
+ export * from './error.js';
3
+ export * from './headers.js';
4
+ export * from './healthcheck.js';
5
+ export * from './logger.js';
@@ -0,0 +1,2 @@
1
+ import type { LoggerOptions } from '../../../wrappers/logger.js';
2
+ export declare const withLogger: (options?: LoggerOptions | undefined) => import("../types.js").Decorator;
@@ -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
@@ -0,0 +1,3 @@
1
+ export { api, createApi, createApi as create } from './api.js';
2
+ export * from './wrappers/index.js';
3
+ export type * from './types.js';
package/api/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { api, createApi, createApi as create } from './api.js';
2
+ export * from './wrappers/index.js';
@@ -0,0 +1,2 @@
1
+ import type { Compose } from '../types.js';
2
+ export declare const compose: Compose;
@@ -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,3 @@
1
+ export const getResponseStream = (args) => args[1];
2
+ export const getContext = (args) => args[2];
3
+ export const factory = (wrapper) => (options) => (handler) => async (event, responseStream, context) => wrapper(handler, [event, responseStream, context], options);
@@ -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,3 @@
1
+ export { api, createApi, createApi as create } from './stream.js';
2
+ export * from './wrappers/index.js';
3
+ export type * from './types.js';
@@ -0,0 +1,2 @@
1
+ export { api, createApi, createApi as create } from './stream.js';
2
+ export * from './wrappers/index.js';
@@ -0,0 +1,3 @@
1
+ import type { Api } from './types.js';
2
+ export declare const createApi: Api;
3
+ export declare const api: import("./types.js").Decorator<import("aws-lambda").APIGatewayProxyEvent>;
@@ -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>;
@@ -0,0 +1,2 @@
1
+ import { type ChaosOptions } from '@vyriy/chaos';
2
+ export declare const withChaos: <Event>(options?: ChaosOptions | undefined) => import("../types.js").Decorator<Event>;
@@ -1,6 +1,6 @@
1
1
  import { chaos } from '@vyriy/chaos';
2
2
  import { getConfig } from '@vyriy/config';
3
- import { factory, streamFactory } from '../factory.js';
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,6 @@
1
+ import { factory, getContext } from '../factory/index.js';
2
+ export const withContext = factory(async (handler, args) => {
3
+ const ctx = getContext(args);
4
+ ctx.callbackWaitsForEmptyEventLoop = false;
5
+ return handler(...args);
6
+ });
@@ -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>;
@@ -9,24 +9,7 @@ const defaultErrorResult = () => ({
9
9
  message: STATUS_CODES[500],
10
10
  }),
11
11
  });
12
- export const withError = (options = {}) => (handler) => async (event, context) => {
13
- try {
14
- return await handler(event, context);
15
- }
16
- catch (err) {
17
- await options.errorHandler?.(err, [event, context]);
18
- throw err;
19
- }
20
- };
21
- export const withApiError = (options = {}) => (handler) => async (event, context) => {
22
- try {
23
- return await handler(event, context);
24
- }
25
- catch (err) {
26
- return options.errorHandler?.(err, [event, context]) ?? defaultErrorResult();
27
- }
28
- };
29
- export const streamWithApiError = (options = {}) => (handler) => async (event, stream, context) => {
12
+ export const withApiError = (options = {}) => (handler) => async (event, stream, context) => {
30
13
  try {
31
14
  await handler(event, stream, context);
32
15
  }
@@ -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,2 @@
1
+ import type { HealthcheckOptions } from '../../wrappers/healthcheck.js';
2
+ export declare const withHealthcheck: (options?: HealthcheckOptions | undefined) => import("../types.js").Decorator<import("aws-lambda").APIGatewayProxyEvent>;
@@ -1,5 +1,5 @@
1
1
  import { STATUS_CODES } from 'node:http';
2
- import { factory, streamFactory } from '../factory.js';
2
+ import { factory } from '../factory/index.js';
3
3
  import { responseStream } from './stream.js';
4
4
  const getHealthcheckResult = async (event, options = {}) => {
5
5
  const { path = '/healthcheck', action } = options;
@@ -17,11 +17,6 @@ const getHealthcheckResult = async (event, options = {}) => {
17
17
  };
18
18
  };
19
19
  export const withHealthcheck = factory(async (handler, args, options = {}) => {
20
- const [event] = args;
21
- const result = await getHealthcheckResult(event, options);
22
- return result ?? handler(...args);
23
- });
24
- export const streamWithHealthcheck = streamFactory(async (handler, args, options = {}) => {
25
20
  const [event, stream] = args;
26
21
  const result = await getHealthcheckResult(event, options);
27
22
  if (result) {
@@ -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,2 @@
1
+ import type { LoggerOptions } from '../../../wrappers/logger.js';
2
+ export declare const withLogger: <Event>(options?: LoggerOptions | undefined) => import("../types.js").Decorator<Event>;
@@ -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
+ });
@@ -0,0 +1,2 @@
1
+ import type { Decorator } from '../types.js';
2
+ export declare const withSmoke: <Event>() => Decorator<Event>;
@@ -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';
@@ -1,2 +1 @@
1
1
  export declare const withCors: (options?: unknown) => import("../types.js").Decorator<import("aws-lambda").APIGatewayProxyEvent, import("aws-lambda").APIGatewayProxyResult>;
2
- export declare const streamWithCors: (options?: unknown) => import("../types.js").StreamDecorator<import("aws-lambda").APIGatewayProxyEvent>;
@@ -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';
@@ -0,0 +1,18 @@
1
+ import { STATUS_CODES } from 'node:http';
2
+ const defaultErrorResult = () => ({
3
+ statusCode: 500,
4
+ headers: {
5
+ 'content-type': 'application/json',
6
+ },
7
+ body: JSON.stringify({
8
+ message: STATUS_CODES[500],
9
+ }),
10
+ });
11
+ export const withApiError = (options = {}) => (handler) => async (event, context) => {
12
+ try {
13
+ return await handler(event, context);
14
+ }
15
+ catch (err) {
16
+ return options.errorHandler?.(err, [event, context]) ?? defaultErrorResult();
17
+ }
18
+ };