@geekmidas/constructs 10.0.0-alpha.1 → 10.0.0-alpha.100

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 (422) hide show
  1. package/README.md +223 -158
  2. package/dist/{Construct-CdhThxDI.mjs → Construct-B1vGBPme.mjs} +45 -33
  3. package/dist/Construct-B1vGBPme.mjs.map +1 -0
  4. package/dist/Construct-BQALFCh2.d.cts +230 -0
  5. package/dist/Construct-BQALFCh2.d.cts.map +1 -0
  6. package/dist/{Construct-roId57cU.cjs → Construct-DUSXuTHP.cjs} +65 -47
  7. package/dist/Construct-DUSXuTHP.cjs.map +1 -0
  8. package/dist/Construct-QXnl3VqT.d.mts +230 -0
  9. package/dist/Construct-QXnl3VqT.d.mts.map +1 -0
  10. package/dist/Cron-DI3nKoic.d.cts +45 -0
  11. package/dist/Cron-DI3nKoic.d.cts.map +1 -0
  12. package/dist/Cron-uYAHPnp7.d.mts +45 -0
  13. package/dist/Cron-uYAHPnp7.d.mts.map +1 -0
  14. package/dist/CronBuilder-C0Ek1-RA.cjs +121 -0
  15. package/dist/CronBuilder-C0Ek1-RA.cjs.map +1 -0
  16. package/dist/CronBuilder-DaSUm2Na.d.mts +47 -0
  17. package/dist/CronBuilder-DaSUm2Na.d.mts.map +1 -0
  18. package/dist/CronBuilder-Dmix_Pen.mjs +109 -0
  19. package/dist/CronBuilder-Dmix_Pen.mjs.map +1 -0
  20. package/dist/CronBuilder-g1lZLWyG.d.cts +47 -0
  21. package/dist/CronBuilder-g1lZLWyG.d.cts.map +1 -0
  22. package/dist/{Endpoint-BTj58Gob.mjs → Endpoint-BG4UJ9oA.mjs} +146 -109
  23. package/dist/Endpoint-BG4UJ9oA.mjs.map +1 -0
  24. package/dist/{Endpoint-BBkV6l0k.cjs → Endpoint-BoUg8ocM.cjs} +174 -131
  25. package/dist/Endpoint-BoUg8ocM.cjs.map +1 -0
  26. package/dist/{Endpoint-BKR5QH6O.d.mts → Endpoint-Du-NwPX2.d.mts} +83 -91
  27. package/dist/Endpoint-Du-NwPX2.d.mts.map +1 -0
  28. package/dist/{Endpoint-BQ9O0P1w.d.cts → Endpoint-aCvBMPoH.d.cts} +82 -90
  29. package/dist/Endpoint-aCvBMPoH.d.cts.map +1 -0
  30. package/dist/{EndpointFactory-BejSTzbB.mjs → EndpointFactory-BDtsrEvJ.mjs} +60 -77
  31. package/dist/EndpointFactory-BDtsrEvJ.mjs.map +1 -0
  32. package/dist/{EndpointFactory-DYoGLaIT.cjs → EndpointFactory-DJ7gXLpR.cjs} +96 -113
  33. package/dist/EndpointFactory-DJ7gXLpR.cjs.map +1 -0
  34. package/dist/{index-D5zqAJ2e.d.cts → EndpointFactory-DMYdJCOj.d.mts} +78 -134
  35. package/dist/EndpointFactory-DMYdJCOj.d.mts.map +1 -0
  36. package/dist/{index-Cvz551AO.d.mts → EndpointFactory-I7s1co3Y.d.cts} +79 -135
  37. package/dist/EndpointFactory-I7s1co3Y.d.cts.map +1 -0
  38. package/dist/Function-DuqGcbOI.d.mts +76 -0
  39. package/dist/Function-DuqGcbOI.d.mts.map +1 -0
  40. package/dist/Function-Pu-1kKZz.d.cts +76 -0
  41. package/dist/Function-Pu-1kKZz.d.cts.map +1 -0
  42. package/dist/{HonoEndpointAdaptor-7aYNdqJq.mjs → HonoEndpointAdaptor-PtPlbeKY.mjs} +75 -57
  43. package/dist/HonoEndpointAdaptor-PtPlbeKY.mjs.map +1 -0
  44. package/dist/{HonoEndpointAdaptor-wMsCyMgt.cjs → HonoEndpointAdaptor-zVzVLJEO.cjs} +83 -62
  45. package/dist/HonoEndpointAdaptor-zVzVLJEO.cjs.map +1 -0
  46. package/dist/Queue-A3wfD0it.cjs +109 -0
  47. package/dist/Queue-A3wfD0it.cjs.map +1 -0
  48. package/dist/Queue-D6USGS4q.mjs +104 -0
  49. package/dist/Queue-D6USGS4q.mjs.map +1 -0
  50. package/dist/{Queue-D6WeziRD.d.cts → Queue-DlsHRzUp.d.mts} +48 -48
  51. package/dist/Queue-DlsHRzUp.d.mts.map +1 -0
  52. package/dist/{Queue-DpUeqdC8.d.mts → Queue-HPyi0e1i.d.cts} +49 -49
  53. package/dist/Queue-HPyi0e1i.d.cts.map +1 -0
  54. package/dist/QueueBuilder-BjuF0UBl.cjs +135 -0
  55. package/dist/QueueBuilder-BjuF0UBl.cjs.map +1 -0
  56. package/dist/QueueBuilder-Cue73M4t.mjs +118 -0
  57. package/dist/QueueBuilder-Cue73M4t.mjs.map +1 -0
  58. package/dist/QueueBuilder-OSi6LkV9.d.cts +75 -0
  59. package/dist/QueueBuilder-OSi6LkV9.d.cts.map +1 -0
  60. package/dist/QueueBuilder-QHsnVt1P.d.mts +75 -0
  61. package/dist/QueueBuilder-QHsnVt1P.d.mts.map +1 -0
  62. package/dist/{Subscriber-4rBJgDKI.d.mts → Subscriber-Bpp02cGr.d.cts} +30 -21
  63. package/dist/Subscriber-Bpp02cGr.d.cts.map +1 -0
  64. package/dist/{Subscriber-DVQowdyj.d.cts → Subscriber-CtN9R48-.d.mts} +29 -20
  65. package/dist/Subscriber-CtN9R48-.d.mts.map +1 -0
  66. package/dist/SubscriberBuilder-CDy4nHCz.mjs +134 -0
  67. package/dist/SubscriberBuilder-CDy4nHCz.mjs.map +1 -0
  68. package/dist/SubscriberBuilder-CuCMFpYW.d.mts +67 -0
  69. package/dist/SubscriberBuilder-CuCMFpYW.d.mts.map +1 -0
  70. package/dist/SubscriberBuilder-D_owVoHo.cjs +145 -0
  71. package/dist/SubscriberBuilder-D_owVoHo.cjs.map +1 -0
  72. package/dist/SubscriberBuilder-g3fAVWgs.d.cts +67 -0
  73. package/dist/SubscriberBuilder-g3fAVWgs.d.cts.map +1 -0
  74. package/dist/Topic-D74b5cgs.mjs +99 -0
  75. package/dist/Topic-D74b5cgs.mjs.map +1 -0
  76. package/dist/Topic-GHxcU8AG.cjs +104 -0
  77. package/dist/Topic-GHxcU8AG.cjs.map +1 -0
  78. package/dist/adaptors/aws.cjs +332 -188
  79. package/dist/adaptors/aws.cjs.map +1 -1
  80. package/dist/adaptors/aws.d.cts +114 -44
  81. package/dist/adaptors/aws.d.cts.map +1 -1
  82. package/dist/adaptors/aws.d.mts +114 -44
  83. package/dist/adaptors/aws.d.mts.map +1 -1
  84. package/dist/adaptors/aws.mjs +308 -166
  85. package/dist/adaptors/aws.mjs.map +1 -1
  86. package/dist/adaptors/hono.cjs +3 -11
  87. package/dist/adaptors/hono.d.cts +7 -16
  88. package/dist/adaptors/hono.d.cts.map +1 -1
  89. package/dist/adaptors/hono.d.mts +8 -17
  90. package/dist/adaptors/hono.d.mts.map +1 -1
  91. package/dist/adaptors/hono.mjs +2 -11
  92. package/dist/adaptors/testing.cjs +743 -90
  93. package/dist/adaptors/testing.cjs.map +1 -1
  94. package/dist/adaptors/testing.d.cts +351 -54
  95. package/dist/adaptors/testing.d.cts.map +1 -1
  96. package/dist/adaptors/testing.d.mts +351 -54
  97. package/dist/adaptors/testing.d.mts.map +1 -1
  98. package/dist/adaptors/testing.mjs +706 -71
  99. package/dist/adaptors/testing.mjs.map +1 -1
  100. package/dist/auth-BMCJN30Y.d.cts +268 -0
  101. package/dist/auth-BMCJN30Y.d.cts.map +1 -0
  102. package/dist/auth-CcuceLYo.d.mts +268 -0
  103. package/dist/auth-CcuceLYo.d.mts.map +1 -0
  104. package/dist/auth.cjs +302 -34
  105. package/dist/auth.cjs.map +1 -1
  106. package/dist/auth.d.cts +2 -108
  107. package/dist/auth.d.mts +2 -108
  108. package/dist/auth.mjs +290 -28
  109. package/dist/auth.mjs.map +1 -1
  110. package/dist/{cache-CdQ7OLpR.d.cts → cache-CXh6GIgb.d.mts} +4 -7
  111. package/dist/cache-CXh6GIgb.d.mts.map +1 -0
  112. package/dist/{cache-DYoJFcfd.d.mts → cache-DnGDGly3.d.cts} +4 -7
  113. package/dist/cache-DnGDGly3.d.cts.map +1 -0
  114. package/dist/cache.cjs +68 -2
  115. package/dist/cache.cjs.map +1 -0
  116. package/dist/cache.d.cts +1 -2
  117. package/dist/cache.d.mts +1 -2
  118. package/dist/cache.mjs +67 -2
  119. package/dist/cache.mjs.map +1 -0
  120. package/dist/cipher-C1lEFX63.mjs +225 -0
  121. package/dist/cipher-C1lEFX63.mjs.map +1 -0
  122. package/dist/cipher-CVxfwLjk.cjs +332 -0
  123. package/dist/cipher-CVxfwLjk.cjs.map +1 -0
  124. package/dist/{clone-DblgEZZa.mjs → clone-EKNovYHu.mjs} +3 -3
  125. package/dist/clone-EKNovYHu.mjs.map +1 -0
  126. package/dist/{clone-Dy0cR2SZ.cjs → clone-UGJpvQnL.cjs} +7 -8
  127. package/dist/clone-UGJpvQnL.cjs.map +1 -0
  128. package/dist/{construct-interface-BqwRNYA2.d.mts → construct-interface-B1AfqRl4.d.cts} +43 -12
  129. package/dist/construct-interface-B1AfqRl4.d.cts.map +1 -0
  130. package/dist/{construct-interface-D2nNkHUN.d.cts → construct-interface-DluK3_da.d.mts} +43 -12
  131. package/dist/construct-interface-DluK3_da.d.mts.map +1 -0
  132. package/dist/construct-interface.cjs +113 -7
  133. package/dist/construct-interface.cjs.map +1 -0
  134. package/dist/construct-interface.d.cts +2 -2
  135. package/dist/construct-interface.d.mts +2 -2
  136. package/dist/construct-interface.mjs +106 -2
  137. package/dist/construct-interface.mjs.map +1 -0
  138. package/dist/credential.cjs +77 -17
  139. package/dist/credential.cjs.map +1 -1
  140. package/dist/credential.d.cts +34 -9
  141. package/dist/credential.d.cts.map +1 -1
  142. package/dist/credential.d.mts +34 -9
  143. package/dist/credential.d.mts.map +1 -1
  144. package/dist/credential.mjs +71 -13
  145. package/dist/credential.mjs.map +1 -1
  146. package/dist/crons/index.cjs +189 -85
  147. package/dist/crons/index.cjs.map +1 -1
  148. package/dist/crons/index.d.cts +70 -48
  149. package/dist/crons/index.d.cts.map +1 -1
  150. package/dist/crons/index.d.mts +70 -48
  151. package/dist/crons/index.d.mts.map +1 -1
  152. package/dist/crons/index.mjs +183 -81
  153. package/dist/crons/index.mjs.map +1 -1
  154. package/dist/database/kysely.cjs +4 -181
  155. package/dist/database/kysely.d.cts +2 -152
  156. package/dist/database/kysely.d.mts +2 -152
  157. package/dist/database/kysely.mjs +2 -180
  158. package/dist/email.cjs +25 -12
  159. package/dist/email.cjs.map +1 -1
  160. package/dist/email.d.cts +3 -7
  161. package/dist/email.d.cts.map +1 -1
  162. package/dist/email.d.mts +3 -7
  163. package/dist/email.d.mts.map +1 -1
  164. package/dist/email.mjs +16 -3
  165. package/dist/email.mjs.map +1 -1
  166. package/dist/encryption.cjs +96 -0
  167. package/dist/encryption.cjs.map +1 -0
  168. package/dist/encryption.d.cts +117 -0
  169. package/dist/encryption.d.cts.map +1 -0
  170. package/dist/encryption.d.mts +117 -0
  171. package/dist/encryption.d.mts.map +1 -0
  172. package/dist/encryption.mjs +83 -0
  173. package/dist/encryption.mjs.map +1 -0
  174. package/dist/endpoints/index.cjs +8 -11
  175. package/dist/endpoints/index.d.cts +51 -7
  176. package/dist/endpoints/index.d.cts.map +1 -0
  177. package/dist/endpoints/index.d.mts +51 -7
  178. package/dist/endpoints/index.d.mts.map +1 -0
  179. package/dist/endpoints/index.mjs +6 -11
  180. package/dist/external-api-MJ8id87V.d.mts +105 -0
  181. package/dist/external-api-MJ8id87V.d.mts.map +1 -0
  182. package/dist/external-api-O107yzZJ.d.cts +105 -0
  183. package/dist/external-api-O107yzZJ.d.cts.map +1 -0
  184. package/dist/external-api.cjs +142 -0
  185. package/dist/external-api.cjs.map +1 -0
  186. package/dist/external-api.d.cts +2 -0
  187. package/dist/external-api.d.mts +2 -0
  188. package/dist/external-api.mjs +139 -0
  189. package/dist/external-api.mjs.map +1 -0
  190. package/dist/file-server.cjs +42 -10
  191. package/dist/file-server.cjs.map +1 -1
  192. package/dist/file-server.d.cts +6 -10
  193. package/dist/file-server.d.cts.map +1 -1
  194. package/dist/file-server.d.mts +6 -10
  195. package/dist/file-server.d.mts.map +1 -1
  196. package/dist/file-server.mjs +34 -2
  197. package/dist/file-server.mjs.map +1 -1
  198. package/dist/functions/index.cjs +2 -6
  199. package/dist/functions/index.d.cts +3 -4
  200. package/dist/functions/index.d.mts +3 -4
  201. package/dist/functions/index.mjs +2 -6
  202. package/dist/{functions-Cpff1uZH.mjs → functions-BFizikJU.mjs} +394 -243
  203. package/dist/functions-BFizikJU.mjs.map +1 -0
  204. package/dist/{functions-DukjG8ov.cjs → functions-CfzJG9hK.cjs} +432 -275
  205. package/dist/functions-CfzJG9hK.cjs.map +1 -0
  206. package/dist/index-BuzRvKOQ.d.cts +115 -0
  207. package/dist/index-BuzRvKOQ.d.cts.map +1 -0
  208. package/dist/index-CTkKOer4.d.mts +115 -0
  209. package/dist/index-CTkKOer4.d.mts.map +1 -0
  210. package/dist/index-CeEtxDmK.d.cts +79 -0
  211. package/dist/index-CeEtxDmK.d.cts.map +1 -0
  212. package/dist/index-CeEtxDmK.d.mts +79 -0
  213. package/dist/index-CeEtxDmK.d.mts.map +1 -0
  214. package/dist/index.cjs +6 -3
  215. package/dist/index.d.cts +27 -4
  216. package/dist/index.d.cts.map +1 -0
  217. package/dist/index.d.mts +27 -4
  218. package/dist/index.d.mts.map +1 -0
  219. package/dist/index.mjs +3 -3
  220. package/dist/kms-B-Hm3d5r.cjs +85 -0
  221. package/dist/kms-B-Hm3d5r.cjs.map +1 -0
  222. package/dist/kms-BdUlMJEZ.mjs +85 -0
  223. package/dist/kms-BdUlMJEZ.mjs.map +1 -0
  224. package/dist/kysely-Bii4l6eP.mjs +370 -0
  225. package/dist/kysely-Bii4l6eP.mjs.map +1 -0
  226. package/dist/kysely-CO_Dk43W.cjs +383 -0
  227. package/dist/kysely-CO_Dk43W.cjs.map +1 -0
  228. package/dist/kysely-D0bpzgPs.d.cts +175 -0
  229. package/dist/kysely-D0bpzgPs.d.cts.map +1 -0
  230. package/dist/kysely-DUqC3Ie0.d.mts +175 -0
  231. package/dist/kysely-DUqC3Ie0.d.mts.map +1 -0
  232. package/dist/{telemetry-C3L0iS28.d.cts → lambdaTelemetry-8vnmVZQ5.d.cts} +3 -6
  233. package/dist/lambdaTelemetry-8vnmVZQ5.d.cts.map +1 -0
  234. package/dist/{telemetry-D7bVFLGi.d.mts → lambdaTelemetry-8vnmVZQ5.d.mts} +3 -6
  235. package/dist/lambdaTelemetry-8vnmVZQ5.d.mts.map +1 -0
  236. package/dist/{lazyAccessors-DM6HcXQk.mjs → lazyAccessors-CFanua0O.mjs} +20 -21
  237. package/dist/lazyAccessors-CFanua0O.mjs.map +1 -0
  238. package/dist/{lazyAccessors-DrJj8NpA.cjs → lazyAccessors-hJKGv8Ay.cjs} +60 -62
  239. package/dist/lazyAccessors-hJKGv8Ay.cjs.map +1 -0
  240. package/dist/mobile-app.cjs +73 -0
  241. package/dist/mobile-app.cjs.map +1 -0
  242. package/dist/mobile-app.d.cts +61 -0
  243. package/dist/mobile-app.d.cts.map +1 -0
  244. package/dist/mobile-app.d.mts +61 -0
  245. package/dist/mobile-app.d.mts.map +1 -0
  246. package/dist/mobile-app.mjs +72 -0
  247. package/dist/mobile-app.mjs.map +1 -0
  248. package/dist/object-storage.cjs +18 -10
  249. package/dist/object-storage.cjs.map +1 -1
  250. package/dist/object-storage.d.cts +3 -7
  251. package/dist/object-storage.d.cts.map +1 -1
  252. package/dist/object-storage.d.mts +3 -7
  253. package/dist/object-storage.d.mts.map +1 -1
  254. package/dist/object-storage.mjs +11 -3
  255. package/dist/object-storage.mjs.map +1 -1
  256. package/dist/processAudits-BRRVVHUB.mjs +131 -0
  257. package/dist/processAudits-BRRVVHUB.mjs.map +1 -0
  258. package/dist/processAudits-DasOZjPl.cjs +154 -0
  259. package/dist/processAudits-DasOZjPl.cjs.map +1 -0
  260. package/dist/queue/index.cjs +6 -189
  261. package/dist/queue/index.d.cts +3 -60
  262. package/dist/queue/index.d.mts +3 -60
  263. package/dist/queue/index.mjs +3 -186
  264. package/dist/rest-api.cjs +92 -63
  265. package/dist/rest-api.cjs.map +1 -1
  266. package/dist/rest-api.d.cts +81 -61
  267. package/dist/rest-api.d.cts.map +1 -1
  268. package/dist/rest-api.d.mts +81 -61
  269. package/dist/rest-api.d.mts.map +1 -1
  270. package/dist/rest-api.mjs +84 -55
  271. package/dist/rest-api.mjs.map +1 -1
  272. package/dist/{chunk-DWy1uDak.cjs → rolldown-runtime-y5ARvAq5.cjs} +14 -18
  273. package/dist/runSubscriber-BHvJ8POr.mjs +109 -0
  274. package/dist/runSubscriber-BHvJ8POr.mjs.map +1 -0
  275. package/dist/runSubscriber-D8nLXIv1.cjs +126 -0
  276. package/dist/runSubscriber-D8nLXIv1.cjs.map +1 -0
  277. package/dist/shutdown-BMJmAhSt.cjs +38 -0
  278. package/dist/shutdown-BMJmAhSt.cjs.map +1 -0
  279. package/dist/shutdown-C7xa8x9S.mjs +27 -0
  280. package/dist/shutdown-C7xa8x9S.mjs.map +1 -0
  281. package/dist/site.cjs +35 -9
  282. package/dist/site.cjs.map +1 -1
  283. package/dist/site.d.cts +25 -22
  284. package/dist/site.d.cts.map +1 -1
  285. package/dist/site.d.mts +25 -22
  286. package/dist/site.d.mts.map +1 -1
  287. package/dist/site.mjs +31 -5
  288. package/dist/site.mjs.map +1 -1
  289. package/dist/stages-BSCF19o2.d.cts +56 -0
  290. package/dist/stages-BSCF19o2.d.cts.map +1 -0
  291. package/dist/stages-BSCF19o2.d.mts +56 -0
  292. package/dist/stages-BSCF19o2.d.mts.map +1 -0
  293. package/dist/subscribers/index.cjs +111 -101
  294. package/dist/subscribers/index.cjs.map +1 -1
  295. package/dist/subscribers/index.d.cts +44 -56
  296. package/dist/subscribers/index.d.cts.map +1 -1
  297. package/dist/subscribers/index.d.mts +44 -56
  298. package/dist/subscribers/index.d.mts.map +1 -1
  299. package/dist/subscribers/index.mjs +108 -98
  300. package/dist/subscribers/index.mjs.map +1 -1
  301. package/dist/surfaceEnv-CNimK76p.cjs +56 -0
  302. package/dist/surfaceEnv-CNimK76p.cjs.map +1 -0
  303. package/dist/surfaceEnv-wMT5QzgZ.mjs +45 -0
  304. package/dist/surfaceEnv-wMT5QzgZ.mjs.map +1 -0
  305. package/dist/telemetry-B48RLjyk.d.cts +40 -0
  306. package/dist/telemetry-B48RLjyk.d.cts.map +1 -0
  307. package/dist/telemetry-DRtT1_0A.d.mts +40 -0
  308. package/dist/telemetry-DRtT1_0A.d.mts.map +1 -0
  309. package/dist/telemetry.cjs +56 -0
  310. package/dist/telemetry.cjs.map +1 -0
  311. package/dist/telemetry.d.cts +2 -0
  312. package/dist/telemetry.d.mts +2 -0
  313. package/dist/telemetry.mjs +55 -0
  314. package/dist/telemetry.mjs.map +1 -0
  315. package/dist/topic/index.cjs +3 -137
  316. package/dist/topic/index.d.cts +2 -32
  317. package/dist/topic/index.d.mts +2 -32
  318. package/dist/topic/index.mjs +2 -134
  319. package/dist/tracing-CxaZ98IB.mjs +110 -0
  320. package/dist/tracing-CxaZ98IB.mjs.map +1 -0
  321. package/dist/tracing-DPMidF_r.cjs +127 -0
  322. package/dist/tracing-DPMidF_r.cjs.map +1 -0
  323. package/dist/{types-BlAkSuGI.d.cts → types-DMuSQeLL.d.cts} +3 -5
  324. package/dist/types-DMuSQeLL.d.cts.map +1 -0
  325. package/dist/{types-aKksMEWL.d.mts → types-DMuSQeLL.d.mts} +3 -5
  326. package/dist/types-DMuSQeLL.d.mts.map +1 -0
  327. package/dist/types.d.cts +1 -1
  328. package/dist/types.d.mts +1 -1
  329. package/dist/types.mjs +1 -0
  330. package/dist/worker.cjs +191 -0
  331. package/dist/worker.cjs.map +1 -0
  332. package/dist/worker.d.cts +171 -0
  333. package/dist/worker.d.cts.map +1 -0
  334. package/dist/worker.d.mts +171 -0
  335. package/dist/worker.d.mts.map +1 -0
  336. package/dist/worker.mjs +190 -0
  337. package/dist/worker.mjs.map +1 -0
  338. package/package.json +116 -70
  339. package/dist/AWSScheduledFunction-9bJS4WdJ.d.cts +0 -122
  340. package/dist/AWSScheduledFunction-9bJS4WdJ.d.cts.map +0 -1
  341. package/dist/AWSScheduledFunction-BJjj8B5V.mjs +0 -243
  342. package/dist/AWSScheduledFunction-BJjj8B5V.mjs.map +0 -1
  343. package/dist/AWSScheduledFunction-BO5iEMSh.d.mts +0 -122
  344. package/dist/AWSScheduledFunction-BO5iEMSh.d.mts.map +0 -1
  345. package/dist/AWSScheduledFunction-qu4ieRZR.cjs +0 -255
  346. package/dist/AWSScheduledFunction-qu4ieRZR.cjs.map +0 -1
  347. package/dist/Construct-B-xc0SE9.d.mts +0 -104
  348. package/dist/Construct-B-xc0SE9.d.mts.map +0 -1
  349. package/dist/Construct-CdhThxDI.mjs.map +0 -1
  350. package/dist/Construct-WhCXIOPV.d.cts +0 -104
  351. package/dist/Construct-WhCXIOPV.d.cts.map +0 -1
  352. package/dist/Construct-roId57cU.cjs.map +0 -1
  353. package/dist/Endpoint-BBkV6l0k.cjs.map +0 -1
  354. package/dist/Endpoint-BKR5QH6O.d.mts.map +0 -1
  355. package/dist/Endpoint-BQ9O0P1w.d.cts.map +0 -1
  356. package/dist/Endpoint-BTj58Gob.mjs.map +0 -1
  357. package/dist/EndpointFactory-BejSTzbB.mjs.map +0 -1
  358. package/dist/EndpointFactory-DYoGLaIT.cjs.map +0 -1
  359. package/dist/HonoEndpointAdaptor-7aYNdqJq.mjs.map +0 -1
  360. package/dist/HonoEndpointAdaptor-wMsCyMgt.cjs.map +0 -1
  361. package/dist/Queue-D6WeziRD.d.cts.map +0 -1
  362. package/dist/Queue-DpUeqdC8.d.mts.map +0 -1
  363. package/dist/Subscriber-4rBJgDKI.d.mts.map +0 -1
  364. package/dist/Subscriber-DVQowdyj.d.cts.map +0 -1
  365. package/dist/Topic-Ohx9dvWr.d.cts +0 -91
  366. package/dist/Topic-Ohx9dvWr.d.cts.map +0 -1
  367. package/dist/Topic-cmy2jOUy.d.mts +0 -91
  368. package/dist/Topic-cmy2jOUy.d.mts.map +0 -1
  369. package/dist/auth.d.cts.map +0 -1
  370. package/dist/auth.d.mts.map +0 -1
  371. package/dist/cache-0ANvRQnD.mjs +0 -51
  372. package/dist/cache-0ANvRQnD.mjs.map +0 -1
  373. package/dist/cache-3WSvAulx.cjs +0 -57
  374. package/dist/cache-3WSvAulx.cjs.map +0 -1
  375. package/dist/cache-CdQ7OLpR.d.cts.map +0 -1
  376. package/dist/cache-DYoJFcfd.d.mts.map +0 -1
  377. package/dist/clone-DblgEZZa.mjs.map +0 -1
  378. package/dist/clone-Dy0cR2SZ.cjs.map +0 -1
  379. package/dist/construct-interface-BfjcOD_E.cjs +0 -117
  380. package/dist/construct-interface-BfjcOD_E.cjs.map +0 -1
  381. package/dist/construct-interface-BqwRNYA2.d.mts.map +0 -1
  382. package/dist/construct-interface-D2nNkHUN.d.cts.map +0 -1
  383. package/dist/construct-interface-Z4CpS8tK.mjs +0 -81
  384. package/dist/construct-interface-Z4CpS8tK.mjs.map +0 -1
  385. package/dist/database/kysely.cjs.map +0 -1
  386. package/dist/database/kysely.d.cts.map +0 -1
  387. package/dist/database/kysely.d.mts.map +0 -1
  388. package/dist/database/kysely.mjs.map +0 -1
  389. package/dist/functions-Cpff1uZH.mjs.map +0 -1
  390. package/dist/functions-DukjG8ov.cjs.map +0 -1
  391. package/dist/index-BTvozlUD.d.cts +0 -163
  392. package/dist/index-BTvozlUD.d.cts.map +0 -1
  393. package/dist/index-Cvz551AO.d.mts.map +0 -1
  394. package/dist/index-D5zqAJ2e.d.cts.map +0 -1
  395. package/dist/index-L7pz0R0T.d.mts +0 -162
  396. package/dist/index-L7pz0R0T.d.mts.map +0 -1
  397. package/dist/lazyAccessors-DM6HcXQk.mjs.map +0 -1
  398. package/dist/lazyAccessors-DrJj8NpA.cjs.map +0 -1
  399. package/dist/processAudits-Bc8rz6Ev.cjs +0 -92
  400. package/dist/processAudits-Bc8rz6Ev.cjs.map +0 -1
  401. package/dist/processAudits-D89tICM4.mjs +0 -80
  402. package/dist/processAudits-D89tICM4.mjs.map +0 -1
  403. package/dist/publisher-CGEo8UKD.mjs +0 -41
  404. package/dist/publisher-CGEo8UKD.mjs.map +0 -1
  405. package/dist/publisher-CqGsXB2X.cjs +0 -53
  406. package/dist/publisher-CqGsXB2X.cjs.map +0 -1
  407. package/dist/queue/index.cjs.map +0 -1
  408. package/dist/queue/index.d.cts.map +0 -1
  409. package/dist/queue/index.d.mts.map +0 -1
  410. package/dist/queue/index.mjs.map +0 -1
  411. package/dist/surfaceEnv-BFXEms2f.cjs +0 -39
  412. package/dist/surfaceEnv-BFXEms2f.cjs.map +0 -1
  413. package/dist/surfaceEnv-C3Ktahea.mjs +0 -27
  414. package/dist/surfaceEnv-C3Ktahea.mjs.map +0 -1
  415. package/dist/telemetry-C3L0iS28.d.cts.map +0 -1
  416. package/dist/telemetry-D7bVFLGi.d.mts.map +0 -1
  417. package/dist/topic/index.cjs.map +0 -1
  418. package/dist/topic/index.d.cts.map +0 -1
  419. package/dist/topic/index.d.mts.map +0 -1
  420. package/dist/topic/index.mjs.map +0 -1
  421. package/dist/types-BlAkSuGI.d.cts.map +0 -1
  422. package/dist/types-aKksMEWL.d.mts.map +0 -1
package/dist/rest-api.mjs CHANGED
@@ -1,23 +1,19 @@
1
- import "./Construct-CdhThxDI.mjs";
2
- import { edgeTo } from "./construct-interface-Z4CpS8tK.mjs";
3
- import "./functions-Cpff1uZH.mjs";
4
- import { EndpointFactory } from "./EndpointFactory-BejSTzbB.mjs";
5
- import "./clone-DblgEZZa.mjs";
6
- import "./Endpoint-BTj58Gob.mjs";
7
- import { envParserFor } from "./surfaceEnv-C3Ktahea.mjs";
1
+ import { edgeTo } from "./construct-interface.mjs";
2
+ import { o as getSecurityScheme, t as EndpointFactory } from "./EndpointFactory-BDtsrEvJ.mjs";
3
+ import { n as envParserFor } from "./surfaceEnv-wMT5QzgZ.mjs";
8
4
  import { canonicalId, provideKey } from "@geekmidas/manifest";
9
5
  import { DEFAULT_LOGGER } from "@geekmidas/logger/console";
10
-
11
6
  //#region src/rest-api.ts
12
7
  /**
13
8
  * What is *not* here, and why.
14
9
  *
15
- * `dependsOn`, `database`, `auditor` and `publisher` all inject a capability
10
+ * `dependsOn`, `database`, `auditor` and `.event(topic, …)` all inject a capability
16
11
  * into a handler. Putting one on the surface hands it to every route the
17
12
  * surface serves — a health check gets the database because a report needed it
18
13
  * — which is the thing least privilege forbids and the reason `.calls()` is not
19
- * spelled `dependsOn`. They belong to the endpoint, or to a factory branched
20
- * from `api.endpoints` for a group of endpoints that genuinely share them.
14
+ * spelled `dependsOn`. They belong to the endpoint, or to a branch —
15
+ * `api.database(db)` — for a group of endpoints that genuinely share them. A
16
+ * branch is a new factory; the surface config stays free of grants.
21
17
  *
22
18
  * `auth` is not here either: `.auth(construct)` already declares it, and a
23
19
  * second way to say the same thing is the duplication this whole model removes.
@@ -25,6 +21,9 @@ import { DEFAULT_LOGGER } from "@geekmidas/logger/console";
25
21
  * What is left is what the *process* is rather than what a route may reach.
26
22
  */
27
23
  var RestApi = class RestApi {
24
+ config;
25
+ dependencies;
26
+ authenticator;
28
27
  id;
29
28
  /**
30
29
  * Declared once and read by both `declare()` and anything that consumes this
@@ -51,6 +50,8 @@ var RestApi = class RestApi {
51
50
  envParser;
52
51
  /** The Telescope instance, when this surface was given one. */
53
52
  telescope;
53
+ /** What this surface's process emits, when it was given a `Telemetry`. */
54
+ telemetry;
54
55
  constructor(id, config, dependencies = [], authenticator) {
55
56
  this.config = config;
56
57
  this.dependencies = dependencies;
@@ -64,57 +65,84 @@ var RestApi = class RestApi {
64
65
  };
65
66
  this.logger = config.logger ?? DEFAULT_LOGGER;
66
67
  this.telescope = config.telescope;
68
+ this.telemetry = config.telemetry;
67
69
  this.envParser = envParserFor(config.envParser ? {
68
70
  id: canonical,
69
71
  envParser: config.envParser
70
72
  } : void 0);
71
- this.endpoints = new EndpointFactory({
73
+ this.#endpoints = new EndpointFactory({
72
74
  defaultLogger: this.logger,
73
- ...config.authorizers ? { availableAuthorizers: config.authorizers.map((name) => ({ name })) } : {},
75
+ ...config.authorizers ? { availableAuthorizers: config.authorizers.map((name) => {
76
+ const securityScheme = getSecurityScheme(name);
77
+ return securityScheme ? {
78
+ name,
79
+ securityScheme
80
+ } : { name };
81
+ }) } : {},
74
82
  ...config.defaultAuthorizer && config.defaultAuthorizer !== "none" ? { defaultAuthorizerName: config.defaultAuthorizer } : {},
75
83
  surface: {
76
84
  id: this.id,
77
- envParser: this.envParser
85
+ envParser: this.envParser,
86
+ ...authenticator ? { auth: authenticator } : {}
78
87
  }
79
88
  });
89
+ const endpoints = this.#endpoints;
90
+ this.get = endpoints.get.bind(endpoints);
91
+ this.post = endpoints.post.bind(endpoints);
92
+ this.put = endpoints.put.bind(endpoints);
93
+ this.patch = endpoints.patch.bind(endpoints);
94
+ this.delete = endpoints.delete.bind(endpoints);
95
+ this.options = endpoints.options.bind(endpoints);
96
+ this.database = endpoints.database.bind(endpoints);
97
+ this.session = endpoints.session.bind(endpoints);
98
+ this.auditor = endpoints.auditor.bind(endpoints);
99
+ this.actor = endpoints.actor.bind(endpoints);
100
+ this.authorizer = endpoints.authorizer.bind(endpoints);
101
+ this.authorize = endpoints.authorize.bind(endpoints);
102
+ this.rls = endpoints.rls.bind(endpoints);
103
+ this.route = endpoints.route.bind(endpoints);
80
104
  }
81
105
  /**
82
- * This surface's endpoint factory.
106
+ * This surface's endpoint factory, which every method below starts from.
83
107
  *
84
- * `api.get('/users')` is the short form and covers most routes. Reach for
85
- * this one when a *group* of endpoints shares something a single route would
86
- * otherwise repeat — a database, an auditor, a publisher:
108
+ * Private: a surface *is* where endpoints are built, so there is no second
109
+ * object to reach through first. `api.database(db)` said the same
110
+ * thing as `api.database(db)` with one more word to learn.
111
+ */
112
+ #endpoints;
113
+ /** `api.get('/users')` — one route on this surface. */
114
+ get;
115
+ post;
116
+ put;
117
+ patch;
118
+ delete;
119
+ options;
120
+ /**
121
+ * A branch for a *group* of endpoints that shares what a single route would
122
+ * otherwise repeat — a database, an auditor, a publisher, a session:
87
123
  *
88
124
  * ```ts
89
- * const audited = api.endpoints.database(db).auditor(AuditStore);
90
- * export const createUser = audited.post('/users').handle(...);
125
+ * export const router = api.database(database);
126
+ * export const createUser = router.post('/users').handle(({ db }) => …);
91
127
  * ```
92
128
  *
93
- * A factory branched from here keeps the surface, so its endpoints still
94
- * know which API serves them. That is deliberately narrower than putting the
95
- * same thing in the surface's own config: a group opts in, where a surface
96
- * would grant it to every route it serves.
129
+ * Each returns a new factory and leaves the surface as it was. That is the
130
+ * whole difference from putting the same thing in the surface's config: a
131
+ * group opts in, where the surface would grant it to every route it serves —
132
+ * a health check handed the database because a profile endpoint needed it.
133
+ *
134
+ * `dependsOn` is deliberately not here. It is per endpoint, and on the
135
+ * surface it would read as the API depending on something, which is what
136
+ * `.calls()` and `.auth()` say instead.
97
137
  */
98
- endpoints;
99
- /** `api.get('/users')` — sugar for `api.endpoints.get('/users')`. */
100
- get(path) {
101
- return this.endpoints.get(path);
102
- }
103
- post(path) {
104
- return this.endpoints.post(path);
105
- }
106
- put(path) {
107
- return this.endpoints.put(path);
108
- }
109
- patch(path) {
110
- return this.endpoints.patch(path);
111
- }
112
- delete(path) {
113
- return this.endpoints.delete(path);
114
- }
115
- options(path) {
116
- return this.endpoints.options(path);
117
- }
138
+ database;
139
+ session;
140
+ auditor;
141
+ actor;
142
+ authorizer;
143
+ authorize;
144
+ rls;
145
+ route;
118
146
  /**
119
147
  * What authenticates this surface.
120
148
  *
@@ -124,13 +152,14 @@ var RestApi = class RestApi {
124
152
  * what a request is allowed to be. A surface with two of the first is a
125
153
  * mistake; two of the second is Tuesday.
126
154
  *
127
- * It records the id, not a client. Every endpoint consumes the same thing —
128
- * `verify(request) → Session | null` — and that is what every provider
129
- * shares, whether the server is mounted in this process, deployed beside it,
130
- * or an OIDC issuer somebody else runs.
155
+ * It declares the id, and keeps the construct: a session callback reads from
156
+ * it as `auth` — `session(async ({ auth }) => auth.getSession())` — which
157
+ * calls the construct's `verify(headers)`. That is the one thing every
158
+ * provider shares, whether the server is mounted in this process, deployed
159
+ * beside it, or an OIDC issuer somebody else runs.
131
160
  */
132
161
  auth(construct) {
133
- return new RestApi(this.id, this.config, [...this.dependencies, edgeTo(construct)], construct.id);
162
+ return new RestApi(this.id, this.config, [...this.dependencies, edgeTo(construct)], construct);
134
163
  }
135
164
  /**
136
165
  * Other surfaces this one calls.
@@ -162,14 +191,14 @@ var RestApi = class RestApi {
162
191
  return [{
163
192
  kind: "rest-api",
164
193
  id: this.id,
165
- app: {
166
- ...this.config.app,
167
- ...this.config.telescope ? { telescope: true } : {}
168
- },
194
+ path: this.config.path,
195
+ ...this.config.subdomain ? { subdomain: this.config.subdomain } : {},
196
+ ...this.config.telescope ? { telescope: true } : {},
169
197
  ...this.config.cors ? { cors: this.config.cors } : {},
170
- ...this.authenticator ? { auth: this.authenticator } : {},
198
+ ...this.authenticator ? { auth: this.authenticator.id } : {},
171
199
  endpoints: [],
172
200
  ...this.dependencies.length ? { calls: this.dependencies } : {},
201
+ ...this.config.telemetry ? { telemetry: this.config.telemetry.id } : {},
173
202
  ...this.config.authorizers?.length ? { authorizers: this.config.authorizers } : {},
174
203
  defaultAuthorizer: this.config.defaultAuthorizer,
175
204
  provides: [
@@ -180,7 +209,7 @@ var RestApi = class RestApi {
180
209
  }];
181
210
  }
182
211
  };
183
-
184
212
  //#endregion
185
213
  export { RestApi };
214
+
186
215
  //# sourceMappingURL=rest-api.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"rest-api.mjs","names":["id: ConstructName<TName>","config: RestApiConfig<TAuthorizers>","dependencies: readonly Dependency[]","authenticator?: string","path: TPath","construct: Declarable","constructs: readonly Declarable[]"],"sources":["../src/rest-api.ts"],"sourcesContent":["/**\n * `RestApi` — the application's own HTTP surface, declared.\n *\n * Everything an app serves already existed; what did not exist was a *node* for\n * it. Without one, three things that are properties of the graph had to be\n * written down somewhere else: which origins the API accepts, which origins the\n * auth server trusts, and which URL a frontend is built against. All three were\n * being derived by walking the workspace config for ports — a second mechanism,\n * running beside the graph and answering the same question worse, since it can\n * only ever describe what this repo happens to run.\n *\n * With the surface declared, all three become one edge read backwards: a\n * consumer depends on the API, and *that* is the CORS entry, the trusted origin,\n * and the build-time URL. Nothing enumerates its own callers.\n *\n * ```ts\n * export const api = new RestApi('Api', {\n * authorizers: ['session'],\n * defaultAuthorizer: 'session',\n * });\n * ```\n */\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { DEFAULT_LOGGER } from '@geekmidas/logger/console';\nimport {\n\ttype AppSpec,\n\ttype ConstructName,\n\tcanonicalId,\n\ttype Declaration,\n\ttype Dependency,\n\tprovideKey,\n} from '@geekmidas/manifest';\nimport type { Telescope } from '@geekmidas/telescope';\nimport { type Declarable, edgeTo } from './construct-interface';\nimport type { BuiltInSecuritySchemeId } from './endpoints/Authorizer';\nimport { EndpointFactory } from './endpoints/EndpointFactory';\nimport { envParserFor } from './endpoints/surfaceEnv';\n\nexport interface RestApiConfig<\n\t// `readonly []` rather than `readonly string[]`: a surface that declares no\n\t// authorizers of its own should narrow `defaultAuthorizer` to the built-ins\n\t// and `'none'`, not widen it back to any string.\n\tTAuthorizers extends readonly string[] = readonly [],\n> {\n\t/**\n\t * The app that serves this surface: where its source lives, which globs\n\t * find its code, how it is run.\n\t *\n\t * What makes a surface a deploy unit rather than something a deploy has to\n\t * be told about separately: one `RestApi` is one server. A `StaticSite` says\n\t * the same thing, and the two are the same kind of statement.\n\t *\n\t * Normally omitted. One RestApi is one server, always — there is no mode in\n\t * which a surface shares somebody else's container, because a surface that\n\t * gets its process by inference gets it from whatever happened to reference\n\t * it, and that was the thing worth removing.\n\t *\n\t * So this is an override and nothing else. Everything in it follows from\n\t * this construct's id — `apps/<kebab-id>` where that directory exists, the\n\t * conventional code directories under it, a port assigned in a stable\n\t * order. Write one when the layout genuinely differs:\n\t * `app: { path: 'services/api' }`.\n\t */\n\tapp?: AppSpec;\n\t/**\n\t * CORS tunables. The *origins* are never here — they are read off the\n\t * constructs that declared an edge to this surface, which is the whole point\n\t * of declaring one. These are the parts a graph cannot answer.\n\t */\n\tcors?: {\n\t\tmaxAge?: number;\n\t\tcredentials?: boolean;\n\t\tallowHeaders?: readonly string[];\n\t\texposeHeaders?: readonly string[];\n\t};\n\t/**\n\t * The authorizer names this surface exposes. Names only — what verifies a\n\t * request legitimately differs between local and deployed, so the mechanism\n\t * belongs to the target and never to portable code.\n\t */\n\tauthorizers?: TAuthorizers;\n\t/**\n\t * The authorizer applied to an endpoint that names none.\n\t *\n\t * Required, and `'none'` is a valid answer that has to be typed out. The\n\t * alternative is an API that ships open because a field was left off, which\n\t * is the one default worth refusing to have.\n\t *\n\t * It was called `default`, which said what it was to the type and nothing\n\t * to the reader: next to `authorizers: ['iam']`, a bare `default: 'none'`\n\t * could be defaulting the runtime or the target. The manifest has always\n\t * called it `defaultAuthorizer` and the factory `defaultAuthorizerName`;\n\t * this is the same fact under the same name.\n\t *\n\t * Typed from `authorizers`, so it can only name one this surface exposes —\n\t * plus a built-in scheme, and `'none'`. It was a bare `string`, which let\n\t * `defaultAuthorizer: 'jwtt'` compile and every endpoint on the surface\n\t * default to an authorizer that does not exist.\n\t */\n\tdefaultAuthorizer: TAuthorizers[number] | BuiltInSecuritySchemeId | 'none';\n\t/**\n\t * The logger every endpoint on this surface runs with.\n\t *\n\t * The actual logger, not a path to one. It used to be named in config as\n\t * `logger: './config/logger'`, because the build wrote an import into each\n\t * generated handler and a generator can print a specifier but not an object.\n\t * Endpoints built from the surface carry it, so there is nothing to print\n\t * and nothing to keep in step with a moved file.\n\t */\n\tlogger?: Logger;\n\t/**\n\t * The environment parser every endpoint on this surface runs with.\n\t *\n\t * Same reason as `logger`, and the same field it replaces —\n\t * `envParser: './config/env#envParser'`, a module path with an export name\n\t * appended, parsed by us, checked by nothing.\n\t */\n\tenvParser?: EnvironmentParser<{}>;\n\t/**\n\t * The Telescope instance this surface's entry mounts.\n\t *\n\t * The actual instance, for the reason `logger` is: it used to be named as\n\t * `telescope: './config/telescope#telescope'`, a module path the build\n\t * printed an import for. The entry already imports the surface.\n\t */\n\ttelescope?: Telescope;\n}\n\n/**\n * What is *not* here, and why.\n *\n * `dependsOn`, `database`, `auditor` and `publisher` all inject a capability\n * into a handler. Putting one on the surface hands it to every route the\n * surface serves — a health check gets the database because a report needed it\n * — which is the thing least privilege forbids and the reason `.calls()` is not\n * spelled `dependsOn`. They belong to the endpoint, or to a factory branched\n * from `api.endpoints` for a group of endpoints that genuinely share them.\n *\n * `auth` is not here either: `.auth(construct)` already declares it, and a\n * second way to say the same thing is the duplication this whole model removes.\n *\n * What is left is what the *process* is rather than what a route may reach.\n */\n\nexport class RestApi<\n\tTName extends string = string,\n\tconst TAuthorizers extends readonly string[] = readonly [],\n> implements Declarable<TName>\n{\n\treadonly id: TName;\n\n\t/**\n\t * Declared once and read by both `declare()` and anything that consumes this\n\t * surface, so what the target publishes and what a consumer reads cannot\n\t * drift.\n\t */\n\treadonly keys: {\n\t\turl: string;\n\t\ttrustedOrigins: string;\n\t\tcookieDomain: string;\n\t};\n\n\t/**\n\t * The logger every endpoint on this surface runs with.\n\t *\n\t * Always defined — the surface's own if it was given one, the console\n\t * logger otherwise — so nothing downstream has to decide what to do about a\n\t * missing one. The generated entry reads it from here.\n\t */\n\treadonly logger: Logger;\n\n\t/**\n\t * The environment parser every endpoint on this surface runs with.\n\t *\n\t * Always defined, and normally the default: `process.env` merged with the\n\t * credentials `gkm dev`/`gkm exec` injected. That is what every\n\t * application's own `config/env.ts` was — boilerplate identical in every\n\t * project, and mandatory, which is a poor combination.\n\t */\n\treadonly envParser: EnvironmentParser<{}>;\n\n\t/** The Telescope instance, when this surface was given one. */\n\treadonly telescope?: Telescope;\n\n\tconstructor(\n\t\tid: ConstructName<TName>,\n\t\tprivate readonly config: RestApiConfig<TAuthorizers>,\n\t\t/** Internal: how `.calls()` carries edges into the copy it returns. */\n\t\tprivate readonly dependencies: readonly Dependency[] = [],\n\t\t/** Internal: how `.auth()` carries the authenticator into its copy. */\n\t\tprivate readonly authenticator?: string,\n\t) {\n\t\tconst canonical = canonicalId(id as string);\n\n\t\tthis.id = canonical as TName;\n\n\t\tthis.keys = {\n\t\t\turl: provideKey(canonical, 'url'),\n\t\t\ttrustedOrigins: provideKey(canonical, 'trustedOrigins'),\n\t\t\tcookieDomain: provideKey(canonical, 'cookieDomain'),\n\t\t};\n\n\t\tthis.logger = config.logger ?? DEFAULT_LOGGER;\n\t\tthis.telescope = config.telescope;\n\t\tthis.envParser = envParserFor(\n\t\t\tconfig.envParser\n\t\t\t\t? { id: canonical, envParser: config.envParser }\n\t\t\t\t: undefined,\n\t\t);\n\n\t\tthis.endpoints = new EndpointFactory({\n\t\t\tdefaultLogger: this.logger,\n\t\t\t...(config.authorizers\n\t\t\t\t? {\n\t\t\t\t\t\tavailableAuthorizers: config.authorizers.map((name) => ({ name })),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t// `'none'` reaches the factory as no default at all, which is what\n\t\t\t// public means to an endpoint that names no authorizer.\n\t\t\t...(config.defaultAuthorizer && config.defaultAuthorizer !== 'none'\n\t\t\t\t? { defaultAuthorizerName: config.defaultAuthorizer }\n\t\t\t\t: {}),\n\t\t\tsurface: { id: this.id, envParser: this.envParser },\n\t\t});\n\t}\n\n\t/**\n\t * This surface's endpoint factory.\n\t *\n\t * `api.get('/users')` is the short form and covers most routes. Reach for\n\t * this one when a *group* of endpoints shares something a single route would\n\t * otherwise repeat — a database, an auditor, a publisher:\n\t *\n\t * ```ts\n\t * const audited = api.endpoints.database(db).auditor(AuditStore);\n\t * export const createUser = audited.post('/users').handle(...);\n\t * ```\n\t *\n\t * A factory branched from here keeps the surface, so its endpoints still\n\t * know which API serves them. That is deliberately narrower than putting the\n\t * same thing in the surface's own config: a group opts in, where a surface\n\t * would grant it to every route it serves.\n\t */\n\treadonly endpoints: EndpointFactory<[], '', Logger>;\n\n\t/** `api.get('/users')` — sugar for `api.endpoints.get('/users')`. */\n\tget<TPath extends string>(path: TPath) {\n\t\treturn this.endpoints.get(path);\n\t}\n\n\tpost<TPath extends string>(path: TPath) {\n\t\treturn this.endpoints.post(path);\n\t}\n\n\tput<TPath extends string>(path: TPath) {\n\t\treturn this.endpoints.put(path);\n\t}\n\n\tpatch<TPath extends string>(path: TPath) {\n\t\treturn this.endpoints.patch(path);\n\t}\n\n\tdelete<TPath extends string>(path: TPath) {\n\t\treturn this.endpoints.delete(path);\n\t}\n\n\toptions<TPath extends string>(path: TPath) {\n\t\treturn this.endpoints.options(path);\n\t}\n\n\t/**\n\t * What authenticates this surface.\n\t *\n\t * An edge like `.calls()` — the auth server learns this origin, and the two\n\t * share a cookie domain — but a named one, because *who authenticates me* is\n\t * a different fact from *who I happen to call*, and only one of them decides\n\t * what a request is allowed to be. A surface with two of the first is a\n\t * mistake; two of the second is Tuesday.\n\t *\n\t * It records the id, not a client. Every endpoint consumes the same thing —\n\t * `verify(request) → Session | null` — and that is what every provider\n\t * shares, whether the server is mounted in this process, deployed beside it,\n\t * or an OIDC issuer somebody else runs.\n\t */\n\tauth(construct: Declarable): RestApi<TName, TAuthorizers> {\n\t\treturn new RestApi<TName, TAuthorizers>(\n\t\t\tthis.id as ConstructName<TName>,\n\t\t\tthis.config,\n\t\t\t[...this.dependencies, edgeTo(construct)],\n\t\t\tconstruct.id,\n\t\t);\n\t}\n\n\t/**\n\t * Other surfaces this one calls.\n\t *\n\t * **Not `.dependsOn()`, and the difference matters.** An endpoint's\n\t * `.dependsOn()` injects a client into that handler and grants it exactly\n\t * what it named. This grants nothing and injects nothing: it records that\n\t * this API calls another surface, which is what puts this API's origin on\n\t * that surface's trusted-origin list.\n\t *\n\t * Spelling it `dependsOn` would invite the thing least privilege forbids —\n\t * every route on the surface receiving whatever the surface named.\n\t *\n\t * Immutable, like every other builder here.\n\t */\n\tcalls(constructs: readonly Declarable[]): RestApi<TName, TAuthorizers> {\n\t\treturn new RestApi<TName, TAuthorizers>(\n\t\t\tthis.id as ConstructName<TName>,\n\t\t\tthis.config,\n\t\t\t[...this.dependencies, ...constructs.map(edgeTo)],\n\t\t\tthis.authenticator,\n\t\t);\n\t}\n\n\t/**\n\t * One surface node, with its endpoints left to the build.\n\t *\n\t * The three provided keys are one fact about this surface and two about its\n\t * callers. Declaring the caller-derived pair here rather than having the\n\t * target invent them is what makes the contract checkable: a target that\n\t * resolves no origins is caught against this list instead of being noticed\n\t * when a browser is refused in production.\n\t */\n\tdeclare(): Declaration[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: 'rest-api',\n\t\t\t\tid: this.id,\n\t\t\t\tapp: {\n\t\t\t\t\t...this.config.app,\n\t\t\t\t\t...(this.config.telescope ? { telescope: true } : {}),\n\t\t\t\t},\n\t\t\t\t...(this.config.cors ? { cors: this.config.cors } : {}),\n\t\t\t\t...(this.authenticator ? { auth: this.authenticator } : {}),\n\t\t\t\t// Filled by the build, which already generates one handler per\n\t\t\t\t// endpoint and knows the path it wrote it to. A surface that\n\t\t\t\t// enumerates its own routes statically — an auth server's single\n\t\t\t\t// wildcard — puts them here instead.\n\t\t\t\tendpoints: [],\n\t\t\t\t...(this.dependencies.length ? { calls: this.dependencies } : {}),\n\t\t\t\t...(this.config.authorizers?.length\n\t\t\t\t\t? { authorizers: this.config.authorizers }\n\t\t\t\t\t: {}),\n\t\t\t\tdefaultAuthorizer: this.config.defaultAuthorizer,\n\t\t\t\tprovides: [\n\t\t\t\t\tthis.keys.url,\n\t\t\t\t\tthis.keys.trustedOrigins,\n\t\t\t\t\tthis.keys.cookieDomain,\n\t\t\t\t],\n\t\t\t},\n\t\t];\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAkJA,IAAa,UAAb,MAAa,QAIb;CACC,AAAS;;;;;;CAOT,AAAS;;;;;;;;CAaT,AAAS;;;;;;;;;CAUT,AAAS;;CAGT,AAAS;CAET,YACCA,IACiBC,QAEAC,eAAsC,CAAE,GAExCC,eAChB;EALgB;EAEA;EAEA;EAEjB,MAAM,YAAY,YAAY,GAAa;AAE3C,OAAK,KAAK;AAEV,OAAK,OAAO;GACX,KAAK,WAAW,WAAW,MAAM;GACjC,gBAAgB,WAAW,WAAW,iBAAiB;GACvD,cAAc,WAAW,WAAW,eAAe;EACnD;AAED,OAAK,SAAS,OAAO,UAAU;AAC/B,OAAK,YAAY,OAAO;AACxB,OAAK,YAAY,aAChB,OAAO,YACJ;GAAE,IAAI;GAAW,WAAW,OAAO;EAAW,WAEjD;AAED,OAAK,YAAY,IAAI,gBAAgB;GACpC,eAAe,KAAK;GACpB,GAAI,OAAO,cACR,EACA,sBAAsB,OAAO,YAAY,IAAI,CAAC,UAAU,EAAE,KAAM,GAAE,CAClE,IACA,CAAE;GAGL,GAAI,OAAO,qBAAqB,OAAO,sBAAsB,SAC1D,EAAE,uBAAuB,OAAO,kBAAmB,IACnD,CAAE;GACL,SAAS;IAAE,IAAI,KAAK;IAAI,WAAW,KAAK;GAAW;EACnD;CACD;;;;;;;;;;;;;;;;;;CAmBD,AAAS;;CAGT,IAA0BC,MAAa;AACtC,SAAO,KAAK,UAAU,IAAI,KAAK;CAC/B;CAED,KAA2BA,MAAa;AACvC,SAAO,KAAK,UAAU,KAAK,KAAK;CAChC;CAED,IAA0BA,MAAa;AACtC,SAAO,KAAK,UAAU,IAAI,KAAK;CAC/B;CAED,MAA4BA,MAAa;AACxC,SAAO,KAAK,UAAU,MAAM,KAAK;CACjC;CAED,OAA6BA,MAAa;AACzC,SAAO,KAAK,UAAU,OAAO,KAAK;CAClC;CAED,QAA8BA,MAAa;AAC1C,SAAO,KAAK,UAAU,QAAQ,KAAK;CACnC;;;;;;;;;;;;;;;CAgBD,KAAKC,WAAqD;AACzD,SAAO,IAAI,QACV,KAAK,IACL,KAAK,QACL,CAAC,GAAG,KAAK,cAAc,OAAO,UAAU,AAAC,GACzC,UAAU;CAEX;;;;;;;;;;;;;;;CAgBD,MAAMC,YAAiE;AACtE,SAAO,IAAI,QACV,KAAK,IACL,KAAK,QACL,CAAC,GAAG,KAAK,cAAc,GAAG,WAAW,IAAI,OAAO,AAAC,GACjD,KAAK;CAEN;;;;;;;;;;CAWD,UAAyB;AACxB,SAAO,CACN;GACC,MAAM;GACN,IAAI,KAAK;GACT,KAAK;IACJ,GAAG,KAAK,OAAO;IACf,GAAI,KAAK,OAAO,YAAY,EAAE,WAAW,KAAM,IAAG,CAAE;GACpD;GACD,GAAI,KAAK,OAAO,OAAO,EAAE,MAAM,KAAK,OAAO,KAAM,IAAG,CAAE;GACtD,GAAI,KAAK,gBAAgB,EAAE,MAAM,KAAK,cAAe,IAAG,CAAE;GAK1D,WAAW,CAAE;GACb,GAAI,KAAK,aAAa,SAAS,EAAE,OAAO,KAAK,aAAc,IAAG,CAAE;GAChE,GAAI,KAAK,OAAO,aAAa,SAC1B,EAAE,aAAa,KAAK,OAAO,YAAa,IACxC,CAAE;GACL,mBAAmB,KAAK,OAAO;GAC/B,UAAU;IACT,KAAK,KAAK;IACV,KAAK,KAAK;IACV,KAAK,KAAK;GACV;EACD,CACD;CACD;AACD"}
1
+ {"version":3,"file":"rest-api.mjs","names":[],"sources":["../src/rest-api.ts"],"sourcesContent":["/**\n * `RestApi` — the application's own HTTP surface, declared.\n *\n * Everything an app serves already existed; what did not exist was a *node* for\n * it. Without one, three things that are properties of the graph had to be\n * written down somewhere else: which origins the API accepts, which origins the\n * auth server trusts, and which URL a frontend is built against. All three were\n * being derived by walking the workspace config for ports — a second mechanism,\n * running beside the graph and answering the same question worse, since it can\n * only ever describe what this repo happens to run.\n *\n * With the surface declared, all three become one edge read backwards: a\n * consumer depends on the API, and *that* is the CORS entry, the trusted origin,\n * and the build-time URL. Nothing enumerates its own callers.\n *\n * ```ts\n * export const api = new RestApi('Api', {\n * authorizers: ['session'],\n * defaultAuthorizer: 'session',\n * });\n * ```\n */\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { DEFAULT_LOGGER } from '@geekmidas/logger/console';\nimport {\n\ttype ConstructName,\n\tcanonicalId,\n\ttype Declaration,\n\ttype Dependency,\n\tprovideKey,\n} from '@geekmidas/manifest';\nimport type { Telescope } from '@geekmidas/telescope';\nimport {\n\ttype Authenticator,\n\ttype Declarable,\n\tedgeTo,\n} from './construct-interface';\n\nexport type { Authenticator } from './construct-interface';\n\nimport {\n\ttype BuiltInSecuritySchemeId,\n\tgetSecurityScheme,\n} from './endpoints/Authorizer';\nimport { EndpointFactory } from './endpoints/EndpointFactory';\nimport { envParserFor } from './endpoints/surfaceEnv';\nimport type { Telemetry } from './telemetry';\n\n/** The factory a surface builds its endpoints from. */\ntype Endpoints = EndpointFactory<[], '', Logger>;\n\nexport interface RestApiConfig<\n\t// `readonly []` rather than `readonly string[]`: a surface that declares no\n\t// authorizers of its own should narrow `defaultAuthorizer` to the built-ins\n\t// and `'none'`, not widen it back to any string.\n\tTAuthorizers extends readonly string[] = readonly [],\n> {\n\t/**\n\t * The app that serves this surface, relative to the workspace root —\n\t * `'apps/api'`, or `'.'` in a single-app project.\n\t *\n\t * Required. It was inferred from the id (`apps/<kebab-id>`, or the root\n\t * when no such directory existed), which meant a surface's home was\n\t * whatever happened to be on disk. It is where the app's `package.json`\n\t * and base `tsconfig.json` are, and which build serves this surface. It\n\t * does not change discovery: constructs still load from the workspace's\n\t * `constructs` glob.\n\t */\n\tpath: string;\n\t/**\n\t * The label it answers on under a stage's domain — `api` for\n\t * `api.myapp.com`, from `domains` — and under the project locally,\n\t * `api.myapp.localhost`. Absent, its id kebab-cased.\n\t */\n\tsubdomain?: string;\n\t/**\n\t * CORS tunables. The *origins* are never here — they are read off the\n\t * constructs that declared an edge to this surface, which is the whole point\n\t * of declaring one. These are the parts a graph cannot answer.\n\t */\n\tcors?: {\n\t\tmaxAge?: number;\n\t\tcredentials?: boolean;\n\t\tallowHeaders?: readonly string[];\n\t\texposeHeaders?: readonly string[];\n\t};\n\t/**\n\t * The authorizer names this surface exposes. Names only — what verifies a\n\t * request legitimately differs between local and deployed, so the mechanism\n\t * belongs to the target and never to portable code.\n\t */\n\tauthorizers?: TAuthorizers;\n\t/**\n\t * The authorizer applied to an endpoint that names none.\n\t *\n\t * Required, and `'none'` is a valid answer that has to be typed out. The\n\t * alternative is an API that ships open because a field was left off, which\n\t * is the one default worth refusing to have.\n\t *\n\t * It was called `default`, which said what it was to the type and nothing\n\t * to the reader: next to `authorizers: ['iam']`, a bare `default: 'none'`\n\t * could be defaulting the runtime or the target. The manifest has always\n\t * called it `defaultAuthorizer` and the factory `defaultAuthorizerName`;\n\t * this is the same fact under the same name.\n\t *\n\t * Typed from `authorizers`, so it can only name one this surface exposes —\n\t * plus a built-in scheme, and `'none'`. It was a bare `string`, which let\n\t * `defaultAuthorizer: 'jwtt'` compile and every endpoint on the surface\n\t * default to an authorizer that does not exist.\n\t */\n\tdefaultAuthorizer: TAuthorizers[number] | BuiltInSecuritySchemeId | 'none';\n\t/**\n\t * The logger every endpoint on this surface runs with.\n\t *\n\t * The actual logger, not a path to one. It used to be named in config as\n\t * `logger: './config/logger'`, because the build wrote an import into each\n\t * generated handler and a generator can print a specifier but not an object.\n\t * Endpoints built from the surface carry it, so there is nothing to print\n\t * and nothing to keep in step with a moved file.\n\t */\n\tlogger?: Logger;\n\t/**\n\t * The environment parser every endpoint on this surface runs with.\n\t *\n\t * Same reason as `logger`, and the same field it replaces —\n\t * `envParser: './config/env#envParser'`, a module path with an export name\n\t * appended, parsed by us, checked by nothing.\n\t */\n\tenvParser?: EnvironmentParser<{}>;\n\t/**\n\t * The Telescope instance this surface's entry mounts.\n\t *\n\t * The actual instance, for the reason `logger` is: it used to be named as\n\t * `telescope: './config/telescope#telescope'`, a module path the build\n\t * printed an import for. The entry already imports the surface.\n\t */\n\ttelescope?: Telescope;\n\t/**\n\t * What this surface's process emits — the `Telemetry` construct, passed\n\t * like the logger: a fact about the process, not a grant to a route.\n\t *\n\t * An edge to the node, so the deploy hands this process the `OTEL_*` keys\n\t * its stage resolves, and the build fails without the OpenTelemetry\n\t * packages. Where the telemetry goes is never here: it is the deploy's,\n\t * per stage.\n\t */\n\ttelemetry?: Telemetry;\n}\n\n/**\n * What is *not* here, and why.\n *\n * `dependsOn`, `database`, `auditor` and `.event(topic, …)` all inject a capability\n * into a handler. Putting one on the surface hands it to every route the\n * surface serves — a health check gets the database because a report needed it\n * — which is the thing least privilege forbids and the reason `.calls()` is not\n * spelled `dependsOn`. They belong to the endpoint, or to a branch —\n * `api.database(db)` — for a group of endpoints that genuinely share them. A\n * branch is a new factory; the surface config stays free of grants.\n *\n * `auth` is not here either: `.auth(construct)` already declares it, and a\n * second way to say the same thing is the duplication this whole model removes.\n *\n * What is left is what the *process* is rather than what a route may reach.\n */\n\nexport class RestApi<\n\tTName extends string = string,\n\tconst TAuthorizers extends readonly string[] = readonly [],\n> implements Declarable<TName>\n{\n\treadonly id: TName;\n\n\t/**\n\t * Declared once and read by both `declare()` and anything that consumes this\n\t * surface, so what the target publishes and what a consumer reads cannot\n\t * drift.\n\t */\n\treadonly keys: {\n\t\turl: string;\n\t\ttrustedOrigins: string;\n\t\tcookieDomain: string;\n\t};\n\n\t/**\n\t * The logger every endpoint on this surface runs with.\n\t *\n\t * Always defined — the surface's own if it was given one, the console\n\t * logger otherwise — so nothing downstream has to decide what to do about a\n\t * missing one. The generated entry reads it from here.\n\t */\n\treadonly logger: Logger;\n\n\t/**\n\t * The environment parser every endpoint on this surface runs with.\n\t *\n\t * Always defined, and normally the default: `process.env` merged with the\n\t * credentials `gkm dev`/`gkm exec` injected. That is what every\n\t * application's own `config/env.ts` was — boilerplate identical in every\n\t * project, and mandatory, which is a poor combination.\n\t */\n\treadonly envParser: EnvironmentParser<{}>;\n\n\t/** The Telescope instance, when this surface was given one. */\n\treadonly telescope?: Telescope;\n\n\t/** What this surface's process emits, when it was given a `Telemetry`. */\n\treadonly telemetry?: Telemetry;\n\n\tconstructor(\n\t\tid: ConstructName<TName>,\n\t\tprivate readonly config: RestApiConfig<TAuthorizers>,\n\t\t/** Internal: how `.calls()` carries edges into the copy it returns. */\n\t\tprivate readonly dependencies: readonly Dependency[] = [],\n\t\t/** Internal: how `.auth()` carries the authenticator into its copy. */\n\t\tprivate readonly authenticator?: Authenticator,\n\t) {\n\t\tconst canonical = canonicalId(id as string);\n\n\t\tthis.id = canonical as TName;\n\n\t\tthis.keys = {\n\t\t\turl: provideKey(canonical, 'url'),\n\t\t\ttrustedOrigins: provideKey(canonical, 'trustedOrigins'),\n\t\t\tcookieDomain: provideKey(canonical, 'cookieDomain'),\n\t\t};\n\n\t\tthis.logger = config.logger ?? DEFAULT_LOGGER;\n\t\tthis.telescope = config.telescope;\n\t\tthis.telemetry = config.telemetry;\n\t\tthis.envParser = envParserFor(\n\t\t\tconfig.envParser\n\t\t\t\t? { id: canonical, envParser: config.envParser }\n\t\t\t\t: undefined,\n\t\t);\n\n\t\tthis.#endpoints = new EndpointFactory({\n\t\t\tdefaultLogger: this.logger,\n\t\t\t...(config.authorizers\n\t\t\t\t? {\n\t\t\t\t\t\t// With the scheme a built-in name stands for, as the factory's own\n\t\t\t\t\t\t// `.authorizers()` resolves it. Bare names reached the OpenAPI\n\t\t\t\t\t\t// document with no scheme, so a guarded endpoint read as public.\n\t\t\t\t\t\tavailableAuthorizers: config.authorizers.map((name) => {\n\t\t\t\t\t\t\tconst securityScheme = getSecurityScheme(name);\n\t\t\t\t\t\t\treturn securityScheme ? { name, securityScheme } : { name };\n\t\t\t\t\t\t}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t// `'none'` reaches the factory as no default at all, which is what\n\t\t\t// public means to an endpoint that names no authorizer.\n\t\t\t...(config.defaultAuthorizer && config.defaultAuthorizer !== 'none'\n\t\t\t\t? { defaultAuthorizerName: config.defaultAuthorizer }\n\t\t\t\t: {}),\n\t\t\tsurface: {\n\t\t\t\tid: this.id,\n\t\t\t\tenvParser: this.envParser,\n\t\t\t\t...(authenticator ? { auth: authenticator } : {}),\n\t\t\t},\n\t\t});\n\n\t\tconst endpoints = this.#endpoints;\n\t\tthis.get = endpoints.get.bind(endpoints);\n\t\tthis.post = endpoints.post.bind(endpoints);\n\t\tthis.put = endpoints.put.bind(endpoints);\n\t\tthis.patch = endpoints.patch.bind(endpoints);\n\t\tthis.delete = endpoints.delete.bind(endpoints);\n\t\tthis.options = endpoints.options.bind(endpoints);\n\t\tthis.database = endpoints.database.bind(endpoints);\n\t\tthis.session = endpoints.session.bind(endpoints);\n\t\tthis.auditor = endpoints.auditor.bind(endpoints);\n\t\tthis.actor = endpoints.actor.bind(endpoints);\n\t\tthis.authorizer = endpoints.authorizer.bind(endpoints);\n\t\tthis.authorize = endpoints.authorize.bind(endpoints);\n\t\tthis.rls = endpoints.rls.bind(endpoints);\n\t\tthis.route = endpoints.route.bind(endpoints);\n\t}\n\n\t/**\n\t * This surface's endpoint factory, which every method below starts from.\n\t *\n\t * Private: a surface *is* where endpoints are built, so there is no second\n\t * object to reach through first. `api.database(db)` said the same\n\t * thing as `api.database(db)` with one more word to learn.\n\t */\n\treadonly #endpoints: Endpoints;\n\n\t/** `api.get('/users')` — one route on this surface. */\n\treadonly get: Endpoints['get'];\n\treadonly post: Endpoints['post'];\n\treadonly put: Endpoints['put'];\n\treadonly patch: Endpoints['patch'];\n\treadonly delete: Endpoints['delete'];\n\treadonly options: Endpoints['options'];\n\n\t/**\n\t * A branch for a *group* of endpoints that shares what a single route would\n\t * otherwise repeat — a database, an auditor, a publisher, a session:\n\t *\n\t * ```ts\n\t * export const router = api.database(database);\n\t * export const createUser = router.post('/users').handle(({ db }) => …);\n\t * ```\n\t *\n\t * Each returns a new factory and leaves the surface as it was. That is the\n\t * whole difference from putting the same thing in the surface's config: a\n\t * group opts in, where the surface would grant it to every route it serves —\n\t * a health check handed the database because a profile endpoint needed it.\n\t *\n\t * `dependsOn` is deliberately not here. It is per endpoint, and on the\n\t * surface it would read as the API depending on something, which is what\n\t * `.calls()` and `.auth()` say instead.\n\t */\n\treadonly database: Endpoints['database'];\n\treadonly session: Endpoints['session'];\n\treadonly auditor: Endpoints['auditor'];\n\treadonly actor: Endpoints['actor'];\n\treadonly authorizer: Endpoints['authorizer'];\n\treadonly authorize: Endpoints['authorize'];\n\treadonly rls: Endpoints['rls'];\n\treadonly route: Endpoints['route'];\n\n\t/**\n\t * What authenticates this surface.\n\t *\n\t * An edge like `.calls()` — the auth server learns this origin, and the two\n\t * share a cookie domain — but a named one, because *who authenticates me* is\n\t * a different fact from *who I happen to call*, and only one of them decides\n\t * what a request is allowed to be. A surface with two of the first is a\n\t * mistake; two of the second is Tuesday.\n\t *\n\t * It declares the id, and keeps the construct: a session callback reads from\n\t * it as `auth` — `session(async ({ auth }) => auth.getSession())` — which\n\t * calls the construct's `verify(headers)`. That is the one thing every\n\t * provider shares, whether the server is mounted in this process, deployed\n\t * beside it, or an OIDC issuer somebody else runs.\n\t */\n\tauth(construct: Authenticator): RestApi<TName, TAuthorizers> {\n\t\treturn new RestApi<TName, TAuthorizers>(\n\t\t\tthis.id as ConstructName<TName>,\n\t\t\tthis.config,\n\t\t\t[...this.dependencies, edgeTo(construct)],\n\t\t\tconstruct,\n\t\t);\n\t}\n\n\t/**\n\t * Other surfaces this one calls.\n\t *\n\t * **Not `.dependsOn()`, and the difference matters.** An endpoint's\n\t * `.dependsOn()` injects a client into that handler and grants it exactly\n\t * what it named. This grants nothing and injects nothing: it records that\n\t * this API calls another surface, which is what puts this API's origin on\n\t * that surface's trusted-origin list.\n\t *\n\t * Spelling it `dependsOn` would invite the thing least privilege forbids —\n\t * every route on the surface receiving whatever the surface named.\n\t *\n\t * Immutable, like every other builder here.\n\t */\n\tcalls(constructs: readonly Declarable[]): RestApi<TName, TAuthorizers> {\n\t\treturn new RestApi<TName, TAuthorizers>(\n\t\t\tthis.id as ConstructName<TName>,\n\t\t\tthis.config,\n\t\t\t[...this.dependencies, ...constructs.map(edgeTo)],\n\t\t\tthis.authenticator,\n\t\t);\n\t}\n\n\t/**\n\t * One surface node, with its endpoints left to the build.\n\t *\n\t * The three provided keys are one fact about this surface and two about its\n\t * callers. Declaring the caller-derived pair here rather than having the\n\t * target invent them is what makes the contract checkable: a target that\n\t * resolves no origins is caught against this list instead of being noticed\n\t * when a browser is refused in production.\n\t */\n\tdeclare(): Declaration[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: 'rest-api',\n\t\t\t\tid: this.id,\n\t\t\t\tpath: this.config.path,\n\t\t\t\t...(this.config.subdomain ? { subdomain: this.config.subdomain } : {}),\n\t\t\t\t...(this.config.telescope ? { telescope: true } : {}),\n\t\t\t\t...(this.config.cors ? { cors: this.config.cors } : {}),\n\t\t\t\t...(this.authenticator ? { auth: this.authenticator.id } : {}),\n\t\t\t\t// Filled by the build, which already generates one handler per\n\t\t\t\t// endpoint and knows the path it wrote it to. A surface that\n\t\t\t\t// enumerates its own routes statically — an auth server's single\n\t\t\t\t// wildcard — puts them here instead.\n\t\t\t\tendpoints: [],\n\t\t\t\t...(this.dependencies.length ? { calls: this.dependencies } : {}),\n\t\t\t\t...(this.config.telemetry\n\t\t\t\t\t? { telemetry: this.config.telemetry.id }\n\t\t\t\t\t: {}),\n\t\t\t\t...(this.config.authorizers?.length\n\t\t\t\t\t? { authorizers: this.config.authorizers }\n\t\t\t\t\t: {}),\n\t\t\t\tdefaultAuthorizer: this.config.defaultAuthorizer,\n\t\t\t\tprovides: [\n\t\t\t\t\tthis.keys.url,\n\t\t\t\t\tthis.keys.trustedOrigins,\n\t\t\t\t\tthis.keys.cookieDomain,\n\t\t\t\t],\n\t\t\t},\n\t\t];\n\t}\n}\n"],"mappings":"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"}
@@ -1,13 +1,11 @@
1
- //#region rolldown:runtime
1
+ //#region \0rolldown/runtime.js
2
2
  var __create = Object.create;
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __commonJS = (cb, mod) => function() {
9
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
- };
8
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
11
9
  var __copyProps = (to, from, except, desc) => {
12
10
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
13
11
  key = keys[i];
@@ -18,22 +16,20 @@ var __copyProps = (to, from, except, desc) => {
18
16
  }
19
17
  return to;
20
18
  };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
22
20
  value: mod,
23
21
  enumerable: true
24
22
  }) : target, mod));
25
-
26
23
  //#endregion
27
-
28
- Object.defineProperty(exports, '__commonJS', {
29
- enumerable: true,
30
- get: function () {
31
- return __commonJS;
32
- }
24
+ Object.defineProperty(exports, "__commonJSMin", {
25
+ enumerable: true,
26
+ get: function() {
27
+ return __commonJSMin;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "__toESM", {
31
+ enumerable: true,
32
+ get: function() {
33
+ return __toESM;
34
+ }
33
35
  });
34
- Object.defineProperty(exports, '__toESM', {
35
- enumerable: true,
36
- get: function () {
37
- return __toESM;
38
- }
39
- });
@@ -0,0 +1,109 @@
1
+ import { ServiceDiscovery } from "@geekmidas/services";
2
+ //#region src/subscribers/runSubscriber.ts
3
+ /** The subscriber's output did not match its `.output()` schema. */
4
+ var SubscriberOutputInvalid = class extends Error {
5
+ issues;
6
+ constructor(issues) {
7
+ super("Subscriber output validation failed: the handler's result does not match its .output() schema.");
8
+ this.issues = issues;
9
+ this.name = "SubscriberOutputInvalid";
10
+ }
11
+ };
12
+ /** The events in an SQS or SNS batch (a Lambda event's `Records`) that `subscriber` subscribed to. */
13
+ function subscribedEvents(subscriber, rawEvent, logger) {
14
+ const events = [];
15
+ const records = rawEvent.Records ?? [];
16
+ const first = records[0];
17
+ const parse = first?.eventSource === "aws:sqs" ? (record) => parseSQSRecord(record) : first?.EventSource === "aws:sns" ? (record) => parseSNSRecord(record) : void 0;
18
+ if (!parse) return events;
19
+ for (const record of records) try {
20
+ const event = parse(record);
21
+ if (isSubscribed(subscriber, event)) events.push(event);
22
+ } catch (error) {
23
+ logger.error({
24
+ err: error,
25
+ record
26
+ }, "Failed to parse record");
27
+ }
28
+ return events;
29
+ }
30
+ /** The subscriber's services and database, registered as functions do. */
31
+ async function subscriberContext(subscriber, envParser) {
32
+ const discovery = ServiceDiscovery.getInstance(envParser);
33
+ const services = subscriber.services.length > 0 ? await discovery.register(subscriber.services) : {};
34
+ const service = subscriber.databaseService;
35
+ return {
36
+ services,
37
+ db: service ? (await discovery.register([service]))[service.serviceName] : void 0
38
+ };
39
+ }
40
+ /** Runs the handler on `events`, and checks its output against its schema. */
41
+ async function runSubscriber(subscriber, context) {
42
+ if (context.events.length === 0) {
43
+ context.logger.info("No subscribed events to process");
44
+ return { batchItemFailures: [] };
45
+ }
46
+ const { events, services, db, logger } = context;
47
+ const result = await subscriber.handler({
48
+ events,
49
+ services,
50
+ logger,
51
+ db
52
+ });
53
+ if (subscriber.outputSchema && result) {
54
+ const validation = await subscriber.outputSchema["~standard"].validate(result);
55
+ if (validation.issues) {
56
+ context.logger.error({ issues: validation.issues }, "Subscriber output validation failed");
57
+ throw new SubscriberOutputInvalid(validation.issues);
58
+ }
59
+ return validation.value;
60
+ }
61
+ return result;
62
+ }
63
+ function isSubscribed(subscriber, event) {
64
+ if (typeof event !== "object" || !event?.type) return true;
65
+ if (!subscriber.subscribedEvents) return true;
66
+ return subscriber.subscribedEvents.includes(event.type);
67
+ }
68
+ function parseSNSRecord(record) {
69
+ const message = safeJsonParse(record.Sns.Message);
70
+ const messageType = record.Sns.MessageAttributes?.type?.Value;
71
+ if (message === null) return messageType ? {
72
+ type: messageType,
73
+ payload: record.Sns.Message
74
+ } : record.Sns.Message;
75
+ if (message.type) return message;
76
+ return messageType ? {
77
+ type: messageType,
78
+ payload: message
79
+ } : message;
80
+ }
81
+ function parseSQSRecord(record) {
82
+ const body = safeJsonParse(record.body);
83
+ if (body === null) return record.body;
84
+ if (body.Type === "Notification" && body.Message) {
85
+ const snsMessage = safeJsonParse(body.Message);
86
+ const messageType = body.MessageAttributes?.type?.Value;
87
+ if (snsMessage === null) return messageType ? {
88
+ type: messageType,
89
+ payload: body.Message
90
+ } : body.Message;
91
+ if (snsMessage.type) return snsMessage;
92
+ return messageType ? {
93
+ type: messageType,
94
+ payload: snsMessage
95
+ } : snsMessage;
96
+ }
97
+ return body;
98
+ }
99
+ function safeJsonParse(value) {
100
+ try {
101
+ return JSON.parse(value);
102
+ } catch {
103
+ return null;
104
+ }
105
+ }
106
+ //#endregion
107
+ export { subscribedEvents as n, subscriberContext as r, runSubscriber as t };
108
+
109
+ //# sourceMappingURL=runSubscriber-BHvJ8POr.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runSubscriber-BHvJ8POr.mjs","names":[],"sources":["../src/subscribers/runSubscriber.ts"],"sourcesContent":["/**\n * What a subscriber does with a batch of records, however they arrived: parse\n * them into events, keep the ones it subscribed to, and run its handler with\n * its services and database.\n *\n * Shared by the Lambda adaptor, which wraps it in middy, and the SNS push\n * adaptor, which a server runs and which must not need middy to load.\n */\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { ServiceDiscovery } from '@geekmidas/services';\nimport type { SNSEvent, SNSEventRecord, SQSEvent, SQSRecord } from 'aws-lambda';\nimport type { Subscriber } from './Subscriber';\n\ntype AnySubscriber = Subscriber<any, any, any, any, any, any, any>;\n\n/** The subscriber's output did not match its `.output()` schema. */\nexport class SubscriberOutputInvalid extends Error {\n\tconstructor(readonly issues: ReadonlyArray<unknown>) {\n\t\tsuper(\n\t\t\t\"Subscriber output validation failed: the handler's result does not match its .output() schema.\",\n\t\t);\n\t\tthis.name = 'SubscriberOutputInvalid';\n\t}\n}\n\n/** The events in an SQS or SNS batch (a Lambda event's `Records`) that `subscriber` subscribed to. */\nexport function subscribedEvents(\n\tsubscriber: AnySubscriber,\n\trawEvent: { Records?: readonly unknown[] },\n\tlogger: Logger,\n): any[] {\n\tconst events: any[] = [];\n\tconst records = rawEvent.Records ?? [];\n\tconst first = records[0] as any;\n\tconst parse =\n\t\tfirst?.eventSource === 'aws:sqs'\n\t\t\t? (record: any) => parseSQSRecord(record)\n\t\t\t: first?.EventSource === 'aws:sns'\n\t\t\t\t? (record: any) => parseSNSRecord(record)\n\t\t\t\t: undefined;\n\tif (!parse) return events;\n\n\tfor (const record of records) {\n\t\ttry {\n\t\t\tconst event = parse(record);\n\t\t\tif (isSubscribed(subscriber, event)) events.push(event);\n\t\t} catch (error) {\n\t\t\tlogger.error({ err: error, record }, 'Failed to parse record');\n\t\t}\n\t}\n\treturn events;\n}\n\n/** The subscriber's services and database, registered as functions do. */\nexport async function subscriberContext(\n\tsubscriber: AnySubscriber,\n\tenvParser: EnvironmentParser<{}>,\n): Promise<{ services: Record<string, unknown>; db: unknown }> {\n\tconst discovery = ServiceDiscovery.getInstance(envParser);\n\tconst services =\n\t\tsubscriber.services.length > 0\n\t\t\t? await discovery.register(subscriber.services)\n\t\t\t: {};\n\tconst service = subscriber.databaseService;\n\tconst db = service\n\t\t? (await discovery.register([service]))[service.serviceName]\n\t\t: undefined;\n\treturn { services, db };\n}\n\n/** Runs the handler on `events`, and checks its output against its schema. */\nexport async function runSubscriber(\n\tsubscriber: AnySubscriber,\n\tcontext: {\n\t\tevents: any[];\n\t\tservices: Record<string, unknown>;\n\t\tdb: unknown;\n\t\tlogger: Logger;\n\t},\n): Promise<unknown> {\n\tif (context.events.length === 0) {\n\t\tcontext.logger.info('No subscribed events to process');\n\t\treturn { batchItemFailures: [] };\n\t}\n\n\tconst { events, services, db, logger } = context;\n\tconst result = await subscriber.handler({\n\t\tevents,\n\t\tservices,\n\t\tlogger,\n\t\tdb,\n\t} as any);\n\n\tif (subscriber.outputSchema && result) {\n\t\tconst validation =\n\t\t\tawait subscriber.outputSchema['~standard'].validate(result);\n\t\tif (validation.issues) {\n\t\t\tcontext.logger.error(\n\t\t\t\t{ issues: validation.issues },\n\t\t\t\t'Subscriber output validation failed',\n\t\t\t);\n\t\t\tthrow new SubscriberOutputInvalid(validation.issues);\n\t\t}\n\t\treturn validation.value;\n\t}\n\n\treturn result;\n}\n\nfunction isSubscribed(subscriber: AnySubscriber, event: any): boolean {\n\t// No event type (raw string/non-object) — always include\n\tif (typeof event !== 'object' || !event?.type) return true;\n\t// No filter configured — accept all\n\tif (!subscriber.subscribedEvents) return true;\n\treturn subscriber.subscribedEvents.includes(event.type);\n}\n\nfunction parseSNSRecord(record: SNSEventRecord): any {\n\tconst message = safeJsonParse(record.Sns.Message);\n\tconst messageType = record.Sns.MessageAttributes?.type?.Value;\n\n\t// Not JSON — wrap raw string with type from MessageAttributes if available\n\tif (message === null) {\n\t\treturn messageType\n\t\t\t? { type: messageType, payload: record.Sns.Message }\n\t\t\t: record.Sns.Message;\n\t}\n\n\tif (message.type) {\n\t\treturn message; // Full event format: { type, payload }\n\t}\n\n\t// Payload-only format: type is in MessageAttributes\n\treturn messageType ? { type: messageType, payload: message } : message;\n}\n\nfunction parseSQSRecord(record: SQSRecord): any {\n\tconst body = safeJsonParse(record.body);\n\n\t// Not JSON — return raw body as-is\n\tif (body === null) {\n\t\treturn record.body;\n\t}\n\n\t// Check if this is an SNS message wrapped in SQS\n\tif (body.Type === 'Notification' && body.Message) {\n\t\tconst snsMessage = safeJsonParse(body.Message);\n\t\tconst messageType = body.MessageAttributes?.type?.Value;\n\n\t\t// SNS Message not JSON — wrap with type from MessageAttributes if available\n\t\tif (snsMessage === null) {\n\t\t\treturn messageType\n\t\t\t\t? { type: messageType, payload: body.Message }\n\t\t\t\t: body.Message;\n\t\t}\n\n\t\tif (snsMessage.type) {\n\t\t\treturn snsMessage; // Full event format: { type, payload }\n\t\t}\n\n\t\t// Payload-only format: type is in MessageAttributes\n\t\treturn messageType\n\t\t\t? { type: messageType, payload: snsMessage }\n\t\t\t: snsMessage;\n\t}\n\n\t// Direct SQS message\n\treturn body;\n}\n\nfunction safeJsonParse(value: string): any | null {\n\ttry {\n\t\treturn JSON.parse(value);\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ let _geekmidas_services = require("@geekmidas/services");
2
+ //#region src/subscribers/runSubscriber.ts
3
+ /** The subscriber's output did not match its `.output()` schema. */
4
+ var SubscriberOutputInvalid = class extends Error {
5
+ issues;
6
+ constructor(issues) {
7
+ super("Subscriber output validation failed: the handler's result does not match its .output() schema.");
8
+ this.issues = issues;
9
+ this.name = "SubscriberOutputInvalid";
10
+ }
11
+ };
12
+ /** The events in an SQS or SNS batch (a Lambda event's `Records`) that `subscriber` subscribed to. */
13
+ function subscribedEvents(subscriber, rawEvent, logger) {
14
+ const events = [];
15
+ const records = rawEvent.Records ?? [];
16
+ const first = records[0];
17
+ const parse = first?.eventSource === "aws:sqs" ? (record) => parseSQSRecord(record) : first?.EventSource === "aws:sns" ? (record) => parseSNSRecord(record) : void 0;
18
+ if (!parse) return events;
19
+ for (const record of records) try {
20
+ const event = parse(record);
21
+ if (isSubscribed(subscriber, event)) events.push(event);
22
+ } catch (error) {
23
+ logger.error({
24
+ err: error,
25
+ record
26
+ }, "Failed to parse record");
27
+ }
28
+ return events;
29
+ }
30
+ /** The subscriber's services and database, registered as functions do. */
31
+ async function subscriberContext(subscriber, envParser) {
32
+ const discovery = _geekmidas_services.ServiceDiscovery.getInstance(envParser);
33
+ const services = subscriber.services.length > 0 ? await discovery.register(subscriber.services) : {};
34
+ const service = subscriber.databaseService;
35
+ return {
36
+ services,
37
+ db: service ? (await discovery.register([service]))[service.serviceName] : void 0
38
+ };
39
+ }
40
+ /** Runs the handler on `events`, and checks its output against its schema. */
41
+ async function runSubscriber(subscriber, context) {
42
+ if (context.events.length === 0) {
43
+ context.logger.info("No subscribed events to process");
44
+ return { batchItemFailures: [] };
45
+ }
46
+ const { events, services, db, logger } = context;
47
+ const result = await subscriber.handler({
48
+ events,
49
+ services,
50
+ logger,
51
+ db
52
+ });
53
+ if (subscriber.outputSchema && result) {
54
+ const validation = await subscriber.outputSchema["~standard"].validate(result);
55
+ if (validation.issues) {
56
+ context.logger.error({ issues: validation.issues }, "Subscriber output validation failed");
57
+ throw new SubscriberOutputInvalid(validation.issues);
58
+ }
59
+ return validation.value;
60
+ }
61
+ return result;
62
+ }
63
+ function isSubscribed(subscriber, event) {
64
+ if (typeof event !== "object" || !event?.type) return true;
65
+ if (!subscriber.subscribedEvents) return true;
66
+ return subscriber.subscribedEvents.includes(event.type);
67
+ }
68
+ function parseSNSRecord(record) {
69
+ const message = safeJsonParse(record.Sns.Message);
70
+ const messageType = record.Sns.MessageAttributes?.type?.Value;
71
+ if (message === null) return messageType ? {
72
+ type: messageType,
73
+ payload: record.Sns.Message
74
+ } : record.Sns.Message;
75
+ if (message.type) return message;
76
+ return messageType ? {
77
+ type: messageType,
78
+ payload: message
79
+ } : message;
80
+ }
81
+ function parseSQSRecord(record) {
82
+ const body = safeJsonParse(record.body);
83
+ if (body === null) return record.body;
84
+ if (body.Type === "Notification" && body.Message) {
85
+ const snsMessage = safeJsonParse(body.Message);
86
+ const messageType = body.MessageAttributes?.type?.Value;
87
+ if (snsMessage === null) return messageType ? {
88
+ type: messageType,
89
+ payload: body.Message
90
+ } : body.Message;
91
+ if (snsMessage.type) return snsMessage;
92
+ return messageType ? {
93
+ type: messageType,
94
+ payload: snsMessage
95
+ } : snsMessage;
96
+ }
97
+ return body;
98
+ }
99
+ function safeJsonParse(value) {
100
+ try {
101
+ return JSON.parse(value);
102
+ } catch {
103
+ return null;
104
+ }
105
+ }
106
+ //#endregion
107
+ Object.defineProperty(exports, "runSubscriber", {
108
+ enumerable: true,
109
+ get: function() {
110
+ return runSubscriber;
111
+ }
112
+ });
113
+ Object.defineProperty(exports, "subscribedEvents", {
114
+ enumerable: true,
115
+ get: function() {
116
+ return subscribedEvents;
117
+ }
118
+ });
119
+ Object.defineProperty(exports, "subscriberContext", {
120
+ enumerable: true,
121
+ get: function() {
122
+ return subscriberContext;
123
+ }
124
+ });
125
+
126
+ //# sourceMappingURL=runSubscriber-D8nLXIv1.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runSubscriber-D8nLXIv1.cjs","names":["ServiceDiscovery"],"sources":["../src/subscribers/runSubscriber.ts"],"sourcesContent":["/**\n * What a subscriber does with a batch of records, however they arrived: parse\n * them into events, keep the ones it subscribed to, and run its handler with\n * its services and database.\n *\n * Shared by the Lambda adaptor, which wraps it in middy, and the SNS push\n * adaptor, which a server runs and which must not need middy to load.\n */\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { ServiceDiscovery } from '@geekmidas/services';\nimport type { SNSEvent, SNSEventRecord, SQSEvent, SQSRecord } from 'aws-lambda';\nimport type { Subscriber } from './Subscriber';\n\ntype AnySubscriber = Subscriber<any, any, any, any, any, any, any>;\n\n/** The subscriber's output did not match its `.output()` schema. */\nexport class SubscriberOutputInvalid extends Error {\n\tconstructor(readonly issues: ReadonlyArray<unknown>) {\n\t\tsuper(\n\t\t\t\"Subscriber output validation failed: the handler's result does not match its .output() schema.\",\n\t\t);\n\t\tthis.name = 'SubscriberOutputInvalid';\n\t}\n}\n\n/** The events in an SQS or SNS batch (a Lambda event's `Records`) that `subscriber` subscribed to. */\nexport function subscribedEvents(\n\tsubscriber: AnySubscriber,\n\trawEvent: { Records?: readonly unknown[] },\n\tlogger: Logger,\n): any[] {\n\tconst events: any[] = [];\n\tconst records = rawEvent.Records ?? [];\n\tconst first = records[0] as any;\n\tconst parse =\n\t\tfirst?.eventSource === 'aws:sqs'\n\t\t\t? (record: any) => parseSQSRecord(record)\n\t\t\t: first?.EventSource === 'aws:sns'\n\t\t\t\t? (record: any) => parseSNSRecord(record)\n\t\t\t\t: undefined;\n\tif (!parse) return events;\n\n\tfor (const record of records) {\n\t\ttry {\n\t\t\tconst event = parse(record);\n\t\t\tif (isSubscribed(subscriber, event)) events.push(event);\n\t\t} catch (error) {\n\t\t\tlogger.error({ err: error, record }, 'Failed to parse record');\n\t\t}\n\t}\n\treturn events;\n}\n\n/** The subscriber's services and database, registered as functions do. */\nexport async function subscriberContext(\n\tsubscriber: AnySubscriber,\n\tenvParser: EnvironmentParser<{}>,\n): Promise<{ services: Record<string, unknown>; db: unknown }> {\n\tconst discovery = ServiceDiscovery.getInstance(envParser);\n\tconst services =\n\t\tsubscriber.services.length > 0\n\t\t\t? await discovery.register(subscriber.services)\n\t\t\t: {};\n\tconst service = subscriber.databaseService;\n\tconst db = service\n\t\t? (await discovery.register([service]))[service.serviceName]\n\t\t: undefined;\n\treturn { services, db };\n}\n\n/** Runs the handler on `events`, and checks its output against its schema. */\nexport async function runSubscriber(\n\tsubscriber: AnySubscriber,\n\tcontext: {\n\t\tevents: any[];\n\t\tservices: Record<string, unknown>;\n\t\tdb: unknown;\n\t\tlogger: Logger;\n\t},\n): Promise<unknown> {\n\tif (context.events.length === 0) {\n\t\tcontext.logger.info('No subscribed events to process');\n\t\treturn { batchItemFailures: [] };\n\t}\n\n\tconst { events, services, db, logger } = context;\n\tconst result = await subscriber.handler({\n\t\tevents,\n\t\tservices,\n\t\tlogger,\n\t\tdb,\n\t} as any);\n\n\tif (subscriber.outputSchema && result) {\n\t\tconst validation =\n\t\t\tawait subscriber.outputSchema['~standard'].validate(result);\n\t\tif (validation.issues) {\n\t\t\tcontext.logger.error(\n\t\t\t\t{ issues: validation.issues },\n\t\t\t\t'Subscriber output validation failed',\n\t\t\t);\n\t\t\tthrow new SubscriberOutputInvalid(validation.issues);\n\t\t}\n\t\treturn validation.value;\n\t}\n\n\treturn result;\n}\n\nfunction isSubscribed(subscriber: AnySubscriber, event: any): boolean {\n\t// No event type (raw string/non-object) — always include\n\tif (typeof event !== 'object' || !event?.type) return true;\n\t// No filter configured — accept all\n\tif (!subscriber.subscribedEvents) return true;\n\treturn subscriber.subscribedEvents.includes(event.type);\n}\n\nfunction parseSNSRecord(record: SNSEventRecord): any {\n\tconst message = safeJsonParse(record.Sns.Message);\n\tconst messageType = record.Sns.MessageAttributes?.type?.Value;\n\n\t// Not JSON — wrap raw string with type from MessageAttributes if available\n\tif (message === null) {\n\t\treturn messageType\n\t\t\t? { type: messageType, payload: record.Sns.Message }\n\t\t\t: record.Sns.Message;\n\t}\n\n\tif (message.type) {\n\t\treturn message; // Full event format: { type, payload }\n\t}\n\n\t// Payload-only format: type is in MessageAttributes\n\treturn messageType ? { type: messageType, payload: message } : message;\n}\n\nfunction parseSQSRecord(record: SQSRecord): any {\n\tconst body = safeJsonParse(record.body);\n\n\t// Not JSON — return raw body as-is\n\tif (body === null) {\n\t\treturn record.body;\n\t}\n\n\t// Check if this is an SNS message wrapped in SQS\n\tif (body.Type === 'Notification' && body.Message) {\n\t\tconst snsMessage = safeJsonParse(body.Message);\n\t\tconst messageType = body.MessageAttributes?.type?.Value;\n\n\t\t// SNS Message not JSON — wrap with type from MessageAttributes if available\n\t\tif (snsMessage === null) {\n\t\t\treturn messageType\n\t\t\t\t? { type: messageType, payload: body.Message }\n\t\t\t\t: body.Message;\n\t\t}\n\n\t\tif (snsMessage.type) {\n\t\t\treturn snsMessage; // Full event format: { type, payload }\n\t\t}\n\n\t\t// Payload-only format: type is in MessageAttributes\n\t\treturn messageType\n\t\t\t? { type: messageType, payload: snsMessage }\n\t\t\t: snsMessage;\n\t}\n\n\t// Direct SQS message\n\treturn body;\n}\n\nfunction safeJsonParse(value: string): any | null {\n\ttry {\n\t\treturn JSON.parse(value);\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],"mappings":";;;AAkBA,IAAa,0BAAb,cAA6C,MAAM;CAC7B;CAArB,YAAY,QAAyC;EACpD,MACC,gGACD;EAHoB,KAAA,SAAA;EAIpB,KAAK,OAAO;CACb;AACD;;AAGA,SAAgB,iBACf,YACA,UACA,QACQ;CACR,MAAM,SAAgB,CAAC;CACvB,MAAM,UAAU,SAAS,WAAW,CAAC;CACrC,MAAM,QAAQ,QAAQ;CACtB,MAAM,QACL,OAAO,gBAAgB,aACnB,WAAgB,eAAe,MAAM,IACtC,OAAO,gBAAgB,aACrB,WAAgB,eAAe,MAAM,IACtC,KAAA;CACL,IAAI,CAAC,OAAO,OAAO;CAEnB,KAAK,MAAM,UAAU,SACpB,IAAI;EACH,MAAM,QAAQ,MAAM,MAAM;EAC1B,IAAI,aAAa,YAAY,KAAK,GAAG,OAAO,KAAK,KAAK;CACvD,SAAS,OAAO;EACf,OAAO,MAAM;GAAE,KAAK;GAAO;EAAO,GAAG,wBAAwB;CAC9D;CAED,OAAO;AACR;;AAGA,eAAsB,kBACrB,YACA,WAC8D;CAC9D,MAAM,YAAYA,oBAAAA,iBAAiB,YAAY,SAAS;CACxD,MAAM,WACL,WAAW,SAAS,SAAS,IAC1B,MAAM,UAAU,SAAS,WAAW,QAAQ,IAC5C,CAAC;CACL,MAAM,UAAU,WAAW;CAI3B,OAAO;EAAE;EAAU,IAHR,WACP,MAAM,UAAU,SAAS,CAAC,OAAO,CAAC,EAAA,CAAG,QAAQ,eAC9C,KAAA;CACmB;AACvB;;AAGA,eAAsB,cACrB,YACA,SAMmB;CACnB,IAAI,QAAQ,OAAO,WAAW,GAAG;EAChC,QAAQ,OAAO,KAAK,iCAAiC;EACrD,OAAO,EAAE,mBAAmB,CAAC,EAAE;CAChC;CAEA,MAAM,EAAE,QAAQ,UAAU,IAAI,WAAW;CACzC,MAAM,SAAS,MAAM,WAAW,QAAQ;EACvC;EACA;EACA;EACA;CACD,CAAQ;CAER,IAAI,WAAW,gBAAgB,QAAQ;EACtC,MAAM,aACL,MAAM,WAAW,aAAa,YAAY,CAAC,SAAS,MAAM;EAC3D,IAAI,WAAW,QAAQ;GACtB,QAAQ,OAAO,MACd,EAAE,QAAQ,WAAW,OAAO,GAC5B,qCACD;GACA,MAAM,IAAI,wBAAwB,WAAW,MAAM;EACpD;EACA,OAAO,WAAW;CACnB;CAEA,OAAO;AACR;AAEA,SAAS,aAAa,YAA2B,OAAqB;CAErE,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,MAAM,OAAO;CAEtD,IAAI,CAAC,WAAW,kBAAkB,OAAO;CACzC,OAAO,WAAW,iBAAiB,SAAS,MAAM,IAAI;AACvD;AAEA,SAAS,eAAe,QAA6B;CACpD,MAAM,UAAU,cAAc,OAAO,IAAI,OAAO;CAChD,MAAM,cAAc,OAAO,IAAI,mBAAmB,MAAM;CAGxD,IAAI,YAAY,MACf,OAAO,cACJ;EAAE,MAAM;EAAa,SAAS,OAAO,IAAI;CAAQ,IACjD,OAAO,IAAI;CAGf,IAAI,QAAQ,MACX,OAAO;CAIR,OAAO,cAAc;EAAE,MAAM;EAAa,SAAS;CAAQ,IAAI;AAChE;AAEA,SAAS,eAAe,QAAwB;CAC/C,MAAM,OAAO,cAAc,OAAO,IAAI;CAGtC,IAAI,SAAS,MACZ,OAAO,OAAO;CAIf,IAAI,KAAK,SAAS,kBAAkB,KAAK,SAAS;EACjD,MAAM,aAAa,cAAc,KAAK,OAAO;EAC7C,MAAM,cAAc,KAAK,mBAAmB,MAAM;EAGlD,IAAI,eAAe,MAClB,OAAO,cACJ;GAAE,MAAM;GAAa,SAAS,KAAK;EAAQ,IAC3C,KAAK;EAGT,IAAI,WAAW,MACd,OAAO;EAIR,OAAO,cACJ;GAAE,MAAM;GAAa,SAAS;EAAW,IACzC;CACJ;CAGA,OAAO;AACR;AAEA,SAAS,cAAc,OAA2B;CACjD,IAAI;EACH,OAAO,KAAK,MAAM,KAAK;CACxB,QAAQ;EACP,OAAO;CACR;AACD"}