@nathapp/na-cli 1.0.0-rc.4 → 1.0.0-rc.41

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 (252) hide show
  1. package/.gitlab-ci.yml +135 -0
  2. package/Makefile +16 -9
  3. package/README.md +18 -2
  4. package/alias-script.sh +30 -0
  5. package/dist/index.js +106 -128
  6. package/dist/index.js.map +1 -1
  7. package/dist/templates/db-schema/.gitignore-rename +1 -0
  8. package/dist/templates/db-schema/.gitlab-ci.yml +139 -0
  9. package/dist/templates/db-schema/001_Schema.sql +1 -0
  10. package/dist/templates/db-schema/DEV_MODE.txt +1 -0
  11. package/dist/templates/db-schema/Dockerfile +3 -0
  12. package/dist/templates/db-schema/Email-Templates/Individual/README.md +1 -0
  13. package/dist/templates/db-schema/GET_VERSION.sql +47 -0
  14. package/dist/templates/db-schema/Makefile +885 -0
  15. package/dist/templates/db-schema/README.md +117 -0
  16. package/dist/templates/db-schema/SET_VERSION.sql +5 -0
  17. package/dist/templates/db-schema/docker-compose.yaml +47 -0
  18. package/dist/templates/db-schema/package.json +3 -0
  19. package/dist/templates/db-schema/push.sh +0 -0
  20. package/dist/templates/db-schema/samples/899_DB_Grant_User.sql +9 -0
  21. package/dist/templates/db-schema/samples/990_SAMPLE_Init_Data.sql +27 -0
  22. package/dist/templates/k8s-deployment/.gitignore-rename +1 -0
  23. package/dist/templates/k8s-deployment/.gitlab-ci.yml +128 -0
  24. package/dist/templates/k8s-deployment/.helmignore +23 -0
  25. package/dist/templates/k8s-deployment/Chart.yaml +23 -0
  26. package/dist/templates/k8s-deployment/Makefile +196 -0
  27. package/dist/templates/k8s-deployment/README.md +32 -0
  28. package/dist/templates/k8s-deployment/resources/charts/mysql/Chart.yaml +23 -0
  29. package/dist/templates/k8s-deployment/resources/charts/mysql/charts/mysql-install/Chart.yaml +23 -0
  30. package/dist/templates/k8s-deployment/resources/charts/mysql/charts/mysql-install/script/Makefile +12 -0
  31. package/dist/templates/k8s-deployment/resources/charts/mysql/charts/mysql-install/templates/_helpers.tpl +62 -0
  32. package/dist/templates/k8s-deployment/resources/charts/mysql/charts/mysql-install/templates/configmap.yaml +1 -0
  33. package/dist/templates/k8s-deployment/resources/charts/mysql/charts/mysql-install/templates/job.yaml +1 -0
  34. package/dist/templates/k8s-deployment/resources/charts/mysql/charts/mysql-install/templates/secret.yaml +1 -0
  35. package/dist/templates/k8s-deployment/resources/charts/mysql/charts/mysql-install/values.yaml +51 -0
  36. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/_helpers.tpl +62 -0
  37. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/configmap.yaml +1 -0
  38. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/deployment.yaml +1 -0
  39. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/ingress.yaml +1 -0
  40. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/job.yaml +1 -0
  41. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/pv.yaml +1 -0
  42. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/pvc.yaml +1 -0
  43. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/sc.yaml +1 -0
  44. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/secret.yaml +1 -0
  45. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/service.yaml +1 -0
  46. package/dist/templates/k8s-deployment/resources/charts/mysql/templates/statefulset.yaml +1 -0
  47. package/dist/templates/k8s-deployment/resources/charts/mysql/values.yaml +15 -0
  48. package/dist/templates/k8s-deployment/resources/charts/redis/Chart.yaml +23 -0
  49. package/dist/templates/k8s-deployment/resources/charts/redis/charts/redis-install/Chart.yaml +23 -0
  50. package/dist/templates/k8s-deployment/resources/charts/redis/charts/redis-install/script/Makefile +8 -0
  51. package/dist/templates/k8s-deployment/resources/charts/redis/charts/redis-install/templates/_helpers.tpl +62 -0
  52. package/dist/templates/k8s-deployment/resources/charts/redis/charts/redis-install/templates/configmap.yaml +1 -0
  53. package/dist/templates/k8s-deployment/resources/charts/redis/charts/redis-install/templates/job.yaml +1 -0
  54. package/dist/templates/k8s-deployment/resources/charts/redis/charts/redis-install/templates/secret.yaml +1 -0
  55. package/dist/templates/k8s-deployment/resources/charts/redis/charts/redis-install/values.yaml +42 -0
  56. package/dist/templates/k8s-deployment/resources/charts/redis/templates/_helpers.tpl +62 -0
  57. package/dist/templates/k8s-deployment/resources/charts/redis/templates/configmap.yaml +1 -0
  58. package/dist/templates/k8s-deployment/resources/charts/redis/templates/deployment.yaml +1 -0
  59. package/dist/templates/k8s-deployment/resources/charts/redis/templates/ingress.yaml +1 -0
  60. package/dist/templates/k8s-deployment/resources/charts/redis/templates/job.yaml +1 -0
  61. package/dist/templates/k8s-deployment/resources/charts/redis/templates/pv.yaml +1 -0
  62. package/dist/templates/k8s-deployment/resources/charts/redis/templates/pvc.yaml +1 -0
  63. package/dist/templates/k8s-deployment/resources/charts/redis/templates/sc.yaml +1 -0
  64. package/dist/templates/k8s-deployment/resources/charts/redis/templates/secret.yaml +1 -0
  65. package/dist/templates/k8s-deployment/resources/charts/redis/templates/service.yaml +1 -0
  66. package/dist/templates/k8s-deployment/resources/charts/redis/templates/statefulset.yaml +1 -0
  67. package/dist/templates/k8s-deployment/resources/charts/redis/values.yaml +12 -0
  68. package/dist/templates/k8s-deployment/services/charts/hooks/Chart.yaml +23 -0
  69. package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/Chart.yaml +23 -0
  70. package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/script/Makefile +49 -0
  71. package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/script/_env.yaml +2 -0
  72. package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/templates/_helpers.tpl +62 -0
  73. package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/templates/configmap.yaml +1 -0
  74. package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/templates/job.yaml +1 -0
  75. package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/templates/secret.yaml +1 -0
  76. package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/values.yaml +36 -0
  77. package/dist/templates/k8s-deployment/services/charts/sample-nginx/Chart.yaml +23 -0
  78. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/_helpers.tpl +62 -0
  79. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/cluster-role-binding.yaml +1 -0
  80. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/configmap.yaml +1 -0
  81. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/cronjob.yaml +1 -0
  82. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/deployment.yaml +1 -0
  83. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/ingress.yaml +1 -0
  84. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/pv.yaml +1 -0
  85. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/pvc.yaml +1 -0
  86. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/sc.yaml +1 -0
  87. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/secret.yaml +1 -0
  88. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/service-account.yaml +1 -0
  89. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/service.yaml +1 -0
  90. package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/statefulset.yaml +1 -0
  91. package/dist/templates/k8s-deployment/services/charts/sample-nginx/values.yaml +47 -0
  92. package/dist/templates/k8s-deployment/services/charts/tests/Chart.yaml +23 -0
  93. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/Chart.yaml +23 -0
  94. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/Makefile +9 -0
  95. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/fixtures/index.json +1 -0
  96. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/integration/login/login-spec.js +47 -0
  97. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/integration/login/loginEmailWrong-spec.js +14 -0
  98. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/integration/login/loginPasswordWrong-spec.js +14 -0
  99. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/integration/profile/updatePassword-spec.js +15 -0
  100. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/integration/profile/updateProfile-spec.js +25 -0
  101. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/integration/test-script.spec.js +9 -0
  102. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/plugins/index.js +22 -0
  103. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/support/commands.js +258 -0
  104. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/support/index.js +35 -0
  105. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress/support/misc.js +8 -0
  106. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/cypress.json +4 -0
  107. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/templates/_helpers.tpl +62 -0
  108. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/templates/configmap.yaml +1 -0
  109. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/templates/pod.yaml +1 -0
  110. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/templates/secret.yaml +1 -0
  111. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/values.yaml +70 -0
  112. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/.helmignore +2 -0
  113. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/Chart.yaml +23 -0
  114. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/script/Makefile +14 -0
  115. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/templates/_helpers.tpl +62 -0
  116. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/templates/configmap.yaml +1 -0
  117. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/templates/pod.yaml +1 -0
  118. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/templates/secret.yaml +1 -0
  119. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/_t-0100-readiness-liveness.ts +84 -0
  120. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/hub.ts +372 -0
  121. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-contact.ts +158 -0
  122. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-contract.ts +328 -0
  123. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-kyc.ts +304 -0
  124. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-onboard-app.ts +823 -0
  125. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-onboard-web.ts +493 -0
  126. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-profile.ts +277 -0
  127. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-whitelist.ts +133 -0
  128. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/resources/live.jpg +0 -0
  129. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/resources/mykad_front.jpg +0 -0
  130. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/resources/profile.jpg +0 -0
  131. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/t-0200-start.ts +172 -0
  132. package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/values.yaml +59 -0
  133. package/dist/templates/k8s-deployment/templates/_cluster-role-binding.tpl +20 -0
  134. package/dist/templates/k8s-deployment/templates/_configmap.tpl +37 -0
  135. package/dist/templates/k8s-deployment/templates/_cronjob.tpl +225 -0
  136. package/dist/templates/k8s-deployment/templates/_deployment.tpl +246 -0
  137. package/dist/templates/k8s-deployment/templates/_helpers.tpl +31 -0
  138. package/dist/templates/k8s-deployment/templates/_ingress.tpl +77 -0
  139. package/dist/templates/k8s-deployment/templates/_job.tpl +233 -0
  140. package/dist/templates/k8s-deployment/templates/_pod.tpl +214 -0
  141. package/dist/templates/k8s-deployment/templates/_pv.tpl +42 -0
  142. package/dist/templates/k8s-deployment/templates/_pvc.tpl +27 -0
  143. package/dist/templates/k8s-deployment/templates/_root.tpl +314 -0
  144. package/dist/templates/k8s-deployment/templates/_sc.tpl +19 -0
  145. package/dist/templates/k8s-deployment/templates/_secret.tpl +15 -0
  146. package/dist/templates/k8s-deployment/templates/_service-account.tpl +8 -0
  147. package/dist/templates/k8s-deployment/templates/_service.tpl +40 -0
  148. package/dist/templates/k8s-deployment/templates/_statefulset.tpl +244 -0
  149. package/dist/templates/k8s-deployment/templates/root-cm.yaml +10 -0
  150. package/dist/templates/k8s-deployment/templates/root-pull-secret.yaml +11 -0
  151. package/dist/templates/k8s-deployment/templates/root-secret.yaml +24 -0
  152. package/dist/templates/k8s-deployment/values.yaml +38 -0
  153. package/dist/templates/k8s-helm-chart/Chart.yaml +23 -0
  154. package/dist/templates/k8s-helm-chart/templates/_helpers.tpl +62 -0
  155. package/dist/templates/k8s-helm-chart/templates/cluster-role-binding.yaml +1 -0
  156. package/dist/templates/k8s-helm-chart/templates/configmap.yaml +1 -0
  157. package/dist/templates/k8s-helm-chart/templates/cronjob.yaml +1 -0
  158. package/dist/templates/k8s-helm-chart/templates/deployment.yaml +1 -0
  159. package/dist/templates/k8s-helm-chart/templates/ingress.yaml +1 -0
  160. package/dist/templates/k8s-helm-chart/templates/pv.yaml +1 -0
  161. package/dist/templates/k8s-helm-chart/templates/pvc.yaml +1 -0
  162. package/dist/templates/k8s-helm-chart/templates/sc.yaml +1 -0
  163. package/dist/templates/k8s-helm-chart/templates/secret.yaml +1 -0
  164. package/dist/templates/k8s-helm-chart/templates/service-account.yaml +1 -0
  165. package/dist/templates/k8s-helm-chart/templates/service.yaml +1 -0
  166. package/dist/templates/k8s-helm-chart/templates/statefulset.yaml +1 -0
  167. package/dist/templates/k8s-helm-chart/values.yaml +41 -0
  168. package/dist/templates/mxw-base-api-express/.dockerignore +2 -0
  169. package/dist/templates/mxw-base-api-express/.env +10 -0
  170. package/dist/templates/mxw-base-api-express/.gitignore-rename +3 -0
  171. package/dist/templates/mxw-base-api-express/.gitlab-ci.yml +174 -0
  172. package/dist/templates/mxw-base-api-express/.nvmrc +1 -0
  173. package/dist/templates/mxw-base-api-express/Dockerfile +14 -0
  174. package/dist/templates/mxw-base-api-express/Makefile +84 -0
  175. package/dist/templates/mxw-base-api-express/README.md +71 -0
  176. package/dist/templates/mxw-base-api-express/package.json +55 -0
  177. package/dist/templates/mxw-base-api-express/src/app-service.test.ts +94 -0
  178. package/dist/templates/mxw-base-api-express/src/app-service.ts +498 -0
  179. package/dist/templates/mxw-base-api-express/src/auth/auth-user.test.ts +215 -0
  180. package/dist/templates/mxw-base-api-express/src/auth/auth-user.ts +86 -0
  181. package/dist/templates/mxw-base-api-express/src/auth/auth.ts +81 -0
  182. package/dist/templates/mxw-base-api-express/src/core-service.ts +72 -0
  183. package/dist/templates/mxw-base-api-express/src/crud.ts +84 -0
  184. package/dist/templates/mxw-base-api-express/src/http-handler.ts +71 -0
  185. package/dist/templates/mxw-base-api-express/src/server.ts +54 -0
  186. package/dist/templates/mxw-base-api-express/src/test.ts +38 -0
  187. package/dist/templates/mxw-base-api-express/src/utils/api-utilities.ts +52 -0
  188. package/dist/templates/mxw-base-api-express/src/utils/file-utilities.ts +55 -0
  189. package/dist/templates/mxw-base-api-express/tsconfig.json +32 -0
  190. package/dist/templates/nestjs-api/.dockerignore +2 -0
  191. package/dist/templates/nestjs-api/.env +12 -0
  192. package/dist/templates/nestjs-api/.eslintrc.js +25 -0
  193. package/dist/templates/nestjs-api/.gitignore-rename +35 -0
  194. package/dist/templates/nestjs-api/.gitlab-ci.yml +174 -0
  195. package/dist/templates/nestjs-api/.nvmrc +1 -0
  196. package/dist/templates/nestjs-api/.prettierrc +4 -0
  197. package/dist/templates/nestjs-api/Dockerfile +19 -0
  198. package/dist/templates/nestjs-api/Makefile +84 -0
  199. package/dist/templates/nestjs-api/README.md +67 -0
  200. package/dist/templates/nestjs-api/nest-cli.json +8 -0
  201. package/dist/templates/nestjs-api/package.json +75 -0
  202. package/dist/templates/nestjs-api/src/app.controller.spec.ts +22 -0
  203. package/dist/templates/nestjs-api/src/app.controller.ts +27 -0
  204. package/dist/templates/nestjs-api/src/app.module.ts +10 -0
  205. package/dist/templates/nestjs-api/src/app.service.ts +12 -0
  206. package/dist/templates/nestjs-api/src/main.ts +31 -0
  207. package/dist/templates/nestjs-api/test/app.e2e-spec.ts +24 -0
  208. package/dist/templates/nestjs-api/test/jest-e2e.json +9 -0
  209. package/dist/templates/nestjs-api/tsconfig.build.json +4 -0
  210. package/dist/templates/nestjs-api/tsconfig.json +22 -0
  211. package/dist/templates/nestjs-library/.eslintrc.js +24 -0
  212. package/dist/templates/nestjs-library/.gitignore-rename +39 -0
  213. package/dist/templates/nestjs-library/.gitlab-ci.yml +135 -0
  214. package/dist/templates/nestjs-library/.npmignore-rename +30 -0
  215. package/dist/templates/nestjs-library/.prettierrc +6 -0
  216. package/dist/templates/nestjs-library/LICENSE +21 -0
  217. package/dist/templates/nestjs-library/Makefile +60 -0
  218. package/dist/templates/nestjs-library/README.md +3 -0
  219. package/dist/templates/nestjs-library/index.d.ts +1 -0
  220. package/dist/templates/nestjs-library/index.js +6 -0
  221. package/dist/templates/nestjs-library/index.ts +1 -0
  222. package/dist/templates/nestjs-library/lib/index.ts +2 -0
  223. package/dist/templates/nestjs-library/package.json +41 -0
  224. package/dist/templates/nestjs-library/tsconfig.build.json +4 -0
  225. package/dist/templates/nestjs-library/tsconfig.json +18 -0
  226. package/dist/templates/ts-library/.dockerignore +2 -0
  227. package/dist/templates/ts-library/.eslintrc.js +24 -0
  228. package/dist/templates/ts-library/.gitignore-rename +37 -0
  229. package/dist/templates/ts-library/.gitlab-ci.yml +135 -0
  230. package/dist/templates/ts-library/.npmignore-rename +30 -0
  231. package/dist/templates/ts-library/.prettierrc +6 -0
  232. package/dist/templates/ts-library/LICENSE +21 -0
  233. package/dist/templates/ts-library/Makefile +58 -0
  234. package/dist/templates/ts-library/README.md +1 -0
  235. package/dist/templates/ts-library/index.d.ts +1 -0
  236. package/dist/templates/ts-library/index.js +6 -0
  237. package/dist/templates/ts-library/index.ts +1 -0
  238. package/dist/templates/ts-library/lib/index.ts +1 -0
  239. package/dist/templates/ts-library/lib/samples/index.ts +5 -0
  240. package/dist/templates/ts-library/lib/samples/samples-function.ts +3 -0
  241. package/dist/templates/ts-library/package.json +34 -0
  242. package/dist/templates/ts-library/test/jest-e2e.json +9 -0
  243. package/dist/templates/ts-library/test/sample.e2e-spec.ts +10 -0
  244. package/dist/templates/ts-library/tsconfig.build.json +4 -0
  245. package/dist/templates/ts-library/tsconfig.json +18 -0
  246. package/dist/utils/env.js +146 -0
  247. package/dist/utils/env.js.map +1 -0
  248. package/dist/utils/template.js +362 -1
  249. package/dist/utils/template.js.map +1 -1
  250. package/package.json +9 -5
  251. package/src/index.ts +0 -182
  252. package/src/utils/template.ts +0 -9
@@ -0,0 +1,94 @@
1
+ 'use strict';
2
+
3
+ import { describe, it, beforeEach, afterEach } from 'mocha';
4
+ import { expect } from 'chai';
5
+ import Sinon from "sinon";
6
+ import AppService from './app-service';
7
+
8
+ let sandbox: Sinon.SinonSandbox;
9
+
10
+ describe('Suite: Endpoint - App Service', () => {
11
+ beforeEach(() => {
12
+ sandbox = Sinon.createSandbox();
13
+ });
14
+
15
+ afterEach(() => {
16
+ if (sandbox) {
17
+ sandbox.restore();
18
+ sandbox = undefined;
19
+ }
20
+ });
21
+
22
+ describe("Initialization", async () => {
23
+ it("Initialize service", async () => {
24
+ sandbox.stub(process, "env").get(() => {
25
+ return {
26
+ JWT_SECRET: "secret",
27
+
28
+ SERVICE_DOMAIN: "default",
29
+ SERVICE_SESSION_TIMEOUT: 6000,
30
+ SERVICE_WALLET_JSON: "hello",
31
+ SERVICE_WALLET_PASSWORD: "world",
32
+
33
+ MYSQL_URL: "hello mysql",
34
+
35
+ CACHE_DIR: null,
36
+ MAX_FILE_SIZE: null,
37
+
38
+ MAX_REQUEST: 100
39
+ };
40
+ });
41
+
42
+ const instance = await AppService.init();
43
+
44
+ expect(instance).is.instanceOf(AppService);
45
+ expect(AppService.Instance).is.instanceOf(AppService);
46
+ });
47
+ });
48
+
49
+ describe("GET /readiness", async () => {
50
+ it("Service is ready", async () => {
51
+ const req: any = {
52
+ query: {}
53
+ };
54
+ const res: any = {
55
+ json: () => { }
56
+ };
57
+
58
+ const stubRes = sandbox.stub(res, "json").callsFake((body: any) => {
59
+ // console.log(JSON.stringify(body, null, 2));
60
+ expect(body).is.undefined;
61
+ });
62
+
63
+ await AppService.Instance["onReadiness"](req, res);
64
+
65
+ Sinon.assert.calledOnce(stubRes);
66
+ });
67
+ });
68
+
69
+ describe("GET /liveness", async () => {
70
+ it("Service is alive", async () => {
71
+ const req: any = {
72
+ query: {}
73
+ };
74
+ const res: any = {
75
+ json: () => { }
76
+ };
77
+
78
+ const stubRes = sandbox.stub(res, "json").callsFake((body: any) => {
79
+ // console.log(JSON.stringify(body, null, 2));
80
+ expect(body).is.undefined;
81
+ });
82
+
83
+ await AppService.Instance["onLiveness"](req, res);
84
+
85
+ Sinon.assert.calledOnce(stubRes);
86
+ });
87
+ });
88
+
89
+ describe("Termination", async () => {
90
+ it("Terminate service", async () => {
91
+ await AppService.term();
92
+ });
93
+ });
94
+ });
@@ -0,0 +1,498 @@
1
+ "use strict";
2
+
3
+ import { Server } from "http";
4
+ import express, { Express, Router, Request, Response, NextFunction, RequestHandler } from "express";
5
+ import cors from "cors";
6
+ import bodyParser from "body-parser";
7
+ import responseTime from "response-time";
8
+ import multer from "multer";
9
+
10
+ import { finalHandler, errorHandler } from "./http-handler";
11
+ import { allowNullOrEmpty, checkFormat, checkPositiveNumber, checkString, isUndefinedOrNull, isUndefinedOrNullOrEmpty, notAllowNullOrEmpty } from "mxw-libs-utils";
12
+ import { clog, levels } from "mxw-libs-clogger";
13
+ import { createError, describeError, errors, throwError } from "mxw-libs-errors";
14
+ import { ApiService } from "mxw-libs-api-token";
15
+ import { Mysql as DB } from "mxw-libs-database";
16
+ import { EmailAgent, EmailServiceEnvironment } from "mxw-libs-email-notify";
17
+ import AuthUser, { CREDENTIAL_TYPE } from "./auth/auth-user";
18
+
19
+
20
+ const { name, version } = require("../package.json");
21
+
22
+ const DEFAULT_FILE_CACHE_DIR = "/tmp"; // Default received file cache directory
23
+ const DEFAULT_MAX_FILE_SIZE = 20000 * (1000 * 1024); // Default to 20MB of max file size
24
+
25
+ enum AuthType {
26
+ API = "API",
27
+ NIL = "NIL",
28
+ JWT = "JWT",
29
+ JWT_GUEST = "JWT_GUEST",
30
+ JWT_USER = "JWT_USER",
31
+ }
32
+
33
+ enum ContentType {
34
+ JSON = "JSON",
35
+ RAW = "RAW",
36
+ FILE = "FILE",
37
+ }
38
+
39
+ enum HttpMethod {
40
+ GET = "GET",
41
+ POST = "POST",
42
+ PATCH = "PATCH",
43
+ PUT = "PUT",
44
+ DELETE = "DELETE",
45
+ HEAD = "HEAD",
46
+ OPTIONS = "OPTIONS",
47
+ }
48
+
49
+ type CallFunc = (req: Request, res: Response) => Promise<void>;
50
+
51
+ export function goodRes(res: Response, data?: any, statusCode?: number) {
52
+ const resp = {
53
+ ret: "0"
54
+ }
55
+ if (!isUndefinedOrNull(data)) {
56
+ delete data.ret;
57
+ resp["data"] = data;
58
+ }
59
+
60
+ if (!isUndefinedOrNull(statusCode)) {
61
+ res.status(statusCode).json(resp);
62
+ }
63
+ else {
64
+ res.json(resp);
65
+ }
66
+ }
67
+
68
+ export function errorRes(res: Response, ret: number | string, message: string, data?: any, statusCode?: number) {
69
+ const resp = {
70
+ ret,
71
+ msg: message,
72
+ }
73
+
74
+ if (!isUndefinedOrNull(data)) {
75
+ delete data.ret;
76
+ delete data.msg;
77
+ if (!isUndefinedOrNull(data)) {
78
+ resp["data"] = data;
79
+ }
80
+ }
81
+
82
+ if (!isUndefinedOrNull(statusCode)) {
83
+ res.status(statusCode).json(resp);
84
+ } else {
85
+ res.json(resp)
86
+ }
87
+ }
88
+
89
+ export default class AppService {
90
+ private static self: AppService;
91
+
92
+ private app: Express;
93
+ private listener: Server;
94
+
95
+ private whitelist: { [walletAddress: string]: boolean } = {};
96
+
97
+ public config: {
98
+ JWT_SECRET: string;
99
+
100
+ SERVICE_DOMAIN: string;
101
+ SERVICE_SESSION_TIMEOUT?: number;
102
+ SERVICE_WALLET_JSON: string;
103
+ SERVICE_WALLET_PASSWORD: string;
104
+
105
+ MYSQL_URL: string;
106
+
107
+ CACHE_DIR?: string;
108
+ MAX_FILE_SIZE?: number;
109
+ };
110
+
111
+ private mailConfig: EmailServiceEnvironment;
112
+
113
+ public static get Instance() {
114
+ return this.self || throwError(errors.NOT_INITIALIZED, "AppService initialization is required");
115
+ }
116
+
117
+ private async onLiveness(req: Request, res: Response) {
118
+ res.json();
119
+ }
120
+
121
+ public async onReadiness(req: Request, res: Response) {
122
+ res.json();
123
+ }
124
+
125
+ private async onRoot(req: Request, res: Response) {
126
+ res.json({
127
+ message: `Welcome to the coolest API on earth - ${name}:${version}!`
128
+ });
129
+ }
130
+
131
+ public static async init() {
132
+ const self = new this();
133
+
134
+ try {
135
+ const checkPathString = function (value) {
136
+ let v: string = checkString(value);
137
+ if (!v.endsWith("/")) {
138
+ v = v + "/";
139
+ }
140
+ return v;
141
+ }
142
+
143
+ self.config = checkFormat({
144
+ JWT_SECRET: notAllowNullOrEmpty(checkString),
145
+
146
+ SERVICE_DOMAIN: notAllowNullOrEmpty(checkString),
147
+ SERVICE_SESSION_TIMEOUT: allowNullOrEmpty(checkPositiveNumber, 60000),
148
+ SERVICE_WALLET_JSON: notAllowNullOrEmpty(checkString),
149
+ SERVICE_WALLET_PASSWORD: notAllowNullOrEmpty(checkString),
150
+
151
+ MYSQL_URL: notAllowNullOrEmpty(checkString),
152
+
153
+ CACHE_DIR: allowNullOrEmpty(checkPathString),
154
+ MAX_FILE_SIZE: allowNullOrEmpty(checkPositiveNumber)
155
+ }, {
156
+ JWT_SECRET: process.env.JWT_SECRET,
157
+
158
+ SERVICE_DOMAIN: process.env.SERVICE_DOMAIN,
159
+ SERVICE_SESSION_TIMEOUT: process.env.SERVICE_SESSION_TIMEOUT,
160
+ SERVICE_WALLET_JSON: process.env.SERVICE_WALLET_JSON,
161
+ SERVICE_WALLET_PASSWORD: process.env.SERVICE_WALLET_PASSWORD,
162
+
163
+ MYSQL_URL: process.env.MYSQL_URL,
164
+
165
+ CACHE_DIR: process.env.CACHE_DIR,
166
+ MAX_FILE_SIZE: process.env.MAX_FILE_SIZE,
167
+ });
168
+ /*
169
+ // Set email agent settings
170
+ self.mailConfig = {
171
+ domain: process.env.EMAIL_NOTIFY_DOMAIN,
172
+ url: process.env.EMAIL_NOTIFY_URL,
173
+ requestTimeout: process.env.EMAIL_NOTIFY_REQUEST_TIMEOUT ? Number(process.env.EMAIL_NOTIFY_REQUEST_TIMEOUT) : 10000,
174
+ wallet: process.env.EMAIL_NOTIFY_WALLET_JSON,
175
+ password: process.env.EMAIL_NOTIFY_WALLET_PASSWORD
176
+ }
177
+ */
178
+ }
179
+ catch (error) {
180
+ const { message } = describeError(error);
181
+ throwError(errors.NOT_CONFIGURED, "Environment: " + message, { error });
182
+ }
183
+
184
+ if (process.env.WHITELIST) {
185
+ if ("*" === process.env.WHITELIST) {
186
+ self.whitelist["*"] = true;
187
+ }
188
+ else {
189
+ for (const walletAddress of process.env.WHITELIST.split(",")) {
190
+ self.whitelist[walletAddress.trim()] = true;
191
+ }
192
+ }
193
+ }
194
+
195
+ // Initialize server
196
+ self.app = express();
197
+
198
+ self.app.set("x-powered-by", false);
199
+
200
+ const origins: string[] | string =
201
+ !isUndefinedOrNullOrEmpty(process.env.CORS)
202
+ ? process.env.CORS == "*"
203
+ ? "*"
204
+ : process.env.CORS.split(",")
205
+ : "*";
206
+
207
+ const corsOptions = {
208
+ origin: origins,
209
+ allowedHeaders: "Origin,X-Requested-With,Content-Type,Accept,Lang,Authorization,Accept-Version,Content-Language,app-id,Location",
210
+ exposedHeaders: "X-Requested-With,X-Metadata",
211
+ preflightContinue: false
212
+ };
213
+
214
+ self.app.use(cors(corsOptions));
215
+
216
+ self.app.use(bodyParser.json({
217
+ limit: 20 * 1024 * 1024, // default to 1MB of max body size
218
+ }));
219
+
220
+ self.app.use(responseTime((req: Request, res: Response, time: number) => {
221
+ res["elapsed"] = time.toFixed(3);
222
+ }));
223
+
224
+ this.self = self;
225
+
226
+ return self;
227
+ }
228
+
229
+ public static async term() {
230
+ if (this.self) {
231
+ if (this.self.listener) {
232
+ await new Promise<void>((resolve, reject) => {
233
+ try {
234
+ this.self.listener.close((error) => {
235
+ if (error) return reject(error);
236
+ return resolve();
237
+ });
238
+ }
239
+ catch (error) {
240
+ return reject(error);
241
+ }
242
+ });
243
+
244
+ this.self.listener = undefined;
245
+ }
246
+
247
+ await DB.Instance.term(null);
248
+
249
+ this.self = undefined;
250
+ }
251
+ }
252
+
253
+ public async run() {
254
+ // Initialize service token verifier
255
+ await ApiService.Instance.init({
256
+ domain: this.config.SERVICE_DOMAIN,
257
+ sessionTimeout: this.config.SERVICE_SESSION_TIMEOUT,
258
+ wallet: this.config.SERVICE_WALLET_JSON,
259
+ password: this.config.SERVICE_WALLET_PASSWORD
260
+ });
261
+
262
+ // Initialize dependencies and modules
263
+ await DB.Instance.init(null, this.config.MYSQL_URL);
264
+
265
+ // Initialize modules
266
+ AuthUser.init(
267
+ this.config.JWT_SECRET,
268
+ undefined,
269
+ {
270
+ JWT_SIGN_ALGO: process.env.JWT_SIGN_ALGO
271
+ }
272
+ );
273
+
274
+ const router = express.Router();
275
+
276
+ // ** Health endpoints **
277
+ this.entryPoint(router, "/", this.onRoot, undefined, [HttpMethod.GET, HttpMethod.POST], AuthType.NIL, ContentType.JSON, true);
278
+ this.entryPoint(router, "/liveness", this.onLiveness, undefined, [HttpMethod.GET, HttpMethod.POST], AuthType.NIL, ContentType.RAW, true);
279
+ this.entryPoint(router, "/readiness", this.onReadiness, undefined, [HttpMethod.GET, HttpMethod.POST], AuthType.NIL, ContentType.RAW, true);
280
+
281
+ this.app.use(router);
282
+ this.app.use(finalHandler); // Make sure this handler is place at the last of the router stack
283
+
284
+ this.app.use(errorHandler);
285
+
286
+ return new Promise<string>((resolve, reject) => {
287
+ try {
288
+ this.listener = this.app.listen(8080, () => {
289
+ return resolve("http://0.0.0.0:8080");
290
+ });
291
+ }
292
+ catch (error) {
293
+ return reject(error);
294
+ }
295
+ });
296
+ }
297
+
298
+ private entryPoint(router: Router, uri: string, func: CallFunc, preCheckFunc: CallFunc, methods: HttpMethod[], authType: AuthType, contentType: ContentType, logExcluded: boolean, overrides?: any) {
299
+ for (const method of methods) {
300
+ let methodPreHandler: RequestHandler;
301
+
302
+ if (ContentType.FILE === contentType) {
303
+ const options: multer.Options = {
304
+ dest: this.config.CACHE_DIR || DEFAULT_FILE_CACHE_DIR,
305
+ limits: {
306
+ fileSize: this.config.MAX_FILE_SIZE || DEFAULT_MAX_FILE_SIZE
307
+ }
308
+ };
309
+ const upload = multer(options);
310
+
311
+ methodPreHandler = async (req: Request, res: Response, next: NextFunction) => {
312
+ req["logExcluded"] = logExcluded;
313
+
314
+ if (!logExcluded) {
315
+ const ip = req.headers?.['x-forwarded-for'] || req.headers?.['x-real-ip'] || "0.0.0.0";
316
+ clog(levels.NORMAL, `REQ: ${req.method} ${req.url} HTTP/${req.httpVersion} @${ip}`);
317
+ }
318
+
319
+ await this.onAuth(authType, req, next);
320
+
321
+ return upload.single(overrides?.fieldName || "file")(req, res, next);
322
+ };
323
+ }
324
+ else {
325
+ methodPreHandler = async (req: Request, res: Response, next: NextFunction) => {
326
+ req["logExcluded"] = logExcluded;
327
+
328
+ if (!logExcluded) {
329
+ const ip = req.headers?.['x-forwarded-for'] || req.headers?.['x-real-ip'] || "0.0.0.0";
330
+ clog(levels.NORMAL, `REQ: ${req.method} ${req.url} HTTP/${req.httpVersion} @${ip}`);
331
+ }
332
+
333
+ await this.onAuth(authType, req, next);
334
+
335
+ switch (req.method) {
336
+ case "GET":
337
+ case "HEAD":
338
+ break;
339
+
340
+ case "POST":
341
+ case "PUT":
342
+ case "PATCH":
343
+ case "DELETE":
344
+ switch (contentType) {
345
+ case ContentType.JSON:
346
+ if (!req.is("json")) {
347
+ const contentType = req.headers?.['content-type'];
348
+ throwError(errors.INVALID_FORMAT, "Content type is not supported", { contentType });
349
+ }
350
+ }
351
+ break;
352
+ }
353
+
354
+ return next();
355
+ };
356
+ }
357
+
358
+ const methodHandler = async (req: Request, res: Response, next: NextFunction) => {
359
+ try {
360
+ preCheckFunc && await preCheckFunc.apply(this, [req, res]);
361
+ func && await func.apply(this, [req, res]);
362
+
363
+ return next();
364
+ }
365
+ catch (error) {
366
+ let { code, message, reason } = errors.describeError(error);
367
+
368
+ clog(levels.ERROR, `ERROR ${code}:`, reason || message);
369
+
370
+ if (errors.DATABASE_ERROR == code) {
371
+ code = isUndefinedOrNullOrEmpty(error.ret) ? "SYSTEM_BUSY" : error.ret;
372
+ if (!isUndefinedOrNullOrEmpty(error.msg)) {
373
+ message = error.msg;
374
+ }
375
+ }
376
+
377
+ try {
378
+ const translated = await this.translateError(req.headers["content-language"], code, message);
379
+
380
+ code = translated.code;
381
+ message = translated.message;
382
+ }
383
+ catch (error) { }
384
+
385
+ return next(createError(code, message, { error }));
386
+ }
387
+ };
388
+
389
+ switch (method) {
390
+ case HttpMethod.GET: router.get(uri, methodPreHandler, methodHandler); break;
391
+ case HttpMethod.POST: router.post(uri, methodPreHandler, methodHandler); break;
392
+ case HttpMethod.PATCH: router.patch(uri, methodPreHandler, methodHandler); break;
393
+ case HttpMethod.PUT: router.put(uri, methodPreHandler, methodHandler); break;
394
+ case HttpMethod.DELETE: router.delete(uri, methodPreHandler, methodHandler); break;
395
+ case HttpMethod.HEAD: router.head(uri, methodPreHandler, methodHandler); break;
396
+ case HttpMethod.OPTIONS: router.options(uri, methodPreHandler, methodHandler); break;
397
+ }
398
+ }
399
+ }
400
+
401
+ private async onAuth(authType: AuthType, req: Request, next: NextFunction) {
402
+ try {
403
+ switch (authType) {
404
+ case AuthType.JWT:
405
+ {
406
+ const credential = (req.headers["authorization"] || "").split(" ")?.[1];
407
+ req["cred"] = AuthUser.Instance.verifyToken(credential, null);
408
+ }
409
+ return;
410
+
411
+ case AuthType.JWT_GUEST:
412
+ {
413
+ const credential = (req.headers["authorization"] || "").split(" ")?.[1];
414
+ req["cred"] = AuthUser.Instance.verifyToken(credential, CREDENTIAL_TYPE.GUEST);
415
+ }
416
+ return;
417
+
418
+ case AuthType.JWT_USER:
419
+ {
420
+ const credential = (req.headers["authorization"] || "").split(" ")?.[1];
421
+ req["cred"] = AuthUser.Instance.verifyToken(credential, CREDENTIAL_TYPE.USER);
422
+ }
423
+ return;
424
+
425
+ case AuthType.API:
426
+ {
427
+ const credential = (req.headers["authorization"] || "").split(" ")?.[1];
428
+
429
+ if (credential) {
430
+ try {
431
+ const walletAddress = ApiService.Instance.verifyToken(credential);
432
+
433
+ if (walletAddress) {
434
+ // Check whitelist
435
+ if (this.whitelist["*"] || this.whitelist[walletAddress]) {
436
+ req["walletAddress"] = walletAddress;
437
+ return;
438
+ }
439
+ }
440
+ } catch (error) {
441
+ const { message } = describeError(error)
442
+ clog(levels.ERROR, "failed to verify api token ", message)
443
+ return next(createError(errors.UNAUTHORISED, message));
444
+ }
445
+ }
446
+ }
447
+ break;
448
+
449
+ case AuthType.NIL:
450
+ return;
451
+ }
452
+ }
453
+ catch (error) {
454
+ const { code, message } = describeError(error);
455
+
456
+ if (errors.EXPIRED === code) {
457
+ //throw error;
458
+ return next(createError(code, message))
459
+ }
460
+ }
461
+
462
+ return next(createError(errors.UNAUTHORISED, "Unauthorised"));
463
+ }
464
+
465
+ private async translateError(language: string, code: string, message: string) {
466
+ if (!language) {
467
+ language = "en_US"; // Default language
468
+ }
469
+
470
+ const codeId = !isNaN(Number(code)) ? Number(code) : 0;
471
+ clog(levels.DETAIL, "Translating error", language, "(", codeId, ")", code, ":", message);
472
+
473
+ try {
474
+ const results = await DB.Instance.callQuery(null, "sp_cm_get_err_msg_sys", [codeId, code, message, language, 1]);
475
+
476
+ let translatedMessage = "";
477
+ if (0 < results.recordsets.length && 0 < results.recordsets[0].length) {
478
+ if (!isUndefinedOrNullOrEmpty(results.recordsets[0][0].msg)) {
479
+ translatedMessage = results.recordsets[0][0].msg;
480
+ }
481
+ }
482
+ clog(levels.INFO, "Translated error", language, "(", codeId, ")", code, ":", translatedMessage);
483
+ return { code, message: translatedMessage };
484
+ }
485
+ catch (error) {
486
+ if (errors.NOT_CONFIGURED != error.code) {
487
+ clog(levels.ERROR, "Translate error message failed", language, "(", codeId, ")", code, ":", message, "ERROR:", JSON.stringify(error));
488
+ }
489
+ return errors.throwError("SYSTEM_BUSY", "System busy", {
490
+ language,
491
+ codeId,
492
+ code,
493
+ message,
494
+ error
495
+ });
496
+ }
497
+ }
498
+ }