@geekmidas/constructs 0.0.2 → 0.0.4

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 (187) hide show
  1. package/dist/{AWSLambdaFunction-nic3vzt3.mjs → AWSLambdaFunction-DWIZYsCy.mjs} +2 -2
  2. package/dist/{AWSLambdaFunction-nic3vzt3.mjs.map → AWSLambdaFunction-DWIZYsCy.mjs.map} +1 -1
  3. package/dist/{AWSLambdaFunction-DW9qrBNR.cjs → AWSLambdaFunction-qA5LqPsv.cjs} +2 -2
  4. package/dist/{AWSLambdaFunction-DW9qrBNR.cjs.map → AWSLambdaFunction-qA5LqPsv.cjs.map} +1 -1
  5. package/dist/{AWSLambdaSubscriberAdaptor-ZuQAhW9_.cjs → AWSLambdaSubscriberAdaptor-CmPZ10JF.cjs} +1 -1
  6. package/dist/{AWSLambdaSubscriberAdaptor-ZuQAhW9_.cjs.map → AWSLambdaSubscriberAdaptor-CmPZ10JF.cjs.map} +1 -1
  7. package/dist/{AWSLambdaSubscriberAdaptor-BhqrpTVc.mjs → AWSLambdaSubscriberAdaptor-G8y3YkWj.mjs} +1 -1
  8. package/dist/{AWSLambdaSubscriberAdaptor-BhqrpTVc.mjs.map → AWSLambdaSubscriberAdaptor-G8y3YkWj.mjs.map} +1 -1
  9. package/dist/{AmazonApiGatewayEndpointAdaptor-D_Q_NTMT.cjs → AmazonApiGatewayEndpointAdaptor-B8mozTcG.cjs} +33 -10
  10. package/dist/AmazonApiGatewayEndpointAdaptor-B8mozTcG.cjs.map +1 -0
  11. package/dist/{AmazonApiGatewayEndpointAdaptor-DtzgQ9Vb.d.cts → AmazonApiGatewayEndpointAdaptor-BFhJ2Rpz.d.cts} +5 -2
  12. package/dist/{AmazonApiGatewayEndpointAdaptor-QzIAnWzS.mjs → AmazonApiGatewayEndpointAdaptor-Bmz6Cy1e.mjs} +33 -10
  13. package/dist/AmazonApiGatewayEndpointAdaptor-Bmz6Cy1e.mjs.map +1 -0
  14. package/dist/{AmazonApiGatewayEndpointAdaptor-DNZLntHj.d.mts → AmazonApiGatewayEndpointAdaptor-BrB3RfbI.d.mts} +5 -2
  15. package/dist/{AmazonApiGatewayV1EndpointAdaptor-BF5bGWV1.mjs → AmazonApiGatewayV1EndpointAdaptor-24g3dLn5.mjs} +3 -3
  16. package/dist/{AmazonApiGatewayV1EndpointAdaptor-BF5bGWV1.mjs.map → AmazonApiGatewayV1EndpointAdaptor-24g3dLn5.mjs.map} +1 -1
  17. package/dist/{AmazonApiGatewayV1EndpointAdaptor-Gw-j61qM.d.cts → AmazonApiGatewayV1EndpointAdaptor-Bd-o8ese.d.cts} +3 -3
  18. package/dist/{AmazonApiGatewayV1EndpointAdaptor-DbJa4cpU.d.mts → AmazonApiGatewayV1EndpointAdaptor-BtNXt0-4.d.mts} +3 -3
  19. package/dist/{AmazonApiGatewayV1EndpointAdaptor-Bh4tckwd.cjs → AmazonApiGatewayV1EndpointAdaptor-D4eZ-fx5.cjs} +3 -3
  20. package/dist/{AmazonApiGatewayV1EndpointAdaptor-Bh4tckwd.cjs.map → AmazonApiGatewayV1EndpointAdaptor-D4eZ-fx5.cjs.map} +1 -1
  21. package/dist/{AmazonApiGatewayV2EndpointAdaptor-BOaOkLXF.mjs → AmazonApiGatewayV2EndpointAdaptor-Cc40RThv.mjs} +3 -3
  22. package/dist/{AmazonApiGatewayV2EndpointAdaptor-BOaOkLXF.mjs.map → AmazonApiGatewayV2EndpointAdaptor-Cc40RThv.mjs.map} +1 -1
  23. package/dist/{AmazonApiGatewayV2EndpointAdaptor-BlKn-KJ6.d.mts → AmazonApiGatewayV2EndpointAdaptor-DAJdtgek.d.mts} +3 -3
  24. package/dist/{AmazonApiGatewayV2EndpointAdaptor-LUlpwmUW.d.cts → AmazonApiGatewayV2EndpointAdaptor-DX-Uci5w.d.cts} +3 -3
  25. package/dist/{AmazonApiGatewayV2EndpointAdaptor-L4Ywv3Pk.cjs → AmazonApiGatewayV2EndpointAdaptor-J6tACl-N.cjs} +3 -3
  26. package/dist/{AmazonApiGatewayV2EndpointAdaptor-L4Ywv3Pk.cjs.map → AmazonApiGatewayV2EndpointAdaptor-J6tACl-N.cjs.map} +1 -1
  27. package/dist/{Cron-BgJo6EW6.mjs → Cron-Br2TtpGY.mjs} +1 -1
  28. package/dist/{Cron-BgJo6EW6.mjs.map → Cron-Br2TtpGY.mjs.map} +1 -1
  29. package/dist/{Cron-JYYGj5ik.cjs → Cron-DF1o3U_T.cjs} +1 -1
  30. package/dist/{Cron-JYYGj5ik.cjs.map → Cron-DF1o3U_T.cjs.map} +1 -1
  31. package/dist/{CronBuilder-DVuhB_kA.mjs → CronBuilder-DNFHMTSl.mjs} +2 -2
  32. package/dist/{CronBuilder-DVuhB_kA.mjs.map → CronBuilder-DNFHMTSl.mjs.map} +1 -1
  33. package/dist/{CronBuilder-BDDS21OP.cjs → CronBuilder-e8CAOwBV.cjs} +2 -2
  34. package/dist/{CronBuilder-BDDS21OP.cjs.map → CronBuilder-e8CAOwBV.cjs.map} +1 -1
  35. package/dist/{Endpoint-DYUjJdEs.d.mts → Endpoint-C7jPJzAH.d.mts} +115 -6
  36. package/dist/{Endpoint-D1nnEsBU.cjs → Endpoint-COGAflGh.cjs} +128 -4
  37. package/dist/Endpoint-COGAflGh.cjs.map +1 -0
  38. package/dist/{Endpoint-DNlmybXV.mjs → Endpoint-DLLZvqoh.mjs} +123 -5
  39. package/dist/Endpoint-DLLZvqoh.mjs.map +1 -0
  40. package/dist/{Endpoint-C7z9YJHK.d.cts → Endpoint-XUMNAXYy.d.cts} +115 -6
  41. package/dist/{EndpointBuilder-B2iScUND.d.mts → EndpointBuilder-CFtWQhcv.d.mts} +2 -2
  42. package/dist/{EndpointBuilder-BhRd626m.cjs → EndpointBuilder-FJktpPOu.cjs} +2 -2
  43. package/dist/{EndpointBuilder-BhRd626m.cjs.map → EndpointBuilder-FJktpPOu.cjs.map} +1 -1
  44. package/dist/{EndpointBuilder-CpjIMYb0.mjs → EndpointBuilder-oXO_ka1-.mjs} +2 -2
  45. package/dist/{EndpointBuilder-CpjIMYb0.mjs.map → EndpointBuilder-oXO_ka1-.mjs.map} +1 -1
  46. package/dist/{EndpointBuilder-1fw103D6.d.cts → EndpointBuilder-t6fVEKBH.d.cts} +2 -2
  47. package/dist/{EndpointFactory-D576BhaH.d.cts → EndpointFactory-DBRGrXAy.d.mts} +10 -10
  48. package/dist/{EndpointFactory-DZQpM-9K.d.mts → EndpointFactory-DInjHvFR.d.cts} +10 -10
  49. package/dist/{EndpointFactory-ChmVHWim.cjs → EndpointFactory-Kk1tpifs.cjs} +4 -3
  50. package/dist/EndpointFactory-Kk1tpifs.cjs.map +1 -0
  51. package/dist/{EndpointFactory-DLpEbLzL.mjs → EndpointFactory-eG8bDhOh.mjs} +4 -3
  52. package/dist/EndpointFactory-eG8bDhOh.mjs.map +1 -0
  53. package/dist/{FunctionExecutionWrapper-UzfHDM2R.cjs → FunctionExecutionWrapper-CElXEjPe.cjs} +1 -1
  54. package/dist/{FunctionExecutionWrapper-UzfHDM2R.cjs.map → FunctionExecutionWrapper-CElXEjPe.cjs.map} +1 -1
  55. package/dist/{FunctionExecutionWrapper-CPzSbfaI.mjs → FunctionExecutionWrapper-XGrSAAPD.mjs} +1 -1
  56. package/dist/{FunctionExecutionWrapper-CPzSbfaI.mjs.map → FunctionExecutionWrapper-XGrSAAPD.mjs.map} +1 -1
  57. package/dist/{HonoEndpointAdaptor-ua6mp3gt.d.cts → HonoEndpointAdaptor-BJgpbMUG.d.cts} +4 -4
  58. package/dist/{HonoEndpointAdaptor-fs2928iO.mjs → HonoEndpointAdaptor-BlT1rWHV.mjs} +24 -9
  59. package/dist/HonoEndpointAdaptor-BlT1rWHV.mjs.map +1 -0
  60. package/dist/{HonoEndpointAdaptor-01cH100U.d.mts → HonoEndpointAdaptor-C9Xe2pRp.d.mts} +2 -2
  61. package/dist/{HonoEndpointAdaptor-6LERutxi.cjs → HonoEndpointAdaptor-Ds433Q8w.cjs} +24 -9
  62. package/dist/HonoEndpointAdaptor-Ds433Q8w.cjs.map +1 -0
  63. package/dist/{TestEndpointAdaptor-CelYsQi0.mjs → TestEndpointAdaptor-BG6fzAOx.mjs} +20 -6
  64. package/dist/TestEndpointAdaptor-BG6fzAOx.mjs.map +1 -0
  65. package/dist/{TestEndpointAdaptor-B4SvJvK-.cjs → TestEndpointAdaptor-BaQaTy_1.cjs} +20 -6
  66. package/dist/TestEndpointAdaptor-BaQaTy_1.cjs.map +1 -0
  67. package/dist/{TestEndpointAdaptor-Da0ooGt2.d.mts → TestEndpointAdaptor-Db0cm1fb.d.mts} +3 -3
  68. package/dist/{TestEndpointAdaptor-CHcgyI3V.d.cts → TestEndpointAdaptor-v7A-7hTs.d.cts} +3 -3
  69. package/dist/adaptors/aws.cjs +8 -8
  70. package/dist/adaptors/aws.d.cts +5 -5
  71. package/dist/adaptors/aws.d.mts +5 -5
  72. package/dist/adaptors/aws.mjs +8 -8
  73. package/dist/adaptors/hono.cjs +4 -4
  74. package/dist/adaptors/hono.d.cts +3 -3
  75. package/dist/adaptors/hono.d.mts +3 -3
  76. package/dist/adaptors/hono.mjs +4 -4
  77. package/dist/adaptors/testing.cjs +2 -2
  78. package/dist/adaptors/testing.d.cts +3 -3
  79. package/dist/adaptors/testing.d.mts +3 -3
  80. package/dist/adaptors/testing.mjs +2 -2
  81. package/dist/crons/Cron.cjs +1 -1
  82. package/dist/crons/Cron.d.cts +1 -1
  83. package/dist/crons/Cron.d.mts +1 -1
  84. package/dist/crons/Cron.mjs +1 -1
  85. package/dist/crons/CronBuilder.cjs +2 -2
  86. package/dist/crons/CronBuilder.d.cts +1 -1
  87. package/dist/crons/CronBuilder.d.mts +1 -1
  88. package/dist/crons/CronBuilder.mjs +2 -2
  89. package/dist/crons/index.cjs +2 -2
  90. package/dist/crons/index.d.cts +5 -5
  91. package/dist/crons/index.d.mts +5 -5
  92. package/dist/crons/index.mjs +2 -2
  93. package/dist/endpoints/AmazonApiGatewayEndpointAdaptor.cjs +2 -2
  94. package/dist/endpoints/AmazonApiGatewayEndpointAdaptor.d.cts +3 -3
  95. package/dist/endpoints/AmazonApiGatewayEndpointAdaptor.d.mts +3 -3
  96. package/dist/endpoints/AmazonApiGatewayEndpointAdaptor.mjs +2 -2
  97. package/dist/endpoints/AmazonApiGatewayV1EndpointAdaptor.cjs +4 -4
  98. package/dist/endpoints/AmazonApiGatewayV1EndpointAdaptor.d.cts +4 -4
  99. package/dist/endpoints/AmazonApiGatewayV1EndpointAdaptor.d.mts +4 -4
  100. package/dist/endpoints/AmazonApiGatewayV1EndpointAdaptor.mjs +4 -4
  101. package/dist/endpoints/AmazonApiGatewayV2EndpointAdaptor.cjs +4 -4
  102. package/dist/endpoints/AmazonApiGatewayV2EndpointAdaptor.d.cts +4 -4
  103. package/dist/endpoints/AmazonApiGatewayV2EndpointAdaptor.d.mts +4 -4
  104. package/dist/endpoints/AmazonApiGatewayV2EndpointAdaptor.mjs +4 -4
  105. package/dist/endpoints/Endpoint.cjs +2 -1
  106. package/dist/endpoints/Endpoint.d.cts +3 -3
  107. package/dist/endpoints/Endpoint.d.mts +3 -3
  108. package/dist/endpoints/Endpoint.mjs +2 -2
  109. package/dist/endpoints/EndpointBuilder.cjs +2 -2
  110. package/dist/endpoints/EndpointBuilder.d.cts +3 -3
  111. package/dist/endpoints/EndpointBuilder.d.mts +3 -3
  112. package/dist/endpoints/EndpointBuilder.mjs +2 -2
  113. package/dist/endpoints/EndpointFactory.cjs +3 -3
  114. package/dist/endpoints/EndpointFactory.d.cts +4 -4
  115. package/dist/endpoints/EndpointFactory.d.mts +4 -4
  116. package/dist/endpoints/EndpointFactory.mjs +3 -3
  117. package/dist/endpoints/HonoEndpointAdaptor.cjs +4 -4
  118. package/dist/endpoints/HonoEndpointAdaptor.d.cts +3 -3
  119. package/dist/endpoints/HonoEndpointAdaptor.d.mts +3 -3
  120. package/dist/endpoints/HonoEndpointAdaptor.mjs +4 -4
  121. package/dist/endpoints/TestEndpointAdaptor.cjs +2 -2
  122. package/dist/endpoints/TestEndpointAdaptor.d.cts +3 -3
  123. package/dist/endpoints/TestEndpointAdaptor.d.mts +3 -3
  124. package/dist/endpoints/TestEndpointAdaptor.mjs +2 -2
  125. package/dist/endpoints/helpers.cjs +2 -2
  126. package/dist/endpoints/helpers.d.cts +2 -2
  127. package/dist/endpoints/helpers.d.mts +2 -2
  128. package/dist/endpoints/helpers.mjs +2 -2
  129. package/dist/endpoints/index.cjs +3 -3
  130. package/dist/endpoints/index.cjs.map +1 -1
  131. package/dist/endpoints/index.d.cts +7 -7
  132. package/dist/endpoints/index.d.mts +7 -7
  133. package/dist/endpoints/index.mjs +3 -3
  134. package/dist/endpoints/index.mjs.map +1 -1
  135. package/dist/endpoints/parseHonoQuery.cjs +1 -1
  136. package/dist/endpoints/parseHonoQuery.mjs +1 -1
  137. package/dist/endpoints/parseQueryParams.cjs +1 -1
  138. package/dist/endpoints/parseQueryParams.mjs +1 -1
  139. package/dist/functions/AWSLambdaFunction.cjs +2 -2
  140. package/dist/functions/AWSLambdaFunction.mjs +2 -2
  141. package/dist/functions/FunctionExecutionWrapper.cjs +1 -1
  142. package/dist/functions/FunctionExecutionWrapper.mjs +1 -1
  143. package/dist/functions/index.d.cts +1 -1
  144. package/dist/functions/index.d.mts +1 -1
  145. package/dist/{helpers-CP7A0U_s.mjs → helpers-CM0U-4Vk.mjs} +2 -2
  146. package/dist/{helpers-CP7A0U_s.mjs.map → helpers-CM0U-4Vk.mjs.map} +1 -1
  147. package/dist/{helpers-CjvCSIF5.cjs → helpers-go4jiRvV.cjs} +2 -2
  148. package/dist/{helpers-CjvCSIF5.cjs.map → helpers-go4jiRvV.cjs.map} +1 -1
  149. package/dist/index-BjB0W_Wq.d.mts +9 -0
  150. package/dist/index-D9vqHZie.d.cts +9 -0
  151. package/dist/{parseHonoQuery-BiPp8bEJ.cjs → parseHonoQuery-DopC24vB.cjs} +1 -1
  152. package/dist/{parseHonoQuery-BiPp8bEJ.cjs.map → parseHonoQuery-DopC24vB.cjs.map} +1 -1
  153. package/dist/{parseHonoQuery-yWRoKFFl.mjs → parseHonoQuery-znDKBhdE.mjs} +1 -1
  154. package/dist/{parseHonoQuery-yWRoKFFl.mjs.map → parseHonoQuery-znDKBhdE.mjs.map} +1 -1
  155. package/dist/{parseQueryParams-DSk9xl09.mjs → parseQueryParams-BJaRh3OB.mjs} +1 -1
  156. package/dist/{parseQueryParams-DSk9xl09.mjs.map → parseQueryParams-BJaRh3OB.mjs.map} +1 -1
  157. package/dist/{parseQueryParams-C2EjouGt.cjs → parseQueryParams-BzPop4I1.cjs} +1 -1
  158. package/dist/{parseQueryParams-C2EjouGt.cjs.map → parseQueryParams-BzPop4I1.cjs.map} +1 -1
  159. package/dist/subscribers/AWSLambdaSubscriberAdaptor.cjs +1 -1
  160. package/dist/subscribers/AWSLambdaSubscriberAdaptor.mjs +1 -1
  161. package/dist/subscribers/index.d.cts +2 -2
  162. package/dist/subscribers/index.d.mts +2 -2
  163. package/package.json +3 -3
  164. package/src/endpoints/AmazonApiGatewayEndpointAdaptor.ts +62 -13
  165. package/src/endpoints/Endpoint.ts +243 -19
  166. package/src/endpoints/EndpointFactory.ts +88 -18
  167. package/src/endpoints/HonoEndpointAdaptor.ts +52 -16
  168. package/src/endpoints/TestEndpointAdaptor.ts +45 -12
  169. package/src/endpoints/__tests__/AmazonApiGatewayV1EndpointAdaptor.spec.ts +240 -0
  170. package/src/endpoints/__tests__/AmazonApiGatewayV2EndpointAdaptor.spec.ts +177 -200
  171. package/src/endpoints/__tests__/Endpoint.cookies.spec.ts +120 -0
  172. package/src/endpoints/__tests__/Endpoint.spec.ts +12 -0
  173. package/src/endpoints/__tests__/ResponseBuilder.spec.ts +235 -0
  174. package/src/endpoints/__tests__/TestEndpointAdaptor.spec.ts +348 -0
  175. package/src/endpoints/index.ts +1 -1
  176. package/dist/AmazonApiGatewayEndpointAdaptor-D_Q_NTMT.cjs.map +0 -1
  177. package/dist/AmazonApiGatewayEndpointAdaptor-QzIAnWzS.mjs.map +0 -1
  178. package/dist/Endpoint-D1nnEsBU.cjs.map +0 -1
  179. package/dist/Endpoint-DNlmybXV.mjs.map +0 -1
  180. package/dist/EndpointFactory-ChmVHWim.cjs.map +0 -1
  181. package/dist/EndpointFactory-DLpEbLzL.mjs.map +0 -1
  182. package/dist/HonoEndpointAdaptor-6LERutxi.cjs.map +0 -1
  183. package/dist/HonoEndpointAdaptor-fs2928iO.mjs.map +0 -1
  184. package/dist/TestEndpointAdaptor-B4SvJvK-.cjs.map +0 -1
  185. package/dist/TestEndpointAdaptor-CelYsQi0.mjs.map +0 -1
  186. package/dist/index-BXTN4mwI.d.mts +0 -9
  187. package/dist/index-zOH9f4sh.d.cts +0 -9
@@ -0,0 +1,235 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ResponseBuilder, SuccessStatus } from '../Endpoint';
3
+
4
+ describe('ResponseBuilder', () => {
5
+ describe('header', () => {
6
+ it('should set a single header', () => {
7
+ const builder = new ResponseBuilder();
8
+ builder.header('X-Custom-Header', 'custom-value');
9
+
10
+ const metadata = builder.getMetadata();
11
+ expect(metadata.headers).toEqual({
12
+ 'X-Custom-Header': 'custom-value',
13
+ });
14
+ });
15
+
16
+ it('should set multiple headers', () => {
17
+ const builder = new ResponseBuilder();
18
+ builder
19
+ .header('X-Header-1', 'value1')
20
+ .header('X-Header-2', 'value2')
21
+ .header('Content-Type', 'application/json');
22
+
23
+ const metadata = builder.getMetadata();
24
+ expect(metadata.headers).toEqual({
25
+ 'X-Header-1': 'value1',
26
+ 'X-Header-2': 'value2',
27
+ 'Content-Type': 'application/json',
28
+ });
29
+ });
30
+
31
+ it('should allow method chaining', () => {
32
+ const builder = new ResponseBuilder();
33
+ const result = builder.header('X-Test', 'value');
34
+
35
+ expect(result).toBe(builder);
36
+ });
37
+ });
38
+
39
+ describe('cookie', () => {
40
+ it('should set a simple cookie', () => {
41
+ const builder = new ResponseBuilder();
42
+ builder.cookie('session', 'abc123');
43
+
44
+ const metadata = builder.getMetadata();
45
+ expect(metadata.cookies?.has('session')).toBe(true);
46
+ expect(metadata.cookies?.get('session')).toEqual({
47
+ value: 'abc123',
48
+ options: undefined,
49
+ });
50
+ });
51
+
52
+ it('should set cookie with options', () => {
53
+ const builder = new ResponseBuilder();
54
+ builder.cookie('session', 'abc123', {
55
+ httpOnly: true,
56
+ secure: true,
57
+ sameSite: 'strict',
58
+ maxAge: 3600,
59
+ path: '/',
60
+ });
61
+
62
+ const metadata = builder.getMetadata();
63
+ const cookie = metadata.cookies?.get('session');
64
+ expect(cookie).toEqual({
65
+ value: 'abc123',
66
+ options: {
67
+ httpOnly: true,
68
+ secure: true,
69
+ sameSite: 'strict',
70
+ maxAge: 3600,
71
+ path: '/',
72
+ },
73
+ });
74
+ });
75
+
76
+ it('should set multiple cookies', () => {
77
+ const builder = new ResponseBuilder();
78
+ builder
79
+ .cookie('session', 'abc123')
80
+ .cookie('theme', 'dark')
81
+ .cookie('lang', 'en');
82
+
83
+ const metadata = builder.getMetadata();
84
+ expect(metadata.cookies?.size).toBe(3);
85
+ expect(metadata.cookies?.get('session')?.value).toBe('abc123');
86
+ expect(metadata.cookies?.get('theme')?.value).toBe('dark');
87
+ expect(metadata.cookies?.get('lang')?.value).toBe('en');
88
+ });
89
+
90
+ it('should allow method chaining', () => {
91
+ const builder = new ResponseBuilder();
92
+ const result = builder.cookie('test', 'value');
93
+
94
+ expect(result).toBe(builder);
95
+ });
96
+ });
97
+
98
+ describe('deleteCookie', () => {
99
+ it('should set cookie with empty value and maxAge 0', () => {
100
+ const builder = new ResponseBuilder();
101
+ builder.deleteCookie('session');
102
+
103
+ const metadata = builder.getMetadata();
104
+ const cookie = metadata.cookies?.get('session');
105
+ expect(cookie?.value).toBe('');
106
+ expect(cookie?.options?.maxAge).toBe(0);
107
+ expect(cookie?.options?.expires?.getTime()).toBe(0);
108
+ });
109
+
110
+ it('should preserve domain and path options', () => {
111
+ const builder = new ResponseBuilder();
112
+ builder.deleteCookie('session', {
113
+ domain: '.example.com',
114
+ path: '/app',
115
+ });
116
+
117
+ const metadata = builder.getMetadata();
118
+ const cookie = metadata.cookies?.get('session');
119
+ expect(cookie?.options).toMatchObject({
120
+ domain: '.example.com',
121
+ path: '/app',
122
+ maxAge: 0,
123
+ });
124
+ });
125
+
126
+ it('should allow method chaining', () => {
127
+ const builder = new ResponseBuilder();
128
+ const result = builder.deleteCookie('test');
129
+
130
+ expect(result).toBe(builder);
131
+ });
132
+ });
133
+
134
+ describe('status', () => {
135
+ it('should set status code', () => {
136
+ const builder = new ResponseBuilder();
137
+ builder.status(SuccessStatus.Created);
138
+
139
+ const metadata = builder.getMetadata();
140
+ expect(metadata.status).toBe(201);
141
+ });
142
+
143
+ it('should allow method chaining', () => {
144
+ const builder = new ResponseBuilder();
145
+ const result = builder.status(SuccessStatus.OK);
146
+
147
+ expect(result).toBe(builder);
148
+ });
149
+ });
150
+
151
+ describe('send', () => {
152
+ it('should return data with metadata', () => {
153
+ const builder = new ResponseBuilder();
154
+ builder.header('X-Test', 'value').status(SuccessStatus.Created);
155
+
156
+ const result = builder.send({ id: '123', name: 'Test' });
157
+
158
+ expect(result).toEqual({
159
+ data: { id: '123', name: 'Test' },
160
+ metadata: {
161
+ headers: { 'X-Test': 'value' },
162
+ cookies: new Map(),
163
+ status: SuccessStatus.Created,
164
+ },
165
+ });
166
+ });
167
+
168
+ it('should work with complex data', () => {
169
+ const builder = new ResponseBuilder();
170
+ const complexData = {
171
+ user: { id: '1', name: 'John' },
172
+ posts: [{ id: '1', title: 'Post' }],
173
+ };
174
+
175
+ const result = builder.send(complexData);
176
+
177
+ expect(result.data).toEqual(complexData);
178
+ expect(result.metadata).toBeDefined();
179
+ });
180
+ });
181
+
182
+ describe('fluent API', () => {
183
+ it('should support full fluent chain', () => {
184
+ const builder = new ResponseBuilder();
185
+
186
+ const result = builder
187
+ .status(SuccessStatus.Created)
188
+ .header('Location', '/users/123')
189
+ .header('X-User-Id', '123')
190
+ .cookie('session', 'abc123', { httpOnly: true })
191
+ .cookie('preferences', 'dark-mode')
192
+ .send({ id: '123', name: 'John' });
193
+
194
+ expect(result).toEqual({
195
+ data: { id: '123', name: 'John' },
196
+ metadata: {
197
+ status: 201,
198
+ headers: {
199
+ Location: '/users/123',
200
+ 'X-User-Id': '123',
201
+ },
202
+ cookies: new Map([
203
+ ['session', { value: 'abc123', options: { httpOnly: true } }],
204
+ ['preferences', { value: 'dark-mode', options: undefined }],
205
+ ]),
206
+ },
207
+ });
208
+ });
209
+ });
210
+
211
+ describe('getMetadata', () => {
212
+ it('should return current metadata', () => {
213
+ const builder = new ResponseBuilder();
214
+ builder.header('X-Test', 'value').cookie('test', 'cookie-value');
215
+
216
+ const metadata = builder.getMetadata();
217
+
218
+ expect(metadata).toEqual({
219
+ headers: { 'X-Test': 'value' },
220
+ cookies: new Map([
221
+ ['test', { value: 'cookie-value', options: undefined }],
222
+ ]),
223
+ });
224
+ });
225
+
226
+ it('should return empty objects for unused features', () => {
227
+ const builder = new ResponseBuilder();
228
+ const metadata = builder.getMetadata();
229
+
230
+ expect(metadata.headers).toEqual({});
231
+ expect(metadata.cookies?.size).toBe(0);
232
+ expect(metadata.status).toBeUndefined();
233
+ });
234
+ });
235
+ });
@@ -2,6 +2,7 @@ import { UnprocessableEntityError } from '@geekmidas/errors';
2
2
  import { ConsoleLogger } from '@geekmidas/logger/console';
3
3
  import { describe, expect, it, vi } from 'vitest';
4
4
  import { z } from 'zod';
5
+ import { SuccessStatus } from '../Endpoint';
5
6
  import { e } from '../EndpointFactory';
6
7
  import { TestEndpointAdaptor } from '../TestEndpointAdaptor';
7
8
 
@@ -191,6 +192,7 @@ describe('TestEndpointAdaptor', () => {
191
192
  logger: expect.any(ConsoleLogger),
192
193
  services: mockServices,
193
194
  header: expect.any(Function),
195
+ cookie: expect.any(Function),
194
196
  });
195
197
  });
196
198
 
@@ -232,5 +234,351 @@ describe('TestEndpointAdaptor', () => {
232
234
  contentType: 'application/json',
233
235
  });
234
236
  });
237
+
238
+ it('should read cookies from request', async () => {
239
+ const endpoint = e
240
+ .get('/cookies')
241
+ .output(
242
+ z.object({
243
+ session: z.string().optional(),
244
+ theme: z.string().optional(),
245
+ }),
246
+ )
247
+ .handle(async ({ cookie }) => ({
248
+ session: cookie('session'),
249
+ theme: cookie('theme'),
250
+ }));
251
+
252
+ const adapter = new TestEndpointAdaptor(endpoint);
253
+
254
+ const result = await adapter.request({
255
+ services: mockServices,
256
+ headers: {
257
+ host: 'example.com',
258
+ cookie: 'session=abc123; theme=dark',
259
+ },
260
+ });
261
+
262
+ expect(result).toEqual({
263
+ session: 'abc123',
264
+ theme: 'dark',
265
+ });
266
+ });
267
+
268
+ it('should handle missing cookies gracefully', async () => {
269
+ const endpoint = e
270
+ .get('/cookies-optional')
271
+ .output(
272
+ z.object({
273
+ session: z.string().optional(),
274
+ }),
275
+ )
276
+ .handle(async ({ cookie }) => ({
277
+ session: cookie('session') || 'default',
278
+ }));
279
+
280
+ const adapter = new TestEndpointAdaptor(endpoint);
281
+
282
+ const result = await adapter.request({
283
+ services: mockServices,
284
+ headers: {
285
+ host: 'example.com',
286
+ },
287
+ });
288
+
289
+ expect(result).toEqual({
290
+ session: 'default',
291
+ });
292
+ });
293
+
294
+ it('should handle URL encoded cookie values', async () => {
295
+ const endpoint = e
296
+ .get('/cookies-encoded')
297
+ .output(z.object({ user: z.string() }))
298
+ .handle(async ({ cookie }) => ({
299
+ user: cookie('user') || 'unknown',
300
+ }));
301
+
302
+ const adapter = new TestEndpointAdaptor(endpoint);
303
+
304
+ const result = await adapter.request({
305
+ services: mockServices,
306
+ headers: {
307
+ host: 'example.com',
308
+ cookie: 'user=John%20Doe',
309
+ },
310
+ });
311
+
312
+ expect(result).toEqual({
313
+ user: 'John Doe',
314
+ });
315
+ });
316
+
317
+ it('should use cookies in session extraction', async () => {
318
+ const endpoint = e
319
+ .get('/profile')
320
+ .output(z.object({ userId: z.string() }))
321
+ .handle(async ({ session }) => ({
322
+ userId: (session as any).userId,
323
+ }));
324
+
325
+ // Mock getSession that uses cookies
326
+ endpoint.getSession = vi.fn().mockImplementation(({ cookie }) => {
327
+ const sessionId = cookie('session');
328
+ if (sessionId === 'valid-session') {
329
+ return { userId: 'user-123' };
330
+ }
331
+ return null;
332
+ });
333
+
334
+ const adapter = new TestEndpointAdaptor(endpoint);
335
+
336
+ const result = await adapter.request({
337
+ services: mockServices,
338
+ headers: {
339
+ host: 'example.com',
340
+ cookie: 'session=valid-session',
341
+ },
342
+ });
343
+
344
+ expect(result).toEqual({ userId: 'user-123' });
345
+ expect(endpoint.getSession).toHaveBeenCalledWith({
346
+ logger: expect.any(ConsoleLogger),
347
+ services: mockServices,
348
+ header: expect.any(Function),
349
+ cookie: expect.any(Function),
350
+ });
351
+ });
352
+
353
+ it('should handle multiple cookies with same name (uses last)', async () => {
354
+ const endpoint = e
355
+ .get('/duplicate-cookies')
356
+ .output(z.object({ value: z.string() }))
357
+ .handle(async ({ cookie }) => ({
358
+ value: cookie('test') || 'none',
359
+ }));
360
+
361
+ const adapter = new TestEndpointAdaptor(endpoint);
362
+
363
+ const result = await adapter.request({
364
+ services: mockServices,
365
+ headers: {
366
+ host: 'example.com',
367
+ cookie: 'test=first; test=second',
368
+ },
369
+ });
370
+
371
+ // When duplicates exist, Map uses the last occurrence
372
+ expect(result).toEqual({
373
+ value: 'second',
374
+ });
375
+ });
376
+ });
377
+
378
+ describe('response handling', () => {
379
+ it('should set response cookies', async () => {
380
+ const endpoint = e
381
+ .post('/auth/login')
382
+ .body(z.object({ email: z.string(), password: z.string() }))
383
+ .output(z.object({ id: z.string(), email: z.string() }))
384
+ .handle(async ({ body }, response) => {
385
+ return response
386
+ .cookie('session', 'abc123', {
387
+ httpOnly: true,
388
+ secure: true,
389
+ sameSite: 'strict',
390
+ maxAge: 3600,
391
+ })
392
+ .send({ id: 'user-1', email: body.email });
393
+ });
394
+
395
+ const adapter = new TestEndpointAdaptor(endpoint);
396
+ const result = await adapter.request({
397
+ body: { email: 'test@example.com', password: 'pass123' },
398
+ services: mockServices,
399
+ headers: { host: 'example.com' },
400
+ });
401
+
402
+ expect(result).toHaveProperty('data');
403
+ expect(result).toHaveProperty('metadata');
404
+ expect((result as any).data).toEqual({
405
+ id: 'user-1',
406
+ email: 'test@example.com',
407
+ });
408
+ expect((result as any).metadata.cookies?.has('session')).toBe(true);
409
+ expect((result as any).metadata.cookies?.get('session')).toEqual({
410
+ value: 'abc123',
411
+ options: {
412
+ httpOnly: true,
413
+ secure: true,
414
+ sameSite: 'strict',
415
+ maxAge: 3600,
416
+ },
417
+ });
418
+ });
419
+
420
+ it('should set custom response headers', async () => {
421
+ const endpoint = e
422
+ .post('/users')
423
+ .body(z.object({ name: z.string() }))
424
+ .output(z.object({ id: z.string(), name: z.string() }))
425
+ .handle(async ({ body }, response) => {
426
+ const user = { id: 'user-123', name: body.name };
427
+ return response
428
+ .header('Location', `/users/${user.id}`)
429
+ .header('X-User-Id', user.id)
430
+ .send(user);
431
+ });
432
+
433
+ const adapter = new TestEndpointAdaptor(endpoint);
434
+ const result = await adapter.request({
435
+ body: { name: 'John Doe' },
436
+ services: mockServices,
437
+ headers: { host: 'example.com' },
438
+ });
439
+
440
+ expect((result as any).data).toEqual({
441
+ id: 'user-123',
442
+ name: 'John Doe',
443
+ });
444
+ expect((result as any).metadata.headers).toEqual({
445
+ Location: '/users/user-123',
446
+ 'X-User-Id': 'user-123',
447
+ });
448
+ });
449
+
450
+ it('should set custom status code', async () => {
451
+ const endpoint = e
452
+ .post('/resources')
453
+ .body(z.object({ name: z.string() }))
454
+ .output(z.object({ id: z.string() }))
455
+ .handle(async (ctx, response) => {
456
+ return response.status(SuccessStatus.Created).send({ id: '123' });
457
+ });
458
+
459
+ const adapter = new TestEndpointAdaptor(endpoint);
460
+ const result = await adapter.request({
461
+ body: { name: 'Resource' },
462
+ services: mockServices,
463
+ headers: { host: 'example.com' },
464
+ });
465
+
466
+ expect((result as any).metadata.status).toBe(201);
467
+ });
468
+
469
+ it('should delete cookies', async () => {
470
+ const endpoint = e
471
+ .post('/auth/logout')
472
+ .output(z.object({ success: z.boolean() }))
473
+ .handle(async (ctx, response) => {
474
+ return response
475
+ .deleteCookie('session', { path: '/' })
476
+ .send({ success: true });
477
+ });
478
+
479
+ const adapter = new TestEndpointAdaptor(endpoint);
480
+ const result = await adapter.request({
481
+ services: mockServices,
482
+ headers: { host: 'example.com' },
483
+ });
484
+
485
+ expect((result as any).data.success).toBe(true);
486
+ const sessionCookie = (result as any).metadata.cookies?.get('session');
487
+ expect(sessionCookie?.value).toBe('');
488
+ expect(sessionCookie?.options?.maxAge).toBe(0);
489
+ expect(sessionCookie?.options?.path).toBe('/');
490
+ });
491
+
492
+ it('should combine cookies, headers, and status', async () => {
493
+ const endpoint = e
494
+ .post('/complete')
495
+ .body(z.object({ data: z.string() }))
496
+ .output(z.object({ id: z.string(), result: z.string() }))
497
+ .handle(async ({ body }, response) => {
498
+ return response
499
+ .status(SuccessStatus.Created)
500
+ .header('Location', '/complete/123')
501
+ .header('X-Request-Id', 'req-456')
502
+ .cookie('tracking', 'track-789')
503
+ .cookie('preference', 'dark', { maxAge: 86400 })
504
+ .send({ id: '123', result: body.data });
505
+ });
506
+
507
+ const adapter = new TestEndpointAdaptor(endpoint);
508
+ const result = await adapter.request({
509
+ body: { data: 'test' },
510
+ services: mockServices,
511
+ headers: { host: 'example.com' },
512
+ });
513
+
514
+ expect((result as any).data).toEqual({
515
+ id: '123',
516
+ result: 'test',
517
+ });
518
+ expect((result as any).metadata.status).toBe(201);
519
+ expect((result as any).metadata.headers).toEqual({
520
+ Location: '/complete/123',
521
+ 'X-Request-Id': 'req-456',
522
+ });
523
+ expect((result as any).metadata.cookies?.size).toBe(2);
524
+ expect((result as any).metadata.cookies?.get('tracking')?.value).toBe(
525
+ 'track-789',
526
+ );
527
+ expect((result as any).metadata.cookies?.get('preference')).toEqual({
528
+ value: 'dark',
529
+ options: { maxAge: 86400 },
530
+ });
531
+ });
532
+
533
+ it('should return simple response without metadata when not using response builder', async () => {
534
+ const endpoint = e
535
+ .get('/simple')
536
+ .output(z.object({ message: z.string() }))
537
+ .handle(async () => {
538
+ // Not using response builder, just returning data
539
+ return { message: 'Hello' };
540
+ });
541
+
542
+ const adapter = new TestEndpointAdaptor(endpoint);
543
+ const result = await adapter.request({
544
+ services: mockServices,
545
+ headers: { host: 'example.com' },
546
+ });
547
+
548
+ // Should return just the data, not wrapped in metadata
549
+ expect(result).toEqual({ message: 'Hello' });
550
+ expect(result).not.toHaveProperty('metadata');
551
+ });
552
+
553
+ it('should combine request cookies and response cookies', async () => {
554
+ const endpoint = e
555
+ .get('/preferences')
556
+ .output(z.object({ theme: z.string(), updated: z.boolean() }))
557
+ .handle(async ({ cookie }, response) => {
558
+ const currentTheme = cookie('theme') || 'light';
559
+ const newTheme = currentTheme === 'light' ? 'dark' : 'light';
560
+
561
+ return response
562
+ .cookie('theme', newTheme, { maxAge: 86400 })
563
+ .send({ theme: newTheme, updated: true });
564
+ });
565
+
566
+ const adapter = new TestEndpointAdaptor(endpoint);
567
+ const result = await adapter.request({
568
+ services: mockServices,
569
+ headers: {
570
+ host: 'example.com',
571
+ cookie: 'theme=light',
572
+ },
573
+ });
574
+
575
+ expect((result as any).data).toEqual({
576
+ theme: 'dark',
577
+ updated: true,
578
+ });
579
+ expect((result as any).metadata.cookies?.get('theme')?.value).toBe(
580
+ 'dark',
581
+ );
582
+ });
235
583
  });
236
584
  });
@@ -1,5 +1,5 @@
1
1
  import { EndpointFactory } from './EndpointFactory';
2
2
 
3
- export { Endpoint, type EndpointOutput } from './Endpoint';
3
+ export { Endpoint, type EndpointOutput, type EndpointSchemas } from './Endpoint';
4
4
 
5
5
  export const e = new EndpointFactory();
@@ -1 +0,0 @@
1
- {"version":3,"file":"AmazonApiGatewayEndpointAdaptor-D_Q_NTMT.cjs","names":["envParser: EnvironmentParser<{}>","endpoint: Endpoint<\n TRoute,\n TMethod,\n TInput,\n TOutSchema,\n TServices,\n TLogger,\n TSession,\n TEventPublisher,\n TEventPublisherServiceName\n >","UnprocessableEntityError","UnauthorizedError","event: Event<TEvent, TInput, TServices, TLogger, TSession>"],"sources":["../src/endpoints/AmazonApiGatewayEndpointAdaptor.ts"],"sourcesContent":["import type { Logger } from '@geekmidas/logger';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { HttpMethod } from '../types';\nimport { Endpoint, type EndpointSchemas } from './Endpoint';\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport middy, { type MiddlewareObj } from '@middy/core';\nimport type {\n APIGatewayProxyEvent,\n APIGatewayProxyEventV2,\n Context,\n} from 'aws-lambda';\nimport set from 'lodash.set';\n\nimport {\n UnauthorizedError,\n UnprocessableEntityError,\n wrapError,\n} from '@geekmidas/errors';\nimport type { EventPublisher } from '@geekmidas/events';\nimport {\n type Service,\n ServiceDiscovery,\n type ServiceRecord,\n} from '@geekmidas/services';\n\nimport type {\n InferComposableStandardSchema,\n InferStandardSchema,\n} from '@geekmidas/schema';\nimport { publishConstructEvents } from '../publisher';\n\n// Helper function to publish events\n\nexport abstract class AmazonApiGatewayEndpoint<\n THandler extends\n | AmazonApiGatewayV1EndpointHandler\n | AmazonApiGatewayV2EndpointHandler,\n TEvent extends HandlerEvent<THandler>,\n TRoute extends string,\n TMethod extends HttpMethod,\n TInput extends EndpointSchemas = {},\n TOutSchema extends StandardSchemaV1 | undefined = undefined,\n TServices extends Service[] = [],\n TLogger extends Logger = Logger,\n TSession = unknown,\n TEventPublisher extends EventPublisher<any> | undefined = undefined,\n TEventPublisherServiceName extends string = string,\n> {\n constructor(\n protected envParser: EnvironmentParser<{}>,\n protected readonly endpoint: Endpoint<\n TRoute,\n TMethod,\n TInput,\n TOutSchema,\n TServices,\n TLogger,\n TSession,\n TEventPublisher,\n TEventPublisherServiceName\n >,\n ) {}\n\n private error(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n onError: (req) => {\n (req.event.logger || this.endpoint.logger).error(\n req.error || {},\n 'Error processing request',\n );\n const wrappedError = wrapError(req.error);\n\n // Set the response with the proper status code from the HttpError\n req.response = {\n statusCode: wrappedError.statusCode,\n body: wrappedError.body,\n };\n },\n };\n }\n abstract getInput(e: TEvent): GetInputResponse;\n\n private input(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: async (req) => {\n try {\n const { body, query, params } = this.getInput(req.event);\n const headers = req.event.headers as Record<string, string>;\n const header = Endpoint.createHeaders(headers);\n\n set(req.event, 'body', await this.endpoint.parseInput(body, 'body'));\n\n set(\n req.event,\n 'query',\n await this.endpoint.parseInput(query, 'query'),\n );\n set(\n req.event,\n 'params',\n await this.endpoint.parseInput(params, 'params'),\n );\n set(req.event, 'header', header);\n } catch (error) {\n // Convert validation errors to 422 Unprocessable Entity\n if (error && typeof error === 'object' && Array.isArray(error)) {\n throw new UnprocessableEntityError('Validation failed', error);\n }\n throw error;\n }\n },\n };\n }\n\n abstract getLoggerContext(data: TEvent, context: Context): LoggerContext;\n\n private logger(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: (req) => {\n req.event.logger = this.endpoint.logger.child({\n route: this.endpoint.route,\n host: req.event.headers?.host,\n method: this.endpoint.method,\n ...this.getLoggerContext(req.event, req.context),\n }) as TLogger;\n },\n };\n }\n private services(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: async (req) => {\n const logger = req.event.logger as TLogger;\n const serviceDiscovery = ServiceDiscovery.getInstance<\n ServiceRecord<TServices>,\n TLogger\n >(logger, this.envParser);\n\n const services = await serviceDiscovery.register(\n this.endpoint.services,\n );\n\n req.event.services = services;\n },\n };\n }\n\n private authorize(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: async (req) => {\n const logger = req.event.logger as TLogger;\n const services = req.event.services;\n const header = req.event.header;\n const session = req.event.session as TSession;\n\n const isAuthorized = await this.endpoint.authorize({\n header,\n services,\n logger,\n session,\n });\n\n if (!isAuthorized) {\n logger.warn('Unauthorized access attempt');\n throw new UnauthorizedError(\n 'Unauthorized access to the endpoint',\n 'You do not have permission to access this resource.',\n );\n }\n },\n };\n }\n\n private session(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: async (req) => {\n const logger = req.event.logger as TLogger;\n const services = req.event.services;\n req.event.session = (await this.endpoint.getSession({\n logger,\n services,\n header: req.event.header,\n })) as TSession;\n },\n };\n }\n\n private events(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n after: async (req) => {\n const event = req.event;\n const response = (event as any)\n .__response as InferStandardSchema<TOutSchema>;\n const statusCode = req.response?.statusCode ?? this.endpoint.status;\n\n // Only publish events on successful responses (2xx status codes)\n if (Endpoint.isSuccessStatus(statusCode)) {\n const logger = event.logger as TLogger;\n const serviceDiscovery = ServiceDiscovery.getInstance<\n ServiceRecord<TServices>,\n TLogger\n >(logger, this.envParser);\n await publishConstructEvents(\n this.endpoint,\n response,\n serviceDiscovery,\n logger,\n );\n }\n },\n };\n }\n\n private async _handler(\n event: Event<TEvent, TInput, TServices, TLogger, TSession>,\n ) {\n const input = this.endpoint.refineInput(event);\n\n const response = await this.endpoint.handler({\n header: event.header,\n logger: event.logger,\n services: event.services,\n session: event.session,\n ...input,\n });\n\n const output = await this.endpoint.parseOutput(response);\n\n const body = output ? JSON.stringify(output) : undefined;\n\n // Store response for middleware access\n (event as any).__response = response;\n\n return {\n statusCode: this.endpoint.status,\n body,\n };\n }\n\n get handler() {\n const handler = this._handler.bind(this);\n return middy(handler)\n .use(this.logger())\n .use(this.error())\n .use(this.services())\n .use(this.input())\n .use(this.session())\n .use(this.authorize())\n .use(this.events()) as unknown as THandler;\n }\n}\n\nexport type Event<\n TEvent extends APIGatewayProxyEvent | APIGatewayProxyEventV2,\n TInput extends EndpointSchemas = {},\n TServices extends Service[] = [],\n TLogger extends Logger = Logger,\n TSession = unknown,\n> = {\n services: ServiceRecord<TServices>;\n logger: TLogger;\n header(key: string): string | undefined;\n session: TSession;\n} & TEvent &\n InferComposableStandardSchema<TInput>;\n\ntype Middleware<\n TEvent extends APIGatewayProxyEvent | APIGatewayProxyEventV2,\n TInput extends EndpointSchemas = {},\n TServices extends Service[] = [],\n TLogger extends Logger = Logger,\n TSession = unknown,\n> = MiddlewareObj<Event<TEvent, TInput, TServices, TLogger, TSession>>;\n\nexport type AmazonApiGatewayEndpointHandlerResponse = {\n statusCode: number;\n body: string | undefined;\n};\n\nexport type LoggerContext = {\n fn: {\n name: string;\n version: string;\n };\n req: {\n id: string | undefined;\n awsRequestId: string;\n path: string;\n ip: string | undefined;\n userAgent: string | undefined;\n };\n};\n\nexport type GetInputResponse = {\n body: any;\n query: any;\n params: any;\n};\n\nexport type AmazonApiGatewayV1EndpointHandler = (\n event: APIGatewayProxyEvent,\n context: Context,\n) => Promise<AmazonApiGatewayEndpointHandlerResponse>;\n\nexport type AmazonApiGatewayV2EndpointHandler = (\n event: APIGatewayProxyEventV2,\n context: Context,\n) => Promise<AmazonApiGatewayEndpointHandlerResponse>;\n\nexport type HandlerEvent<T extends Function> = T extends (\n event: infer E,\n context: Context,\n) => any\n ? E\n : never;\n"],"mappings":";;;;;;;;;AAkCA,IAAsB,2BAAtB,MAcE;CACA,YACYA,WACSC,UAWnB;EAZU;EACS;CAWjB;CAEJ,AAAQ,QAAwD;AAC9D,SAAO,EACL,SAAS,CAAC,QAAQ;AAChB,IAAC,IAAI,MAAM,UAAU,KAAK,SAAS,QAAQ,MACzC,IAAI,SAAS,CAAE,GACf,2BACD;GACD,MAAM,eAAe,kCAAU,IAAI,MAAM;AAGzC,OAAI,WAAW;IACb,YAAY,aAAa;IACzB,MAAM,aAAa;GACpB;EACF,EACF;CACF;CAGD,AAAQ,QAAwD;AAC9D,SAAO,EACL,QAAQ,OAAO,QAAQ;AACrB,OAAI;IACF,MAAM,EAAE,MAAM,OAAO,QAAQ,GAAG,KAAK,SAAS,IAAI,MAAM;IACxD,MAAM,UAAU,IAAI,MAAM;IAC1B,MAAM,SAAS,0BAAS,cAAc,QAAQ;AAE9C,4BAAI,IAAI,OAAO,QAAQ,MAAM,KAAK,SAAS,WAAW,MAAM,OAAO,CAAC;AAEpE,4BACE,IAAI,OACJ,SACA,MAAM,KAAK,SAAS,WAAW,OAAO,QAAQ,CAC/C;AACD,4BACE,IAAI,OACJ,UACA,MAAM,KAAK,SAAS,WAAW,QAAQ,SAAS,CACjD;AACD,4BAAI,IAAI,OAAO,UAAU,OAAO;GACjC,SAAQ,OAAO;AAEd,QAAI,gBAAgB,UAAU,YAAY,MAAM,QAAQ,MAAM,CAC5D,OAAM,IAAIC,4CAAyB,qBAAqB;AAE1D,UAAM;GACP;EACF,EACF;CACF;CAID,AAAQ,SAAyD;AAC/D,SAAO,EACL,QAAQ,CAAC,QAAQ;AACf,OAAI,MAAM,SAAS,KAAK,SAAS,OAAO,MAAM;IAC5C,OAAO,KAAK,SAAS;IACrB,MAAM,IAAI,MAAM,SAAS;IACzB,QAAQ,KAAK,SAAS;IACtB,GAAG,KAAK,iBAAiB,IAAI,OAAO,IAAI,QAAQ;GACjD,EAAC;EACH,EACF;CACF;CACD,AAAQ,WAA2D;AACjE,SAAO,EACL,QAAQ,OAAO,QAAQ;GACrB,MAAM,SAAS,IAAI,MAAM;GACzB,MAAM,mBAAmB,sCAAiB,YAGxC,QAAQ,KAAK,UAAU;GAEzB,MAAM,WAAW,MAAM,iBAAiB,SACtC,KAAK,SAAS,SACf;AAED,OAAI,MAAM,WAAW;EACtB,EACF;CACF;CAED,AAAQ,YAA4D;AAClE,SAAO,EACL,QAAQ,OAAO,QAAQ;GACrB,MAAM,SAAS,IAAI,MAAM;GACzB,MAAM,WAAW,IAAI,MAAM;GAC3B,MAAM,SAAS,IAAI,MAAM;GACzB,MAAM,UAAU,IAAI,MAAM;GAE1B,MAAM,eAAe,MAAM,KAAK,SAAS,UAAU;IACjD;IACA;IACA;IACA;GACD,EAAC;AAEF,QAAK,cAAc;AACjB,WAAO,KAAK,8BAA8B;AAC1C,UAAM,IAAIC,qCACR,uCACA;GAEH;EACF,EACF;CACF;CAED,AAAQ,UAA0D;AAChE,SAAO,EACL,QAAQ,OAAO,QAAQ;GACrB,MAAM,SAAS,IAAI,MAAM;GACzB,MAAM,WAAW,IAAI,MAAM;AAC3B,OAAI,MAAM,UAAW,MAAM,KAAK,SAAS,WAAW;IAClD;IACA;IACA,QAAQ,IAAI,MAAM;GACnB,EAAC;EACH,EACF;CACF;CAED,AAAQ,SAAyD;AAC/D,SAAO,EACL,OAAO,OAAO,QAAQ;GACpB,MAAM,QAAQ,IAAI;GAClB,MAAM,WAAY,MACf;GACH,MAAM,aAAa,IAAI,UAAU,cAAc,KAAK,SAAS;AAG7D,OAAI,0BAAS,gBAAgB,WAAW,EAAE;IACxC,MAAM,SAAS,MAAM;IACrB,MAAM,mBAAmB,sCAAiB,YAGxC,QAAQ,KAAK,UAAU;AACzB,UAAM,yCACJ,KAAK,UACL,UACA,kBACA,OACD;GACF;EACF,EACF;CACF;CAED,MAAc,SACZC,OACA;EACA,MAAM,QAAQ,KAAK,SAAS,YAAY,MAAM;EAE9C,MAAM,WAAW,MAAM,KAAK,SAAS,QAAQ;GAC3C,QAAQ,MAAM;GACd,QAAQ,MAAM;GACd,UAAU,MAAM;GAChB,SAAS,MAAM;GACf,GAAG;EACJ,EAAC;EAEF,MAAM,SAAS,MAAM,KAAK,SAAS,YAAY,SAAS;EAExD,MAAM,OAAO,SAAS,KAAK,UAAU,OAAO;AAG5C,EAAC,MAAc,aAAa;AAE5B,SAAO;GACL,YAAY,KAAK,SAAS;GAC1B;EACD;CACF;CAED,IAAI,UAAU;EACZ,MAAM,UAAU,KAAK,SAAS,KAAK,KAAK;AACxC,SAAO,0BAAM,QAAQ,CAClB,IAAI,KAAK,QAAQ,CAAC,CAClB,IAAI,KAAK,OAAO,CAAC,CACjB,IAAI,KAAK,UAAU,CAAC,CACpB,IAAI,KAAK,OAAO,CAAC,CACjB,IAAI,KAAK,SAAS,CAAC,CACnB,IAAI,KAAK,WAAW,CAAC,CACrB,IAAI,KAAK,QAAQ,CAAC;CACtB;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"AmazonApiGatewayEndpointAdaptor-QzIAnWzS.mjs","names":["envParser: EnvironmentParser<{}>","endpoint: Endpoint<\n TRoute,\n TMethod,\n TInput,\n TOutSchema,\n TServices,\n TLogger,\n TSession,\n TEventPublisher,\n TEventPublisherServiceName\n >","event: Event<TEvent, TInput, TServices, TLogger, TSession>"],"sources":["../src/endpoints/AmazonApiGatewayEndpointAdaptor.ts"],"sourcesContent":["import type { Logger } from '@geekmidas/logger';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { HttpMethod } from '../types';\nimport { Endpoint, type EndpointSchemas } from './Endpoint';\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport middy, { type MiddlewareObj } from '@middy/core';\nimport type {\n APIGatewayProxyEvent,\n APIGatewayProxyEventV2,\n Context,\n} from 'aws-lambda';\nimport set from 'lodash.set';\n\nimport {\n UnauthorizedError,\n UnprocessableEntityError,\n wrapError,\n} from '@geekmidas/errors';\nimport type { EventPublisher } from '@geekmidas/events';\nimport {\n type Service,\n ServiceDiscovery,\n type ServiceRecord,\n} from '@geekmidas/services';\n\nimport type {\n InferComposableStandardSchema,\n InferStandardSchema,\n} from '@geekmidas/schema';\nimport { publishConstructEvents } from '../publisher';\n\n// Helper function to publish events\n\nexport abstract class AmazonApiGatewayEndpoint<\n THandler extends\n | AmazonApiGatewayV1EndpointHandler\n | AmazonApiGatewayV2EndpointHandler,\n TEvent extends HandlerEvent<THandler>,\n TRoute extends string,\n TMethod extends HttpMethod,\n TInput extends EndpointSchemas = {},\n TOutSchema extends StandardSchemaV1 | undefined = undefined,\n TServices extends Service[] = [],\n TLogger extends Logger = Logger,\n TSession = unknown,\n TEventPublisher extends EventPublisher<any> | undefined = undefined,\n TEventPublisherServiceName extends string = string,\n> {\n constructor(\n protected envParser: EnvironmentParser<{}>,\n protected readonly endpoint: Endpoint<\n TRoute,\n TMethod,\n TInput,\n TOutSchema,\n TServices,\n TLogger,\n TSession,\n TEventPublisher,\n TEventPublisherServiceName\n >,\n ) {}\n\n private error(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n onError: (req) => {\n (req.event.logger || this.endpoint.logger).error(\n req.error || {},\n 'Error processing request',\n );\n const wrappedError = wrapError(req.error);\n\n // Set the response with the proper status code from the HttpError\n req.response = {\n statusCode: wrappedError.statusCode,\n body: wrappedError.body,\n };\n },\n };\n }\n abstract getInput(e: TEvent): GetInputResponse;\n\n private input(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: async (req) => {\n try {\n const { body, query, params } = this.getInput(req.event);\n const headers = req.event.headers as Record<string, string>;\n const header = Endpoint.createHeaders(headers);\n\n set(req.event, 'body', await this.endpoint.parseInput(body, 'body'));\n\n set(\n req.event,\n 'query',\n await this.endpoint.parseInput(query, 'query'),\n );\n set(\n req.event,\n 'params',\n await this.endpoint.parseInput(params, 'params'),\n );\n set(req.event, 'header', header);\n } catch (error) {\n // Convert validation errors to 422 Unprocessable Entity\n if (error && typeof error === 'object' && Array.isArray(error)) {\n throw new UnprocessableEntityError('Validation failed', error);\n }\n throw error;\n }\n },\n };\n }\n\n abstract getLoggerContext(data: TEvent, context: Context): LoggerContext;\n\n private logger(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: (req) => {\n req.event.logger = this.endpoint.logger.child({\n route: this.endpoint.route,\n host: req.event.headers?.host,\n method: this.endpoint.method,\n ...this.getLoggerContext(req.event, req.context),\n }) as TLogger;\n },\n };\n }\n private services(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: async (req) => {\n const logger = req.event.logger as TLogger;\n const serviceDiscovery = ServiceDiscovery.getInstance<\n ServiceRecord<TServices>,\n TLogger\n >(logger, this.envParser);\n\n const services = await serviceDiscovery.register(\n this.endpoint.services,\n );\n\n req.event.services = services;\n },\n };\n }\n\n private authorize(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: async (req) => {\n const logger = req.event.logger as TLogger;\n const services = req.event.services;\n const header = req.event.header;\n const session = req.event.session as TSession;\n\n const isAuthorized = await this.endpoint.authorize({\n header,\n services,\n logger,\n session,\n });\n\n if (!isAuthorized) {\n logger.warn('Unauthorized access attempt');\n throw new UnauthorizedError(\n 'Unauthorized access to the endpoint',\n 'You do not have permission to access this resource.',\n );\n }\n },\n };\n }\n\n private session(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n before: async (req) => {\n const logger = req.event.logger as TLogger;\n const services = req.event.services;\n req.event.session = (await this.endpoint.getSession({\n logger,\n services,\n header: req.event.header,\n })) as TSession;\n },\n };\n }\n\n private events(): Middleware<TEvent, TInput, TServices, TLogger> {\n return {\n after: async (req) => {\n const event = req.event;\n const response = (event as any)\n .__response as InferStandardSchema<TOutSchema>;\n const statusCode = req.response?.statusCode ?? this.endpoint.status;\n\n // Only publish events on successful responses (2xx status codes)\n if (Endpoint.isSuccessStatus(statusCode)) {\n const logger = event.logger as TLogger;\n const serviceDiscovery = ServiceDiscovery.getInstance<\n ServiceRecord<TServices>,\n TLogger\n >(logger, this.envParser);\n await publishConstructEvents(\n this.endpoint,\n response,\n serviceDiscovery,\n logger,\n );\n }\n },\n };\n }\n\n private async _handler(\n event: Event<TEvent, TInput, TServices, TLogger, TSession>,\n ) {\n const input = this.endpoint.refineInput(event);\n\n const response = await this.endpoint.handler({\n header: event.header,\n logger: event.logger,\n services: event.services,\n session: event.session,\n ...input,\n });\n\n const output = await this.endpoint.parseOutput(response);\n\n const body = output ? JSON.stringify(output) : undefined;\n\n // Store response for middleware access\n (event as any).__response = response;\n\n return {\n statusCode: this.endpoint.status,\n body,\n };\n }\n\n get handler() {\n const handler = this._handler.bind(this);\n return middy(handler)\n .use(this.logger())\n .use(this.error())\n .use(this.services())\n .use(this.input())\n .use(this.session())\n .use(this.authorize())\n .use(this.events()) as unknown as THandler;\n }\n}\n\nexport type Event<\n TEvent extends APIGatewayProxyEvent | APIGatewayProxyEventV2,\n TInput extends EndpointSchemas = {},\n TServices extends Service[] = [],\n TLogger extends Logger = Logger,\n TSession = unknown,\n> = {\n services: ServiceRecord<TServices>;\n logger: TLogger;\n header(key: string): string | undefined;\n session: TSession;\n} & TEvent &\n InferComposableStandardSchema<TInput>;\n\ntype Middleware<\n TEvent extends APIGatewayProxyEvent | APIGatewayProxyEventV2,\n TInput extends EndpointSchemas = {},\n TServices extends Service[] = [],\n TLogger extends Logger = Logger,\n TSession = unknown,\n> = MiddlewareObj<Event<TEvent, TInput, TServices, TLogger, TSession>>;\n\nexport type AmazonApiGatewayEndpointHandlerResponse = {\n statusCode: number;\n body: string | undefined;\n};\n\nexport type LoggerContext = {\n fn: {\n name: string;\n version: string;\n };\n req: {\n id: string | undefined;\n awsRequestId: string;\n path: string;\n ip: string | undefined;\n userAgent: string | undefined;\n };\n};\n\nexport type GetInputResponse = {\n body: any;\n query: any;\n params: any;\n};\n\nexport type AmazonApiGatewayV1EndpointHandler = (\n event: APIGatewayProxyEvent,\n context: Context,\n) => Promise<AmazonApiGatewayEndpointHandlerResponse>;\n\nexport type AmazonApiGatewayV2EndpointHandler = (\n event: APIGatewayProxyEventV2,\n context: Context,\n) => Promise<AmazonApiGatewayEndpointHandlerResponse>;\n\nexport type HandlerEvent<T extends Function> = T extends (\n event: infer E,\n context: Context,\n) => any\n ? E\n : never;\n"],"mappings":"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"}