@yopdev/dev-server 3.0.3-alpha.2 → 3.0.3-beta.2

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.
@@ -23,7 +23,7 @@ class DynamoDbTableCloudFormation {
23
23
  command: command,
24
24
  ttlAttribute: resource.TimeToLiveSpecification?.AttributeName,
25
25
  }))))
26
- .tap(() => this.LOGGER.info('configured'))
26
+ .tap(() => this.LOGGER.debug('configured'))
27
27
  .then((service) => service.start(config));
28
28
  this.stop = () => Promise.resolve();
29
29
  this.createTableCommand = async (definition, throughput) => new client_dynamodb_1.CreateTableCommand({
@@ -4,11 +4,10 @@ import { HttpSettings } from './http-server';
4
4
  import { Authorizer, Route } from './lambda-http-proxy';
5
5
  import { Callback, Service, Startable } from './services';
6
6
  import { LambdaPayloadVersion } from './mappers';
7
- import { APIGatewayAuthorizerResult } from 'aws-lambda';
8
- export declare const newLambdaProxyFromCloudFormationTemplate: <Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event_1, HandlerResponse>(name: string, settings: HttpSettings, payloadVersion: LambdaPayloadVersion<AuthorizerContext, Event_1, HandlerResponse>, config: CloudFormationLambdaProxyConfig<Context, AuthorizerContext, Event_1, HandlerResponse>, callback: Callback<string>) => Startable<Service<string>>;
9
- type CloudFormationLambdaProxyConfig<Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event, HandlerResponse> = {
10
- authorizer?: (config: DevServerConfig) => Authorizer<AuthorizerContext> | undefined;
11
- extraRoutes: Route<Context, AuthorizerContext, Event, HandlerResponse>[];
7
+ export declare const newLambdaProxyFromCloudFormationTemplate: <Context, Event_1, HandlerResponse>(name: string, settings: HttpSettings, payloadVersion: LambdaPayloadVersion<Event_1, HandlerResponse>, config: CloudFormationLambdaProxyConfig<Context, Event_1, HandlerResponse>, callback: Callback<string>) => Startable<Service<string>>;
8
+ type CloudFormationLambdaProxyConfig<Context, Event, HandlerResponse> = {
9
+ authorizer?: (config: DevServerConfig) => Authorizer | undefined;
10
+ extraRoutes: Route<Context, Event, HandlerResponse>[];
12
11
  prepare?: (config: DevServerConfig) => Promise<void>;
13
12
  context?: () => Context;
14
13
  } & CloudFormationSetupConfig;
@@ -11,7 +11,7 @@ const newLambdaProxyFromCloudFormationTemplate = (name, settings, payloadVersion
11
11
  exports.newLambdaProxyFromCloudFormationTemplate = newLambdaProxyFromCloudFormationTemplate;
12
12
  class CloudFormationLambdaProxy extends cloudformation_1.CloudFormationSetup {
13
13
  constructor(name, settings, extraRoutes, payloadVersion, config, callback) {
14
- super(name, (event) => event.Type === 'HttpApi', async (event, handler) => Promise.resolve(this.pathWithCapturingGroups(event.Properties.Path)).then((pathWithCapturingGroups) => ({
14
+ super(name, (event) => event.Type === 'HttpApi' || event.Type === 'Api', async (event, handler) => Promise.resolve(this.pathWithCapturingGroups(event.Properties.Path)).then((pathWithCapturingGroups) => ({
15
15
  method: new RegExp(this.method(event.Properties.Method)),
16
16
  path: new RegExp(`^${pathWithCapturingGroups}${QUERY_STRING_OR_LOCATION_REG_EXP}?$`),
17
17
  weight: this.computeWeight(pathWithCapturingGroups),
@@ -17,7 +17,7 @@ class CloudFormationSetup {
17
17
  .then(async (routes) => this.afterStart(this.name, config, routes));
18
18
  this.resolvedHandlers = async () => {
19
19
  const template = this.template(this.name);
20
- this.LOGGER.info('parsing %s', template);
20
+ this.LOGGER.debug('parsing %s', template);
21
21
  const definition = this.parseApiEvents(template);
22
22
  const functions = this.handlers(this.name);
23
23
  const routes = Object.values(definition)
@@ -33,7 +33,7 @@ class CloudFormationSetup {
33
33
  this.handlerResolver(event, handler) :
34
34
  Promise.reject(new Error(`function ${event.Handler} defined in ${(0, path_1.resolve)(template)} not found in ${(0, path_1.resolve)(functions)}`)))
35
35
  .then((handler) => {
36
- this.LOGGER.info(this.logHandler(handler));
36
+ this.LOGGER.debug(this.logHandler(handler));
37
37
  return handler;
38
38
  })));
39
39
  return Promise.all(routes);
@@ -10,7 +10,7 @@ class Container {
10
10
  constructor(name, image, networkAlias, environment, bindMounts, exposedPorts, logConsumer, startup, endpointBuilder) {
11
11
  this.name = name;
12
12
  this.networkAlias = networkAlias;
13
- this.start = async (config) => Promise.resolve(this.LOGGER.info('start'))
13
+ this.start = async (config) => Promise.resolve(this.LOGGER.debug('start'))
14
14
  .then(() => this.container
15
15
  .withNetwork(config.network)
16
16
  .withNetworkAliases(this.networkAlias)
@@ -19,7 +19,7 @@ class Lazy {
19
19
  async start(config) {
20
20
  const local = this.configurable(config);
21
21
  this.started = local;
22
- this.LOGGER.info('DISCOVERY:%s', local.name);
22
+ this.LOGGER.debug('DISCOVERY:%s', local.name);
23
23
  return local.start(config);
24
24
  }
25
25
  withStartedOr(task, fallback) {
@@ -38,8 +38,8 @@ class Promised {
38
38
  this.start = async (config) => configurable(config)
39
39
  .catch((e) => e?.cleanup?.() ?? Promise.reject(e))
40
40
  .then((service) => initialized = service)
41
- .tap((service) => this.LOGGER.info('DISCOVERY:%s', service.name))
41
+ .tap((service) => this.LOGGER.debug('DISCOVERY:%s', service.name))
42
42
  .then((service) => service.start(config));
43
- this.stop = async () => (initialized ?? { stop: async () => this.LOGGER.info('not started') }).stop();
43
+ this.stop = async () => (initialized ?? { stop: async () => this.LOGGER.warn('not started') }).stop();
44
44
  }
45
45
  }
@@ -24,7 +24,7 @@ class DynamoDbTableCreator {
24
24
  AttributeName: attributeName,
25
25
  }
26
26
  }))
27
- .tap((out) => this.LOGGER.info('set ttl attribute %s? %s', attributeName, out.$metadata.httpStatusCode === 200))
27
+ .tap((out) => this.LOGGER.debug('set ttl attribute %s? %s', attributeName, out.$metadata.httpStatusCode === 200))
28
28
  .then(() => undefined);
29
29
  this.stop = () => Promise.resolve();
30
30
  this.LOGGER = logging_1.LoggerFactory.create(`TABLE[${name}]`);
@@ -1,7 +1,7 @@
1
1
  export { DevServer } from './dev-server';
2
2
  export { newHttpServer as httpServer, HttpSettings } from './http-server';
3
- export { newLambdaHttpProxy as lambdaHttpProxy } from './lambda-http-proxy';
4
- export { v1 as v1LambdaProxyPayload, v2 as v2LambdaProxyPayload } from './mappers';
3
+ export { newLambdaHttpProxy as lambdaHttpProxy, Route } from './lambda-http-proxy';
4
+ export { v1 as v1LambdaProxyPayload, v2 as v2LambdaProxyPayload, LambdaPayloadVersion } from './mappers';
5
5
  export { newLambdaProxyFromCloudFormationTemplate as cloudFormationLambdaProxy } from './cloudformation-lambda-http-proxy';
6
6
  export { newDynamoDbTableFromCloudFormationTemplate as cloudFormationDynamoDbTable } from './cloudformation-dynamodb-table';
7
7
  export { newSnsHttpProxy as snsHttpProxy } from './sns-http-proxy';
@@ -34,11 +34,11 @@ class InternalQueue {
34
34
  consumer.on('processing_error', (err) => {
35
35
  this.LOGGER.error(err, 'failed to process message');
36
36
  });
37
- this.LOGGER.info('consumer for %s initialized', name);
37
+ this.LOGGER.debug('consumer for %s initialized', name);
38
38
  return consumer;
39
39
  })
40
40
  .then(async (consumer) => consumer.start())
41
- .then(() => this.LOGGER.info('started'))
41
+ .then(() => this.LOGGER.debug('started'))
42
42
  .then(() => this);
43
43
  this.stop = async () => this.consumer !== undefined ? (0, stoppable_1.stopConsumer)(this.visibility, this.consumer) : this.LOGGER.warn('no consumer');
44
44
  this.LOGGER = logging_1.LoggerFactory.create(`INTERNALQUEUE[${name}]`);
@@ -46,7 +46,7 @@ class InternalQueue {
46
46
  async createQueue(sqs, name) {
47
47
  return this.creator(sqs)(name) //
48
48
  .then((queue) => {
49
- this.LOGGER.info('created: %s', queue.url);
49
+ this.LOGGER.debug('created: %s', queue.url);
50
50
  return queue;
51
51
  });
52
52
  }
@@ -3,11 +3,11 @@ import { HttpSettings } from "./http-server";
3
3
  import { LambdaMapperFactory } from "./mappers";
4
4
  import { Service, Callback } from "./services";
5
5
  import { APIGatewayAuthorizerResult } from "aws-lambda";
6
- export declare const newLambdaHttpProxy: <Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event_1, HandlerResponse>(name: string, config: {
6
+ export declare const newLambdaHttpProxy: <Context, Event_1, HandlerResponse>(name: string, config: {
7
7
  settings: HttpSettings;
8
- routes: Route<Context, AuthorizerContext, Event_1, HandlerResponse>[];
9
- mapper: LambdaMapperFactory<AuthorizerContext, Event_1, HandlerResponse>;
10
- authorizer?: Authorizer<AuthorizerContext>;
8
+ routes: Route<Context, Event_1, HandlerResponse>[];
9
+ mapper: LambdaMapperFactory<Event_1, HandlerResponse>;
10
+ authorizer?: Authorizer;
11
11
  context?: () => Context;
12
12
  }, callback?: Callback<string>) => Service<string>;
13
13
  export declare abstract class Response {
@@ -18,11 +18,11 @@ export declare abstract class Response {
18
18
  constructor(statusCode: number, contentType: string | undefined, location: string | undefined, cookies: string[] | undefined);
19
19
  body: () => string | Buffer | undefined;
20
20
  }
21
- export type Route<Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event, HandlerResponse> = {
21
+ export type Route<Context, Event, HandlerResponse> = {
22
22
  method: RegExp;
23
23
  path: RegExp;
24
24
  weight: number;
25
- authorizer?: Authorizer<AuthorizerContext>;
25
+ authorizer?: Authorizer;
26
26
  handler: (event: Event, context: Context) => Promise<HandlerResponse>;
27
27
  };
28
- export type Authorizer<Context extends APIGatewayAuthorizerResult> = (authorization: string) => Promise<Context | undefined>;
28
+ export type Authorizer = (authorization: string) => Promise<APIGatewayAuthorizerResult | undefined>;
@@ -20,7 +20,7 @@ class LambdaHttpProxy {
20
20
  this.handler = (authorizer, lambdaHandler) => (request, body, response) => this.mapper.newInstance(request, body)
21
21
  .then(async (mapper) => authorizer(mapper.authorization())
22
22
  .then(async (context) => context?.policyDocument?.Statement?.find((s) => s.Effect === 'Deny') === undefined
23
- ? { ...context, lambda: context?.context }
23
+ ? context
24
24
  : Promise.reject(UNAUTHORIZED))
25
25
  .then((context) => lambdaHandler(mapper.event(context), this.context())
26
26
  .then((lambda) => {
@@ -39,7 +39,7 @@ class LambdaHttpProxy {
39
39
  .find(() => true) ?? this.fallback)(request, body, response);
40
40
  this.server = new http_server_1.HttpServer(name, settings, this.resolveRoute);
41
41
  this.LOGGER = logging_1.LoggerFactory.create(`HTTP->LAMBDA[${this.name}]`);
42
- this.LOGGER.info('registered %i routes', routes.length);
42
+ this.LOGGER.debug('registered %i routes', routes.length);
43
43
  }
44
44
  }
45
45
  class Response {
@@ -1,24 +1,22 @@
1
1
  /// <reference types="node" />
2
2
  import { Message } from "@aws-sdk/client-sqs";
3
- import { APIGatewayProxyEvent, APIGatewayProxyEventPathParameters, APIGatewayProxyEventV2, APIGatewayProxyResult, APIGatewayProxyStructuredResultV2, SQSRecord } from "aws-lambda";
3
+ import { APIGatewayAuthorizerResult, APIGatewayProxyEvent, APIGatewayProxyEventPathParameters, APIGatewayProxyEventV2, APIGatewayProxyResult, APIGatewayProxyStructuredResultV2, SQSRecord } from "aws-lambda";
4
4
  import { IncomingMessage } from "http";
5
5
  import { Response } from "./lambda-http-proxy";
6
6
  export declare const mapToLambdaSqsRecord: (message: Message) => SQSRecord;
7
- export type LambdaPayloadVersion<AuthorizerContext, Event, HandlerResponse> = {
8
- mapper: LambdaMapperFactory<AuthorizerContext, Event, HandlerResponse>;
7
+ export type LambdaPayloadVersion<Event, HandlerResponse> = {
8
+ mapper: LambdaMapperFactory<Event, HandlerResponse>;
9
9
  resolver: PathParameterResolver<Event>;
10
10
  };
11
- export declare const v1: <AuthorizerContext>() => LambdaPayloadVersion<AuthorizerContext, APIGatewayProxyEvent, APIGatewayProxyResult>;
12
- export declare const v2: <AuthorizerContext>() => LambdaPayloadVersion<AuthorizerContext, APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2>;
13
- interface LambdaMapper<AuthorizerContext, Event, HandlerResponse> {
14
- event(context: {
15
- [name: string]: any;
16
- } & AuthorizerContext): Event;
11
+ export declare const v1: () => LambdaPayloadVersion<APIGatewayProxyEvent, APIGatewayProxyResult>;
12
+ export declare const v2: () => LambdaPayloadVersion<APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2>;
13
+ interface LambdaMapper<Event, HandlerResponse> {
14
+ event(context: APIGatewayAuthorizerResult): Event;
17
15
  authorization(): string;
18
16
  toResponse: (response: HandlerResponse) => Response;
19
17
  }
20
- export interface LambdaMapperFactory<AuthorizerContext, Event, LambdaResponse> {
21
- newInstance(request: IncomingMessage, body: string): Promise<LambdaMapper<AuthorizerContext, Event, LambdaResponse>>;
18
+ export interface LambdaMapperFactory<Event, LambdaResponse> {
19
+ newInstance(request: IncomingMessage, body: string): Promise<LambdaMapper<Event, LambdaResponse>>;
22
20
  }
23
21
  export type PathParameterResolver<Event> = {
24
22
  locate: (event: Event) => string;
@@ -70,7 +70,7 @@ class DefaultLambdaMapper {
70
70
  }
71
71
  return [];
72
72
  };
73
- this.event = (context) => ({
73
+ this.event = (authorizerResult) => ({
74
74
  version: '2.0',
75
75
  rawPath: this.url.pathname,
76
76
  rawQueryString: this.url.search,
@@ -102,7 +102,11 @@ class DefaultLambdaMapper {
102
102
  timeEpoch: this.time,
103
103
  accountId: '',
104
104
  apiId: '',
105
- authorizer: context,
105
+ authorizer: {
106
+ ...authorizerResult,
107
+ ...authorizerResult?.context,
108
+ lambda: authorizerResult?.context,
109
+ },
106
110
  httpMethod: '',
107
111
  identity: {
108
112
  accessKey: '',
@@ -14,6 +14,6 @@ class PreTrafficHooks {
14
14
  .then(() => undefined);
15
15
  this.stop = async () => Promise.resolve();
16
16
  this.LOGGER = logging_1.LoggerFactory.create(`PRETRAFFIC[${name}]`);
17
- this.LOGGER.info('%i hooks registered', hooks.length);
17
+ this.LOGGER.debug('%i hooks registered', hooks.length);
18
18
  }
19
19
  }
@@ -15,6 +15,6 @@ class ScheduledTasks {
15
15
  .then(() => undefined);
16
16
  this.stop = async () => Promise.resolve(this.intervals.forEach((interval) => (0, timers_1.clearInterval)(interval)));
17
17
  this.LOGGER = logging_1.LoggerFactory.create(`SCHEDULER[${name}]`);
18
- this.LOGGER.info('registered %i scheduled tasks', schedules.length);
18
+ this.LOGGER.debug('registered %i scheduled tasks', schedules.length);
19
19
  }
20
20
  }
@@ -16,10 +16,10 @@ class Service {
16
16
  .then(() => Promise.reject(error)))
17
17
  .then((started) => this
18
18
  .callbackOrDefault(started)
19
- .then(() => this.LOGGER.info('started'))
19
+ .then(() => this.LOGGER.debug('started'))
20
20
  .then(() => started));
21
21
  this.doStop = () => stop()
22
- .then(() => this.LOGGER.info('stopped'));
22
+ .then(() => this.LOGGER.debug('stopped'));
23
23
  this.stop = () => this.doStop();
24
24
  }
25
25
  }
@@ -60,7 +60,7 @@ class SnsHttpProxy {
60
60
  };
61
61
  this.server = new http_server_1.HttpServer(this.name, this.settings, this.handler(this.method, this.subject));
62
62
  this.LOGGER = logging_1.LoggerFactory.create(`HTTP->SNS[${name}]`);
63
- this.LOGGER.info('forwarding %s %s events to %s', subject ? `events with ${subject} subject` : 'all', method, topic ?? 'the event bus');
63
+ this.LOGGER.debug('forwarding %s %s events to %s', subject ? `events with ${subject} subject` : 'all', method, topic ?? 'the event bus');
64
64
  }
65
65
  }
66
66
  exports.SnsHttpProxy = SnsHttpProxy;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yopdev/dev-server",
3
- "version": "3.0.3-alpha.2",
3
+ "version": "3.0.3-beta.2",
4
4
  "scripts": {
5
5
  "compile": "tsc",
6
6
  "pretest": "npm run compile",
@@ -42,7 +42,7 @@ class DynamoDbTableCloudFormation implements Lifecycle<string> {
42
42
  command: command,
43
43
  ttlAttribute: resource.TimeToLiveSpecification?.AttributeName,
44
44
  }))))
45
- .tap(() => this.LOGGER.info('configured'))
45
+ .tap(() => this.LOGGER.debug('configured'))
46
46
  .then((service) => service.start(config))
47
47
 
48
48
  stop = () => Promise.resolve()
@@ -4,21 +4,20 @@ import { HttpSettings } from './http-server';
4
4
  import { Authorizer, Route, newLambdaHttpProxy } from './lambda-http-proxy';
5
5
  import { Callback, Service, Startable } from './services';
6
6
  import { LambdaMapperFactory, LambdaPayloadVersion, PathParameterResolver } from './mappers';
7
- import { APIGatewayAuthorizerResult } from 'aws-lambda';
8
7
 
9
8
  const PATH_VARIABLE_CAPTURE = /{(.*?)}/g;
10
9
  const QUERY_STRING_OR_LOCATION_REG_EXP = '(?:([?#].*))?';
11
10
  const PROXY_PATH_PARAM = 'proxy';
12
11
  const NOOP_AUTHORIZER = async () => undefined
13
- export const newLambdaProxyFromCloudFormationTemplate = <Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event, HandlerResponse>(
12
+ export const newLambdaProxyFromCloudFormationTemplate = <Context, Event, HandlerResponse>(
14
13
  name: string,
15
14
  settings: HttpSettings,
16
- payloadVersion: LambdaPayloadVersion<AuthorizerContext, Event, HandlerResponse>,
17
- config: CloudFormationLambdaProxyConfig<Context, AuthorizerContext, Event, HandlerResponse>,
15
+ payloadVersion: LambdaPayloadVersion<Event, HandlerResponse>,
16
+ config: CloudFormationLambdaProxyConfig<Context, Event, HandlerResponse>,
18
17
  callback: Callback<string>,
19
18
  ): Startable<Service<string>> => new CloudFormationLambdaProxy(name, settings, config.extraRoutes, payloadVersion, config, callback);
20
19
 
21
- class CloudFormationLambdaProxy<Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event, HandlerResponse> extends CloudFormationSetup<
20
+ class CloudFormationLambdaProxy<Context, Event, HandlerResponse> extends CloudFormationSetup<
22
21
  {
23
22
  Path: string;
24
23
  Method: string;
@@ -27,24 +26,24 @@ class CloudFormationLambdaProxy<Context, AuthorizerContext extends APIGatewayAut
27
26
  }
28
27
  },
29
28
  (event: Event) => Promise<HandlerResponse>,
30
- Route<Context, AuthorizerContext, Event, HandlerResponse>,
29
+ Route<Context, Event, HandlerResponse>,
31
30
  Service<string>
32
31
  > {
33
- private mapper: LambdaMapperFactory<AuthorizerContext, Event, HandlerResponse>;
34
- private authorizer: (cfg: DevServerConfig) => Authorizer<AuthorizerContext>;
32
+ private mapper: LambdaMapperFactory<Event, HandlerResponse>;
33
+ private authorizer: (cfg: DevServerConfig) => Authorizer;
35
34
  private pathParameterResolver: PathParameterResolver<Event>
36
35
 
37
36
  constructor(
38
37
  name: string,
39
38
  private readonly settings: HttpSettings,
40
- private readonly extraRoutes: Route<Context, AuthorizerContext, Event, HandlerResponse>[],
41
- payloadVersion: LambdaPayloadVersion<AuthorizerContext, Event, HandlerResponse>,
42
- config: CloudFormationLambdaProxyConfig<Context, AuthorizerContext, Event, HandlerResponse>,
39
+ private readonly extraRoutes: Route<Context, Event, HandlerResponse>[],
40
+ payloadVersion: LambdaPayloadVersion<Event, HandlerResponse>,
41
+ config: CloudFormationLambdaProxyConfig<Context, Event, HandlerResponse>,
43
42
  private readonly callback?: Callback<string>,
44
43
  ) {
45
44
  super(
46
45
  name,
47
- (event) => event.Type === 'HttpApi',
46
+ (event) => event.Type === 'HttpApi' || event.Type === 'Api',
48
47
  async (event, handler) =>
49
48
  Promise.resolve(this.pathWithCapturingGroups(event.Properties.Path)).then(
50
49
  (pathWithCapturingGroups) => ({
@@ -53,7 +52,7 @@ class CloudFormationLambdaProxy<Context, AuthorizerContext extends APIGatewayAut
53
52
  weight: this.computeWeight(pathWithCapturingGroups),
54
53
  handler: this.pathParameterCapture(new RegExp(pathWithCapturingGroups), handler, config.context),
55
54
  authorizer: event.Properties?.Auth?.Authorizer === 'NONE' ? NOOP_AUTHORIZER : undefined,
56
- } satisfies Route<Context, AuthorizerContext, Event, HandlerResponse>),
55
+ } satisfies Route<Context, Event, HandlerResponse>),
57
56
  ),
58
57
  config.prepare,
59
58
  config,
@@ -63,7 +62,7 @@ class CloudFormationLambdaProxy<Context, AuthorizerContext extends APIGatewayAut
63
62
  this.pathParameterResolver = payloadVersion.resolver;
64
63
  }
65
64
 
66
- protected afterStart = (name: string, cfg: DevServerConfig, routes: Route<Context, AuthorizerContext, Event, HandlerResponse>[]) =>
65
+ protected afterStart = (name: string, cfg: DevServerConfig, routes: Route<Context, Event, HandlerResponse>[]) =>
67
66
  newLambdaHttpProxy(
68
67
  `${name}:apigw`,
69
68
  {
@@ -80,7 +79,7 @@ class CloudFormationLambdaProxy<Context, AuthorizerContext extends APIGatewayAut
80
79
  private segments = (path: string) => path.split('/').length;
81
80
  private variables = (path: string) => path.split('(?<').length;
82
81
 
83
- logHandler(handler: Route<Context, AuthorizerContext, Event, HandlerResponse>): string {
82
+ logHandler(handler: Route<Context, Event, HandlerResponse>): string {
84
83
  return `detected handler for ${handler.method} on ${handler.path} with weight ${handler.weight}`;
85
84
  }
86
85
 
@@ -123,9 +122,9 @@ class CloudFormationLambdaProxy<Context, AuthorizerContext extends APIGatewayAut
123
122
  }
124
123
  }
125
124
 
126
- type CloudFormationLambdaProxyConfig<Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event, HandlerResponse> = {
127
- authorizer?: (config: DevServerConfig) => Authorizer<AuthorizerContext> | undefined,
128
- extraRoutes: Route<Context, AuthorizerContext, Event, HandlerResponse>[],
125
+ type CloudFormationLambdaProxyConfig<Context, Event, HandlerResponse> = {
126
+ authorizer?: (config: DevServerConfig) => Authorizer | undefined,
127
+ extraRoutes: Route<Context, Event, HandlerResponse>[],
129
128
  prepare?: (config: DevServerConfig) => Promise<void>,
130
129
  context?: () => Context,
131
130
  } & CloudFormationSetupConfig;
@@ -32,7 +32,7 @@ export abstract class CloudFormationSetup<P, H, R, F> implements Startable<F> {
32
32
 
33
33
  private resolvedHandlers = async (): Promise<R[]> => {
34
34
  const template = this.template(this.name);
35
- this.LOGGER.info('parsing %s', template);
35
+ this.LOGGER.debug('parsing %s', template);
36
36
  const definition = this.parseApiEvents(template);
37
37
  const functions = this.handlers(this.name);
38
38
  const routes = Object.values(definition)
@@ -53,7 +53,7 @@ export abstract class CloudFormationSetup<P, H, R, F> implements Startable<F> {
53
53
  this.handlerResolver(event, handler) :
54
54
  Promise.reject(new Error(`function ${event.Handler} defined in ${resolve(template)} not found in ${resolve(functions)}`)))
55
55
  .then((handler) => {
56
- this.LOGGER.info(this.logHandler(handler));
56
+ this.LOGGER.debug(this.logHandler(handler));
57
57
  return handler;
58
58
  }),
59
59
  ),
package/src/container.ts CHANGED
@@ -68,7 +68,7 @@ class Container implements Lifecycle<string> {
68
68
  }
69
69
 
70
70
  start = async (config: DevServerConfig) =>
71
- Promise.resolve(this.LOGGER.info('start'))
71
+ Promise.resolve(this.LOGGER.debug('start'))
72
72
  .then(() => this.container
73
73
  .withNetwork(config.network)
74
74
  .withNetworkAliases(this.networkAlias)
package/src/deferred.ts CHANGED
@@ -20,7 +20,7 @@ class Lazy<I> implements Lifecycle<I> {
20
20
  async start(config: DevServerConfig) {
21
21
  const local = this.configurable(config);
22
22
  this.started = local;
23
- this.LOGGER.info('DISCOVERY:%s', local.name)
23
+ this.LOGGER.debug('DISCOVERY:%s', local.name)
24
24
  return local.start(config);
25
25
  }
26
26
 
@@ -52,9 +52,9 @@ class Promised<I> implements Lifecycle<I> {
52
52
  configurable(config)
53
53
  .catch((e) => e?.cleanup?.() ?? Promise.reject(e))
54
54
  .then((service) => initialized = service)
55
- .tap((service) => this.LOGGER.info('DISCOVERY:%s', service.name))
55
+ .tap((service) => this.LOGGER.debug('DISCOVERY:%s', service.name))
56
56
  .then((service) => service.start(config))
57
57
 
58
- this.stop = async () => (initialized ?? { stop: async () => this.LOGGER.info('not started') }).stop()
58
+ this.stop = async () => (initialized ?? { stop: async () => this.LOGGER.warn('not started') }).stop()
59
59
  }
60
60
  }
package/src/dynamodb.ts CHANGED
@@ -37,7 +37,7 @@ class DynamoDbTableCreator implements Lifecycle<string> {
37
37
  AttributeName: attributeName,
38
38
  }
39
39
  }))
40
- .tap((out) => this.LOGGER.info('set ttl attribute %s? %s', attributeName, out.$metadata.httpStatusCode === 200))
40
+ .tap((out) => this.LOGGER.debug('set ttl attribute %s? %s', attributeName, out.$metadata.httpStatusCode === 200))
41
41
  .then(() => undefined)
42
42
 
43
43
  stop = () => Promise.resolve()
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { DevServer } from './dev-server'
2
2
  export { newHttpServer as httpServer, HttpSettings } from './http-server'
3
- export { newLambdaHttpProxy as lambdaHttpProxy } from './lambda-http-proxy'
4
- export { v1 as v1LambdaProxyPayload, v2 as v2LambdaProxyPayload } from './mappers'
3
+ export { newLambdaHttpProxy as lambdaHttpProxy, Route } from './lambda-http-proxy'
4
+ export { v1 as v1LambdaProxyPayload, v2 as v2LambdaProxyPayload, LambdaPayloadVersion } from './mappers'
5
5
  export { newLambdaProxyFromCloudFormationTemplate as cloudFormationLambdaProxy } from './cloudformation-lambda-http-proxy'
6
6
  export { newDynamoDbTableFromCloudFormationTemplate as cloudFormationDynamoDbTable } from './cloudformation-dynamodb-table'
7
7
  export { newSnsHttpProxy as snsHttpProxy } from './sns-http-proxy'
@@ -52,7 +52,7 @@ class InternalQueue implements Lifecycle<string> {
52
52
  private async createQueue(sqs: Sqs, name: string) {
53
53
  return this.creator(sqs)(name) //
54
54
  .then((queue) => {
55
- this.LOGGER.info('created: %s', queue.url);
55
+ this.LOGGER.debug('created: %s', queue.url);
56
56
  return queue;
57
57
  });
58
58
  }
@@ -78,11 +78,11 @@ class InternalQueue implements Lifecycle<string> {
78
78
  consumer.on('processing_error', (err) => {
79
79
  this.LOGGER.error(err, 'failed to process message');
80
80
  });
81
- this.LOGGER.info('consumer for %s initialized', name);
81
+ this.LOGGER.debug('consumer for %s initialized', name);
82
82
  return consumer;
83
83
  })
84
84
  .then(async (consumer) => consumer.start())
85
- .then(() => this.LOGGER.info('started'))
85
+ .then(() => this.LOGGER.debug('started'))
86
86
  .then(() => this)
87
87
 
88
88
  stop = async () => this.consumer !== undefined ? stopConsumer(this.visibility, this.consumer) : this.LOGGER.warn('no consumer')
@@ -7,17 +7,17 @@ import { Lifecycle, Service, Callback } from "./services";
7
7
  import { APIGatewayAuthorizerResult } from "aws-lambda";
8
8
 
9
9
  const UNAUTHORIZED = new Error('UNAUTHORIZED');
10
- export const newLambdaHttpProxy = <Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event, HandlerResponse>(
10
+ export const newLambdaHttpProxy = <Context, Event, HandlerResponse>(
11
11
  name: string,
12
12
  config: {
13
13
  settings: HttpSettings,
14
- routes: Route<Context, AuthorizerContext, Event, HandlerResponse>[],
15
- mapper: LambdaMapperFactory<AuthorizerContext, Event, HandlerResponse>,
16
- authorizer?: Authorizer<AuthorizerContext>
14
+ routes: Route<Context, Event, HandlerResponse>[],
15
+ mapper: LambdaMapperFactory<Event, HandlerResponse>,
16
+ authorizer?: Authorizer
17
17
  context?: () => Context
18
18
  },
19
19
  callback?: Callback<string>,
20
- ) => new Service(new LambdaHttpProxy<Context, AuthorizerContext, Event, HandlerResponse>(
20
+ ) => new Service(new LambdaHttpProxy<Context, Event, HandlerResponse>(
21
21
  name,
22
22
  config.settings,
23
23
  config.routes,
@@ -26,21 +26,21 @@ export const newLambdaHttpProxy = <Context, AuthorizerContext extends APIGateway
26
26
  config.context,
27
27
  ), callback)
28
28
 
29
- class LambdaHttpProxy<Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event, HandlerResponse> implements Lifecycle<string> {
29
+ class LambdaHttpProxy<Context, Event, HandlerResponse> implements Lifecycle<string> {
30
30
  private LOGGER: Logger
31
31
  private readonly server: HttpServer
32
32
 
33
33
  constructor(
34
34
  readonly name: string,
35
35
  settings: HttpSettings,
36
- private readonly routes: Route<Context, AuthorizerContext, Event, HandlerResponse>[],
37
- private readonly mapper: LambdaMapperFactory<AuthorizerContext, Event, HandlerResponse>,
38
- private readonly defaultAuthorizer: Authorizer<AuthorizerContext>,
36
+ private readonly routes: Route<Context, Event, HandlerResponse>[],
37
+ private readonly mapper: LambdaMapperFactory<Event, HandlerResponse>,
38
+ private readonly defaultAuthorizer: Authorizer,
39
39
  private readonly context: () => Context = () => undefined,
40
40
  ) {
41
41
  this.server = new HttpServer(name, settings, this.resolveRoute)
42
42
  this.LOGGER = LoggerFactory.create(`HTTP->LAMBDA[${this.name}]`);
43
- this.LOGGER.info('registered %i routes', routes.length)
43
+ this.LOGGER.debug('registered %i routes', routes.length)
44
44
  }
45
45
 
46
46
  start = () => this.server.start()
@@ -48,7 +48,7 @@ class LambdaHttpProxy<Context, AuthorizerContext extends APIGatewayAuthorizerRes
48
48
  stop = () => this.server.stop()
49
49
 
50
50
  private handler = (
51
- authorizer: Authorizer<AuthorizerContext>,
51
+ authorizer: Authorizer,
52
52
  lambdaHandler: (event: Event, context: Context) => Promise<HandlerResponse>
53
53
  ) =>
54
54
  (request: IncomingMessage, body: string, response: ServerResponse) =>
@@ -57,7 +57,7 @@ class LambdaHttpProxy<Context, AuthorizerContext extends APIGatewayAuthorizerRes
57
57
  authorizer(mapper.authorization())
58
58
  .then(async (context) =>
59
59
  context?.policyDocument?.Statement?.find((s) => s.Effect === 'Deny') === undefined
60
- ? { ...context, lambda: context?.context }
60
+ ? context
61
61
  : Promise.reject(UNAUTHORIZED),
62
62
  )
63
63
  .then((context) =>
@@ -106,12 +106,12 @@ export abstract class Response {
106
106
  body: () => string | Buffer | undefined
107
107
  }
108
108
 
109
- export type Route<Context, AuthorizerContext extends APIGatewayAuthorizerResult, Event, HandlerResponse> = {
109
+ export type Route<Context, Event, HandlerResponse> = {
110
110
  method: RegExp;
111
111
  path: RegExp;
112
112
  weight: number;
113
- authorizer?: Authorizer<AuthorizerContext>;
113
+ authorizer?: Authorizer;
114
114
  handler: (event: Event, context: Context) => Promise<HandlerResponse>;
115
115
  };
116
116
 
117
- export type Authorizer<Context extends APIGatewayAuthorizerResult> = (authorization: string) => Promise<Context | undefined>;
117
+ export type Authorizer = (authorization: string) => Promise<APIGatewayAuthorizerResult | undefined>;
package/src/mappers.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Message } from "@aws-sdk/client-sqs";
2
- import { APIGatewayEventRequestContextV2WithAuthorizer, APIGatewayProxyEvent, APIGatewayProxyEventHeaders, APIGatewayProxyEventPathParameters, APIGatewayProxyEventQueryStringParameters, APIGatewayProxyEventV2, APIGatewayProxyEventV2WithRequestContext, APIGatewayProxyResult, APIGatewayProxyStructuredResultV2, SQSRecord } from "aws-lambda";
2
+ import { APIGatewayAuthorizerResult, APIGatewayEventRequestContextV2WithAuthorizer, APIGatewayProxyEvent, APIGatewayProxyEventHeaders, APIGatewayProxyEventPathParameters, APIGatewayProxyEventQueryStringParameters, APIGatewayProxyEventV2, APIGatewayProxyEventV2WithRequestContext, APIGatewayProxyResult, APIGatewayProxyStructuredResultV2, SQSRecord } from "aws-lambda";
3
3
  import { IncomingMessage } from "http";
4
4
  import { URL } from "url";
5
5
  import { Response } from "./lambda-http-proxy";
@@ -25,12 +25,12 @@ export const mapToLambdaSqsRecord = (message: Message): SQSRecord => {
25
25
  };
26
26
  }
27
27
 
28
- const payloadV1JwtAuthorizerLambdaMapper = <AuthorizerContext>(): LambdaMapperFactory<AuthorizerContext, APIGatewayProxyEvent, APIGatewayProxyResult> => ({
29
- newInstance: (request, body) => Promise.resolve(new DefaultLambdaMapper<AuthorizerContext>(request, body))
28
+ const payloadV1JwtAuthorizerLambdaMapper = (): LambdaMapperFactory<APIGatewayProxyEvent, APIGatewayProxyResult> => ({
29
+ newInstance: (request, body) => Promise.resolve(new DefaultLambdaMapper(request, body))
30
30
  })
31
31
 
32
- const payloadV2LambdaAuthorizerLambdaMapper = <AuthorizerContext>(): LambdaMapperFactory<AuthorizerContext, APIGatewayEventRequestContextV2WithGenericAuthorizer<AuthorizerContext>, APIGatewayProxyStructuredResultV2> => ({
33
- newInstance: (request, body) => Promise.resolve(new DefaultLambdaMapper<AuthorizerContext>(request, body))
32
+ const payloadV2LambdaAuthorizerLambdaMapper = (): LambdaMapperFactory<APIGatewayEventRequestContextV2WithGenericAuthorizer, APIGatewayProxyStructuredResultV2> => ({
33
+ newInstance: (request, body) => Promise.resolve(new DefaultLambdaMapper(request, body))
34
34
  })
35
35
 
36
36
  const payloadV1PathParameterResolver: PathParameterResolver<APIGatewayProxyEvent> = {
@@ -43,22 +43,22 @@ const payloadV2PathParameterResolver: PathParameterResolver<APIGatewayProxyEvent
43
43
  store: (event: APIGatewayProxyEventV2, params: APIGatewayProxyEventPathParameters) => event.pathParameters = params
44
44
  }
45
45
 
46
- export type LambdaPayloadVersion<AuthorizerContext, Event, HandlerResponse> = {
47
- mapper: LambdaMapperFactory<AuthorizerContext, Event, HandlerResponse>,
46
+ export type LambdaPayloadVersion<Event, HandlerResponse> = {
47
+ mapper: LambdaMapperFactory<Event, HandlerResponse>,
48
48
  resolver: PathParameterResolver<Event>,
49
49
  }
50
50
 
51
- export const v1 = <AuthorizerContext>(): LambdaPayloadVersion<AuthorizerContext, APIGatewayProxyEvent, APIGatewayProxyResult> => ({
52
- mapper: payloadV1JwtAuthorizerLambdaMapper<AuthorizerContext>(),
51
+ export const v1 = (): LambdaPayloadVersion<APIGatewayProxyEvent, APIGatewayProxyResult> => ({
52
+ mapper: payloadV1JwtAuthorizerLambdaMapper(),
53
53
  resolver: payloadV1PathParameterResolver,
54
54
  })
55
55
 
56
- export const v2 = <AuthorizerContext>(): LambdaPayloadVersion<AuthorizerContext, APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2> => ({
57
- mapper: payloadV2LambdaAuthorizerLambdaMapper<AuthorizerContext>(),
56
+ export const v2 = (): LambdaPayloadVersion<APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2> => ({
57
+ mapper: payloadV2LambdaAuthorizerLambdaMapper(),
58
58
  resolver: payloadV2PathParameterResolver,
59
59
  })
60
60
 
61
- class DefaultLambdaMapper<AuthorizerContext> implements LambdaMapper<AuthorizerContext, APIGatewayProxyEvent & APIGatewayEventRequestContextV2WithGenericAuthorizer<AuthorizerContext>, APIGatewayProxyResult & APIGatewayProxyStructuredResultV2> {
61
+ class DefaultLambdaMapper implements LambdaMapper<APIGatewayProxyEvent & APIGatewayEventRequestContextV2WithGenericAuthorizer, APIGatewayProxyResult & APIGatewayProxyStructuredResultV2> {
62
62
  private readonly url: URL
63
63
  private readonly authorizationHeaderValue: string
64
64
  private readonly time: number
@@ -120,7 +120,7 @@ class DefaultLambdaMapper<AuthorizerContext> implements LambdaMapper<AuthorizerC
120
120
  return [];
121
121
  };
122
122
 
123
- event = (context: { [name: string]: any; } & AuthorizerContext): APIGatewayProxyEvent & APIGatewayEventRequestContextV2WithGenericAuthorizer<AuthorizerContext> => ({
123
+ event = (authorizerResult: APIGatewayAuthorizerResult): APIGatewayProxyEvent & APIGatewayEventRequestContextV2WithGenericAuthorizer => ({
124
124
  version: '2.0',
125
125
  rawPath: this.url.pathname,
126
126
  rawQueryString: this.url.search,
@@ -152,7 +152,11 @@ class DefaultLambdaMapper<AuthorizerContext> implements LambdaMapper<AuthorizerC
152
152
  timeEpoch: this.time,
153
153
  accountId: '',
154
154
  apiId: '',
155
- authorizer: context,
155
+ authorizer: {
156
+ ...authorizerResult,
157
+ ...authorizerResult?.context,
158
+ lambda: authorizerResult?.context,
159
+ },
156
160
  httpMethod: '',
157
161
  identity: {
158
162
  accessKey: '',
@@ -189,14 +193,14 @@ class DefaultLambdaMapper<AuthorizerContext> implements LambdaMapper<AuthorizerC
189
193
 
190
194
  authorization = () => this.authorizationHeaderValue
191
195
  }
192
- interface LambdaMapper<AuthorizerContext, Event, HandlerResponse> {
193
- event(context: { [name: string]: any; } & AuthorizerContext): Event
196
+ interface LambdaMapper<Event, HandlerResponse> {
197
+ event(context: APIGatewayAuthorizerResult): Event
194
198
  authorization(): string
195
199
  toResponse: (response: HandlerResponse) => Response
196
200
  }
197
201
 
198
- export interface LambdaMapperFactory<AuthorizerContext, Event, LambdaResponse> {
199
- newInstance(request: IncomingMessage, body: string): Promise<LambdaMapper<AuthorizerContext, Event, LambdaResponse>>;
202
+ export interface LambdaMapperFactory<Event, LambdaResponse> {
203
+ newInstance(request: IncomingMessage, body: string): Promise<LambdaMapper<Event, LambdaResponse>>;
200
204
  }
201
205
 
202
206
  class StringResponse extends Response {
@@ -229,7 +233,7 @@ class Base64EncodedResponse extends Response {
229
233
  }
230
234
  }
231
235
 
232
- type APIGatewayEventRequestContextV2WithGenericAuthorizer<AuthorizerContext> = APIGatewayProxyEventV2WithRequestContext<APIGatewayEventRequestContextV2WithAuthorizer<AuthorizerContext>>;
236
+ type APIGatewayEventRequestContextV2WithGenericAuthorizer = APIGatewayProxyEventV2WithRequestContext<APIGatewayEventRequestContextV2WithAuthorizer<APIGatewayAuthorizerResult>>;
233
237
 
234
238
  export type PathParameterResolver<Event> = {
235
239
  locate: (event: Event) => string
@@ -13,7 +13,7 @@ class PreTrafficHooks implements Lifecycle<void> {
13
13
  private readonly hooks: () => Promise<void>[]
14
14
  ) {
15
15
  this.LOGGER = LoggerFactory.create(`PRETRAFFIC[${name}]`);
16
- this.LOGGER.info('%i hooks registered', hooks.length);
16
+ this.LOGGER.debug('%i hooks registered', hooks.length);
17
17
  }
18
18
 
19
19
  start = async () => Promise
@@ -12,7 +12,7 @@ class ScheduledTasks implements Lifecycle<void> {
12
12
 
13
13
  constructor(readonly name: string, private readonly schedules: Rate[]) {
14
14
  this.LOGGER = LoggerFactory.create(`SCHEDULER[${name}]`)
15
- this.LOGGER.info('registered %i scheduled tasks', schedules.length);
15
+ this.LOGGER.debug('registered %i scheduled tasks', schedules.length);
16
16
  }
17
17
 
18
18
  intervals: NodeJS.Timeout[] = [];
package/src/services.ts CHANGED
@@ -34,11 +34,11 @@ export class Service<I> implements Lifecycle<I> {
34
34
  )
35
35
  .then((started) => this
36
36
  .callbackOrDefault(started)
37
- .then(() => this.LOGGER.info('started'))
37
+ .then(() => this.LOGGER.debug('started'))
38
38
  .then(() => started)
39
39
  )
40
40
  this.doStop = () => stop()
41
- .then(() => this.LOGGER.info('stopped'))
41
+ .then(() => this.LOGGER.debug('stopped'))
42
42
  this.stop = () => this.doStop();
43
43
  }
44
44
 
@@ -40,7 +40,7 @@ export class SnsHttpProxy implements Lifecycle<string> {
40
40
  this.handler(this.method, this.subject)
41
41
  )
42
42
  this.LOGGER = LoggerFactory.create(`HTTP->SNS[${name}]`)
43
- this.LOGGER.info(
43
+ this.LOGGER.debug(
44
44
  'forwarding %s %s events to %s',
45
45
  subject ? `events with ${subject} subject` : 'all',
46
46
  method,