@creator.co/wapi 1.2.1-beta6 → 1.2.3
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/.eslintrc.cjs +29 -22
- package/.github/workflows/npmpublish.yml +11 -19
- package/.github/workflows/prs.yml +13 -0
- package/index.ts +12 -10
- package/jest.config.ts +39 -0
- package/package.json +15 -4
- package/src/API/Request.ts +136 -44
- package/src/API/Response.ts +256 -46
- package/src/API/Utils.ts +60 -7
- package/src/BaseEvent/EventProcessor.ts +93 -28
- package/src/BaseEvent/Process.ts +69 -13
- package/src/BaseEvent/Transaction.ts +29 -50
- package/src/Config/Configuration.ts +119 -19
- package/src/Config/EnvironmentVar.ts +100 -21
- package/src/Crypto/Crypto.ts +78 -19
- package/src/Crypto/JWT.ts +53 -13
- package/src/Globals.ts +159 -27
- package/src/Logger/Logger.ts +204 -65
- package/src/Mailer/Mailer.ts +114 -31
- package/src/Publisher/Publisher.ts +57 -16
- package/src/Server/RouteResolver.ts +141 -0
- package/src/Server/Router.ts +84 -12
- package/src/Server/lib/ContainerServer.ts +53 -6
- package/src/Server/lib/Server.ts +82 -54
- package/src/Server/lib/container/GenericHandler.ts +15 -18
- package/src/Server/lib/container/GenericHandlerEvent.ts +78 -50
- package/src/Server/lib/container/HealthHandler.ts +2 -2
- package/src/Server/lib/container/Proxy.ts +114 -45
- package/src/Server/lib/container/Utils.ts +18 -27
- package/src/Validation/Validator.ts +23 -7
- package/tests/API/Request.test.ts +259 -0
- package/tests/API/Response.test.ts +367 -0
- package/tests/API/Utils.test.ts +157 -0
- package/tests/BaseEvent/EventProcessor.test.ts +262 -0
- package/tests/BaseEvent/Process.test.ts +49 -0
- package/tests/BaseEvent/Transaction.test.ts +222 -0
- package/tests/Config/Config.test.ts +193 -0
- package/tests/Config/EnvironmentVar.test.ts +214 -0
- package/tests/Crypto/Crypto.test.ts +88 -0
- package/tests/Crypto/JWT.test.ts +92 -0
- package/tests/Logger/Logger.test.ts +96 -0
- package/tests/Mailer/Mailer.test.ts +59 -0
- package/tests/Publisher/Publisher.test.ts +60 -0
- package/tests/Server/RouteResolver.test.ts +103 -0
- package/tests/Server/Router.test.ts +38 -0
- package/tests/Server/lib/ContainerServer.test.ts +327 -0
- package/tests/Server/lib/Server.test.ts +12 -0
- package/tests/Server/lib/container/GenericHandler.test.ts +131 -0
- package/tests/Server/lib/container/GenericHandlerEvent.test.ts +102 -0
- package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
- package/tests/Server/lib/container/Proxy.test.ts +265 -0
- package/tests/Server/lib/container/Utils.test.ts +47 -0
- package/tests/Test.utils.ts +95 -0
- package/tests/Validation/Validator.test.ts +76 -0
- package/tests/main.test.ts +15 -0
- package/tsconfig.json +1 -0
- package/dist/index.d.ts +0 -11
- package/dist/index.js +0 -24
- package/dist/index.js.map +0 -1
- package/dist/package.json +0 -53
- package/dist/src/API/Request.d.ts +0 -21
- package/dist/src/API/Request.js +0 -86
- package/dist/src/API/Request.js.map +0 -1
- package/dist/src/API/Response.d.ts +0 -39
- package/dist/src/API/Response.js +0 -232
- package/dist/src/API/Response.js.map +0 -1
- package/dist/src/API/Utils.d.ts +0 -8
- package/dist/src/API/Utils.js +0 -49
- package/dist/src/API/Utils.js.map +0 -1
- package/dist/src/BaseEvent/EventProcessor.d.ts +0 -13
- package/dist/src/BaseEvent/EventProcessor.js +0 -151
- package/dist/src/BaseEvent/EventProcessor.js.map +0 -1
- package/dist/src/BaseEvent/Process.d.ts +0 -12
- package/dist/src/BaseEvent/Process.js +0 -114
- package/dist/src/BaseEvent/Process.js.map +0 -1
- package/dist/src/BaseEvent/Transaction.d.ts +0 -29
- package/dist/src/BaseEvent/Transaction.js +0 -248
- package/dist/src/BaseEvent/Transaction.js.map +0 -1
- package/dist/src/Config/Configuration.d.ts +0 -34
- package/dist/src/Config/Configuration.js +0 -93
- package/dist/src/Config/Configuration.js.map +0 -1
- package/dist/src/Config/EnvironmentVar.d.ts +0 -17
- package/dist/src/Config/EnvironmentVar.js +0 -152
- package/dist/src/Config/EnvironmentVar.js.map +0 -1
- package/dist/src/Crypto/Crypto.d.ts +0 -8
- package/dist/src/Crypto/Crypto.js +0 -84
- package/dist/src/Crypto/Crypto.js.map +0 -1
- package/dist/src/Crypto/JWT.d.ts +0 -16
- package/dist/src/Crypto/JWT.js +0 -49
- package/dist/src/Crypto/JWT.js.map +0 -1
- package/dist/src/Globals.d.ts +0 -21
- package/dist/src/Globals.js +0 -35
- package/dist/src/Globals.js.map +0 -1
- package/dist/src/Logger/Logger.d.ts +0 -34
- package/dist/src/Logger/Logger.js +0 -345
- package/dist/src/Logger/Logger.js.map +0 -1
- package/dist/src/Mailer/Mailer.d.ts +0 -12
- package/dist/src/Mailer/Mailer.js +0 -234
- package/dist/src/Mailer/Mailer.js.map +0 -1
- package/dist/src/Publisher/Publisher.d.ts +0 -10
- package/dist/src/Publisher/Publisher.js +0 -109
- package/dist/src/Publisher/Publisher.js.map +0 -1
- package/dist/src/Server/Router.d.ts +0 -27
- package/dist/src/Server/Router.js +0 -22
- package/dist/src/Server/Router.js.map +0 -1
- package/dist/src/Server/lib/ContainerServer.d.ts +0 -11
- package/dist/src/Server/lib/ContainerServer.js +0 -103
- package/dist/src/Server/lib/ContainerServer.js.map +0 -1
- package/dist/src/Server/lib/Server.d.ts +0 -9
- package/dist/src/Server/lib/Server.js +0 -141
- package/dist/src/Server/lib/Server.js.map +0 -1
- package/dist/src/Server/lib/container/GenericHandler.d.ts +0 -4
- package/dist/src/Server/lib/container/GenericHandler.js +0 -136
- package/dist/src/Server/lib/container/GenericHandler.js.map +0 -1
- package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +0 -14
- package/dist/src/Server/lib/container/GenericHandlerEvent.js +0 -164
- package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +0 -1
- package/dist/src/Server/lib/container/HealthHandler.d.ts +0 -3
- package/dist/src/Server/lib/container/HealthHandler.js +0 -44
- package/dist/src/Server/lib/container/HealthHandler.js.map +0 -1
- package/dist/src/Server/lib/container/Proxy.d.ts +0 -15
- package/dist/src/Server/lib/container/Proxy.js +0 -157
- package/dist/src/Server/lib/container/Proxy.js.map +0 -1
- package/dist/src/Server/lib/container/Utils.d.ts +0 -6
- package/dist/src/Server/lib/container/Utils.js +0 -109
- package/dist/src/Server/lib/container/Utils.js.map +0 -1
- package/dist/src/Validation/Validator.d.ts +0 -5
- package/dist/src/Validation/Validator.js +0 -31
- package/dist/src/Validation/Validator.js.map +0 -1
|
@@ -1,34 +1,94 @@
|
|
|
1
|
-
import type { Context, SQSBatchResponse, SQSEvent } from
|
|
1
|
+
import type { Context, SQSBatchResponse, SQSEvent } from 'aws-lambda'
|
|
2
2
|
|
|
3
|
-
import Transaction, { TransactionConfig } from
|
|
4
|
-
import Response, { ResponseErrorType } from
|
|
5
|
-
import Globals from
|
|
3
|
+
import Transaction, { TransactionConfig } from './Transaction'
|
|
4
|
+
import Response, { ResponseErrorType } from '../API/Response'
|
|
5
|
+
import Globals from '../Globals'
|
|
6
6
|
|
|
7
7
|
// Handler
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
/**
|
|
9
|
+
* ${1:Description placeholder}
|
|
10
|
+
*
|
|
11
|
+
* @export
|
|
12
|
+
* @typedef {EventProcessorExecution}
|
|
13
|
+
* @template ResponseInnerType
|
|
14
|
+
*/
|
|
15
|
+
export type EventProcessorExecution<ResponseInnerType> = (
|
|
16
|
+
transaction: Transaction<null, ResponseInnerType | ResponseErrorType, SQSBatchResponse>,
|
|
17
|
+
recordContent: string | object
|
|
18
|
+
) => Promise<Response<ResponseInnerType | ResponseErrorType> | SQSBatchResponse>
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
/**
|
|
21
|
+
* ${1:Description placeholder}
|
|
22
|
+
*
|
|
23
|
+
* @export
|
|
24
|
+
* @class EventProcessor
|
|
25
|
+
* @typedef {EventProcessor}
|
|
26
|
+
* @template ResponseInnerType
|
|
27
|
+
*/
|
|
28
|
+
export default class EventProcessor<ResponseInnerType> {
|
|
29
|
+
/**
|
|
30
|
+
* ${1:Description placeholder}
|
|
31
|
+
*
|
|
32
|
+
* @private
|
|
33
|
+
* @readonly
|
|
34
|
+
* @type {boolean}
|
|
35
|
+
*/
|
|
14
36
|
private readonly _allowFailure: boolean
|
|
37
|
+
/**
|
|
38
|
+
* ${1:Description placeholder}
|
|
39
|
+
*
|
|
40
|
+
* @private
|
|
41
|
+
* @readonly
|
|
42
|
+
* @type {TransactionConfig}
|
|
43
|
+
*/
|
|
15
44
|
private readonly _apiConfig: TransactionConfig
|
|
45
|
+
/**
|
|
46
|
+
* ${1:Description placeholder}
|
|
47
|
+
*
|
|
48
|
+
* @private
|
|
49
|
+
* @readonly
|
|
50
|
+
* @type {Context}
|
|
51
|
+
*/
|
|
16
52
|
private readonly _context: Context
|
|
53
|
+
/**
|
|
54
|
+
* ${1:Description placeholder}
|
|
55
|
+
*
|
|
56
|
+
* @private
|
|
57
|
+
* @readonly
|
|
58
|
+
* @type {SQSEvent}
|
|
59
|
+
*/
|
|
17
60
|
private readonly _event: SQSEvent
|
|
61
|
+
/**
|
|
62
|
+
* Creates an instance of EventProcessor.
|
|
63
|
+
*
|
|
64
|
+
* @constructor
|
|
65
|
+
* @param {SQSEvent} event
|
|
66
|
+
* @param {Context} context
|
|
67
|
+
* @param {?TransactionConfig} [config]
|
|
68
|
+
* @param {?boolean} [allowFailure]
|
|
69
|
+
*/
|
|
18
70
|
constructor(
|
|
19
71
|
event: SQSEvent,
|
|
20
72
|
context: Context,
|
|
21
|
-
config
|
|
22
|
-
allowFailure?: boolean
|
|
73
|
+
config?: TransactionConfig,
|
|
74
|
+
allowFailure?: boolean
|
|
23
75
|
) {
|
|
24
76
|
this._event = event
|
|
25
77
|
this._context = context
|
|
26
|
-
this._apiConfig = config
|
|
78
|
+
this._apiConfig = config || {}
|
|
27
79
|
this._allowFailure = allowFailure
|
|
28
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* ${1:Description placeholder}
|
|
83
|
+
*
|
|
84
|
+
* @async
|
|
85
|
+
* @param {EventProcessorExecution<ResponseInnerType>} execution
|
|
86
|
+
* @param {?boolean} [doNotDecodeMessage]
|
|
87
|
+
* @returns {(Promise<Response<ResponseErrorType> | null | SQSBatchResponse>)}
|
|
88
|
+
*/
|
|
29
89
|
async processEvent(
|
|
30
|
-
execution: EventProcessorExecution
|
|
31
|
-
doNotDecodeMessage?: boolean
|
|
90
|
+
execution: EventProcessorExecution<ResponseInnerType>,
|
|
91
|
+
doNotDecodeMessage?: boolean
|
|
32
92
|
): Promise<Response<ResponseErrorType> | null | SQSBatchResponse> {
|
|
33
93
|
const resp = await this._processRawEvent(execution, !!doNotDecodeMessage)
|
|
34
94
|
if (
|
|
@@ -37,13 +97,21 @@ export default class EventProcessor {
|
|
|
37
97
|
resp instanceof Response &&
|
|
38
98
|
!(resp.getCode() >= 200 && resp.getCode() < 300)
|
|
39
99
|
)
|
|
40
|
-
throw new Error(JSON.stringify(resp.getBody()))
|
|
100
|
+
throw new Error(JSON.stringify(resp.getBody() || {}))
|
|
41
101
|
else if (resp) return resp
|
|
42
102
|
return null
|
|
43
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* ${1:Description placeholder}
|
|
106
|
+
*
|
|
107
|
+
* @async
|
|
108
|
+
* @param {EventProcessorExecution<ResponseInnerType>} execution
|
|
109
|
+
* @param {boolean} doNotDecodeMessage
|
|
110
|
+
* @returns {(Promise<Response<ResponseErrorType> | null | SQSBatchResponse>)}
|
|
111
|
+
*/
|
|
44
112
|
async _processRawEvent(
|
|
45
|
-
execution: EventProcessorExecution
|
|
46
|
-
doNotDecodeMessage: boolean
|
|
113
|
+
execution: EventProcessorExecution<ResponseInnerType>,
|
|
114
|
+
doNotDecodeMessage: boolean
|
|
47
115
|
): Promise<Response<ResponseErrorType> | null | SQSBatchResponse> {
|
|
48
116
|
if (this._event.Records && this._event.Records.length > 0) {
|
|
49
117
|
//safe check for empty events?
|
|
@@ -54,14 +122,11 @@ export default class EventProcessor {
|
|
|
54
122
|
{
|
|
55
123
|
...this._apiConfig,
|
|
56
124
|
syncReturn: true,
|
|
57
|
-
}
|
|
58
|
-
).execute(async
|
|
125
|
+
}
|
|
126
|
+
).execute(async transaction => {
|
|
59
127
|
//Map records with decoded message when required
|
|
60
|
-
const decodedRecords: string[] | object[] = this._event.Records.map(
|
|
61
|
-
(eventRecord)
|
|
62
|
-
doNotDecodeMessage
|
|
63
|
-
? eventRecord.body
|
|
64
|
-
: JSON.parse(eventRecord.body),
|
|
128
|
+
const decodedRecords: string[] | object[] = this._event.Records.map(eventRecord =>
|
|
129
|
+
doNotDecodeMessage ? eventRecord.body : JSON.parse(eventRecord.body)
|
|
65
130
|
)
|
|
66
131
|
|
|
67
132
|
//for each available event
|
|
@@ -73,8 +138,8 @@ export default class EventProcessor {
|
|
|
73
138
|
const resp = await execution(transaction, eventRecord)
|
|
74
139
|
//check for failure
|
|
75
140
|
if (
|
|
76
|
-
resp
|
|
77
|
-
!(resp
|
|
141
|
+
!resp ||
|
|
142
|
+
(resp instanceof Response && !(resp?.getCode() >= 200 && resp?.getCode() < 300))
|
|
78
143
|
) {
|
|
79
144
|
//response with failures or fail hard at first
|
|
80
145
|
if (this._allowFailure) failureIDs.push(message.messageId)
|
|
@@ -84,14 +149,14 @@ export default class EventProcessor {
|
|
|
84
149
|
//not errored and loop ended - succeeded (might have failures)
|
|
85
150
|
if (this._allowFailure)
|
|
86
151
|
return {
|
|
87
|
-
batchItemFailures: failureIDs.map(
|
|
152
|
+
batchItemFailures: failureIDs.map(id => ({ itemIdentifier: id })),
|
|
88
153
|
}
|
|
89
154
|
return Response.SuccessResponse(null)
|
|
90
155
|
})
|
|
91
156
|
} else
|
|
92
157
|
return Response.BadRequestResponse(
|
|
93
158
|
Globals.ErrorResponseNoRecords,
|
|
94
|
-
Globals.ErrorCode_NoRecords
|
|
159
|
+
Globals.ErrorCode_NoRecords
|
|
95
160
|
) //no event to be processed?
|
|
96
161
|
}
|
|
97
162
|
}
|
package/src/BaseEvent/Process.ts
CHANGED
|
@@ -1,35 +1,93 @@
|
|
|
1
|
-
import { TransactionConfig } from
|
|
2
|
-
import Logger from
|
|
3
|
-
import Publisher from
|
|
1
|
+
import { TransactionConfig } from './Transaction'
|
|
2
|
+
import Logger from '../Logger/Logger'
|
|
3
|
+
import Publisher from '../Publisher/Publisher'
|
|
4
4
|
|
|
5
5
|
// Config
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
/**
|
|
7
|
+
* ${1:Description placeholder}
|
|
8
|
+
*
|
|
9
|
+
* @export
|
|
10
|
+
* @typedef {ProcessConfig}
|
|
11
|
+
*/
|
|
12
|
+
export type ProcessConfig = Omit<TransactionConfig, 'throwOnErrors' | 'syncReturn'>
|
|
10
13
|
|
|
14
|
+
/**
|
|
15
|
+
* ${1:Description placeholder}
|
|
16
|
+
*
|
|
17
|
+
* @export
|
|
18
|
+
* @class Process
|
|
19
|
+
* @typedef {Process}
|
|
20
|
+
*/
|
|
11
21
|
export default class Process {
|
|
22
|
+
/**
|
|
23
|
+
* ${1:Description placeholder}
|
|
24
|
+
*
|
|
25
|
+
* @private
|
|
26
|
+
* @type {number}
|
|
27
|
+
*/
|
|
12
28
|
private _interval: number
|
|
13
29
|
//
|
|
30
|
+
/**
|
|
31
|
+
* ${1:Description placeholder}
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
* @readonly
|
|
35
|
+
* @type {Logger}
|
|
36
|
+
*/
|
|
14
37
|
public readonly logger: Logger
|
|
38
|
+
/**
|
|
39
|
+
* ${1:Description placeholder}
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
* @readonly
|
|
43
|
+
* @type {Publisher}
|
|
44
|
+
*/
|
|
15
45
|
public readonly publisher: Publisher
|
|
46
|
+
/**
|
|
47
|
+
* ${1:Description placeholder}
|
|
48
|
+
*
|
|
49
|
+
* @public
|
|
50
|
+
* @type {NodeJS.Timeout}
|
|
51
|
+
*/
|
|
52
|
+
public interval: NodeJS.Timeout
|
|
53
|
+
/**
|
|
54
|
+
* Creates an instance of Process.
|
|
55
|
+
*
|
|
56
|
+
* @constructor
|
|
57
|
+
* @param {ProcessConfig} config
|
|
58
|
+
* @param {number} interval
|
|
59
|
+
*/
|
|
16
60
|
constructor(config: ProcessConfig, interval: number) {
|
|
17
61
|
this._interval = interval
|
|
18
|
-
this.logger = new Logger(config.logger,
|
|
62
|
+
this.logger = new Logger(config.logger, 'long-running-process')
|
|
19
63
|
this.publisher = new Publisher(config.publisher)
|
|
20
64
|
}
|
|
21
65
|
|
|
22
66
|
//Main interface
|
|
67
|
+
/**
|
|
68
|
+
* ${1:Description placeholder}
|
|
69
|
+
*
|
|
70
|
+
* @async
|
|
71
|
+
* @param {*} executionFunc
|
|
72
|
+
* @returns {*}
|
|
73
|
+
*/
|
|
23
74
|
async execute(executionFunc) {
|
|
24
|
-
this.logger.debug(
|
|
75
|
+
this.logger.debug('Starting main process code')
|
|
25
76
|
//Connect DB
|
|
26
77
|
// if (this.db) await this.db.connect();
|
|
27
78
|
//Program loop
|
|
28
|
-
setInterval(async () => {
|
|
79
|
+
this.interval = setInterval(async () => {
|
|
29
80
|
await this._execute(executionFunc)
|
|
30
81
|
}, this._interval)
|
|
31
82
|
}
|
|
32
83
|
//Executions
|
|
84
|
+
/**
|
|
85
|
+
* ${1:Description placeholder}
|
|
86
|
+
*
|
|
87
|
+
* @async
|
|
88
|
+
* @param {*} executionFunc
|
|
89
|
+
* @returns {unknown}
|
|
90
|
+
*/
|
|
33
91
|
async _execute(executionFunc) {
|
|
34
92
|
let executionFailed = true //failled til we say no!
|
|
35
93
|
//safe execution handler
|
|
@@ -44,9 +102,7 @@ export default class Process {
|
|
|
44
102
|
executionFailed = false
|
|
45
103
|
} catch (e) {
|
|
46
104
|
/*EXECUTION FAIL*/
|
|
47
|
-
this.logger.error(
|
|
48
|
-
"Exception when executing main process code. Rolling back DB!",
|
|
49
|
-
)
|
|
105
|
+
this.logger.error('Exception when executing main process code. Rolling back DB!')
|
|
50
106
|
this.logger.exception(e)
|
|
51
107
|
//Rollback DB
|
|
52
108
|
// if (this.db) await this.db.rollback();
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
import type { APIGatewayEvent, Context, SQSEvent } from
|
|
1
|
+
import type { APIGatewayEvent, Context, SQSEvent } from 'aws-lambda'
|
|
2
2
|
|
|
3
|
-
import Request from
|
|
4
|
-
import Response, { ResponseErrorType } from
|
|
5
|
-
import Globals from
|
|
6
|
-
import Logger, { LoggerConfig } from
|
|
7
|
-
import Publisher, { PublisherConfig } from
|
|
3
|
+
import Request from '../API/Request'
|
|
4
|
+
import Response, { ResponseErrorType } from '../API/Response'
|
|
5
|
+
import Globals from '../Globals'
|
|
6
|
+
import Logger, { LoggerConfig } from '../Logger/Logger'
|
|
7
|
+
import Publisher, { PublisherConfig } from '../Publisher/Publisher'
|
|
8
8
|
|
|
9
9
|
// Request
|
|
10
|
-
export type TransactionExecution<
|
|
11
|
-
TransactionType
|
|
12
|
-
|
|
13
|
-
MiscRespType = null,
|
|
14
|
-
> = (
|
|
15
|
-
transaction: TransactionType,
|
|
16
|
-
) => Promise<
|
|
17
|
-
Response<ResponseInnerType> | Response<ResponseErrorType> | MiscRespType
|
|
18
|
-
>
|
|
10
|
+
export type TransactionExecution<TransactionType, ResponseInnerType, MiscRespType = null> = (
|
|
11
|
+
transaction: TransactionType
|
|
12
|
+
) => Promise<Response<ResponseInnerType> | Response<ResponseErrorType> | MiscRespType>
|
|
19
13
|
// Config
|
|
20
14
|
export type TransactionConfig = {
|
|
21
15
|
throwOnErrors?: boolean
|
|
@@ -32,10 +26,7 @@ export default class Transaction<
|
|
|
32
26
|
> {
|
|
33
27
|
private event: any
|
|
34
28
|
private context: Context
|
|
35
|
-
private response:
|
|
36
|
-
| Response<ResponseInnerType | ResponseErrorType>
|
|
37
|
-
| MiscRespType
|
|
38
|
-
| null
|
|
29
|
+
private response: Response<ResponseInnerType | ResponseErrorType> | MiscRespType | null
|
|
39
30
|
private syncReturn: boolean
|
|
40
31
|
private retrowErrors: boolean
|
|
41
32
|
//
|
|
@@ -44,16 +35,12 @@ export default class Transaction<
|
|
|
44
35
|
public readonly publisher: Publisher
|
|
45
36
|
public responseProxy: (response: Response<ResponseInnerType>) => Promise<void>
|
|
46
37
|
//
|
|
47
|
-
constructor(
|
|
48
|
-
event: APIGatewayEvent | SQSEvent,
|
|
49
|
-
context: Context,
|
|
50
|
-
config?: TransactionConfig,
|
|
51
|
-
) {
|
|
38
|
+
constructor(event: APIGatewayEvent | SQSEvent, context: Context, config?: TransactionConfig) {
|
|
52
39
|
const transactionId = context.awsRequestId
|
|
53
40
|
? context.awsRequestId
|
|
54
41
|
: (<APIGatewayEvent>event).requestContext
|
|
55
42
|
? (<APIGatewayEvent>event).requestContext.requestId
|
|
56
|
-
:
|
|
43
|
+
: 'unknown'
|
|
57
44
|
// transaction ctx
|
|
58
45
|
this.event = event
|
|
59
46
|
this.context = context
|
|
@@ -75,7 +62,7 @@ export default class Transaction<
|
|
|
75
62
|
Transaction<InputType, ResponseInnerType, MiscRespType>,
|
|
76
63
|
ResponseInnerType,
|
|
77
64
|
MiscRespType
|
|
78
|
-
|
|
65
|
+
>
|
|
79
66
|
): Promise<Response<ResponseInnerType | ResponseErrorType> | MiscRespType> {
|
|
80
67
|
await this.executeLoggerFlush(async () => {
|
|
81
68
|
await this.executeDBTransactions(async () => {
|
|
@@ -93,46 +80,42 @@ export default class Transaction<
|
|
|
93
80
|
Transaction<InputType, ResponseInnerType, MiscRespType>,
|
|
94
81
|
ResponseInnerType,
|
|
95
82
|
MiscRespType
|
|
96
|
-
|
|
83
|
+
>
|
|
97
84
|
): Promise<boolean> {
|
|
98
85
|
let executionFailed = true //failed til we say no!
|
|
99
86
|
//safe execution handler
|
|
100
87
|
try {
|
|
101
88
|
//Execute
|
|
102
|
-
this.logger.debug(
|
|
89
|
+
this.logger.debug('Starting main request code')
|
|
103
90
|
this.response = await executionFunc(this)
|
|
104
91
|
//Answer client
|
|
105
92
|
if (this.response && this.response instanceof Response) {
|
|
106
93
|
await this.response.build(this.context, this, this.syncReturn)
|
|
107
|
-
executionFailed = !!(
|
|
108
|
-
this.response.getBody() && this.response.getBody()["rollback"]
|
|
109
|
-
)
|
|
94
|
+
executionFailed = !!(this.response.getBody() && this.response.getBody()['rollback'])
|
|
110
95
|
} else if (this.syncReturn && this.response) {
|
|
111
|
-
this.logger.log(
|
|
96
|
+
this.logger.log('Sync return with different response object')
|
|
112
97
|
this.logger.debug(this.response)
|
|
113
98
|
executionFailed = false
|
|
114
99
|
} else {
|
|
115
100
|
this.response = this.getErrorResponse(
|
|
116
101
|
Globals.ErrorResponseInvalidServerResponse,
|
|
117
|
-
Globals.ErrorCode_APIError
|
|
102
|
+
Globals.ErrorCode_APIError
|
|
118
103
|
)
|
|
119
104
|
await this.response.build(this.context, this, this.syncReturn)
|
|
120
|
-
this.logger.error(
|
|
105
|
+
this.logger.error('Invalid response object from main request code.')
|
|
121
106
|
}
|
|
122
107
|
} catch (e) {
|
|
123
108
|
/*EXECUTION FAIL*/
|
|
124
|
-
this.logger.error(
|
|
109
|
+
this.logger.error('Exception when executing main request code.')
|
|
125
110
|
this.logger.exception(e)
|
|
126
111
|
//retrow?
|
|
127
112
|
if (this.retrowErrors) throw e
|
|
128
113
|
//envelope exception?
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
await this.response.build(this.context, this, this.syncReturn)
|
|
135
|
-
}
|
|
114
|
+
this.response = this.getErrorResponse(
|
|
115
|
+
Globals.ErrorResponseUnhandledError,
|
|
116
|
+
Globals.ErrorCode_APIError
|
|
117
|
+
)
|
|
118
|
+
await this.response.build(this.context, this, this.syncReturn)
|
|
136
119
|
}
|
|
137
120
|
return executionFailed
|
|
138
121
|
}
|
|
@@ -155,7 +138,7 @@ export default class Transaction<
|
|
|
155
138
|
// //Cleanup DB after execution
|
|
156
139
|
// if (this.db) await this.db.cleanup();
|
|
157
140
|
} catch (e) {
|
|
158
|
-
this.logger.error(
|
|
141
|
+
this.logger.error('Exception when executing DB transactions.')
|
|
159
142
|
this.logger.log(e.stack)
|
|
160
143
|
//retrow?
|
|
161
144
|
if (this.retrowErrors) throw e
|
|
@@ -164,21 +147,17 @@ export default class Transaction<
|
|
|
164
147
|
private async executeLoggerFlush(safeExecution) {
|
|
165
148
|
try {
|
|
166
149
|
await safeExecution()
|
|
167
|
-
await this.logger.flushLogs()
|
|
168
150
|
} catch (e) {
|
|
169
|
-
this.logger.error(
|
|
151
|
+
this.logger.error('Exception when flushing logs.')
|
|
170
152
|
this.logger.exception(e)
|
|
171
153
|
//retrow?
|
|
172
154
|
if (this.retrowErrors) throw e
|
|
173
155
|
} finally {
|
|
174
|
-
this.logger.debug(
|
|
156
|
+
this.logger.debug('Transaction ended')
|
|
175
157
|
}
|
|
176
158
|
}
|
|
177
159
|
/* Response support */
|
|
178
|
-
private getErrorResponse(
|
|
179
|
-
error: string,
|
|
180
|
-
code: string,
|
|
181
|
-
): Response<ResponseErrorType> {
|
|
160
|
+
private getErrorResponse(error: string, code: string): Response<ResponseErrorType> {
|
|
182
161
|
return Response.BadRequestResponseWithRollback(error, code)
|
|
183
162
|
}
|
|
184
163
|
}
|
|
@@ -1,11 +1,23 @@
|
|
|
1
|
-
import * as MemCache from
|
|
2
|
-
import * as DurationParser from
|
|
1
|
+
import * as MemCache from 'node-cache'
|
|
2
|
+
import * as DurationParser from 'parse-duration'
|
|
3
3
|
|
|
4
|
-
import EnvironmentVar, { EnvironmentType } from
|
|
4
|
+
import EnvironmentVar, { EnvironmentType } from './EnvironmentVar'
|
|
5
5
|
|
|
6
6
|
// Hold cached values at nodeVM level
|
|
7
|
-
|
|
7
|
+
// eslint-disable-next-line no-var
|
|
8
|
+
/**
|
|
9
|
+
* ${1:Description placeholder}
|
|
10
|
+
*
|
|
11
|
+
* @type {*}
|
|
12
|
+
*/
|
|
13
|
+
let cacheStore = new MemCache()
|
|
8
14
|
|
|
15
|
+
/**
|
|
16
|
+
* ${1:Description placeholder}
|
|
17
|
+
*
|
|
18
|
+
* @export
|
|
19
|
+
* @typedef {ConfigurationSchema}
|
|
20
|
+
*/
|
|
9
21
|
export type ConfigurationSchema = {
|
|
10
22
|
[name: string]: {
|
|
11
23
|
isLocal?: boolean
|
|
@@ -16,6 +28,12 @@ export type ConfigurationSchema = {
|
|
|
16
28
|
}
|
|
17
29
|
|
|
18
30
|
// runtime type infer to ConfigurationSchema keys, which type is remote
|
|
31
|
+
/**
|
|
32
|
+
* ${1:Description placeholder}
|
|
33
|
+
*
|
|
34
|
+
* @typedef {ExtractRemote}
|
|
35
|
+
* @template Type
|
|
36
|
+
*/
|
|
19
37
|
type ExtractRemote<Type> = {
|
|
20
38
|
[Property in keyof Type]-?: Type[Property] extends {
|
|
21
39
|
isRemote: true
|
|
@@ -24,6 +42,12 @@ type ExtractRemote<Type> = {
|
|
|
24
42
|
: null
|
|
25
43
|
}
|
|
26
44
|
// runtime type infer to ConfigurationSchema keys, which type is local
|
|
45
|
+
/**
|
|
46
|
+
* ${1:Description placeholder}
|
|
47
|
+
*
|
|
48
|
+
* @typedef {ExtractLocal}
|
|
49
|
+
* @template Type
|
|
50
|
+
*/
|
|
27
51
|
type ExtractLocal<Type> = {
|
|
28
52
|
[Property in keyof Type]-?: Type[Property] extends {
|
|
29
53
|
isLocal: true
|
|
@@ -33,25 +57,75 @@ type ExtractLocal<Type> = {
|
|
|
33
57
|
}
|
|
34
58
|
|
|
35
59
|
// Helpers to filter null keys
|
|
60
|
+
/**
|
|
61
|
+
* ${1:Description placeholder}
|
|
62
|
+
*
|
|
63
|
+
* @typedef {OmitKeysByValueType}
|
|
64
|
+
* @template T
|
|
65
|
+
* @template U
|
|
66
|
+
*/
|
|
36
67
|
type OmitKeysByValueType<T, U> = {
|
|
37
68
|
[P in keyof T]: T[P] extends U ? never : P
|
|
38
69
|
}[keyof T]
|
|
39
70
|
|
|
40
|
-
|
|
41
|
-
|
|
71
|
+
/**
|
|
72
|
+
* ${1:Description placeholder}
|
|
73
|
+
*
|
|
74
|
+
* @typedef {OmitByValueType}
|
|
75
|
+
* @template T
|
|
76
|
+
* @template V
|
|
77
|
+
*/
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, prettier/prettier
|
|
79
|
+
type OmitByValueType<T, V> = T extends infer _
|
|
42
80
|
? {
|
|
43
81
|
[key in OmitKeysByValueType<T, V>]: T[key]
|
|
44
82
|
}
|
|
45
83
|
: never
|
|
46
84
|
|
|
85
|
+
/**
|
|
86
|
+
* ${1:Description placeholder}
|
|
87
|
+
*
|
|
88
|
+
* @export
|
|
89
|
+
* @class Configuration
|
|
90
|
+
* @typedef {Configuration}
|
|
91
|
+
* @template {ConfigurationSchema} T
|
|
92
|
+
*/
|
|
47
93
|
export default class Configuration<T extends ConfigurationSchema> {
|
|
94
|
+
/**
|
|
95
|
+
* ${1:Description placeholder}
|
|
96
|
+
*
|
|
97
|
+
* @private
|
|
98
|
+
* @readonly
|
|
99
|
+
* @type {T}
|
|
100
|
+
*/
|
|
48
101
|
private readonly schema: T
|
|
102
|
+
/**
|
|
103
|
+
* ${1:Description placeholder}
|
|
104
|
+
*
|
|
105
|
+
* @private
|
|
106
|
+
* @readonly
|
|
107
|
+
* @type {string}
|
|
108
|
+
*/
|
|
49
109
|
private readonly remotePrefix: string
|
|
110
|
+
/**
|
|
111
|
+
* Creates an instance of Configuration.
|
|
112
|
+
*
|
|
113
|
+
* @constructor
|
|
114
|
+
* @param {T} schema
|
|
115
|
+
* @param {string} remotePrefix
|
|
116
|
+
*/
|
|
50
117
|
constructor(schema: T, remotePrefix: string) {
|
|
51
118
|
this.schema = schema
|
|
52
119
|
this.remotePrefix = remotePrefix
|
|
53
120
|
}
|
|
54
121
|
|
|
122
|
+
/**
|
|
123
|
+
* ${1:Description placeholder}
|
|
124
|
+
*
|
|
125
|
+
* @public
|
|
126
|
+
* @param {keyof OmitByValueType<ExtractLocal<T>, null>} propName
|
|
127
|
+
* @returns {*}
|
|
128
|
+
*/
|
|
55
129
|
public get(propName: keyof OmitByValueType<ExtractLocal<T>, null>): any {
|
|
56
130
|
const propString = propName as string
|
|
57
131
|
const propSchema = this.schema[propString]
|
|
@@ -61,15 +135,21 @@ export default class Configuration<T extends ConfigurationSchema> {
|
|
|
61
135
|
new EnvironmentVar<string>(
|
|
62
136
|
propString,
|
|
63
137
|
EnvironmentType.Local,
|
|
64
|
-
propSchema.required,
|
|
65
|
-
this.remotePrefix
|
|
138
|
+
!propSchema.required,
|
|
139
|
+
this.remotePrefix
|
|
66
140
|
).syncResolve()
|
|
67
141
|
this.cacheValue(propString, v, propSchema.cachingPolicy)
|
|
68
142
|
return v
|
|
69
143
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
144
|
+
/**
|
|
145
|
+
* ${1:Description placeholder}
|
|
146
|
+
*
|
|
147
|
+
* @public
|
|
148
|
+
* @async
|
|
149
|
+
* @param {keyof OmitByValueType<ExtractRemote<T>, null>} propName
|
|
150
|
+
* @returns {Promise<any>}
|
|
151
|
+
*/
|
|
152
|
+
public async asyncGet(propName: keyof OmitByValueType<ExtractRemote<T>, null>): Promise<any> {
|
|
73
153
|
const propString = propName as string
|
|
74
154
|
const propSchema = this.schema[propString]
|
|
75
155
|
let v = this.getCachedValue(propString)
|
|
@@ -78,21 +158,41 @@ export default class Configuration<T extends ConfigurationSchema> {
|
|
|
78
158
|
(await new EnvironmentVar<string>(
|
|
79
159
|
propString,
|
|
80
160
|
EnvironmentType.PlainRemote,
|
|
81
|
-
propSchema.required,
|
|
82
|
-
this.remotePrefix
|
|
161
|
+
!propSchema.required,
|
|
162
|
+
this.remotePrefix
|
|
83
163
|
).resolve())
|
|
84
164
|
this.cacheValue(propString, v, propSchema.cachingPolicy)
|
|
85
165
|
return v
|
|
86
166
|
}
|
|
87
167
|
// caching layer
|
|
168
|
+
/**
|
|
169
|
+
* ${1:Description placeholder}
|
|
170
|
+
*
|
|
171
|
+
* @private
|
|
172
|
+
* @param {string} valueKey
|
|
173
|
+
* @returns {*}
|
|
174
|
+
*/
|
|
88
175
|
private getCachedValue(valueKey: string): any {
|
|
89
176
|
return cacheStore.get(valueKey)
|
|
90
177
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
178
|
+
/**
|
|
179
|
+
* ${1:Description placeholder}
|
|
180
|
+
*
|
|
181
|
+
* @private
|
|
182
|
+
* @param {string} valueKey
|
|
183
|
+
* @param {*} value
|
|
184
|
+
* @param {string} [policy="1d"]
|
|
185
|
+
*/
|
|
186
|
+
private cacheValue(valueKey: string, value: any, policy: string = '1d'): void {
|
|
187
|
+
cacheStore.set(valueKey, value, DurationParser(policy, 's'))
|
|
188
|
+
}
|
|
189
|
+
// unit-test support
|
|
190
|
+
/**
|
|
191
|
+
* ${1:Description placeholder}
|
|
192
|
+
*
|
|
193
|
+
* @private
|
|
194
|
+
*/
|
|
195
|
+
private resetCache() {
|
|
196
|
+
cacheStore = new MemCache()
|
|
97
197
|
}
|
|
98
198
|
}
|