@geekmidas/constructs 10.0.0-alpha.12 → 10.0.0-alpha.13
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.
- package/dist/{Construct-BD5neF7w.mjs → Construct-BeYVu_QF.mjs} +30 -28
- package/dist/Construct-BeYVu_QF.mjs.map +1 -0
- package/dist/{Construct-Ct8nalEi.d.mts → Construct-DfbwIntp.d.cts} +10 -12
- package/dist/Construct-DfbwIntp.d.cts.map +1 -0
- package/dist/{Construct-CyS3RpTL.cjs → Construct-DqdlARxq.cjs} +50 -42
- package/dist/{Construct-BD5neF7w.mjs.map → Construct-DqdlARxq.cjs.map} +1 -1
- package/dist/{Construct-C0ijr2qp.d.cts → Construct-l5aOn_jv.d.mts} +9 -11
- package/dist/Construct-l5aOn_jv.d.mts.map +1 -0
- package/dist/{Cron-DmQ8vQ4b.d.cts → Cron-DKqnnTdH.d.cts} +4 -5
- package/dist/Cron-DKqnnTdH.d.cts.map +1 -0
- package/dist/{Cron-dh4rUgib.d.mts → Cron-SyqS5oWJ.d.mts} +5 -6
- package/dist/Cron-SyqS5oWJ.d.mts.map +1 -0
- package/dist/{CronBuilder-Da0C0edR.cjs → CronBuilder-BdnI6lxF.cjs} +24 -25
- package/dist/CronBuilder-BdnI6lxF.cjs.map +1 -0
- package/dist/{CronBuilder-BquXDbDI.d.cts → CronBuilder-CRGnDfTq.d.mts} +7 -10
- package/dist/CronBuilder-CRGnDfTq.d.mts.map +1 -0
- package/dist/{CronBuilder-CYKT5RiO.mjs → CronBuilder-D_0HNBTr.mjs} +14 -15
- package/dist/CronBuilder-D_0HNBTr.mjs.map +1 -0
- package/dist/{CronBuilder-CGgY2080.d.mts → CronBuilder-Df1q9PNy.d.cts} +7 -10
- package/dist/CronBuilder-Df1q9PNy.d.cts.map +1 -0
- package/dist/{Endpoint-DCQPMdUX.mjs → Endpoint-BCiCYvx2.mjs} +79 -106
- package/dist/Endpoint-BCiCYvx2.mjs.map +1 -0
- package/dist/{Endpoint-BjWKinFA.d.mts → Endpoint-C6yyHpRS.d.cts} +14 -65
- package/dist/Endpoint-C6yyHpRS.d.cts.map +1 -0
- package/dist/{Endpoint-dav89W6-.d.cts → Endpoint-DuT4TEEq.d.mts} +14 -65
- package/dist/Endpoint-DuT4TEEq.d.mts.map +1 -0
- package/dist/{Endpoint-DcWXE-SZ.cjs → Endpoint-s0AyrQGC.cjs} +101 -128
- package/dist/Endpoint-s0AyrQGC.cjs.map +1 -0
- package/dist/{EndpointFactory-CdWB7wPw.cjs → EndpointFactory-M8OQKZRY.cjs} +57 -66
- package/dist/EndpointFactory-M8OQKZRY.cjs.map +1 -0
- package/dist/{EndpointFactory-CjV8F_lJ.mjs → EndpointFactory-ptPR1cXw.mjs} +20 -29
- package/dist/EndpointFactory-ptPR1cXw.mjs.map +1 -0
- package/dist/{HonoEndpointAdaptor-DtL9j19R.cjs → HonoEndpointAdaptor-7QagYKdP.cjs} +48 -52
- package/dist/HonoEndpointAdaptor-7QagYKdP.cjs.map +1 -0
- package/dist/{HonoEndpointAdaptor-P1ahhZHu.mjs → HonoEndpointAdaptor-CYHA0WAt.mjs} +40 -47
- package/dist/{HonoEndpointAdaptor-DtL9j19R.cjs.map → HonoEndpointAdaptor-CYHA0WAt.mjs.map} +1 -1
- package/dist/{Queue-D7ZuwBhy.d.cts → Queue-D9X6OoON.d.mts} +10 -11
- package/dist/Queue-D9X6OoON.d.mts.map +1 -0
- package/dist/{Queue-gVGfi2Yk.d.mts → Queue-DYPB2KWL.d.cts} +10 -11
- package/dist/Queue-DYPB2KWL.d.cts.map +1 -0
- package/dist/{Subscriber-2mEi0ImH.d.cts → Subscriber-C4heaAyO.d.mts} +7 -8
- package/dist/Subscriber-C4heaAyO.d.mts.map +1 -0
- package/dist/{Subscriber-xTJ9ayPN.d.mts → Subscriber-CotDUELC.d.cts} +7 -8
- package/dist/Subscriber-CotDUELC.d.cts.map +1 -0
- package/dist/{SubscriberBuilder-Dptmo-1A.d.mts → SubscriberBuilder-BEv0eoHy.d.cts} +8 -11
- package/dist/SubscriberBuilder-BEv0eoHy.d.cts.map +1 -0
- package/dist/{SubscriberBuilder-4OPehf2R.cjs → SubscriberBuilder-C0ZEtGDI.cjs} +28 -23
- package/dist/SubscriberBuilder-C0ZEtGDI.cjs.map +1 -0
- package/dist/{SubscriberBuilder-BjkbeT9l.mjs → SubscriberBuilder-h7B_cHMr.mjs} +16 -10
- package/dist/SubscriberBuilder-h7B_cHMr.mjs.map +1 -0
- package/dist/{SubscriberBuilder-waNhzjSM.d.cts → SubscriberBuilder-tyH5yTk5.d.mts} +8 -11
- package/dist/SubscriberBuilder-tyH5yTk5.d.mts.map +1 -0
- package/dist/{Topic-19QeHBIR.d.cts → Topic-DEVGo0Dm.d.cts} +5 -7
- package/dist/Topic-DEVGo0Dm.d.cts.map +1 -0
- package/dist/{Topic-DuFeqkBh.d.mts → Topic-zk_6Gthr.d.mts} +6 -8
- package/dist/Topic-zk_6Gthr.d.mts.map +1 -0
- package/dist/adaptors/aws.cjs +87 -106
- package/dist/adaptors/aws.cjs.map +1 -1
- package/dist/adaptors/aws.d.cts +14 -27
- package/dist/adaptors/aws.d.cts.map +1 -1
- package/dist/adaptors/aws.d.mts +16 -29
- package/dist/adaptors/aws.d.mts.map +1 -1
- package/dist/adaptors/aws.mjs +60 -81
- package/dist/adaptors/aws.mjs.map +1 -1
- package/dist/adaptors/hono.cjs +3 -10
- package/dist/adaptors/hono.d.cts +5 -13
- package/dist/adaptors/hono.d.cts.map +1 -1
- package/dist/adaptors/hono.d.mts +7 -15
- package/dist/adaptors/hono.d.mts.map +1 -1
- package/dist/adaptors/hono.mjs +2 -10
- package/dist/adaptors/testing.cjs +60 -73
- package/dist/adaptors/testing.cjs.map +1 -1
- package/dist/adaptors/testing.d.cts +17 -28
- package/dist/adaptors/testing.d.cts.map +1 -1
- package/dist/adaptors/testing.d.mts +18 -29
- package/dist/adaptors/testing.d.mts.map +1 -1
- package/dist/adaptors/testing.mjs +42 -55
- package/dist/adaptors/testing.mjs.map +1 -1
- package/dist/auth.cjs +39 -14
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +5 -9
- package/dist/auth.d.cts.map +1 -1
- package/dist/auth.d.mts +5 -9
- package/dist/auth.d.mts.map +1 -1
- package/dist/auth.mjs +30 -5
- package/dist/auth.mjs.map +1 -1
- package/dist/cache.cjs +68 -2
- package/dist/cache.cjs.map +1 -0
- package/dist/cache.d.cts +43 -3
- package/dist/cache.d.cts.map +1 -0
- package/dist/cache.d.mts +43 -3
- package/dist/cache.d.mts.map +1 -0
- package/dist/cache.mjs +67 -2
- package/dist/cache.mjs.map +1 -0
- package/dist/{clone-DblgEZZa.mjs → clone-EKNovYHu.mjs} +3 -3
- package/dist/clone-EKNovYHu.mjs.map +1 -0
- package/dist/{clone-Dy0cR2SZ.cjs → clone-UGJpvQnL.cjs} +7 -8
- package/dist/clone-UGJpvQnL.cjs.map +1 -0
- package/dist/{construct-interface-g5GM5pwR.d.mts → construct-interface-DPlxfpoS.d.mts} +3 -6
- package/dist/construct-interface-DPlxfpoS.d.mts.map +1 -0
- package/dist/{construct-interface-D9d4Gm4p.d.cts → construct-interface-DgXTJcOD.d.cts} +3 -6
- package/dist/construct-interface-DgXTJcOD.d.cts.map +1 -0
- package/dist/construct-interface.cjs +87 -7
- package/dist/construct-interface.cjs.map +1 -0
- package/dist/construct-interface.d.cts +1 -1
- package/dist/construct-interface.d.mts +1 -1
- package/dist/construct-interface.mjs +81 -2
- package/dist/construct-interface.mjs.map +1 -0
- package/dist/credential.cjs +43 -9
- package/dist/credential.cjs.map +1 -1
- package/dist/credential.d.cts +5 -8
- package/dist/credential.d.cts.map +1 -1
- package/dist/credential.d.mts +5 -8
- package/dist/credential.d.mts.map +1 -1
- package/dist/credential.mjs +36 -2
- package/dist/credential.mjs.map +1 -1
- package/dist/crons/index.cjs +4 -7
- package/dist/crons/index.cjs.map +1 -1
- package/dist/crons/index.d.cts +5 -11
- package/dist/crons/index.d.cts.map +1 -1
- package/dist/crons/index.d.mts +5 -11
- package/dist/crons/index.d.mts.map +1 -1
- package/dist/crons/index.mjs +3 -7
- package/dist/crons/index.mjs.map +1 -1
- package/dist/database/kysely.cjs +28 -14
- package/dist/database/kysely.cjs.map +1 -1
- package/dist/database/kysely.d.cts +5 -8
- package/dist/database/kysely.d.cts.map +1 -1
- package/dist/database/kysely.d.mts +6 -9
- package/dist/database/kysely.d.mts.map +1 -1
- package/dist/database/kysely.mjs +16 -4
- package/dist/database/kysely.mjs.map +1 -1
- package/dist/email.cjs +25 -12
- package/dist/email.cjs.map +1 -1
- package/dist/email.d.cts +3 -7
- package/dist/email.d.cts.map +1 -1
- package/dist/email.d.mts +3 -7
- package/dist/email.d.mts.map +1 -1
- package/dist/email.mjs +16 -3
- package/dist/email.mjs.map +1 -1
- package/dist/endpoints/index.cjs +6 -10
- package/dist/endpoints/index.d.cts +3 -7
- package/dist/endpoints/index.d.mts +3 -7
- package/dist/endpoints/index.mjs +5 -10
- package/dist/file-server.cjs +42 -10
- package/dist/file-server.cjs.map +1 -1
- package/dist/file-server.d.cts +6 -10
- package/dist/file-server.d.cts.map +1 -1
- package/dist/file-server.d.mts +6 -10
- package/dist/file-server.d.mts.map +1 -1
- package/dist/file-server.mjs +34 -2
- package/dist/file-server.mjs.map +1 -1
- package/dist/functions/index.cjs +3 -6
- package/dist/functions/index.d.cts +2 -4
- package/dist/functions/index.d.mts +2 -4
- package/dist/functions/index.mjs +2 -6
- package/dist/{functions-i_la-N5r.cjs → functions-B6qCvfmy.cjs} +298 -252
- package/dist/functions-B6qCvfmy.cjs.map +1 -0
- package/dist/{functions-14lpEFL4.mjs → functions-C53GW2eQ.mjs} +272 -229
- package/dist/functions-C53GW2eQ.mjs.map +1 -0
- package/dist/{index-BknhM6Ux.d.mts → index-B2urf3YI.d.cts} +4 -9
- package/dist/index-B2urf3YI.d.cts.map +1 -0
- package/dist/{index-Bd5FqCoe.d.cts → index-BPSZ_Lp_.d.cts} +9 -38
- package/dist/index-BPSZ_Lp_.d.cts.map +1 -0
- package/dist/{index-lAO9egTb.d.mts → index-BoZ-iisU.d.mts} +12 -41
- package/dist/index-BoZ-iisU.d.mts.map +1 -0
- package/dist/{index-_ajboYxK.d.mts → index-CdaU--_B.d.cts} +10 -16
- package/dist/index-CdaU--_B.d.cts.map +1 -0
- package/dist/index-CeEtxDmK.d.cts +79 -0
- package/dist/index-CeEtxDmK.d.cts.map +1 -0
- package/dist/index-CeEtxDmK.d.mts +79 -0
- package/dist/index-CeEtxDmK.d.mts.map +1 -0
- package/dist/{index-CBSfrowv.d.cts → index-DMCDvnsM.d.mts} +4 -9
- package/dist/index-DMCDvnsM.d.mts.map +1 -0
- package/dist/{index-D24Xm79M.d.cts → index-PQRWOQj4.d.mts} +10 -16
- package/dist/index-PQRWOQj4.d.mts.map +1 -0
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +2 -3
- package/dist/{lazyAccessors-BoJN3SMd.mjs → lazyAccessors-BHtcqgz2.mjs} +22 -25
- package/dist/lazyAccessors-BHtcqgz2.mjs.map +1 -0
- package/dist/{lazyAccessors-e3j2oE2m.cjs → lazyAccessors-Dx9NLwJZ.cjs} +72 -76
- package/dist/lazyAccessors-Dx9NLwJZ.cjs.map +1 -0
- package/dist/object-storage.cjs +18 -10
- package/dist/object-storage.cjs.map +1 -1
- package/dist/object-storage.d.cts +3 -7
- package/dist/object-storage.d.cts.map +1 -1
- package/dist/object-storage.d.mts +3 -7
- package/dist/object-storage.d.mts.map +1 -1
- package/dist/object-storage.mjs +11 -3
- package/dist/object-storage.mjs.map +1 -1
- package/dist/{processAudits-Dmts9H_b.mjs → processAudits-BpRlPQMW.mjs} +16 -19
- package/dist/processAudits-BpRlPQMW.mjs.map +1 -0
- package/dist/{processAudits-CGqttuXm.cjs → processAudits-D_2W5x8k.cjs} +26 -30
- package/dist/processAudits-D_2W5x8k.cjs.map +1 -0
- package/dist/queue/index.cjs +25 -21
- package/dist/queue/index.cjs.map +1 -1
- package/dist/queue/index.d.cts +8 -15
- package/dist/queue/index.d.cts.map +1 -1
- package/dist/queue/index.d.mts +8 -15
- package/dist/queue/index.d.mts.map +1 -1
- package/dist/queue/index.mjs +15 -11
- package/dist/queue/index.mjs.map +1 -1
- package/dist/rest-api.cjs +15 -17
- package/dist/rest-api.cjs.map +1 -1
- package/dist/rest-api.d.cts +15 -20
- package/dist/rest-api.d.cts.map +1 -1
- package/dist/rest-api.d.mts +9 -14
- package/dist/rest-api.d.mts.map +1 -1
- package/dist/rest-api.mjs +7 -9
- package/dist/rest-api.mjs.map +1 -1
- package/dist/{chunk-DWy1uDak.cjs → rolldown-runtime-y5ARvAq5.cjs} +14 -18
- package/dist/site.cjs +31 -7
- package/dist/site.cjs.map +1 -1
- package/dist/site.d.cts +3 -7
- package/dist/site.d.cts.map +1 -1
- package/dist/site.d.mts +3 -7
- package/dist/site.d.mts.map +1 -1
- package/dist/site.mjs +27 -3
- package/dist/site.mjs.map +1 -1
- package/dist/subscribers/index.cjs +3 -6
- package/dist/subscribers/index.d.cts +2 -5
- package/dist/subscribers/index.d.mts +2 -5
- package/dist/subscribers/index.mjs +2 -6
- package/dist/surfaceEnv-CNimK76p.cjs +56 -0
- package/dist/surfaceEnv-CNimK76p.cjs.map +1 -0
- package/dist/surfaceEnv-wMT5QzgZ.mjs +45 -0
- package/dist/surfaceEnv-wMT5QzgZ.mjs.map +1 -0
- package/dist/{telemetry-C3L0iS28.d.cts → telemetry-DGcFlVpB.d.cts} +2 -5
- package/dist/telemetry-DGcFlVpB.d.cts.map +1 -0
- package/dist/{telemetry-D7bVFLGi.d.mts → telemetry-DGcFlVpB.d.mts} +2 -5
- package/dist/telemetry-DGcFlVpB.d.mts.map +1 -0
- package/dist/topic/index.cjs +18 -20
- package/dist/topic/index.cjs.map +1 -1
- package/dist/topic/index.d.cts +3 -4
- package/dist/topic/index.d.mts +3 -4
- package/dist/topic/index.mjs +8 -10
- package/dist/topic/index.mjs.map +1 -1
- package/dist/{types-BlAkSuGI.d.cts → types-DMuSQeLL.d.cts} +3 -5
- package/dist/types-DMuSQeLL.d.cts.map +1 -0
- package/dist/{types-aKksMEWL.d.mts → types-DMuSQeLL.d.mts} +3 -5
- package/dist/types-DMuSQeLL.d.mts.map +1 -0
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +1 -0
- package/dist/worker.cjs +13 -14
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.cts +21 -27
- package/dist/worker.d.cts.map +1 -1
- package/dist/worker.d.mts +14 -19
- package/dist/worker.d.mts.map +1 -1
- package/dist/worker.mjs +8 -9
- package/dist/worker.mjs.map +1 -1
- package/package.json +30 -30
- package/dist/Construct-C0ijr2qp.d.cts.map +0 -1
- package/dist/Construct-Ct8nalEi.d.mts.map +0 -1
- package/dist/Construct-CyS3RpTL.cjs.map +0 -1
- package/dist/Cron-DmQ8vQ4b.d.cts.map +0 -1
- package/dist/Cron-dh4rUgib.d.mts.map +0 -1
- package/dist/CronBuilder-BquXDbDI.d.cts.map +0 -1
- package/dist/CronBuilder-CGgY2080.d.mts.map +0 -1
- package/dist/CronBuilder-CYKT5RiO.mjs.map +0 -1
- package/dist/CronBuilder-Da0C0edR.cjs.map +0 -1
- package/dist/Endpoint-BjWKinFA.d.mts.map +0 -1
- package/dist/Endpoint-DCQPMdUX.mjs.map +0 -1
- package/dist/Endpoint-DcWXE-SZ.cjs.map +0 -1
- package/dist/Endpoint-dav89W6-.d.cts.map +0 -1
- package/dist/EndpointFactory-CdWB7wPw.cjs.map +0 -1
- package/dist/EndpointFactory-CjV8F_lJ.mjs.map +0 -1
- package/dist/HonoEndpointAdaptor-P1ahhZHu.mjs.map +0 -1
- package/dist/Queue-D7ZuwBhy.d.cts.map +0 -1
- package/dist/Queue-gVGfi2Yk.d.mts.map +0 -1
- package/dist/Subscriber-2mEi0ImH.d.cts.map +0 -1
- package/dist/Subscriber-xTJ9ayPN.d.mts.map +0 -1
- package/dist/SubscriberBuilder-4OPehf2R.cjs.map +0 -1
- package/dist/SubscriberBuilder-BjkbeT9l.mjs.map +0 -1
- package/dist/SubscriberBuilder-Dptmo-1A.d.mts.map +0 -1
- package/dist/SubscriberBuilder-waNhzjSM.d.cts.map +0 -1
- package/dist/Topic-19QeHBIR.d.cts.map +0 -1
- package/dist/Topic-DuFeqkBh.d.mts.map +0 -1
- package/dist/cache-0ANvRQnD.mjs +0 -51
- package/dist/cache-0ANvRQnD.mjs.map +0 -1
- package/dist/cache-3WSvAulx.cjs +0 -57
- package/dist/cache-3WSvAulx.cjs.map +0 -1
- package/dist/cache-BrRz3fEB.d.mts +0 -47
- package/dist/cache-BrRz3fEB.d.mts.map +0 -1
- package/dist/cache-BtZY_tHe.d.cts +0 -47
- package/dist/cache-BtZY_tHe.d.cts.map +0 -1
- package/dist/clone-DblgEZZa.mjs.map +0 -1
- package/dist/clone-Dy0cR2SZ.cjs.map +0 -1
- package/dist/construct-interface-BfjcOD_E.cjs +0 -117
- package/dist/construct-interface-BfjcOD_E.cjs.map +0 -1
- package/dist/construct-interface-D9d4Gm4p.d.cts.map +0 -1
- package/dist/construct-interface-Z4CpS8tK.mjs +0 -81
- package/dist/construct-interface-Z4CpS8tK.mjs.map +0 -1
- package/dist/construct-interface-g5GM5pwR.d.mts.map +0 -1
- package/dist/functions-14lpEFL4.mjs.map +0 -1
- package/dist/functions-i_la-N5r.cjs.map +0 -1
- package/dist/index-Bd5FqCoe.d.cts.map +0 -1
- package/dist/index-BknhM6Ux.d.mts.map +0 -1
- package/dist/index-CBSfrowv.d.cts.map +0 -1
- package/dist/index-D24Xm79M.d.cts.map +0 -1
- package/dist/index-_ajboYxK.d.mts.map +0 -1
- package/dist/index-lAO9egTb.d.mts.map +0 -1
- package/dist/lazyAccessors-BoJN3SMd.mjs.map +0 -1
- package/dist/lazyAccessors-e3j2oE2m.cjs.map +0 -1
- package/dist/processAudits-CGqttuXm.cjs.map +0 -1
- package/dist/processAudits-Dmts9H_b.mjs.map +0 -1
- package/dist/surfaceEnv-BFXEms2f.cjs +0 -39
- package/dist/surfaceEnv-BFXEms2f.cjs.map +0 -1
- package/dist/surfaceEnv-C3Ktahea.mjs +0 -27
- package/dist/surfaceEnv-C3Ktahea.mjs.map +0 -1
- package/dist/telemetry-C3L0iS28.d.cts.map +0 -1
- package/dist/telemetry-D7bVFLGi.d.mts.map +0 -1
- package/dist/types-BlAkSuGI.d.cts.map +0 -1
- package/dist/types-aKksMEWL.d.mts.map +0 -1
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
require(
|
|
3
|
-
require(
|
|
4
|
-
const
|
|
5
|
-
require(
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const __geekmidas_audit = require_chunk.__toESM(require("@geekmidas/audit"));
|
|
14
|
-
const hono = require_chunk.__toESM(require("hono"));
|
|
15
|
-
const msw = require_chunk.__toESM(require("msw"));
|
|
16
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_functions = require("../functions-B6qCvfmy.cjs");
|
|
3
|
+
const require_Endpoint = require("../Endpoint-s0AyrQGC.cjs");
|
|
4
|
+
const require_lazyAccessors = require("../lazyAccessors-Dx9NLwJZ.cjs");
|
|
5
|
+
const require_HonoEndpointAdaptor = require("../HonoEndpointAdaptor-7QagYKdP.cjs");
|
|
6
|
+
const require_processAudits = require("../processAudits-D_2W5x8k.cjs");
|
|
7
|
+
let _geekmidas_errors = require("@geekmidas/errors");
|
|
8
|
+
let _geekmidas_envkit = require("@geekmidas/envkit");
|
|
9
|
+
let _geekmidas_services = require("@geekmidas/services");
|
|
10
|
+
let hono = require("hono");
|
|
11
|
+
let _geekmidas_audit = require("@geekmidas/audit");
|
|
12
|
+
let msw = require("msw");
|
|
17
13
|
//#region src/endpoints/MswEndpointAdaptor.ts
|
|
18
14
|
/**
|
|
19
15
|
* Header used to identify which test context a request belongs to.
|
|
@@ -52,8 +48,8 @@ function createMswHandlers(endpoints, options) {
|
|
|
52
48
|
* Creates a fresh ServiceDiscovery and pre-registers all provided services.
|
|
53
49
|
*/
|
|
54
50
|
function registerContext(id, ctxOptions) {
|
|
55
|
-
const envParser = new
|
|
56
|
-
const serviceDiscovery = new
|
|
51
|
+
const envParser = new _geekmidas_envkit.EnvironmentParser({});
|
|
52
|
+
const serviceDiscovery = new _geekmidas_services.ServiceDiscovery(envParser);
|
|
57
53
|
const serviceDefs = [];
|
|
58
54
|
if (ctxOptions.services) for (const [name, instance] of Object.entries(ctxOptions.services)) serviceDefs.push({
|
|
59
55
|
serviceName: name,
|
|
@@ -112,7 +108,6 @@ function createMswHandlers(endpoints, options) {
|
|
|
112
108
|
registerContext
|
|
113
109
|
};
|
|
114
110
|
}
|
|
115
|
-
|
|
116
111
|
//#endregion
|
|
117
112
|
//#region src/endpoints/TestEndpointAdaptor.ts
|
|
118
113
|
/**
|
|
@@ -132,8 +127,10 @@ function serializeCookie(name, value, options) {
|
|
|
132
127
|
return cookieString;
|
|
133
128
|
}
|
|
134
129
|
var TestEndpointAdaptor = class TestEndpointAdaptor {
|
|
130
|
+
endpoint;
|
|
131
|
+
serviceDiscovery;
|
|
135
132
|
static getDefaultServiceDiscover(_endpoint) {
|
|
136
|
-
return
|
|
133
|
+
return _geekmidas_services.ServiceDiscovery.getInstance(new _geekmidas_envkit.EnvironmentParser({}));
|
|
137
134
|
}
|
|
138
135
|
constructor(endpoint, serviceDiscovery = TestEndpointAdaptor.getDefaultServiceDiscover(endpoint)) {
|
|
139
136
|
this.endpoint = endpoint;
|
|
@@ -154,7 +151,7 @@ var TestEndpointAdaptor = class TestEndpointAdaptor {
|
|
|
154
151
|
method: this.endpoint.method
|
|
155
152
|
});
|
|
156
153
|
const rawDb = ctx.database;
|
|
157
|
-
return (0,
|
|
154
|
+
return (0, _geekmidas_services.runWithRequestContext)({
|
|
158
155
|
logger,
|
|
159
156
|
requestId,
|
|
160
157
|
startTime
|
|
@@ -166,7 +163,7 @@ var TestEndpointAdaptor = class TestEndpointAdaptor {
|
|
|
166
163
|
cookie,
|
|
167
164
|
...rawDb !== void 0 && { db: rawDb }
|
|
168
165
|
});
|
|
169
|
-
|
|
166
|
+
if (!await this.endpoint.authorize({
|
|
170
167
|
header,
|
|
171
168
|
cookie,
|
|
172
169
|
services: ctx.services,
|
|
@@ -176,10 +173,9 @@ var TestEndpointAdaptor = class TestEndpointAdaptor {
|
|
|
176
173
|
body,
|
|
177
174
|
query,
|
|
178
175
|
params
|
|
179
|
-
})
|
|
180
|
-
if (!isAuthorized) {
|
|
176
|
+
})) {
|
|
181
177
|
logger.warn("Forbidden access attempt");
|
|
182
|
-
throw new
|
|
178
|
+
throw new _geekmidas_errors.ForbiddenError("Forbidden access to the endpoint", "You do not have permission to access this resource.");
|
|
183
179
|
}
|
|
184
180
|
const auditorStorage = ctx.auditorStorage;
|
|
185
181
|
let auditContext;
|
|
@@ -199,24 +195,22 @@ var TestEndpointAdaptor = class TestEndpointAdaptor {
|
|
|
199
195
|
} catch (error) {
|
|
200
196
|
logger.error(error, "Failed to extract actor for audits");
|
|
201
197
|
}
|
|
202
|
-
const auditor = new __geekmidas_audit.DefaultAuditor({
|
|
203
|
-
actor,
|
|
204
|
-
storage: auditorStorage,
|
|
205
|
-
metadata: {
|
|
206
|
-
endpoint: this.endpoint.route,
|
|
207
|
-
method: this.endpoint.method
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
198
|
auditContext = {
|
|
211
|
-
auditor
|
|
199
|
+
auditor: new _geekmidas_audit.DefaultAuditor({
|
|
200
|
+
actor,
|
|
201
|
+
storage: auditorStorage,
|
|
202
|
+
metadata: {
|
|
203
|
+
endpoint: this.endpoint.route,
|
|
204
|
+
method: this.endpoint.method
|
|
205
|
+
}
|
|
206
|
+
}),
|
|
212
207
|
storage: auditorStorage
|
|
213
208
|
};
|
|
214
209
|
}
|
|
215
210
|
const audits = this.endpoint.audits;
|
|
216
211
|
if (!auditContext && audits?.length) logger.warn("No auditor storage service available");
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
const db = trx ?? rawDb;
|
|
212
|
+
const { output, metadata } = await require_processAudits.executeWithAuditTransaction(auditContext, async (auditor) => {
|
|
213
|
+
const db = auditor?.getTransaction?.() ?? rawDb;
|
|
220
214
|
const responseBuilder = new require_Endpoint.ResponseBuilder();
|
|
221
215
|
const response = await this.endpoint.handler({
|
|
222
216
|
body,
|
|
@@ -231,36 +225,34 @@ var TestEndpointAdaptor = class TestEndpointAdaptor {
|
|
|
231
225
|
db
|
|
232
226
|
}, responseBuilder);
|
|
233
227
|
let data = response;
|
|
234
|
-
let metadata
|
|
228
|
+
let metadata = responseBuilder.getMetadata();
|
|
235
229
|
if (require_Endpoint.Endpoint.hasMetadata(response)) {
|
|
236
230
|
data = response.data;
|
|
237
|
-
metadata
|
|
231
|
+
metadata = response.metadata;
|
|
238
232
|
}
|
|
239
|
-
const output$1 = await this.endpoint.parseOutput(data);
|
|
240
233
|
return {
|
|
241
|
-
output:
|
|
242
|
-
metadata
|
|
234
|
+
output: await this.endpoint.parseOutput(data),
|
|
235
|
+
metadata,
|
|
243
236
|
responseBuilder
|
|
244
237
|
};
|
|
245
|
-
}, async (result
|
|
238
|
+
}, async (result, auditor) => {
|
|
246
239
|
if (!audits?.length) return;
|
|
247
240
|
for (const audit of audits) {
|
|
248
|
-
if (audit.when && !audit.when(result
|
|
249
|
-
const payload = audit.payload(result
|
|
250
|
-
const entityId = audit.entityId?.(result
|
|
241
|
+
if (audit.when && !audit.when(result.output)) continue;
|
|
242
|
+
const payload = audit.payload(result.output);
|
|
243
|
+
const entityId = audit.entityId?.(result.output);
|
|
251
244
|
auditor.audit(audit.type, payload, {
|
|
252
245
|
table: audit.table,
|
|
253
246
|
entityId
|
|
254
247
|
});
|
|
255
248
|
}
|
|
256
249
|
}, { db: rawDb });
|
|
257
|
-
const { output, metadata } = result;
|
|
258
250
|
ctx.publisher && await this.serviceDiscovery.register([ctx.publisher]);
|
|
259
251
|
await require_lazyAccessors.publishConstructEvents(this.endpoint, output, this.serviceDiscovery);
|
|
260
252
|
const headers = { ...metadata.headers || {} };
|
|
261
253
|
if (metadata.cookies && metadata.cookies.size > 0) {
|
|
262
254
|
const setCookieValues = [];
|
|
263
|
-
for (const [name, cookie
|
|
255
|
+
for (const [name, cookie] of metadata.cookies.entries()) setCookieValues.push(serializeCookie(name, cookie.value, cookie.options));
|
|
264
256
|
headers["set-cookie"] = setCookieValues;
|
|
265
257
|
}
|
|
266
258
|
return {
|
|
@@ -271,16 +263,16 @@ var TestEndpointAdaptor = class TestEndpointAdaptor {
|
|
|
271
263
|
});
|
|
272
264
|
}
|
|
273
265
|
async request(ctx) {
|
|
274
|
-
|
|
275
|
-
return response.body;
|
|
266
|
+
return (await this.fullRequest(ctx)).body;
|
|
276
267
|
}
|
|
277
268
|
};
|
|
278
|
-
|
|
279
269
|
//#endregion
|
|
280
270
|
//#region src/functions/TestFunctionAdaptor.ts
|
|
281
271
|
var TestFunctionAdaptor = class TestFunctionAdaptor {
|
|
272
|
+
fn;
|
|
273
|
+
serviceDiscovery;
|
|
282
274
|
static getDefaultServiceDiscovery(_fn) {
|
|
283
|
-
return
|
|
275
|
+
return _geekmidas_services.ServiceDiscovery.getInstance(new _geekmidas_envkit.EnvironmentParser({}));
|
|
284
276
|
}
|
|
285
277
|
constructor(fn, serviceDiscovery = TestFunctionAdaptor.getDefaultServiceDiscovery(fn)) {
|
|
286
278
|
this.fn = fn;
|
|
@@ -294,16 +286,12 @@ var TestFunctionAdaptor = class TestFunctionAdaptor {
|
|
|
294
286
|
else services = await this.serviceDiscovery.register(this.fn.services);
|
|
295
287
|
let db;
|
|
296
288
|
if ("db" in ctx && ctx.db !== void 0) db = ctx.db;
|
|
297
|
-
else if (this.fn.databaseService)
|
|
298
|
-
const dbServices = await this.serviceDiscovery.register([this.fn.databaseService]);
|
|
299
|
-
db = dbServices[this.fn.databaseService.serviceName];
|
|
300
|
-
}
|
|
289
|
+
else if (this.fn.databaseService) db = (await this.serviceDiscovery.register([this.fn.databaseService]))[this.fn.databaseService.serviceName];
|
|
301
290
|
let auditor;
|
|
302
291
|
if ("auditor" in ctx && ctx.auditor !== void 0) auditor = ctx.auditor;
|
|
303
292
|
else if (this.fn.auditorStorageService) {
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
auditor = new __geekmidas_audit.DefaultAuditor({
|
|
293
|
+
const storage = (await this.serviceDiscovery.register([this.fn.auditorStorageService]))[this.fn.auditorStorageService.serviceName];
|
|
294
|
+
auditor = new _geekmidas_audit.DefaultAuditor({
|
|
307
295
|
actor: {
|
|
308
296
|
id: "system",
|
|
309
297
|
type: "system"
|
|
@@ -316,11 +304,10 @@ var TestFunctionAdaptor = class TestFunctionAdaptor {
|
|
|
316
304
|
});
|
|
317
305
|
}
|
|
318
306
|
const requestId = `test-${Date.now()}`;
|
|
319
|
-
|
|
320
|
-
return (0, __geekmidas_services.runWithRequestContext)({
|
|
307
|
+
return (0, _geekmidas_services.runWithRequestContext)({
|
|
321
308
|
logger,
|
|
322
309
|
requestId,
|
|
323
|
-
startTime
|
|
310
|
+
startTime: Date.now()
|
|
324
311
|
}, async () => {
|
|
325
312
|
const response = await this.fn.fn({
|
|
326
313
|
input: parsedInput,
|
|
@@ -342,7 +329,6 @@ var TestFunctionAdaptor = class TestFunctionAdaptor {
|
|
|
342
329
|
});
|
|
343
330
|
}
|
|
344
331
|
};
|
|
345
|
-
|
|
346
332
|
//#endregion
|
|
347
333
|
//#region src/queue/TestQueueAdaptor.ts
|
|
348
334
|
/**
|
|
@@ -355,8 +341,10 @@ var TestFunctionAdaptor = class TestFunctionAdaptor {
|
|
|
355
341
|
* await adapter.invoke({ messages: [{ orderId: '123' }] });
|
|
356
342
|
*/
|
|
357
343
|
var TestQueueAdaptor = class TestQueueAdaptor {
|
|
344
|
+
queue;
|
|
345
|
+
serviceDiscovery;
|
|
358
346
|
static getDefaultServiceDiscovery() {
|
|
359
|
-
return
|
|
347
|
+
return _geekmidas_services.ServiceDiscovery.getInstance(new _geekmidas_envkit.EnvironmentParser({}));
|
|
360
348
|
}
|
|
361
349
|
constructor(queue, serviceDiscovery = TestQueueAdaptor.getDefaultServiceDiscovery()) {
|
|
362
350
|
this.queue = queue;
|
|
@@ -366,11 +354,10 @@ var TestQueueAdaptor = class TestQueueAdaptor {
|
|
|
366
354
|
const logger = this.queue.logger.child({ test: true });
|
|
367
355
|
const services = request.services ?? await this.serviceDiscovery.register(this.queue.services);
|
|
368
356
|
const requestId = `test-${Date.now()}`;
|
|
369
|
-
|
|
370
|
-
return (0, __geekmidas_services.runWithRequestContext)({
|
|
357
|
+
return (0, _geekmidas_services.runWithRequestContext)({
|
|
371
358
|
logger,
|
|
372
359
|
requestId,
|
|
373
|
-
startTime
|
|
360
|
+
startTime: Date.now()
|
|
374
361
|
}, () => this.queue.handler({
|
|
375
362
|
messages: request.messages,
|
|
376
363
|
services,
|
|
@@ -378,12 +365,13 @@ var TestQueueAdaptor = class TestQueueAdaptor {
|
|
|
378
365
|
}));
|
|
379
366
|
}
|
|
380
367
|
};
|
|
381
|
-
|
|
382
368
|
//#endregion
|
|
383
369
|
//#region src/subscribers/TestSubscriberAdaptor.ts
|
|
384
370
|
var TestSubscriberAdaptor = class TestSubscriberAdaptor {
|
|
371
|
+
subscriber;
|
|
372
|
+
serviceDiscovery;
|
|
385
373
|
static getDefaultServiceDiscovery() {
|
|
386
|
-
return
|
|
374
|
+
return _geekmidas_services.ServiceDiscovery.getInstance(new _geekmidas_envkit.EnvironmentParser({}));
|
|
387
375
|
}
|
|
388
376
|
constructor(subscriber, serviceDiscovery = TestSubscriberAdaptor.getDefaultServiceDiscovery()) {
|
|
389
377
|
this.subscriber = subscriber;
|
|
@@ -397,11 +385,10 @@ var TestSubscriberAdaptor = class TestSubscriberAdaptor {
|
|
|
397
385
|
const filteredEvents = this.filterEvents(request.events);
|
|
398
386
|
if (filteredEvents.length === 0) return { batchItemFailures: [] };
|
|
399
387
|
const requestId = `test-${Date.now()}`;
|
|
400
|
-
|
|
401
|
-
return (0, __geekmidas_services.runWithRequestContext)({
|
|
388
|
+
return (0, _geekmidas_services.runWithRequestContext)({
|
|
402
389
|
logger,
|
|
403
390
|
requestId,
|
|
404
|
-
startTime
|
|
391
|
+
startTime: Date.now()
|
|
405
392
|
}, async () => {
|
|
406
393
|
const result = await this.subscriber.handler({
|
|
407
394
|
events: filteredEvents,
|
|
@@ -423,7 +410,6 @@ var TestSubscriberAdaptor = class TestSubscriberAdaptor {
|
|
|
423
410
|
return events.filter((event) => this.subscriber.subscribedEvents.includes(event.type));
|
|
424
411
|
}
|
|
425
412
|
};
|
|
426
|
-
|
|
427
413
|
//#endregion
|
|
428
414
|
exports.TEST_CONTEXT_HEADER = TEST_CONTEXT_HEADER;
|
|
429
415
|
exports.TestEndpointAdaptor = TestEndpointAdaptor;
|
|
@@ -431,4 +417,5 @@ exports.TestFunctionAdaptor = TestFunctionAdaptor;
|
|
|
431
417
|
exports.TestQueueAdaptor = TestQueueAdaptor;
|
|
432
418
|
exports.TestSubscriberAdaptor = TestSubscriberAdaptor;
|
|
433
419
|
exports.createMswHandlers = createMswHandlers;
|
|
420
|
+
|
|
434
421
|
//# sourceMappingURL=testing.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.cjs","names":["endpoints: Endpoint<any, any, any, any, any, any>[]","options: CreateMswHandlersOptions","id: string","ctxOptions: RegisterContextOptions","EnvironmentParser","ServiceDiscovery","serviceDefs: Service[]","handlers: HttpHandler[]","http","Hono","name: string","value: string","options?: CookieOptions","_endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>","EnvironmentParser","endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>","serviceDiscovery: ServiceDiscovery<any>","ctx: TestRequestAdaptor<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>","ForbiddenError","auditContext: AuditExecutionContext<TAuditAction> | undefined","actor: AuditActor","DefaultAuditor","ResponseBuilder","metadata","output","result","headers: Record<string, string | string[]>","setCookieValues: string[]","cookie","_fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>","EnvironmentParser","fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>","serviceDiscovery: ServiceDiscovery<any>","ctx: TestFunctionRequest<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTDatabase,\n\t\t\tTAuditAction\n\t\t>","services: ServiceRecord<TServices>","db: TDatabase | undefined","auditor: Auditor<TAuditAction> | undefined","DefaultAuditor","EnvironmentParser","queue: Queue<TName, TMessage, TServices, TLogger>","serviceDiscovery: ServiceDiscovery<any>","request: TestQueueRequest<TMessage, TServices>","EnvironmentParser","subscriber: Subscriber<\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTSubscribedEvents\n\t\t>","serviceDiscovery: ServiceDiscovery<any>","request: TestSubscriberRequest<\n\t\t\tTEventPublisher,\n\t\t\tTSubscribedEvents,\n\t\t\tTServices\n\t\t>","services: ServiceRecord<TServices>","output: any","events: ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[]","event: any"],"sources":["../../src/endpoints/MswEndpointAdaptor.ts","../../src/endpoints/TestEndpointAdaptor.ts","../../src/functions/TestFunctionAdaptor.ts","../../src/queue/TestQueueAdaptor.ts","../../src/subscribers/TestSubscriberAdaptor.ts"],"sourcesContent":["import { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Service } from '@geekmidas/services';\nimport { ServiceDiscovery } from '@geekmidas/services';\nimport { Hono } from 'hono';\nimport { type HttpHandler, http } from 'msw';\nimport type { Endpoint } from './Endpoint';\nimport { HonoEndpoint } from './HonoEndpointAdaptor';\n\n/**\n * Header used to identify which test context a request belongs to.\n * Each concurrent test registers its own context (services, db transaction, etc.)\n * and the MSW handler looks it up by this header value.\n */\nexport const TEST_CONTEXT_HEADER = 'x-test-context-id';\n\n/**\n * Per-test context containing an isolated ServiceDiscovery instance.\n * Registered in the context map and looked up per-request via the context ID header.\n */\nexport interface MswTestContext {\n\tserviceDiscovery: ServiceDiscovery<any>;\n}\n\n/**\n * Options for creating MSW handlers from endpoint constructs.\n *\n * @example\n * ```typescript\n * import { createMswHandlers, registerTestContext } from '@geekmidas/constructs/testing';\n * import { setupServer } from 'msw/node';\n *\n * // Create handlers once (global)\n * const { handlers, registerContext, removeContext } = createMswHandlers(\n * [getUsers, createUser],\n * { baseURL: 'http://localhost:3000' },\n * );\n * const server = setupServer(...handlers);\n *\n * // Per test: register an isolated context with its own services/transaction\n * it('should list users', async ({ db }) => {\n * const contextId = crypto.randomUUID();\n * registerContext(contextId, {\n * services: { database: db, auth: mockAuth },\n * });\n *\n * const api = createApi({\n * baseURL: 'http://localhost:3000',\n * headers: { [TEST_CONTEXT_HEADER]: contextId },\n * });\n *\n * const result = await api('GET /users');\n * expect(result).toBeDefined();\n *\n * removeContext(contextId);\n * });\n * ```\n */\nexport interface CreateMswHandlersOptions {\n\t/** Base URL the client fetches from (e.g., 'http://localhost:3000') */\n\tbaseURL: string;\n}\n\n/**\n * Options for registering a per-test context.\n * Follows the same pattern as TestRequestAdaptor — services, database,\n * publisher, and auditorStorage are provided explicitly.\n */\nexport interface RegisterContextOptions {\n\t/** Service instances keyed by serviceName */\n\tservices?: Record<string, unknown>;\n\t/** Database instance — required when endpoints use .database() */\n\tdatabase?: unknown;\n\t/** Event publisher service definition */\n\tpublisher?: Service;\n\t/** Audit storage instance — required when endpoints use .auditor() */\n\tauditorStorage?: unknown;\n}\n\nconst MSW_HTTP_METHODS = [\n\t'get',\n\t'post',\n\t'put',\n\t'patch',\n\t'delete',\n\t'options',\n] as const;\n\ntype MswHttpMethod = (typeof MSW_HTTP_METHODS)[number];\n\n/**\n * Result of creating MSW handlers from endpoint constructs.\n */\nexport interface CreateMswHandlersResult {\n\t/** MSW handlers to pass to setupServer() */\n\thandlers: HttpHandler[];\n\t/** Register an isolated context for a test */\n\tregisterContext: (id: string, options: RegisterContextOptions) => void;\n}\n\n/**\n * Creates MSW HTTP handlers from endpoint constructs.\n *\n * Mounts endpoints on a Hono app and creates MSW handlers that intercept\n * fetch requests and route them through `app.request()` — giving frontend\n * tests full endpoint behavior (validation, auth, sessions) without HTTP.\n *\n * Each test registers its own isolated context via `registerContext()`,\n * which is resolved per-request using the `x-test-context-id` header.\n * This allows concurrent tests with their own transactions and services.\n *\n * @param endpoints - Array of endpoint constructs to create handlers for\n * @param options - Configuration including baseURL\n * @returns MSW handlers, the Hono app, and context management functions\n */\nexport function createMswHandlers(\n\tendpoints: Endpoint<any, any, any, any, any, any>[],\n\toptions: CreateMswHandlersOptions,\n): CreateMswHandlersResult {\n\tconst { baseURL } = options;\n\tconst contexts = new Map<string, MswTestContext>();\n\n\t/**\n\t * Register an isolated context for a test.\n\t * Creates a fresh ServiceDiscovery and pre-registers all provided services.\n\t */\n\tfunction registerContext(id: string, ctxOptions: RegisterContextOptions) {\n\t\tconst envParser = new EnvironmentParser({});\n\t\tconst serviceDiscovery = new ServiceDiscovery(envParser);\n\n\t\tconst serviceDefs: Service[] = [];\n\n\t\t// Register explicit services\n\t\tif (ctxOptions.services) {\n\t\t\tfor (const [name, instance] of Object.entries(ctxOptions.services)) {\n\t\t\t\tserviceDefs.push({\n\t\t\t\t\tserviceName: name,\n\t\t\t\t\tregister: () => instance,\n\t\t\t\t} as Service);\n\t\t\t}\n\t\t}\n\n\t\t// Register database service from endpoint metadata\n\t\tif (ctxOptions.database !== undefined) {\n\t\t\tfor (const endpoint of endpoints) {\n\t\t\t\tif (endpoint.databaseService) {\n\t\t\t\t\tserviceDefs.push({\n\t\t\t\t\t\tserviceName: endpoint.databaseService.serviceName,\n\t\t\t\t\t\tregister: () => ctxOptions.database,\n\t\t\t\t\t} as Service);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Register publisher service\n\t\tif (ctxOptions.publisher) {\n\t\t\tserviceDefs.push(ctxOptions.publisher);\n\t\t}\n\n\t\t// Register auditor storage service from endpoint metadata\n\t\tif (ctxOptions.auditorStorage !== undefined) {\n\t\t\tfor (const endpoint of endpoints) {\n\t\t\t\tif (endpoint.auditorStorageService) {\n\t\t\t\t\tserviceDefs.push({\n\t\t\t\t\t\tserviceName: endpoint.auditorStorageService.serviceName,\n\t\t\t\t\t\tregister: () => ctxOptions.auditorStorage,\n\t\t\t\t\t} as Service);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (serviceDefs.length > 0) {\n\t\t\tserviceDiscovery.register(serviceDefs);\n\t\t}\n\n\t\tcontexts.set(id, { serviceDiscovery });\n\t}\n\n\t// Create a Hono app per-request that uses the correct ServiceDiscovery.\n\t// We use a wrapper app that resolves the context from the header,\n\t// then delegates to a context-specific Hono app.\n\tconst handlers: HttpHandler[] = [];\n\n\tfor (const endpoint of endpoints) {\n\t\tconst method = endpoint.method.toLowerCase() as MswHttpMethod;\n\t\tif (!MSW_HTTP_METHODS.includes(method)) continue;\n\n\t\tconst mswUrl = `${baseURL}${endpoint.route}`;\n\t\tconst mswMethod = http[method];\n\n\t\thandlers.push(\n\t\t\tmswMethod(mswUrl, async ({ request }) => {\n\t\t\t\tconst contextId = request.headers.get(TEST_CONTEXT_HEADER);\n\t\t\t\tconst ctx = contextId ? contexts.get(contextId) : undefined;\n\n\t\t\t\tif (!ctx) {\n\t\t\t\t\treturn new Response(\n\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\terror: 'Missing or unknown test context ID',\n\t\t\t\t\t\t\thint: `Set the '${TEST_CONTEXT_HEADER}' header to a registered context ID`,\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t{ status: 500, headers: { 'content-type': 'application/json' } },\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Build a fresh Hono app with this context's ServiceDiscovery\n\t\t\t\tconst app = new Hono();\n\t\t\t\tHonoEndpoint.addRoute(endpoint, ctx.serviceDiscovery as any, app);\n\n\t\t\t\tconst response = await app.request(request);\n\n\t\t\t\treturn new Response(response.body, {\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t\tstatusText: response.statusText,\n\t\t\t\t\theaders: response.headers,\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn {\n\t\thandlers,\n\t\tregisterContext,\n\t};\n}\n","import type {\n\tAuditActor,\n\tAuditableAction,\n\tAuditStorage,\n} from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport { ForbiddenError } from '@geekmidas/errors';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\trunWithRequestContext,\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishConstructEvents } from '../publisher';\nimport type { HttpMethod } from '../types';\nimport type { MappedAudit } from './audit';\nimport {\n\ttype CookieOptions,\n\tEndpoint,\n\ttype EndpointSchemas,\n\tResponseBuilder,\n} from './Endpoint';\nimport {\n\tcreateCookieHeaderAccessor,\n\tcreateObjectHeaders,\n} from './lazyAccessors';\nimport {\n\ttype AuditExecutionContext,\n\texecuteWithAuditTransaction,\n} from './processAudits';\n\nexport type TestHttpResponse<TBody = any> = {\n\tbody: TBody;\n\tstatus: number;\n\theaders: Record<string, string | string[]>;\n};\n\n/**\n * Serializes a cookie into a Set-Cookie header string\n */\nfunction serializeCookie(\n\tname: string,\n\tvalue: string,\n\toptions?: CookieOptions,\n): string {\n\tlet cookieString = `${name}=${value}`;\n\n\tif (options) {\n\t\tif (options.maxAge !== undefined) {\n\t\t\tcookieString += `; Max-Age=${options.maxAge}`;\n\t\t}\n\t\tif (options.expires) {\n\t\t\tcookieString += `; Expires=${options.expires.toUTCString()}`;\n\t\t}\n\t\tif (options.domain) {\n\t\t\tcookieString += `; Domain=${options.domain}`;\n\t\t}\n\t\tif (options.path) {\n\t\t\tcookieString += `; Path=${options.path}`;\n\t\t}\n\t\tif (options.httpOnly) {\n\t\t\tcookieString += '; HttpOnly';\n\t\t}\n\t\tif (options.secure) {\n\t\t\tcookieString += '; Secure';\n\t\t}\n\t\tif (options.sameSite) {\n\t\t\tcookieString += `; SameSite=${options.sameSite}`;\n\t\t}\n\t}\n\n\treturn cookieString;\n}\n\nexport class TestEndpointAdaptor<\n\tTRoute extends string,\n\tTMethod extends HttpMethod,\n\tTInput extends EndpointSchemas = {},\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTSession = unknown,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> {\n\tstatic getDefaultServiceDiscover<\n\t\tTRoute extends string,\n\t\tTMethod extends HttpMethod,\n\t\tTInput extends EndpointSchemas = {},\n\t\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\t\tTServices extends Service[] = [],\n\t\tTLogger extends Logger = Logger,\n\t\tTSession = unknown,\n\t\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\t\tTEventPublisherServiceName extends string = string,\n\t\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t\tTAuditStorageServiceName extends string = string,\n\t\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>,\n\t\tTDatabase = undefined,\n\t\tTDatabaseServiceName extends string = string,\n\t>(\n\t\t_endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t) {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\tconstructor(\n\t\tprivate readonly endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestEndpointAdaptor.getDefaultServiceDiscover(\n\t\t\tendpoint,\n\t\t),\n\t) {}\n\n\tasync fullRequest(\n\t\tctx: TestRequestAdaptor<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t): Promise<TestHttpResponse<InferStandardSchema<TOutSchema>>> {\n\t\tconst body = await this.endpoint.parseInput((ctx as any).body, 'body');\n\t\tconst query = await this.endpoint.parseInput((ctx as any).query, 'query');\n\t\tconst params = await this.endpoint.parseInput(\n\t\t\t(ctx as any).params,\n\t\t\t'params',\n\t\t);\n\n\t\t// Lazy accessors - defer parsing until needed\n\t\tconst header = createObjectHeaders(ctx.headers);\n\t\tconst cookie = createCookieHeaderAccessor(ctx.headers.cookie);\n\n\t\t// Request context setup\n\t\tconst startTime = Date.now();\n\t\tconst requestId =\n\t\t\t(ctx as any).requestId ??\n\t\t\tctx.headers['x-request-id'] ??\n\t\t\tcrypto.randomUUID();\n\n\t\tconst logger = this.endpoint.logger.child({\n\t\t\trequestId,\n\t\t\troute: this.endpoint.route,\n\t\t\thost: ctx.headers.host,\n\t\t\tmethod: this.endpoint.method,\n\t\t}) as TLogger;\n\n\t\t// Get database from context for session extraction\n\t\tconst rawDb = (ctx as any).database as TDatabase;\n\n\t\t// Wrap handler execution in request context\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, async () => {\n\t\t\tconst session = await this.endpoint.getSession({\n\t\t\t\tlogger,\n\t\t\t\tservices: ctx.services,\n\t\t\t\theader,\n\t\t\t\tcookie,\n\t\t\t\t...(rawDb !== undefined && { db: rawDb }),\n\t\t\t} as any);\n\n\t\t\t// Check authorization\n\t\t\tconst isAuthorized = await this.endpoint.authorize({\n\t\t\t\theader,\n\t\t\t\tcookie,\n\t\t\t\tservices: ctx.services,\n\t\t\t\tlogger,\n\t\t\t\tsession,\n\t\t\t\t...(rawDb !== undefined && { db: rawDb }),\n\t\t\t\tbody,\n\t\t\t\tquery,\n\t\t\t\tparams,\n\t\t\t} as any);\n\n\t\t\tif (!isAuthorized) {\n\t\t\t\tlogger.warn('Forbidden access attempt');\n\t\t\t\tthrow new ForbiddenError(\n\t\t\t\t\t'Forbidden access to the endpoint',\n\t\t\t\t\t'You do not have permission to access this resource.',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Create audit context if audit storage is provided\n\t\t\t// The auditorStorage instance is required when endpoint uses .auditor()\n\t\t\tconst auditorStorage = (ctx as any).auditorStorage as TAuditStorage;\n\t\t\tlet auditContext: AuditExecutionContext<TAuditAction> | undefined;\n\n\t\t\tif (auditorStorage) {\n\t\t\t\t// Extract actor if configured\n\t\t\t\tlet actor: AuditActor = { id: 'system', type: 'system' };\n\t\t\t\tif (this.endpoint.actorExtractor) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tactor = await this.endpoint.actorExtractor({\n\t\t\t\t\t\t\tservices: ctx.services as any,\n\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\tcookie,\n\t\t\t\t\t\t\tlogger,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger.error(error as Error, 'Failed to extract actor for audits');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst auditor = new DefaultAuditor<TAuditAction>({\n\t\t\t\t\tactor,\n\t\t\t\t\tstorage: auditorStorage as AuditStorage,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tendpoint: this.endpoint.route,\n\t\t\t\t\t\tmethod: this.endpoint.method,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tauditContext = { auditor, storage: auditorStorage as AuditStorage };\n\t\t\t}\n\n\t\t\t// Warn if declarative audits are configured but no audit storage\n\t\t\tconst audits = this.endpoint.audits as MappedAudit<\n\t\t\t\tTAuditAction,\n\t\t\t\tTOutSchema\n\t\t\t>[];\n\t\t\tif (!auditContext && audits?.length) {\n\t\t\t\tlogger.warn('No auditor storage service available');\n\t\t\t}\n\n\t\t\t// Execute handler with automatic audit transaction support\n\t\t\tconst result = await executeWithAuditTransaction(\n\t\t\t\tauditContext,\n\t\t\t\tasync (auditor) => {\n\t\t\t\t\t// Use audit transaction as db if available (when storage has same database)\n\t\t\t\t\t// For testing, the tester controls whether to use transactional auditing\n\t\t\t\t\tconst trx = auditor?.getTransaction?.();\n\t\t\t\t\tconst db = trx ?? rawDb;\n\n\t\t\t\t\tconst responseBuilder = new ResponseBuilder();\n\t\t\t\t\tconst response = await this.endpoint.handler(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbody,\n\t\t\t\t\t\t\tquery,\n\t\t\t\t\t\t\tparams,\n\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\tservices: ctx.services,\n\t\t\t\t\t\t\tlogger,\n\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\tcookie,\n\t\t\t\t\t\t\tauditor,\n\t\t\t\t\t\t\tdb,\n\t\t\t\t\t\t} as any,\n\t\t\t\t\t\tresponseBuilder,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Check if response has metadata\n\t\t\t\t\tlet data = response;\n\t\t\t\t\tlet metadata = responseBuilder.getMetadata();\n\n\t\t\t\t\tif (Endpoint.hasMetadata(response)) {\n\t\t\t\t\t\tdata = response.data;\n\t\t\t\t\t\tmetadata = response.metadata;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst output = await this.endpoint.parseOutput(data);\n\n\t\t\t\t\treturn { output, metadata, responseBuilder };\n\t\t\t\t},\n\t\t\t\t// Process declarative audits after handler (inside transaction)\n\t\t\t\tasync (result, auditor) => {\n\t\t\t\t\tif (!audits?.length) return;\n\n\t\t\t\t\tfor (const audit of audits) {\n\t\t\t\t\t\tif (audit.when && !audit.when(result.output as any)) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst payload = audit.payload(result.output as any);\n\t\t\t\t\t\tconst entityId = audit.entityId?.(result.output as any);\n\t\t\t\t\t\tauditor.audit(audit.type as any, payload as any, {\n\t\t\t\t\t\t\ttable: audit.table,\n\t\t\t\t\t\t\tentityId,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t// Pass rawDb so storage can reuse existing transactions\n\t\t\t\t{ db: rawDb },\n\t\t\t);\n\n\t\t\tconst { output, metadata } = result;\n\n\t\t\tctx.publisher && (await this.serviceDiscovery.register([ctx.publisher]));\n\t\t\tawait publishConstructEvents(\n\t\t\t\tthis.endpoint,\n\t\t\t\toutput,\n\t\t\t\tthis.serviceDiscovery,\n\t\t\t);\n\n\t\t\t// Convert cookies to Set-Cookie headers\n\t\t\tconst headers: Record<string, string | string[]> = {\n\t\t\t\t...(metadata.headers || {}),\n\t\t\t};\n\n\t\t\tif (metadata.cookies && metadata.cookies.size > 0) {\n\t\t\t\tconst setCookieValues: string[] = [];\n\t\t\t\tfor (const [name, cookie] of metadata.cookies.entries()) {\n\t\t\t\t\tsetCookieValues.push(\n\t\t\t\t\t\tserializeCookie(name, cookie.value, cookie.options),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\theaders['set-cookie'] = setCookieValues;\n\t\t\t}\n\n\t\t\t// Return HTTP response format\n\t\t\treturn {\n\t\t\t\tbody: output,\n\t\t\t\tstatus: metadata.status || 200,\n\t\t\t\theaders,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync request(\n\t\tctx: TestRequestAdaptor<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t): Promise<InferStandardSchema<TOutSchema>> {\n\t\tconst response = await this.fullRequest(ctx);\n\t\treturn response.body;\n\t}\n}\n\n/**\n * Conditional audit storage requirement - required when TAuditStorage is configured\n */\ntype AuditStorageRequirement<\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n> = TAuditStorage extends undefined\n\t? {}\n\t: {\n\t\t\t/** Audit storage instance - required when endpoint uses .auditor() */\n\t\t\tauditorStorage: TAuditStorage;\n\t\t};\n\n/**\n * Conditional database requirement - required when TDatabase is configured\n */\ntype DatabaseRequirement<TDatabase = undefined> = TDatabase extends undefined\n\t? {}\n\t: {\n\t\t\t/** Database instance - required when endpoint uses .database() */\n\t\t\tdatabase: TDatabase;\n\t\t};\n\nexport type TestRequestAdaptor<\n\tTInput extends EndpointSchemas = {},\n\tTServices extends Service[] = [],\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t_TAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\t_TDatabaseServiceName extends string = string,\n> = {\n\tservices: ServiceRecord<TServices>;\n\theaders: Record<string, string>;\n\tpublisher?: Service<TEventPublisherServiceName, TEventPublisher>;\n} & InferComposableStandardSchema<TInput> &\n\tAuditStorageRequirement<TAuditStorage> &\n\tDatabaseRequirement<TDatabase>;\n","import type { AuditableAction, Auditor, AuditStorage } from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tComposableStandardSchema,\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\trunWithRequestContext,\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishEvents } from '../publisher';\nimport type { Function } from './Function';\nimport { FunctionBuilder } from './FunctionBuilder';\n\nexport class TestFunctionAdaptor<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> {\n\tstatic getDefaultServiceDiscovery<\n\t\tTInput extends ComposableStandardSchema | undefined = undefined,\n\t\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\t\tTServices extends Service[] = [],\n\t\tTLogger extends Logger = Logger,\n\t\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\t\tTEventPublisherServiceName extends string = string,\n\t\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t\tTAuditStorageServiceName extends string = string,\n\t\tTDatabase = undefined,\n\t\tTDatabaseServiceName extends string = string,\n\t\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>,\n\t>(\n\t\t_fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>,\n\t) {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestFunctionAdaptor.getDefaultServiceDiscovery(\n\t\t\tfn,\n\t\t),\n\t) {}\n\n\tasync invoke(\n\t\tctx: TestFunctionRequest<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTDatabase,\n\t\t\tTAuditAction\n\t\t>,\n\t): Promise<InferStandardSchema<TOutSchema>> {\n\t\t// Parse input if schema is provided\n\n\t\tconst parsedInput = await FunctionBuilder.parseComposableStandardSchema(\n\t\t\tctx.input,\n\t\t\tthis.fn.input,\n\t\t);\n\n\t\t// Create logger with context\n\t\tconst logger = this.fn.logger.child({\n\t\t\ttest: true,\n\t\t}) as TLogger;\n\n\t\t// Register services (use provided services or register from function)\n\t\tlet services: ServiceRecord<TServices>;\n\t\tif (ctx.services) {\n\t\t\tservices = ctx.services;\n\t\t} else {\n\t\t\tservices = await this.serviceDiscovery.register(this.fn.services);\n\t\t}\n\n\t\t// Resolve database (use provided db or register from function)\n\t\tlet db: TDatabase | undefined;\n\t\tif ('db' in ctx && ctx.db !== undefined) {\n\t\t\tdb = ctx.db;\n\t\t} else if (this.fn.databaseService) {\n\t\t\tconst dbServices = await this.serviceDiscovery.register([\n\t\t\t\tthis.fn.databaseService,\n\t\t\t]);\n\t\t\tdb = dbServices[\n\t\t\t\tthis.fn.databaseService.serviceName as keyof typeof dbServices\n\t\t\t] as TDatabase;\n\t\t}\n\n\t\t// Resolve auditor (use provided auditor or create from function)\n\t\tlet auditor: Auditor<TAuditAction> | undefined;\n\t\tif ('auditor' in ctx && ctx.auditor !== undefined) {\n\t\t\tauditor = ctx.auditor;\n\t\t} else if (this.fn.auditorStorageService) {\n\t\t\tconst auditServices = await this.serviceDiscovery.register([\n\t\t\t\tthis.fn.auditorStorageService,\n\t\t\t]);\n\t\t\tconst storage = auditServices[\n\t\t\t\tthis.fn.auditorStorageService.serviceName as keyof typeof auditServices\n\t\t\t] as AuditStorage;\n\n\t\t\tauditor = new DefaultAuditor<TAuditAction>({\n\t\t\t\tactor: { id: 'system', type: 'system' },\n\t\t\t\tstorage,\n\t\t\t\tmetadata: {\n\t\t\t\t\tfunction: this.fn.type,\n\t\t\t\t\ttest: true,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Wrap execution in request context for service access via context.getLogger()\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, async () => {\n\t\t\t// Execute the function\n\t\t\tconst response = await this.fn.fn({\n\t\t\t\tinput: parsedInput,\n\t\t\t\tservices,\n\t\t\t\tlogger,\n\t\t\t\tdb,\n\t\t\t\tauditor,\n\t\t\t} as any);\n\n\t\t\t// Parse output if schema is provided\n\t\t\tconst output = await this.fn.parseOutput(response);\n\n\t\t\t// Flush audits if any were recorded\n\t\t\tif (auditor) {\n\t\t\t\tconst records = auditor.getRecords();\n\t\t\t\tif (records.length > 0) {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t{ auditCount: records.length },\n\t\t\t\t\t\t'Flushing function audits',\n\t\t\t\t\t);\n\t\t\t\t\tawait auditor.flush();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Register publisher service if provided in context\n\n\t\t\tawait publishEvents(\n\t\t\t\tlogger,\n\t\t\t\tthis.serviceDiscovery,\n\t\t\t\tthis.fn.events,\n\t\t\t\toutput,\n\t\t\t\tthis.fn.publisherService,\n\t\t\t);\n\n\t\t\treturn output;\n\t\t}) as Promise<InferStandardSchema<TOutSchema>>;\n\t}\n}\n\nexport type TestFunctionRequest<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTDatabase = undefined,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> = {\n\tinput: InferComposableStandardSchema<TInput>;\n\tservices: ServiceRecord<TServices>;\n\tpublisher?: Service<TEventPublisherServiceName, TEventPublisher>;\n\tdb?: TDatabase;\n\tauditor?: Auditor<TAuditAction>;\n} & InferComposableStandardSchema<{ input: TInput }>;\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Queue } from './Queue';\n\n/**\n * In-memory test driver for a {@link Queue} worker. Hand it a batch of messages\n * and it registers the queue's services, runs the handler in a request context,\n * and returns the handler result — no SQS/pg-boss required.\n *\n * @example\n * const adapter = new TestQueueAdaptor(ordersQueue);\n * await adapter.invoke({ messages: [{ orderId: '123' }] });\n */\nexport class TestQueueAdaptor<\n\tTName extends string = string,\n\tTMessage extends StandardSchemaV1 = StandardSchemaV1,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n> {\n\tstatic getDefaultServiceDiscovery() {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly queue: Queue<TName, TMessage, TServices, TLogger>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestQueueAdaptor.getDefaultServiceDiscovery(),\n\t) {}\n\n\tasync invoke(\n\t\trequest: TestQueueRequest<TMessage, TServices>,\n\t): Promise<unknown> {\n\t\tconst logger = this.queue.logger.child({ test: true }) as TLogger;\n\n\t\tconst services =\n\t\t\trequest.services ??\n\t\t\t((await this.serviceDiscovery.register(\n\t\t\t\tthis.queue.services,\n\t\t\t)) as ServiceRecord<TServices>);\n\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, () =>\n\t\t\tthis.queue.handler({\n\t\t\t\tmessages: request.messages,\n\t\t\t\tservices,\n\t\t\t\tlogger,\n\t\t\t}),\n\t\t);\n\t}\n}\n\nexport type TestQueueRequest<\n\tTMessage extends StandardSchemaV1 = StandardSchemaV1,\n\tTServices extends Service[] = [],\n> = {\n\tmessages: InferStandardSchema<TMessage>[];\n\tservices?: ServiceRecord<TServices>;\n};\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type {\n\tEventPublisher,\n\tExtractPublisherMessage,\n} from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishEvents } from '../publisher';\nimport type { Subscriber } from './Subscriber';\n\n// Helper type to extract payload types for subscribed events\ntype ExtractEventPayloads<\n\tTPublisher extends EventPublisher<any> | undefined,\n\tTEventTypes extends any[],\n> = TPublisher extends EventPublisher<any>\n\t? Extract<ExtractPublisherMessage<TPublisher>, { type: TEventTypes[number] }>\n\t: never;\n\nexport class TestSubscriberAdaptor<\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTSubscribedEvents extends\n\t\tExtractPublisherMessage<TEventPublisher>['type'][] = ExtractPublisherMessage<TEventPublisher>['type'][],\n> {\n\tstatic getDefaultServiceDiscovery() {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly subscriber: Subscriber<\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTSubscribedEvents\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestSubscriberAdaptor.getDefaultServiceDiscovery(),\n\t) {}\n\n\tasync invoke(\n\t\trequest: TestSubscriberRequest<\n\t\t\tTEventPublisher,\n\t\t\tTSubscribedEvents,\n\t\t\tTServices\n\t\t>,\n\t): Promise<InferStandardSchema<OutSchema>> {\n\t\t// Create logger with test context\n\t\tconst logger = this.subscriber.logger.child({\n\t\t\ttest: true,\n\t\t}) as TLogger;\n\n\t\t// Resolve services (use provided or auto-register)\n\t\tlet services: ServiceRecord<TServices>;\n\t\tif (request.services) {\n\t\t\tservices = request.services;\n\t\t} else {\n\t\t\tservices = await this.serviceDiscovery.register(this.subscriber.services);\n\t\t}\n\n\t\t// Filter events to only subscribed types\n\t\tconst filteredEvents = this.filterEvents(request.events);\n\n\t\t// Return early if no events after filtering (mirrors AWSLambdaSubscriber)\n\t\tif (filteredEvents.length === 0) {\n\t\t\treturn { batchItemFailures: [] } as any;\n\t\t}\n\n\t\t// Wrap execution in request context for service access via context.getLogger()\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, async () => {\n\t\t\t// Execute the subscriber handler\n\t\t\tconst result = await this.subscriber.handler({\n\t\t\t\tevents: filteredEvents,\n\t\t\t\tservices,\n\t\t\t\tlogger,\n\t\t\t});\n\n\t\t\t// Validate output if schema is provided\n\t\t\tlet output: any = result;\n\t\t\tif (this.subscriber.outputSchema && result) {\n\t\t\t\tconst validationResult =\n\t\t\t\t\tawait this.subscriber.outputSchema['~standard'].validate(result);\n\n\t\t\t\tif (validationResult.issues) {\n\t\t\t\t\tthrow new Error('Subscriber output validation failed');\n\t\t\t\t}\n\n\t\t\t\toutput = validationResult.value;\n\t\t\t}\n\n\t\t\t// Publish events if configured\n\t\t\tawait publishEvents(\n\t\t\t\tlogger,\n\t\t\t\tthis.serviceDiscovery,\n\t\t\t\tthis.subscriber.events,\n\t\t\t\toutput,\n\t\t\t\tthis.subscriber.publisherService,\n\t\t\t);\n\n\t\t\treturn output;\n\t\t}) as Promise<InferStandardSchema<OutSchema>>;\n\t}\n\n\tprivate filterEvents(\n\t\tevents: ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[],\n\t): ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[] {\n\t\tif (!this.subscriber.subscribedEvents) {\n\t\t\treturn events;\n\t\t}\n\n\t\treturn events.filter((event: any) =>\n\t\t\tthis.subscriber.subscribedEvents!.includes(event.type),\n\t\t);\n\t}\n}\n\nexport type TestSubscriberRequest<\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTSubscribedEvents extends any[] = [],\n\tTServices extends Service[] = [],\n> = {\n\tevents: ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[];\n\tservices?: ServiceRecord<TServices>;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAaA,MAAa,sBAAsB;AAiEnC,MAAM,mBAAmB;CACxB;CACA;CACA;CACA;CACA;CACA;AACA;;;;;;;;;;;;;;;;AA6BD,SAAgB,kBACfA,WACAC,SAC0B;CAC1B,MAAM,EAAE,SAAS,GAAG;CACpB,MAAM,2BAAW,IAAI;;;;;CAMrB,SAAS,gBAAgBC,IAAYC,YAAoC;EACxE,MAAM,YAAY,IAAIC,qCAAkB,CAAE;EAC1C,MAAM,mBAAmB,IAAIC,sCAAiB;EAE9C,MAAMC,cAAyB,CAAE;AAGjC,MAAI,WAAW,SACd,MAAK,MAAM,CAAC,MAAM,SAAS,IAAI,OAAO,QAAQ,WAAW,SAAS,CACjE,aAAY,KAAK;GAChB,aAAa;GACb,UAAU,MAAM;EAChB,EAAY;AAKf,MAAI,WAAW,qBACd;QAAK,MAAM,YAAY,UACtB,KAAI,SAAS,iBAAiB;AAC7B,gBAAY,KAAK;KAChB,aAAa,SAAS,gBAAgB;KACtC,UAAU,MAAM,WAAW;IAC3B,EAAY;AACb;GACA;EACD;AAIF,MAAI,WAAW,UACd,aAAY,KAAK,WAAW,UAAU;AAIvC,MAAI,WAAW,2BACd;QAAK,MAAM,YAAY,UACtB,KAAI,SAAS,uBAAuB;AACnC,gBAAY,KAAK;KAChB,aAAa,SAAS,sBAAsB;KAC5C,UAAU,MAAM,WAAW;IAC3B,EAAY;AACb;GACA;EACD;AAGF,MAAI,YAAY,SAAS,EACxB,kBAAiB,SAAS,YAAY;AAGvC,WAAS,IAAI,IAAI,EAAE,iBAAkB,EAAC;CACtC;CAKD,MAAMC,WAA0B,CAAE;AAElC,MAAK,MAAM,YAAY,WAAW;EACjC,MAAM,SAAS,SAAS,OAAO,aAAa;AAC5C,OAAK,iBAAiB,SAAS,OAAO,CAAE;EAExC,MAAM,UAAU,EAAE,QAAQ,EAAE,SAAS,MAAM;EAC3C,MAAM,YAAYC,SAAK;AAEvB,WAAS,KACR,UAAU,QAAQ,OAAO,EAAE,SAAS,KAAK;GACxC,MAAM,YAAY,QAAQ,QAAQ,IAAI,oBAAoB;GAC1D,MAAM,MAAM,YAAY,SAAS,IAAI,UAAU;AAE/C,QAAK,IACJ,QAAO,IAAI,SACV,KAAK,UAAU;IACd,OAAO;IACP,OAAO,WAAW,oBAAoB;GACtC,EAAC,EACF;IAAE,QAAQ;IAAK,SAAS,EAAE,gBAAgB,mBAAoB;GAAE;GAKlE,MAAM,MAAM,IAAIC;AAChB,4CAAa,SAAS,UAAU,IAAI,kBAAyB,IAAI;GAEjE,MAAM,WAAW,MAAM,IAAI,QAAQ,QAAQ;AAE3C,UAAO,IAAI,SAAS,SAAS,MAAM;IAClC,QAAQ,SAAS;IACjB,YAAY,SAAS;IACrB,SAAS,SAAS;GAClB;EACD,EAAC,CACF;CACD;AAED,QAAO;EACN;EACA;CACA;AACD;;;;;;;ACjLD,SAAS,gBACRC,MACAC,OACAC,SACS;CACT,IAAI,gBAAgB,EAAE,KAAK,GAAG,MAAM;AAEpC,KAAI,SAAS;AACZ,MAAI,QAAQ,kBACX,kBAAiB,YAAY,QAAQ,OAAO;AAE7C,MAAI,QAAQ,QACX,kBAAiB,YAAY,QAAQ,QAAQ,aAAa,CAAC;AAE5D,MAAI,QAAQ,OACX,kBAAiB,WAAW,QAAQ,OAAO;AAE5C,MAAI,QAAQ,KACX,kBAAiB,SAAS,QAAQ,KAAK;AAExC,MAAI,QAAQ,SACX,iBAAgB;AAEjB,MAAI,QAAQ,OACX,iBAAgB;AAEjB,MAAI,QAAQ,SACX,kBAAiB,aAAa,QAAQ,SAAS;CAEhD;AAED,QAAO;AACP;AAED,IAAa,sBAAb,MAAa,oBAkBX;CACD,OAAO,0BAmBNC,WAgBC;AACD,SAAO,sCAAiB,YAAY,IAAIC,qCAAkB,CAAE,GAAE;CAC9D;CACD,YACkBC,UAgBTC,mBAA0C,oBAAoB,0BACrE,SACA,EACA;EAnBgB;EAgBT;CAGL;CAEJ,MAAM,YACLC,KAU6D;EAC7D,MAAM,OAAO,MAAM,KAAK,SAAS,WAAY,IAAY,MAAM,OAAO;EACtE,MAAM,QAAQ,MAAM,KAAK,SAAS,WAAY,IAAY,OAAO,QAAQ;EACzE,MAAM,SAAS,MAAM,KAAK,SAAS,WACjC,IAAY,QACb,SACA;EAGD,MAAM,SAAS,0CAAoB,IAAI,QAAQ;EAC/C,MAAM,SAAS,iDAA2B,IAAI,QAAQ,OAAO;EAG7D,MAAM,YAAY,KAAK,KAAK;EAC5B,MAAM,YACJ,IAAY,aACb,IAAI,QAAQ,mBACZ,OAAO,YAAY;EAEpB,MAAM,SAAS,KAAK,SAAS,OAAO,MAAM;GACzC;GACA,OAAO,KAAK,SAAS;GACrB,MAAM,IAAI,QAAQ;GAClB,QAAQ,KAAK,SAAS;EACtB,EAAC;EAGF,MAAM,QAAS,IAAY;AAG3B,SAAO,gDAAsB;GAAE;GAAQ;GAAW;EAAW,GAAE,YAAY;GAC1E,MAAM,UAAU,MAAM,KAAK,SAAS,WAAW;IAC9C;IACA,UAAU,IAAI;IACd;IACA;IACA,GAAI,oBAAuB,EAAE,IAAI,MAAO;GACxC,EAAQ;GAGT,MAAM,eAAe,MAAM,KAAK,SAAS,UAAU;IAClD;IACA;IACA,UAAU,IAAI;IACd;IACA;IACA,GAAI,oBAAuB,EAAE,IAAI,MAAO;IACxC;IACA;IACA;GACA,EAAQ;AAET,QAAK,cAAc;AAClB,WAAO,KAAK,2BAA2B;AACvC,UAAM,IAAIC,kCACT,oCACA;GAED;GAID,MAAM,iBAAkB,IAAY;GACpC,IAAIC;AAEJ,OAAI,gBAAgB;IAEnB,IAAIC,QAAoB;KAAE,IAAI;KAAU,MAAM;IAAU;AACxD,QAAI,KAAK,SAAS,eACjB,KAAI;AACH,aAAQ,MAAM,KAAK,SAAS,eAAe;MAC1C,UAAU,IAAI;MACd;MACA;MACA;MACA;KACA,EAAC;IACF,SAAQ,OAAO;AACf,YAAO,MAAM,OAAgB,qCAAqC;IAClE;IAGF,MAAM,UAAU,IAAIC,iCAA6B;KAChD;KACA,SAAS;KACT,UAAU;MACT,UAAU,KAAK,SAAS;MACxB,QAAQ,KAAK,SAAS;KACtB;IACD;AAED,mBAAe;KAAE;KAAS,SAAS;IAAgC;GACnE;GAGD,MAAM,SAAS,KAAK,SAAS;AAI7B,QAAK,gBAAgB,QAAQ,OAC5B,QAAO,KAAK,uCAAuC;GAIpD,MAAM,SAAS,MAAM,kDACpB,cACA,OAAO,YAAY;IAGlB,MAAM,MAAM,SAAS,kBAAkB;IACvC,MAAM,KAAK,OAAO;IAElB,MAAM,kBAAkB,IAAIC;IAC5B,MAAM,WAAW,MAAM,KAAK,SAAS,QACpC;KACC;KACA;KACA;KACA;KACA,UAAU,IAAI;KACd;KACA;KACA;KACA;KACA;IACA,GACD,gBACA;IAGD,IAAI,OAAO;IACX,IAAIC,aAAW,gBAAgB,aAAa;AAE5C,QAAI,0BAAS,YAAY,SAAS,EAAE;AACnC,YAAO,SAAS;AAChB,kBAAW,SAAS;IACpB;IAED,MAAMC,WAAS,MAAM,KAAK,SAAS,YAAY,KAAK;AAEpD,WAAO;KAAE;KAAQ;KAAU;IAAiB;GAC5C,GAED,OAAOC,UAAQ,YAAY;AAC1B,SAAK,QAAQ,OAAQ;AAErB,SAAK,MAAM,SAAS,QAAQ;AAC3B,SAAI,MAAM,SAAS,MAAM,KAAKA,SAAO,OAAc,CAClD;KAED,MAAM,UAAU,MAAM,QAAQA,SAAO,OAAc;KACnD,MAAM,WAAW,MAAM,WAAWA,SAAO,OAAc;AACvD,aAAQ,MAAM,MAAM,MAAa,SAAgB;MAChD,OAAO,MAAM;MACb;KACA,EAAC;IACF;GACD,GAED,EAAE,IAAI,MAAO,EACb;GAED,MAAM,EAAE,QAAQ,UAAU,GAAG;AAE7B,OAAI,aAAc,MAAM,KAAK,iBAAiB,SAAS,CAAC,IAAI,SAAU,EAAC;AACvE,SAAM,6CACL,KAAK,UACL,QACA,KAAK,iBACL;GAGD,MAAMC,UAA6C,EAClD,GAAI,SAAS,WAAW,CAAE,EAC1B;AAED,OAAI,SAAS,WAAW,SAAS,QAAQ,OAAO,GAAG;IAClD,MAAMC,kBAA4B,CAAE;AACpC,SAAK,MAAM,CAAC,MAAMC,SAAO,IAAI,SAAS,QAAQ,SAAS,CACtD,iBAAgB,KACf,gBAAgB,MAAMA,SAAO,OAAOA,SAAO,QAAQ,CACnD;AAEF,YAAQ,gBAAgB;GACxB;AAGD,UAAO;IACN,MAAM;IACN,QAAQ,SAAS,UAAU;IAC3B;GACA;EACD,EAAC;CACF;CAED,MAAM,QACLX,KAU2C;EAC3C,MAAM,WAAW,MAAM,KAAK,YAAY,IAAI;AAC5C,SAAO,SAAS;CAChB;AACD;;;;ACzWD,IAAa,sBAAb,MAAa,oBAeX;CACD,OAAO,2BAgBNY,KAcC;AACD,SAAO,sCAAiB,YAAY,IAAIC,qCAAkB,CAAE,GAAE;CAC9D;CAED,YACkBC,IAcTC,mBAA0C,oBAAoB,2BACrE,GACA,EACA;EAjBgB;EAcT;CAGL;CAEJ,MAAM,OACLC,KAQ2C;EAG3C,MAAM,cAAc,MAAM,kCAAgB,8BACzC,IAAI,OACJ,KAAK,GAAG,MACR;EAGD,MAAM,SAAS,KAAK,GAAG,OAAO,MAAM,EACnC,MAAM,KACN,EAAC;EAGF,IAAIC;AACJ,MAAI,IAAI,SACP,YAAW,IAAI;MAEf,YAAW,MAAM,KAAK,iBAAiB,SAAS,KAAK,GAAG,SAAS;EAIlE,IAAIC;AACJ,MAAI,QAAQ,OAAO,IAAI,cACtB,MAAK,IAAI;WACC,KAAK,GAAG,iBAAiB;GACnC,MAAM,aAAa,MAAM,KAAK,iBAAiB,SAAS,CACvD,KAAK,GAAG,eACR,EAAC;AACF,QAAK,WACJ,KAAK,GAAG,gBAAgB;EAEzB;EAGD,IAAIC;AACJ,MAAI,aAAa,OAAO,IAAI,mBAC3B,WAAU,IAAI;WACJ,KAAK,GAAG,uBAAuB;GACzC,MAAM,gBAAgB,MAAM,KAAK,iBAAiB,SAAS,CAC1D,KAAK,GAAG,qBACR,EAAC;GACF,MAAM,UAAU,cACf,KAAK,GAAG,sBAAsB;AAG/B,aAAU,IAAIC,iCAA6B;IAC1C,OAAO;KAAE,IAAI;KAAU,MAAM;IAAU;IACvC;IACA,UAAU;KACT,UAAU,KAAK,GAAG;KAClB,MAAM;IACN;GACD;EACD;EAGD,MAAM,aAAa,OAAO,KAAK,KAAK,CAAC;EACrC,MAAM,YAAY,KAAK,KAAK;AAE5B,SAAO,gDAAsB;GAAE;GAAQ;GAAW;EAAW,GAAE,YAAY;GAE1E,MAAM,WAAW,MAAM,KAAK,GAAG,GAAG;IACjC,OAAO;IACP;IACA;IACA;IACA;GACA,EAAQ;GAGT,MAAM,SAAS,MAAM,KAAK,GAAG,YAAY,SAAS;AAGlD,OAAI,SAAS;IACZ,MAAM,UAAU,QAAQ,YAAY;AACpC,QAAI,QAAQ,SAAS,GAAG;AACvB,YAAO,MACN,EAAE,YAAY,QAAQ,OAAQ,GAC9B,2BACA;AACD,WAAM,QAAQ,OAAO;IACrB;GACD;AAID,SAAM,oCACL,QACA,KAAK,kBACL,KAAK,GAAG,QACR,QACA,KAAK,GAAG,iBACR;AAED,UAAO;EACP,EAAC;CACF;AACD;;;;;;;;;;;;;ACrLD,IAAa,mBAAb,MAAa,iBAKX;CACD,OAAO,6BAA6B;AACnC,SAAO,sCAAiB,YAAY,IAAIC,qCAAkB,CAAE,GAAE;CAC9D;CAED,YACkBC,OACTC,mBAA0C,iBAAiB,4BAA4B,EAC9F;EAFgB;EACT;CACL;CAEJ,MAAM,OACLC,SACmB;EACnB,MAAM,SAAS,KAAK,MAAM,OAAO,MAAM,EAAE,MAAM,KAAM,EAAC;EAEtD,MAAM,WACL,QAAQ,YACN,MAAM,KAAK,iBAAiB,SAC7B,KAAK,MAAM,SACX;EAEF,MAAM,aAAa,OAAO,KAAK,KAAK,CAAC;EACrC,MAAM,YAAY,KAAK,KAAK;AAE5B,SAAO,gDAAsB;GAAE;GAAQ;GAAW;EAAW,GAAE,MAC9D,KAAK,MAAM,QAAQ;GAClB,UAAU,QAAQ;GAClB;GACA;EACA,EAAC,CACF;CACD;AACD;;;;ACjCD,IAAa,wBAAb,MAAa,sBAQX;CACD,OAAO,6BAA6B;AACnC,SAAO,sCAAiB,YAAY,IAAIC,qCAAkB,CAAE,GAAE;CAC9D;CAED,YACkBC,YAQTC,mBAA0C,sBAAsB,4BAA4B,EACnG;EATgB;EAQT;CACL;CAEJ,MAAM,OACLC,SAK0C;EAE1C,MAAM,SAAS,KAAK,WAAW,OAAO,MAAM,EAC3C,MAAM,KACN,EAAC;EAGF,IAAIC;AACJ,MAAI,QAAQ,SACX,YAAW,QAAQ;MAEnB,YAAW,MAAM,KAAK,iBAAiB,SAAS,KAAK,WAAW,SAAS;EAI1E,MAAM,iBAAiB,KAAK,aAAa,QAAQ,OAAO;AAGxD,MAAI,eAAe,WAAW,EAC7B,QAAO,EAAE,mBAAmB,CAAE,EAAE;EAIjC,MAAM,aAAa,OAAO,KAAK,KAAK,CAAC;EACrC,MAAM,YAAY,KAAK,KAAK;AAE5B,SAAO,gDAAsB;GAAE;GAAQ;GAAW;EAAW,GAAE,YAAY;GAE1E,MAAM,SAAS,MAAM,KAAK,WAAW,QAAQ;IAC5C,QAAQ;IACR;IACA;GACA,EAAC;GAGF,IAAIC,SAAc;AAClB,OAAI,KAAK,WAAW,gBAAgB,QAAQ;IAC3C,MAAM,mBACL,MAAM,KAAK,WAAW,aAAa,aAAa,SAAS,OAAO;AAEjE,QAAI,iBAAiB,OACpB,OAAM,IAAI,MAAM;AAGjB,aAAS,iBAAiB;GAC1B;AAGD,SAAM,oCACL,QACA,KAAK,kBACL,KAAK,WAAW,QAChB,QACA,KAAK,WAAW,iBAChB;AAED,UAAO;EACP,EAAC;CACF;CAED,AAAQ,aACPC,QAC6D;AAC7D,OAAK,KAAK,WAAW,iBACpB,QAAO;AAGR,SAAO,OAAO,OAAO,CAACC,UACrB,KAAK,WAAW,iBAAkB,SAAS,MAAM,KAAK,CACtD;CACD;AACD"}
|
|
1
|
+
{"version":3,"file":"testing.cjs","names":["EnvironmentParser","ServiceDiscovery","http","Hono","ServiceDiscovery","EnvironmentParser","createObjectHeaders","createCookieHeaderAccessor","runWithRequestContext","ForbiddenError","DefaultAuditor","executeWithAuditTransaction","ResponseBuilder","Endpoint","publishConstructEvents","ServiceDiscovery","EnvironmentParser","FunctionBuilder","DefaultAuditor","runWithRequestContext","publishEvents","ServiceDiscovery","EnvironmentParser","runWithRequestContext","ServiceDiscovery","EnvironmentParser","runWithRequestContext","publishEvents"],"sources":["../../src/endpoints/MswEndpointAdaptor.ts","../../src/endpoints/TestEndpointAdaptor.ts","../../src/functions/TestFunctionAdaptor.ts","../../src/queue/TestQueueAdaptor.ts","../../src/subscribers/TestSubscriberAdaptor.ts"],"sourcesContent":["import { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Service } from '@geekmidas/services';\nimport { ServiceDiscovery } from '@geekmidas/services';\nimport { Hono } from 'hono';\nimport { type HttpHandler, http } from 'msw';\nimport type { Endpoint } from './Endpoint';\nimport { HonoEndpoint } from './HonoEndpointAdaptor';\n\n/**\n * Header used to identify which test context a request belongs to.\n * Each concurrent test registers its own context (services, db transaction, etc.)\n * and the MSW handler looks it up by this header value.\n */\nexport const TEST_CONTEXT_HEADER = 'x-test-context-id';\n\n/**\n * Per-test context containing an isolated ServiceDiscovery instance.\n * Registered in the context map and looked up per-request via the context ID header.\n */\nexport interface MswTestContext {\n\tserviceDiscovery: ServiceDiscovery<any>;\n}\n\n/**\n * Options for creating MSW handlers from endpoint constructs.\n *\n * @example\n * ```typescript\n * import { createMswHandlers, registerTestContext } from '@geekmidas/constructs/testing';\n * import { setupServer } from 'msw/node';\n *\n * // Create handlers once (global)\n * const { handlers, registerContext, removeContext } = createMswHandlers(\n * [getUsers, createUser],\n * { baseURL: 'http://localhost:3000' },\n * );\n * const server = setupServer(...handlers);\n *\n * // Per test: register an isolated context with its own services/transaction\n * it('should list users', async ({ db }) => {\n * const contextId = crypto.randomUUID();\n * registerContext(contextId, {\n * services: { database: db, auth: mockAuth },\n * });\n *\n * const api = createApi({\n * baseURL: 'http://localhost:3000',\n * headers: { [TEST_CONTEXT_HEADER]: contextId },\n * });\n *\n * const result = await api('GET /users');\n * expect(result).toBeDefined();\n *\n * removeContext(contextId);\n * });\n * ```\n */\nexport interface CreateMswHandlersOptions {\n\t/** Base URL the client fetches from (e.g., 'http://localhost:3000') */\n\tbaseURL: string;\n}\n\n/**\n * Options for registering a per-test context.\n * Follows the same pattern as TestRequestAdaptor — services, database,\n * publisher, and auditorStorage are provided explicitly.\n */\nexport interface RegisterContextOptions {\n\t/** Service instances keyed by serviceName */\n\tservices?: Record<string, unknown>;\n\t/** Database instance — required when endpoints use .database() */\n\tdatabase?: unknown;\n\t/** Event publisher service definition */\n\tpublisher?: Service;\n\t/** Audit storage instance — required when endpoints use .auditor() */\n\tauditorStorage?: unknown;\n}\n\nconst MSW_HTTP_METHODS = [\n\t'get',\n\t'post',\n\t'put',\n\t'patch',\n\t'delete',\n\t'options',\n] as const;\n\ntype MswHttpMethod = (typeof MSW_HTTP_METHODS)[number];\n\n/**\n * Result of creating MSW handlers from endpoint constructs.\n */\nexport interface CreateMswHandlersResult {\n\t/** MSW handlers to pass to setupServer() */\n\thandlers: HttpHandler[];\n\t/** Register an isolated context for a test */\n\tregisterContext: (id: string, options: RegisterContextOptions) => void;\n}\n\n/**\n * Creates MSW HTTP handlers from endpoint constructs.\n *\n * Mounts endpoints on a Hono app and creates MSW handlers that intercept\n * fetch requests and route them through `app.request()` — giving frontend\n * tests full endpoint behavior (validation, auth, sessions) without HTTP.\n *\n * Each test registers its own isolated context via `registerContext()`,\n * which is resolved per-request using the `x-test-context-id` header.\n * This allows concurrent tests with their own transactions and services.\n *\n * @param endpoints - Array of endpoint constructs to create handlers for\n * @param options - Configuration including baseURL\n * @returns MSW handlers, the Hono app, and context management functions\n */\nexport function createMswHandlers(\n\tendpoints: Endpoint<any, any, any, any, any, any>[],\n\toptions: CreateMswHandlersOptions,\n): CreateMswHandlersResult {\n\tconst { baseURL } = options;\n\tconst contexts = new Map<string, MswTestContext>();\n\n\t/**\n\t * Register an isolated context for a test.\n\t * Creates a fresh ServiceDiscovery and pre-registers all provided services.\n\t */\n\tfunction registerContext(id: string, ctxOptions: RegisterContextOptions) {\n\t\tconst envParser = new EnvironmentParser({});\n\t\tconst serviceDiscovery = new ServiceDiscovery(envParser);\n\n\t\tconst serviceDefs: Service[] = [];\n\n\t\t// Register explicit services\n\t\tif (ctxOptions.services) {\n\t\t\tfor (const [name, instance] of Object.entries(ctxOptions.services)) {\n\t\t\t\tserviceDefs.push({\n\t\t\t\t\tserviceName: name,\n\t\t\t\t\tregister: () => instance,\n\t\t\t\t} as Service);\n\t\t\t}\n\t\t}\n\n\t\t// Register database service from endpoint metadata\n\t\tif (ctxOptions.database !== undefined) {\n\t\t\tfor (const endpoint of endpoints) {\n\t\t\t\tif (endpoint.databaseService) {\n\t\t\t\t\tserviceDefs.push({\n\t\t\t\t\t\tserviceName: endpoint.databaseService.serviceName,\n\t\t\t\t\t\tregister: () => ctxOptions.database,\n\t\t\t\t\t} as Service);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Register publisher service\n\t\tif (ctxOptions.publisher) {\n\t\t\tserviceDefs.push(ctxOptions.publisher);\n\t\t}\n\n\t\t// Register auditor storage service from endpoint metadata\n\t\tif (ctxOptions.auditorStorage !== undefined) {\n\t\t\tfor (const endpoint of endpoints) {\n\t\t\t\tif (endpoint.auditorStorageService) {\n\t\t\t\t\tserviceDefs.push({\n\t\t\t\t\t\tserviceName: endpoint.auditorStorageService.serviceName,\n\t\t\t\t\t\tregister: () => ctxOptions.auditorStorage,\n\t\t\t\t\t} as Service);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (serviceDefs.length > 0) {\n\t\t\tserviceDiscovery.register(serviceDefs);\n\t\t}\n\n\t\tcontexts.set(id, { serviceDiscovery });\n\t}\n\n\t// Create a Hono app per-request that uses the correct ServiceDiscovery.\n\t// We use a wrapper app that resolves the context from the header,\n\t// then delegates to a context-specific Hono app.\n\tconst handlers: HttpHandler[] = [];\n\n\tfor (const endpoint of endpoints) {\n\t\tconst method = endpoint.method.toLowerCase() as MswHttpMethod;\n\t\tif (!MSW_HTTP_METHODS.includes(method)) continue;\n\n\t\tconst mswUrl = `${baseURL}${endpoint.route}`;\n\t\tconst mswMethod = http[method];\n\n\t\thandlers.push(\n\t\t\tmswMethod(mswUrl, async ({ request }) => {\n\t\t\t\tconst contextId = request.headers.get(TEST_CONTEXT_HEADER);\n\t\t\t\tconst ctx = contextId ? contexts.get(contextId) : undefined;\n\n\t\t\t\tif (!ctx) {\n\t\t\t\t\treturn new Response(\n\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\terror: 'Missing or unknown test context ID',\n\t\t\t\t\t\t\thint: `Set the '${TEST_CONTEXT_HEADER}' header to a registered context ID`,\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t{ status: 500, headers: { 'content-type': 'application/json' } },\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Build a fresh Hono app with this context's ServiceDiscovery\n\t\t\t\tconst app = new Hono();\n\t\t\t\tHonoEndpoint.addRoute(endpoint, ctx.serviceDiscovery as any, app);\n\n\t\t\t\tconst response = await app.request(request);\n\n\t\t\t\treturn new Response(response.body, {\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t\tstatusText: response.statusText,\n\t\t\t\t\theaders: response.headers,\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn {\n\t\thandlers,\n\t\tregisterContext,\n\t};\n}\n","import type {\n\tAuditActor,\n\tAuditableAction,\n\tAuditStorage,\n} from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport { ForbiddenError } from '@geekmidas/errors';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\trunWithRequestContext,\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishConstructEvents } from '../publisher';\nimport type { HttpMethod } from '../types';\nimport type { MappedAudit } from './audit';\nimport {\n\ttype CookieOptions,\n\tEndpoint,\n\ttype EndpointSchemas,\n\tResponseBuilder,\n} from './Endpoint';\nimport {\n\tcreateCookieHeaderAccessor,\n\tcreateObjectHeaders,\n} from './lazyAccessors';\nimport {\n\ttype AuditExecutionContext,\n\texecuteWithAuditTransaction,\n} from './processAudits';\n\nexport type TestHttpResponse<TBody = any> = {\n\tbody: TBody;\n\tstatus: number;\n\theaders: Record<string, string | string[]>;\n};\n\n/**\n * Serializes a cookie into a Set-Cookie header string\n */\nfunction serializeCookie(\n\tname: string,\n\tvalue: string,\n\toptions?: CookieOptions,\n): string {\n\tlet cookieString = `${name}=${value}`;\n\n\tif (options) {\n\t\tif (options.maxAge !== undefined) {\n\t\t\tcookieString += `; Max-Age=${options.maxAge}`;\n\t\t}\n\t\tif (options.expires) {\n\t\t\tcookieString += `; Expires=${options.expires.toUTCString()}`;\n\t\t}\n\t\tif (options.domain) {\n\t\t\tcookieString += `; Domain=${options.domain}`;\n\t\t}\n\t\tif (options.path) {\n\t\t\tcookieString += `; Path=${options.path}`;\n\t\t}\n\t\tif (options.httpOnly) {\n\t\t\tcookieString += '; HttpOnly';\n\t\t}\n\t\tif (options.secure) {\n\t\t\tcookieString += '; Secure';\n\t\t}\n\t\tif (options.sameSite) {\n\t\t\tcookieString += `; SameSite=${options.sameSite}`;\n\t\t}\n\t}\n\n\treturn cookieString;\n}\n\nexport class TestEndpointAdaptor<\n\tTRoute extends string,\n\tTMethod extends HttpMethod,\n\tTInput extends EndpointSchemas = {},\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTSession = unknown,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> {\n\tstatic getDefaultServiceDiscover<\n\t\tTRoute extends string,\n\t\tTMethod extends HttpMethod,\n\t\tTInput extends EndpointSchemas = {},\n\t\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\t\tTServices extends Service[] = [],\n\t\tTLogger extends Logger = Logger,\n\t\tTSession = unknown,\n\t\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\t\tTEventPublisherServiceName extends string = string,\n\t\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t\tTAuditStorageServiceName extends string = string,\n\t\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>,\n\t\tTDatabase = undefined,\n\t\tTDatabaseServiceName extends string = string,\n\t>(\n\t\t_endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t) {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\tconstructor(\n\t\tprivate readonly endpoint: Endpoint<\n\t\t\tTRoute,\n\t\t\tTMethod,\n\t\t\tTInput,\n\t\t\tTOutSchema,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTSession,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditAction,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestEndpointAdaptor.getDefaultServiceDiscover(\n\t\t\tendpoint,\n\t\t),\n\t) {}\n\n\tasync fullRequest(\n\t\tctx: TestRequestAdaptor<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t): Promise<TestHttpResponse<InferStandardSchema<TOutSchema>>> {\n\t\tconst body = await this.endpoint.parseInput((ctx as any).body, 'body');\n\t\tconst query = await this.endpoint.parseInput((ctx as any).query, 'query');\n\t\tconst params = await this.endpoint.parseInput(\n\t\t\t(ctx as any).params,\n\t\t\t'params',\n\t\t);\n\n\t\t// Lazy accessors - defer parsing until needed\n\t\tconst header = createObjectHeaders(ctx.headers);\n\t\tconst cookie = createCookieHeaderAccessor(ctx.headers.cookie);\n\n\t\t// Request context setup\n\t\tconst startTime = Date.now();\n\t\tconst requestId =\n\t\t\t(ctx as any).requestId ??\n\t\t\tctx.headers['x-request-id'] ??\n\t\t\tcrypto.randomUUID();\n\n\t\tconst logger = this.endpoint.logger.child({\n\t\t\trequestId,\n\t\t\troute: this.endpoint.route,\n\t\t\thost: ctx.headers.host,\n\t\t\tmethod: this.endpoint.method,\n\t\t}) as TLogger;\n\n\t\t// Get database from context for session extraction\n\t\tconst rawDb = (ctx as any).database as TDatabase;\n\n\t\t// Wrap handler execution in request context\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, async () => {\n\t\t\tconst session = await this.endpoint.getSession({\n\t\t\t\tlogger,\n\t\t\t\tservices: ctx.services,\n\t\t\t\theader,\n\t\t\t\tcookie,\n\t\t\t\t...(rawDb !== undefined && { db: rawDb }),\n\t\t\t} as any);\n\n\t\t\t// Check authorization\n\t\t\tconst isAuthorized = await this.endpoint.authorize({\n\t\t\t\theader,\n\t\t\t\tcookie,\n\t\t\t\tservices: ctx.services,\n\t\t\t\tlogger,\n\t\t\t\tsession,\n\t\t\t\t...(rawDb !== undefined && { db: rawDb }),\n\t\t\t\tbody,\n\t\t\t\tquery,\n\t\t\t\tparams,\n\t\t\t} as any);\n\n\t\t\tif (!isAuthorized) {\n\t\t\t\tlogger.warn('Forbidden access attempt');\n\t\t\t\tthrow new ForbiddenError(\n\t\t\t\t\t'Forbidden access to the endpoint',\n\t\t\t\t\t'You do not have permission to access this resource.',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Create audit context if audit storage is provided\n\t\t\t// The auditorStorage instance is required when endpoint uses .auditor()\n\t\t\tconst auditorStorage = (ctx as any).auditorStorage as TAuditStorage;\n\t\t\tlet auditContext: AuditExecutionContext<TAuditAction> | undefined;\n\n\t\t\tif (auditorStorage) {\n\t\t\t\t// Extract actor if configured\n\t\t\t\tlet actor: AuditActor = { id: 'system', type: 'system' };\n\t\t\t\tif (this.endpoint.actorExtractor) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tactor = await this.endpoint.actorExtractor({\n\t\t\t\t\t\t\tservices: ctx.services as any,\n\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\tcookie,\n\t\t\t\t\t\t\tlogger,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger.error(error as Error, 'Failed to extract actor for audits');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst auditor = new DefaultAuditor<TAuditAction>({\n\t\t\t\t\tactor,\n\t\t\t\t\tstorage: auditorStorage as AuditStorage,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tendpoint: this.endpoint.route,\n\t\t\t\t\t\tmethod: this.endpoint.method,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tauditContext = { auditor, storage: auditorStorage as AuditStorage };\n\t\t\t}\n\n\t\t\t// Warn if declarative audits are configured but no audit storage\n\t\t\tconst audits = this.endpoint.audits as MappedAudit<\n\t\t\t\tTAuditAction,\n\t\t\t\tTOutSchema\n\t\t\t>[];\n\t\t\tif (!auditContext && audits?.length) {\n\t\t\t\tlogger.warn('No auditor storage service available');\n\t\t\t}\n\n\t\t\t// Execute handler with automatic audit transaction support\n\t\t\tconst result = await executeWithAuditTransaction(\n\t\t\t\tauditContext,\n\t\t\t\tasync (auditor) => {\n\t\t\t\t\t// Use audit transaction as db if available (when storage has same database)\n\t\t\t\t\t// For testing, the tester controls whether to use transactional auditing\n\t\t\t\t\tconst trx = auditor?.getTransaction?.();\n\t\t\t\t\tconst db = trx ?? rawDb;\n\n\t\t\t\t\tconst responseBuilder = new ResponseBuilder();\n\t\t\t\t\tconst response = await this.endpoint.handler(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbody,\n\t\t\t\t\t\t\tquery,\n\t\t\t\t\t\t\tparams,\n\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\tservices: ctx.services,\n\t\t\t\t\t\t\tlogger,\n\t\t\t\t\t\t\theader,\n\t\t\t\t\t\t\tcookie,\n\t\t\t\t\t\t\tauditor,\n\t\t\t\t\t\t\tdb,\n\t\t\t\t\t\t} as any,\n\t\t\t\t\t\tresponseBuilder,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Check if response has metadata\n\t\t\t\t\tlet data = response;\n\t\t\t\t\tlet metadata = responseBuilder.getMetadata();\n\n\t\t\t\t\tif (Endpoint.hasMetadata(response)) {\n\t\t\t\t\t\tdata = response.data;\n\t\t\t\t\t\tmetadata = response.metadata;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst output = await this.endpoint.parseOutput(data);\n\n\t\t\t\t\treturn { output, metadata, responseBuilder };\n\t\t\t\t},\n\t\t\t\t// Process declarative audits after handler (inside transaction)\n\t\t\t\tasync (result, auditor) => {\n\t\t\t\t\tif (!audits?.length) return;\n\n\t\t\t\t\tfor (const audit of audits) {\n\t\t\t\t\t\tif (audit.when && !audit.when(result.output as any)) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst payload = audit.payload(result.output as any);\n\t\t\t\t\t\tconst entityId = audit.entityId?.(result.output as any);\n\t\t\t\t\t\tauditor.audit(audit.type as any, payload as any, {\n\t\t\t\t\t\t\ttable: audit.table,\n\t\t\t\t\t\t\tentityId,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t// Pass rawDb so storage can reuse existing transactions\n\t\t\t\t{ db: rawDb },\n\t\t\t);\n\n\t\t\tconst { output, metadata } = result;\n\n\t\t\tctx.publisher && (await this.serviceDiscovery.register([ctx.publisher]));\n\t\t\tawait publishConstructEvents(\n\t\t\t\tthis.endpoint,\n\t\t\t\toutput,\n\t\t\t\tthis.serviceDiscovery,\n\t\t\t);\n\n\t\t\t// Convert cookies to Set-Cookie headers\n\t\t\tconst headers: Record<string, string | string[]> = {\n\t\t\t\t...(metadata.headers || {}),\n\t\t\t};\n\n\t\t\tif (metadata.cookies && metadata.cookies.size > 0) {\n\t\t\t\tconst setCookieValues: string[] = [];\n\t\t\t\tfor (const [name, cookie] of metadata.cookies.entries()) {\n\t\t\t\t\tsetCookieValues.push(\n\t\t\t\t\t\tserializeCookie(name, cookie.value, cookie.options),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\theaders['set-cookie'] = setCookieValues;\n\t\t\t}\n\n\t\t\t// Return HTTP response format\n\t\t\treturn {\n\t\t\t\tbody: output,\n\t\t\t\tstatus: metadata.status || 200,\n\t\t\t\theaders,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync request(\n\t\tctx: TestRequestAdaptor<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t): Promise<InferStandardSchema<TOutSchema>> {\n\t\tconst response = await this.fullRequest(ctx);\n\t\treturn response.body;\n\t}\n}\n\n/**\n * Conditional audit storage requirement - required when TAuditStorage is configured\n */\ntype AuditStorageRequirement<\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n> = TAuditStorage extends undefined\n\t? {}\n\t: {\n\t\t\t/** Audit storage instance - required when endpoint uses .auditor() */\n\t\t\tauditorStorage: TAuditStorage;\n\t\t};\n\n/**\n * Conditional database requirement - required when TDatabase is configured\n */\ntype DatabaseRequirement<TDatabase = undefined> = TDatabase extends undefined\n\t? {}\n\t: {\n\t\t\t/** Database instance - required when endpoint uses .database() */\n\t\t\tdatabase: TDatabase;\n\t\t};\n\nexport type TestRequestAdaptor<\n\tTInput extends EndpointSchemas = {},\n\tTServices extends Service[] = [],\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t_TAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\t_TDatabaseServiceName extends string = string,\n> = {\n\tservices: ServiceRecord<TServices>;\n\theaders: Record<string, string>;\n\tpublisher?: Service<TEventPublisherServiceName, TEventPublisher>;\n} & InferComposableStandardSchema<TInput> &\n\tAuditStorageRequirement<TAuditStorage> &\n\tDatabaseRequirement<TDatabase>;\n","import type { AuditableAction, Auditor, AuditStorage } from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { EnvironmentParser } from '@geekmidas/envkit';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tComposableStandardSchema,\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\trunWithRequestContext,\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishEvents } from '../publisher';\nimport type { Function } from './Function';\nimport { FunctionBuilder } from './FunctionBuilder';\n\nexport class TestFunctionAdaptor<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> {\n\tstatic getDefaultServiceDiscovery<\n\t\tTInput extends ComposableStandardSchema | undefined = undefined,\n\t\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\t\tTServices extends Service[] = [],\n\t\tTLogger extends Logger = Logger,\n\t\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\t\tTEventPublisherServiceName extends string = string,\n\t\tTAuditStorage extends AuditStorage | undefined = undefined,\n\t\tTAuditStorageServiceName extends string = string,\n\t\tTDatabase = undefined,\n\t\tTDatabaseServiceName extends string = string,\n\t\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>,\n\t>(\n\t\t_fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>,\n\t) {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tany\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestFunctionAdaptor.getDefaultServiceDiscovery(\n\t\t\tfn,\n\t\t),\n\t) {}\n\n\tasync invoke(\n\t\tctx: TestFunctionRequest<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTDatabase,\n\t\t\tTAuditAction\n\t\t>,\n\t): Promise<InferStandardSchema<TOutSchema>> {\n\t\t// Parse input if schema is provided\n\n\t\tconst parsedInput = await FunctionBuilder.parseComposableStandardSchema(\n\t\t\tctx.input,\n\t\t\tthis.fn.input,\n\t\t);\n\n\t\t// Create logger with context\n\t\tconst logger = this.fn.logger.child({\n\t\t\ttest: true,\n\t\t}) as TLogger;\n\n\t\t// Register services (use provided services or register from function)\n\t\tlet services: ServiceRecord<TServices>;\n\t\tif (ctx.services) {\n\t\t\tservices = ctx.services;\n\t\t} else {\n\t\t\tservices = await this.serviceDiscovery.register(this.fn.services);\n\t\t}\n\n\t\t// Resolve database (use provided db or register from function)\n\t\tlet db: TDatabase | undefined;\n\t\tif ('db' in ctx && ctx.db !== undefined) {\n\t\t\tdb = ctx.db;\n\t\t} else if (this.fn.databaseService) {\n\t\t\tconst dbServices = await this.serviceDiscovery.register([\n\t\t\t\tthis.fn.databaseService,\n\t\t\t]);\n\t\t\tdb = dbServices[\n\t\t\t\tthis.fn.databaseService.serviceName as keyof typeof dbServices\n\t\t\t] as TDatabase;\n\t\t}\n\n\t\t// Resolve auditor (use provided auditor or create from function)\n\t\tlet auditor: Auditor<TAuditAction> | undefined;\n\t\tif ('auditor' in ctx && ctx.auditor !== undefined) {\n\t\t\tauditor = ctx.auditor;\n\t\t} else if (this.fn.auditorStorageService) {\n\t\t\tconst auditServices = await this.serviceDiscovery.register([\n\t\t\t\tthis.fn.auditorStorageService,\n\t\t\t]);\n\t\t\tconst storage = auditServices[\n\t\t\t\tthis.fn.auditorStorageService.serviceName as keyof typeof auditServices\n\t\t\t] as AuditStorage;\n\n\t\t\tauditor = new DefaultAuditor<TAuditAction>({\n\t\t\t\tactor: { id: 'system', type: 'system' },\n\t\t\t\tstorage,\n\t\t\t\tmetadata: {\n\t\t\t\t\tfunction: this.fn.type,\n\t\t\t\t\ttest: true,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Wrap execution in request context for service access via context.getLogger()\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, async () => {\n\t\t\t// Execute the function\n\t\t\tconst response = await this.fn.fn({\n\t\t\t\tinput: parsedInput,\n\t\t\t\tservices,\n\t\t\t\tlogger,\n\t\t\t\tdb,\n\t\t\t\tauditor,\n\t\t\t} as any);\n\n\t\t\t// Parse output if schema is provided\n\t\t\tconst output = await this.fn.parseOutput(response);\n\n\t\t\t// Flush audits if any were recorded\n\t\t\tif (auditor) {\n\t\t\t\tconst records = auditor.getRecords();\n\t\t\t\tif (records.length > 0) {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t{ auditCount: records.length },\n\t\t\t\t\t\t'Flushing function audits',\n\t\t\t\t\t);\n\t\t\t\t\tawait auditor.flush();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Register publisher service if provided in context\n\n\t\t\tawait publishEvents(\n\t\t\t\tlogger,\n\t\t\t\tthis.serviceDiscovery,\n\t\t\t\tthis.fn.events,\n\t\t\t\toutput,\n\t\t\t\tthis.fn.publisherService,\n\t\t\t);\n\n\t\t\treturn output;\n\t\t}) as Promise<InferStandardSchema<TOutSchema>>;\n\t}\n}\n\nexport type TestFunctionRequest<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTDatabase = undefined,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> = {\n\tinput: InferComposableStandardSchema<TInput>;\n\tservices: ServiceRecord<TServices>;\n\tpublisher?: Service<TEventPublisherServiceName, TEventPublisher>;\n\tdb?: TDatabase;\n\tauditor?: Auditor<TAuditAction>;\n} & InferComposableStandardSchema<{ input: TInput }>;\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Queue } from './Queue';\n\n/**\n * In-memory test driver for a {@link Queue} worker. Hand it a batch of messages\n * and it registers the queue's services, runs the handler in a request context,\n * and returns the handler result — no SQS/pg-boss required.\n *\n * @example\n * const adapter = new TestQueueAdaptor(ordersQueue);\n * await adapter.invoke({ messages: [{ orderId: '123' }] });\n */\nexport class TestQueueAdaptor<\n\tTName extends string = string,\n\tTMessage extends StandardSchemaV1 = StandardSchemaV1,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n> {\n\tstatic getDefaultServiceDiscovery() {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly queue: Queue<TName, TMessage, TServices, TLogger>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestQueueAdaptor.getDefaultServiceDiscovery(),\n\t) {}\n\n\tasync invoke(\n\t\trequest: TestQueueRequest<TMessage, TServices>,\n\t): Promise<unknown> {\n\t\tconst logger = this.queue.logger.child({ test: true }) as TLogger;\n\n\t\tconst services =\n\t\t\trequest.services ??\n\t\t\t((await this.serviceDiscovery.register(\n\t\t\t\tthis.queue.services,\n\t\t\t)) as ServiceRecord<TServices>);\n\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, () =>\n\t\t\tthis.queue.handler({\n\t\t\t\tmessages: request.messages,\n\t\t\t\tservices,\n\t\t\t\tlogger,\n\t\t\t}),\n\t\t);\n\t}\n}\n\nexport type TestQueueRequest<\n\tTMessage extends StandardSchemaV1 = StandardSchemaV1,\n\tTServices extends Service[] = [],\n> = {\n\tmessages: InferStandardSchema<TMessage>[];\n\tservices?: ServiceRecord<TServices>;\n};\n","import { EnvironmentParser } from '@geekmidas/envkit';\nimport type {\n\tEventPublisher,\n\tExtractPublisherMessage,\n} from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishEvents } from '../publisher';\nimport type { Subscriber } from './Subscriber';\n\n// Helper type to extract payload types for subscribed events\ntype ExtractEventPayloads<\n\tTPublisher extends EventPublisher<any> | undefined,\n\tTEventTypes extends any[],\n> = TPublisher extends EventPublisher<any>\n\t? Extract<ExtractPublisherMessage<TPublisher>, { type: TEventTypes[number] }>\n\t: never;\n\nexport class TestSubscriberAdaptor<\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTSubscribedEvents extends\n\t\tExtractPublisherMessage<TEventPublisher>['type'][] = ExtractPublisherMessage<TEventPublisher>['type'][],\n> {\n\tstatic getDefaultServiceDiscovery() {\n\t\treturn ServiceDiscovery.getInstance(new EnvironmentParser({}));\n\t}\n\n\tconstructor(\n\t\tprivate readonly subscriber: Subscriber<\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTSubscribedEvents\n\t\t>,\n\t\tprivate serviceDiscovery: ServiceDiscovery<any> = TestSubscriberAdaptor.getDefaultServiceDiscovery(),\n\t) {}\n\n\tasync invoke(\n\t\trequest: TestSubscriberRequest<\n\t\t\tTEventPublisher,\n\t\t\tTSubscribedEvents,\n\t\t\tTServices\n\t\t>,\n\t): Promise<InferStandardSchema<OutSchema>> {\n\t\t// Create logger with test context\n\t\tconst logger = this.subscriber.logger.child({\n\t\t\ttest: true,\n\t\t}) as TLogger;\n\n\t\t// Resolve services (use provided or auto-register)\n\t\tlet services: ServiceRecord<TServices>;\n\t\tif (request.services) {\n\t\t\tservices = request.services;\n\t\t} else {\n\t\t\tservices = await this.serviceDiscovery.register(this.subscriber.services);\n\t\t}\n\n\t\t// Filter events to only subscribed types\n\t\tconst filteredEvents = this.filterEvents(request.events);\n\n\t\t// Return early if no events after filtering (mirrors AWSLambdaSubscriber)\n\t\tif (filteredEvents.length === 0) {\n\t\t\treturn { batchItemFailures: [] } as any;\n\t\t}\n\n\t\t// Wrap execution in request context for service access via context.getLogger()\n\t\tconst requestId = `test-${Date.now()}`;\n\t\tconst startTime = Date.now();\n\n\t\treturn runWithRequestContext({ logger, requestId, startTime }, async () => {\n\t\t\t// Execute the subscriber handler\n\t\t\tconst result = await this.subscriber.handler({\n\t\t\t\tevents: filteredEvents,\n\t\t\t\tservices,\n\t\t\t\tlogger,\n\t\t\t});\n\n\t\t\t// Validate output if schema is provided\n\t\t\tlet output: any = result;\n\t\t\tif (this.subscriber.outputSchema && result) {\n\t\t\t\tconst validationResult =\n\t\t\t\t\tawait this.subscriber.outputSchema['~standard'].validate(result);\n\n\t\t\t\tif (validationResult.issues) {\n\t\t\t\t\tthrow new Error('Subscriber output validation failed');\n\t\t\t\t}\n\n\t\t\t\toutput = validationResult.value;\n\t\t\t}\n\n\t\t\t// Publish events if configured\n\t\t\tawait publishEvents(\n\t\t\t\tlogger,\n\t\t\t\tthis.serviceDiscovery,\n\t\t\t\tthis.subscriber.events,\n\t\t\t\toutput,\n\t\t\t\tthis.subscriber.publisherService,\n\t\t\t);\n\n\t\t\treturn output;\n\t\t}) as Promise<InferStandardSchema<OutSchema>>;\n\t}\n\n\tprivate filterEvents(\n\t\tevents: ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[],\n\t): ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[] {\n\t\tif (!this.subscriber.subscribedEvents) {\n\t\t\treturn events;\n\t\t}\n\n\t\treturn events.filter((event: any) =>\n\t\t\tthis.subscriber.subscribedEvents!.includes(event.type),\n\t\t);\n\t}\n}\n\nexport type TestSubscriberRequest<\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTSubscribedEvents extends any[] = [],\n\tTServices extends Service[] = [],\n> = {\n\tevents: ExtractEventPayloads<TEventPublisher, TSubscribedEvents>[];\n\tservices?: ServiceRecord<TServices>;\n};\n"],"mappings":"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"}
|