@@ -9,11 +9,12 @@ import {
99 BaseResourceModel ,
1010 BaseResourceHandlerRequest ,
1111 Callable ,
12+ CfnResponse ,
1213 Credentials ,
1314 HandlerErrorCode ,
1415 OperationStatus ,
1516 Optional ,
16- Response ,
17+ RequestContext ,
1718} from './interface' ;
1819import { ProviderLogHandler } from './log-delivery' ;
1920import { MetricsPublisherProxy } from './metrics' ;
@@ -37,31 +38,36 @@ class HandlerEvents extends Map<Action, string | symbol> {};
3738/**
3839 * Decorates a method to ensure that the JSON input and output are serialized properly.
3940 *
40- * @returns {PropertyDescriptor }
41+ * @returns {MethodDecorator }
4142 */
42- function ensureSerialize ( target : any , propertyKey : string , descriptor : PropertyDescriptor ) : PropertyDescriptor {
43-
44- // Save a reference to the original method this way we keep the values currently in the
45- // descriptor and don't overwrite what another decorator might have done to the descriptor.
46- if ( descriptor === undefined ) {
47- descriptor = Object . getOwnPropertyDescriptor ( target , propertyKey ) ;
48- }
49- const originalMethod = descriptor . value ;
50- // Wrapping the original method with new signature.
51- descriptor . value = async function ( event : Object | Map < string , any > , context : any ) : Promise < any > {
52- let mappedEvent : Map < string , any > ;
53- if ( event instanceof Map ) {
54- mappedEvent = new Map < string , any > ( event ) ;
55- } else {
56- mappedEvent = new Map < string , any > ( Object . entries ( event ) ) ;
43+ function ensureSerialize ( toResponse : boolean = false ) : MethodDecorator {
44+ return function ( target : any , propertyKey : string , descriptor : PropertyDescriptor ) : PropertyDescriptor {
45+ type Resource = typeof target ;
46+ // Save a reference to the original method this way we keep the values currently in the
47+ // descriptor and don't overwrite what another decorator might have done to the descriptor.
48+ if ( descriptor === undefined ) {
49+ descriptor = Object . getOwnPropertyDescriptor ( target , propertyKey ) ;
50+ }
51+ const originalMethod = descriptor . value ;
52+ // Wrapping the original method with new signature.
53+ descriptor . value = async function ( event : Object | Map < string , any > , context : any ) : Promise < ProgressEvent | CfnResponse < Resource > > {
54+ let mappedEvent : Map < string , any > ;
55+ if ( event instanceof Map ) {
56+ mappedEvent = new Map < string , any > ( event ) ;
57+ } else {
58+ mappedEvent = new Map < string , any > ( Object . entries ( event ) ) ;
59+ }
60+ const progress : ProgressEvent = await originalMethod . apply ( this , [ mappedEvent , context ] ) ;
61+ if ( toResponse ) {
62+ // Use the raw event data as a last-ditch attempt to call back if the
63+ // request is invalid.
64+ const serialized = progress . serialize ( true , mappedEvent . get ( 'bearerToken' ) ) ;
65+ return serialized . toObject ( ) as CfnResponse < Resource > ;
66+ }
67+ return progress ;
5768 }
58- const progress = await originalMethod . apply ( this , [ mappedEvent , context ] ) ;
59- // Use the raw event data as a last-ditch attempt to call back if the
60- // request is invalid.
61- const serialized = progress . serialize ( true , mappedEvent . get ( 'bearerToken' ) ) ;
62- return serialized . toObject ( ) ;
69+ return descriptor ;
6370 }
64- return descriptor ;
6571}
6672
6773/**
@@ -112,16 +118,16 @@ export abstract class BaseResource<T extends BaseResourceModel = BaseResourceMod
112118 if ( handlerResponse . status !== OperationStatus . InProgress ) {
113119 return false ;
114120 }
115- // Modify requestContext dict in-place, so that invoke count is bumped on local
116- // reinvoke too
117- const reinvokeContext = handlerRequest . requestContext ;
121+ // Modify requestContext in-place, so that invoke count is bumped on local
122+ // reinvoke too.
123+ const reinvokeContext : RequestContext < Map < string , any > > = handlerRequest . requestContext ;
118124 reinvokeContext . invocation = ( reinvokeContext . invocation || 0 ) + 1 ;
119125 const callbackDelaySeconds = handlerResponse . callbackDelaySeconds ;
120126 const remainingMs = context . getRemainingTimeInMillis ( ) ;
121127
122128 // When a handler requests a sub-minute callback delay, and if the lambda
123129 // invocation has enough runtime (with 20% buffer), we can re-run the handler
124- // locally otherwise we re-invoke through CloudWatchEvents
130+ // locally otherwise we re-invoke through CloudWatchEvents.
125131 const neededMsRemaining = callbackDelaySeconds * 1200 + INVOCATION_TIMEOUT_MS ;
126132 if ( callbackDelaySeconds < 60 && remainingMs > neededMsRemaining ) {
127133 const delay = async ( ms : number ) => {
@@ -196,15 +202,15 @@ export abstract class BaseResource<T extends BaseResourceModel = BaseResourceMod
196202 throw new InternalFailure ( `${ err } (${ err . name } )` ) ;
197203 }
198204
199- return [ session , request , action , event . callbackContext || new Map ( ) ] ;
205+ return [ session , request , action , event . callbackContext || new Map < string , any > ( ) ] ;
200206 }
201207
202208 // @ts -ignore
203209 public async testEntrypoint (
204210 eventData : Object | Map < string , any > , context : any
205- ) : Promise < Response < BaseResource > > ;
211+ ) : Promise < ProgressEvent > ;
206212 @boundMethod
207- @ensureSerialize
213+ @ensureSerialize ( )
208214 public async testEntrypoint (
209215 eventData : Map < string , any > , context : any
210216 ) : Promise < ProgressEvent > {
@@ -217,10 +223,11 @@ export abstract class BaseResource<T extends BaseResourceModel = BaseResourceMod
217223 if ( err instanceof BaseHandlerException ) {
218224 LOGGER . error ( 'Handler error' )
219225 progress = err . toProgressEvent ( ) ;
226+ } else {
227+ LOGGER . error ( 'Exception caught' ) ;
228+ msg = err . message || msg ;
229+ progress = ProgressEvent . failed ( HandlerErrorCode . InternalFailure , msg ) ;
220230 }
221- LOGGER . error ( 'Exception caught' ) ;
222- msg = err . message || msg ;
223- progress = ProgressEvent . failed ( HandlerErrorCode . InternalFailure , msg ) ;
224231 }
225232 return Promise . resolve ( progress ) ;
226233 }
@@ -253,7 +260,7 @@ export abstract class BaseResource<T extends BaseResourceModel = BaseResourceMod
253260 throw new Error ( 'No platform credentials' ) ;
254261 }
255262 action = event . action ;
256- callbackContext = event . requestContext . callbackContext || { } as Map < string , any > ;
263+ callbackContext = event . requestContext ? .callbackContext || new Map < string , any > ( ) ;
257264 } catch ( err ) {
258265 LOGGER . error ( 'Invalid request' ) ;
259266 throw new InvalidRequest ( `${ err } (${ err . name } )` ) ;
@@ -286,9 +293,9 @@ export abstract class BaseResource<T extends BaseResourceModel = BaseResourceMod
286293 // @ts -ignore
287294 public async entrypoint (
288295 eventData : Object | Map < string , any > , context : LambdaContext
289- ) : Promise < Response < BaseResource > > ;
296+ ) : Promise < CfnResponse < BaseResource > > ;
290297 @boundMethod
291- @ensureSerialize
298+ @ensureSerialize ( true )
292299 public async entrypoint (
293300 eventData : Map < string , any > , context : LambdaContext
294301 ) : Promise < ProgressEvent > {
@@ -357,6 +364,9 @@ export abstract class BaseResource<T extends BaseResourceModel = BaseResourceMod
357364 }
358365 if ( progress . callbackContext ) {
359366 const callback = progress . callbackContext ;
367+ if ( ! event . requestContext ) {
368+ event . requestContext = { } as RequestContext < Map < string , any > > ;
369+ }
360370 event . requestContext . callbackContext = callback ;
361371 }
362372 if ( MUTATING_ACTIONS . includes ( event . action ) ) {
0 commit comments