@creator.co/wapi 1.2.1-beta6 → 1.2.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.
- package/.github/workflows/npmpublish.yml +11 -19
- package/.github/workflows/prs.yml +13 -0
- package/jest.config.ts +39 -0
- package/package.json +15 -4
- package/src/API/Request.ts +120 -10
- package/src/API/Response.ts +236 -8
- package/src/API/Utils.ts +56 -1
- package/src/BaseEvent/EventProcessor.ts +84 -11
- package/src/BaseEvent/Process.ts +62 -1
- package/src/BaseEvent/Transaction.ts +5 -8
- package/src/Config/Configuration.ts +111 -5
- package/src/Config/EnvironmentVar.ts +90 -1
- package/src/Crypto/Crypto.ts +77 -18
- package/src/Crypto/JWT.ts +49 -3
- package/src/Globals.ts +141 -3
- package/src/Logger/Logger.ts +173 -19
- package/src/Mailer/Mailer.ts +95 -0
- package/src/Publisher/Publisher.ts +50 -4
- package/src/Server/RouteResolver.ts +142 -0
- package/src/Server/Router.ts +77 -0
- package/src/Server/lib/ContainerServer.ts +48 -1
- package/src/Server/lib/Server.ts +78 -38
- package/src/Server/lib/container/GenericHandler.ts +7 -5
- package/src/Server/lib/container/GenericHandlerEvent.ts +59 -17
- package/src/Server/lib/container/HealthHandler.ts +1 -1
- package/src/Server/lib/container/Proxy.ts +92 -11
- package/src/Server/lib/container/Utils.ts +16 -25
- package/src/Validation/Validator.ts +18 -2
- package/tests/API/Request.test.ts +263 -0
- package/tests/API/Response.test.ts +372 -0
- package/tests/API/Utils.test.ts +157 -0
- package/tests/BaseEvent/EventProcessor.test.ts +278 -0
- package/tests/BaseEvent/Process.test.ts +49 -0
- package/tests/BaseEvent/Transaction.test.ts +231 -0
- package/tests/Config/Config.test.ts +193 -0
- package/tests/Config/EnvironmentVar.test.ts +223 -0
- package/tests/Crypto/Crypto.test.ts +90 -0
- package/tests/Crypto/JWT.test.ts +92 -0
- package/tests/Logger/Logger.test.ts +108 -0
- package/tests/Mailer/Mailer.test.ts +67 -0
- package/tests/Publisher/Publisher.test.ts +60 -0
- package/tests/Server/RouteResolver.test.ts +106 -0
- package/tests/Server/Router.test.ts +38 -0
- package/tests/Server/lib/ContainerServer.test.ts +329 -0
- package/tests/Server/lib/Server.test.ts +12 -0
- package/tests/Server/lib/container/GenericHandler.test.ts +141 -0
- package/tests/Server/lib/container/GenericHandlerEvent.test.ts +103 -0
- package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
- package/tests/Server/lib/container/Proxy.test.ts +278 -0
- package/tests/Server/lib/container/Utils.test.ts +48 -0
- package/tests/Test.utils.ts +95 -0
- package/tests/Validation/Validator.test.ts +88 -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
package/src/API/Utils.ts
CHANGED
|
@@ -1,14 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ${1:Description placeholder}
|
|
3
|
+
*
|
|
4
|
+
* @export
|
|
5
|
+
* @class Utils
|
|
6
|
+
* @typedef {Utils}
|
|
7
|
+
*/
|
|
1
8
|
export default class Utils {
|
|
9
|
+
/**
|
|
10
|
+
* ${1:Description placeholder}
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
* @static
|
|
14
|
+
* @returns {boolean}
|
|
15
|
+
*/
|
|
2
16
|
public static isHybridlessContainer(): boolean {
|
|
3
|
-
return
|
|
17
|
+
return process.env.HYBRIDLESS_RUNTIME == "true"
|
|
4
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* ${1:Description placeholder}
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
* @static
|
|
24
|
+
* @param {string} string
|
|
25
|
+
* @returns {boolean}
|
|
26
|
+
*/
|
|
5
27
|
public static isValidString(string: string): boolean {
|
|
6
28
|
return string?.length > 0 && !Array.isArray(string)
|
|
7
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* ${1:Description placeholder}
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
* @static
|
|
35
|
+
* @param {string} string
|
|
36
|
+
* @returns {(number | null)}
|
|
37
|
+
*/
|
|
8
38
|
public static parseIntNullIfNaN(string: string): number | null {
|
|
9
39
|
const n = parseInt(string)
|
|
10
40
|
return isNaN(n) ? null : n
|
|
11
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* ${1:Description placeholder}
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
* @static
|
|
47
|
+
* @param {string} string
|
|
48
|
+
* @returns {(any | null)}
|
|
49
|
+
*/
|
|
12
50
|
public static parseObjectNullIfEmpty(string: string): any | null {
|
|
13
51
|
let o = null
|
|
14
52
|
try {
|
|
@@ -19,6 +57,14 @@ export default class Utils {
|
|
|
19
57
|
}
|
|
20
58
|
return o
|
|
21
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* ${1:Description placeholder}
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
* @static
|
|
65
|
+
* @param {string} number
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
22
68
|
public static isValidNumber(number: string): boolean {
|
|
23
69
|
let validNumb = NaN
|
|
24
70
|
try {
|
|
@@ -28,6 +74,15 @@ export default class Utils {
|
|
|
28
74
|
}
|
|
29
75
|
return !isNaN(validNumb) && !Array.isArray(number)
|
|
30
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* ${1:Description placeholder}
|
|
79
|
+
*
|
|
80
|
+
* @public
|
|
81
|
+
* @static
|
|
82
|
+
* @param {*} obj
|
|
83
|
+
* @param {string} key
|
|
84
|
+
* @returns {(any | null)}
|
|
85
|
+
*/
|
|
31
86
|
public static caseInsensitiveObjectForKey(obj: any, key: string): any | null {
|
|
32
87
|
if (!obj) return null
|
|
33
88
|
const insensitiveKey = Object.keys(obj).find(
|
|
@@ -5,29 +5,93 @@ import Response, { ResponseErrorType } from "../API/Response"
|
|
|
5
5
|
import Globals from "../Globals"
|
|
6
6
|
|
|
7
7
|
// Handler
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* ${1:Description placeholder}
|
|
10
|
+
*
|
|
11
|
+
* @export
|
|
12
|
+
* @typedef {EventProcessorExecution}
|
|
13
|
+
* @template ResponseInnerType
|
|
14
|
+
*/
|
|
15
|
+
export type EventProcessorExecution<ResponseInnerType> = (
|
|
16
|
+
transaction: Transaction<
|
|
17
|
+
null,
|
|
18
|
+
ResponseInnerType | ResponseErrorType,
|
|
19
|
+
SQSBatchResponse
|
|
20
|
+
>,
|
|
10
21
|
recordContent: string | object,
|
|
11
|
-
) => Promise<Response | SQSBatchResponse>
|
|
22
|
+
) => Promise<Response<ResponseInnerType | ResponseErrorType> | SQSBatchResponse>
|
|
12
23
|
|
|
13
|
-
|
|
24
|
+
/**
|
|
25
|
+
* ${1:Description placeholder}
|
|
26
|
+
*
|
|
27
|
+
* @export
|
|
28
|
+
* @class EventProcessor
|
|
29
|
+
* @typedef {EventProcessor}
|
|
30
|
+
* @template ResponseInnerType
|
|
31
|
+
*/
|
|
32
|
+
export default class EventProcessor<ResponseInnerType> {
|
|
33
|
+
/**
|
|
34
|
+
* ${1:Description placeholder}
|
|
35
|
+
*
|
|
36
|
+
* @private
|
|
37
|
+
* @readonly
|
|
38
|
+
* @type {boolean}
|
|
39
|
+
*/
|
|
14
40
|
private readonly _allowFailure: boolean
|
|
41
|
+
/**
|
|
42
|
+
* ${1:Description placeholder}
|
|
43
|
+
*
|
|
44
|
+
* @private
|
|
45
|
+
* @readonly
|
|
46
|
+
* @type {TransactionConfig}
|
|
47
|
+
*/
|
|
15
48
|
private readonly _apiConfig: TransactionConfig
|
|
49
|
+
/**
|
|
50
|
+
* ${1:Description placeholder}
|
|
51
|
+
*
|
|
52
|
+
* @private
|
|
53
|
+
* @readonly
|
|
54
|
+
* @type {Context}
|
|
55
|
+
*/
|
|
16
56
|
private readonly _context: Context
|
|
57
|
+
/**
|
|
58
|
+
* ${1:Description placeholder}
|
|
59
|
+
*
|
|
60
|
+
* @private
|
|
61
|
+
* @readonly
|
|
62
|
+
* @type {SQSEvent}
|
|
63
|
+
*/
|
|
17
64
|
private readonly _event: SQSEvent
|
|
65
|
+
/**
|
|
66
|
+
* Creates an instance of EventProcessor.
|
|
67
|
+
*
|
|
68
|
+
* @constructor
|
|
69
|
+
* @param {SQSEvent} event
|
|
70
|
+
* @param {Context} context
|
|
71
|
+
* @param {?TransactionConfig} [config]
|
|
72
|
+
* @param {?boolean} [allowFailure]
|
|
73
|
+
*/
|
|
18
74
|
constructor(
|
|
19
75
|
event: SQSEvent,
|
|
20
76
|
context: Context,
|
|
21
|
-
config
|
|
77
|
+
config?: TransactionConfig,
|
|
22
78
|
allowFailure?: boolean,
|
|
23
79
|
) {
|
|
24
80
|
this._event = event
|
|
25
81
|
this._context = context
|
|
26
|
-
this._apiConfig = config
|
|
82
|
+
this._apiConfig = config || {}
|
|
27
83
|
this._allowFailure = allowFailure
|
|
28
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* ${1:Description placeholder}
|
|
87
|
+
*
|
|
88
|
+
* @async
|
|
89
|
+
* @param {EventProcessorExecution<ResponseInnerType>} execution
|
|
90
|
+
* @param {?boolean} [doNotDecodeMessage]
|
|
91
|
+
* @returns {(Promise<Response<ResponseErrorType> | null | SQSBatchResponse>)}
|
|
92
|
+
*/
|
|
29
93
|
async processEvent(
|
|
30
|
-
execution: EventProcessorExecution
|
|
94
|
+
execution: EventProcessorExecution<ResponseInnerType>,
|
|
31
95
|
doNotDecodeMessage?: boolean,
|
|
32
96
|
): Promise<Response<ResponseErrorType> | null | SQSBatchResponse> {
|
|
33
97
|
const resp = await this._processRawEvent(execution, !!doNotDecodeMessage)
|
|
@@ -37,12 +101,20 @@ export default class EventProcessor {
|
|
|
37
101
|
resp instanceof Response &&
|
|
38
102
|
!(resp.getCode() >= 200 && resp.getCode() < 300)
|
|
39
103
|
)
|
|
40
|
-
throw new Error(JSON.stringify(resp.getBody()))
|
|
104
|
+
throw new Error(JSON.stringify(resp.getBody() || {}))
|
|
41
105
|
else if (resp) return resp
|
|
42
106
|
return null
|
|
43
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* ${1:Description placeholder}
|
|
110
|
+
*
|
|
111
|
+
* @async
|
|
112
|
+
* @param {EventProcessorExecution<ResponseInnerType>} execution
|
|
113
|
+
* @param {boolean} doNotDecodeMessage
|
|
114
|
+
* @returns {(Promise<Response<ResponseErrorType> | null | SQSBatchResponse>)}
|
|
115
|
+
*/
|
|
44
116
|
async _processRawEvent(
|
|
45
|
-
execution: EventProcessorExecution
|
|
117
|
+
execution: EventProcessorExecution<ResponseInnerType>,
|
|
46
118
|
doNotDecodeMessage: boolean,
|
|
47
119
|
): Promise<Response<ResponseErrorType> | null | SQSBatchResponse> {
|
|
48
120
|
if (this._event.Records && this._event.Records.length > 0) {
|
|
@@ -73,8 +145,9 @@ export default class EventProcessor {
|
|
|
73
145
|
const resp = await execution(transaction, eventRecord)
|
|
74
146
|
//check for failure
|
|
75
147
|
if (
|
|
76
|
-
resp
|
|
77
|
-
|
|
148
|
+
!resp ||
|
|
149
|
+
(resp instanceof Response &&
|
|
150
|
+
!(resp?.getCode() >= 200 && resp?.getCode() < 300))
|
|
78
151
|
) {
|
|
79
152
|
//response with failures or fail hard at first
|
|
80
153
|
if (this._allowFailure) failureIDs.push(message.messageId)
|
package/src/BaseEvent/Process.ts
CHANGED
|
@@ -3,16 +3,63 @@ import Logger from "../Logger/Logger"
|
|
|
3
3
|
import Publisher from "../Publisher/Publisher"
|
|
4
4
|
|
|
5
5
|
// Config
|
|
6
|
+
/**
|
|
7
|
+
* ${1:Description placeholder}
|
|
8
|
+
*
|
|
9
|
+
* @export
|
|
10
|
+
* @typedef {ProcessConfig}
|
|
11
|
+
*/
|
|
6
12
|
export type ProcessConfig = Omit<
|
|
7
13
|
TransactionConfig,
|
|
8
14
|
"throwOnErrors" | "syncReturn"
|
|
9
15
|
>
|
|
10
16
|
|
|
17
|
+
/**
|
|
18
|
+
* ${1:Description placeholder}
|
|
19
|
+
*
|
|
20
|
+
* @export
|
|
21
|
+
* @class Process
|
|
22
|
+
* @typedef {Process}
|
|
23
|
+
*/
|
|
11
24
|
export default class Process {
|
|
25
|
+
/**
|
|
26
|
+
* ${1:Description placeholder}
|
|
27
|
+
*
|
|
28
|
+
* @private
|
|
29
|
+
* @type {number}
|
|
30
|
+
*/
|
|
12
31
|
private _interval: number
|
|
13
32
|
//
|
|
33
|
+
/**
|
|
34
|
+
* ${1:Description placeholder}
|
|
35
|
+
*
|
|
36
|
+
* @public
|
|
37
|
+
* @readonly
|
|
38
|
+
* @type {Logger}
|
|
39
|
+
*/
|
|
14
40
|
public readonly logger: Logger
|
|
41
|
+
/**
|
|
42
|
+
* ${1:Description placeholder}
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
* @readonly
|
|
46
|
+
* @type {Publisher}
|
|
47
|
+
*/
|
|
15
48
|
public readonly publisher: Publisher
|
|
49
|
+
/**
|
|
50
|
+
* ${1:Description placeholder}
|
|
51
|
+
*
|
|
52
|
+
* @public
|
|
53
|
+
* @type {NodeJS.Timeout}
|
|
54
|
+
*/
|
|
55
|
+
public interval: NodeJS.Timeout
|
|
56
|
+
/**
|
|
57
|
+
* Creates an instance of Process.
|
|
58
|
+
*
|
|
59
|
+
* @constructor
|
|
60
|
+
* @param {ProcessConfig} config
|
|
61
|
+
* @param {number} interval
|
|
62
|
+
*/
|
|
16
63
|
constructor(config: ProcessConfig, interval: number) {
|
|
17
64
|
this._interval = interval
|
|
18
65
|
this.logger = new Logger(config.logger, "long-running-process")
|
|
@@ -20,16 +67,30 @@ export default class Process {
|
|
|
20
67
|
}
|
|
21
68
|
|
|
22
69
|
//Main interface
|
|
70
|
+
/**
|
|
71
|
+
* ${1:Description placeholder}
|
|
72
|
+
*
|
|
73
|
+
* @async
|
|
74
|
+
* @param {*} executionFunc
|
|
75
|
+
* @returns {*}
|
|
76
|
+
*/
|
|
23
77
|
async execute(executionFunc) {
|
|
24
78
|
this.logger.debug("Starting main process code")
|
|
25
79
|
//Connect DB
|
|
26
80
|
// if (this.db) await this.db.connect();
|
|
27
81
|
//Program loop
|
|
28
|
-
setInterval(async () => {
|
|
82
|
+
this.interval = setInterval(async () => {
|
|
29
83
|
await this._execute(executionFunc)
|
|
30
84
|
}, this._interval)
|
|
31
85
|
}
|
|
32
86
|
//Executions
|
|
87
|
+
/**
|
|
88
|
+
* ${1:Description placeholder}
|
|
89
|
+
*
|
|
90
|
+
* @async
|
|
91
|
+
* @param {*} executionFunc
|
|
92
|
+
* @returns {unknown}
|
|
93
|
+
*/
|
|
33
94
|
async _execute(executionFunc) {
|
|
34
95
|
let executionFailed = true //failled til we say no!
|
|
35
96
|
//safe execution handler
|
|
@@ -126,13 +126,11 @@ export default class Transaction<
|
|
|
126
126
|
//retrow?
|
|
127
127
|
if (this.retrowErrors) throw e
|
|
128
128
|
//envelope exception?
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
await this.response.build(this.context, this, this.syncReturn)
|
|
135
|
-
}
|
|
129
|
+
this.response = this.getErrorResponse(
|
|
130
|
+
Globals.ErrorResponseUnhandledError,
|
|
131
|
+
Globals.ErrorCode_APIError,
|
|
132
|
+
)
|
|
133
|
+
await this.response.build(this.context, this, this.syncReturn)
|
|
136
134
|
}
|
|
137
135
|
return executionFailed
|
|
138
136
|
}
|
|
@@ -164,7 +162,6 @@ export default class Transaction<
|
|
|
164
162
|
private async executeLoggerFlush(safeExecution) {
|
|
165
163
|
try {
|
|
166
164
|
await safeExecution()
|
|
167
|
-
await this.logger.flushLogs()
|
|
168
165
|
} catch (e) {
|
|
169
166
|
this.logger.error("Exception when flushing logs.")
|
|
170
167
|
this.logger.exception(e)
|
|
@@ -4,8 +4,20 @@ import * as DurationParser from "parse-duration"
|
|
|
4
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,12 +135,20 @@ export default class Configuration<T extends ConfigurationSchema> {
|
|
|
61
135
|
new EnvironmentVar<string>(
|
|
62
136
|
propString,
|
|
63
137
|
EnvironmentType.Local,
|
|
64
|
-
propSchema.required,
|
|
138
|
+
!propSchema.required,
|
|
65
139
|
this.remotePrefix,
|
|
66
140
|
).syncResolve()
|
|
67
141
|
this.cacheValue(propString, v, propSchema.cachingPolicy)
|
|
68
142
|
return v
|
|
69
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* ${1:Description placeholder}
|
|
146
|
+
*
|
|
147
|
+
* @public
|
|
148
|
+
* @async
|
|
149
|
+
* @param {keyof OmitByValueType<ExtractRemote<T>, null>} propName
|
|
150
|
+
* @returns {Promise<any>}
|
|
151
|
+
*/
|
|
70
152
|
public async asyncGet(
|
|
71
153
|
propName: keyof OmitByValueType<ExtractRemote<T>, null>,
|
|
72
154
|
): Promise<any> {
|
|
@@ -78,16 +160,31 @@ export default class Configuration<T extends ConfigurationSchema> {
|
|
|
78
160
|
(await new EnvironmentVar<string>(
|
|
79
161
|
propString,
|
|
80
162
|
EnvironmentType.PlainRemote,
|
|
81
|
-
propSchema.required,
|
|
163
|
+
!propSchema.required,
|
|
82
164
|
this.remotePrefix,
|
|
83
165
|
).resolve())
|
|
84
166
|
this.cacheValue(propString, v, propSchema.cachingPolicy)
|
|
85
167
|
return v
|
|
86
168
|
}
|
|
87
169
|
// caching layer
|
|
170
|
+
/**
|
|
171
|
+
* ${1:Description placeholder}
|
|
172
|
+
*
|
|
173
|
+
* @private
|
|
174
|
+
* @param {string} valueKey
|
|
175
|
+
* @returns {*}
|
|
176
|
+
*/
|
|
88
177
|
private getCachedValue(valueKey: string): any {
|
|
89
178
|
return cacheStore.get(valueKey)
|
|
90
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* ${1:Description placeholder}
|
|
182
|
+
*
|
|
183
|
+
* @private
|
|
184
|
+
* @param {string} valueKey
|
|
185
|
+
* @param {*} value
|
|
186
|
+
* @param {string} [policy="1d"]
|
|
187
|
+
*/
|
|
91
188
|
private cacheValue(
|
|
92
189
|
valueKey: string,
|
|
93
190
|
value: any,
|
|
@@ -95,4 +192,13 @@ export default class Configuration<T extends ConfigurationSchema> {
|
|
|
95
192
|
): void {
|
|
96
193
|
cacheStore.set(valueKey, value, DurationParser(policy, "s"))
|
|
97
194
|
}
|
|
195
|
+
// unit-test support
|
|
196
|
+
/**
|
|
197
|
+
* ${1:Description placeholder}
|
|
198
|
+
*
|
|
199
|
+
* @private
|
|
200
|
+
*/
|
|
201
|
+
private resetCache() {
|
|
202
|
+
cacheStore = new MemCache()
|
|
203
|
+
}
|
|
98
204
|
}
|
|
@@ -7,19 +7,75 @@ import { SSMClient, GetParameterCommand } from "@aws-sdk/client-ssm"
|
|
|
7
7
|
// Explicity setting VM level variables in order to persist
|
|
8
8
|
// client across different important and instances.
|
|
9
9
|
// eslint-disable-next-line no-var
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* ${1:Description placeholder}
|
|
12
|
+
*
|
|
13
|
+
* @type {*}
|
|
14
|
+
*/
|
|
15
|
+
let ssmClient = null,
|
|
11
16
|
secretsClient = null
|
|
12
17
|
|
|
18
|
+
/**
|
|
19
|
+
* ${1:Description placeholder}
|
|
20
|
+
*
|
|
21
|
+
* @export
|
|
22
|
+
* @enum {number}
|
|
23
|
+
*/
|
|
13
24
|
export enum EnvironmentType {
|
|
14
25
|
PlainRemote,
|
|
15
26
|
SecureRemote,
|
|
16
27
|
Local,
|
|
17
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* ${1:Description placeholder}
|
|
31
|
+
*
|
|
32
|
+
* @export
|
|
33
|
+
* @class EnvironmentVar
|
|
34
|
+
* @typedef {EnvironmentVar}
|
|
35
|
+
* @template T
|
|
36
|
+
*/
|
|
18
37
|
export default class EnvironmentVar<T> {
|
|
38
|
+
/**
|
|
39
|
+
* ${1:Description placeholder}
|
|
40
|
+
*
|
|
41
|
+
* @private
|
|
42
|
+
* @readonly
|
|
43
|
+
* @type {string}
|
|
44
|
+
*/
|
|
19
45
|
private readonly paramName: string
|
|
46
|
+
/**
|
|
47
|
+
* ${1:Description placeholder}
|
|
48
|
+
*
|
|
49
|
+
* @private
|
|
50
|
+
* @readonly
|
|
51
|
+
* @type {EnvironmentType}
|
|
52
|
+
*/
|
|
20
53
|
private readonly type: EnvironmentType
|
|
54
|
+
/**
|
|
55
|
+
* ${1:Description placeholder}
|
|
56
|
+
*
|
|
57
|
+
* @private
|
|
58
|
+
* @readonly
|
|
59
|
+
* @type {boolean}
|
|
60
|
+
*/
|
|
21
61
|
private readonly optional: boolean
|
|
62
|
+
/**
|
|
63
|
+
* ${1:Description placeholder}
|
|
64
|
+
*
|
|
65
|
+
* @private
|
|
66
|
+
* @readonly
|
|
67
|
+
* @type {string}
|
|
68
|
+
*/
|
|
22
69
|
private readonly paramPrefix: string
|
|
70
|
+
/**
|
|
71
|
+
* Creates an instance of EnvironmentVar.
|
|
72
|
+
*
|
|
73
|
+
* @constructor
|
|
74
|
+
* @param {string} paramName
|
|
75
|
+
* @param {EnvironmentType} type
|
|
76
|
+
* @param {?boolean} [optional]
|
|
77
|
+
* @param {string} [paramPrefix=`/creatorco-api-\${process.env.STAGE\}/env/`]
|
|
78
|
+
*/
|
|
23
79
|
constructor(
|
|
24
80
|
paramName: string,
|
|
25
81
|
type: EnvironmentType,
|
|
@@ -32,6 +88,12 @@ export default class EnvironmentVar<T> {
|
|
|
32
88
|
this.paramPrefix = paramPrefix
|
|
33
89
|
}
|
|
34
90
|
|
|
91
|
+
/**
|
|
92
|
+
* ${1:Description placeholder}
|
|
93
|
+
*
|
|
94
|
+
* @public
|
|
95
|
+
* @returns {T}
|
|
96
|
+
*/
|
|
35
97
|
public syncResolve(): T {
|
|
36
98
|
if (this.type == EnvironmentType.Local) return this.getLocalValue()
|
|
37
99
|
else {
|
|
@@ -40,6 +102,13 @@ export default class EnvironmentVar<T> {
|
|
|
40
102
|
)
|
|
41
103
|
}
|
|
42
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* ${1:Description placeholder}
|
|
107
|
+
*
|
|
108
|
+
* @public
|
|
109
|
+
* @async
|
|
110
|
+
* @returns {unknown}
|
|
111
|
+
*/
|
|
43
112
|
public async resolve() {
|
|
44
113
|
if (this.type == EnvironmentType.Local) return this.getLocalValue()
|
|
45
114
|
else if (this.type == EnvironmentType.SecureRemote)
|
|
@@ -47,6 +116,12 @@ export default class EnvironmentVar<T> {
|
|
|
47
116
|
else return this.getPlainValue()
|
|
48
117
|
}
|
|
49
118
|
|
|
119
|
+
/**
|
|
120
|
+
* ${1:Description placeholder}
|
|
121
|
+
*
|
|
122
|
+
* @private
|
|
123
|
+
* @returns {T}
|
|
124
|
+
*/
|
|
50
125
|
private getLocalValue(): T {
|
|
51
126
|
const value = process.env[this.paramName]
|
|
52
127
|
if (!value && !this.optional) {
|
|
@@ -56,6 +131,13 @@ export default class EnvironmentVar<T> {
|
|
|
56
131
|
}
|
|
57
132
|
return value as T
|
|
58
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* ${1:Description placeholder}
|
|
136
|
+
*
|
|
137
|
+
* @private
|
|
138
|
+
* @async
|
|
139
|
+
* @returns {Promise<T>}
|
|
140
|
+
*/
|
|
59
141
|
private async getPlainValue(): Promise<T> {
|
|
60
142
|
if (!ssmClient) ssmClient = new SSMClient()
|
|
61
143
|
const pName = `${this.paramPrefix}${this.paramName}`
|
|
@@ -72,6 +154,13 @@ export default class EnvironmentVar<T> {
|
|
|
72
154
|
throw new Error(`Unable to retrieve plain remote env value: ${pName}`)
|
|
73
155
|
}
|
|
74
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* ${1:Description placeholder}
|
|
159
|
+
*
|
|
160
|
+
* @private
|
|
161
|
+
* @async
|
|
162
|
+
* @returns {Promise<T>}
|
|
163
|
+
*/
|
|
75
164
|
private async getSecureValue(): Promise<T> {
|
|
76
165
|
if (!secretsClient) secretsClient = new SecretsManagerClient()
|
|
77
166
|
const pName = `${this.paramPrefix}${this.paramName}`
|