@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.
Files changed (75) hide show
  1. package/.eslintrc.cjs +22 -22
  2. package/dist/index.d.ts +2 -1
  3. package/dist/index.js +3 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/package.json +48 -0
  6. package/dist/src/API/Request.d.ts +4 -5
  7. package/dist/src/API/Request.js +3 -4
  8. package/dist/src/API/Request.js.map +1 -1
  9. package/dist/src/API/Response.d.ts +1 -1
  10. package/dist/src/API/Response.js.map +1 -1
  11. package/dist/src/BaseEvent/EventProcessor.js +0 -1
  12. package/dist/src/BaseEvent/EventProcessor.js.map +1 -1
  13. package/dist/src/BaseEvent/Process.d.ts +0 -1
  14. package/dist/src/BaseEvent/Process.js +1 -2
  15. package/dist/src/BaseEvent/Process.js.map +1 -1
  16. package/dist/src/BaseEvent/Transaction.d.ts +6 -6
  17. package/dist/src/BaseEvent/Transaction.js +2 -4
  18. package/dist/src/BaseEvent/Transaction.js.map +1 -1
  19. package/dist/src/Config/EnvironmentVar.d.ts +17 -0
  20. package/dist/src/Config/EnvironmentVar.js +155 -0
  21. package/dist/src/Config/EnvironmentVar.js.map +1 -0
  22. package/dist/src/Globals.d.ts +11 -0
  23. package/dist/src/Globals.js +12 -0
  24. package/dist/src/Globals.js.map +1 -1
  25. package/dist/src/Logger/Logger.js +42 -11
  26. package/dist/src/Logger/Logger.js.map +1 -1
  27. package/dist/src/Mailer/Mailer.js +52 -26
  28. package/dist/src/Mailer/Mailer.js.map +1 -1
  29. package/dist/src/Server/Router.d.ts +30 -0
  30. package/dist/src/Server/Router.js +21 -0
  31. package/dist/src/Server/Router.js.map +1 -0
  32. package/dist/src/Server/lib/ContainerServer.d.ts +11 -0
  33. package/dist/src/Server/lib/ContainerServer.js +100 -0
  34. package/dist/src/Server/lib/ContainerServer.js.map +1 -0
  35. package/dist/src/Server/lib/Server.d.ts +9 -0
  36. package/dist/src/Server/lib/Server.js +137 -0
  37. package/dist/src/Server/lib/Server.js.map +1 -0
  38. package/dist/src/Server/lib/container/GenericHandler.d.ts +4 -0
  39. package/dist/src/Server/lib/container/GenericHandler.js +138 -0
  40. package/dist/src/Server/lib/container/GenericHandler.js.map +1 -0
  41. package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +14 -0
  42. package/dist/src/Server/lib/container/GenericHandlerEvent.js +164 -0
  43. package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +1 -0
  44. package/dist/src/Server/lib/container/HealthHandler.d.ts +3 -0
  45. package/dist/src/Server/lib/container/HealthHandler.js +44 -0
  46. package/dist/src/Server/lib/container/HealthHandler.js.map +1 -0
  47. package/dist/src/Server/lib/container/Proxy.d.ts +15 -0
  48. package/dist/src/Server/lib/container/Proxy.js +153 -0
  49. package/dist/src/Server/lib/container/Proxy.js.map +1 -0
  50. package/dist/src/Server/lib/container/Utils.d.ts +6 -0
  51. package/dist/src/Server/lib/container/Utils.js +109 -0
  52. package/dist/src/Server/lib/container/Utils.js.map +1 -0
  53. package/dist/src/Validation/Validator.d.ts +5 -0
  54. package/dist/src/Validation/Validator.js +39 -0
  55. package/dist/src/Validation/Validator.js.map +1 -0
  56. package/index.ts +2 -0
  57. package/package.json +12 -3
  58. package/src/API/Request.ts +6 -12
  59. package/src/API/Response.ts +1 -1
  60. package/src/BaseEvent/EventProcessor.ts +3 -2
  61. package/src/BaseEvent/Process.ts +4 -4
  62. package/src/BaseEvent/Transaction.ts +24 -16
  63. package/src/Config/EnvironmentVar.ts +94 -0
  64. package/src/Globals.ts +15 -0
  65. package/src/Mailer/Mailer.ts +2 -0
  66. package/src/Server/Router.ts +51 -0
  67. package/src/Server/lib/ContainerServer.ts +27 -0
  68. package/src/Server/lib/Server.ts +66 -0
  69. package/src/Server/lib/container/GenericHandler.ts +63 -0
  70. package/src/Server/lib/container/GenericHandlerEvent.ts +133 -0
  71. package/src/Server/lib/container/HealthHandler.ts +5 -0
  72. package/src/Server/lib/container/Proxy.ts +107 -0
  73. package/src/Server/lib/container/Utils.ts +45 -0
  74. package/src/Validation/Validator.ts +35 -0
  75. 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,5 @@
1
+ import { z } from "zod";
2
+ import Response from "../API/Response";
3
+ export default class Validator {
4
+ static validateSchema(data: any, schema: z.ZodObject<any>): boolean | Response;
5
+ }
@@ -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.1.7",
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",
@@ -1,22 +1,16 @@
1
1
  import type { Context, APIGatewayEvent } from "aws-lambda"
2
2
 
3
3
  import Utils from "./Utils"
4
- import Transaction from "../BaseEvent/Transaction"
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
- private transaction: Transaction
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
- this.transaction.logger.debug("Request info:", JSON.stringify(requestEvent))
19
- this.transaction.logger.debug("Request context:", JSON.stringify(context))
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(): object | null {
52
+ public getBody(): T | null {
59
53
  let b: any = null
60
54
  try {
61
55
  b = this.requestEvent.body
@@ -63,7 +63,7 @@ export default class Response {
63
63
  }
64
64
  public async build(
65
65
  context: Context,
66
- transaction: Transaction,
66
+ transaction: Transaction<any>,
67
67
  _optDoNotCallContext: boolean,
68
68
  ): Promise<void> {
69
69
  //Stream support
@@ -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
@@ -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 request code. Rolling back DB!",
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
- import type { Context, SQSBatchResponse } from "aws-lambda"
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
- //Request
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(event, context: Context, config?: TransactionConfig) {
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
- //When set, this will be called with the response context right before calling the context suceed/fail - useful for writing the resp for example.
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
  }
@@ -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
+ }