@creator.co/wapi 1.1.7 → 1.2.0-alpha1
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 +22 -22
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/package.json +48 -0
- package/dist/src/API/Request.d.ts +4 -5
- package/dist/src/API/Request.js +3 -4
- package/dist/src/API/Request.js.map +1 -1
- package/dist/src/API/Response.d.ts +1 -1
- package/dist/src/API/Response.js.map +1 -1
- package/dist/src/BaseEvent/EventProcessor.js +0 -1
- package/dist/src/BaseEvent/EventProcessor.js.map +1 -1
- package/dist/src/BaseEvent/Process.d.ts +0 -1
- package/dist/src/BaseEvent/Process.js +1 -2
- package/dist/src/BaseEvent/Process.js.map +1 -1
- package/dist/src/BaseEvent/Transaction.d.ts +6 -6
- package/dist/src/BaseEvent/Transaction.js +2 -4
- package/dist/src/BaseEvent/Transaction.js.map +1 -1
- package/dist/src/Config/EnvironmentVar.d.ts +17 -0
- package/dist/src/Config/EnvironmentVar.js +155 -0
- package/dist/src/Config/EnvironmentVar.js.map +1 -0
- package/dist/src/Globals.d.ts +11 -0
- package/dist/src/Globals.js +12 -0
- package/dist/src/Globals.js.map +1 -1
- package/dist/src/Logger/Logger.js +42 -11
- package/dist/src/Logger/Logger.js.map +1 -1
- package/dist/src/Mailer/Mailer.js +52 -26
- package/dist/src/Mailer/Mailer.js.map +1 -1
- package/dist/src/Server/Router.d.ts +30 -0
- package/dist/src/Server/Router.js +21 -0
- package/dist/src/Server/Router.js.map +1 -0
- package/dist/src/Server/lib/ContainerServer.d.ts +11 -0
- package/dist/src/Server/lib/ContainerServer.js +100 -0
- package/dist/src/Server/lib/ContainerServer.js.map +1 -0
- package/dist/src/Server/lib/Server.d.ts +9 -0
- package/dist/src/Server/lib/Server.js +137 -0
- package/dist/src/Server/lib/Server.js.map +1 -0
- package/dist/src/Server/lib/container/GenericHandler.d.ts +4 -0
- package/dist/src/Server/lib/container/GenericHandler.js +138 -0
- package/dist/src/Server/lib/container/GenericHandler.js.map +1 -0
- package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +14 -0
- package/dist/src/Server/lib/container/GenericHandlerEvent.js +164 -0
- package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +1 -0
- package/dist/src/Server/lib/container/HealthHandler.d.ts +3 -0
- package/dist/src/Server/lib/container/HealthHandler.js +44 -0
- package/dist/src/Server/lib/container/HealthHandler.js.map +1 -0
- package/dist/src/Server/lib/container/Proxy.d.ts +15 -0
- package/dist/src/Server/lib/container/Proxy.js +153 -0
- package/dist/src/Server/lib/container/Proxy.js.map +1 -0
- package/dist/src/Server/lib/container/Utils.d.ts +6 -0
- package/dist/src/Server/lib/container/Utils.js +109 -0
- package/dist/src/Server/lib/container/Utils.js.map +1 -0
- package/dist/src/Validation/Validator.d.ts +5 -0
- package/dist/src/Validation/Validator.js +39 -0
- package/dist/src/Validation/Validator.js.map +1 -0
- package/index.ts +2 -0
- package/package.json +12 -3
- package/src/API/Request.ts +6 -12
- package/src/API/Response.ts +1 -1
- package/src/BaseEvent/EventProcessor.ts +3 -2
- package/src/BaseEvent/Process.ts +4 -4
- package/src/BaseEvent/Transaction.ts +24 -16
- package/src/Config/EnvironmentVar.ts +94 -0
- package/src/Globals.ts +15 -0
- package/src/Mailer/Mailer.ts +2 -0
- package/src/Server/Router.ts +51 -0
- package/src/Server/lib/ContainerServer.ts +27 -0
- package/src/Server/lib/Server.ts +66 -0
- package/src/Server/lib/container/GenericHandler.ts +63 -0
- package/src/Server/lib/container/GenericHandlerEvent.ts +133 -0
- package/src/Server/lib/container/HealthHandler.ts +5 -0
- package/src/Server/lib/container/Proxy.ts +107 -0
- package/src/Server/lib/container/Utils.ts +45 -0
- package/src/Validation/Validator.ts +35 -0
- package/tsconfig.json +2 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __values = (this && this.__values) || function(o) {
|
|
3
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
4
|
+
if (m) return m.call(o);
|
|
5
|
+
if (o && typeof o.length === "number") return {
|
|
6
|
+
next: function () {
|
|
7
|
+
if (o && i >= o.length) o = void 0;
|
|
8
|
+
return { value: o && o[i++], done: !o };
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
12
|
+
};
|
|
13
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
14
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
15
|
+
if (!m) return o;
|
|
16
|
+
var i = m.call(o), r, ar = [], e;
|
|
17
|
+
try {
|
|
18
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
19
|
+
}
|
|
20
|
+
catch (error) { e = { error: error }; }
|
|
21
|
+
finally {
|
|
22
|
+
try {
|
|
23
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
24
|
+
}
|
|
25
|
+
finally { if (e) throw e.error; }
|
|
26
|
+
}
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.nullIfEmpty = exports.parseQueryStringParameters = exports.parseMultiValueQueryStringParameters = exports.parseMultiValueHeaders = void 0;
|
|
31
|
+
var unflatten_1 = require("unflatten");
|
|
32
|
+
// https://aws.amazon.com/blogs/compute/support-for-multi-value-parameters-in-amazon-api-gateway/
|
|
33
|
+
// (rawHeaders: Array<string>): { [string]: Array<string> }
|
|
34
|
+
function parseMultiValueHeaders(rawHeaders) {
|
|
35
|
+
var e_1, _a;
|
|
36
|
+
if (rawHeaders.length === 0)
|
|
37
|
+
return null;
|
|
38
|
+
//
|
|
39
|
+
var map = new Map();
|
|
40
|
+
var unflattened = (0, unflatten_1.default)(rawHeaders, 2);
|
|
41
|
+
try {
|
|
42
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
43
|
+
for (var _b = __values(Object.keys(unflattened)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
44
|
+
var key = _c.value;
|
|
45
|
+
var item = map.get(key);
|
|
46
|
+
if (item)
|
|
47
|
+
item.push(unflattened[key]);
|
|
48
|
+
else
|
|
49
|
+
map.set(key, [unflattened[key]]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
53
|
+
finally {
|
|
54
|
+
try {
|
|
55
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
56
|
+
}
|
|
57
|
+
finally { if (e_1) throw e_1.error; }
|
|
58
|
+
}
|
|
59
|
+
return Object.fromEntries(map);
|
|
60
|
+
}
|
|
61
|
+
exports.parseMultiValueHeaders = parseMultiValueHeaders;
|
|
62
|
+
// https://aws.amazon.com/blogs/compute/support-for-multi-value-parameters-in-amazon-api-gateway/
|
|
63
|
+
// [ [ 'petType', 'dog' ], [ 'petType', 'fish' ] ]
|
|
64
|
+
// => { petType: [ 'dog', 'fish' ] },
|
|
65
|
+
function parseMultiValueQueryStringParameters(url) {
|
|
66
|
+
var e_2, _a;
|
|
67
|
+
// dummy placeholder url for the WHATWG URL constructor
|
|
68
|
+
// https://github.com/nodejs/node/issues/12682
|
|
69
|
+
var searchParams = new URL(url, "http://example").searchParams;
|
|
70
|
+
//
|
|
71
|
+
if (Array.from(searchParams).length === 0)
|
|
72
|
+
return null;
|
|
73
|
+
var map = new Map();
|
|
74
|
+
try {
|
|
75
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
76
|
+
for (var searchParams_1 = __values(searchParams), searchParams_1_1 = searchParams_1.next(); !searchParams_1_1.done; searchParams_1_1 = searchParams_1.next()) {
|
|
77
|
+
var _b = __read(searchParams_1_1.value, 2), key = _b[0], value = _b[1];
|
|
78
|
+
var item = map.get(key);
|
|
79
|
+
if (item)
|
|
80
|
+
item.push(value);
|
|
81
|
+
else
|
|
82
|
+
map.set(key, [value]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
86
|
+
finally {
|
|
87
|
+
try {
|
|
88
|
+
if (searchParams_1_1 && !searchParams_1_1.done && (_a = searchParams_1.return)) _a.call(searchParams_1);
|
|
89
|
+
}
|
|
90
|
+
finally { if (e_2) throw e_2.error; }
|
|
91
|
+
}
|
|
92
|
+
return Object.fromEntries(map);
|
|
93
|
+
}
|
|
94
|
+
exports.parseMultiValueQueryStringParameters = parseMultiValueQueryStringParameters;
|
|
95
|
+
function parseQueryStringParameters(url) {
|
|
96
|
+
// dummy placeholder url for the WHATWG URL constructor
|
|
97
|
+
// https://github.com/nodejs/node/issues/12682
|
|
98
|
+
var searchParams = new URL(url, "http://example").searchParams;
|
|
99
|
+
if (Array.from(searchParams).length === 0)
|
|
100
|
+
return null;
|
|
101
|
+
return Object.fromEntries(searchParams);
|
|
102
|
+
}
|
|
103
|
+
exports.parseQueryStringParameters = parseQueryStringParameters;
|
|
104
|
+
//
|
|
105
|
+
function nullIfEmpty(obj) {
|
|
106
|
+
return obj && (Object.keys(obj).length > 0 ? obj : null);
|
|
107
|
+
}
|
|
108
|
+
exports.nullIfEmpty = nullIfEmpty;
|
|
109
|
+
//# sourceMappingURL=Utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Utils.js","sourceRoot":"","sources":["../../../../../src/Server/lib/container/Utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAiC;AACjC,iGAAiG;AACjG,2DAA2D;AAC3D,SAAgB,sBAAsB,CAAC,UAAU;;IAC/C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACxC,EAAE;IACF,IAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAA;IACrB,IAAM,WAAW,GAAG,IAAA,mBAAS,EAAC,UAAU,EAAE,CAAC,CAAC,CAAA;;QAC5C,gDAAgD;QAChD,KAAkB,IAAA,KAAA,SAAA,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA,gBAAA,4BAAE;YAAvC,IAAM,GAAG,WAAA;YACZ,IAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACzB,IAAI,IAAI;gBAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAA;;gBAChC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;SACtC;;;;;;;;;IACD,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;AAChC,CAAC;AAZD,wDAYC;AACD,iGAAiG;AACjG,kDAAkD;AAClD,qCAAqC;AACrC,SAAgB,oCAAoC,CAAC,GAAG;;IACtD,uDAAuD;IACvD,8CAA8C;IACtC,IAAA,YAAY,GAAK,IAAI,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,aAAnC,CAAmC;IACvD,EAAE;IACF,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACtD,IAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAA;;QACrB,gDAAgD;QAChD,KAA2B,IAAA,iBAAA,SAAA,YAAY,CAAA,0CAAA,oEAAE;YAA9B,IAAA,KAAA,iCAAY,EAAX,GAAG,QAAA,EAAE,KAAK,QAAA;YACpB,IAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACzB,IAAI,IAAI;gBAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;;gBACrB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;SAC3B;;;;;;;;;IACD,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;AAChC,CAAC;AAdD,oFAcC;AACD,SAAgB,0BAA0B,CAAC,GAAG;IAC5C,uDAAuD;IACvD,8CAA8C;IACtC,IAAA,YAAY,GAAK,IAAI,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,aAAnC,CAAmC;IACvD,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACtD,OAAO,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAA;AACzC,CAAC;AAND,gEAMC;AACD,EAAE;AACF,SAAgB,WAAW,CAAC,GAAG;IAC7B,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;AAC1D,CAAC;AAFD,kCAEC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var zod_1 = require("zod");
|
|
4
|
+
var Response_1 = require("../API/Response");
|
|
5
|
+
var Globals_1 = require("../Globals");
|
|
6
|
+
var Validator = /** @class */ (function () {
|
|
7
|
+
function Validator() {
|
|
8
|
+
}
|
|
9
|
+
Validator.validateSchema = function (data, schema) {
|
|
10
|
+
var error, validatedInput;
|
|
11
|
+
// Validate body against known zod schema
|
|
12
|
+
try {
|
|
13
|
+
validatedInput = schema.parse(data);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (err instanceof zod_1.z.ZodError) {
|
|
17
|
+
error = err.issues
|
|
18
|
+
.map(function (v) {
|
|
19
|
+
return "".concat(v.code, " - ").concat(v.message, " ").concat(v.path);
|
|
20
|
+
})
|
|
21
|
+
.join(", ");
|
|
22
|
+
}
|
|
23
|
+
else if (err.message)
|
|
24
|
+
error = err.message;
|
|
25
|
+
else
|
|
26
|
+
error = "Unknown validation error!";
|
|
27
|
+
}
|
|
28
|
+
// Error validation
|
|
29
|
+
if (!validatedInput || error) {
|
|
30
|
+
return Response_1.default.BadRequestResponse(Globals_1.default.ErrorResponseValidationFail, Globals_1.default.ErrorCode_InvalidInput);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return Validator;
|
|
37
|
+
}());
|
|
38
|
+
exports.default = Validator;
|
|
39
|
+
//# sourceMappingURL=Validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Validator.js","sourceRoot":"","sources":["../../../src/Validation/Validator.ts"],"names":[],"mappings":";;AAAA,2BAAuB;AAEvB,4CAAsC;AACtC,sCAAgC;AAEhC;IAAA;IA6BA,CAAC;IA5Be,wBAAc,GAA5B,UACE,IAAS,EACT,MAAwB;QAExB,IAAI,KAAK,EAAE,cAAc,CAAA;QACzB,yCAAyC;QACzC,IAAI;YACF,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAkB,CAAA;SACrD;QAAC,OAAO,GAAqB,EAAE;YAC9B,IAAI,GAAG,YAAY,OAAC,CAAC,QAAQ,EAAE;gBAC7B,KAAK,GAAG,GAAG,CAAC,MAAM;qBACf,GAAG,CAAC,UAAC,CAAC;oBACL,OAAO,UAAG,CAAC,CAAC,IAAI,gBAAM,CAAC,CAAC,OAAO,cAAI,CAAC,CAAC,IAAI,CAAE,CAAA;gBAC7C,CAAC,CAAC;qBACD,IAAI,CAAC,IAAI,CAAC,CAAA;aACd;iBAAM,IAAI,GAAG,CAAC,OAAO;gBAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAAA;;gBACtC,KAAK,GAAG,2BAA2B,CAAA;SACzC;QACD,mBAAmB;QACnB,IAAI,CAAC,cAAc,IAAI,KAAK,EAAE;YAC5B,OAAO,kBAAQ,CAAC,kBAAkB,CAChC,iBAAO,CAAC,2BAA2B,EACnC,iBAAO,CAAC,sBAAsB,CAC/B,CAAA;SACF;aAAM;YACL,OAAO,IAAI,CAAA;SACZ;IACH,CAAC;IACH,gBAAC;AAAD,CAAC,AA7BD,IA6BC"}
|
package/index.ts
CHANGED
|
@@ -6,12 +6,14 @@ import Transaction from "./src/BaseEvent/Transaction"
|
|
|
6
6
|
import Crypto from "./src/Crypto/Crypto"
|
|
7
7
|
import Mailer from "./src/Mailer/Mailer"
|
|
8
8
|
import Publisher from "./src/Publisher/Publisher"
|
|
9
|
+
import Router from "./src/Server/Router"
|
|
9
10
|
|
|
10
11
|
export {
|
|
11
12
|
//Base Events
|
|
12
13
|
Transaction,
|
|
13
14
|
Process,
|
|
14
15
|
EventProcessor,
|
|
16
|
+
Router,
|
|
15
17
|
//Client
|
|
16
18
|
Publisher,
|
|
17
19
|
Mailer,
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@creator.co/wapi",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0-alpha1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "commonjs",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"prepare": "npm run build",
|
|
10
9
|
"build": "npm run lint && tsc --build",
|
|
11
10
|
"clean": "tsc --build --clean",
|
|
12
11
|
"lint": "eslint . --ext .ts --fix"
|
|
@@ -14,22 +13,32 @@
|
|
|
14
13
|
"author": "",
|
|
15
14
|
"license": "ISC",
|
|
16
15
|
"dependencies": {
|
|
16
|
+
"@aws-sdk/client-secrets-manager": "^3.427.0",
|
|
17
17
|
"@aws-sdk/client-ses": "^3.414.0",
|
|
18
18
|
"@aws-sdk/client-sns": "^3.398.0",
|
|
19
|
+
"@aws-sdk/client-ssm": "^3.427.0",
|
|
19
20
|
"@aws-sdk/credential-provider-node": "^3.414.0",
|
|
20
21
|
"@types/email-templates": "^10.0.1",
|
|
21
22
|
"@types/nodemailer": "^6.4.10",
|
|
22
23
|
"abind": "^1.0.5",
|
|
24
|
+
"cors": "^2.8.5",
|
|
25
|
+
"cuid": "^3.0.0",
|
|
26
|
+
"dotenv": "^16.3.1",
|
|
23
27
|
"email-templates": "^11.1.1",
|
|
28
|
+
"express": "^4.18.2",
|
|
24
29
|
"json-stringify-safe": "^5.0.1",
|
|
25
30
|
"sha1": "^1.1.1",
|
|
26
|
-
"stack-trace": "0.0.10"
|
|
31
|
+
"stack-trace": "0.0.10",
|
|
32
|
+
"unflatten": "^1.0.4",
|
|
33
|
+
"zod": "^3.22.4"
|
|
27
34
|
},
|
|
28
35
|
"devDependencies": {
|
|
29
36
|
"@types/aws-lambda": "^8.10.119",
|
|
37
|
+
"@types/express": "^4.17.19",
|
|
30
38
|
"@types/node": "^20.5.7",
|
|
31
39
|
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
|
32
40
|
"@typescript-eslint/parser": "^6.5.0",
|
|
41
|
+
"aws-lambda": "^1.0.7",
|
|
33
42
|
"eslint": "^8.48.0",
|
|
34
43
|
"eslint-config-prettier": "^9.0.0",
|
|
35
44
|
"eslint-plugin-import": "^2.28.1",
|
package/src/API/Request.ts
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import type { Context, APIGatewayEvent } from "aws-lambda"
|
|
2
2
|
|
|
3
3
|
import Utils from "./Utils"
|
|
4
|
-
import
|
|
4
|
+
import Logger from "../Logger/Logger"
|
|
5
5
|
//
|
|
6
|
-
export default class Request {
|
|
6
|
+
export default class Request<T> {
|
|
7
7
|
private requestEvent: APIGatewayEvent
|
|
8
8
|
private context: Context
|
|
9
|
-
|
|
10
|
-
constructor(
|
|
11
|
-
requestEvent: APIGatewayEvent,
|
|
12
|
-
context: Context,
|
|
13
|
-
transaction: Transaction,
|
|
14
|
-
) {
|
|
9
|
+
constructor(requestEvent: APIGatewayEvent, context: Context, logger: Logger) {
|
|
15
10
|
this.requestEvent = requestEvent
|
|
16
|
-
this.transaction = transaction
|
|
17
11
|
this.context = context
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
logger.debug("Request info:", JSON.stringify(requestEvent))
|
|
13
|
+
logger.debug("Request context:", JSON.stringify(context))
|
|
20
14
|
}
|
|
21
15
|
//query
|
|
22
16
|
public containsQueryParam(paramName: string): boolean {
|
|
@@ -55,7 +49,7 @@ export default class Request {
|
|
|
55
49
|
)
|
|
56
50
|
}
|
|
57
51
|
//body
|
|
58
|
-
public getBody():
|
|
52
|
+
public getBody(): T | null {
|
|
59
53
|
let b: any = null
|
|
60
54
|
try {
|
|
61
55
|
b = this.requestEvent.body
|
package/src/API/Response.ts
CHANGED
|
@@ -3,12 +3,13 @@ import type { Context, SQSBatchResponse, SQSEvent } from "aws-lambda"
|
|
|
3
3
|
import Transaction, { TransactionConfig } from "./Transaction"
|
|
4
4
|
import Response from "../API/Response"
|
|
5
5
|
import Globals from "../Globals"
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
// Handler
|
|
7
8
|
export type EventProcessorExecution = (
|
|
8
9
|
transaction: Transaction,
|
|
9
10
|
recordContent: string | object,
|
|
10
11
|
) => Promise<Response | SQSBatchResponse>
|
|
11
|
-
|
|
12
|
+
|
|
12
13
|
export default class EventProcessor {
|
|
13
14
|
private readonly _allowFailure: boolean
|
|
14
15
|
private readonly _apiConfig: TransactionConfig
|
package/src/BaseEvent/Process.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import Logger, { LoggerConfig } from "../Logger/Logger"
|
|
2
2
|
import Publisher, { PublisherConfig } from "../Publisher/Publisher"
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
// Config
|
|
4
5
|
export type ProcessConfig = {
|
|
5
6
|
logger?: LoggerConfig
|
|
6
7
|
publisher?: PublisherConfig
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
+
|
|
9
10
|
export default class Process {
|
|
10
11
|
private _interval: number
|
|
11
12
|
//
|
|
12
13
|
public readonly logger: Logger
|
|
13
|
-
public readonly request: Request
|
|
14
14
|
public readonly publisher: Publisher
|
|
15
15
|
constructor(config: ProcessConfig, interval: number) {
|
|
16
16
|
this._interval = interval
|
|
@@ -44,7 +44,7 @@ export default class Process {
|
|
|
44
44
|
} catch (e) {
|
|
45
45
|
/*EXECUTION FAIL*/
|
|
46
46
|
this.logger.error(
|
|
47
|
-
"Exception when executing main
|
|
47
|
+
"Exception when executing main process code. Rolling back DB!",
|
|
48
48
|
)
|
|
49
49
|
this.logger.exception(e)
|
|
50
50
|
//Rollback DB
|
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
APIGatewayEvent,
|
|
3
|
+
Context,
|
|
4
|
+
SQSBatchResponse,
|
|
5
|
+
SQSEvent,
|
|
6
|
+
} from "aws-lambda"
|
|
3
7
|
|
|
4
8
|
import Request from "../API/Request"
|
|
5
9
|
import Response from "../API/Response"
|
|
6
10
|
import Globals from "../Globals"
|
|
7
|
-
//Comps
|
|
8
11
|
import Logger, { LoggerConfig } from "../Logger/Logger"
|
|
9
12
|
import Publisher, { PublisherConfig } from "../Publisher/Publisher"
|
|
10
|
-
|
|
11
|
-
//
|
|
13
|
+
|
|
14
|
+
// Request
|
|
12
15
|
export type TransactionExecution<T> = (
|
|
13
16
|
transaction: T,
|
|
14
17
|
) => Promise<Response | SQSBatchResponse>
|
|
15
|
-
//
|
|
18
|
+
// Config
|
|
16
19
|
export type TransactionConfig = {
|
|
17
20
|
throwOnErrors?: boolean
|
|
18
21
|
syncReturn?: boolean
|
|
22
|
+
//
|
|
19
23
|
logger?: LoggerConfig
|
|
20
24
|
publisher?: PublisherConfig
|
|
21
25
|
}
|
|
22
|
-
|
|
23
|
-
export default class Transaction {
|
|
26
|
+
|
|
27
|
+
export default class Transaction<T = object> {
|
|
24
28
|
private _event: any
|
|
25
29
|
private _context: Context
|
|
26
30
|
private _response: Response | null | SQSBatchResponse
|
|
@@ -28,34 +32,38 @@ export default class Transaction {
|
|
|
28
32
|
private _retrowErrors: boolean
|
|
29
33
|
//
|
|
30
34
|
public readonly logger: Logger
|
|
31
|
-
public readonly request: Request
|
|
35
|
+
public readonly request: Request<T>
|
|
32
36
|
public readonly publisher: Publisher
|
|
33
37
|
public responseProxy: (response: Response) => Promise<void>
|
|
34
38
|
//
|
|
35
|
-
constructor(
|
|
39
|
+
constructor(
|
|
40
|
+
event: APIGatewayEvent | SQSEvent,
|
|
41
|
+
context: Context,
|
|
42
|
+
config?: TransactionConfig,
|
|
43
|
+
) {
|
|
36
44
|
const transactionId = context.awsRequestId
|
|
37
45
|
? context.awsRequestId
|
|
38
|
-
: event.requestContext
|
|
39
|
-
? event.requestContext.requestId
|
|
46
|
+
: (<APIGatewayEvent>event).requestContext
|
|
47
|
+
? (<APIGatewayEvent>event).requestContext.requestId
|
|
40
48
|
: "unknown"
|
|
41
49
|
// transaction ctx
|
|
42
50
|
this._event = event
|
|
43
51
|
this._context = context
|
|
44
52
|
this._response = null
|
|
45
|
-
//
|
|
53
|
+
// when set, this will be called with the response context right before calling the context suceed/fail - useful for writing the resp for example.
|
|
46
54
|
this.responseProxy = null
|
|
47
55
|
// transaction flags
|
|
48
56
|
this._syncReturn = !!config?.syncReturn
|
|
49
57
|
this._retrowErrors = !!config?.throwOnErrors /* retrow internal errors */
|
|
50
58
|
// components
|
|
51
59
|
this.logger = new Logger(config?.logger, transactionId)
|
|
52
|
-
this.request = new Request(this._event, this._context, this)
|
|
60
|
+
this.request = new Request<T>(this._event, this._context, this.logger)
|
|
53
61
|
this.publisher = new Publisher(config?.publisher)
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
//Main interface
|
|
57
65
|
async execute(
|
|
58
|
-
executionFunc: TransactionExecution<Transaction
|
|
66
|
+
executionFunc: TransactionExecution<Transaction<T>>,
|
|
59
67
|
): Promise<Response | null | SQSBatchResponse> {
|
|
60
68
|
await this._executeLoggerFlush(async () => {
|
|
61
69
|
await this._executeDBTransactions(async () => {
|
|
@@ -69,7 +77,7 @@ export default class Transaction {
|
|
|
69
77
|
}
|
|
70
78
|
//Executions
|
|
71
79
|
async _execute(
|
|
72
|
-
executionFunc: TransactionExecution<Transaction
|
|
80
|
+
executionFunc: TransactionExecution<Transaction<T>>,
|
|
73
81
|
): Promise<boolean> {
|
|
74
82
|
let executionFailed = true //failed til we say no!
|
|
75
83
|
//safe execution handler
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SecretsManagerClient,
|
|
3
|
+
GetSecretValueCommand,
|
|
4
|
+
} from "@aws-sdk/client-secrets-manager"
|
|
5
|
+
import { SSMClient, GetParameterCommand } from "@aws-sdk/client-ssm"
|
|
6
|
+
// important for dev env to load .env file
|
|
7
|
+
import * as dotenv from "dotenv"
|
|
8
|
+
dotenv.config()
|
|
9
|
+
|
|
10
|
+
// Explicity setting VM level variables in order to persist
|
|
11
|
+
// client across different important and instances.
|
|
12
|
+
// eslint-disable-next-line no-var
|
|
13
|
+
var ssmClient = null,
|
|
14
|
+
secretsClient = null
|
|
15
|
+
|
|
16
|
+
export enum EnvironmentType {
|
|
17
|
+
PlainRemote,
|
|
18
|
+
SecureRemote,
|
|
19
|
+
Local,
|
|
20
|
+
}
|
|
21
|
+
export default class EnvironmentVar<T> {
|
|
22
|
+
private readonly paramName: string
|
|
23
|
+
private readonly type: EnvironmentType
|
|
24
|
+
private readonly optional: boolean
|
|
25
|
+
private readonly paramPrefix: string
|
|
26
|
+
constructor(
|
|
27
|
+
paramName: string,
|
|
28
|
+
type: EnvironmentType,
|
|
29
|
+
optional?: boolean,
|
|
30
|
+
paramPrefix = `/creatorco-api-${process.env.STAGE}/env/` /* only allowed process.env */,
|
|
31
|
+
) {
|
|
32
|
+
this.paramName = paramName
|
|
33
|
+
this.type = type
|
|
34
|
+
this.optional = !!optional
|
|
35
|
+
this.paramPrefix = paramPrefix
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public syncResolve(): T {
|
|
39
|
+
if (this.type == EnvironmentType.Local) return this.getLocalValue()
|
|
40
|
+
else {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"EnvironmentVar syncResolve method can only be called for environments of type 'Local'",
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
public async resolve() {
|
|
47
|
+
if (this.type == EnvironmentType.Local) return this.getLocalValue()
|
|
48
|
+
else if (this.type == EnvironmentType.SecureRemote)
|
|
49
|
+
return this.getSecureValue()
|
|
50
|
+
else return this.getPlainValue()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private getLocalValue(): T {
|
|
54
|
+
const value = process.env[this.paramName]
|
|
55
|
+
if (!value && !this.optional) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Local environment ${this.paramName} is not defined, please reconfigure the application and redeploy!`,
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
return value as T
|
|
61
|
+
}
|
|
62
|
+
private async getPlainValue(): Promise<T> {
|
|
63
|
+
if (!ssmClient) ssmClient = new SSMClient()
|
|
64
|
+
const pName = `${this.paramPrefix}${this.paramName}`
|
|
65
|
+
try {
|
|
66
|
+
const data = await ssmClient.send(
|
|
67
|
+
new GetParameterCommand({ Name: pName }),
|
|
68
|
+
)
|
|
69
|
+
if (data.Parameter && data.Parameter.Value)
|
|
70
|
+
return data.Parameter.Value as T
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error(error)
|
|
73
|
+
}
|
|
74
|
+
if (!this.optional) {
|
|
75
|
+
throw new Error(`Unable to retrieve plain remote env value: ${pName}`)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
private async getSecureValue(): Promise<T> {
|
|
79
|
+
if (!secretsClient) secretsClient = new SecretsManagerClient()
|
|
80
|
+
const pName = `${this.paramPrefix}${this.paramName}`
|
|
81
|
+
try {
|
|
82
|
+
const data = await secretsClient.send(
|
|
83
|
+
new GetSecretValueCommand({ SecretId: pName }),
|
|
84
|
+
)
|
|
85
|
+
if (data.Parameter && data.Parameter.Value)
|
|
86
|
+
return data.Parameter.Value as T
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error(error)
|
|
89
|
+
}
|
|
90
|
+
if (!this.optional) {
|
|
91
|
+
throw new Error(`Unable to retrieve secure remote env: ${pName}`)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/Globals.ts
CHANGED
|
@@ -11,4 +11,19 @@ export default class Globals {
|
|
|
11
11
|
public static ErrorCode_InvalidInput = "INVALID_INPUT"
|
|
12
12
|
public static ErrorCode_APIError = "API_ERROR"
|
|
13
13
|
public static ErrorCode_NoRecords = "EMPTY_EVENT"
|
|
14
|
+
|
|
15
|
+
public static Listener_HTTP_DefaultPort = 80
|
|
16
|
+
public static Listener_HTTP_DefaultHost = "localhost"
|
|
17
|
+
public static Listener_HTTP_ProxyRoute = "*"
|
|
18
|
+
public static Listener_HTTP_DefaultTimeout = 30000
|
|
19
|
+
public static Listener_HTTP_DefaultHealthCheckRoute = "/health"
|
|
20
|
+
//Resps
|
|
21
|
+
public static Resp_MSG_EXCEPTION =
|
|
22
|
+
"[Proxy]: Exception during request execution!"
|
|
23
|
+
public static Resp_CODE_EXCEPTION = "EXEC_EXCEPTION"
|
|
24
|
+
public static Resp_STATUSCODE_EXCEPTION = 502
|
|
25
|
+
|
|
26
|
+
public static Resp_MSG_INVALIDRESP = "[Proxy]: Invalid response from server!"
|
|
27
|
+
public static Resp_CODE_INVALIDRESP = "EMPTY_RESPONSE"
|
|
28
|
+
public static Resp_STATUSCODE_INVALIDRESP = 400
|
|
14
29
|
}
|
package/src/Mailer/Mailer.ts
CHANGED
|
@@ -56,6 +56,7 @@ export default class Mailer {
|
|
|
56
56
|
console.debug("Mailer resp:", resp)
|
|
57
57
|
} catch (e) {
|
|
58
58
|
console.error("Mailer error:", e)
|
|
59
|
+
throw e
|
|
59
60
|
}
|
|
60
61
|
return resp
|
|
61
62
|
}
|
|
@@ -90,6 +91,7 @@ export default class Mailer {
|
|
|
90
91
|
console.debug("Mailer resp:", resp)
|
|
91
92
|
} catch (e) {
|
|
92
93
|
console.error("Mailer error:", e)
|
|
94
|
+
throw e
|
|
93
95
|
}
|
|
94
96
|
return resp
|
|
95
97
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
|
|
3
|
+
import ContainerServer from "./lib/ContainerServer"
|
|
4
|
+
import Server from "./lib/Server"
|
|
5
|
+
import Transaction, {
|
|
6
|
+
TransactionConfig,
|
|
7
|
+
TransactionExecution,
|
|
8
|
+
} from "../BaseEvent/Transaction"
|
|
9
|
+
|
|
10
|
+
// Route
|
|
11
|
+
export type Route<InputType = object> = {
|
|
12
|
+
path: string
|
|
13
|
+
method: string
|
|
14
|
+
handler: TransactionExecution<Transaction<InputType>>
|
|
15
|
+
inputValidation?: z.ZodObject<any>
|
|
16
|
+
outputValidation?: {
|
|
17
|
+
type: any
|
|
18
|
+
validationSchema: z.ZodObject<any>
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Config
|
|
23
|
+
export type RouterConfig = TransactionConfig & {
|
|
24
|
+
routes: Route[]
|
|
25
|
+
// container based configs - otherwise enforced by serverless engine
|
|
26
|
+
port?: number
|
|
27
|
+
timeout?: number
|
|
28
|
+
cors?: {
|
|
29
|
+
origin?: string | string[]
|
|
30
|
+
headers?: string[]
|
|
31
|
+
allowCredentials?: boolean
|
|
32
|
+
}
|
|
33
|
+
healthCheckRoute?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default class Router {
|
|
37
|
+
private readonly config: RouterConfig
|
|
38
|
+
private readonly server: Server
|
|
39
|
+
constructor(config: RouterConfig) {
|
|
40
|
+
this.config = config
|
|
41
|
+
this.server = this.isContainer()
|
|
42
|
+
? new ContainerServer(config)
|
|
43
|
+
: new Server(config)
|
|
44
|
+
}
|
|
45
|
+
public getExport(): CallableFunction {
|
|
46
|
+
return this.server.getExport()
|
|
47
|
+
}
|
|
48
|
+
private isContainer(): boolean {
|
|
49
|
+
return true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Proxy from "./container/Proxy"
|
|
2
|
+
import Server from "./Server"
|
|
3
|
+
import { RouterConfig } from "../Router"
|
|
4
|
+
|
|
5
|
+
export default class ContainerServer extends Server {
|
|
6
|
+
protected readonly proxy: Proxy
|
|
7
|
+
constructor(config: RouterConfig) {
|
|
8
|
+
super(config)
|
|
9
|
+
this.proxy = new Proxy(config, this.handleServerlessEvent.bind(this))
|
|
10
|
+
this.listenProcessEvents()
|
|
11
|
+
}
|
|
12
|
+
public getExport(): CallableFunction {
|
|
13
|
+
return this.start
|
|
14
|
+
}
|
|
15
|
+
/* private */
|
|
16
|
+
public async start() {
|
|
17
|
+
await this.proxy.load()
|
|
18
|
+
}
|
|
19
|
+
public async stop(err) {
|
|
20
|
+
await this.proxy.unload(err)
|
|
21
|
+
}
|
|
22
|
+
private listenProcessEvents() {
|
|
23
|
+
// start process listeners
|
|
24
|
+
process.on("unhandledRejection", this.stop.bind(this)) // listen to exceptions
|
|
25
|
+
process.on("SIGINT", this.stop.bind(this)) // listen on SIGINT signal and gracefully stop the server
|
|
26
|
+
}
|
|
27
|
+
}
|