theokit 0.43.12 → 0.44.3
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/{actions-virtual-module-RSFRPJQZ.js → actions-virtual-module-67K4POQ2.js} +20 -20
- package/dist/actions-virtual-module-67K4POQ2.js.map +1 -0
- package/dist/{actions-virtual-module-HG66SZ7T.js → actions-virtual-module-IK2SDIZ3.js} +4 -3
- package/dist/{actions-virtual-module-HG66SZ7T.js.map → actions-virtual-module-IK2SDIZ3.js.map} +1 -1
- package/dist/adapters/web-shim.js +1 -1
- package/dist/adapters/web-shim.js.map +1 -1
- package/dist/adapters/ws-shim.js +1 -1
- package/dist/adapters/ws-shim.js.map +1 -1
- package/dist/{agent-OXRRKB55.js → agent-OCCL5RUY.js} +2 -2
- package/dist/{agents-typed-client-ZP7BKJB3.js → agents-typed-client-TNHCUU7Q.js} +2 -2
- package/dist/agents-typed-client-TNHCUU7Q.js.map +1 -0
- package/dist/{app-typed-client-GDF2OMJ2.js → app-typed-client-4OH3JREB.js} +47 -8
- package/dist/app-typed-client-4OH3JREB.js.map +1 -0
- package/dist/{app-typed-client-USLAMN7X.js → app-typed-client-N5WUE2CP.js} +62 -24
- package/dist/app-typed-client-N5WUE2CP.js.map +1 -0
- package/dist/{body-parser-web-NNEJGX6Y.js → body-parser-web-4Z2QTPDU.js} +2 -2
- package/dist/body-parser-web-4Z2QTPDU.js.map +1 -0
- package/dist/boot/index.js +4 -4
- package/dist/boot/index.js.map +1 -1
- package/dist/{broadcast-4SX7R5XE.js → broadcast-H64DJRBE.js} +3 -3
- package/dist/broadcast-H64DJRBE.js.map +1 -0
- package/dist/{build-MQHIJROR.js → build-25RSFP22.js} +13 -4
- package/dist/build-25RSFP22.js.map +1 -0
- package/dist/{build-request-body-preview-FVBQ7LCE.js → build-request-body-preview-CKWWBF2M.js} +2 -2
- package/dist/build-request-body-preview-CKWWBF2M.js.map +1 -0
- package/dist/{chunk-26ECIX74.js → chunk-2ADKT37V.js} +5 -5
- package/dist/chunk-2ADKT37V.js.map +1 -0
- package/dist/{chunk-JIL74SFK.js → chunk-37ZO643S.js} +9 -9
- package/dist/chunk-37ZO643S.js.map +1 -0
- package/dist/{chunk-ESC54TAK.js → chunk-3DGIANAN.js} +1 -1
- package/dist/chunk-3DGIANAN.js.map +1 -0
- package/dist/{chunk-6FK7FKY6.js → chunk-47FFT43U.js} +1 -1
- package/dist/chunk-47FFT43U.js.map +1 -0
- package/dist/{chunk-ZJQ4O76G.js → chunk-4FWBKX6G.js} +1 -1
- package/dist/chunk-4FWBKX6G.js.map +1 -0
- package/dist/{chunk-NM4WF3XD.js → chunk-4PBJ266F.js} +1 -1
- package/dist/chunk-4PBJ266F.js.map +1 -0
- package/dist/{chunk-7MQOHNHE.js → chunk-52PDWL5S.js} +1 -1
- package/dist/chunk-52PDWL5S.js.map +1 -0
- package/dist/{chunk-JQJN6LFK.js → chunk-62EU2BVZ.js} +2 -2
- package/dist/chunk-62EU2BVZ.js.map +1 -0
- package/dist/{chunk-SJIRP73B.js → chunk-646CA6RV.js} +2 -2
- package/dist/chunk-646CA6RV.js.map +1 -0
- package/dist/{chunk-ASDXVRJD.js → chunk-6KDXP472.js} +4 -4
- package/dist/chunk-6KDXP472.js.map +1 -0
- package/dist/chunk-6LNIGF5P.js +46 -0
- package/dist/chunk-6LNIGF5P.js.map +1 -0
- package/dist/chunk-7IHWXDJJ.js +1 -0
- package/dist/chunk-7IHWXDJJ.js.map +1 -0
- package/dist/{chunk-JQSKBMXP.js → chunk-7LVM22VG.js} +1 -1
- package/dist/chunk-7LVM22VG.js.map +1 -0
- package/dist/{chunk-UVXB2ER7.js → chunk-7SABX4DJ.js} +1 -1
- package/dist/chunk-7SABX4DJ.js.map +1 -0
- package/dist/{chunk-X32XEJXR.js → chunk-ACKBVBUI.js} +1 -1
- package/dist/chunk-ACKBVBUI.js.map +1 -0
- package/dist/{chunk-UUFYP2UM.js → chunk-AM3QABW5.js} +3 -3
- package/dist/chunk-AM3QABW5.js.map +1 -0
- package/dist/{chunk-FH3DYBAN.js → chunk-ANS4ELRH.js} +1 -1
- package/dist/chunk-ANS4ELRH.js.map +1 -0
- package/dist/{chunk-UD3LFGDL.js → chunk-AVQU5CQF.js} +1 -1
- package/dist/chunk-AVQU5CQF.js.map +1 -0
- package/dist/{chunk-CJNMJUHE.js → chunk-B7ONQ4QJ.js} +2 -2
- package/dist/{chunk-WSJKACWB.js → chunk-C34PMLSN.js} +1 -1
- package/dist/chunk-C34PMLSN.js.map +1 -0
- package/dist/{chunk-2WH6SD3C.js → chunk-DSOBIXXR.js} +4 -4
- package/dist/{chunk-DJFMAWH5.js → chunk-EIRQM55C.js} +6 -5
- package/dist/chunk-EIRQM55C.js.map +1 -0
- package/dist/{chunk-ZEGYW52B.js → chunk-FB2HBNIC.js} +1 -1
- package/dist/chunk-FB2HBNIC.js.map +1 -0
- package/dist/chunk-FXZZS7YW.js +605 -0
- package/dist/chunk-FXZZS7YW.js.map +1 -0
- package/dist/{chunk-HGUZWG2C.js → chunk-FZG3JYB3.js} +8 -47
- package/dist/chunk-FZG3JYB3.js.map +1 -0
- package/dist/{chunk-V3LJN2GS.js → chunk-GAPBPRPP.js} +1 -1
- package/dist/chunk-GAPBPRPP.js.map +1 -0
- package/dist/chunk-GUBN5UTT.js +1 -0
- package/dist/chunk-GUBN5UTT.js.map +1 -0
- package/dist/{chunk-6OXCZMW3.js → chunk-HEK4SET7.js} +5 -5
- package/dist/chunk-HEK4SET7.js.map +1 -0
- package/dist/{chunk-N2D5AVRR.js → chunk-HRCNHWLP.js} +7 -109
- package/dist/chunk-HRCNHWLP.js.map +1 -0
- package/dist/{chunk-C3ZZ56YZ.js → chunk-JA2ZAT5Q.js} +1 -1
- package/dist/chunk-JA2ZAT5Q.js.map +1 -0
- package/dist/{chunk-L2S2R3TI.js → chunk-KBGGQK4I.js} +25 -8
- package/dist/chunk-KBGGQK4I.js.map +1 -0
- package/dist/{chunk-VPISAMXU.js → chunk-KD5G3YXI.js} +4 -4
- package/dist/chunk-KD5G3YXI.js.map +1 -0
- package/dist/{chunk-VMEWD57H.js → chunk-KPKLIUUL.js} +1 -1
- package/dist/chunk-KPKLIUUL.js.map +1 -0
- package/dist/{chunk-4HAU7AJM.js → chunk-L4Y6RJ4E.js} +3 -3
- package/dist/chunk-L4Y6RJ4E.js.map +1 -0
- package/dist/{chunk-OVHW23YC.js → chunk-L5Z6IY5U.js} +5 -5
- package/dist/chunk-L5Z6IY5U.js.map +1 -0
- package/dist/{chunk-JBCHWRKF.js → chunk-MTEWLGVY.js} +2 -2
- package/dist/chunk-MTEWLGVY.js.map +1 -0
- package/dist/{chunk-XZ6B2Y2R.js → chunk-MWP4YXWJ.js} +1 -1
- package/dist/chunk-MWP4YXWJ.js.map +1 -0
- package/dist/{chunk-575PAX5L.js → chunk-NGEBYCOZ.js} +62 -38
- package/dist/chunk-NGEBYCOZ.js.map +1 -0
- package/dist/{chunk-5QW7IQQU.js → chunk-NTDN54XO.js} +1 -1
- package/dist/chunk-NTDN54XO.js.map +1 -0
- package/dist/{chunk-7BIM27LV.js → chunk-OIGJOYX6.js} +1 -1
- package/dist/chunk-OIGJOYX6.js.map +1 -0
- package/dist/{chunk-TSLSIRBR.js → chunk-OLGPYOLO.js} +2 -2
- package/dist/chunk-OLGPYOLO.js.map +1 -0
- package/dist/{chunk-IE6C4KZX.js → chunk-Q5OT7LZG.js} +11 -496
- package/dist/chunk-Q5OT7LZG.js.map +1 -0
- package/dist/{chunk-6NEXVBPY.js → chunk-RWNSW4FM.js} +1 -1
- package/dist/chunk-RWNSW4FM.js.map +1 -0
- package/dist/{chunk-E25FBYJP.js → chunk-SAFGDIPQ.js} +1 -1
- package/dist/chunk-SAFGDIPQ.js.map +1 -0
- package/dist/{chunk-OP7QCTR5.js → chunk-SEELKQUM.js} +2 -2
- package/dist/chunk-SEELKQUM.js.map +1 -0
- package/dist/{chunk-4B2ZMX45.js → chunk-SSYDEKWF.js} +1 -1
- package/dist/chunk-SSYDEKWF.js.map +1 -0
- package/dist/{chunk-DQVBL2G4.js → chunk-SZU6BOMV.js} +75 -53
- package/dist/chunk-SZU6BOMV.js.map +1 -0
- package/dist/{chunk-65EFIUDD.js → chunk-U267AOWS.js} +1 -1
- package/dist/chunk-U267AOWS.js.map +1 -0
- package/dist/{chunk-FX72VHAE.js → chunk-U3H53IIN.js} +6 -6
- package/dist/chunk-U3H53IIN.js.map +1 -0
- package/dist/{chunk-OPLICDUB.js → chunk-UW2TEAGR.js} +1 -1
- package/dist/chunk-UW2TEAGR.js.map +1 -0
- package/dist/{chunk-IAJ2JVEH.js → chunk-VSLTKX5L.js} +1 -1
- package/dist/chunk-VSLTKX5L.js.map +1 -0
- package/dist/{chunk-YB5DJJ4U.js → chunk-VZTYCAO6.js} +1 -1
- package/dist/chunk-VZTYCAO6.js.map +1 -0
- package/dist/chunk-WDGYCBNI.js +65 -0
- package/dist/chunk-WDGYCBNI.js.map +1 -0
- package/dist/chunk-WPJOTQA5.js +1 -0
- package/dist/chunk-WPJOTQA5.js.map +1 -0
- package/dist/{chunk-DGUM43GV.js → chunk-XTHN6JBX.js} +1 -1
- package/dist/chunk-XTHN6JBX.js.map +1 -0
- package/dist/{chunk-HZ6USUHC.js → chunk-YOIVCCZT.js} +1 -1
- package/dist/chunk-YOIVCCZT.js.map +1 -0
- package/dist/{chunk-OI6DK6ZJ.js → chunk-ZC2UESE4.js} +6 -4
- package/dist/{chunk-OI6DK6ZJ.js.map → chunk-ZC2UESE4.js.map} +1 -1
- package/dist/cli/index.js +8 -8
- package/dist/client/core.d.ts +4 -258
- package/dist/client/core.js +13 -9
- package/dist/client/core.js.map +1 -1
- package/dist/client/index.d.ts +7 -96
- package/dist/client/index.js +19 -67
- package/dist/client/index.js.map +1 -1
- package/dist/{controller-swc-transform-JJRMTSDY.js → controller-swc-transform-T7ZTD55V.js} +2 -2
- package/dist/controller-swc-transform-T7ZTD55V.js.map +1 -0
- package/dist/{cookies-MJKMGJ7N.js → cookies-SOXUQJXG.js} +3 -3
- package/dist/cookies-SOXUQJXG.js.map +1 -0
- package/dist/{dev-WQ4LWCAW.js → dev-V6UBM2OL.js} +8 -7
- package/dist/{dev-WQ4LWCAW.js.map → dev-V6UBM2OL.js.map} +1 -1
- package/dist/{dev-emit-HLGJK3PP.js → dev-emit-F54Y5TIU.js} +5 -5
- package/dist/dev-emit-F54Y5TIU.js.map +1 -0
- package/dist/devtools/entry.js +61 -53
- package/dist/devtools/entry.js.map +1 -1
- package/dist/dispatcher-MXKF3CRH.js +8 -0
- package/dist/dispatcher-MXKF3CRH.js.map +1 -0
- package/dist/index.js +25 -25
- package/dist/index.js.map +1 -1
- package/dist/{info-75U6GCMD.js → info-ICDTPJDC.js} +3 -3
- package/dist/{internal-api-JFORKYLR.js → internal-api-ALXVBL56.js} +10 -8
- package/dist/{internal-api-DV3H5NNV.js → internal-api-S7WK2WCY.js} +20 -20
- package/dist/internal-api-S7WK2WCY.js.map +1 -0
- package/dist/{load-config-XP7NSSA7.js → load-config-ICCNMO74.js} +3 -3
- package/dist/{mcp-FF3NTCHB.js → mcp-4JFODA5U.js} +3 -3
- package/dist/{openapi-ZPXYRAM2.js → openapi-NIYA2VBG.js} +3 -3
- package/dist/react-query/index.js +2 -2
- package/dist/react-query/index.js.map +1 -1
- package/dist/{routes-ZVDKABXZ.js → routes-2RD4S5PZ.js} +3 -3
- package/dist/{schema-FBOTN46F.js → schema-S553QCAU.js} +2 -2
- package/dist/server/agent/index.d.ts +3 -72
- package/dist/server/agent/index.js +4 -4
- package/dist/server/agent/index.js.map +1 -1
- package/dist/server/auth/index.js +4 -4
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cost/index.js +2 -2
- package/dist/server/cost/index.js.map +1 -1
- package/dist/server/cron/index.js +6 -6
- package/dist/server/cron/index.js.map +1 -1
- package/dist/server/define/index.js +4 -4
- package/dist/server/define/index.js.map +1 -1
- package/dist/server/http/index.js +11 -11
- package/dist/server/http/index.js.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +41 -41
- package/dist/server/index.js.map +1 -1
- package/dist/server/jobs/index.js +7 -7
- package/dist/server/jobs/index.js.map +1 -1
- package/dist/server/observability/index.d.ts +8 -1
- package/dist/server/observability/index.js +5 -5
- package/dist/server/observability/index.js.map +1 -1
- package/dist/server/plugins/index.js +3 -3
- package/dist/server/plugins/index.js.map +1 -1
- package/dist/server/rate-limit/index.js +4 -4
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/realtime/index.js +2 -2
- package/dist/server/realtime/index.js.map +1 -1
- package/dist/server/scan/index.js +7 -7
- package/dist/server/scan/index.js.map +1 -1
- package/dist/server/security/index.js +5 -5
- package/dist/server/security/index.js.map +1 -1
- package/dist/server/storage/index.js +2 -2
- package/dist/server/storage/index.js.map +1 -1
- package/dist/server/webhook/index.js +3 -3
- package/dist/server/webhook/index.js.map +1 -1
- package/dist/server-error-to-envelope-UM7DEVM4.js +8 -0
- package/dist/server-error-to-envelope-UM7DEVM4.js.map +1 -0
- package/dist/{server-routes-hmr-RI7SYNT2.js → server-routes-hmr-6CRNSEWF.js} +2 -2
- package/dist/server-routes-hmr-6CRNSEWF.js.map +1 -0
- package/dist/{services-typed-client-AU6DKXAO.js → services-typed-client-IXNOPVZA.js} +3 -3
- package/dist/services-typed-client-IXNOPVZA.js.map +1 -0
- package/dist/{start-2U3FUCJX.js → start-2LNPPG74.js} +35 -11
- package/dist/start-2LNPPG74.js.map +1 -0
- package/dist/vite-plugin/index.js +25 -25
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/{vite-plugin-D2NTPZNC.js → vite-plugin-X6YO3OUH.js} +8 -7
- package/package.json +9 -5
- package/dist/actions-virtual-module-RSFRPJQZ.js.map +0 -1
- package/dist/agents-typed-client-ZP7BKJB3.js.map +0 -1
- package/dist/app-typed-client-GDF2OMJ2.js.map +0 -1
- package/dist/app-typed-client-USLAMN7X.js.map +0 -1
- package/dist/body-parser-web-NNEJGX6Y.js.map +0 -1
- package/dist/build-MQHIJROR.js.map +0 -1
- package/dist/build-request-body-preview-FVBQ7LCE.js.map +0 -1
- package/dist/chunk-26ECIX74.js.map +0 -1
- package/dist/chunk-4B2ZMX45.js.map +0 -1
- package/dist/chunk-4HAU7AJM.js.map +0 -1
- package/dist/chunk-575PAX5L.js.map +0 -1
- package/dist/chunk-5QW7IQQU.js.map +0 -1
- package/dist/chunk-65EFIUDD.js.map +0 -1
- package/dist/chunk-6FK7FKY6.js.map +0 -1
- package/dist/chunk-6NEXVBPY.js.map +0 -1
- package/dist/chunk-6OXCZMW3.js.map +0 -1
- package/dist/chunk-7BIM27LV.js.map +0 -1
- package/dist/chunk-7MQOHNHE.js.map +0 -1
- package/dist/chunk-ASDXVRJD.js.map +0 -1
- package/dist/chunk-C3ZZ56YZ.js.map +0 -1
- package/dist/chunk-DJFMAWH5.js.map +0 -1
- package/dist/chunk-DQVBL2G4.js.map +0 -1
- package/dist/chunk-E25FBYJP.js.map +0 -1
- package/dist/chunk-E3JH6YUM.js +0 -1
- package/dist/chunk-ESC54TAK.js.map +0 -1
- package/dist/chunk-FH3DYBAN.js.map +0 -1
- package/dist/chunk-FX72VHAE.js.map +0 -1
- package/dist/chunk-HGUZWG2C.js.map +0 -1
- package/dist/chunk-HZ6USUHC.js.map +0 -1
- package/dist/chunk-IAJ2JVEH.js.map +0 -1
- package/dist/chunk-IE6C4KZX.js.map +0 -1
- package/dist/chunk-JBCHWRKF.js.map +0 -1
- package/dist/chunk-JHEAWR3L.js +0 -1
- package/dist/chunk-JIL74SFK.js.map +0 -1
- package/dist/chunk-JQJN6LFK.js.map +0 -1
- package/dist/chunk-JQSKBMXP.js.map +0 -1
- package/dist/chunk-KPRJS3II.js +0 -505
- package/dist/chunk-KPRJS3II.js.map +0 -1
- package/dist/chunk-L2S2R3TI.js.map +0 -1
- package/dist/chunk-N2D5AVRR.js.map +0 -1
- package/dist/chunk-NM4WF3XD.js.map +0 -1
- package/dist/chunk-NPMCKOX4.js +0 -1
- package/dist/chunk-NPMCKOX4.js.map +0 -1
- package/dist/chunk-OP7QCTR5.js.map +0 -1
- package/dist/chunk-OPLICDUB.js.map +0 -1
- package/dist/chunk-OVHW23YC.js.map +0 -1
- package/dist/chunk-SJIRP73B.js.map +0 -1
- package/dist/chunk-TSLSIRBR.js.map +0 -1
- package/dist/chunk-UD3LFGDL.js.map +0 -1
- package/dist/chunk-UUFYP2UM.js.map +0 -1
- package/dist/chunk-UVXB2ER7.js.map +0 -1
- package/dist/chunk-V3LJN2GS.js.map +0 -1
- package/dist/chunk-VMEWD57H.js.map +0 -1
- package/dist/chunk-VPISAMXU.js.map +0 -1
- package/dist/chunk-WSJKACWB.js.map +0 -1
- package/dist/chunk-X32XEJXR.js.map +0 -1
- package/dist/chunk-XZ6B2Y2R.js.map +0 -1
- package/dist/chunk-YB5DJJ4U.js.map +0 -1
- package/dist/chunk-ZEGYW52B.js.map +0 -1
- package/dist/chunk-ZJQ4O76G.js.map +0 -1
- package/dist/controller-swc-transform-JJRMTSDY.js.map +0 -1
- package/dist/cookies-MJKMGJ7N.js.map +0 -1
- package/dist/dev-emit-HLGJK3PP.js.map +0 -1
- package/dist/dispatcher-DLKIXYNO.js +0 -8
- package/dist/dispatcher-DLKIXYNO.js.map +0 -1
- package/dist/internal-api-DV3H5NNV.js.map +0 -1
- package/dist/internal-api-JFORKYLR.js.map +0 -1
- package/dist/load-config-XP7NSSA7.js.map +0 -1
- package/dist/schema-FBOTN46F.js.map +0 -1
- package/dist/server-error-to-envelope-EOFUIUNB.js +0 -8
- package/dist/server-error-to-envelope-EOFUIUNB.js.map +0 -1
- package/dist/server-routes-hmr-RI7SYNT2.js.map +0 -1
- package/dist/services-typed-client-AU6DKXAO.js.map +0 -1
- package/dist/start-2U3FUCJX.js.map +0 -1
- package/dist/vite-plugin-D2NTPZNC.js.map +0 -1
- /package/dist/{agent-OXRRKB55.js.map → agent-OCCL5RUY.js.map} +0 -0
- /package/dist/{chunk-CJNMJUHE.js.map → chunk-B7ONQ4QJ.js.map} +0 -0
- /package/dist/{chunk-2WH6SD3C.js.map → chunk-DSOBIXXR.js.map} +0 -0
- /package/dist/{info-75U6GCMD.js.map → info-ICDTPJDC.js.map} +0 -0
- /package/dist/{broadcast-4SX7R5XE.js.map → internal-api-ALXVBL56.js.map} +0 -0
- /package/dist/{chunk-DGUM43GV.js.map → load-config-ICCNMO74.js.map} +0 -0
- /package/dist/{mcp-FF3NTCHB.js.map → mcp-4JFODA5U.js.map} +0 -0
- /package/dist/{openapi-ZPXYRAM2.js.map → openapi-NIYA2VBG.js.map} +0 -0
- /package/dist/{routes-ZVDKABXZ.js.map → routes-2RD4S5PZ.js.map} +0 -0
- /package/dist/{chunk-E3JH6YUM.js.map → schema-S553QCAU.js.map} +0 -0
- /package/dist/{chunk-JHEAWR3L.js.map → vite-plugin-X6YO3OUH.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/security/csp-report.ts","../src/server/security/csrf-readiness-endpoint.ts","../src/server/security/csrf-readiness-store.ts","../src/server/security/security-headers.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport { safeAudit, type AuditLogger } from '../observability/audit-log.js'\n\n/**\n * T5.1 — Built-in CSP report endpoint.\n *\n * Browsers POST violation reports to `report-uri` (legacy `application/csp-report`)\n * or `Reporting API` (`application/reports+json`). Framework auto-registers this\n * endpoint so `cspMode: 'report-only'` is actually useful out of the box.\n *\n * Forwards normalized violations to:\n * - audit logger (`csp.violation`)\n * - devtools dispatcher (dev only, for Errors tab)\n * - optional user hook (Sentry, etc.)\n *\n * EC-2: browser MAY send `{\"csp-report\": null}`, empty `{}`, or\n * reports+json entries lacking `body`. Handler MUST short-circuit to\n * 204 (valid format, no violation), NEVER crash via null deref.\n */\n\nexport const CSP_REPORT_PATH = '/__theo/csp-report'\n\n/** Max body bytes accepted. Real CSP reports are < 2 KB; 16 KB is generous. */\nconst MAX_BODY = 16 * 1024\n\nexport interface CspViolation {\n blockedUrl: string\n documentUrl: string\n violatedDirective: string\n effectiveDirective?: string\n originalPolicy?: string\n disposition?: 'enforce' | 'report'\n statusCode?: number\n sourceFile?: string\n lineNumber?: number\n columnNumber?: number\n}\n\nexport interface CspReportHandlerOptions {\n auditLogger?: AuditLogger\n devtoolsDispatcher?: {\n onCspViolation?: (v: CspViolation) => void\n }\n /** Optional user-provided sink (Sentry, custom log router). Errors here are swallowed. */\n onViolation?: (v: CspViolation) => void\n}\n\n/**\n * Map a legacy `application/csp-report` payload to the internal shape.\n * Caller must ensure `raw` is a non-null object.\n */\nfunction pickHeader(value: string | string[] | undefined): string {\n if (typeof value === 'string') return value\n if (Array.isArray(value) && value.length > 0) return value[0]\n return ''\n}\n\nfunction toStringSafe(value: unknown, fallback = '(missing)'): string {\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n return fallback\n}\n\nexport function normalizeLegacy(raw: Record<string, unknown>): CspViolation {\n return {\n blockedUrl: toStringSafe(raw['blocked-uri']),\n documentUrl: toStringSafe(raw['document-uri']),\n violatedDirective: toStringSafe(raw['violated-directive']),\n effectiveDirective:\n typeof raw['effective-directive'] === 'string' ? raw['effective-directive'] : undefined,\n originalPolicy: typeof raw['original-policy'] === 'string' ? raw['original-policy'] : undefined,\n disposition:\n raw.disposition === 'enforce' || raw.disposition === 'report' ? raw.disposition : undefined,\n statusCode: typeof raw['status-code'] === 'number' ? raw['status-code'] : undefined,\n sourceFile: typeof raw['source-file'] === 'string' ? raw['source-file'] : undefined,\n lineNumber: typeof raw['line-number'] === 'number' ? raw['line-number'] : undefined,\n columnNumber: typeof raw['column-number'] === 'number' ? raw['column-number'] : undefined,\n }\n}\n\n/**\n * Map a `reports+json` entry to the internal shape. Returns `null` if\n * the entry lacks a usable `body` object (EC-2).\n */\nexport function normalizeNew(entry: unknown): CspViolation | null {\n if (!entry || typeof entry !== 'object') return null\n const body = (entry as { body?: unknown }).body\n if (!body || typeof body !== 'object') return null\n const b = body as Record<string, unknown>\n return {\n blockedUrl: toStringSafe(b.blockedURL),\n documentUrl: toStringSafe(b.documentURL),\n violatedDirective: toStringSafe(b.violatedDirective),\n effectiveDirective: typeof b.effectiveDirective === 'string' ? b.effectiveDirective : undefined,\n originalPolicy: typeof b.originalPolicy === 'string' ? b.originalPolicy : undefined,\n disposition:\n b.disposition === 'enforce' || b.disposition === 'report' ? b.disposition : undefined,\n statusCode: typeof b.statusCode === 'number' ? b.statusCode : undefined,\n sourceFile: typeof b.sourceFile === 'string' ? b.sourceFile : undefined,\n lineNumber: typeof b.lineNumber === 'number' ? b.lineNumber : undefined,\n columnNumber: typeof b.columnNumber === 'number' ? b.columnNumber : undefined,\n }\n}\n\nasync function readBody(req: IncomingMessage, maxBytes: number): Promise<string> {\n return await new Promise<string>((resolve, reject) => {\n const chunks: Buffer[] = []\n let total = 0\n req.on('data', (chunk: Buffer) => {\n total += chunk.length\n if (total > maxBytes) {\n reject(new Error('body too large'))\n req.destroy()\n return\n }\n chunks.push(chunk)\n })\n req.on('end', () => {\n resolve(Buffer.concat(chunks).toString('utf8'))\n })\n req.on('error', reject)\n })\n}\n\nexport async function handleCspReport(\n req: IncomingMessage,\n res: ServerResponse,\n opts: CspReportHandlerOptions,\n): Promise<void> {\n const ctHeader = req.headers['content-type']\n const ct = pickHeader(ctHeader)\n\n let raw: string\n try {\n raw = await readBody(req, MAX_BODY)\n } catch {\n res.statusCode = 413\n res.end()\n return\n }\n\n let violations: CspViolation[]\n try {\n if (ct.startsWith('application/csp-report')) {\n // EC-2: browsers MAY POST {\"csp-report\": null} or {} on\n // disposition='report' policies. Guard against null/undefined/non-object.\n const parsed = JSON.parse(raw) as Record<string, unknown>\n const inner = parsed['csp-report']\n if (!inner || typeof inner !== 'object') {\n res.statusCode = 204\n res.end()\n return\n }\n violations = [normalizeLegacy(inner as Record<string, unknown>)]\n } else if (ct.startsWith('application/reports+json')) {\n // EC-2: filter out entries lacking `body` BEFORE normalizing.\n const parsed: unknown = JSON.parse(raw)\n const entries = Array.isArray(parsed) ? parsed : []\n violations = entries.map((e) => normalizeNew(e)).filter((v): v is CspViolation => v !== null)\n } else {\n res.statusCode = 415\n res.end()\n return\n }\n } catch {\n res.statusCode = 400\n res.end()\n return\n }\n\n for (const v of violations) {\n safeAudit(opts.auditLogger, {\n action: 'csp.violation',\n metadata: v as unknown as Record<string, unknown>,\n })\n try {\n opts.devtoolsDispatcher?.onCspViolation?.(v)\n } catch {\n // dispatcher errors are isolated from the request\n }\n try {\n opts.onViolation?.(v)\n } catch {\n // user hook throws are swallowed — never crash the request\n }\n }\n\n res.statusCode = 204\n res.end()\n}\n\n/**\n * T5a.2 Phase B slice 4/6 — Web-Standards CSP report handler.\n *\n * Mirror of `handleCspReport(req: IncomingMessage, res: ServerResponse,\n * opts): Promise<void>` for the Web `Request` shape. Returns\n * `Response` directly instead of mutating `res`.\n *\n * Same content-type dispatch (legacy `application/csp-report` vs new\n * `application/reports+json`), same normalizers (`normalizeLegacy`,\n * `normalizeNew`), same side-effect loop (safeAudit + devtools + user\n * hook). The body cap is enforced post-read because Web Request body\n * streaming doesn't have a portable mid-stream rejection primitive\n * across CF Workers / Bun / Deno; CSP reports are < 2 KB typical, well\n * under MAX_BODY (16 KB).\n *\n * Returns:\n * - 204 on accepted reports OR no-op empty payload\n * - 413 on body too large (post-read check)\n * - 415 on unsupported content-type\n * - 400 on malformed JSON\n */\nasync function readBodyFromRequest(request: Request, maxBytes: number): Promise<string | null> {\n const contentLengthHeader = request.headers.get('content-length')\n if (contentLengthHeader !== null) {\n const declared = Number.parseInt(contentLengthHeader, 10)\n if (Number.isFinite(declared) && declared > maxBytes) return null\n }\n const text = await request.text()\n if (text.length > maxBytes) return null\n return text\n}\n\nfunction dispatchViolations(violations: CspViolation[], opts: CspReportHandlerOptions): void {\n for (const v of violations) {\n safeAudit(opts.auditLogger, {\n action: 'csp.violation',\n metadata: v as unknown as Record<string, unknown>,\n })\n try {\n opts.devtoolsDispatcher?.onCspViolation?.(v)\n } catch {\n // dispatcher errors are isolated from the request\n }\n try {\n opts.onViolation?.(v)\n } catch {\n // user hook throws are swallowed — never crash the request\n }\n }\n}\n\nexport async function handleCspReportRequest(\n request: Request,\n opts: CspReportHandlerOptions,\n): Promise<Response> {\n const ct = request.headers.get('content-type') ?? ''\n\n const raw = await readBodyFromRequest(request, MAX_BODY)\n if (raw === null) {\n return new Response(null, { status: 413 })\n }\n\n let violations: CspViolation[]\n try {\n if (ct.startsWith('application/csp-report')) {\n const parsed = JSON.parse(raw) as Record<string, unknown>\n const inner = parsed['csp-report']\n if (!inner || typeof inner !== 'object') {\n return new Response(null, { status: 204 })\n }\n violations = [normalizeLegacy(inner as Record<string, unknown>)]\n } else if (ct.startsWith('application/reports+json')) {\n const parsed: unknown = JSON.parse(raw)\n const entries = Array.isArray(parsed) ? parsed : []\n violations = entries.map((e) => normalizeNew(e)).filter((v): v is CspViolation => v !== null)\n } else {\n return new Response(null, { status: 415 })\n }\n } catch {\n return new Response(null, { status: 400 })\n }\n\n dispatchViolations(violations, opts)\n return new Response(null, { status: 204 })\n}\n","/**\n * T2.2 — `/__theo/csrf-readiness` endpoint.\n *\n * GET /__theo/csrf-readiness → 200 + JSON summary\n * POST /__theo/csrf-readiness/reset → 204; clears the store\n *\n * The reset endpoint enforces CSRF (own dog food) — requires\n * `X-Theo-Action: 1` AND a matching Origin header (EC-15). This avoids\n * the endpoint being weaponizable from a cross-origin page when the\n * endpoint is opt-in exposed in production.\n *\n * Mount opt-in: in dev mode, the host wires this in unconditionally. In\n * production, only mount when `config.security.csrfTelemetry.exposeReadinessEndpoint === true`.\n * EC-10 parallel: returns 404 (via boolean false return) when the URL\n * does not match — the caller continues normal request handling.\n */\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport type { CsrfReadinessStore } from './csrf-readiness-store.js'\n\nexport const CSRF_READINESS_PATH = '/__theo/csrf-readiness'\nexport const CSRF_READINESS_RESET_PATH = '/__theo/csrf-readiness/reset'\n\nfunction originMatchesHost(req: IncomingMessage): boolean {\n const origin = req.headers.origin\n if (typeof origin !== 'string') return false\n const host = req.headers.host\n if (typeof host !== 'string') return false\n try {\n const parsed = new URL(origin)\n return parsed.host === host\n } catch {\n return false\n }\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, { 'content-type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\nfunction sendNoContent(res: ServerResponse): void {\n res.writeHead(204)\n res.end()\n}\n\nfunction sendError(res: ServerResponse, status: number, code: string, message: string): void {\n res.writeHead(status, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ error: { code, message } }))\n}\n\n// eslint-disable-next-line @typescript-eslint/require-await -- async return for future telemetry hooks\nexport async function handleCsrfReadiness(\n req: IncomingMessage,\n res: ServerResponse,\n store: CsrfReadinessStore,\n): Promise<boolean> {\n const url = (req.url ?? '').split('?')[0]\n const method = req.method ?? 'GET'\n\n if (url === CSRF_READINESS_PATH) {\n if (method === 'GET') {\n sendJson(res, 200, store.summary())\n return true\n }\n sendError(res, 405, 'METHOD_NOT_ALLOWED', `Use GET on ${CSRF_READINESS_PATH}`)\n return true\n }\n\n if (url === CSRF_READINESS_RESET_PATH) {\n if (method !== 'POST') {\n sendError(res, 405, 'METHOD_NOT_ALLOWED', `Use POST on ${CSRF_READINESS_RESET_PATH}`)\n return true\n }\n // Enforce CSRF on our own endpoint (dog-food).\n const hasHeader = req.headers['x-theo-action'] === '1'\n if (!hasHeader || !originMatchesHost(req)) {\n sendError(res, 403, 'CSRF_INVALID', 'Reset requires X-Theo-Action: 1 + same-origin')\n return true\n }\n store.reset()\n sendNoContent(res)\n return true\n }\n\n return false\n}\n\n/**\n * T5a.2 Phase B slice 3/6 — Web-Standards-shaped CSRF readiness handler.\n *\n * Mirror of `handleCsrfReadiness(req: IncomingMessage, res: ServerResponse,\n * store): Promise<boolean>` for the Web `Request` shape. Returns\n * `Response | null` instead of mutating `res` and returning a boolean:\n * - `Response` → this handler claimed the URL; caller short-circuits.\n * - `null` → URL doesn't match our endpoint; caller continues normal dispatch.\n *\n * Same routes (GET `CSRF_READINESS_PATH`, POST `CSRF_READINESS_RESET_PATH`).\n * Same CSRF dog-food on reset (X-Theo-Action + same-origin).\n *\n * Wire into `executeWebRequest` integration via a future Phase B sub-slice\n * (consumer can also call this directly today via the\n * `theokit/server/security` sub-path).\n */\nfunction buildJsonResponse(status: number, body: unknown): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n}\n\nfunction buildErrorResponse(status: number, code: string, message: string): Response {\n return buildJsonResponse(status, { error: { code, message } })\n}\n\n/**\n * Returns true when `Origin` header and request URL host match (RFC 6454\n * same-origin check). Web-Standards counterpart of `originMatchesHost`.\n */\nfunction originMatchesHostFromRequest(request: Request): boolean {\n const origin = request.headers.get('origin')\n if (origin === null || origin.length === 0) return false\n const host = request.headers.get('host')\n if (host === null || host.length === 0) {\n // Fallback: derive host from request.url (Web Request guarantees absolute URL)\n try {\n const reqHost = new URL(request.url).host\n const originHost = new URL(origin).host\n return originHost === reqHost\n } catch {\n return false\n }\n }\n try {\n return new URL(origin).host === host\n } catch {\n return false\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/require-await -- async return for future telemetry hooks\nexport async function handleCsrfReadinessRequest(\n request: Request,\n store: CsrfReadinessStore,\n): Promise<Response | null> {\n const url = new URL(request.url).pathname\n const method = request.method.toUpperCase()\n\n if (url === CSRF_READINESS_PATH) {\n if (method === 'GET') {\n return buildJsonResponse(200, store.summary())\n }\n return buildErrorResponse(405, 'METHOD_NOT_ALLOWED', `Use GET on ${CSRF_READINESS_PATH}`)\n }\n\n if (url === CSRF_READINESS_RESET_PATH) {\n if (method !== 'POST') {\n return buildErrorResponse(\n 405,\n 'METHOD_NOT_ALLOWED',\n `Use POST on ${CSRF_READINESS_RESET_PATH}`,\n )\n }\n // Enforce CSRF on our own endpoint (dog-food).\n const hasHeader = request.headers.get('x-theo-action') === '1'\n if (!hasHeader || !originMatchesHostFromRequest(request)) {\n return buildErrorResponse(\n 403,\n 'CSRF_INVALID',\n 'Reset requires X-Theo-Action: 1 + same-origin',\n )\n }\n store.reset()\n return new Response(null, { status: 204 })\n }\n\n return null\n}\n","/**\n * T2.2 — In-memory bounded counter for CSRF warn events.\n *\n * Aggregates `csrf.warn` payloads by `(method, path, reason)` triple.\n * Used by the `/__theo/csrf-readiness` endpoint to expose a summary the\n * developer (or devtools tab) can inspect, so users do NOT need to grep\n * stdout to know which endpoints will break under 0.3.0 strict CSRF.\n *\n * Bounded at 1000 distinct keys (EC-22). Eviction is LRU-by-insertion —\n * when the cap is hit, the oldest key is dropped and a re-record of an\n * evicted key starts fresh (count: 1).\n *\n * Single-threaded by virtue of the JS event loop; Map operations are\n * atomic. NOT shared across processes — each worker has its own store.\n */\n\nexport interface CsrfWarnRecord {\n method: string\n path: string\n reason: string\n}\n\nexport interface CsrfReadinessRouteSummary {\n method: string\n path: string\n reason: string\n count: number\n firstSeen: string\n lastSeen: string\n}\n\nexport interface CsrfReadinessSummary {\n generatedAt: string\n totalEvents: number\n routes: CsrfReadinessRouteSummary[]\n}\n\ninterface StoredEntry {\n count: number\n firstSeen: string\n lastSeen: string\n}\n\nexport class CsrfReadinessStore {\n static readonly MAX_ENTRIES = 1000\n private readonly entries = new Map<string, StoredEntry>()\n\n private keyFor(event: CsrfWarnRecord): string {\n return `${event.method}\u0000${event.path}\u0000${event.reason}`\n }\n\n record(event: CsrfWarnRecord): void {\n const key = this.keyFor(event)\n const now = new Date().toISOString()\n const existing = this.entries.get(key)\n if (existing) {\n existing.count++\n existing.lastSeen = now\n return\n }\n if (this.entries.size >= CsrfReadinessStore.MAX_ENTRIES) {\n const firstKey = this.entries.keys().next().value\n if (firstKey !== undefined) this.entries.delete(firstKey)\n }\n this.entries.set(key, { count: 1, firstSeen: now, lastSeen: now })\n }\n\n summary(): CsrfReadinessSummary {\n let total = 0\n const routes: CsrfReadinessRouteSummary[] = []\n for (const [key, entry] of this.entries) {\n const [method, path, reason] = key.split('\u0000')\n routes.push({\n method,\n path,\n reason,\n count: entry.count,\n firstSeen: entry.firstSeen,\n lastSeen: entry.lastSeen,\n })\n total += entry.count\n }\n return {\n generatedAt: new Date().toISOString(),\n totalEvents: total,\n routes,\n }\n }\n\n reset(): void {\n this.entries.clear()\n }\n}\n","import type { ServerResponse } from 'node:http'\n\n/**\n * Phase 6 — Default Security Headers (D4 / EC-2).\n *\n * Per-response security baseline. The framework applies these BEFORE the\n * route handler runs so a handler can still override via `res.setHeader`.\n *\n * EC-2 backward-compatibility: CSP ships in `report-only` mode by default\n * for 0.2.0. Existing apps with inline scripts or third-party CDN scripts\n * keep working but consumers see violation reports via their CSP report\n * collector (or browser DevTools). 0.3.0 will flip the default to\n * `enforce` after a release of visibility.\n */\n\n/**\n * Default Content-Security-Policy. Conservative-but-not-paralyzing:\n *\n * - default-src 'self' — every fetch falls back to same-origin\n * - script-src 'self' — T6.1 (0.3.0): `'unsafe-inline'`\n * dropped. The SSR pipeline issues a\n * per-request nonce that REPLACES\n * this directive at runtime\n * (`'nonce-<token>'`). For static /\n * non-SSR contexts where no nonce is\n * available, the policy is strict-\n * no-inline — user inline scripts\n * must be migrated to external\n * `<script src=\"...\">` or threaded\n * through `ctx.nonce`.\n * - style-src 'self' 'unsafe-inline' — Tailwind + TheoUI use style attrs\n * in animation directives\n * - img-src 'self' data: blob: — supports inline data URIs, blobs\n * from canvas exports\n * - font-src 'self' data: — Geist fonts inline-base64\n * - connect-src 'self' ws: wss: — WebSocket dev HMR + agent streams\n * - frame-ancestors 'none' — clickjacking defense\n */\n/**\n * T5.1 — default CSP includes the built-in report endpoint so violations\n * are visible without extra config. Apps that ship a custom `csp` string\n * override the report-uri.\n */\nexport const DEFAULT_CSP =\n \"default-src 'self'; \" +\n \"script-src 'self'; \" +\n \"style-src 'self' 'unsafe-inline'; \" +\n \"img-src 'self' data: blob:; \" +\n \"font-src 'self' data:; \" +\n \"connect-src 'self' ws: wss:; \" +\n \"frame-ancestors 'none'; \" +\n 'report-uri /__theo/csp-report'\n\n/**\n * T1.1 — Default Permissions-Policy header (default-deny stance).\n *\n * Disables sensitive Web APIs that the vast majority of apps don't use.\n * Apps that DO need any of these opt in by overriding `permissionsPolicy`\n * in `config.security.headers`.\n *\n * The seven features listed are the most-abused for: tracking\n * (geolocation, accelerometer, gyroscope), spyware (camera, microphone),\n * fraud (payment), and hardware exfiltration (usb).\n *\n * Aligns with Mozilla baseline + OWASP Secure Headers + Lighthouse PWA.\n */\nexport const DEFAULT_PERMISSIONS_POLICY =\n 'geolocation=(), camera=(), microphone=(), payment=(), usb=(), accelerometer=(), gyroscope=()'\n\nexport type CspMode = 'enforce' | 'report-only' | 'off'\n\nexport interface SecurityHeadersConfig {\n /**\n * Custom CSP policy string. When set, replaces the default verbatim.\n * Pass `false` to disable CSP entirely (alias for `cspMode: 'off'`).\n */\n csp?: string | false\n /**\n * Enforcement mode for CSP. Default `report-only` for 0.2.0 (EC-2).\n * 0.3.0 will default to `enforce`.\n */\n cspMode?: CspMode\n /**\n * Strict-Transport-Security value. Defaults to\n * `max-age=31536000; includeSubDomains` in production. Pass `false` to\n * suppress (e.g. internal LANs without TLS).\n */\n hsts?: string | false\n /** X-Frame-Options. Default DENY. */\n frameOptions?: 'DENY' | 'SAMEORIGIN'\n /** X-Content-Type-Options. Default `nosniff`. */\n contentTypeOptions?: 'nosniff'\n /** Referrer-Policy. Default `strict-origin-when-cross-origin`. */\n referrerPolicy?: string\n /**\n * T1.1 — Permissions-Policy directive string. When set, replaces the\n * default verbatim (no merge — see ADR-EC-12). Pass `false` to disable\n * the header entirely. Schema-level refinement rejects any string\n * containing CR/LF (EC-3 — CWE-113 HTTP Response Splitting mitigation).\n */\n permissionsPolicy?: string | false\n}\n\nexport interface SecurityEnv {\n production: boolean\n}\n\n/**\n * T4.1 — Per-request options passed by the SSR pipeline.\n *\n * - `nonce`: when set, the framework substitutes the `'unsafe-inline'`\n * token in `script-src` with `'nonce-<nonce>'`. EC-3 forces\n * `Cache-Control: private, no-store` so a CDN cannot cache the HTML\n * (carrying one nonce) and re-serve it with a freshly-generated CSP\n * header (carrying a different nonce).\n * - `prerender`: when true, the nonce is IGNORED. Prerendered HTML is\n * generated at build time with no nonce in the script tags; mixing a\n * runtime nonce in the header would block every script. EC-4.\n */\nexport interface SecurityHeadersOptions {\n nonce?: string\n prerender?: boolean\n}\n\nconst DEFAULT_HSTS = 'max-age=31536000; includeSubDomains'\n\n/**\n * Apply a nonce to the script-src directive of an existing CSP policy\n * string. Replaces `'unsafe-inline'` (if present) with `'nonce-<value>'`;\n * otherwise appends the nonce directive to the script-src line.\n */\nfunction applyNonceToCsp(policy: string, nonce: string): string {\n return policy\n .split(';')\n .map((directive) => {\n const trimmed = directive.trim()\n if (!trimmed.startsWith('script-src')) return directive\n if (trimmed.includes(\"'unsafe-inline'\")) {\n return directive.replace(\"'unsafe-inline'\", `'nonce-${nonce}'`)\n }\n return `${directive} 'nonce-${nonce}'`\n })\n .join(';')\n}\n\n/**\n * Apply Content-Security-Policy header(s) to `out`. Extracted from\n * `buildSecurityHeaders` to keep that function's complexity within ceiling.\n * Handles the four shapes:\n * csp: false → opt out\n * cspMode: 'off' → opt out\n * cspMode: 'enforce' → Content-Security-Policy (T6.1 default for 0.3.0)\n * cspMode: 'report-only' → Content-Security-Policy-Report-Only (legacy 0.2.x)\n */\nfunction applyCsp(\n out: Record<string, string>,\n config: SecurityHeadersConfig,\n effectiveNonce: string | undefined,\n): void {\n if (config.csp === false || config.cspMode === 'off') return\n let policy = typeof config.csp === 'string' ? config.csp : DEFAULT_CSP\n if (effectiveNonce) {\n policy = applyNonceToCsp(policy, effectiveNonce)\n }\n // T6.1 — default flipped from 'report-only' to 'enforce' for 0.3.0.\n const mode: CspMode = config.cspMode ?? 'enforce'\n if (mode === 'enforce') {\n out['Content-Security-Policy'] = policy\n } else {\n out['Content-Security-Policy-Report-Only'] = policy\n }\n}\n\n/**\n * Build the security headers map for a given config + env. Pure function —\n * returned object can be inspected, logged, or applied to a response.\n */\nexport function buildSecurityHeaders(\n config: SecurityHeadersConfig,\n env: SecurityEnv,\n options: SecurityHeadersOptions = {},\n): Record<string, string> {\n const out: Record<string, string> = {}\n\n // EC-4: prerendered routes must NOT receive a nonce — the build-time\n // HTML carries no nonce, so a runtime nonce would mismatch.\n const effectiveNonce = options.prerender ? undefined : options.nonce\n\n applyCsp(out, config, effectiveNonce)\n\n // X-Frame-Options\n out['X-Frame-Options'] = config.frameOptions ?? 'DENY'\n\n // X-Content-Type-Options\n out['X-Content-Type-Options'] = config.contentTypeOptions ?? 'nosniff'\n\n // Referrer-Policy\n out['Referrer-Policy'] = config.referrerPolicy ?? 'strict-origin-when-cross-origin'\n\n // T1.1 — Permissions-Policy. Default-deny on geo/camera/mic/payment/usb;\n // configurable via `permissionsPolicy`; suppressed via `permissionsPolicy: false`.\n if (config.permissionsPolicy !== false) {\n out['Permissions-Policy'] =\n typeof config.permissionsPolicy === 'string'\n ? config.permissionsPolicy\n : DEFAULT_PERMISSIONS_POLICY\n }\n\n // HSTS — production only, suppressible via hsts: false\n if (env.production && config.hsts !== false) {\n out['Strict-Transport-Security'] = typeof config.hsts === 'string' ? config.hsts : DEFAULT_HSTS\n }\n\n // EC-3: when a nonce is in play, the response carries a one-shot CSP\n // header AND inline scripts in the HTML body. A CDN that caches the\n // HTML and proxies a fresh CSP per request would block every script\n // (nonces wouldn't match). Force no-store to prevent that class of\n // silent prod-only failure. Prerendered routes (which carry no nonce\n // by design — EC-4) are exempt; their HTML is meant to be cacheable.\n if (effectiveNonce) {\n out['Cache-Control'] = 'private, no-store'\n }\n\n return out\n}\n\n/**\n * Apply security headers to a Node ServerResponse. Called by the\n * api-middleware before the route handler runs. The handler can override\n * any header via `res.setHeader()` — last write wins by Node convention.\n */\nexport function applySecurityHeaders(\n res: ServerResponse,\n config: SecurityHeadersConfig,\n env: SecurityEnv,\n options: SecurityHeadersOptions = {},\n): void {\n const headers = buildSecurityHeaders(config, env, options)\n for (const [key, value] of Object.entries(headers)) {\n res.setHeader(key, value)\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-JHEAWR3L.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=chunk-JHEAWR3L.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/contracts/action-protocol.ts","../src/server/http/send-response.ts","../src/server/http/middleware-runner.ts","../src/server/http/node-request.ts","../src/core/contracts/auth-error-guard.ts","../src/server/security/csrf-warn-dispatch.ts","../src/server/http/execute-stages.ts","../src/server/http/execute.ts","../src/server/http/handle-request-error.ts","../src/server/http/form-data-to-object.ts","../src/server/http/serialize-action-result.ts","../src/server/http/action-execute.ts","../src/server/http/batch-handler.ts","../src/server/http/cors.ts","../src/server/http/trace-context.ts"],"sourcesContent":["/**\n * Action protocol — cross-boundary contract for `defineAction` + `useAction`.\n *\n * Per plan g3-server-actions-and-useaction v1.2 § Phase 0 / T0.1, ADRs D1 (encoding)\n * + D6 (full dot-notation path) + D7 (PII mask) — types and runtime referenced\n * by server (`server/http/action-execute.ts`, `server/define/define-action.ts`)\n * and client (`@theokit/react/useAction`, `vite-plugin/actions-virtual-module`).\n *\n * Lives in `core/contracts/` per architecture.md v3.1 exception — cross-module\n * deep imports ALLOWED for this file. Core depends on NOTHING intra-monorepo;\n * `extractUniversalIssues` is implemented INLINE (NOT imported from `@theokit/sdk`)\n * to honor dep-cruiser `core-depends-on-nothing` invariant (EC-1 absorbed).\n *\n * Field-key convention (D6 + EC-13): dot-notation full path. Nested objects use\n * `'user.address.zip'`; array indices use `'items.0.name'` (NOT bracket\n * `'items[0].name'`). Root-level errors (path = []) use empty string `''`\n * (EC-7). Consumers needing bracket notation can write a small `dotToBracket`\n * helper in userland.\n */\n\nimport type { TheoErrorCode, TheoErrorEnvelope, ValidationFieldsExt } from './error-envelope.js'\n\n/**\n * HTTP-status mapping per IANA HTTP Status Code Registry (subset relevant to\n * action surface). VALIDATION_ERROR → 422 is preferred over Astro's BAD_REQUEST/400\n * (more semantic for input-shape mismatch). PAYLOAD_TOO_LARGE → 413 covers EC-3\n * (response-side size limit; request-side reuses standard 413).\n */\nexport type ActionErrorCode =\n | 'VALIDATION_ERROR'\n | 'BAD_REQUEST'\n | 'UNAUTHORIZED'\n | 'FORBIDDEN'\n | 'NOT_FOUND'\n | 'METHOD_NOT_ALLOWED'\n | 'CONFLICT'\n | 'CONTENT_TOO_LARGE'\n | 'PAYLOAD_TOO_LARGE'\n | 'UNSUPPORTED_MEDIA_TYPE'\n | 'TOO_MANY_REQUESTS'\n | 'INTERNAL_SERVER_ERROR'\n\nconst CODE_TO_STATUS: Record<ActionErrorCode, number> = {\n VALIDATION_ERROR: 422,\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n METHOD_NOT_ALLOWED: 405,\n CONFLICT: 409,\n CONTENT_TOO_LARGE: 413,\n PAYLOAD_TOO_LARGE: 413,\n UNSUPPORTED_MEDIA_TYPE: 415,\n TOO_MANY_REQUESTS: 429,\n INTERNAL_SERVER_ERROR: 500,\n}\n\nconst STATUS_TO_CODE: Record<number, ActionErrorCode> = {\n 400: 'BAD_REQUEST',\n 401: 'UNAUTHORIZED',\n 403: 'FORBIDDEN',\n 404: 'NOT_FOUND',\n 405: 'METHOD_NOT_ALLOWED',\n 409: 'CONFLICT',\n 413: 'PAYLOAD_TOO_LARGE',\n 415: 'UNSUPPORTED_MEDIA_TYPE',\n 422: 'VALIDATION_ERROR',\n 429: 'TOO_MANY_REQUESTS',\n 500: 'INTERNAL_SERVER_ERROR',\n}\n\n/**\n * Universal zod issue shape covering BOTH v3 (`z.ZodIssue`) and v4 (`$ZodIssue`).\n * Duck-typed minimum surface: `{path, message}`. Implemented per EC-1 absorbed —\n * consumers chain may ship either zod major; constructor accepts `unknown` and\n * normalizes via `extractUniversalIssues`.\n */\nexport interface UniversalZodIssue {\n readonly path: readonly (string | number)[]\n readonly message: string\n readonly code?: string\n}\n\n/**\n * `ActionError` — general server-side action failure. Discriminator `type` is\n * literal `'TheoActionError'`; used by `ActionError.fromJson` to distinguish\n * from `ActionInputError`.\n */\nexport class ActionError extends Error {\n // Discriminator widened to the full union so subclasses can narrow to their\n // specific literal (TypeScript would otherwise reject the override). Concrete\n // values are still always exact literals at runtime.\n readonly type: 'TheoActionError' | 'TheoActionInputError' = 'TheoActionError'\n readonly code: ActionErrorCode\n readonly status: number\n\n constructor(params: { code: ActionErrorCode; message?: string; stack?: string }) {\n super(params.message ?? params.code)\n this.code = params.code\n this.status = ActionError.codeToStatus(params.code)\n if (params.stack) {\n this.stack = params.stack\n }\n }\n\n /**\n * G5 T2.4 — canonical envelope view of the action error. Maps the G3\n * ActionErrorCode to a canonical TheoErrorCode (VALIDATION_ERROR ↔\n * UNPROCESSABLE_ENTITY, CONTENT_TOO_LARGE ↔ PAYLOAD_TOO_LARGE) so consumer\n * UI / SDK code can switch on the unified envelope.\n *\n * Subclasses override to populate `ext` (see `ActionInputError.envelope`).\n */\n get envelope(): TheoErrorEnvelope {\n return {\n code: ActionError.toTheoErrorCode(this.code),\n message: this.message,\n }\n }\n\n /**\n * Translate G3 ActionErrorCode → canonical TheoErrorCode (blueprint\n * Recommendations § \"G3 ActionError becomes inaugural envelope user\").\n */\n static toTheoErrorCode(code: ActionErrorCode): TheoErrorCode {\n if (code === 'VALIDATION_ERROR') return 'UNPROCESSABLE_ENTITY'\n if (code === 'CONTENT_TOO_LARGE') return 'PAYLOAD_TOO_LARGE'\n // The other ActionErrorCode members (BAD_REQUEST/UNAUTHORIZED/FORBIDDEN/\n // NOT_FOUND/METHOD_NOT_ALLOWED/CONFLICT/PAYLOAD_TOO_LARGE/\n // UNSUPPORTED_MEDIA_TYPE/TOO_MANY_REQUESTS/INTERNAL_SERVER_ERROR) are\n // identical strings in TheoErrorCode. Narrow via a type predicate\n // instead of assertion.\n return code\n }\n\n static codeToStatus(code: ActionErrorCode): number {\n return CODE_TO_STATUS[code]\n }\n\n static statusToCode(status: number): ActionErrorCode {\n return STATUS_TO_CODE[status] ?? 'INTERNAL_SERVER_ERROR'\n }\n\n /**\n * Parse a serialized error JSON back into the typed class hierarchy.\n * Distinguishes `TheoActionInputError` (with `issues` array) from\n * `TheoActionError` via the `type` discriminator. Falls back to\n * `INTERNAL_SERVER_ERROR` for malformed bodies (non-object, missing\n * `type`, unknown `code`).\n */\n static fromJson(body: unknown): ActionError {\n if (typeof body !== 'object' || body === null) {\n return new ActionError({ code: 'INTERNAL_SERVER_ERROR' })\n }\n const obj = body as Record<string, unknown>\n if (obj.type === 'TheoActionInputError' && Array.isArray(obj.issues)) {\n return new ActionInputError(obj.issues as unknown[])\n }\n if (\n obj.type === 'TheoActionError' &&\n typeof obj.code === 'string' &&\n obj.code in CODE_TO_STATUS\n ) {\n return new ActionError({\n code: obj.code as ActionErrorCode,\n message: typeof obj.message === 'string' ? obj.message : undefined,\n })\n }\n return new ActionError({ code: 'INTERNAL_SERVER_ERROR' })\n }\n}\n\n/**\n * `ActionInputError` — validation failure with field-level mapping.\n *\n * `fields` is auto-derived from `issues`: for each issue, key = full\n * dot-notation path (`'user.address.zip'`; root-level `path:[]` → `''`;\n * array indices as numeric segments → `'items.0.name'`). Multiple messages\n * for the same key accumulate; duplicate (path, message) tuples are deduped.\n */\nexport class ActionInputError extends ActionError {\n override readonly type = 'TheoActionInputError' as const\n readonly issues: readonly UniversalZodIssue[]\n readonly fields: Record<string, string[]>\n\n constructor(rawIssues: unknown) {\n super({ code: 'VALIDATION_ERROR', message: 'Validation failed' })\n this.issues = extractUniversalIssues(rawIssues)\n this.fields = buildFieldsMap(this.issues)\n }\n\n /**\n * G5 T2.4 — envelope view with ValidationFieldsExt populated from .fields.\n * UI consumers can `switch (env.code)` on `UNPROCESSABLE_ENTITY` and read\n * `(env.ext as ValidationFieldsExt).fields` for field-level rendering.\n */\n override get envelope(): TheoErrorEnvelope<ValidationFieldsExt> {\n return {\n code: 'UNPROCESSABLE_ENTITY',\n message: this.message,\n ext: { fields: this.fields },\n }\n }\n}\n\nfunction buildFieldsMap(issues: readonly UniversalZodIssue[]): Record<string, string[]> {\n const fields: Record<string, string[]> = {}\n const seen = new Set<string>()\n for (const issue of issues) {\n // EC-7: root path → empty string key. EC-8: numeric segments preserved as strings.\n const key = issue.path.length === 0 ? '' : issue.path.join('.')\n const dedupeKey = `${key}\u0000${issue.message}`\n if (seen.has(dedupeKey)) continue\n seen.add(dedupeKey)\n const bucket = fields[key] ?? []\n bucket.push(issue.message)\n fields[key] = bucket\n }\n return fields\n}\n\n/**\n * Normalize zod v3 (`z.ZodIssue`) and v4 (`$ZodIssue`) raw issues to\n * `UniversalZodIssue[]` (EC-1 absorbed). Duck-typed on `{path, message}` —\n * does NOT import zod types (`core/contracts/` depends on no intra-monorepo\n * + zod is consumer-controlled across the boundary).\n *\n * Silently skips entries missing required fields or shape mismatches; returns\n * empty array on non-array input.\n */\nexport function extractUniversalIssues(raw: unknown): UniversalZodIssue[] {\n if (!Array.isArray(raw)) return []\n const out: UniversalZodIssue[] = []\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null) continue\n const obj = entry as Record<string, unknown>\n if (!Array.isArray(obj.path)) continue\n if (typeof obj.message !== 'string') continue\n // Path entries must be string or number\n const path: (string | number)[] = []\n let pathValid = true\n for (const seg of obj.path) {\n if (typeof seg === 'string' || typeof seg === 'number') {\n path.push(seg)\n } else {\n pathValid = false\n break\n }\n }\n if (!pathValid) continue\n out.push({\n path,\n message: obj.message,\n code: typeof obj.code === 'string' ? obj.code : undefined,\n })\n }\n return out\n}\n\n/**\n * Type guard for `ActionError` (and its subclass `ActionInputError`). True\n * iff the value is an instance of `ActionError`. Use `isInputError` to\n * narrow specifically to validation failures.\n */\nexport function isActionError(value: unknown): value is ActionError {\n return value instanceof ActionError\n}\n\n/**\n * Type guard narrowing to `ActionInputError`. Requires `instanceof` check\n * (not duck-typing on `type`) to prevent attacker-controlled JSON from\n * being mistaken for a real error instance.\n */\nexport function isInputError(value: unknown): value is ActionInputError {\n return value instanceof ActionInputError\n}\n\n/**\n * `ActionResult<TData, TError>` — discriminated union returned by client-side\n * action invocation. Either `{data, error: undefined}` (success) or\n * `{data: undefined, error}` (failure). Mirrors Astro `SafeResult` shape.\n */\nexport type ActionResult<TData = unknown, TError extends ActionError = ActionError> =\n | { data: TData; error: undefined }\n | { data: undefined; error: TError }\n\n/**\n * `SerializedActionResult` — wire-shape emitted by `serializeActionResult`\n * in `server/http/serialize-action-result.ts` (T1.3). Discriminator `type`\n * distinguishes data (devalue-encoded), error (JSON), and empty (204) cases.\n */\nexport type SerializedActionResult =\n | {\n type: 'data'\n status: number\n contentType: 'application/json+devalue'\n body: string\n }\n | {\n type: 'error'\n status: number\n contentType: 'application/json'\n body: string\n }\n | { type: 'empty'; status: 204 }\n\n/**\n * `ActionManifestEntry` — per-action metadata emitted by `action-scan.ts`\n * (T1.4) into `.theokit/actions-manifest.json`. Consumed by virtual module\n * `@theo/actions` (T3.1) and G4 devtools \"Actions\" tab (T5.1).\n */\nexport interface ActionManifestEntry {\n readonly name: string\n readonly filePath: string\n readonly urlPath: string\n readonly accept: 'form' | 'json'\n readonly hasInput: boolean\n}\n","import type { ServerResponse } from 'node:http'\n\nimport type { TheoTransformer } from '../transformer.js'\n\n/**\n * Canonical HTTP response helpers (T5.1 extraction).\n *\n * Moved out of execute.ts so request-pipeline stages (execute-stages.ts,\n * handle-request-error.ts, etc.) can depend on these helpers without\n * creating a cycle through execute.ts.\n *\n * Public surface re-exported from execute.ts for backward compat — every\n * existing caller of `sendError` / `sendJson` continues to work via the\n * `theokit/server` barrel.\n */\n\nexport function sendJson(\n res: ServerResponse,\n data: unknown,\n status = 200,\n transformer?: TheoTransformer,\n): void {\n // T1.2 — transformer-aware serialization. Default (no transformer) uses\n // JSON.stringify direct for backward compat.\n const body = transformer ? transformer.serialize(data) : JSON.stringify(data)\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n}\n\nexport interface SendErrorOptions {\n custom404Html?: string\n custom500Html?: string\n}\n\n/**\n * Canonical error response.\n *\n * T6.3 (PV-17): the positional 7-param signature is preserved for backward\n * compat. New call sites should use the options-bag form:\n *\n * sendError(res, { code, message, status, issues?, requestId?, options? })\n *\n * Both shapes resolve to the same implementation.\n */\nexport interface SendErrorInput {\n code: string\n message: string\n status: number\n issues?: unknown[]\n requestId?: string\n options?: SendErrorOptions\n}\n\nexport function sendError(res: ServerResponse, input: SendErrorInput): void\n/* eslint-disable-next-line max-params -- T6.3: positional overload preserved\n for backward compat (callers across cli/server still use positional). The\n options-bag overload above is the recommended path. */\nexport function sendError(\n res: ServerResponse,\n code: string,\n message: string,\n status: number,\n issues?: unknown[],\n requestId?: string,\n options?: SendErrorOptions,\n): void\n/* eslint-disable-next-line max-params, complexity -- delegates to two\n surface overloads above; the branch density mirrors the back-compat\n contract, not internal complexity. */\nexport function sendError(\n res: ServerResponse,\n codeOrInput: string | SendErrorInput,\n message?: string,\n status?: number,\n issues?: unknown[],\n requestId?: string,\n options?: SendErrorOptions,\n): void {\n let code: string\n if (typeof codeOrInput === 'string') {\n code = codeOrInput\n message = message ?? ''\n status = status ?? 500\n } else {\n code = codeOrInput.code\n message = codeOrInput.message\n status = codeOrInput.status\n issues = codeOrInput.issues\n requestId = codeOrInput.requestId\n options = codeOrInput.options\n }\n const errorMessage =\n code === 'INTERNAL_ERROR' && process.env.NODE_ENV === 'production'\n ? 'Internal server error'\n : message\n\n if (code === 'INTERNAL_ERROR') {\n console.error(`[${requestId ?? 'no-id'}] ${message}`)\n }\n\n if (status === 404 && options?.custom404Html) {\n const body = options.custom404Html\n res.writeHead(404, {\n 'Content-Type': 'text/html; charset=utf-8',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n return\n }\n if (status === 500 && options?.custom500Html) {\n const body = options.custom500Html\n res.writeHead(500, {\n 'Content-Type': 'text/html; charset=utf-8',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n return\n }\n\n sendJson(\n res,\n {\n error: {\n code,\n message: errorMessage,\n ...(requestId ? { requestId } : {}),\n ...(issues ? { issues } : {}),\n },\n },\n status,\n )\n}\n\n/**\n * T5a.2 Phase G slice 4/N — Web-Standards response helpers.\n *\n * Mirror of `sendJson` + `sendError` for the Web `Request`/`Response`\n * shape. Returns a native `Response` directly instead of mutating a\n * `ServerResponse`.\n *\n * Per `docs/plans/t5a2-incoming-message-to-request-shape-refactor-plan.md`\n * v1.0 § Phase G.\n *\n * **Difference vs IncomingMessage path:**\n * - No `Content-Length` set explicitly — the runtime computes it from\n * the body when needed. CF Workers / Bun / Deno all do this; setting\n * it manually risks conflict if the body is a stream rather than a\n * fixed string.\n * - Custom 404/500 HTML options preserved (same opts shape).\n * - `requestId` flows into the response body's error envelope AND\n * surfaces as `x-request-id` header (parity with handleWebRequestError\n * Phase G slice 3/N).\n */\nexport function buildJsonResponse(\n data: unknown,\n status = 200,\n transformer?: TheoTransformer,\n): Response {\n const body = transformer ? transformer.serialize(data) : JSON.stringify(data)\n return new Response(body, {\n status,\n headers: { 'content-type': 'application/json' },\n })\n}\n\nexport function buildErrorResponse(input: SendErrorInput): Response {\n const { code, message, status, issues, requestId, options } = input\n const errorMessage =\n code === 'INTERNAL_ERROR' && process.env.NODE_ENV === 'production'\n ? 'Internal server error'\n : message\n\n if (code === 'INTERNAL_ERROR') {\n console.error(`[${requestId ?? 'no-id'}] ${message}`)\n }\n\n const headers: Record<string, string> = {}\n if (requestId !== undefined) headers['x-request-id'] = requestId\n\n if (status === 404 && options?.custom404Html !== undefined) {\n headers['content-type'] = 'text/html; charset=utf-8'\n return new Response(options.custom404Html, { status: 404, headers })\n }\n if (status === 500 && options?.custom500Html !== undefined) {\n headers['content-type'] = 'text/html; charset=utf-8'\n return new Response(options.custom500Html, { status: 500, headers })\n }\n\n headers['content-type'] = 'application/json'\n const body = JSON.stringify({\n error: {\n code,\n message: errorMessage,\n ...(requestId ? { requestId } : {}),\n ...(issues ? { issues } : {}),\n },\n })\n return new Response(body, { status, headers })\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Middleware runner. Checks for `serverDir/middleware.ts` + `context.ts`,\n * cached by CR-017. Paths are derived from `serverDir` (cwd-derived). No\n * HTTP input.\n */\nimport { existsSync } from 'node:fs'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport { join } from 'node:path'\n\nimport { scanMiddlewares } from '../scan/middleware-scan.js'\nimport type { LoadModule } from '../scan/module-loader.js'\n\nexport interface MiddlewareResult {\n ctx: unknown\n aborted: boolean\n}\n\n// CR-017 fix: in dev `existsSync` + `scanMiddlewares` ran on EVERY request,\n// turning a constant filesystem read into per-request overhead. We cache\n// the scan result by serverDir. In prod the same scan should be done once\n// at boot — `theo build` already emits a manifest, but the dev path uses\n// this runtime cache as a defense-in-depth. The cache is invalidated by\n// process restart (Vite HMR replaces the module, clearing this map).\ninterface MiddlewareCacheEntry {\n singleFilePath: string\n singleFileExists: boolean\n dirMiddlewares: string[]\n}\nconst middlewareCache = new Map<string, MiddlewareCacheEntry>()\n\nexport function _resetMiddlewareCacheForTests(): void {\n middlewareCache.clear()\n}\n\n// Middleware default-export contract: a function (req, res, next).\ntype MiddlewareFn = (\n req: IncomingMessage,\n res: ServerResponse,\n next: () => void,\n) => void | Promise<void>\ntype ContextFactory = (args: { request: IncomingMessage; response: ServerResponse }) => unknown // Promise<unknown> is structurally `unknown`; one arm covers both.\n\nfunction getCachedScan(serverDir: string): MiddlewareCacheEntry {\n let cached = middlewareCache.get(serverDir)\n if (!cached) {\n const singleFilePath = join(serverDir, 'middleware.ts')\n cached = {\n singleFilePath,\n singleFileExists: existsSync(singleFilePath),\n dirMiddlewares: scanMiddlewares(serverDir),\n }\n middlewareCache.set(serverDir, cached)\n }\n return cached\n}\n\nasync function runOneMiddleware(\n mw: MiddlewareFn,\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<{ nextCalled: boolean }> {\n // Object-held flag avoids TS narrowing `let nextCalled = false` to the\n // literal `false`, which would make `!nextCalled` an \"always-truthy\"\n // condition under control-flow analysis.\n const state = { nextCalled: false }\n await mw(req, res, () => {\n state.nextCalled = true\n })\n return state\n}\n\nexport async function runMiddlewareAndContext(\n req: IncomingMessage,\n res: ServerResponse,\n loadModule: LoadModule,\n serverDir: string,\n): Promise<MiddlewareResult> {\n const { singleFilePath, singleFileExists, dirMiddlewares } = getCachedScan(serverDir)\n const dirExists = dirMiddlewares.length > 0\n\n // 1. Ambiguity check — both file and directory is a configuration error\n if (singleFileExists && dirExists) {\n throw new Error(\n 'Ambiguous middleware configuration: found both server/middleware.ts and server/middleware/ directory. ' +\n 'Use one or the other, not both.',\n )\n }\n\n // 2. Run middleware chain from directory\n if (dirExists) {\n for (const mwPath of dirMiddlewares) {\n const mod = await loadModule(mwPath)\n const mw = mod.default as MiddlewareFn | undefined\n if (typeof mw !== 'function') continue\n\n const { nextCalled } = await runOneMiddleware(mw, req, res)\n if (!nextCalled || res.writableEnded) {\n return { ctx: {}, aborted: true }\n }\n }\n }\n\n // 3. Run single middleware file (backward compat)\n if (singleFileExists) {\n const mod = await loadModule(singleFilePath)\n const mw = mod.default as MiddlewareFn | undefined\n if (typeof mw === 'function') {\n const { nextCalled } = await runOneMiddleware(mw, req, res)\n if (!nextCalled || res.writableEnded) {\n return { ctx: {}, aborted: true }\n }\n }\n }\n\n // 4. Create context (if exists)\n let ctx: unknown = {}\n const contextPath = join(serverDir, 'context.ts')\n if (existsSync(contextPath)) {\n const mod = await loadModule(contextPath)\n const createContext = mod.createContext as ContextFactory | undefined\n if (typeof createContext === 'function') {\n ctx = await createContext({ request: req, response: res })\n }\n }\n\n return { ctx, aborted: false }\n}\n","/**\n * Pure Node `IncomingMessage` → Web `Request` converters.\n *\n * Kept free of any dependency on `web-handler.js` / `execute*.js` so the\n * executor (`execute.ts`) can build the handler-facing Web `Request` without\n * pulling the Web dispatch pipeline into its import graph (ADR-0028 R3a — the\n * Node adapter is the ONLY place IncomingMessage ↔ Request conversion lives;\n * these are the primitive converters it and the executor share).\n */\nimport type { IncomingMessage } from 'node:http'\nimport { Readable } from 'node:stream'\n\n/** Pick the first usable string from Node's `string | string[] | undefined` headers. */\nfunction pickHeaderString(value: string | string[] | undefined): string | undefined {\n if (typeof value === 'string') return value\n if (Array.isArray(value)) {\n for (const v of value) if (typeof v === 'string' && v.length > 0) return v\n }\n return undefined\n}\n\n/** Web Request requires an absolute URL; synthesize one from the Host header. */\nfunction synthesizeAbsoluteUrl(req: IncomingMessage): string {\n const host = pickHeaderString(req.headers.host) ?? 'localhost'\n return `http://${host}${req.url ?? '/'}`\n}\n\n/**\n * Collapse Node's `string | string[]` headers into a Web `Headers`. Repeated\n * headers are comma-joined (not `.append`ed) because `Headers.append` creates\n * multi-value entries that behave differently on `.get()` (EC-1).\n */\nfunction nodeHeadersToWeb(req: IncomingMessage): Headers {\n const headers = new Headers()\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue\n if (Array.isArray(value)) {\n headers.set(key, value.join(', '))\n } else {\n headers.set(key, value)\n }\n }\n return headers\n}\n\n/**\n * Build a Web `Request` from a Node `IncomingMessage`, body included. The Web\n * Request spec requires an absolute URL; we synthesize one from the Host header\n * (fallback `localhost` for test doubles).\n *\n * For methods with a body (POST/PUT/PATCH/DELETE), the Node Readable stream is\n * wrapped as a Web ReadableStream via `Readable.toWeb()` so downstream consumers\n * can call `request.json()` / `request.formData()` / `request.text()` natively.\n */\nexport function incomingMessageToWebRequest(req: IncomingMessage): Request {\n const url = synthesizeAbsoluteUrl(req)\n const headers = nodeHeadersToWeb(req)\n\n const method = (req.method ?? 'GET').toUpperCase()\n const hasBody = method !== 'GET' && method !== 'HEAD'\n\n if (!hasBody) {\n return new Request(url, { method, headers })\n }\n\n // Drain Node's Readable into a Web ReadableStream. `Readable.toWeb` is\n // available in Node 18+ (theokit's engines.node floor is 22+, so safe).\n const webStream = Readable.toWeb(req) as ReadableStream\n return new Request(url, {\n method,\n headers,\n body: webStream,\n // EC-2: Node 18+ requires `duplex: 'half'` when body is a stream.\n // The `RequestInit` type omits it (Web spec gap); cast accordingly.\n ...({ duplex: 'half' } as { duplex: 'half' }),\n })\n}\n\n/**\n * Build the Web `Request` handed to a route handler as `ctx.request` in the\n * Node server path (dev + `theokit start`). Method + absolute URL + headers\n * only — NO body.\n *\n * Why no body: the Node executor parses the request body BEFORE the handler\n * runs and exposes the parsed value as `ctx.body` (the typed, documented body\n * API). By the time the handler is called the Node stream is already drained,\n * so re-wrapping it would yield an empty/closed stream. Handlers read the body\n * via `ctx.body`; `ctx.request` is for the Web-standard header/cookie/URL/method\n * surface (e.g. `createSessionManagerWeb.getSession(ctx.request)`).\n *\n * Per ADR-0028 R3a, handlers see a Web `Request` in every runtime — this closes\n * the gap where the Node path leaked the raw `IncomingMessage` (whose `.headers`\n * is a plain object, so `.headers.get(...)` threw for Web-standard consumers).\n */\nexport function incomingMessageToHandlerRequest(req: IncomingMessage): Request {\n return new Request(synthesizeAbsoluteUrl(req), {\n method: (req.method ?? 'GET').toUpperCase(),\n headers: nodeHeadersToWeb(req),\n })\n}\n","/**\n * Shape-based guard for AuthRequiredError detection.\n *\n * Uses duck-type check ONLY — no class import from `server/auth/` to\n * preserve `core` INVARIANT 1 (core depends on nothing intra-monorepo).\n *\n * The `instanceof AuthRequiredError` check is intentionally omitted:\n * Vite HMR can duplicate class identity across module boundaries,\n * making `instanceof` unreliable. The shape check (`code` + `status`)\n * is the canonical detection path.\n *\n * Single source of truth — previously duplicated in handle-request-error.ts\n * and execute.ts (architecture-remediation plan T1.3, 2026-06-12).\n */\nexport function isAuthRequiredError(err: unknown): boolean {\n if (err == null || typeof err !== 'object') return false\n const e = err as Record<string, unknown>\n return e.code === 'AUTH_REQUIRED' && e.status === 401\n}\n","/**\n * Canonical CSRF warn dispatcher (T3.3 of architecture-review-remediation-plan).\n *\n * Consolidates the duplicated `warn: (payload) => { warnOnce(...) }` closure\n * that previously appeared in both `http/execute.ts` and\n * `http/action-execute.ts`. Resolves PV-10 (DRY).\n *\n * `warnOnce` dedupes by `event:method:path` so a request loop with 1000 POSTs\n * doesn't flood logs with identical warnings. Apps grep for `event\":\"csrf.warn\"`\n * (stable event shape — see [[enforcement-cutover.md]]).\n */\nimport { warnOnce } from '../observability/logger.js'\n\ninterface CsrfWarnPayload {\n event: string\n method: string\n path?: string\n reason: string\n code?: string\n docsUrl?: string\n warnOnce?: boolean\n}\n\n/**\n * Build the warn callback that `enforceCsrf` invokes for soft-mode warnings.\n * Returned function is suitable for the `warn` field of `enforceCsrf`'s options.\n */\nexport function dispatchCsrfWarn(payload: CsrfWarnPayload): void {\n const key = `${payload.event}:${payload.method}:${payload.path ?? ''}`\n warnOnce(key, payload as unknown as Record<string, unknown>)\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport { parseRequestBody } from '../body-parser.js'\n\nimport { sendError } from './send-response.js'\n\n/**\n * T5.1 (partial Pipeline extraction) — request-parsing + Zod-validation\n * stages extracted from the executeRoute monolith.\n *\n * Each stage returns `{ ok: true, ...data }` on success OR `{ ok: false }`\n * on short-circuit (in which case the stage already sent an error response).\n *\n * Per EC-5 (plugin hook ordering) and EC-15 (AsyncLocalStorage), these\n * stages do NOT invoke plugin hooks — the orchestrator (`executeRoute`)\n * keeps that responsibility in one place.\n */\n\ntype StageResult<T> = { ok: true; data: T } | { ok: false }\n\n/**\n * Parse URL query + request body (multipart/form-data or JSON).\n * On parse failure, sends 400 or 415 (Unsupported Content-Type) + returns\n * `{ ok: false }`. Otherwise returns `{ query, body }`.\n */\nexport async function parseQueryAndBody(\n req: IncomingMessage,\n res: ServerResponse,\n requestId: string | undefined,\n): Promise<StageResult<{ query: Record<string, string>; body: unknown }>> {\n // Query\n const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`)\n const query: Record<string, string> = Object.fromEntries(url.searchParams)\n\n // Body (JSON + multipart/form-data)\n let body: unknown\n try {\n const parsed = await parseRequestBody(req)\n if (parsed.json !== undefined) {\n body = parsed.json\n } else if (parsed.files.length > 0 || Object.keys(parsed.fields).length > 0) {\n body = { ...parsed.fields, _files: parsed.files }\n } else {\n body = undefined\n }\n } catch (err) {\n const message = (err as Error).message\n const status = message.includes('Unsupported Content-Type') ? 415 : 400\n sendError(res, 'VALIDATION_ERROR', message, status, undefined, requestId)\n return { ok: false }\n }\n\n return { ok: true, data: { query, body } }\n}\n\n/**\n * Validate query, body, params against the route's Zod schemas (when present).\n * On validation failure, sends 400 with Zod issues + returns `{ ok: false }`.\n * On success, returns the (possibly-transformed) values from `schema.safeParse(...).data`.\n */\ninterface ZodLike {\n safeParse: (value: unknown) => {\n success: boolean\n data?: unknown\n error?: { issues: unknown[] }\n }\n}\nexport const isZodLike = (value: unknown): value is ZodLike =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { safeParse?: unknown }).safeParse === 'function'\n\nexport function runZodValidation(\n routeConfig: Record<string, unknown>,\n res: ServerResponse,\n requestId: string | undefined,\n input: {\n query: Record<string, string>\n body: unknown\n params: Record<string, string>\n },\n): StageResult<{ query: Record<string, string>; body: unknown; params: Record<string, string> }> {\n const { query, params } = input\n let { body } = input\n\n if (isZodLike(routeConfig.query)) {\n const result = routeConfig.query.safeParse(query)\n if (!result.success) {\n sendError(\n res,\n 'VALIDATION_ERROR',\n 'Invalid query parameters',\n 400,\n result.error?.issues,\n requestId,\n )\n return { ok: false }\n }\n Object.assign(query, result.data)\n }\n\n if (isZodLike(routeConfig.body)) {\n const result = routeConfig.body.safeParse(body)\n if (!result.success) {\n sendError(\n res,\n 'VALIDATION_ERROR',\n 'Invalid request body',\n 400,\n result.error?.issues,\n requestId,\n )\n return { ok: false }\n }\n body = result.data\n }\n\n if (isZodLike(routeConfig.params)) {\n const result = routeConfig.params.safeParse(params)\n if (!result.success) {\n sendError(\n res,\n 'VALIDATION_ERROR',\n 'Invalid route parameters',\n 400,\n result.error?.issues,\n requestId,\n )\n return { ok: false }\n }\n Object.assign(params, result.data)\n }\n\n return { ok: true, data: { query, body, params } }\n}\n","import type { ServerResponse } from 'node:http'\n\nimport { isAuthRequiredError } from '../../core/contracts/auth-error-guard.js'\nimport { TheoError } from '../../core/contracts/theo-error.js'\nimport { DuplicateContextKeyError } from '../jobs/duplicate-context-key-error.js'\nimport { createOutbox } from '../jobs/outbox.js'\nimport { createOutboxDispatcher, createQueueClient } from '../jobs/queue-client.js'\nimport { warnOnce } from '../observability/logger.js'\nimport type { PluginContext } from '../plugin-types.js'\nimport type { PluginRunner } from '../plugins/plugin-runner.js'\nimport { dispatchCsrfWarn } from '../security/csrf-warn-dispatch.js'\nimport { enforceCsrf } from '../security/csrf.js'\n\nimport type { ExecuteRouteContext } from './execute-context.js'\nimport { isZodLike, parseQueryAndBody, runZodValidation } from './execute-stages.js'\nimport { runMiddlewareAndContext } from './middleware-runner.js'\nimport { incomingMessageToHandlerRequest } from './node-request.js'\nimport { sendError, sendJson } from './send-response.js'\n\n// CSRF policy applies to every state-mutating method, including DELETE.\nconst CSRF_PROTECTED_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])\n\n// T5.1: sendJson + sendError + SendErrorOptions moved to send-response.ts\n// to break the execute ↔ execute-stages cycle. Re-exported below for\n// backward compat.\nexport { sendJson, sendError } from './send-response.js'\nexport type { SendErrorOptions, SendErrorInput } from './send-response.js'\n// T3.1 — ExecuteRouteContext (ADR-0016)\nexport type { ExecuteRouteContext } from './execute-context.js'\n\ninterface StreamPipeCtx {\n buildPluginCtx: (ctxObj: Record<string, unknown>) => PluginContext\n ctx: Record<string, unknown>\n method: string\n pluginRunner: PluginRunner | undefined\n requestId: string | undefined\n routePath: string\n}\n\n/**\n * Pipe a Web Standard ReadableStream into a Node ServerResponse. Stream\n * errors after headers are sent cannot change the response status, but\n * MUST be logged + reported (CR-004 fix). Extracted from `executeRoute`\n * to keep that function's nesting under the max-depth ceiling.\n */\nasync function pipeWebStreamToResponse(\n body: ReadableStream<Uint8Array>,\n res: ServerResponse,\n ctx: StreamPipeCtx,\n): Promise<void> {\n const reader = body.getReader()\n try {\n let done = false\n while (!done) {\n const chunk = await reader.read()\n done = chunk.done\n if (!done) res.write(chunk.value)\n }\n } catch (streamErr) {\n warnOnce(`stream-error:${ctx.routePath}:${ctx.method}`, {\n event: 'stream.error',\n requestId: ctx.requestId ?? 'no-id',\n route: ctx.routePath,\n method: ctx.method,\n message: streamErr instanceof Error ? streamErr.message : String(streamErr),\n })\n if (ctx.pluginRunner) {\n try {\n await ctx.pluginRunner.runOnError(ctx.buildPluginCtx(ctx.ctx), streamErr)\n } catch {\n // onError plugins must never destabilize the response close.\n }\n }\n } finally {\n try {\n reader.releaseLock()\n } catch {\n /* lock may already be released by abort */\n }\n }\n}\n\n// sendError moved to send-response.ts (T5.1) — re-exported above.\n\n// CR-007/Knip cleanup: `parseBody` (legacy JSON-only parser) was exported\n// but had no remaining consumers — the route pipeline uses\n// `parseRequestBody` (multipart + JSON) directly. Removed to shrink the\n// public surface and remove the duplicated METHODS_WITH_BODY constant.\n\n// eslint-disable-next-line max-lines-per-function, sonarjs/cognitive-complexity, complexity -- `executeRoute` is the framework's central request pipeline; its body length + branch density mirror the actual request lifecycle. T3.1 / ADR-0016 retired `max-params` (context object replaces 12 positional args). Branch complexity remains intentional: the request lifecycle has irreducible state machine arms (CSRF stage → Zod validate → middleware → handler → stream/JSON response). Remaining helpers `runCsrfStage`, `parseQueryAndBody`, `runHandlerStage`, etc. were extracted in earlier waves.\nexport async function executeRoute(ctx: ExecuteRouteContext): Promise<void> {\n // T3.1 — destructure the context with defaults applied\n const {\n route,\n method,\n params,\n req,\n res,\n loadModule,\n serverDir,\n requestId,\n pluginRunner,\n transformer,\n csrfMode = 'strict',\n disallowed,\n jobBackend,\n } = ctx\n // ADR-0028 R3a / #117 / #119 — handlers AND plugin hooks see a Web `Request` in every runtime. Built\n // once from the Node `IncomingMessage` (headers/URL/method; body stays on the parsed `ctx.body`) and\n // shared by every buildPluginCtx call + the handler invocation below.\n const webRequest = incomingMessageToHandlerRequest(req)\n const buildPluginCtx = (ctxObj: Record<string, unknown>): PluginContext => ({\n request: webRequest,\n response: res,\n ctx: ctxObj,\n requestId: requestId ?? 'no-id',\n })\n\n // T1.2 — emit x-theo-transformer header when a non-default transformer is in use.\n // 'json' is treated as default (no header); any named transformer emits.\n if (transformer && transformer.name !== 'json') {\n res.setHeader('x-theo-transformer', transformer.name)\n }\n\n try {\n // T4.2 — onRequest hook (runs before middleware)\n let ctx: Record<string, unknown> = {}\n if (pluginRunner) {\n pluginRunner.applyDecorations(ctx)\n const onReqResult = await pluginRunner.runOnRequest(buildPluginCtx(ctx))\n if (onReqResult.shortCircuited) return\n }\n\n // Run middleware + context pipeline\n if (serverDir) {\n const result = await runMiddlewareAndContext(req, res, loadModule, serverDir)\n if (result.aborted) return\n ctx = (result.ctx ?? {}) as Record<string, unknown>\n // Re-apply decorations on top of middleware-produced ctx so plugin\n // decorations win when middleware did not set the same key.\n if (pluginRunner) pluginRunner.applyDecorations(ctx)\n }\n\n // T2.1 — wire ctx.queue + outbox lifecycle when jobBackend is configured.\n // EC-202: throw on collision instead of silent override.\n if (jobBackend) {\n if (ctx.queue !== undefined) {\n throw new DuplicateContextKeyError('queue', {\n reason:\n 'A plugin or middleware already decorated ctx.queue; choose a different key OR remove jobs.backend from theo.config.ts.',\n })\n }\n const outbox = createOutbox()\n const queueClient = createQueueClient(jobBackend, outbox)\n ctx.queue = queueClient\n\n // Discard on abort or 4xx (handler throws cascade to 500 via catch\n // below, where statusCode is already >= 400).\n res.on('close', () => {\n if (!res.writableFinished) outbox.discard()\n })\n // Flush on commit, only when response indicates success.\n res.on('finish', () => {\n if (res.statusCode >= 400) {\n outbox.discard()\n return\n }\n void outbox.flush(createOutboxDispatcher(jobBackend))\n })\n }\n\n const mod = await loadModule(route.filePath)\n const routeConfig = mod[method]\n\n if (!routeConfig) {\n sendError(\n res,\n 'METHOD_NOT_ALLOWED',\n `Method ${method} not allowed`,\n 405,\n undefined,\n requestId,\n )\n return\n }\n\n const handler =\n typeof routeConfig === 'function'\n ? routeConfig\n : (routeConfig as Record<string, unknown>).handler\n if (typeof handler !== 'function') {\n sendError(res, 'INTERNAL_ERROR', 'Route handler is not a function', 500, undefined, requestId)\n return\n }\n\n // Phase 5 — CSRF enforcement (warn-first default; strict in 0.3.0).\n // Skips: safe methods (GET/HEAD/OPTIONS), per-route opt-out (`csrf: false`),\n // and bare function exports (legacy style — no opt-out hook available).\n const routeOptOut =\n typeof routeConfig === 'object' && (routeConfig as { csrf?: unknown }).csrf === false\n if (CSRF_PROTECTED_METHODS.has(method) && !routeOptOut) {\n const decision = enforceCsrf(\n req,\n csrfMode,\n {\n // T3.3 DRY — see security/csrf-warn-dispatch.ts\n warn: dispatchCsrfWarn,\n path: req.url,\n },\n disallowed,\n )\n if (!decision.allow) {\n sendError(\n res,\n 'CSRF_INVALID',\n decision.reason ?? 'CSRF check failed',\n 403,\n undefined,\n requestId,\n )\n return\n }\n }\n\n // T5.1 — extracted stages (parseQueryAndBody + runZodValidation).\n // Each stage either succeeds (returns parsed data) OR short-circuits\n // (sends the error response inline + returns ok:false).\n const rc = routeConfig as Record<string, unknown>\n\n const parseResult = await parseQueryAndBody(req, res, requestId)\n if (!parseResult.ok) return\n const { query } = parseResult.data\n let { body } = parseResult.data\n\n const validationResult = runZodValidation(rc, res, requestId, { query, body, params })\n if (!validationResult.ok) return\n body = validationResult.data.body\n\n // T4.3 — preHandler hook (after Zod validation, before handler)\n if (pluginRunner) {\n const preResult = await pluginRunner.runPreHandler(buildPluginCtx(ctx))\n if (preResult.shortCircuited) return\n }\n\n // Execute handler. `handler` is structurally typed as `unknown` at\n // this point (came out of a duck-typed module). Cast through a narrow\n // type so the call is properly typed.\n type RouteHandlerCallable = (args: {\n query: Record<string, string>\n body: unknown\n params: Record<string, string>\n request: Request\n ctx: Record<string, unknown>\n }) => unknown\n const callableHandler = handler as RouteHandlerCallable\n // ADR-0028 R3a — handlers receive a Web `Request` in EVERY runtime (built once above, shared with\n // the plugin hooks). The Node path previously leaked the raw `IncomingMessage` here, so any\n // Web-standard use of `ctx.request` (e.g. `ctx.request.headers.get(...)`,\n // `createSessionManagerWeb.getSession(ctx.request)`) threw at runtime even though it type-checked\n // (`ctx.request` is declared `Request`). Body is exposed via `ctx.body`, so the request carries\n // headers/url/method only (the Node stream is already drained by `parseQueryAndBody`).\n const handlerResult = await callableHandler({ query, body, params, request: webRequest, ctx })\n\n // Handle result\n if (handlerResult === undefined || handlerResult === null) {\n sendJson(res, null, (rc.status as number | undefined) ?? 204, transformer)\n if (pluginRunner) await pluginRunner.runOnResponse(buildPluginCtx(ctx))\n return\n }\n\n if (handlerResult instanceof Response) {\n // `Object.fromEntries(Headers)` collapses multi-valued headers like\n // `Set-Cookie` to a single string. Set Set-Cookie via setHeader array\n // overload BEFORE writeHead (writeHead flushes headers; later setHeader\n // is a no-op or throws). Then writeHead with the remaining singletons.\n const headersBag: Record<string, string> = {}\n for (const [k, v] of handlerResult.headers) {\n if (k.toLowerCase() !== 'set-cookie') headersBag[k] = v\n }\n const setCookies = handlerResult.headers.getSetCookie()\n if (setCookies.length > 0) {\n res.setHeader('Set-Cookie', setCookies)\n }\n res.writeHead(handlerResult.status, headersBag)\n\n if (handlerResult.body) {\n await pipeWebStreamToResponse(handlerResult.body, res, {\n buildPluginCtx,\n ctx,\n method,\n pluginRunner,\n requestId,\n routePath: route.routePath,\n })\n }\n\n res.end()\n if (pluginRunner) await pluginRunner.runOnResponse(buildPluginCtx(ctx))\n return\n }\n\n // Validate the plain-object return against config.response when declared\n // (D1/D2). A mismatch is a SERVER fault → throw TheoError, routed to a 500\n // by the catch below. Response-instance + 204 branches above are untouched.\n let responseBody: unknown = handlerResult\n if (isZodLike(rc.response)) {\n const parsed = rc.response.safeParse(handlerResult)\n if (!parsed.success) {\n throw new TheoError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'response validation failed',\n ext: { issues: parsed.error?.issues },\n })\n }\n responseBody = parsed.data\n }\n sendJson(res, responseBody, (rc.status as number | undefined) ?? 200, transformer)\n if (pluginRunner) await pluginRunner.runOnResponse(buildPluginCtx(ctx))\n } catch (err) {\n // T4.4 — onError hook (runs before default error response)\n if (pluginRunner) {\n // Best-effort: capture a ctx snapshot for plugins. Decorations were\n // applied to local `ctx` above, but if the error came before that, we\n // pass an empty ctx — the request/response are what matters here.\n const errCtxObj: Record<string, unknown> = {}\n pluginRunner.applyDecorations(errCtxObj)\n await pluginRunner.runOnError(buildPluginCtx(errCtxObj), err)\n // EC-9: response may already have been ended by an onError hook\n if (res.writableEnded) {\n // Still run onResponse but mark inErrorPath to prevent recursion\n await pluginRunner.runOnResponse(buildPluginCtx(errCtxObj), { inErrorPath: true })\n return\n }\n }\n // Auth error detection (shape-based guard from core/contracts — Vite HMR\n // can break instanceof, so shape check is the canonical path).\n if (isAuthRequiredError(err)) {\n const authErr = err as { code: string; message: string; status: number }\n sendError(res, authErr.code, authErr.message, authErr.status, undefined, requestId)\n if (pluginRunner) {\n const errCtxObj: Record<string, unknown> = {}\n pluginRunner.applyDecorations(errCtxObj)\n await pluginRunner.runOnResponse(buildPluginCtx(errCtxObj), { inErrorPath: true })\n }\n return\n }\n sendError(\n res,\n 'INTERNAL_ERROR',\n err instanceof Error && err.message ? err.message : 'Internal server error',\n 500,\n undefined,\n requestId,\n )\n if (pluginRunner) {\n const errCtxObj: Record<string, unknown> = {}\n pluginRunner.applyDecorations(errCtxObj)\n await pluginRunner.runOnResponse(buildPluginCtx(errCtxObj), { inErrorPath: true })\n }\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport { isAuthRequiredError } from '../../core/contracts/auth-error-guard.js'\nimport { envelopeCodeToStatus } from '../../core/contracts/envelope-code-to-status.js'\nimport { serverErrorToEnvelope } from '../../core/contracts/server-error-to-envelope.js'\nimport type { PluginContext } from '../plugin-types.js'\nimport type { PluginRunner } from '../plugins/plugin-runner.js'\n\nimport { sendError } from './send-response.js'\n\n/**\n * Canonical error handler for HTTP request pipelines (T3.4 of\n * architecture-review-remediation-plan, PV-9 DRY).\n *\n * Replaces the duplicated catch-block logic in `executeRoute` (1 site) and\n * `executeAction` (1 site, via `handleActionError`). Both code paths now\n * share this implementation.\n *\n * Behavior contract (preserved from previous inline catches):\n * - Plugin `onError` fires first (swallowed if it throws — never amplify failure).\n * - `AuthRequiredError` is detected via `instanceof` AND a duck-type shape\n * check (`code === 'AUTH_REQUIRED' && status === 401`) — required because\n * under Vite dev / vitest the module-loader can produce a duplicate\n * AuthRequiredError class identity, breaking `instanceof`.\n * - `onResponse({ inErrorPath: true })` always fires at the end (swallowed\n * if it throws — EC-9).\n */\ninterface HandleRequestErrorCtx {\n req: IncomingMessage\n res: ServerResponse\n requestId: string | undefined\n pluginRunner: PluginRunner | undefined\n buildPluginCtx: (ctxObj: Record<string, unknown>) => PluginContext\n}\n\nexport async function handleRequestError(err: unknown, c: HandleRequestErrorCtx): Promise<void> {\n // 1. onError hook — swallowed on failure (EC-9 — never amplify)\n if (c.pluginRunner) {\n const errCtxObj: Record<string, unknown> = {}\n c.pluginRunner.applyDecorations(errCtxObj)\n try {\n await c.pluginRunner.runOnError(c.buildPluginCtx(errCtxObj), err)\n } catch {\n // onError handlers must never destabilize the response.\n }\n // EC-9: response may already have been ended by an onError hook\n if (c.res.writableEnded) {\n try {\n await c.pluginRunner.runOnResponse(c.buildPluginCtx(errCtxObj), {\n inErrorPath: true,\n })\n } catch {\n // Containment (same as above).\n }\n return\n }\n }\n\n // 2. Auth error detection (shape-based guard from core/contracts)\n if (isAuthRequiredError(err)) {\n const authErr = err as { code: string; message: string; status: number }\n sendError(c.res, authErr.code, authErr.message, authErr.status, undefined, c.requestId)\n } else {\n // M7-1: a thrown TheoError (incl. NotFoundError) carries a typed code that\n // maps to a real status — emit it. An untyped/unknown error has no typed\n // code (serverErrorToEnvelope falls back to INTERNAL_SERVER_ERROR), so we\n // preserve the legacy INTERNAL_ERROR path, which `sendError` special-cases\n // for production message masking + structured logging. This keeps generic\n // 500s backward-compatible while giving typed errors their proper envelope.\n const envelope = serverErrorToEnvelope(err)\n if (envelope.code === 'INTERNAL_SERVER_ERROR') {\n sendError(\n c.res,\n 'INTERNAL_ERROR',\n err instanceof Error ? err.message : 'Internal server error',\n 500,\n undefined,\n c.requestId,\n )\n } else {\n sendError(\n c.res,\n envelope.code,\n envelope.message,\n envelopeCodeToStatus(envelope.code),\n undefined,\n c.requestId,\n )\n }\n }\n\n // 3. onResponse(inErrorPath) — swallowed on failure (EC-9)\n if (c.pluginRunner) {\n const errCtxObj: Record<string, unknown> = {}\n c.pluginRunner.applyDecorations(errCtxObj)\n try {\n await c.pluginRunner.runOnResponse(c.buildPluginCtx(errCtxObj), {\n inErrorPath: true,\n })\n } catch {\n // Containment.\n }\n }\n}\n\n/**\n * T5a.2 Phase G slice 3/N — Web-Standards request error handler.\n *\n * Mirror of `handleRequestError(err, c: HandleRequestErrorCtx)` for the\n * Web `Request` shape. Returns a native `Response` directly instead of\n * mutating `res`. Same behavioral contract:\n *\n * 1. Auth-error detection via `instanceof AuthRequiredError` PLUS a\n * duck-type fallback (`code === 'AUTH_REQUIRED' && status === 401`)\n * — needed because Vite dev / vitest can produce duplicate class\n * identities, breaking `instanceof`.\n * 2. Envelope-shaped JSON body using `serverErrorToEnvelope` (G5 D3\n * boundary translation).\n * 3. Status code derived from envelope.code via `envelopeCodeToStatus`\n * mirror (already implemented inline in web-handler.ts; this slice\n * uses the same mapping table).\n *\n * **Difference vs IncomingMessage path:** the Web path's plugin runner\n * orchestration lives in `executeWebRequest`'s `runWithHooks` /\n * `runErrorHooks` (Phase G slice 1/N) — `handleWebRequestError` is the\n * leaf that builds the error Response WITHOUT touching plugin hooks.\n * Callers compose: `executeWebRequest` (or future Web execute pipeline)\n * catches a throw, calls `handleWebRequestError(err, { requestId })` to\n * build the Response, then routes through onError hooks separately.\n */\ninterface HandleWebRequestErrorCtx {\n requestId?: string\n}\n\nexport async function handleWebRequestError(\n err: unknown,\n ctx: HandleWebRequestErrorCtx = {},\n): Promise<Response> {\n // Lazy import to avoid pulling the full envelope translator into the\n // bundle for consumers who don't hit the error path. Same dynamic-\n // import pattern as web-handler.ts's parseBodyFull.\n const { serverErrorToEnvelope } = await import('../../core/contracts/server-error-to-envelope.js')\n\n // 1. Auth-error detection (shape-based guard from core/contracts)\n if (isAuthRequiredError(err)) {\n const authErr = err as { code?: string; message?: string; status?: number }\n return new Response(\n JSON.stringify({\n code: authErr.code ?? 'AUTH_REQUIRED',\n message: authErr.message ?? 'Authentication required',\n }),\n {\n status: authErr.status ?? 401,\n headers: {\n 'content-type': 'application/json',\n ...(ctx.requestId !== undefined ? { 'x-request-id': ctx.requestId } : {}),\n },\n },\n )\n }\n\n // 2. Envelope translation for everything else (G5 D3 boundary).\n const envelope = serverErrorToEnvelope(err)\n return new Response(JSON.stringify(envelope), {\n status: envelopeCodeToStatus(envelope.code),\n headers: {\n 'content-type': 'application/json',\n ...(ctx.requestId !== undefined ? { 'x-request-id': ctx.requestId } : {}),\n },\n })\n}\n\n// envelopeCodeToStatus extracted to core/contracts/envelope-code-to-status.ts\n// (architecture-remediation T1.2, 2026-06-12)\n","/**\n * FormData → ZodObject coercion driven by the declared schema.\n *\n * Per plan g3-server-actions-and-useaction v1.2 § Phase 1 / T1.3 + Astro\n * runtime/server.ts:323-397 pattern (adapted to Zod 4 shape access via\n * `.def.shape`). FormData entries arrive as strings (or File for binary);\n * we walk the schema field-by-field and coerce to the declared zod type\n * before letting `safeParse` finalize validation.\n *\n * Supports: ZodString, ZodNumber, ZodBoolean, ZodArray (via getAll), nested\n * ZodObject (via dot-notation prefix), ZodOptional / ZodNullable / ZodDefault\n * wrappers. Skips: ZodDiscriminatedUnion + ZodPipe + ZodIntersection (deferred\n * to consumer's safeParse fallback — values returned as-is, zod will validate\n * or coerce).\n */\nimport { z } from 'zod'\n\n/**\n * Walk the declared ZodObject schema and pull values from `formData`,\n * coercing per-field. Returns a plain object suitable for `schema.safeParse`.\n *\n * `prefix` is used for recursive nested-object resolution: a nested field at\n * `user.address.zip` is read from formData key `user.address.zip` (top-level\n * call uses empty prefix).\n */\nexport function formDataToObject(\n formData: FormData,\n schema: z.ZodObject<z.ZodRawShape>,\n prefix = '',\n): Record<string, unknown> {\n // Zod 4: `.shape` is a direct property on ZodObject.\n const shape = schema.shape as Record<string, z.ZodType>\n const out: Record<string, unknown> = {}\n\n for (const [key, rawValidator] of Object.entries(shape)) {\n const fullKey = prefix + key\n const validator = unwrapWrappers(rawValidator)\n\n if (validator instanceof z.ZodObject) {\n // Recurse for nested object types\n const nestedPrefix = `${fullKey}.`\n const hasNestedKeys = [...formData.keys()].some((k) => k.startsWith(nestedPrefix))\n if (hasNestedKeys) {\n out[key] = formDataToObject(formData, validator, nestedPrefix)\n continue\n }\n // No nested keys present — apply default / nullable / undefined semantics\n out[key] = unwrapMissingDefault(rawValidator)\n continue\n }\n\n if (validator instanceof z.ZodArray) {\n const values = formData.getAll(fullKey)\n out[key] = coerceArrayElements(values, validator as z.ZodArray<z.ZodType>)\n continue\n }\n\n if (validator instanceof z.ZodBoolean) {\n out[key] = coerceBoolean(formData, fullKey)\n continue\n }\n\n // Scalar (string / number / etc.)\n if (formData.has(fullKey)) {\n const raw = formData.get(fullKey)\n out[key] = coerceScalar(raw, validator)\n } else {\n out[key] = unwrapMissingDefault(rawValidator)\n }\n }\n\n return out\n}\n\n/** Strip ZodOptional / ZodNullable / ZodDefault to reach the inner validator. */\nfunction unwrapWrappers(validator: z.ZodType): z.ZodType {\n let inner: z.ZodType = validator\n while (\n inner instanceof z.ZodOptional ||\n inner instanceof z.ZodNullable ||\n inner instanceof z.ZodDefault\n ) {\n inner = getInnerType(inner)\n }\n return inner\n}\n\nfunction getInnerType(wrapper: z.ZodType): z.ZodType {\n // Zod 4 stores inner type in def.innerType\n const def = wrapper.def as unknown as { innerType?: z.ZodType }\n if (def.innerType) return def.innerType\n // Fallback: try _def for cross-version compat\n const legacyDef = (wrapper as unknown as { _def?: { innerType?: z.ZodType } })._def\n if (legacyDef?.innerType) return legacyDef.innerType\n return wrapper\n}\n\n/**\n * What to return when a field is missing from FormData:\n * - ZodDefault → the default value (evaluated if function)\n * - ZodNullable → null\n * - ZodOptional → undefined\n * - else → undefined (consumer safeParse will likely error)\n */\nfunction unwrapMissingDefault(validator: z.ZodType): unknown {\n let cursor: z.ZodType = validator\n while (\n cursor instanceof z.ZodOptional ||\n cursor instanceof z.ZodNullable ||\n cursor instanceof z.ZodDefault\n ) {\n if (cursor instanceof z.ZodDefault) {\n const def = cursor.def as unknown as { defaultValue: unknown }\n return typeof def.defaultValue === 'function'\n ? (def.defaultValue as () => unknown)()\n : def.defaultValue\n }\n if (cursor instanceof z.ZodNullable) return null\n cursor = getInnerType(cursor)\n }\n return undefined\n}\n\nfunction coerceScalar(raw: FormDataEntryValue | null, validator: z.ZodType): unknown {\n if (raw === null) return undefined\n if (validator instanceof z.ZodNumber) {\n return typeof raw === 'string' ? Number(raw) : raw\n }\n // String, File, default — pass through (zod will validate File via .instanceof if used)\n return raw\n}\n\nfunction coerceArrayElements(\n values: FormDataEntryValue[],\n arrayValidator: z.ZodArray<z.ZodType>,\n): unknown[] {\n // zod 4 stores the array element schema in `def.element` (`def.type` is the\n // discriminator string 'array'). Fall back to `def.type` for older shapes.\n const def = arrayValidator.def as unknown as { element?: z.ZodType; type?: unknown }\n const elementSchema = def.element ?? (def.type instanceof z.ZodType ? def.type : undefined)\n const elementType = elementSchema ? unwrapWrappers(elementSchema) : undefined\n if (elementType instanceof z.ZodNumber) {\n return values.map((v) => (typeof v === 'string' ? Number(v) : v))\n }\n if (elementType instanceof z.ZodBoolean) {\n return values.map((v) => {\n if (v === 'true') return true\n if (v === 'false') return false\n return Boolean(v)\n })\n }\n // String / File / unknown — pass through\n return values\n}\n\nfunction coerceBoolean(formData: FormData, key: string): boolean | undefined {\n if (!formData.has(key)) return undefined\n const val = formData.get(key)\n if (val === 'true') return true\n if (val === 'false') return false\n // Presence with truthy non-boolean string (e.g., HTML checkbox \"on\") → true\n return Boolean(val)\n}\n","/**\n * Server-side action result serializer.\n *\n * Per plan g3-server-actions-and-useaction v1.2 § Phase 1 / T1.3 + ADR D1.\n * Wraps `devalue.stringify` for success payloads (preserves Date/Set/URL/bigint\n * roundtrip) and JSON-encodes error envelopes for `ActionError` /\n * `ActionInputError`. Returns a `SerializedActionResult` discriminated union\n * consumed by the HTTP send layer (`action-execute.ts`).\n *\n * EC absorbed:\n * - EC-3 (response side): `responseBodySizeLimit` default 5 MB; throws\n * `ActionError({code:'PAYLOAD_TOO_LARGE'})` when the serialized body\n * exceeds the limit. Prevents handler-returns-100MB DoS.\n */\nimport { stringify as devalueStringify } from 'devalue'\n\nimport {\n ActionError,\n ActionInputError,\n type ActionResult,\n type SerializedActionResult,\n} from '../../core/contracts/action-protocol.js'\n\nconst DEFAULT_RESPONSE_BODY_SIZE_LIMIT = 5 * 1024 * 1024 // 5 MB\n\ninterface SerializeOptions {\n /**\n * Maximum allowed length of the serialized response body in BYTES (UTF-8\n * length of `body` string is checked, not the JS string length). Default\n * 5 MB. Configurable via `defineConfig({security:{responseBodySizeLimit}})`.\n */\n responseBodySizeLimit?: number\n}\n\n/**\n * Serialize an action result for the wire.\n *\n * - Success with data: `application/json+devalue` body via devalue.stringify\n * with a `URL` reviver for round-tripping URL instances.\n * - Success with `undefined` data: status 204 empty.\n * - Error: `application/json` JSON body with type discriminator\n * (`TheoActionError` or `TheoActionInputError`) + code + message\n * (+ fields/issues for input errors).\n *\n * Throws `ActionError({code:'PAYLOAD_TOO_LARGE'})` if the serialized body\n * exceeds the configured size limit (EC-3).\n *\n * Throws on `Response` instance as data (Astro guard — handler must return\n * plain JSON-serializable values, not Web Response objects).\n */\nexport function serializeActionResult(\n result: ActionResult,\n options: SerializeOptions = {},\n): SerializedActionResult {\n const limit = options.responseBodySizeLimit ?? DEFAULT_RESPONSE_BODY_SIZE_LIMIT\n\n if (result.error !== undefined) {\n const body =\n result.error instanceof ActionInputError\n ? JSON.stringify({\n type: result.error.type,\n code: result.error.code,\n message: result.error.message,\n issues: result.error.issues,\n fields: result.error.fields,\n })\n : JSON.stringify({\n type: result.error.type,\n code: result.error.code,\n message: result.error.message,\n })\n if (Buffer.byteLength(body, 'utf8') > limit) {\n throw new ActionError({\n code: 'PAYLOAD_TOO_LARGE',\n message: `Serialized error body exceeds limit (${limit} bytes)`,\n })\n }\n return {\n type: 'error',\n status: result.error.status,\n contentType: 'application/json',\n body,\n }\n }\n\n if (result.data === undefined) {\n return { type: 'empty', status: 204 }\n }\n\n if (result.data instanceof Response) {\n throw new ActionError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Action handler cannot serialize Response objects — return plain data instead',\n })\n }\n\n let body: string\n try {\n body = devalueStringify(result.data, {\n URL: (value: unknown) => value instanceof URL && value.href,\n })\n } catch (e) {\n throw new ActionError({\n code: 'INTERNAL_SERVER_ERROR',\n message: `Action data not serializable: ${e instanceof Error ? e.message : String(e)}`,\n })\n }\n\n if (Buffer.byteLength(body, 'utf8') > limit) {\n throw new ActionError({\n code: 'PAYLOAD_TOO_LARGE',\n message: `Serialized response body exceeds limit (${limit} bytes)`,\n })\n }\n\n return {\n type: 'data',\n status: 200,\n contentType: 'application/json+devalue',\n body,\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport type { z } from 'zod'\n\nimport {\n ActionError,\n ActionInputError,\n type ActionErrorCode,\n} from '../../core/contracts/action-protocol.js'\nimport { parseRequestBody, type ParsedBody } from '../body-parser.js'\nimport type { PluginContext } from '../plugin-types.js'\nimport type { PluginRunner } from '../plugins/plugin-runner.js'\nimport type { LoadModule } from '../scan/module-loader.js'\nimport { dispatchCsrfWarn } from '../security/csrf-warn-dispatch.js'\nimport { enforceCsrf, type CsrfMode, type DisallowedConfig } from '../security/csrf.js'\n\nimport { sendError } from './execute.js'\nimport { formDataToObject } from './form-data-to-object.js'\nimport { handleRequestError } from './handle-request-error.js'\nimport { runMiddlewareAndContext } from './middleware-runner.js'\nimport { incomingMessageToHandlerRequest } from './node-request.js'\nimport { serializeActionResult } from './serialize-action-result.js'\n\n// Universal dev gate — same IIFE pattern as track-agent-run (EC-11 tree-shake).\n// Both checks are statically replaceable by bundlers in prod build, so the\n// devtools dispatcher import is eliminated from prod bundles entirely.\nconst __IS_DEV = (() => {\n try {\n return (import.meta as { env?: { DEV?: boolean } }).env?.DEV === true\n } catch {\n return process.env.NODE_ENV !== 'production'\n }\n})()\n\n// Minimal Zod-shaped contract — we only need `safeParse`, not the whole API.\ninterface ZodLike {\n safeParse: (value: unknown) => {\n success: boolean\n data?: unknown\n // Derive the issue element type from `ZodError` — `z.ZodIssue` is deprecated in Zod 4.\n error?: { issues: z.ZodError['issues'] }\n }\n}\n\n// Shape of a `defineAction` export. Anchored by structural typing — we do\n// not import the action factory's return type to avoid module cycles, but\n// we do reject inputs that fail the structural test.\ninterface ActionConfig {\n input: ZodLike\n handler: (params: { input: unknown; ctx: unknown }) => unknown\n csrf?: false\n /** T1.3 sub-C: wire-protocol accept mode (defaults to 'json' when omitted). */\n accept?: 'form' | 'json'\n}\n\nfunction isActionConfig(value: unknown): value is ActionConfig {\n if (typeof value !== 'object' || value === null) return false\n const candidate = value as Record<string, unknown>\n if (typeof candidate.handler !== 'function') return false\n const input = candidate.input as ZodLike | undefined\n return typeof input?.safeParse === 'function'\n}\n\nexport interface ExecuteActionOptions {\n filePath: string\n exportName: string\n req: IncomingMessage\n res: ServerResponse\n loadModule: LoadModule\n serverDir?: string\n requestId?: string\n pluginRunner?: PluginRunner\n csrfMode?: CsrfMode\n disallowed?: DisallowedConfig\n}\n\n// Backwards-compatible positional signature; the options-shape is the new\n// preferred entry point and what the framework uses internally.\n// eslint-disable-next-line max-params -- public API surface; existing callers pass positional args\nexport async function executeAction(\n filePath: string,\n exportName: string,\n req: IncomingMessage,\n res: ServerResponse,\n loadModule: LoadModule,\n serverDir?: string,\n requestId?: string,\n pluginRunner?: PluginRunner,\n csrfMode: CsrfMode = 'strict',\n disallowed?: DisallowedConfig,\n): Promise<void> {\n return executeActionWithOptions({\n filePath,\n exportName,\n req,\n res,\n loadModule,\n serverDir,\n requestId,\n pluginRunner,\n csrfMode,\n disallowed,\n })\n}\n\nasync function loadActionConfig(\n loadModule: LoadModule,\n filePath: string,\n exportName: string,\n res: ServerResponse,\n requestId: string | undefined,\n): Promise<ActionConfig | null> {\n const mod = await loadModule(filePath)\n const exportedValue = mod[exportName]\n if (!isActionConfig(exportedValue)) {\n sendError(res, 'NOT_FOUND', `Action \"${exportName}\" not found`, 404, undefined, requestId)\n return null\n }\n return exportedValue\n}\n\ninterface CsrfActionCtx {\n actionConfig: ActionConfig\n csrfMode: CsrfMode\n disallowed: DisallowedConfig | undefined\n requestId: string | undefined\n}\n\nfunction enforceCsrfForAction(\n req: IncomingMessage,\n res: ServerResponse,\n ctx: CsrfActionCtx,\n): boolean {\n if (ctx.actionConfig.csrf === false) return true\n const decision = enforceCsrf(\n req,\n ctx.csrfMode,\n {\n // T3.3 DRY — canonical dispatcher\n warn: dispatchCsrfWarn,\n path: req.url,\n },\n ctx.disallowed,\n )\n if (decision.allow) return true\n sendError(\n res,\n 'CSRF_INVALID',\n decision.reason ?? 'CSRF check failed',\n 403,\n undefined,\n ctx.requestId,\n )\n return false\n}\n\ninterface ActionPipeline {\n ctx: Record<string, unknown>\n buildPluginCtx: (ctxObj: Record<string, unknown>) => PluginContext\n pluginRunner: PluginRunner | undefined\n serverDir: string | undefined\n loadModule: LoadModule\n req: IncomingMessage\n res: ServerResponse\n}\n\nasync function runPreHandlerPipeline(p: ActionPipeline): Promise<boolean> {\n if (p.serverDir) {\n const result = await runMiddlewareAndContext(p.req, p.res, p.loadModule, p.serverDir)\n if (result.aborted) return false\n Object.assign(p.ctx, (result.ctx ?? {}) as Record<string, unknown>)\n p.pluginRunner?.applyDecorations(p.ctx)\n }\n if (p.pluginRunner) {\n const preResult = await p.pluginRunner.runPreHandler(p.buildPluginCtx(p.ctx))\n if (preResult.shortCircuited) return false\n }\n return true\n}\n\nasync function readActionBody(\n req: IncomingMessage,\n res: ServerResponse,\n requestId: string | undefined,\n actionConfig: ActionConfig,\n): Promise<{ ok: true; body: unknown } | { ok: false }> {\n try {\n const parsed = await parseRequestBody(req)\n const accept = actionConfig.accept ?? 'json'\n let body: unknown\n if (accept === 'form') {\n body = formDataToObject(\n synthesizeFormData(parsed),\n actionConfig.input as unknown as z.ZodObject<z.ZodRawShape>,\n )\n } else if (parsed.json !== undefined) {\n body = parsed.json\n } else {\n body = parsed.fields\n }\n return { ok: true, body }\n } catch (err) {\n sendError(res, 'VALIDATION_ERROR', (err as Error).message, 400, undefined, requestId)\n return { ok: false }\n }\n}\n\n/**\n * Build a FormData instance from the body-parser's `ParsedBody`. Fields become\n * string entries; files become Blob entries with the original filename. Used\n * only when `accept === 'form'` to feed `formDataToObject`.\n */\nfunction synthesizeFormData(parsed: ParsedBody): FormData {\n const fd = new FormData()\n for (const [name, value] of Object.entries(parsed.fields)) {\n fd.append(name, value)\n }\n for (const file of parsed.files) {\n const blob = new Blob([file.buffer as unknown as ArrayBuffer], {\n type: file.mimeType,\n })\n fd.append(file.fieldname, blob, file.filename)\n }\n return fd\n}\n\n/**\n * Write a serialized ActionResult to the response. Sets content-type, status,\n * and body. Returns void; caller must not write further after invoking.\n */\nfunction writeSerialized(\n res: ServerResponse,\n serialized: ReturnType<typeof serializeActionResult>,\n): void {\n if (serialized.type === 'empty') {\n res.statusCode = serialized.status\n res.end()\n return\n }\n res.statusCode = serialized.status\n res.setHeader('Content-Type', serialized.contentType)\n res.end(serialized.body)\n}\n\n/**\n * Dev-only telemetry: dispatch ACTION_CALL_ADD so the devtools Actions tab\n * (T5.1) can render this call. Tree-shaken in prod via __IS_DEV guard.\n * Mirrors trackAgentRun pattern. Never throws (swallow + log).\n */\nasync function emitActionCallTelemetry(\n name: string,\n startedAt: number,\n input: unknown,\n outcome: { status: 'success'; output: unknown } | { status: 'error'; error: ActionError },\n): Promise<void> {\n if (!__IS_DEV) return\n try {\n const mod = (await import('../../devtools/bridge/dispatcher.js')) as {\n dispatcher: {\n onActionCall: (r: {\n id: string\n timestamp: number\n name: string\n input: unknown\n output?: unknown\n error?: { code: string; message: string; fields?: Record<string, string[]> }\n durationMs: number\n status: 'success' | 'error'\n }) => void\n }\n }\n mod.dispatcher.onActionCall({\n // eslint-disable-next-line sonarjs/pseudo-random -- non-secret correlation id\n id: `act-${String(Date.now())}-${Math.random().toString(36).slice(2, 8)}`,\n timestamp: startedAt,\n name,\n input,\n output: outcome.status === 'success' ? outcome.output : undefined,\n error:\n outcome.status === 'error'\n ? {\n code: outcome.error.code,\n message: outcome.error.message,\n fields: outcome.error instanceof ActionInputError ? outcome.error.fields : undefined,\n }\n : undefined,\n durationMs: Date.now() - startedAt,\n status: outcome.status,\n })\n } catch {\n // devtools dispatcher missing in some prod-like bundle — silently skip\n }\n}\n\nasync function executeActionWithOptions(opts: ExecuteActionOptions): Promise<void> {\n const {\n filePath,\n exportName,\n req,\n res,\n loadModule,\n serverDir,\n requestId,\n pluginRunner,\n csrfMode = 'strict',\n disallowed,\n } = opts\n\n // ADR-0028 R3a / #119 — plugin hooks see a Web `Request` in every runtime (built once, shared across\n // buildPluginCtx calls). Actions have no request body on the handler ctx; hooks read headers/URL/method.\n const webRequest = incomingMessageToHandlerRequest(req)\n const buildPluginCtx = (ctxObj: Record<string, unknown>): PluginContext => ({\n request: webRequest,\n response: res,\n ctx: ctxObj,\n requestId: requestId ?? 'no-id',\n })\n\n let ctx: Record<string, unknown> = {}\n\n try {\n // 1. Only POST.\n if ((req.method ?? 'GET').toUpperCase() !== 'POST') {\n sendError(res, 'METHOD_NOT_ALLOWED', 'Actions only accept POST', 405, undefined, requestId)\n return\n }\n\n // 2. Plugin onRequest hook (parity with executeRoute).\n if (pluginRunner) {\n pluginRunner.applyDecorations(ctx)\n const onReqResult = await pluginRunner.runOnRequest(buildPluginCtx(ctx))\n if (onReqResult.shortCircuited) return\n }\n\n // 3. Load module + locate action export.\n const actionConfig = await loadActionConfig(loadModule, filePath, exportName, res, requestId)\n if (!actionConfig) return\n\n // 4. CSRF enforcement\n if (!enforceCsrfForAction(req, res, { actionConfig, csrfMode, disallowed, requestId })) {\n return\n }\n\n // 5+6. Middleware + context pipeline, then plugin preHandler.\n const pipeline: ActionPipeline = {\n ctx,\n buildPluginCtx,\n pluginRunner,\n serverDir,\n loadModule,\n req,\n res,\n }\n if (!(await runPreHandlerPipeline(pipeline))) return\n ctx = pipeline.ctx\n\n // 7. Parse body (supports JSON and multipart/form-data).\n const bodyOutcome = await readActionBody(req, res, requestId, actionConfig)\n if (!bodyOutcome.ok) return\n\n // T1.3 sub-C action name derived from exportName for telemetry.\n const actionName = exportName === 'default' ? deriveActionNameFromPath(filePath) : exportName\n const startedAt = Date.now()\n\n // 8. Validate input with Zod — failure → ActionInputError envelope (T0.1 + ADR D6).\n const result = actionConfig.input.safeParse(bodyOutcome.body)\n if (!result.success) {\n const inputErr = new ActionInputError(result.error?.issues ?? [])\n writeSerialized(res, serializeActionResult({ data: undefined, error: inputErr }))\n await emitActionCallTelemetry(actionName, startedAt, bodyOutcome.body, {\n status: 'error',\n error: inputErr,\n })\n return\n }\n\n await runActionHandler({\n actionConfig,\n actionName,\n startedAt,\n input: result.data,\n ctx,\n res,\n pluginRunner,\n buildPluginCtx,\n })\n } catch (err) {\n await handleActionError(err, { req, res, ctx, requestId, pluginRunner, buildPluginCtx })\n }\n}\n\n/** Derive a stable display name from filePath when handler exported as default. */\nfunction deriveActionNameFromPath(filePath: string): string {\n const base = filePath.split(/[\\\\/]/).pop() ?? 'unknown'\n return base.replace(/\\.[jt]sx?$/, '')\n}\n\n/**\n * Duck-typed guard for ActionError-shaped throws. Necessary because Vite SSR\n * may load multiple module copies of `core/contracts/action-protocol.ts` when\n * the fixture resolves `theokit/server` via a different path than the runtime\n * import — `err instanceof ActionError` then fails even though the user\n * legitimately threw `new ActionError(...)`.\n *\n * Server-only: only invoked on handler-thrown errors (trust boundary already\n * inside the action runtime). Not safe to use on client-parsed JSON — for\n * that path keep `isActionError` (the instanceof guard) from action-protocol.\n */\nfunction isActionErrorLike(err: unknown): err is ActionError {\n if (err === null || typeof err !== 'object') return false\n const obj = err as Record<string, unknown>\n return (\n (obj.type === 'TheoActionError' || obj.type === 'TheoActionInputError') &&\n typeof obj.code === 'string' &&\n typeof obj.status === 'number'\n )\n}\n\ninterface HandlerCtx {\n actionConfig: ActionConfig\n actionName: string\n startedAt: number\n input: unknown\n ctx: Record<string, unknown>\n res: ServerResponse\n pluginRunner: PluginRunner | undefined\n buildPluginCtx: (ctxObj: Record<string, unknown>) => PluginContext\n}\n\nasync function runActionHandler(args: HandlerCtx): Promise<void> {\n try {\n const handlerResult = await args.actionConfig.handler({ input: args.input, ctx: args.ctx })\n // T1.3 sub-C — wire devalue serialization (ADR D1). Undefined → 204; data → 200 + json+devalue.\n writeSerialized(args.res, serializeActionResult({ data: handlerResult, error: undefined }))\n if (args.pluginRunner) {\n await args.pluginRunner.runOnResponse(args.buildPluginCtx(args.ctx))\n }\n await emitActionCallTelemetry(args.actionName, args.startedAt, args.input, {\n status: 'success',\n output: handlerResult,\n })\n } catch (err) {\n // Handler-thrown ActionError → use the typed envelope; other throws bubble\n // up to executeActionWithOptions for handleActionError fallback chain.\n // Duck-type the `type` discriminator (not instanceof): Vite SSR can load\n // multiple module copies of action-protocol.ts when fixture and runtime\n // resolve different paths; `err instanceof ActionError` then fails even\n // when the handler legitimately threw via `new ActionError(...)`.\n if (isActionErrorLike(err)) {\n writeSerialized(args.res, serializeActionResult({ data: undefined, error: err }))\n await emitActionCallTelemetry(args.actionName, args.startedAt, args.input, {\n status: 'error',\n error: err,\n })\n return\n }\n // Wrap unknown throws as INTERNAL_SERVER_ERROR with the original message\n // preserved for telemetry; production error handler still consumes via\n // handleActionError fallback (preserves AuthRequiredError duck-type).\n const wrapped = new ActionError({\n code: 'INTERNAL_SERVER_ERROR' satisfies ActionErrorCode,\n message: err instanceof Error ? err.message : 'Action handler threw',\n })\n await emitActionCallTelemetry(args.actionName, args.startedAt, args.input, {\n status: 'error',\n error: wrapped,\n })\n throw err\n }\n}\n\ninterface ActionErrorCtx {\n req: IncomingMessage\n res: ServerResponse\n ctx: Record<string, unknown>\n requestId: string | undefined\n pluginRunner: PluginRunner | undefined\n buildPluginCtx: (ctxObj: Record<string, unknown>) => PluginContext\n}\n\n// T3.4 (PV-9 DRY): delegate to the shared `handleRequestError` helper.\n// Adds the duck-type AuthRequiredError fallback (latent bug fix — was\n// missing from action-execute, present in execute).\nasync function handleActionError(err: unknown, c: ActionErrorCtx): Promise<void> {\n return handleRequestError(err, {\n req: c.req,\n res: c.res,\n requestId: c.requestId,\n pluginRunner: c.pluginRunner,\n buildPluginCtx: c.buildPluginCtx,\n })\n}\n","/**\n * T1.4 — Server-side batch handler.\n *\n * Receives `{ requests: [...] }` POSTed to `/api/__theo_batch__` and returns\n * `{ results: [...] }` with per-item error isolation. EC-2: items cannot\n * override auth/forwarded headers (would be a session-bypass vector).\n */\n\nimport { z } from 'zod'\n\nexport const STRIPPED_HEADERS = [\n 'authorization',\n 'cookie',\n 'x-forwarded-for',\n 'x-forwarded-host',\n 'x-forwarded-proto',\n 'x-real-ip',\n 'host',\n] as const\n\nexport const BATCH_PATH = '/api/__theo_batch__'\nconst DEFAULT_MAX_BATCH = 32\n\nexport class BatchPathConflictError extends Error {\n constructor(path: string) {\n super(\n `Server route conflicts with reserved batch path ${path}. ` +\n `Rename the route or disable batching in theo.config.ts.`,\n )\n this.name = 'BatchPathConflictError'\n }\n}\n\nconst batchRequestSchema = z.object({\n path: z.string().min(1),\n method: z.string().min(1),\n query: z.record(z.string(), z.unknown()).optional(),\n body: z.unknown().optional(),\n headers: z.record(z.string(), z.string()).optional(),\n})\n\nconst batchPayloadSchema = z.object({\n requests: z.array(batchRequestSchema).min(1),\n})\n\nexport type BatchRequestItem = z.infer<typeof batchRequestSchema>\nexport type BatchPayload = z.infer<typeof batchPayloadSchema>\n\nexport type BatchExecuteFn = (\n req: BatchRequestItem,\n) => Promise<{ data: unknown } | { error: { message: string; code?: string } }>\n\nexport interface HandleBatchOptions {\n execute: BatchExecuteFn\n /** Max number of items per batch. Default 32. */\n max?: number\n /** Outer-request headers that override per-item headers in STRIPPED_HEADERS. */\n outerHeaders?: Record<string, string>\n}\n\nexport type BatchResultItem = { data: unknown } | { error: { message: string; code?: string } }\n\nexport interface BatchResponse {\n results: BatchResultItem[]\n}\n\n/**\n * Sanitize a per-item header object: keys in STRIPPED_HEADERS are removed,\n * then the outer request's values for those keys are layered on top so that\n * downstream middlewares see the real session/auth headers.\n */\nfunction sanitizeItemHeaders(\n itemHeaders: Record<string, string> | undefined,\n outerHeaders: Record<string, string> | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {}\n if (itemHeaders) {\n for (const [k, v] of Object.entries(itemHeaders)) {\n const lower = k.toLowerCase()\n if (!(STRIPPED_HEADERS as readonly string[]).includes(lower)) {\n out[lower] = v\n }\n }\n }\n if (outerHeaders) {\n for (const stripped of STRIPPED_HEADERS) {\n // `Object.hasOwn` defends against missing keys without triggering\n // `no-unnecessary-condition` (TypeScript types `outerHeaders` keys\n // as defined; `hasOwn` keeps the conditional honest at runtime).\n if (Object.hasOwn(outerHeaders, stripped)) {\n out[stripped] = outerHeaders[stripped]\n }\n }\n }\n return out\n}\n\n/**\n * Validate + execute a batch request.\n *\n * CR-028 fix: previously the signature was `payload: BatchPayload`,\n * suggesting the caller had already validated. In reality `api-middleware`\n * passes `JSON.parse(rawBody) as BatchPayload` — an unsafe cast over raw\n * HTTP input. We widen the input type to `unknown` so the type system\n * forces validation, then run Zod once at this single trust boundary.\n */\nexport async function handleBatchRequest(\n payload: unknown,\n options: HandleBatchOptions,\n): Promise<BatchResponse> {\n const parsed = batchPayloadSchema.parse(payload)\n const max = options.max ?? DEFAULT_MAX_BATCH\n if (parsed.requests.length > max) {\n throw new Error(`Batch size ${parsed.requests.length} exceeds max ${max}`)\n }\n\n const results: BatchResultItem[] = []\n for (const item of parsed.requests) {\n const sanitized: BatchRequestItem = {\n ...item,\n headers: sanitizeItemHeaders(item.headers, options.outerHeaders),\n }\n try {\n const r = await options.execute(sanitized)\n results.push(r)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n results.push({ error: { message } })\n }\n }\n return { results }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\n/**\n * T1.2 — CORS middleware.\n *\n * Single global middleware that runs FIRST in the request pipeline:\n * CORS preflight → rate limit → CSRF → security headers → handler\n *\n * Preflight (`OPTIONS` with `Access-Control-Request-Method`) is handled\n * by `handlePreflight`, which short-circuits the response with 204 +\n * Access-Control-* headers.\n *\n * Non-preflight requests pass through; `applyHeaders` adds\n * `Access-Control-Allow-Origin` (echoing the request's Origin),\n * `Access-Control-Expose-Headers`, and `Access-Control-Allow-Credentials`.\n *\n * Per ADR D3: preflight responses are deterministic and only the matched\n * origin is echoed back (never `'*'` when credentials are enabled —\n * required by the CORS spec).\n */\n\n// `'*'` is conceptually distinct from a regular host string (it means\n// \"any origin\"), but TypeScript-wise it is just `string`, so we collapse\n// the union and document the wildcard via the type's name. Callers should\n// still pass the literal `'*'` to mean \"allow anywhere\" for readability.\nexport type CorsOrigin =\n | string\n | RegExp\n | readonly (string | RegExp)[]\n | ((origin: string) => boolean)\n\nexport interface CorsConfig {\n origins: CorsOrigin\n methods?: readonly ('GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD')[]\n allowedHeaders?: readonly string[]\n exposedHeaders?: readonly string[]\n credentials?: boolean\n maxAge?: number\n}\n\nexport interface CorsHandler {\n handlePreflight(req: IncomingMessage, res: ServerResponse): boolean\n applyHeaders(req: IncomingMessage, res: ServerResponse): void\n}\n\nconst DEFAULT_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'] as const\nconst DEFAULT_ALLOWED_HEADERS = ['Content-Type', 'X-Theo-Action', 'Authorization'] as const\nconst DEFAULT_MAX_AGE = 600\n\n/**\n * Read the request Origin header. Per Node typing, it can be a string,\n * string[] (proxy doubled), or undefined. We take the FIRST non-empty\n * value (consistent with `csrf.ts:121-122`).\n */\nfunction readOrigin(req: IncomingMessage): string | undefined {\n const raw = req.headers.origin\n if (raw === undefined) return undefined\n if (Array.isArray(raw)) {\n return raw.find((v): v is string => typeof v === 'string' && v.length > 0)\n }\n return raw\n}\n\n/**\n * Test whether `origin` is allowed by `allowed`. Pure function — no I/O.\n *\n * EC-8: callback variants that throw are fail-closed (deny). Without\n * this, a transient datastore outage would silently widen CORS during\n * the failure window.\n */\nexport function matchesOrigin(origin: string, allowed: CorsOrigin): boolean {\n if (allowed === '*') return true\n if (typeof allowed === 'string') return origin === allowed\n if (allowed instanceof RegExp) {\n allowed.lastIndex = 0\n return allowed.test(origin)\n }\n if (Array.isArray(allowed)) {\n for (const entry of allowed) {\n if (typeof entry === 'string' && origin === entry) return true\n if (entry instanceof RegExp) {\n entry.lastIndex = 0\n if (entry.test(origin)) return true\n }\n }\n return false\n }\n if (typeof allowed === 'function') {\n // EC-8: fail-closed on any throw\n try {\n return allowed(origin)\n } catch {\n return false\n }\n }\n return false\n}\n\nexport function createCorsHandler(config: CorsConfig): CorsHandler {\n const methods = (config.methods ?? DEFAULT_METHODS).slice()\n const allowedHeaders = (config.allowedHeaders ?? DEFAULT_ALLOWED_HEADERS).slice()\n const maxAge = String(config.maxAge ?? DEFAULT_MAX_AGE)\n const credentials = config.credentials === true\n\n return {\n handlePreflight(req, res) {\n if (req.method !== 'OPTIONS') return false\n const acMethod = req.headers['access-control-request-method']\n if (!acMethod) return false\n const origin = readOrigin(req)\n if (!origin) return false\n\n if (!matchesOrigin(origin, config.origins)) {\n res.statusCode = 403\n res.end()\n return true\n }\n\n // Echo the matched origin (NEVER '*' when credentials are enabled —\n // browsers reject wildcard responses with credentials per CORS spec).\n res.setHeader('Access-Control-Allow-Origin', origin)\n res.setHeader('Access-Control-Allow-Methods', methods.join(', '))\n res.setHeader('Access-Control-Allow-Headers', allowedHeaders.join(', '))\n res.setHeader('Access-Control-Max-Age', maxAge)\n // Mark the response as origin-varying so caches don't poison\n res.setHeader('Vary', 'Origin')\n if (credentials) res.setHeader('Access-Control-Allow-Credentials', 'true')\n res.statusCode = 204\n res.end()\n return true\n },\n\n applyHeaders(req, res) {\n const origin = readOrigin(req)\n if (!origin) return\n if (!matchesOrigin(origin, config.origins)) return\n\n res.setHeader('Access-Control-Allow-Origin', origin)\n res.setHeader('Vary', 'Origin')\n if (credentials) res.setHeader('Access-Control-Allow-Credentials', 'true')\n if (config.exposedHeaders && config.exposedHeaders.length > 0) {\n res.setHeader('Access-Control-Expose-Headers', config.exposedHeaders.join(', '))\n }\n },\n }\n}\n\n/**\n * T5a.2 Phase B slice 5/6 — Web-Standards CORS handler.\n *\n * Mirror of `createCorsHandler(config): CorsHandler` for the Web `Request`\n * shape. Same `CorsConfig`, same `matchesOrigin` logic (pure helper\n * already), same security guarantees (echo matched origin only — never\n * `'*'` when credentials enabled; EC-8 fail-closed on callback throw).\n *\n * Signature differences vs the IncomingMessage pair:\n * - `handlePreflightRequest(request, config): Response | null` — returns\n * `Response` when this is a CORS preflight; `null` when not. Caller\n * short-circuits accordingly (same control-flow semantic as boolean).\n * - `applyCorsHeaders(request, target, config): void` — mutates a\n * `Headers` instance in place. Caller passes the headers they're\n * building for their Response.\n */\nexport interface CorsWebHandler {\n handlePreflightRequest(request: Request): Response | null\n applyCorsHeaders(request: Request, target: Headers): void\n}\n\nexport function createCorsWebHandler(config: CorsConfig): CorsWebHandler {\n const methods = (config.methods ?? DEFAULT_METHODS).slice()\n const allowedHeaders = (config.allowedHeaders ?? DEFAULT_ALLOWED_HEADERS).slice()\n const maxAge = String(config.maxAge ?? DEFAULT_MAX_AGE)\n const credentials = config.credentials === true\n\n return {\n handlePreflightRequest(request) {\n if (request.method !== 'OPTIONS') return null\n const acMethod = request.headers.get('access-control-request-method')\n if (acMethod === null || acMethod.length === 0) return null\n const origin = request.headers.get('origin')\n if (origin === null || origin.length === 0) return null\n\n if (!matchesOrigin(origin, config.origins)) {\n return new Response(null, { status: 403 })\n }\n\n // Echo matched origin only (security: never `'*'` when credentials\n // enabled — browsers reject per CORS spec).\n const headers = new Headers({\n 'Access-Control-Allow-Origin': origin,\n 'Access-Control-Allow-Methods': methods.join(', '),\n 'Access-Control-Allow-Headers': allowedHeaders.join(', '),\n 'Access-Control-Max-Age': maxAge,\n Vary: 'Origin',\n })\n if (credentials) headers.set('Access-Control-Allow-Credentials', 'true')\n return new Response(null, { status: 204, headers })\n },\n\n applyCorsHeaders(request, target) {\n const origin = request.headers.get('origin')\n if (origin === null || origin.length === 0) return\n if (!matchesOrigin(origin, config.origins)) return\n\n target.set('Access-Control-Allow-Origin', origin)\n target.set('Vary', 'Origin')\n if (credentials) target.set('Access-Control-Allow-Credentials', 'true')\n if (config.exposedHeaders !== undefined && config.exposedHeaders.length > 0) {\n target.set('Access-Control-Expose-Headers', config.exposedHeaders.join(', '))\n }\n },\n }\n}\n","// T5a.1b — Web Crypto migration. randomUUID() moved to globalThis.crypto.\n// IncomingMessage stays as a type-only import (runtime-clean — TS erases at\n// build); full IncomingMessage→Request boundary migration deferred to a\n// later T5a.1c+ slice per ADR-0028 incremental leaf-first sequence.\nimport type { IncomingMessage } from 'node:http'\n\n/**\n * Phase 7 — Observability: traceId propagation (D7).\n *\n * Extract a stable identifier from incoming requests so a single value\n * correlates the client request, every server log line, the response\n * envelope, and any downstream span. Precedence:\n *\n * 1. `traceparent` (W3C Trace Context — `00-{32-hex}-{16-hex}-{flags}`)\n * 2. `x-request-id` (Heroku / GCP / generic proxy header)\n * 3. Generated UUID (fresh per request)\n *\n * UUIDs are accepted as trace identifiers by every major vendor that\n * does not enforce strict 32-hex (Datadog, Honeycomb, Sentry, Logflare,\n * Axiom, etc). We don't need ULIDs to ship this surface.\n */\n\nexport const TRACE_HEADER = 'x-trace-id'\nexport const TRACE_PARENT_HEADER = 'traceparent'\nconst REQUEST_ID_HEADER = 'x-request-id'\n\n// W3C Trace Context: 00-<trace-id 32 hex>-<span-id 16 hex>-<flags 2 hex>\nconst TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/\n\n/**\n * Parse a W3C Trace Context `traceparent` header value. Returns the\n * 32-hex trace-id when valid (and not the reserved all-zeros), else\n * `null`.\n */\nexport function parseTraceparent(value: string): string | null {\n if (!value) return null\n const m = TRACEPARENT_RE.exec(value)\n if (!m) return null\n const traceId = m[1]\n // W3C: trace-id of all zeroes is invalid by spec\n if (/^0+$/.test(traceId)) return null\n return traceId\n}\n\n/**\n * Pick the first string value out of an IncomingMessage header. Node\n * collapses repeated headers into arrays; proxies sometimes do this for\n * `x-request-id`. Empty strings count as absent.\n */\nfunction pickHeader(value: string | string[] | undefined): string | null {\n if (Array.isArray(value)) {\n for (const v of value) {\n if (typeof v === 'string' && v.length > 0) return v\n }\n return null\n }\n if (typeof value === 'string' && value.length > 0) return value\n return null\n}\n\n/**\n * T5a.2 Phase C slice 1/2 — pure traceId resolution from pre-extracted\n * header values. Shared between IncomingMessage and Web Request wrappers.\n */\nfunction resolveTraceIdFromHeaders(traceparent: string | null, requestId: string | null): string {\n if (traceparent !== null) {\n const parsed = parseTraceparent(traceparent)\n if (parsed !== null) return parsed\n }\n if (requestId !== null) return requestId\n return globalThis.crypto.randomUUID()\n}\n\n/**\n * Resolve the request's traceId following the precedence above.\n */\nexport function extractTraceId(req: IncomingMessage): string {\n return resolveTraceIdFromHeaders(\n pickHeader(req.headers[TRACE_PARENT_HEADER]),\n pickHeader(req.headers[REQUEST_ID_HEADER]),\n )\n}\n\n/**\n * T5a.2 Phase C slice 1/2 — Web-Standards-shaped traceId resolver.\n *\n * Mirror of `extractTraceId(req: IncomingMessage)` for the Web `Request`\n * shape. Same precedence (`traceparent` → `x-request-id` → generated\n * UUID). Uses `request.headers.get(name)` (native Web `Headers` API)\n * instead of the Node indexer.\n *\n * **Multi-value note:** Web `Headers` collapses repeated headers into a\n * single comma-separated string at parse. The IncomingMessage path's\n * `pickHeader` \"first non-empty value\" semantic is naturally satisfied\n * because there's no array to pick from on the Web side — `.get()`\n * returns the comma-joined value, which for `traceparent` / `x-request-id`\n * is treated as a single string anyway (both headers are conventionally\n * single-valued).\n */\nexport function extractTraceIdFromRequest(request: Request): string {\n return resolveTraceIdFromHeaders(\n request.headers.get(TRACE_PARENT_HEADER),\n request.headers.get(REQUEST_ID_HEADER),\n )\n}\n"],"mappings":"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","names":["ctx","serverErrorToEnvelope","body","z"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/define/define-route.ts","../src/server/define/route-builder.ts","../src/server/define/define-action.ts","../src/server/define/action-builder.ts","../src/server/define/define-websocket.ts","../src/server/define/websocket-builder.ts","../src/server/define/define-middleware.ts","../src/server/define/middleware-builder.ts","../src/server/define/tool-builder.ts","../src/server/plugin-types.ts","../src/server/define/plugin-builder.ts","../src/server/define/ui-message-stream-response.ts","../src/server/define/define-channel.ts"],"sourcesContent":["import type { z } from 'zod'\n\n// T2.2 (architecture-cleanup) — RouteConfig type moved to core/contracts/\n// (canonical home per ADR-0001 v3). Re-export preserves the public path\n// `import { type RouteConfig } from 'theokit/server'`.\nexport type { RouteConfig } from '../../core/contracts/route-config.js'\n\nimport type { RouteConfig } from '../../core/contracts/route-config.js'\n\n/**\n * Define a typed HTTP route.\n * Identity function — provides type inference for route handlers.\n */\nexport function defineRoute<\n TQuery extends z.ZodType = z.ZodUndefined,\n TBody extends z.ZodType = z.ZodUndefined,\n TParams extends z.ZodType = z.ZodUndefined,\n TCtx = unknown,\n TResponse = unknown,\n>(\n config: RouteConfig<TQuery, TBody, TParams, TCtx, TResponse>,\n): RouteConfig<TQuery, TBody, TParams, TCtx, TResponse> {\n return config\n}\n","/**\n * M31 Phase 3 — `route()`, the fluent builder that replaces `defineRoute({...})`.\n *\n * Pure type-state (mirrors `tool-builder.ts`). `.query/.body/.params` set Zod schemas whose\n * `z.infer<>` flows into the handler's `ctx`; `.handler()` is required before `.build()`. `.build()`\n * delegates to the internal {@link defineRoute} (an identity fn), emitting the identical\n * `RouteConfig` — the scan/execute path is UNCHANGED (identity-shape delegation, blueprint §2).\n *\n * export const POST = route()\n * .params(z.object({ id: z.string() }))\n * .body(z.object({ text: z.string() }))\n * .handler(({ params, body }) => save(params.id, body.text))\n * .build()\n */\nimport type { z } from 'zod'\n\nimport type { RouteConfig } from '../../core/contracts/route-config.js'\n\nimport { defineRoute } from './define-route.js'\n\n/** Compile-error carrier: `.build()` called before `.handler()`. */\ninterface MissingHandlerError {\n readonly __theokitError: 'a route needs .handler(fn) before .build()'\n}\n\n/**\n * The fluent route builder. `TQuery/TBody/TParams` track the input schemas (default `z.ZodUndefined`,\n * matching {@link RouteConfig}); `TResponse` tracks the handler return; `THandlerSet` gates `.build()`.\n */\nexport interface RouteBuilder<\n TQuery extends z.ZodType = z.ZodUndefined,\n TBody extends z.ZodType = z.ZodUndefined,\n TParams extends z.ZodType = z.ZodUndefined,\n TCtx = unknown,\n TResponse = unknown,\n THandlerSet extends boolean = false,\n> {\n /** Set the URL search-params schema. Inferred into `ctx.query`. */\n query<S extends z.ZodType>(\n schema: S,\n ): RouteBuilder<S, TBody, TParams, TCtx, TResponse, THandlerSet>\n /** Set the request-body schema. Inferred into `ctx.body`. */\n body<S extends z.ZodType>(\n schema: S,\n ): RouteBuilder<TQuery, S, TParams, TCtx, TResponse, THandlerSet>\n /** Set the path-params schema. Inferred into `ctx.params`. */\n params<S extends z.ZodType>(\n schema: S,\n ): RouteBuilder<TQuery, TBody, S, TCtx, TResponse, THandlerSet>\n /** Runtime-only validation of the handler's plain-object return (500 on mismatch). Not inferred (YAGNI). */\n response(schema: z.ZodType): RouteBuilder<TQuery, TBody, TParams, TCtx, TResponse, THandlerSet>\n /** Override the HTTP status for a plain-object return (default 200; 204 for void). */\n status(code: number): RouteBuilder<TQuery, TBody, TParams, TCtx, TResponse, THandlerSet>\n /** Opt out of CSRF enforcement for this route (webhooks / OAuth callbacks). */\n csrf(disabled: false): RouteBuilder<TQuery, TBody, TParams, TCtx, TResponse, THandlerSet>\n /**\n * Set the handler. Its `ctx` infers `query/body/params` from the schemas set above. Required\n * before `.build()`.\n */\n handler<R>(\n fn: (ctx: {\n query: z.infer<TQuery>\n body: z.infer<TBody>\n params: z.infer<TParams>\n request: Request\n ctx: TCtx\n }) => R | Promise<R>,\n ): RouteBuilder<TQuery, TBody, TParams, TCtx, R, true>\n /**\n * Resolve to the `RouteConfig` — the SAME value `defineRoute({...})` returns. COMPILE ERROR when\n * `.handler()` was never called.\n */\n build(\n ...guard: THandlerSet extends true ? [] : [error: MissingHandlerError]\n ): RouteConfig<TQuery, TBody, TParams, TCtx, TResponse>\n}\n\n/**\n * Permissive internal shape — the runtime seam works with `z.ZodType` schemas (ctx fields typed\n * `unknown`); the precise per-schema types are carried to callers by the {@link RouteBuilder}\n * interface via the `as unknown as RouteBuilder` bridge. `defineRoute` is an identity fn.\n */\ntype AnyRouteConfig = RouteConfig<z.ZodType, z.ZodType, z.ZodType>\n\ninterface RouteSpecAccumulator {\n query?: z.ZodType\n body?: z.ZodType\n params?: z.ZodType\n response?: z.ZodType\n status?: number\n csrf?: false\n handler?: AnyRouteConfig['handler']\n}\n\nfunction makeRouteBuilder(spec: RouteSpecAccumulator): RouteBuilder {\n const runtime = {\n query: (schema: z.ZodType) => makeRouteBuilder({ ...spec, query: schema }),\n body: (schema: z.ZodType) => makeRouteBuilder({ ...spec, body: schema }),\n params: (schema: z.ZodType) => makeRouteBuilder({ ...spec, params: schema }),\n response: (schema: z.ZodType) => makeRouteBuilder({ ...spec, response: schema }),\n status: (code: number) => makeRouteBuilder({ ...spec, status: code }),\n csrf: (disabled: false) => makeRouteBuilder({ ...spec, csrf: disabled }),\n handler: (fn: AnyRouteConfig['handler']) => makeRouteBuilder({ ...spec, handler: fn }),\n build: (): AnyRouteConfig => {\n // Fail-fast for untyped (JS) callers — the type-state guard makes this unreachable from TS.\n if (spec.handler === undefined) {\n throw new Error('route(): call .handler(fn) before .build()')\n }\n const config: AnyRouteConfig = {\n ...(spec.query !== undefined ? { query: spec.query } : {}),\n ...(spec.body !== undefined ? { body: spec.body } : {}),\n ...(spec.params !== undefined ? { params: spec.params } : {}),\n ...(spec.response !== undefined ? { response: spec.response } : {}),\n ...(spec.status !== undefined ? { status: spec.status } : {}),\n ...(spec.csrf !== undefined ? { csrf: spec.csrf } : {}),\n handler: spec.handler,\n }\n return defineRoute(config)\n },\n }\n return runtime as unknown as RouteBuilder\n}\n\n/**\n * Start a fluent route definition. Chain `.query/.body/.params/.response/.status/.csrf` (all\n * optional), then `.handler()` (required) and `.build()` for the `RouteConfig`.\n */\nexport function route(): RouteBuilder {\n return makeRouteBuilder({})\n}\n","import type { z } from 'zod'\n\n/**\n * Action wire-protocol accept mode per plan g3-server-actions-and-useaction\n * v1.2 ADR D1. Default behavior (when omitted) is `'json'`. `'form'` opts the\n * action into FormData multipart parsing for progressive-enhancement forms;\n * the runtime in `server/http/action-execute.ts` will coerce FormData entries\n * against the `input` schema via `formDataToObject` (Astro pattern).\n */\nexport type ActionAccept = 'form' | 'json'\n\nexport interface ActionConfig<TInput extends z.ZodType, TCtx = unknown> {\n /**\n * Zod input schema. Required: every action declares its input contract via\n * Zod (architecture rule: zod-is-SSOT). The shape becomes the handler's\n * typed `input` parameter via `z.infer<TInput>`.\n */\n input: TInput\n /**\n * Wire-protocol accept mode. Defaults to `'json'` when omitted. Setting\n * `'form'` switches the runtime to FormData multipart parsing — the input\n * schema MUST be `z.object(...)` so field-by-field coercion can drive\n * boolean string / number / array coercion (Astro pattern).\n */\n accept?: ActionAccept\n /**\n * Opt OUT of CSRF enforcement for this action. Default (omitted) keeps the\n * multi-header CSRF gate active. Set `false` for endpoints intentionally\n * callable without the `X-Theo-Action` header (e.g. public webhooks). The\n * runtime in `server/http/action-execute.ts` reads this flag.\n */\n csrf?: false\n handler: (ctx: { input: z.infer<TInput>; ctx: TCtx }) => unknown\n}\n\n/**\n * Define a typed server action.\n *\n * Identity function — provides type inference for action handlers. The\n * runtime that consumes the config (validation + invocation + serialization)\n * lives in `server/http/action-execute.ts`.\n *\n * Per plan g3-server-actions-and-useaction v1.2 § Phase 1 / T1.2: the new\n * `accept?: 'form' | 'json'` field is the only contract change vs the\n * pre-G3 identity. Existing callsites (`defineAction({input, handler})`)\n * continue to compile — `accept` is opt-in.\n */\nexport function defineAction<TInput extends z.ZodType, TCtx = unknown>(\n config: ActionConfig<TInput, TCtx>,\n): ActionConfig<TInput, TCtx> {\n return config\n}\n","/**\n * M31 Phase 3 — `action()`, the fluent builder that replaces `defineAction({...})`.\n *\n * Pure type-state (mirrors `route-builder.ts`). `.input()` (required) sets the Zod schema whose\n * `z.infer<>` types the handler's `ctx.input`; `.handler()` (required) closes the chain. `.build()`\n * delegates to the internal {@link defineAction} (identity) — the action-execute path is UNCHANGED.\n *\n * export const createUser = action()\n * .input(z.object({ email: z.string().email() }))\n * .handler(({ input }) => createUser(input.email))\n * .build()\n */\nimport type { z } from 'zod'\n\nimport { defineAction, type ActionConfig, type ActionAccept } from './define-action.js'\n\n/** Compile-error carrier: `.execute`/`.build()` reached before `.input()`. */\ninterface MissingInputError {\n readonly __theokitError: 'call .input(schema) before .handler(fn)'\n}\n/** Compile-error carrier: `.build()` before both `.input()` and `.handler()` are set. */\ninterface IncompleteActionError {\n readonly __theokitError: 'an action needs .input(schema) and .handler(fn) before .build()'\n}\n\n/** A required-but-unset field. Branded so no ordinary value satisfies it (tRPC UnsetMarker). */\ntype UnsetMarker = 'theokit.unset' & { readonly __brand: 'theokit.unset' }\n\n/**\n * The fluent action builder. `TInput` tracks the Zod schema (drives `ctx.input` inference);\n * `THandlerSet` gates `.build()`.\n */\nexport interface ActionBuilder<\n TInput extends z.ZodType | UnsetMarker = UnsetMarker,\n TCtx = unknown,\n THandlerSet extends boolean = false,\n> {\n /** Set the Zod input schema. Required — every action declares its input contract (zod-is-SSOT). */\n input<S extends z.ZodType>(schema: S): ActionBuilder<S, TCtx, THandlerSet>\n /** Wire-protocol accept mode (`'json'` default, `'form'` for FormData multipart). */\n accept(mode: ActionAccept): ActionBuilder<TInput, TCtx, THandlerSet>\n /** Opt out of CSRF enforcement for this action. */\n csrf(disabled: false): ActionBuilder<TInput, TCtx, THandlerSet>\n /**\n * Set the handler. COMPILE ERROR before `.input()` — the param type collapses to\n * {@link MissingInputError}. `ctx.input` is inferred via `z.infer<TInput>`.\n */\n handler(\n fn: TInput extends z.ZodType\n ? (ctx: { input: z.infer<TInput>; ctx: TCtx }) => unknown\n : MissingInputError,\n ): ActionBuilder<TInput, TCtx, true>\n /**\n * Resolve to the `ActionConfig` — the SAME value `defineAction({...})` returns. COMPILE ERROR when\n * `.input()` or `.handler()` was never called.\n */\n build(\n ...guard: THandlerSet extends true\n ? TInput extends z.ZodType\n ? []\n : [error: IncompleteActionError]\n : [error: IncompleteActionError]\n ): ActionConfig<TInput extends z.ZodType ? TInput : z.ZodType, TCtx>\n}\n\ntype AnyActionConfig = ActionConfig<z.ZodType>\n\ninterface ActionSpecAccumulator {\n input?: z.ZodType\n accept?: ActionAccept\n csrf?: false\n handler?: AnyActionConfig['handler']\n}\n\nfunction makeActionBuilder(spec: ActionSpecAccumulator): ActionBuilder {\n const runtime = {\n input: (schema: z.ZodType) => makeActionBuilder({ ...spec, input: schema }),\n accept: (mode: ActionAccept) => makeActionBuilder({ ...spec, accept: mode }),\n csrf: (disabled: false) => makeActionBuilder({ ...spec, csrf: disabled }),\n handler: (fn: AnyActionConfig['handler']) => makeActionBuilder({ ...spec, handler: fn }),\n build: (): AnyActionConfig => {\n // Fail-fast for untyped (JS) callers — the type-state guards make this unreachable from TS.\n if (spec.input === undefined) {\n throw new Error('action(): call .input(schema) before .build()')\n }\n if (spec.handler === undefined) {\n throw new Error('action(): call .handler(fn) before .build()')\n }\n const config: AnyActionConfig = {\n input: spec.input,\n handler: spec.handler,\n ...(spec.accept !== undefined ? { accept: spec.accept } : {}),\n ...(spec.csrf !== undefined ? { csrf: spec.csrf } : {}),\n }\n return defineAction(config)\n },\n }\n return runtime as unknown as ActionBuilder\n}\n\n/**\n * Start a fluent action definition. Chain `.input()` (required), optionally `.accept()` / `.csrf()`,\n * then `.handler()` (required) and `.build()` for the `ActionConfig`.\n */\nexport function action(): ActionBuilder {\n return makeActionBuilder({})\n}\n","import type { IncomingMessage } from 'node:http'\n\nexport interface WebSocketLike {\n send(data: string | Buffer): void\n close(code?: number, reason?: string): void\n}\n\nexport interface WebSocketHandler {\n onOpen?: (ws: WebSocketLike, req: IncomingMessage) => void\n onMessage?: (ws: WebSocketLike, data: string | Buffer) => void\n onClose?: (ws: WebSocketLike, code: number, reason: Buffer) => void\n onError?: (ws: WebSocketLike, error: Error) => void\n}\n\n/**\n * Define a WebSocket endpoint handler.\n * Identity function — provides type inference for WebSocket handlers.\n */\nexport function defineWebSocket(handler: WebSocketHandler): WebSocketHandler {\n return handler\n}\n\n/**\n * T5a.2 Phase F slice 3/3 — Web-Standards WebSocket endpoint handler.\n *\n * Mirror of `WebSocketHandler` for the Web `Request` shape. `onOpen`\n * receives `request: Request` instead of `req: IncomingMessage`. The\n * rest of the lifecycle (onMessage, onClose, onError) is shape-agnostic\n * (`WebSocketLike` is already Web-standards-compatible per the existing\n * design — `send(string | Buffer)` works on both Node `ws` and Web\n * `WebSocket` instances; CF Workers / Bun / Deno coerce as needed at\n * the adapter boundary).\n *\n * Per `docs/plans/t5a2-incoming-message-to-request-shape-refactor-plan.md`\n * v1.0 § Phase F (closes Phase F).\n *\n * **Architectural note — WebSocket upgrade semantics differ across runtimes:**\n * - Node + `ws`: `WebSocketServer.handleUpgrade(req, socket, head, cb)` —\n * `req` is `IncomingMessage`. Use `WebSocketHandler`.\n * - CF Workers: `new WebSocketPair()` + `request.headers` (the upgrade\n * handshake IS a Web Request). Use `WebSocketHandlerWeb`.\n * - Bun: `server.upgrade(request, { data })` — same Web Request shape.\n * - Deno: `Deno.upgradeWebSocket(request)` — same Web Request shape.\n *\n * Cross-runtime WebSocket endpoints ship BOTH `WebSocketHandler` +\n * `WebSocketHandlerWeb` exports; the runtime adapter picks the matching\n * one. This is the canonical Hono / Nitric pattern.\n */\nexport interface WebSocketHandlerWeb {\n onOpen?: (ws: WebSocketLike, request: Request) => void\n onMessage?: (ws: WebSocketLike, data: string | Uint8Array) => void\n onClose?: (ws: WebSocketLike, code: number, reason: string) => void\n onError?: (ws: WebSocketLike, error: Error) => void\n}\n\n/**\n * Web-Standards `defineWebSocket` sibling. Identity function — provides\n * type inference for Web WebSocket handlers.\n *\n * **Type difference note vs Node path:**\n * - `onMessage` data is `string | Uint8Array` instead of `string | Buffer`\n * (Web standards have no `Buffer`; Node's Buffer is a Uint8Array\n * subclass so the Node path's Buffer values flow through unchanged\n * when adapters wrap them).\n * - `onClose` reason is `string` instead of `Buffer` (Web `CloseEvent`\n * exposes the reason as a UTF-8 string natively).\n */\nexport function defineWebSocketWeb(handler: WebSocketHandlerWeb): WebSocketHandlerWeb {\n return handler\n}\n","/**\n * M31 Phase 3 — `websocket()`, the fluent builder that replaces `defineWebSocket({...})`.\n *\n * Lifecycle setters (`onOpen/onMessage/onClose/onError`), all optional; `.build()` delegates to the\n * internal {@link defineWebSocket} (identity) — the ws handler loading path is UNCHANGED.\n *\n * export default websocket()\n * .onOpen((ws) => ws.send('hi'))\n * .onMessage((ws, data) => ws.send(`echo:${data}`))\n * .build()\n */\nimport { defineWebSocket, type WebSocketHandler } from './define-websocket.js'\n\n/** The fluent WebSocket builder. Each lifecycle hook is optional; `.build()` returns the handler. */\nexport interface WebSocketBuilder {\n onOpen(fn: NonNullable<WebSocketHandler['onOpen']>): WebSocketBuilder\n onMessage(fn: NonNullable<WebSocketHandler['onMessage']>): WebSocketBuilder\n onClose(fn: NonNullable<WebSocketHandler['onClose']>): WebSocketBuilder\n onError(fn: NonNullable<WebSocketHandler['onError']>): WebSocketBuilder\n /** Resolve to the `WebSocketHandler` — the SAME value `defineWebSocket({...})` returns. */\n build(): WebSocketHandler\n}\n\nfunction makeWebSocketBuilder(spec: WebSocketHandler): WebSocketBuilder {\n const runtime: WebSocketBuilder = {\n onOpen: (fn) => makeWebSocketBuilder({ ...spec, onOpen: fn }),\n onMessage: (fn) => makeWebSocketBuilder({ ...spec, onMessage: fn }),\n onClose: (fn) => makeWebSocketBuilder({ ...spec, onClose: fn }),\n onError: (fn) => makeWebSocketBuilder({ ...spec, onError: fn }),\n build: () => defineWebSocket(spec),\n }\n return runtime\n}\n\n/** Start a fluent WebSocket definition. Chain any of the lifecycle hooks, then `.build()`. */\nexport function websocket(): WebSocketBuilder {\n return makeWebSocketBuilder({})\n}\n","export type MiddlewareHandler = (\n request: Request,\n next: (request: Request) => Promise<Response>,\n) => Response | Promise<Response>\n\n/**\n * Define a middleware handler.\n * Identity function — provides type annotation for middleware.\n */\nexport function defineMiddleware(handler: MiddlewareHandler): MiddlewareHandler {\n return handler\n}\n","/**\n * M31 Phase 3 — `middleware()`, the fluent builder that replaces `defineMiddleware(fn)`.\n *\n * A middleware IS a single function `(request, next) => Response`. The builder's `.handle()` sets it\n * (required); `.build()` delegates to the internal {@link defineMiddleware} (identity) and returns\n * the handler the runtime expects.\n *\n * export default middleware()\n * .handle(async (request, next) => {\n * const res = await next(request)\n * res.headers.set('x-mw', '1')\n * return res\n * })\n * .build()\n */\nimport { defineMiddleware, type MiddlewareHandler } from './define-middleware.js'\n\n/** Compile-error carrier: `.build()` called before `.handle()`. */\ninterface MissingHandleError {\n readonly __theokitError: 'middleware needs .handle(fn) before .build()'\n}\n\n/** The fluent middleware builder. `THandleSet` gates `.build()`. */\nexport interface MiddlewareBuilder<THandleSet extends boolean = false> {\n /** Set the `(request, next) => Response` handler. Required before `.build()`. */\n handle(fn: MiddlewareHandler): MiddlewareBuilder<true>\n /** Resolve to the `MiddlewareHandler`. COMPILE ERROR when `.handle()` was never called. */\n build(...guard: THandleSet extends true ? [] : [error: MissingHandleError]): MiddlewareHandler\n}\n\nfunction makeMiddlewareBuilder(fn: MiddlewareHandler | undefined): MiddlewareBuilder {\n const runtime = {\n handle: (handler: MiddlewareHandler) => makeMiddlewareBuilder(handler),\n build: (): MiddlewareHandler => {\n // Fail-fast for untyped (JS) callers — the type-state guard makes this unreachable from TS.\n if (fn === undefined) {\n throw new Error('middleware(): call .handle(fn) before .build()')\n }\n return defineMiddleware(fn)\n },\n }\n return runtime as unknown as MiddlewareBuilder\n}\n\n/** Start a fluent middleware definition. Chain `.handle()` (required), then `.build()`. */\nexport function middleware(): MiddlewareBuilder {\n return makeMiddlewareBuilder(undefined)\n}\n","/**\n * M31 Phase 1 — `tool()`, the fluent builder that replaces `defineAgentTool({...})`.\n *\n * Pure type-state (tRPC `UnsetMarker` technique, mirroring `agent-builder.ts`). The runtime is a\n * plain accumulator; `.build()` delegates to the internal {@link defineAgentTool}, so the emitted\n * `CustomTool` is byte-for-byte the legacy shape — the SDK/agent compile path is UNCHANGED\n * (identity-shape delegation, blueprint §2).\n *\n * PURE metadata (G2 / sdk-runtime.md): a tool describes a capability; it NEVER calls an LLM.\n *\n * tool('read')\n * .describe('Read a UTF-8 file')\n * .input(z.object({ path: z.string() }))\n * .execute(async ({ path }, ctx) => readFile(resolveInProject(ctx, path)))\n * .build()\n */\nimport type { z } from 'zod'\n\nimport { defineAgentTool, type CustomTool, type ToolTransform } from './define-agent-tool.js'\n\n/** A required-but-unset builder field. Branded so no ordinary value satisfies it (tRPC UnsetMarker). */\ntype UnsetMarker = 'theokit.unset' & { readonly __brand: 'theokit.unset' }\n\n/** Compile-error carrier: `.execute()` called before `.input()`. */\ninterface MissingInputError {\n readonly __theokitError: 'call .input(schema) before .execute(handler)'\n}\n/** Compile-error carrier: `.build()` called before both `.input()` and `.execute()` are set. */\ninterface IncompleteToolError {\n readonly __theokitError: 'a tool needs .input(schema) and .execute(handler) before .build()'\n}\n\n/** The run context a tool handler receives (M7). */\ninterface ToolCtx {\n signal?: AbortSignal\n context?: unknown\n}\n\n/**\n * The fluent tool builder. Each method returns a NEW builder type with the relevant type parameter\n * advanced. `TInput` tracks the Zod schema (drives `execute` input inference); `R` tracks the\n * handler result; `THandlerSet` gates `.build()`.\n */\nexport interface ToolBuilder<\n TName extends string = string,\n TInput extends z.ZodType | UnsetMarker = UnsetMarker,\n R = string,\n THandlerSet extends boolean = false,\n> {\n /** Set the LLM-facing description. Optional; an empty description warns at build (LLM selection). */\n describe(description: string): ToolBuilder<TName, TInput, R, THandlerSet>\n /** Set the Zod input schema (must be `z.object(...)` at the root). Required before `.execute()`. */\n input<S extends z.ZodType>(schema: S): ToolBuilder<TName, S, R, THandlerSet>\n /**\n * Set the handler. COMPILE ERROR when `.input()` was not called first — the parameter type\n * collapses to {@link MissingInputError}. The `input` argument is inferred via `z.infer<TInput>`.\n */\n execute<R2>(\n handler: TInput extends z.ZodType\n ? (input: z.infer<TInput>, ctx?: ToolCtx) => R2 | Promise<R2>\n : MissingInputError,\n ): ToolBuilder<TName, TInput, R2, true>\n /** M18 — map a rich handler result to the model-visible string. */\n toModelOutput(fn: (result: R) => string): ToolBuilder<TName, TInput, R, THandlerSet>\n /** M18 — per-target formatters (`display` / `transcript`) for the app UI/transcript. */\n transform(t: ToolTransform<R>): ToolBuilder<TName, TInput, R, THandlerSet>\n /**\n * Resolve to the `CustomTool` — the SAME value `defineAgentTool({...})` returns. COMPILE ERROR\n * when `.input()` or `.execute()` was never called.\n */\n build(\n ...guard: THandlerSet extends true\n ? TInput extends z.ZodType\n ? []\n : [error: IncompleteToolError]\n : [error: IncompleteToolError]\n ): CustomTool\n}\n\ninterface ToolSpecAccumulator {\n name: string\n description?: string\n inputSchema?: z.ZodType\n handler?: (input: unknown, ctx?: ToolCtx) => unknown\n toModelOutput?: (result: unknown) => string\n transform?: ToolTransform\n}\n\n/**\n * Build the runtime accumulator. The public method signatures carry the type-state generics + the\n * compile-time guards; the runtime cannot track generics, so the object is bridged to the typed\n * interface once here (the single, documented type-state impl seam — same technique as agent-builder).\n */\nfunction makeToolBuilder(spec: ToolSpecAccumulator): ToolBuilder {\n const runtime = {\n describe: (description: string) => makeToolBuilder({ ...spec, description }),\n input: (schema: z.ZodType) => makeToolBuilder({ ...spec, inputSchema: schema }),\n execute: (handler: (input: unknown, ctx?: ToolCtx) => unknown) =>\n makeToolBuilder({ ...spec, handler }),\n toModelOutput: (fn: (result: unknown) => string) =>\n makeToolBuilder({ ...spec, toModelOutput: fn }),\n transform: (t: ToolTransform) => makeToolBuilder({ ...spec, transform: t }),\n build: (): CustomTool => {\n // Fail-fast: the type-state guards make these unreachable from typed callers, but an untyped\n // (JS) caller could skip them — surface a clear error instead of a confusing downstream one.\n if (spec.inputSchema === undefined) {\n throw new Error(`tool(${JSON.stringify(spec.name)}): call .input(schema) before .build()`)\n }\n if (spec.handler === undefined) {\n throw new Error(\n `tool(${JSON.stringify(spec.name)}): call .execute(handler) before .build()`,\n )\n }\n return defineAgentTool({\n name: spec.name,\n description: spec.description ?? '',\n inputSchema: spec.inputSchema,\n handler: spec.handler,\n ...(spec.toModelOutput !== undefined ? { toModelOutput: spec.toModelOutput } : {}),\n ...(spec.transform !== undefined ? { transform: spec.transform } : {}),\n })\n },\n }\n return runtime as unknown as ToolBuilder\n}\n\n/**\n * Start a fluent tool definition. Chain `.input()` + `.execute()` (both required), optionally\n * `.describe()` / `.toModelOutput()` / `.transform()`, then `.build()` for the `CustomTool`.\n */\nexport function tool<TName extends string>(name: TName): ToolBuilder<TName> {\n return makeToolBuilder({ name })\n}\n","import type { ServerResponse } from 'node:http'\n\nexport interface PluginContext {\n /**\n * The incoming request as a Web `Request` — the same shape a plugin hook sees on the edge adapters\n * (`WebPluginContext.request`), so a hook that reads `request.headers.get(...)` / `request.url` /\n * `request.method` is portable across `theokit dev` / `theokit start` (Node) and Web runtimes (#119,\n * ADR-0028 R3a). Method + absolute URL + headers; the request body is not exposed here (onRequest /\n * preHandler fire before the body is parsed — the handler reads it via `ctx.body`).\n */\n request: Request\n response: ServerResponse\n ctx: Record<string, unknown>\n requestId: string\n}\n\nexport interface PluginErrorContext extends PluginContext {\n error: unknown\n}\n\nexport interface RunHookOptions {\n inErrorPath?: boolean\n}\n\nexport interface HookResult {\n shortCircuited: boolean\n}\n\nexport type OnRequestHook = (ctx: PluginContext) => void | Promise<void>\nexport type PreHandlerHook = (ctx: PluginContext) => void | Promise<void>\nexport type OnResponseHook = (ctx: PluginContext) => void | Promise<void>\nexport type OnErrorHook = (ctx: PluginErrorContext) => void | Promise<void>\n\nexport type HookName = 'onRequest' | 'preHandler' | 'onResponse' | 'onError'\n\nexport type HookByName<K extends HookName> = K extends 'onError'\n ? OnErrorHook\n : K extends 'onRequest'\n ? OnRequestHook\n : K extends 'preHandler'\n ? PreHandlerHook\n : K extends 'onResponse'\n ? OnResponseHook\n : never\n\nexport interface TheoApp {\n addHook<K extends HookName>(name: K, fn: HookByName<K>): void\n // `T` lets plugin authors document the per-key shape of decorations.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- T documents the value type for plugin authors\n decorateRequest<T>(key: string, value: T): void\n}\n\nexport interface TheoPlugin {\n name: string\n register(app: TheoApp): void | Promise<void>\n}\n\n/**\n * Identity function for plugin authors. Provides auto-completion + type\n * inference at the call site (TanStack/Vite/Astro pattern). Pure runtime\n * no-op — returns the input unchanged.\n *\n * @example\n * import { definePlugin } from 'theokit/server'\n * export default definePlugin({\n * name: 'my-plugin',\n * register(app) {\n * app.addHook('onRequest', (req) => { ... })\n * },\n * })\n *\n * Equivalent to `const p: TheoPlugin = {...}` but more ergonomic. See\n * ADR-0008 (D1 + D6) for the rationale.\n */\nexport function definePlugin(plugin: TheoPlugin): TheoPlugin {\n return plugin\n}\n\n// ===== T5a.2 Phase F slice 1/3 — Web-Standards plugin context types =====\n//\n// Mirror of the IncomingMessage/ServerResponse-shaped `PluginContext` for\n// the Web `Request`/`Headers` shape. Per `docs/plans/t5a2-incoming-message-\n// to-request-shape-refactor-plan.md` v1.0 § Phase F.\n//\n// **Key difference vs IncomingMessage path:** the Web path has no\n// `ServerResponse` to mutate. Plugins instead get a `responseHeaders: Headers`\n// instance they can append to (e.g., add Set-Cookie, CORS headers) and the\n// runtime composes the final `Response` after the hook chain runs. The\n// `response` object (if any) is the in-flight Response constructed by the\n// handler — present only during `onResponse` / `onError` hooks AFTER the\n// handler returned, NOT during `onRequest` / `preHandler` (which fire BEFORE\n// the handler runs).\n//\n// This split mirrors Hono's `c.res` + Fastify's `reply.headers` semantics\n// — plugins mutate headers freely; the body is the handler's responsibility.\n\n/**\n * Web-Standards plugin context. Available during all 4 hook lifecycle\n * stages (onRequest, preHandler, onResponse, onError).\n *\n * - `request` — the incoming Web Request (read-only at the runtime level;\n * plugins can call `request.headers.get()`, `request.clone()`, etc.).\n * - `responseHeaders` — a mutable `Headers` instance the runtime threads\n * through the hook chain. Plugins append (e.g., CORS, Set-Cookie); the\n * final Response composes these.\n * - `response` — set to the handler's Response AFTER the handler returns.\n * Available during `onResponse` / `onError`. `undefined` during\n * `onRequest` / `preHandler` (which fire before the handler runs).\n * - `ctx` / `requestId` — same semantics as the IncomingMessage path.\n */\nexport interface WebPluginContext {\n request: Request\n responseHeaders: Headers\n response?: Response\n ctx: Record<string, unknown>\n requestId: string\n}\n\nexport interface WebPluginErrorContext extends WebPluginContext {\n error: unknown\n}\n\nexport type WebOnRequestHook = (ctx: WebPluginContext) => void | Promise<void>\nexport type WebPreHandlerHook = (ctx: WebPluginContext) => void | Promise<void>\nexport type WebOnResponseHook = (ctx: WebPluginContext) => void | Promise<void>\nexport type WebOnErrorHook = (ctx: WebPluginErrorContext) => void | Promise<void>\n\nexport type WebHookByName<K extends HookName> = K extends 'onError'\n ? WebOnErrorHook\n : K extends 'onRequest'\n ? WebOnRequestHook\n : K extends 'preHandler'\n ? WebPreHandlerHook\n : K extends 'onResponse'\n ? WebOnResponseHook\n : never\n\n/**\n * Web-Standards `TheoApp` facade. Same `addHook` + `decorateRequest`\n * surface as the IncomingMessage path; only the hook function signatures\n * differ (they receive `WebPluginContext` instead of `PluginContext`).\n *\n * Plugin authors who target both shapes can branch on the context type\n * via a type guard (`'responseHeaders' in ctx`) OR ship two separate\n * `register()` exports — one for each runtime adapter. Most plugins\n * register hooks at the IncomingMessage path today (legacy); future\n * Web-native plugins will register against `WebTheoApp`.\n */\nexport interface WebTheoApp {\n addHook<K extends HookName>(name: K, fn: WebHookByName<K>): void\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- T documents the value type for plugin authors\n decorateRequest<T>(key: string, value: T): void\n}\n\n/**\n * Web-Standards plugin shape. Identical to `TheoPlugin` except the\n * `register(app)` argument is `WebTheoApp` instead of `TheoApp`.\n *\n * Cross-runtime plugins ship BOTH `TheoPlugin` + `WebTheoPlugin` exports;\n * the adapter (Node, CF Workers, Bun, Deno) picks the matching one based\n * on which runtime executes the plugin chain. This is the canonical\n * Hono/Nitro pattern.\n */\nexport interface WebTheoPlugin {\n name: string\n register(app: WebTheoApp): void | Promise<void>\n}\n\n/**\n * Identity function for Web plugin authors — same auto-completion +\n * type-inference DX as `definePlugin`, but for the Web-shaped `WebTheoApp`.\n */\nexport function defineWebPlugin(plugin: WebTheoPlugin): WebTheoPlugin {\n return plugin\n}\n","/**\n * M31 Phase 3 — `plugin()`, the fluent builder that replaces `definePlugin({...})`.\n *\n * Collects lifecycle hooks + request decorations and SYNTHESIZES the `register(app)` function, so\n * authors never write the imperative `register` body. `.build()` returns a `TheoPlugin` the plugin\n * runner consumes UNCHANGED.\n *\n * export default plugin('request-id')\n * .onRequest((ctx) => { ctx.ctx.requestId = crypto.randomUUID() })\n * .onResponse((ctx) => { ctx.response.setHeader('x-request-id', String(ctx.ctx.requestId)) })\n * .build()\n */\nimport {\n definePlugin,\n type TheoPlugin,\n type TheoApp,\n type OnRequestHook,\n type PreHandlerHook,\n type OnResponseHook,\n type OnErrorHook,\n} from '../plugin-types.js'\n\n/** The fluent plugin builder. `name` is set at entry; every hook is optional and may repeat. */\nexport interface PluginBuilder {\n /** Register an `onRequest` hook (runs before the CSRF gate). May be called multiple times. */\n onRequest(fn: OnRequestHook): PluginBuilder\n /** Register a `preHandler` hook (after CSRF, before the route handler). */\n preHandler(fn: PreHandlerHook): PluginBuilder\n /** Register an `onResponse` hook (after the handler returns). */\n onResponse(fn: OnResponseHook): PluginBuilder\n /** Register an `onError` hook (error path). */\n onError(fn: OnErrorHook): PluginBuilder\n /** Decorate every request with a key/value pair (available on `ctx.ctx[key]`). */\n decorateRequest<T>(key: string, value: T): PluginBuilder\n /** Resolve to the `TheoPlugin` — a synthesized `{ name, register }` the runner consumes. */\n build(): TheoPlugin\n}\n\ninterface PluginSpecAccumulator {\n name: string\n onRequest: OnRequestHook[]\n preHandler: PreHandlerHook[]\n onResponse: OnResponseHook[]\n onError: OnErrorHook[]\n decorations: { key: string; value: unknown }[]\n}\n\nfunction makePluginBuilder(spec: PluginSpecAccumulator): PluginBuilder {\n const runtime: PluginBuilder = {\n onRequest: (fn) => makePluginBuilder({ ...spec, onRequest: [...spec.onRequest, fn] }),\n preHandler: (fn) => makePluginBuilder({ ...spec, preHandler: [...spec.preHandler, fn] }),\n onResponse: (fn) => makePluginBuilder({ ...spec, onResponse: [...spec.onResponse, fn] }),\n onError: (fn) => makePluginBuilder({ ...spec, onError: [...spec.onError, fn] }),\n decorateRequest: (key, value) =>\n makePluginBuilder({ ...spec, decorations: [...spec.decorations, { key, value }] }),\n build: () =>\n definePlugin({\n name: spec.name,\n register(app: TheoApp): void {\n for (const fn of spec.onRequest) app.addHook('onRequest', fn)\n for (const fn of spec.preHandler) app.addHook('preHandler', fn)\n for (const fn of spec.onResponse) app.addHook('onResponse', fn)\n for (const fn of spec.onError) app.addHook('onError', fn)\n for (const d of spec.decorations) app.decorateRequest(d.key, d.value)\n },\n }),\n }\n return runtime\n}\n\n/** Start a fluent plugin definition. `name` is required; chain hooks/decorations, then `.build()`. */\nexport function plugin(name: string): PluginBuilder {\n return makePluginBuilder({\n name,\n onRequest: [],\n preHandler: [],\n onResponse: [],\n onError: [],\n decorations: [],\n })\n}\n","import type { UIMessageChunk } from 'ai'\n\n/**\n * M0 (theokit-ai-first) — serialize a stream of ai-sdk `UIMessageChunk`s into a\n * Web-Standards `Response` on the UIMessageStream wire so `@ai-sdk/react`'s\n * `useChat` consumes it WITHOUT a custom adapter.\n *\n * Wire contract (must match ai-sdk's consumer transport exactly):\n * - `content-type: text/event-stream`\n * - `x-vercel-ai-ui-message-stream: v1` — the version marker `useChat` checks\n * - each chunk framed as `data: ${JSON.stringify(chunk)}\\n\\n`\n * - a terminal `data: [DONE]\\n\\n` after the last chunk (ignored by the parser)\n *\n * Web Standards only — `Response` + `ReadableStream` (G8, no node:http). The\n * headers commit before the stream starts.\n *\n * Fail-clear (error-handling.md): if the source iterable throws mid-stream, the\n * `[DONE]` terminal is still flushed and the stream is closed — never left\n * hanging. (The translator upstream already closes gracefully; this is defense\n * in depth for any other chunk source.)\n */\nconst UI_MESSAGE_STREAM_HEADERS = {\n 'content-type': 'text/event-stream',\n 'x-vercel-ai-ui-message-stream': 'v1',\n} as const\n\nconst DONE_FRAME = 'data: [DONE]\\n\\n'\n\nfunction encode(text: string): Uint8Array {\n return new TextEncoder().encode(text)\n}\n\nexport function uiMessageStreamResponse(chunks: AsyncIterable<UIMessageChunk>): Response {\n const stream = new ReadableStream<Uint8Array>({\n async start(controller) {\n try {\n for await (const chunk of chunks) {\n controller.enqueue(encode(`data: ${JSON.stringify(chunk)}\\n\\n`))\n }\n } catch {\n // The source iterable aborted mid-stream. The upstream translator owns\n // error semantics (it surfaces failures as chunks + closes gracefully);\n // this transport's sole guarantee is a terminated stream — fall through\n // to the DONE terminal rather than re-throw and error an open stream.\n } finally {\n controller.enqueue(encode(DONE_FRAME))\n controller.close()\n }\n },\n })\n return new Response(stream, { headers: UI_MESSAGE_STREAM_HEADERS })\n}\n","import type { IncomingMessage } from 'node:http'\n\nimport type { WebSocketLike } from './define-websocket.js'\n\nexport interface ChannelHandler<TMessage = unknown> {\n onSubscribe?: (ws: WebSocketLike, room: string, req: IncomingMessage) => void\n onMessage?: (ws: WebSocketLike, room: string, data: TMessage) => void\n onUnsubscribe?: (ws: WebSocketLike, room: string) => void\n}\n\n/**\n * Define a channel handler for WebSocket rooms.\n * Identity function — provides type inference for channel handlers.\n */\nexport function defineChannel<TMessage = unknown>(\n handler: ChannelHandler<TMessage>,\n): ChannelHandler<TMessage> {\n return handler\n}\n\n/**\n * T5a.2 Phase F slice 2/3 — Web-Standards channel handler.\n *\n * Mirror of `ChannelHandler<TMessage>` for the Web `Request` shape.\n * `onSubscribe` receives `request: Request` instead of `req: IncomingMessage`\n * — the rest of the surface (onMessage, onUnsubscribe) is shape-agnostic\n * (WebSocketLike is already Web-standards-compatible per `define-websocket.ts`).\n *\n * Per `docs/plans/t5a2-incoming-message-to-request-shape-refactor-plan.md`\n * v1.0 § Phase F.\n *\n * **Architectural note:** WebSocket upgrade semantics differ across\n * runtimes:\n * - Node: `WebSocketServer.handleUpgrade(req, socket, head, cb)` —\n * hands you `req: IncomingMessage` at the upgrade handshake.\n * - CF Workers: `new WebSocketPair()` + `request.headers` (the upgrade\n * handshake IS a Web Request) — hands you `request: Request`.\n * - Bun: `server.upgrade(request, { data })` — same Web Request shape.\n * - Deno: `Deno.upgradeWebSocket(request)` — same Web Request shape.\n *\n * Channel handlers targeting CF/Bun/Deno use `WebChannelHandler`; legacy\n * Node consumers stay on `ChannelHandler`. Cross-runtime channels ship\n * both shapes.\n */\nexport interface WebChannelHandler<TMessage = unknown> {\n onSubscribe?: (ws: WebSocketLike, room: string, request: Request) => void\n onMessage?: (ws: WebSocketLike, room: string, data: TMessage) => void\n onUnsubscribe?: (ws: WebSocketLike, room: string) => void\n}\n\n/**\n * Web-Standards `defineChannel` sibling. Identity function — provides\n * type inference for Web channel handlers.\n */\nexport function defineWebChannel<TMessage = unknown>(\n handler: WebChannelHandler<TMessage>,\n): WebChannelHandler<TMessage> {\n return handler\n}\n"],"mappings":"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","names":["plugin"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/scan/module-loader.ts"],"sourcesContent":["import { pathToFileURL } from 'node:url'\n\nimport type { ViteDevServer } from 'vite'\n\nexport type LoadModule = (path: string) => Promise<Record<string, unknown>>\n\nexport function createViteLoader(vite: ViteDevServer): LoadModule {\n return (path) => vite.ssrLoadModule(path) as Promise<Record<string, unknown>>\n}\n\nexport function createProductionLoader(): LoadModule {\n return async (path) => {\n const url = pathToFileURL(path).href\n return import(url) as Promise<Record<string, unknown>>\n }\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAMvB,SAAS,iBAAiB,MAAiC;AAChE,SAAO,CAAC,SAAS,KAAK,cAAc,IAAI;AAC1C;AAEO,SAAS,yBAAqC;AACnD,SAAO,OAAO,SAAS;AACrB,UAAM,MAAM,cAAc,IAAI,EAAE;AAChC,WAAO,OAAO;AAAA,EAChB;AACF;","names":[]}
|