@ikonintegration/ikapi 4.0.1 → 5.0.0

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 (236) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.cjs +81 -0
  3. package/.github/workflows/npmpublish.yml +8 -19
  4. package/.github/workflows/prs.yml +12 -0
  5. package/README.md +89 -99
  6. package/dist/index.d.ts +16 -0
  7. package/dist/index.js +27 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/package-lock.json +11881 -0
  10. package/dist/package.json +81 -0
  11. package/dist/src/API/Request.d.ts +125 -0
  12. package/dist/src/API/Request.js +185 -0
  13. package/dist/src/API/Request.js.map +1 -0
  14. package/dist/src/API/Response.d.ts +188 -0
  15. package/dist/src/API/Response.js +270 -0
  16. package/dist/src/API/Response.js.map +1 -0
  17. package/dist/src/BaseEvent/DynamoTransaction.d.ts +70 -0
  18. package/dist/src/BaseEvent/DynamoTransaction.js +104 -0
  19. package/dist/src/BaseEvent/DynamoTransaction.js.map +1 -0
  20. package/dist/src/BaseEvent/EventProcessor.d.ts +58 -0
  21. package/dist/src/BaseEvent/EventProcessor.js +101 -0
  22. package/dist/src/BaseEvent/EventProcessor.js.map +1 -0
  23. package/dist/src/BaseEvent/Process.d.ts +50 -0
  24. package/dist/src/BaseEvent/Process.js +64 -0
  25. package/dist/src/BaseEvent/Process.js.map +1 -0
  26. package/dist/src/BaseEvent/StepTransaction.d.ts +23 -0
  27. package/dist/src/BaseEvent/StepTransaction.js +27 -0
  28. package/dist/src/BaseEvent/StepTransaction.js.map +1 -0
  29. package/dist/src/BaseEvent/Transaction.d.ts +149 -0
  30. package/dist/src/BaseEvent/Transaction.js +224 -0
  31. package/dist/src/BaseEvent/Transaction.js.map +1 -0
  32. package/dist/src/Cache/Redis.d.ts +29 -0
  33. package/dist/src/Cache/Redis.js +80 -0
  34. package/dist/src/Cache/Redis.js.map +1 -0
  35. package/dist/src/Cache/types.d.ts +31 -0
  36. package/dist/src/Cache/types.js +2 -0
  37. package/dist/src/Cache/types.js.map +1 -0
  38. package/dist/src/Config/Configuration.d.ts +123 -0
  39. package/dist/src/Config/Configuration.js +109 -0
  40. package/dist/src/Config/Configuration.js.map +1 -0
  41. package/dist/src/Config/EnvironmentVar.d.ts +74 -0
  42. package/dist/src/Config/EnvironmentVar.js +138 -0
  43. package/dist/src/Config/EnvironmentVar.js.map +1 -0
  44. package/dist/src/Crypto/Crypto.d.ts +45 -0
  45. package/dist/src/Crypto/Crypto.js +72 -0
  46. package/dist/src/Crypto/Crypto.js.map +1 -0
  47. package/dist/src/Database/Database.d.ts +21 -0
  48. package/dist/src/Database/Database.js +15 -0
  49. package/dist/src/Database/Database.js.map +1 -0
  50. package/dist/src/Database/DatabaseManager.d.ts +47 -0
  51. package/dist/src/Database/DatabaseManager.js +60 -0
  52. package/dist/src/Database/DatabaseManager.js.map +1 -0
  53. package/dist/src/Database/DatabaseTransaction.d.ts +101 -0
  54. package/dist/src/Database/DatabaseTransaction.js +126 -0
  55. package/dist/src/Database/DatabaseTransaction.js.map +1 -0
  56. package/dist/src/Database/index.d.ts +10 -0
  57. package/dist/src/Database/index.js +15 -0
  58. package/dist/src/Database/index.js.map +1 -0
  59. package/dist/src/Database/integrations/dynamo/DynamoDatabase.d.ts +35 -0
  60. package/dist/src/Database/integrations/dynamo/DynamoDatabase.js +59 -0
  61. package/dist/src/Database/integrations/dynamo/DynamoDatabase.js.map +1 -0
  62. package/dist/src/Database/integrations/kysely/KyselyDatabase.d.ts +66 -0
  63. package/dist/src/Database/integrations/kysely/KyselyDatabase.js +86 -0
  64. package/dist/src/Database/integrations/kysely/KyselyDatabase.js.map +1 -0
  65. package/dist/src/Database/integrations/kysely/KyselyTransaction.d.ts +70 -0
  66. package/dist/src/Database/integrations/kysely/KyselyTransaction.js +118 -0
  67. package/dist/src/Database/integrations/kysely/KyselyTransaction.js.map +1 -0
  68. package/dist/src/Database/integrations/pgsql/PostgresDatabase.d.ts +36 -0
  69. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js +54 -0
  70. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js.map +1 -0
  71. package/dist/src/Database/integrations/pgsql/PostgresTransaction.d.ts +63 -0
  72. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js +61 -0
  73. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js.map +1 -0
  74. package/dist/src/Database/types.d.ts +76 -0
  75. package/dist/src/Database/types.js +2 -0
  76. package/dist/src/Database/types.js.map +1 -0
  77. package/dist/src/Globals.d.ts +93 -0
  78. package/dist/src/Globals.js +99 -0
  79. package/dist/src/Globals.js.map +1 -0
  80. package/dist/src/Logger/Logger.d.ts +161 -0
  81. package/dist/src/Logger/Logger.js +299 -0
  82. package/dist/src/Logger/Logger.js.map +1 -0
  83. package/dist/src/Mailer/Mailer.d.ts +78 -0
  84. package/dist/src/Mailer/Mailer.js +182 -0
  85. package/dist/src/Mailer/Mailer.js.map +1 -0
  86. package/dist/src/Publisher/Publisher.d.ts +39 -0
  87. package/dist/src/Publisher/Publisher.js +77 -0
  88. package/dist/src/Publisher/Publisher.js.map +1 -0
  89. package/dist/src/Server/RouteResolver.d.ts +33 -0
  90. package/dist/src/Server/RouteResolver.js +100 -0
  91. package/dist/src/Server/RouteResolver.js.map +1 -0
  92. package/dist/src/Server/Router.d.ts +157 -0
  93. package/dist/src/Server/Router.js +32 -0
  94. package/dist/src/Server/Router.js.map +1 -0
  95. package/dist/src/Server/lib/ContainerServer.d.ts +42 -0
  96. package/dist/src/Server/lib/ContainerServer.js +66 -0
  97. package/dist/src/Server/lib/ContainerServer.js.map +1 -0
  98. package/dist/src/Server/lib/Server.d.ts +45 -0
  99. package/dist/src/Server/lib/Server.js +93 -0
  100. package/dist/src/Server/lib/Server.js.map +1 -0
  101. package/dist/src/Server/lib/container/GenericHandler.d.ts +9 -0
  102. package/dist/src/Server/lib/container/GenericHandler.js +82 -0
  103. package/dist/src/Server/lib/container/GenericHandler.js.map +1 -0
  104. package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +52 -0
  105. package/dist/src/Server/lib/container/GenericHandlerEvent.js +132 -0
  106. package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +1 -0
  107. package/dist/src/Server/lib/container/HealthHandler.d.ts +9 -0
  108. package/dist/src/Server/lib/container/HealthHandler.js +19 -0
  109. package/dist/src/Server/lib/container/HealthHandler.js.map +1 -0
  110. package/dist/src/Server/lib/container/Proxy.d.ts +67 -0
  111. package/dist/src/Server/lib/container/Proxy.js +143 -0
  112. package/dist/src/Server/lib/container/Proxy.js.map +1 -0
  113. package/dist/src/Server/lib/container/Utils.d.ts +14 -0
  114. package/dist/src/Server/lib/container/Utils.js +37 -0
  115. package/dist/src/Server/lib/container/Utils.js.map +1 -0
  116. package/dist/src/Util/AsyncSingleton.d.ts +31 -0
  117. package/dist/src/Util/AsyncSingleton.js +83 -0
  118. package/dist/src/Util/AsyncSingleton.js.map +1 -0
  119. package/dist/src/Util/Utils.d.ts +61 -0
  120. package/dist/src/Util/Utils.js +147 -0
  121. package/dist/src/Util/Utils.js.map +1 -0
  122. package/dist/src/Validation/Validator.d.ts +17 -0
  123. package/dist/src/Validation/Validator.js +39 -0
  124. package/dist/src/Validation/Validator.js.map +1 -0
  125. package/dist/tsconfig.tsbuildinfo +1 -0
  126. package/index.ts +41 -0
  127. package/jest.config.ts +37 -0
  128. package/jest.smoke.config.ts +34 -0
  129. package/package.json +66 -22
  130. package/src/API/Request.ts +214 -0
  131. package/src/API/Response.ts +370 -0
  132. package/src/BaseEvent/DynamoTransaction.ts +175 -0
  133. package/src/BaseEvent/EventProcessor.ts +140 -0
  134. package/src/BaseEvent/Process.ts +78 -0
  135. package/src/BaseEvent/StepTransaction.ts +35 -0
  136. package/src/BaseEvent/Transaction.ts +323 -0
  137. package/src/Cache/Redis.ts +89 -0
  138. package/src/Cache/types.ts +33 -0
  139. package/src/Config/Configuration.ts +199 -0
  140. package/src/Config/EnvironmentVar.ts +142 -0
  141. package/src/Crypto/Crypto.ts +89 -0
  142. package/src/Database/Database.ts +22 -0
  143. package/src/Database/DatabaseManager.ts +67 -0
  144. package/src/Database/DatabaseTransaction.ts +170 -0
  145. package/src/Database/index.ts +27 -0
  146. package/src/Database/integrations/dynamo/DynamoDatabase.ts +58 -0
  147. package/src/Database/integrations/kysely/KyselyDatabase.ts +99 -0
  148. package/src/Database/integrations/kysely/KyselyTransaction.ts +172 -0
  149. package/src/Database/integrations/pgsql/PostgresDatabase.ts +56 -0
  150. package/src/Database/integrations/pgsql/PostgresTransaction.ts +87 -0
  151. package/src/Database/types.ts +85 -0
  152. package/src/Globals.ts +103 -0
  153. package/src/Logger/Logger.ts +363 -0
  154. package/src/Mailer/Mailer.ts +217 -0
  155. package/src/Publisher/Publisher.ts +96 -0
  156. package/src/Server/RouteResolver.ts +124 -0
  157. package/src/Server/Router.ts +200 -0
  158. package/src/Server/lib/ContainerServer.ts +65 -0
  159. package/src/Server/lib/Server.ts +109 -0
  160. package/src/Server/lib/container/GenericHandler.ts +76 -0
  161. package/src/Server/lib/container/GenericHandlerEvent.ts +154 -0
  162. package/src/Server/lib/container/HealthHandler.ts +11 -0
  163. package/src/Server/lib/container/Proxy.ts +172 -0
  164. package/src/Server/lib/container/Utils.ts +33 -0
  165. package/src/Util/AsyncSingleton.ts +86 -0
  166. package/src/Util/Utils.ts +131 -0
  167. package/src/Validation/Validator.ts +45 -0
  168. package/tests/API/Request.test.ts +273 -0
  169. package/tests/API/Response.test.ts +367 -0
  170. package/tests/BaseEvent/DynamoTransaction.test.ts +272 -0
  171. package/tests/BaseEvent/EventProcessor.test.ts +263 -0
  172. package/tests/BaseEvent/Process.test.ts +47 -0
  173. package/tests/BaseEvent/StepTransaction.test.ts +44 -0
  174. package/tests/BaseEvent/Transaction.test.ts +402 -0
  175. package/tests/Cache/Redis-client.test.ts +90 -0
  176. package/tests/Cache/Redis-cluster.test.ts +100 -0
  177. package/tests/Config/Config.test.ts +205 -0
  178. package/tests/Config/EnvironmentVar.test.ts +251 -0
  179. package/tests/Crypto/Crypto.test.ts +88 -0
  180. package/tests/Database/DatabaseManager.test.ts +79 -0
  181. package/tests/Database/integrations/dynamo/DynamoDatabase.test.ts +44 -0
  182. package/tests/Database/integrations/kysely/KyselyDatabase.test.ts +113 -0
  183. package/tests/Database/integrations/kysely/KyselyTransaction.test.ts +119 -0
  184. package/tests/Database/integrations/pg/PostgresDatabase.test.ts +76 -0
  185. package/tests/Database/integrations/pg/PostgresTransaction.test.ts +118 -0
  186. package/tests/Logger/Logger.test.ts +215 -0
  187. package/tests/Mailer/Mailer.test.ts +59 -0
  188. package/tests/Publisher/Publisher.test.ts +60 -0
  189. package/tests/Server/RouteResolver.test.ts +116 -0
  190. package/tests/Server/Router.test.ts +39 -0
  191. package/tests/Server/lib/ContainerServer.test.ts +531 -0
  192. package/tests/Server/lib/Server.test.ts +12 -0
  193. package/tests/Server/lib/container/GenericHandler.test.ts +131 -0
  194. package/tests/Server/lib/container/GenericHandlerEvent.test.ts +103 -0
  195. package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
  196. package/tests/Server/lib/container/Proxy.test.ts +268 -0
  197. package/tests/Server/lib/container/Utils.test.ts +47 -0
  198. package/tests/Test.utils.ts +78 -0
  199. package/tests/Utils/Utils.test.ts +229 -0
  200. package/tests/Validation/Validator.test.ts +82 -0
  201. package/tsconfig.json +26 -0
  202. package/tsconfig.smoke.json +26 -0
  203. package/index.js +0 -88
  204. package/src/API/IKRequest.js +0 -52
  205. package/src/API/IKResponse.js +0 -119
  206. package/src/API/IKUtils.js +0 -51
  207. package/src/BaseEvent/IKProcess.js +0 -77
  208. package/src/BaseEvent/IKTransaction.js +0 -139
  209. package/src/Cache/Prototype/IKCache.js +0 -17
  210. package/src/Cache/Redis/IKRedis.js +0 -148
  211. package/src/Database/DDB/IKDB.js +0 -56
  212. package/src/Database/DDB/IKDBBaseExpression.js +0 -130
  213. package/src/Database/DDB/IKDBBaseQuery.js +0 -151
  214. package/src/Database/DDB/IKDBQueryBatchGet.js +0 -37
  215. package/src/Database/DDB/IKDBQueryBatchWrite.js +0 -64
  216. package/src/Database/DDB/IKDBQueryDelete.js +0 -34
  217. package/src/Database/DDB/IKDBQueryGet.js +0 -48
  218. package/src/Database/DDB/IKDBQueryPut.js +0 -87
  219. package/src/Database/DDB/IKDBQueryScan.js +0 -45
  220. package/src/Database/DDB/IKDBQueryTransactionalWrite.js +0 -69
  221. package/src/Database/DDB/IKDBQueryUpdate.js +0 -221
  222. package/src/Database/DDB/_IKDBQueryTransactionalRead.js +0 -46
  223. package/src/Database/PSQL/IKDB.js +0 -41
  224. package/src/Database/PSQL/IKDBBaseQuery.js +0 -26
  225. package/src/Database/Prototype/IKDB.js +0 -21
  226. package/src/Database/Prototype/IKDBBaseQuery.js +0 -14
  227. package/src/IKDynamoStream.js +0 -42
  228. package/src/IKEventProcessor.js +0 -42
  229. package/src/IKGlobals.js +0 -24
  230. package/src/IKRouter.js +0 -47
  231. package/src/IKStepTransaction.js +0 -14
  232. package/src/Logger/IKLogger.js +0 -136
  233. package/src/Mailer/IKMailer.js +0 -69
  234. package/src/Publisher/IKPublisher.js +0 -44
  235. package/src/Tracker/IKExecutionTracker.js +0 -79
  236. package/src/Validation/IKValidation.js +0 -76
@@ -0,0 +1,273 @@
1
+ import { APIGatewayEvent, Context } from 'aws-lambda'
2
+ import { expect } from 'chai'
3
+
4
+ import Request, { HttpMethod } from '../../src/API/Request.js'
5
+ import Logger from '../../src/Logger/Logger.js'
6
+
7
+ function newReq(event: any, context?: any) {
8
+ const logger = new Logger(
9
+ {
10
+ logLevel: 'DEBUG',
11
+ },
12
+ '123-456'
13
+ )
14
+ return new Request<any, any, any>(
15
+ <APIGatewayEvent>(<unknown>event),
16
+ <Context>context ? context : {},
17
+ logger
18
+ )
19
+ }
20
+
21
+ describe('Request querystring', () => {
22
+ test('Null query string', () => {
23
+ const r = newReq({
24
+ queryStringParameters: null,
25
+ })
26
+ expect(r.containsQueryParam('123')).to.be.false
27
+ expect(r.getQueryParam('123')).to.be.null
28
+ })
29
+
30
+ test('Empty query string', () => {
31
+ const r = newReq({
32
+ queryStringParameters: {},
33
+ })
34
+ expect(r.containsQueryParam('123')).to.be.false
35
+ expect(r.getQueryParam('123')).to.be.null
36
+ })
37
+
38
+ test('Valid query string', () => {
39
+ const v = { '123': 'abc' }
40
+ const r = newReq({
41
+ queryStringParameters: v,
42
+ })
43
+ expect(r.containsQueryParam('123')).to.be.true
44
+ expect(r.getQueryParam('123')).to.be.equals('abc')
45
+ expect(r.getQueryParams()).to.be.deep.equal(v)
46
+ })
47
+
48
+ test('Valid query string number', () => {
49
+ const r = newReq({
50
+ queryStringParameters: { '123': 456 },
51
+ })
52
+ expect(r.containsQueryParam('123')).to.be.true
53
+ expect(r.getQueryParam('123')).to.be.equals(456)
54
+ })
55
+ })
56
+
57
+ describe('Request headers', () => {
58
+ test('Null headers', () => {
59
+ const r = newReq({ headers: null })
60
+ expect(r.getHeader('123')).to.be.null
61
+ })
62
+
63
+ test('Empty headers', () => {
64
+ const r = newReq({ headers: {} })
65
+ expect(r.getHeader('123')).to.be.null
66
+ })
67
+
68
+ test('Valid headers', () => {
69
+ const r = newReq({ headers: { '123': 'abc' } })
70
+ expect(r.getHeader('123')).to.be.equals('abc')
71
+ })
72
+
73
+ test('Auth headers', () => {
74
+ const r = newReq({ headers: { Authorization: 'abc' } })
75
+ expect(r.getAuthorizationHeader()).to.be.equals('abc')
76
+ })
77
+ })
78
+
79
+ describe('Request context', () => {
80
+ test('Null context', () => {
81
+ const r = newReq({ requestContext: null })
82
+ expect(r.getContextParam('123')).to.be.null
83
+ })
84
+
85
+ test('Empty context', () => {
86
+ const r = newReq({ requestContext: {} })
87
+ expect(r.getContextParam('123')).to.be.null
88
+ })
89
+
90
+ test('Valid context', () => {
91
+ const r = newReq({
92
+ requestContext: { '123': 'abc' },
93
+ })
94
+ expect(r.getContextParam('123')).to.be.equals('abc')
95
+ })
96
+ })
97
+
98
+ describe('Request path params', () => {
99
+ test('Null path params', () => {
100
+ const r = newReq({ pathParameters: null })
101
+ expect(r.containsPathParam('123')).to.be.false
102
+ expect(r.getPathParam('123')).to.be.null
103
+ expect(r.getPathParams()).to.be.null
104
+ })
105
+
106
+ test('Empty path params', () => {
107
+ const r = newReq({ pathParameters: {} })
108
+ expect(r.containsPathParam('123')).to.be.false
109
+ expect(r.getPathParam('123')).to.be.null
110
+ expect(r.getPathParams()).to.be.deep.equal({})
111
+ })
112
+
113
+ test('Valid path params', () => {
114
+ const v = { '123': 'abc' }
115
+ const r = newReq({
116
+ pathParameters: v,
117
+ })
118
+ expect(r.containsPathParam('123')).to.be.true
119
+ expect(r.getPathParam('123')).to.be.equals('abc')
120
+ expect(r.getPathParams()).to.be.deep.equal(v)
121
+ })
122
+
123
+ test('Valid path param number', () => {
124
+ const v = { '123': 456 }
125
+ const r = newReq({
126
+ pathParameters: v,
127
+ })
128
+ expect(r.containsPathParam('123')).to.be.true
129
+ expect(r.getPathParam('123')).to.be.equals(456)
130
+ expect(r.getPathParams()).to.be.deep.equal(v)
131
+ })
132
+
133
+ test('Fix path params', () => {
134
+ const v = { '123': 'abc' }
135
+ const r = newReq({ pathParameters: null })
136
+ r.setFixedPathParams(
137
+ Object.keys(v).map(k => ({ name: k })),
138
+ ['/'].concat(Object.values(v))
139
+ )
140
+ expect(r.containsPathParam('123')).to.be.true
141
+ expect(r.getPathParam('123')).to.be.equals('abc')
142
+ expect(r.getPathParams()).to.be.deep.equal(v)
143
+ })
144
+ })
145
+
146
+ describe('Request body', () => {
147
+ test('Null body', () => {
148
+ const r = newReq({ body: null })
149
+ expect(r.getBody()).to.be.null
150
+ })
151
+
152
+ test('Empty body', () => {
153
+ const r = newReq({ body: {} })
154
+ expect(r.getBody()).to.be.deep.equals({})
155
+ })
156
+
157
+ test('Empty string body', () => {
158
+ const r = newReq({ body: '{}' })
159
+ expect(r.getBody()).to.be.deep.equals({})
160
+ })
161
+
162
+ test('Broken json string body', () => {
163
+ const r = newReq({ body: '{name": "Joe"}' })
164
+ expect(r.getBody()).to.be.equals('{name": "Joe"}')
165
+ })
166
+
167
+ test('Valid string body', () => {
168
+ const r = newReq({ body: '{"name": "Joe"}' })
169
+ expect(r.getBody()).to.be.deep.equals({
170
+ name: 'Joe',
171
+ })
172
+ })
173
+
174
+ test('Valid json body', () => {
175
+ const r = newReq({ body: { name: 'Joe' } })
176
+ expect(r.getBody()).to.be.deep.equals({
177
+ name: 'Joe',
178
+ })
179
+ })
180
+ })
181
+
182
+ describe('Request path/method', () => {
183
+ test('Null path/method', () => {
184
+ const r = newReq({
185
+ path: null,
186
+ httpMethod: null,
187
+ })
188
+ expect(r.getPath()).to.be.null
189
+ expect(r.getMethod.bind(r)).to.throw('Invalid HTTP method: null')
190
+ })
191
+
192
+ test('Empty path/method', () => {
193
+ const r = newReq({
194
+ path: '',
195
+ httpMethod: '',
196
+ })
197
+ expect(r.getPath()).to.be.a('string')
198
+ expect(r.getPath()).to.be.equals('')
199
+ expect(r.getMethod.bind(r)).to.throw('Invalid HTTP method: ')
200
+ })
201
+
202
+ test('Valid method/path', () => {
203
+ const r = newReq({
204
+ path: '/root',
205
+ httpMethod: HttpMethod.GET,
206
+ })
207
+ expect(r.getPath()).to.be.a('string')
208
+ expect(r.getPath()).to.be.equals('/root')
209
+ expect(r.getMethod()).to.be.a('string')
210
+ expect(r.getMethod()).to.be.equals(HttpMethod.GET)
211
+ })
212
+
213
+ test('Case insensitive method', () => {
214
+ const r = newReq({
215
+ path: '/root',
216
+ httpMethod: 'poST',
217
+ })
218
+
219
+ expect(r.getMethod()).to.be.equals(HttpMethod.POST)
220
+ })
221
+ })
222
+
223
+ describe('Request ID', () => {
224
+ test('From context', () => {
225
+ const r = newReq({}, { awsRequestId: '123' })
226
+ expect(r.getRequestID()).to.not.be.null
227
+ expect(r.getRequestID()).to.be.equals('123')
228
+ })
229
+
230
+ test('From event', () => {
231
+ const r = newReq({
232
+ requestContext: { requestId: '123' },
233
+ })
234
+ expect(r.getRequestID()).to.not.be.null
235
+ expect(r.getRequestID()).to.be.equals('123')
236
+ })
237
+
238
+ test('unknown', () => {
239
+ const r = newReq({})
240
+ expect(r.getRequestID()).to.not.be.null
241
+ expect(r.getRequestID()).to.be.equals('unknown')
242
+ })
243
+ })
244
+
245
+ describe('Request origin IP', () => {
246
+ test('From context', () => {
247
+ const r = newReq({
248
+ requestContext: {
249
+ identity: { sourceIp: '127.0.0.1' },
250
+ },
251
+ })
252
+ expect(r.getOriginIP()).to.not.be.null
253
+ expect(r.getOriginIP()).to.be.equals('127.0.0.1')
254
+ })
255
+
256
+ test('From header', () => {
257
+ const r = newReq({
258
+ headers: {
259
+ 'X-Forwarded-For': '127.0.0.1',
260
+ },
261
+ })
262
+ expect(r.getOriginIP()).to.not.be.null
263
+ expect(r.getOriginIP()).to.be.equals('127.0.0.1')
264
+ })
265
+
266
+ test('unknown', () => {
267
+ const r = newReq({})
268
+ expect(r.getOriginIP()).to.not.be.null
269
+ expect(r.getOriginIP()).to.be.equals('unknown')
270
+ })
271
+ })
272
+
273
+ export {}
@@ -0,0 +1,367 @@
1
+ import { jest } from '@jest/globals'
2
+ import { APIGatewayEvent, Context } from 'aws-lambda'
3
+ import { expect as c_expect } from 'chai'
4
+
5
+ import Response from '../../src/API/Response.js'
6
+ import Transaction from '../../src/BaseEvent/Transaction.js'
7
+ import Globals from '../../src/Globals.js'
8
+ import { observableTransaction, defaultHeaders } from '../Test.utils.js'
9
+
10
+ async function testResponse(r: Response<any>, body: any, optCode?: number, optHeaders?: any) {
11
+ const t = observableTransaction()
12
+ const context = t['context']
13
+ const buildR = await r.build(context, t, false)
14
+ c_expect(buildR).to.be.undefined
15
+ expect(t.responseProxy).toBeCalledTimes(1)
16
+ expect(context.fail).not.toBeCalled()
17
+ expect(context.done).not.toBeCalled()
18
+ expect(context.succeed).toHaveBeenCalledWith({
19
+ statusCode: optCode || 400,
20
+ headers: {
21
+ ...defaultHeaders,
22
+ ...(optHeaders || {}),
23
+ },
24
+ ...(body
25
+ ? {
26
+ body: JSON.stringify({
27
+ ...body,
28
+ transactionID: 'unknown',
29
+ }),
30
+ }
31
+ : {}),
32
+ })
33
+ }
34
+
35
+ describe('Response basics', () => {
36
+ test('Null body', () => {
37
+ const r = new Response<null>(200, null)
38
+ c_expect(r.getCode()).to.be.equals(200)
39
+ c_expect(r.getBody()).to.be.null
40
+ })
41
+
42
+ test('String body', () => {
43
+ const r = new Response<string>(200, 'abc')
44
+ c_expect(r.getCode()).to.be.equals(200)
45
+ c_expect(r.getBody()).to.be.equals('abc')
46
+ })
47
+
48
+ test('Generic body', () => {
49
+ const r = new Response<any>(200, { name: 'abc' })
50
+ r.appendIntoBody('name2', '123')
51
+ c_expect(r.getCode()).to.be.equals(200)
52
+ c_expect(r.getBody().name).to.be.equals('abc')
53
+ c_expect(r.getBody().name2).to.be.equals('123')
54
+ })
55
+
56
+ test('Append/validate header', () => {
57
+ const r = new Response<any>(200, {})
58
+ r.appendHeader('name2', '123')
59
+ c_expect(r['headers']['name2']).to.be.equals('123')
60
+ })
61
+ })
62
+
63
+ describe('Response build', () => {
64
+ test('Succeeds to transaction context', async () => {
65
+ const b = { name: 'abc' }
66
+ const r = new Response<any>(200, b)
67
+ r.appendHeader('abc', '123')
68
+ // do not use default, so we dont use proxy response for once
69
+ const t = new Transaction(
70
+ <APIGatewayEvent>(<unknown>{}),
71
+ <Context>(<unknown>{
72
+ done: jest.fn(),
73
+ fail: jest.fn(),
74
+ succeed: jest.fn(),
75
+ })
76
+ )
77
+ const context = t['context']
78
+ const buildR = await r.build(context, t, false)
79
+ c_expect(buildR).to.be.undefined
80
+ expect(context.fail).not.toBeCalled()
81
+ expect(context.done).not.toBeCalled()
82
+ expect(context.succeed).toHaveBeenCalledWith({
83
+ statusCode: 200,
84
+ headers: {
85
+ ...defaultHeaders,
86
+ abc: '123',
87
+ },
88
+ body: JSON.stringify({
89
+ ...b,
90
+ transactionID: 'unknown',
91
+ }),
92
+ })
93
+ })
94
+
95
+ test('Succeeds with no context call', async () => {
96
+ const b = { name: 'abc' }
97
+ const r = new Response<any>(200, b)
98
+ const t = observableTransaction()
99
+ const context = t['context']
100
+ const buildR = await r.build(context, t, true)
101
+ c_expect(buildR).to.be.undefined
102
+ expect(context.fail).not.toBeCalled()
103
+ expect(context.done).not.toBeCalled()
104
+ expect(context.succeed).not.toBeCalled()
105
+ })
106
+
107
+ test('Succeeds to transaction context as RAW', async () => {
108
+ const b = { name: 'abc' }
109
+ const r = new Response<any>(200, b, {
110
+ rawBody: true,
111
+ })
112
+ const t = observableTransaction()
113
+ const context = t['context']
114
+ const buildR = await r.build(context, t, false)
115
+ c_expect(buildR).to.be.undefined
116
+ expect(context.fail).not.toBeCalled()
117
+ expect(context.done).not.toBeCalled()
118
+ expect(context.succeed).toHaveBeenCalledWith({
119
+ ...b,
120
+ transactionID: 'unknown',
121
+ })
122
+ })
123
+
124
+ test('Succeeds to transaction piping', async () => {
125
+ const b = { name: 'abc' }
126
+ const r = new Response<any>(200, b, {
127
+ shouldStream: true,
128
+ })
129
+ const t = observableTransaction()
130
+ const context = t['context']
131
+ const buildR = await r.build(context, t, false)
132
+ await r.build(context, t, false) //pipe twice, should not affect
133
+ c_expect(buildR).to.be.undefined
134
+ expect(context.fail).not.toBeCalled()
135
+ expect(context.done).not.toBeCalled()
136
+ expect(context.succeed).toHaveBeenCalledTimes(1)
137
+ expect(context.succeed).toHaveBeenCalledWith({
138
+ statusCode: 200,
139
+ headers: {
140
+ ...defaultHeaders,
141
+ },
142
+ body: {
143
+ ...b,
144
+ },
145
+ })
146
+ })
147
+
148
+ test('Failure to transaction context as RAW', async () => {
149
+ const b = { name: 'abc' }
150
+ const r = new Response<any>(400, b, {
151
+ rawBody: true,
152
+ })
153
+ const t = observableTransaction()
154
+ const context = t['context']
155
+ const buildR = await r.build(context, t, false)
156
+ c_expect(buildR).to.be.undefined
157
+ expect(context.done).not.toBeCalled()
158
+ expect(context.succeed).not.toBeCalled()
159
+ expect(context.fail).toHaveBeenCalledTimes(1)
160
+ })
161
+
162
+ test('Failure exception to transaction context as RAW', async () => {
163
+ const b = { name: 'abc' }
164
+ const r = new Response<any>(400, b, {
165
+ rawBody: true,
166
+ throwOnErrors: true,
167
+ })
168
+ const t = observableTransaction()
169
+ const context = t['context']
170
+ let buildR: any = null,
171
+ exception = null
172
+ try {
173
+ buildR = await r.build(context, t, false)
174
+ } catch (e) {
175
+ exception = e
176
+ }
177
+ c_expect(buildR).to.be.null
178
+ c_expect(exception).to.not.be.null
179
+ expect(context.done).not.toBeCalled()
180
+ expect(context.succeed).not.toBeCalled()
181
+ expect(context.fail).not.toBeCalled()
182
+ })
183
+
184
+ test('Failure exception to transaction context as RAW and null body', async () => {
185
+ const b = null
186
+ const r = new Response<any>(400, b, {
187
+ rawBody: true,
188
+ throwOnErrors: true,
189
+ })
190
+ const t = observableTransaction()
191
+ const context = t['context']
192
+ let buildR: any = null,
193
+ exception = null
194
+ try {
195
+ buildR = await r.build(context, t, false)
196
+ } catch (e) {
197
+ exception = e
198
+ }
199
+ c_expect(buildR).to.be.null
200
+ c_expect(exception).to.not.be.null
201
+ expect(context.done).not.toBeCalled()
202
+ expect(context.succeed).not.toBeCalled()
203
+ expect(context.fail).not.toBeCalled()
204
+ })
205
+
206
+ test('Failure exception to transaction context as RAW and custom ero', async () => {
207
+ const b = { message: 'abc', error: 'error 123' }
208
+ const r = new Response<any>(400, b, {
209
+ rawBody: true,
210
+ throwOnErrors: true,
211
+ })
212
+ const t = observableTransaction()
213
+ const context = t['context']
214
+ let buildR: any = null,
215
+ exception = null
216
+ try {
217
+ buildR = await r.build(context, t, false)
218
+ } catch (e) {
219
+ exception = e
220
+ }
221
+ c_expect(buildR).to.be.null
222
+ c_expect(exception).to.not.be.null
223
+ expect(context.done).not.toBeCalled()
224
+ expect(context.succeed).not.toBeCalled()
225
+ expect(context.fail).not.toBeCalled()
226
+ })
227
+ })
228
+
229
+ describe('Response shortcuts', () => {
230
+ test('MissingParamResponse', async () => {
231
+ const pName = 'abc'
232
+ const r = Response.MissingParamResponse(pName)
233
+ await testResponse(r, {
234
+ err: `Invalid request. Path parameter ${pName} is missing.`,
235
+ errCode: Globals.ErrorCode_MissingParam,
236
+ })
237
+ })
238
+
239
+ test('MissingQueryResponse', async () => {
240
+ const pName = 'abc'
241
+ const r = Response.MissingQueryResponse(pName)
242
+ await testResponse(r, {
243
+ err: `Invalid request. Query parameter ${pName} is missing.`,
244
+ errCode: Globals.ErrorCode_MissingParam,
245
+ })
246
+ })
247
+
248
+ test('BadRequestResponse', async () => {
249
+ const message = 'abc'
250
+ const code = 'CODE'
251
+ const optBody = { additional: 123 }
252
+ const r = Response.BadRequestResponse(message, code, optBody)
253
+ await testResponse(r, {
254
+ err: message,
255
+ errCode: code,
256
+ ...optBody,
257
+ })
258
+ })
259
+
260
+ test('BadRequestResponse no opts', async () => {
261
+ const message = 'abc'
262
+ const r = Response.BadRequestResponse(message)
263
+ await testResponse(r, {
264
+ err: message,
265
+ })
266
+ })
267
+
268
+ test('BadRequestResponseWithRollback', async () => {
269
+ const message = 'abc'
270
+ const code = 'CODE'
271
+ const optBody = { additional: 123 }
272
+ const r = Response.BadRequestResponseWithRollback(message, code, optBody)
273
+ await testResponse(r, {
274
+ err: message,
275
+ rollback: true,
276
+ errCode: code,
277
+ ...optBody,
278
+ })
279
+ })
280
+
281
+ test('BadRequestResponseWithRollback no opts', async () => {
282
+ const message = 'abc'
283
+ const r = Response.BadRequestResponseWithRollback(message)
284
+ await testResponse(r, {
285
+ err: message,
286
+ rollback: true,
287
+ })
288
+ })
289
+
290
+ test('UnauthorizedResponse', async () => {
291
+ const message = 'abc'
292
+ const code = 'CODE'
293
+ const r = Response.UnauthorizedResponse(message, code)
294
+ await testResponse(
295
+ r,
296
+ {
297
+ err: message,
298
+ errCode: code,
299
+ },
300
+ 401
301
+ )
302
+ })
303
+
304
+ test('UnauthorizedResponse no code', async () => {
305
+ const message = 'abc'
306
+ const r = Response.UnauthorizedResponse(message)
307
+ await testResponse(r, { err: message }, 401)
308
+ })
309
+
310
+ test('SuccessResponse', async () => {
311
+ const body = { additional: 123 }
312
+ const r = Response.SuccessResponse(body)
313
+ await testResponse(r, body, 200)
314
+ })
315
+
316
+ test('SuccessResponse null body', async () => {
317
+ const r = Response.SuccessResponse(null)
318
+ await testResponse(r, {}, 200)
319
+ })
320
+
321
+ test('SuccessNoContentResponse', async () => {
322
+ const r = Response.SuccessNoContentResponse()
323
+ await testResponse(r, null, 204)
324
+ })
325
+
326
+ test('SimpleResponse', async () => {
327
+ const r = Response.SimpleResponse(null)
328
+ await testResponse(r, null, 200)
329
+ })
330
+
331
+ test('SimpleResponse override statuscode', async () => {
332
+ const r = Response.SimpleResponse(null, 203)
333
+ await testResponse(r, null, 203)
334
+ })
335
+
336
+ test('RedirectResponse', async () => {
337
+ const url = 'https://google.com'
338
+ const r = Response.RedirectResponse(url)
339
+ await testResponse(r, null, 302, { Location: url })
340
+ })
341
+
342
+ test('SuccessStreamResponse', async () => {
343
+ const b = { name: 'abc' }
344
+ const r = Response.SuccessStreamResponse(b, 'test-stream')
345
+ const t = observableTransaction()
346
+ const context = t['context']
347
+ const buildR = await r.build(context, t, false)
348
+ await r.build(context, t, false) //pipe twice, should not affect
349
+ c_expect(buildR).to.be.undefined
350
+ expect(context.fail).not.toBeCalled()
351
+ expect(context.done).not.toBeCalled()
352
+ expect(context.succeed).toHaveBeenCalledTimes(1)
353
+ expect(context.succeed).toHaveBeenCalledWith({
354
+ statusCode: 200,
355
+ headers: {
356
+ ...defaultHeaders,
357
+ 'Content-Type': 'test-stream',
358
+ Connection: 'keep-alive',
359
+ },
360
+ body: {
361
+ ...b,
362
+ },
363
+ })
364
+ })
365
+ })
366
+
367
+ export {}