theokit 0.48.14 → 0.50.1
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/README.md +1 -0
- package/dist/{actions-virtual-module-YZRZMHAX.js → actions-virtual-module-DSIVNGK7.js} +14 -8
- package/dist/{actions-virtual-module-YZRZMHAX.js.map → actions-virtual-module-DSIVNGK7.js.map} +1 -1
- package/dist/{actions-virtual-module-E4PISKMB.js → actions-virtual-module-RXL2RJTW.js} +23 -12
- package/dist/actions-virtual-module-RXL2RJTW.js.map +1 -0
- package/dist/adapters/agent-mount.d.ts +127 -0
- package/dist/adapters/agent-mount.js +25 -0
- package/dist/adapters/security-headers.d.ts +132 -0
- package/dist/adapters/security-headers.js +64 -0
- package/dist/adapters/security-headers.js.map +1 -0
- package/dist/adapters/web-shim.d.ts +100 -13
- package/dist/adapters/web-shim.js +158 -54
- package/dist/adapters/web-shim.js.map +1 -1
- package/dist/agent-7IPEVCAY.js +15 -0
- package/dist/agent-scan-BZa-pagG.d.ts +16 -0
- package/dist/{app-typed-client-I4X2UJWW.js → app-typed-client-UTBMJZOE.js} +15 -9
- package/dist/app-typed-client-UTBMJZOE.js.map +1 -0
- package/dist/{app-typed-client-HLP26EYM.js → app-typed-client-XGDZKH73.js} +24 -13
- package/dist/app-typed-client-XGDZKH73.js.map +1 -0
- package/dist/aws-lambda-VKMYUMP2.js +261 -0
- package/dist/aws-lambda-VKMYUMP2.js.map +1 -0
- package/dist/{body-parser-web-4Z2QTPDU.js → body-parser-web-ON5CUTEL.js} +5 -2
- package/dist/body-parser-web-ON5CUTEL.js.map +1 -0
- package/dist/{body-parser-web-TIOTXPDW.js → body-parser-web-RV2SSAI3.js} +5 -2
- package/dist/body-parser-web-RV2SSAI3.js.map +1 -0
- package/dist/{build-F2Q5QTSC.js → build-VZODSYIQ.js} +72 -26
- package/dist/build-VZODSYIQ.js.map +1 -0
- package/dist/{bun-A5B2MJMO.js → bun-L7PP6ID5.js} +105 -13
- package/dist/bun-L7PP6ID5.js.map +1 -0
- package/dist/{check-45NKUVSQ.js → check-GIPZBFTX.js} +2 -2
- package/dist/{chunk-WYHYOYRH.js → chunk-2COPDKIG.js} +468 -203
- package/dist/chunk-2COPDKIG.js.map +1 -0
- package/dist/chunk-3PBAN2YE.js +146 -0
- package/dist/chunk-3PBAN2YE.js.map +1 -0
- package/dist/{chunk-HBU2GIMZ.js → chunk-3QPVEJ7D.js} +15 -9
- package/dist/chunk-3QPVEJ7D.js.map +1 -0
- package/dist/{chunk-IEES3CHD.js → chunk-47MM2JUK.js} +8 -2
- package/dist/chunk-47MM2JUK.js.map +1 -0
- package/dist/chunk-4X6H2BXP.js +108 -0
- package/dist/chunk-4X6H2BXP.js.map +1 -0
- package/dist/{chunk-A7JBF5FO.js → chunk-5K4TDLRG.js} +8 -5
- package/dist/chunk-5K4TDLRG.js.map +1 -0
- package/dist/chunk-5YPXXSYY.js +181 -0
- package/dist/chunk-5YPXXSYY.js.map +1 -0
- package/dist/{chunk-YGAXV5HR.js → chunk-6J4JWHDJ.js} +191 -112
- package/dist/chunk-6J4JWHDJ.js.map +1 -0
- package/dist/{chunk-FTFN4MYN.js → chunk-7AEBH52I.js} +639 -516
- package/dist/chunk-7AEBH52I.js.map +1 -0
- package/dist/chunk-7UZZHCRN.js +21 -0
- package/dist/chunk-7UZZHCRN.js.map +1 -0
- package/dist/{chunk-MTEWLGVY.js → chunk-BPYMC7SU.js} +4 -48
- package/dist/chunk-BPYMC7SU.js.map +1 -0
- package/dist/chunk-BU6RJPPJ.js +421 -0
- package/dist/chunk-BU6RJPPJ.js.map +1 -0
- package/dist/{chunk-FB2HBNIC.js → chunk-BX6EUYHU.js} +6 -2
- package/dist/chunk-BX6EUYHU.js.map +1 -0
- package/dist/chunk-CHTAWXC2.js +18 -0
- package/dist/chunk-CHTAWXC2.js.map +1 -0
- package/dist/chunk-D4VP2QPR.js +16 -0
- package/dist/chunk-D4VP2QPR.js.map +1 -0
- package/dist/{chunk-YXG2SGQ3.js → chunk-DHAD2O3S.js} +6 -6
- package/dist/chunk-DHAD2O3S.js.map +1 -0
- package/dist/chunk-DOI4G4X3.js +428 -0
- package/dist/chunk-DOI4G4X3.js.map +1 -0
- package/dist/chunk-E43VJ3E5.js +188 -0
- package/dist/chunk-E43VJ3E5.js.map +1 -0
- package/dist/{chunk-47CINLWF.js → chunk-EDWEYQRG.js} +2 -2
- package/dist/chunk-EVZKNA2W.js +110 -0
- package/dist/chunk-EVZKNA2W.js.map +1 -0
- package/dist/chunk-FD4ZDTQ6.js +181 -0
- package/dist/chunk-FD4ZDTQ6.js.map +1 -0
- package/dist/chunk-FDOOBTXJ.js +17 -0
- package/dist/chunk-FDOOBTXJ.js.map +1 -0
- package/dist/chunk-FH3SQR6P.js +275 -0
- package/dist/chunk-FH3SQR6P.js.map +1 -0
- package/dist/{chunk-T5C46IIU.js → chunk-FMTRNQQ7.js} +28 -269
- package/dist/chunk-FMTRNQQ7.js.map +1 -0
- package/dist/chunk-H53KNS6Q.js +513 -0
- package/dist/chunk-H53KNS6Q.js.map +1 -0
- package/dist/chunk-HJHGTFEJ.js +23 -0
- package/dist/chunk-HJHGTFEJ.js.map +1 -0
- package/dist/{chunk-LXAESF4Y.js → chunk-HK4AZBKX.js} +7 -4
- package/dist/chunk-HK4AZBKX.js.map +1 -0
- package/dist/chunk-IRQGAC4L.js +52 -0
- package/dist/chunk-IRQGAC4L.js.map +1 -0
- package/dist/{chunk-FNTLKHZ7.js → chunk-JDN5SAAD.js} +7 -4
- package/dist/chunk-JDN5SAAD.js.map +1 -0
- package/dist/{chunk-XALU5LCU.js → chunk-JKF25N73.js} +555 -147
- package/dist/chunk-JKF25N73.js.map +1 -0
- package/dist/{chunk-BHOTGS7N.js → chunk-KI4DOTN4.js} +25 -2
- package/dist/chunk-KI4DOTN4.js.map +1 -0
- package/dist/chunk-KOS567NB.js +790 -0
- package/dist/chunk-KOS567NB.js.map +1 -0
- package/dist/{chunk-OOBYPCZC.js → chunk-KTS6G26H.js} +304 -195
- package/dist/chunk-KTS6G26H.js.map +1 -0
- package/dist/{chunk-ZB7D62OA.js → chunk-KUZVRJ7M.js} +3 -3
- package/dist/chunk-L4VFNFDL.js +248 -0
- package/dist/chunk-L4VFNFDL.js.map +1 -0
- package/dist/chunk-M2WC5MF7.js +127 -0
- package/dist/chunk-M2WC5MF7.js.map +1 -0
- package/dist/chunk-N42ZWWOW.js +273 -0
- package/dist/chunk-N42ZWWOW.js.map +1 -0
- package/dist/chunk-OGLS76RN.js +43 -0
- package/dist/chunk-OGLS76RN.js.map +1 -0
- package/dist/{chunk-7LVM22VG.js → chunk-OQCRCXCP.js} +6 -6
- package/dist/chunk-OQCRCXCP.js.map +1 -0
- package/dist/{chunk-OLGPYOLO.js → chunk-P6OS7652.js} +5 -2
- package/dist/chunk-P6OS7652.js.map +1 -0
- package/dist/{chunk-O3JIAU3V.js → chunk-PF3YM6NY.js} +157 -103
- package/dist/chunk-PF3YM6NY.js.map +1 -0
- package/dist/{chunk-NTWNO24W.js → chunk-PLUHPNGA.js} +266 -110
- package/dist/chunk-PLUHPNGA.js.map +1 -0
- package/dist/chunk-Q5L5EGWZ.js +26 -0
- package/dist/chunk-Q5L5EGWZ.js.map +1 -0
- package/dist/{chunk-AATSV4UV.js → chunk-QTHVHNJJ.js} +6 -36
- package/dist/chunk-QTHVHNJJ.js.map +1 -0
- package/dist/{chunk-KD5G3YXI.js → chunk-RARK7JBR.js} +39 -10
- package/dist/chunk-RARK7JBR.js.map +1 -0
- package/dist/chunk-RJJF457I.js +111 -0
- package/dist/chunk-RJJF457I.js.map +1 -0
- package/dist/chunk-RPET332G.js +84 -0
- package/dist/chunk-RPET332G.js.map +1 -0
- package/dist/{chunk-646CA6RV.js → chunk-RQW5YMH7.js} +12 -4
- package/dist/chunk-RQW5YMH7.js.map +1 -0
- package/dist/chunk-U5PWXS3J.js +39 -0
- package/dist/chunk-U5PWXS3J.js.map +1 -0
- package/dist/{chunk-RWNSW4FM.js → chunk-UMNXCU3K.js} +12 -6
- package/dist/{chunk-RWNSW4FM.js.map → chunk-UMNXCU3K.js.map} +1 -1
- package/dist/{chunk-DS5MCU2X.js → chunk-URCXSUI3.js} +9 -9
- package/dist/chunk-VI7ZANB3.js +193 -0
- package/dist/chunk-VI7ZANB3.js.map +1 -0
- package/dist/chunk-VQPHPQ5L.js +14 -0
- package/dist/chunk-VQPHPQ5L.js.map +1 -0
- package/dist/chunk-WNJTJRM6.js +147 -0
- package/dist/chunk-WNJTJRM6.js.map +1 -0
- package/dist/{chunk-BMHS4WAN.js → chunk-XS7EX55U.js} +156 -42
- package/dist/chunk-XS7EX55U.js.map +1 -0
- package/dist/chunk-YN4W7LCX.js +31 -0
- package/dist/chunk-YN4W7LCX.js.map +1 -0
- package/dist/chunk-YSJOZEI6.js +1 -0
- package/dist/{chunk-JA2ZAT5Q.js → chunk-Z4PJMZLM.js} +2 -2
- package/dist/chunk-Z4PJMZLM.js.map +1 -0
- package/dist/{chunk-WSXNGF7X.js → chunk-ZNZISJDZ.js} +6 -2
- package/dist/chunk-ZNZISJDZ.js.map +1 -0
- package/dist/chunk-ZWN3AODA.js +11 -0
- package/dist/chunk-ZWN3AODA.js.map +1 -0
- package/dist/cli/index.js +25 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/client/core.d.ts +1 -1
- package/dist/client/core.js +2 -0
- package/dist/client/core.js.map +1 -1
- package/dist/client/index.d.ts +44 -10
- package/dist/client/index.js +35 -0
- package/dist/client/index.js.map +1 -1
- package/dist/cloudflare-SIG42OIW.js +335 -0
- package/dist/cloudflare-SIG42OIW.js.map +1 -0
- package/dist/config-support-WQHQIJTA.js +104 -0
- package/dist/config-support-WQHQIJTA.js.map +1 -0
- package/dist/{csrf-BBrEZSBW.d.ts → csrf-Dgot9qSM.d.ts} +1 -1
- package/dist/deno-deploy-LQAYOOPW.js +196 -0
- package/dist/deno-deploy-LQAYOOPW.js.map +1 -0
- package/dist/{dev-CDFPXISP.js → dev-3UQVD2W6.js} +29 -18
- package/dist/dev-3UQVD2W6.js.map +1 -0
- package/dist/{dev-emit-GWD6IXV7.js → dev-emit-BFNMDCPB.js} +5 -5
- package/dist/{dev-emit-NBT6JD7R.js → dev-emit-MVAJAFGX.js} +5 -3
- package/dist/dev-emit-MVAJAFGX.js.map +1 -0
- package/dist/engine-singleton-X4R7AZBJ.js +315 -0
- package/dist/engine-singleton-X4R7AZBJ.js.map +1 -0
- package/dist/{generate-Y3GWM57K.js → generate-EN6EDITF.js} +43 -4
- package/dist/generate-EN6EDITF.js.map +1 -0
- package/dist/index-DctfHtv-.d.ts +1058 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +25 -13
- package/dist/index.js.map +1 -1
- package/dist/{info-QXZW722N.js → info-Y55RWS42.js} +8 -6
- package/dist/{info-QXZW722N.js.map → info-Y55RWS42.js.map} +1 -1
- package/dist/{internal-api-FBK2YXSI.js → internal-api-4X6NDS2F.js} +23 -12
- package/dist/{internal-api-ZCJWJ5EC.js → internal-api-XQHU5JKY.js} +31 -16
- package/dist/internal-api-XQHU5JKY.js.map +1 -0
- package/dist/load-config-4ATXQUN3.js +16 -0
- package/dist/match-DmGgxjIU.d.ts +44 -0
- package/dist/{mcp-KTYP4ZON.js → mcp-IQRHFP3Y.js} +7 -7
- package/dist/netlify-C2IRCZKI.js +245 -0
- package/dist/netlify-C2IRCZKI.js.map +1 -0
- package/dist/node-OSVPYQ3D.js +10 -0
- package/dist/nonce-BXt7Qu_C.d.ts +31 -0
- package/dist/observability-bootstrap-LERYDHKY.js +16 -0
- package/dist/{openapi-OUXNB2F2.js → openapi-VFPEZSRI.js} +13 -11
- package/dist/{openapi-OUXNB2F2.js.map → openapi-VFPEZSRI.js.map} +1 -1
- package/dist/{plugin-runner-DHVr1cC5.d.ts → plugin-runner-BVMOSxvb.d.ts} +1 -1
- package/dist/{plugin-types-4VN1GMqV.d.ts → plugin-types-BUVfUQ0V.d.ts} +1 -1
- package/dist/preview-BT47VMIB.js +23 -0
- package/dist/preview-BT47VMIB.js.map +1 -0
- package/dist/provider-resolver-Dx6QuWrw.d.ts +128 -0
- package/dist/registry-KBZDCFVQ.js +23 -0
- package/dist/route-config-Cm_ZMA1C.d.ts +72 -0
- package/dist/route-policy-BxOycCDq.d.ts +65 -0
- package/dist/router/element-scroll-restoration.d.ts +28 -0
- package/dist/router/element-scroll-restoration.js +96 -0
- package/dist/router/element-scroll-restoration.js.map +1 -0
- package/dist/{routes-NJR4ISCT.js → routes-BPLU3ISV.js} +11 -9
- package/dist/{routes-NJR4ISCT.js.map → routes-BPLU3ISV.js.map} +1 -1
- package/dist/{scan-7MJC6PYU.js → scan-YJEE4KQK.js} +2 -2
- package/dist/{schema-DNIT7JQX.js → schema-SOAD43RQ.js} +7 -5
- package/dist/schemas-4AXHQMV3.js +25 -0
- package/dist/schemas-4AXHQMV3.js.map +1 -0
- package/dist/security-headers-Ccj7ncNx.d.ts +129 -0
- package/dist/server/agent/index.d.ts +2 -105
- package/dist/server/agent/index.js +1 -1
- package/dist/server/auth/index.d.ts +2 -21
- package/dist/server/auth/index.js +3 -2
- package/dist/server/cron/index.js +4 -3
- package/dist/server/define/index.d.ts +43 -57
- package/dist/server/define/index.js +10 -1
- package/dist/server/http/index.d.ts +7 -5
- package/dist/server/http/index.js +57 -12
- package/dist/server/index.d.ts +47 -439
- package/dist/server/index.js +120 -201
- package/dist/server/index.js.map +1 -1
- package/dist/server/jobs/index.js +4 -3
- package/dist/server/observability/index.d.ts +109 -35
- package/dist/server/observability/index.js +11 -7
- package/dist/server/plugins/index.d.ts +3 -3
- package/dist/server/scan/index.d.ts +47 -12
- package/dist/server/scan/index.js +13 -4
- package/dist/server/security/index.d.ts +61 -103
- package/dist/server/security/index.js +15 -6
- package/dist/server/webhook/index.d.ts +90 -3
- package/dist/server/webhook/index.js +12 -2
- package/dist/server-boundary-2WFT546S.js +149 -0
- package/dist/server-boundary-2WFT546S.js.map +1 -0
- package/dist/server-boundary-A67OPRKO.js +134 -0
- package/dist/server-boundary-A67OPRKO.js.map +1 -0
- package/dist/{services-typed-client-P4JERLBL.js → services-typed-client-XGT5SUUN.js} +2 -2
- package/dist/{start-25OV2CAK.js → start-3K3C4Z2X.js} +224 -161
- package/dist/start-3K3C4Z2X.js.map +1 -0
- package/dist/{static-RTO637XW.js → static-SVDWIOXJ.js} +24 -13
- package/dist/static-SVDWIOXJ.js.map +1 -0
- package/dist/{theo-cloud-UZ3GINRU.js → theo-cloud-3ET4G5T6.js} +9 -2
- package/dist/theo-cloud-3ET4G5T6.js.map +1 -0
- package/dist/vercel-BMCQKCWE.js +277 -0
- package/dist/vercel-BMCQKCWE.js.map +1 -0
- package/dist/vite-plugin/index.js +25 -13
- package/dist/vite-plugin-USXUIV3H.js +43 -0
- package/dist/vite-plugin-USXUIV3H.js.map +1 -0
- package/package.json +19 -6
- package/dist/actions-virtual-module-E4PISKMB.js.map +0 -1
- package/dist/agent-XAQCUQNB.js +0 -15
- package/dist/app-typed-client-HLP26EYM.js.map +0 -1
- package/dist/app-typed-client-I4X2UJWW.js.map +0 -1
- package/dist/aws-lambda-KES4MFJV.js +0 -172
- package/dist/aws-lambda-KES4MFJV.js.map +0 -1
- package/dist/body-parser-web-4Z2QTPDU.js.map +0 -1
- package/dist/body-parser-web-TIOTXPDW.js.map +0 -1
- package/dist/build-F2Q5QTSC.js.map +0 -1
- package/dist/bun-A5B2MJMO.js.map +0 -1
- package/dist/chunk-646CA6RV.js.map +0 -1
- package/dist/chunk-7LVM22VG.js.map +0 -1
- package/dist/chunk-A7JBF5FO.js.map +0 -1
- package/dist/chunk-AATSV4UV.js.map +0 -1
- package/dist/chunk-AM3QABW5.js +0 -161
- package/dist/chunk-AM3QABW5.js.map +0 -1
- package/dist/chunk-AXKUA57G.js +0 -94
- package/dist/chunk-AXKUA57G.js.map +0 -1
- package/dist/chunk-BHOTGS7N.js.map +0 -1
- package/dist/chunk-BMHS4WAN.js.map +0 -1
- package/dist/chunk-CMYSHZFT.js +0 -422
- package/dist/chunk-CMYSHZFT.js.map +0 -1
- package/dist/chunk-DQIPV7L5.js +0 -118
- package/dist/chunk-DQIPV7L5.js.map +0 -1
- package/dist/chunk-FB2HBNIC.js.map +0 -1
- package/dist/chunk-FNTLKHZ7.js.map +0 -1
- package/dist/chunk-FTFN4MYN.js.map +0 -1
- package/dist/chunk-HBU2GIMZ.js.map +0 -1
- package/dist/chunk-IEES3CHD.js.map +0 -1
- package/dist/chunk-JA2ZAT5Q.js.map +0 -1
- package/dist/chunk-KD5G3YXI.js.map +0 -1
- package/dist/chunk-KTKTHIUF.js +0 -405
- package/dist/chunk-KTKTHIUF.js.map +0 -1
- package/dist/chunk-LNVMHQ2Z.js +0 -54
- package/dist/chunk-LNVMHQ2Z.js.map +0 -1
- package/dist/chunk-LXAESF4Y.js.map +0 -1
- package/dist/chunk-MTEWLGVY.js.map +0 -1
- package/dist/chunk-NTWNO24W.js.map +0 -1
- package/dist/chunk-O3JIAU3V.js.map +0 -1
- package/dist/chunk-OLGPYOLO.js.map +0 -1
- package/dist/chunk-OOBYPCZC.js.map +0 -1
- package/dist/chunk-T5C46IIU.js.map +0 -1
- package/dist/chunk-U267AOWS.js +0 -28
- package/dist/chunk-U267AOWS.js.map +0 -1
- package/dist/chunk-UW2TEAGR.js +0 -77
- package/dist/chunk-UW2TEAGR.js.map +0 -1
- package/dist/chunk-WPJOTQA5.js +0 -1
- package/dist/chunk-WSXNGF7X.js.map +0 -1
- package/dist/chunk-WYHYOYRH.js.map +0 -1
- package/dist/chunk-XALU5LCU.js.map +0 -1
- package/dist/chunk-XR74JD4M.js +0 -457
- package/dist/chunk-XR74JD4M.js.map +0 -1
- package/dist/chunk-YGAXV5HR.js.map +0 -1
- package/dist/chunk-YXG2SGQ3.js.map +0 -1
- package/dist/cloudflare-IN2WB7FZ.js +0 -122
- package/dist/cloudflare-IN2WB7FZ.js.map +0 -1
- package/dist/deno-deploy-LYXQEJ6A.js +0 -107
- package/dist/deno-deploy-LYXQEJ6A.js.map +0 -1
- package/dist/dev-CDFPXISP.js.map +0 -1
- package/dist/dev-emit-NBT6JD7R.js.map +0 -1
- package/dist/generate-Y3GWM57K.js.map +0 -1
- package/dist/index-D_PxPXgQ.d.ts +0 -575
- package/dist/load-config-FIWNKOJO.js +0 -14
- package/dist/match-CfbEFRG4.d.ts +0 -26
- package/dist/netlify-DLEOCFAD.js +0 -150
- package/dist/netlify-DLEOCFAD.js.map +0 -1
- package/dist/node-QXYSUWQ4.js +0 -10
- package/dist/registry-S7OMF3OS.js +0 -23
- package/dist/start-25OV2CAK.js.map +0 -1
- package/dist/static-RTO637XW.js.map +0 -1
- package/dist/theo-cloud-UZ3GINRU.js.map +0 -1
- package/dist/vercel-6D6EZUVD.js +0 -133
- package/dist/vercel-6D6EZUVD.js.map +0 -1
- package/dist/vite-plugin-RJFKLF2U.js +0 -36
- /package/dist/{chunk-WPJOTQA5.js.map → adapters/agent-mount.js.map} +0 -0
- /package/dist/{agent-XAQCUQNB.js.map → agent-7IPEVCAY.js.map} +0 -0
- /package/dist/{check-45NKUVSQ.js.map → check-GIPZBFTX.js.map} +0 -0
- /package/dist/{chunk-47CINLWF.js.map → chunk-EDWEYQRG.js.map} +0 -0
- /package/dist/{chunk-ZB7D62OA.js.map → chunk-KUZVRJ7M.js.map} +0 -0
- /package/dist/{chunk-DS5MCU2X.js.map → chunk-URCXSUI3.js.map} +0 -0
- /package/dist/{internal-api-ZCJWJ5EC.js.map → chunk-YSJOZEI6.js.map} +0 -0
- /package/dist/{dev-emit-GWD6IXV7.js.map → dev-emit-BFNMDCPB.js.map} +0 -0
- /package/dist/{internal-api-FBK2YXSI.js.map → internal-api-4X6NDS2F.js.map} +0 -0
- /package/dist/{load-config-FIWNKOJO.js.map → load-config-4ATXQUN3.js.map} +0 -0
- /package/dist/{mcp-KTYP4ZON.js.map → mcp-IQRHFP3Y.js.map} +0 -0
- /package/dist/{node-QXYSUWQ4.js.map → node-OSVPYQ3D.js.map} +0 -0
- /package/dist/{scan-7MJC6PYU.js.map → observability-bootstrap-LERYDHKY.js.map} +0 -0
- /package/dist/{registry-S7OMF3OS.js.map → registry-KBZDCFVQ.js.map} +0 -0
- /package/dist/{schema-DNIT7JQX.js.map → scan-YJEE4KQK.js.map} +0 -0
- /package/dist/{vite-plugin-RJFKLF2U.js.map → schema-SOAD43RQ.js.map} +0 -0
- /package/dist/{services-typed-client-P4JERLBL.js.map → services-typed-client-XGT5SUUN.js.map} +0 -0
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveTheoRootDir
|
|
3
|
+
} from "./chunk-VQPHPQ5L.js";
|
|
1
4
|
import {
|
|
2
5
|
buildServicesProxyConfig,
|
|
3
6
|
servicesConfigSchema
|
|
4
7
|
} from "./chunk-SSYDEKWF.js";
|
|
8
|
+
import {
|
|
9
|
+
dispatchControllerRequest
|
|
10
|
+
} from "./chunk-RJJF457I.js";
|
|
5
11
|
import {
|
|
6
12
|
broadcastToDevtools
|
|
7
13
|
} from "./chunk-OIGJOYX6.js";
|
|
@@ -9,38 +15,53 @@ import {
|
|
|
9
15
|
RUN_ID_HEADER,
|
|
10
16
|
SSE_BASE_HEADERS,
|
|
11
17
|
SSE_DONE_FRAME,
|
|
12
|
-
|
|
18
|
+
admitAgentRequest,
|
|
19
|
+
agentAccessDenied,
|
|
20
|
+
cacheSchema,
|
|
21
|
+
closePauseSpan,
|
|
22
|
+
createObservabilityPluginFromConfig,
|
|
13
23
|
encodeSse,
|
|
14
24
|
formatSseFrame,
|
|
15
25
|
getApprovalRegistry,
|
|
16
26
|
getRunEventCache,
|
|
27
|
+
loggingSchema,
|
|
17
28
|
makeThreadStartRun,
|
|
18
29
|
mintRunId,
|
|
19
30
|
mountAgent,
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
observabilitySchema,
|
|
32
|
+
parseAgentRequestBody,
|
|
33
|
+
rateLimitSchema,
|
|
34
|
+
readAgentPolicy,
|
|
35
|
+
securitySchema,
|
|
36
|
+
storageSchema,
|
|
37
|
+
uploadSchema
|
|
38
|
+
} from "./chunk-KOS567NB.js";
|
|
39
|
+
import {
|
|
40
|
+
loadEnv
|
|
41
|
+
} from "./chunk-4X6H2BXP.js";
|
|
22
42
|
import {
|
|
23
|
-
loadEnv,
|
|
24
43
|
resolveTransformer
|
|
25
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-OGLS76RN.js";
|
|
26
45
|
import {
|
|
27
46
|
BATCH_PATH,
|
|
28
|
-
TRACE_HEADER,
|
|
29
47
|
createCorsHandler,
|
|
48
|
+
createServerContext,
|
|
49
|
+
createWebRequestSource,
|
|
30
50
|
executeAction,
|
|
31
51
|
executeRoute,
|
|
32
|
-
extractTraceId,
|
|
33
52
|
handleBatchRequest,
|
|
34
53
|
incomingMessageToHandlerRequest,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} from "./chunk-
|
|
54
|
+
sendError,
|
|
55
|
+
writeWebResponseToServerResponse
|
|
56
|
+
} from "./chunk-JKF25N73.js";
|
|
38
57
|
import {
|
|
39
58
|
findSuggestion
|
|
40
59
|
} from "./chunk-NTDN54XO.js";
|
|
41
60
|
import {
|
|
61
|
+
TRACE_HEADER,
|
|
62
|
+
extractTraceId,
|
|
42
63
|
logRequest
|
|
43
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-DOI4G4X3.js";
|
|
44
65
|
import {
|
|
45
66
|
createPluginRunnerFromConfig
|
|
46
67
|
} from "./chunk-VSLTKX5L.js";
|
|
@@ -49,24 +70,26 @@ import {
|
|
|
49
70
|
} from "./chunk-TNI4MARH.js";
|
|
50
71
|
import {
|
|
51
72
|
createViteLoader
|
|
52
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-OQCRCXCP.js";
|
|
53
74
|
import {
|
|
54
75
|
matchRoute,
|
|
55
|
-
scanAgents,
|
|
56
76
|
scanServerActions,
|
|
57
77
|
scanServerRoutes,
|
|
58
78
|
scanWebSocketRoutes
|
|
59
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-6J4JWHDJ.js";
|
|
80
|
+
import {
|
|
81
|
+
scanAgents
|
|
82
|
+
} from "./chunk-L4VFNFDL.js";
|
|
60
83
|
import {
|
|
61
84
|
CSP_REPORT_PATH,
|
|
62
85
|
CsrfReadinessStore,
|
|
63
86
|
applySecurityHeaders,
|
|
64
87
|
handleCspReport,
|
|
65
88
|
handleCsrfReadiness
|
|
66
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-BPYMC7SU.js";
|
|
67
90
|
import {
|
|
68
91
|
validateCsrfRequest
|
|
69
|
-
} from "./chunk-
|
|
92
|
+
} from "./chunk-P6OS7652.js";
|
|
70
93
|
import {
|
|
71
94
|
extractAppResources,
|
|
72
95
|
handleMcpJsonRpc,
|
|
@@ -74,17 +97,20 @@ import {
|
|
|
74
97
|
} from "./chunk-YOIVCCZT.js";
|
|
75
98
|
import {
|
|
76
99
|
resolveProvider
|
|
77
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-3PBAN2YE.js";
|
|
78
101
|
import {
|
|
79
102
|
generateNonce
|
|
80
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-Z4PJMZLM.js";
|
|
81
104
|
import {
|
|
82
105
|
importUserModule
|
|
83
106
|
} from "./chunk-52PDWL5S.js";
|
|
107
|
+
import {
|
|
108
|
+
subjectFromContext
|
|
109
|
+
} from "./chunk-YN4W7LCX.js";
|
|
84
110
|
|
|
85
111
|
// src/vite-plugin/index.ts
|
|
86
|
-
import { existsSync as
|
|
87
|
-
import { resolve as
|
|
112
|
+
import { existsSync as existsSync8 } from "fs";
|
|
113
|
+
import { resolve as resolve10, dirname as dirname4 } from "path";
|
|
88
114
|
import { fileURLToPath } from "url";
|
|
89
115
|
|
|
90
116
|
// src/vite-plugin/config-hook.ts
|
|
@@ -129,42 +155,56 @@ function runConfigHook(ctx) {
|
|
|
129
155
|
},
|
|
130
156
|
resolve: {
|
|
131
157
|
alias: [
|
|
132
|
-
// Order matters
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
158
|
+
// Order still matters — first match wins — but the entries below are
|
|
159
|
+
// EXACT (#377). A Vite alias whose `find` is a string matches by prefix,
|
|
160
|
+
// and every replacement here points at a FILE, so the old string form
|
|
161
|
+
// rewrote `theokit/client/core` into `…/client/index.ts/core` and the
|
|
162
|
+
// build died with ENOTDIR. It did that for every subpath nobody had
|
|
163
|
+
// listed, which made the failure open-ended rather than a typo.
|
|
164
|
+
{ find: /^theokit\/server$/u, replacement: resolve(ctx.theoSrcDir, `server/index${ext}`) },
|
|
165
|
+
{ find: /^theokit\/client$/u, replacement: resolve(ctx.theoSrcDir, `client/index${ext}`) },
|
|
136
166
|
{
|
|
137
167
|
// T2.1 (M5 lonely folders) moved the source from
|
|
138
168
|
// `react-query/index.ts` into `client/react-query.ts` (sibling of
|
|
139
169
|
// `client/index.ts`). The package.json export `./react-query`
|
|
140
170
|
// still points at the build artifact `./dist/react-query/index.{js,d.ts}`,
|
|
141
171
|
// but the dev-time source alias must follow the new location.
|
|
142
|
-
find:
|
|
172
|
+
find: /^theokit\/react-query$/u,
|
|
143
173
|
replacement: resolve(ctx.theoSrcDir, `client/react-query${ext}`)
|
|
144
174
|
},
|
|
145
175
|
{
|
|
146
|
-
find:
|
|
176
|
+
find: /^theokit\/vite-plugin$/u,
|
|
147
177
|
replacement: resolve(ctx.theoSrcDir, `vite-plugin/index${ext}`)
|
|
148
178
|
},
|
|
149
179
|
{
|
|
150
|
-
find:
|
|
180
|
+
find: /^theokit\/adapters\/web-shim$/u,
|
|
151
181
|
replacement: resolve(ctx.theoSrcDir, `adapters/web-shim${ext}`)
|
|
152
182
|
},
|
|
153
183
|
{
|
|
154
|
-
find:
|
|
184
|
+
find: /^theokit\/adapters\/ws-shim$/u,
|
|
155
185
|
replacement: resolve(ctx.theoSrcDir, `adapters/ws-shim${ext}`)
|
|
156
186
|
},
|
|
157
187
|
// T1.2 — devtools entry (DEV only; tree-shaken in build).
|
|
158
188
|
// Source layout: src/devtools/dom/entry.tsx (has /dom/ segment)
|
|
159
189
|
// Dist layout: dist/devtools/entry.js (tsup flattens /dom/)
|
|
160
190
|
{
|
|
161
|
-
find:
|
|
191
|
+
find: /^theokit\/devtools\/entry$/u,
|
|
162
192
|
replacement: resolve(
|
|
163
193
|
ctx.theoSrcDir,
|
|
164
194
|
ext === ".ts" ? "devtools/dom/entry.tsx" : "devtools/entry.js"
|
|
165
195
|
)
|
|
166
196
|
},
|
|
167
|
-
|
|
197
|
+
// Everything else under the package, by one rule rather than a list that
|
|
198
|
+
// has to grow with the exports map. The source layout mirrors the
|
|
199
|
+
// subpath, so `theokit/cache` is `<src>/cache` and Vite's own extension
|
|
200
|
+
// resolution finds the file. The two entries above that do NOT mirror it
|
|
201
|
+
// — react-query moved to a sibling, devtools' source carries a `/dom/`
|
|
202
|
+
// segment the dist flattens — are matched before this and keep their
|
|
203
|
+
// mapping.
|
|
204
|
+
{ find: /^theokit\/(.+)$/u, replacement: resolve(ctx.theoSrcDir, "$1") },
|
|
205
|
+
// Exact, so a package merely NAMED like ours — `theokit-anything` — is
|
|
206
|
+
// left alone. The prefix form ate those too.
|
|
207
|
+
{ find: /^theokit$/u, replacement: resolve(ctx.theoSrcDir, `index${ext}`) }
|
|
168
208
|
]
|
|
169
209
|
}
|
|
170
210
|
};
|
|
@@ -196,177 +236,13 @@ ${issueLines}
|
|
|
196
236
|
};
|
|
197
237
|
|
|
198
238
|
// src/config/schema.ts
|
|
199
|
-
import { z
|
|
239
|
+
import { z } from "zod";
|
|
200
240
|
|
|
201
241
|
// src/core/contracts/theo-ui-theme.ts
|
|
202
242
|
var THEME_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
203
243
|
|
|
204
|
-
// src/config/schemas/rate-limit.ts
|
|
205
|
-
import { z } from "zod";
|
|
206
|
-
var baseRateLimitSchema = z.object({
|
|
207
|
-
windowMs: z.number().min(1),
|
|
208
|
-
max: z.number().int().min(1)
|
|
209
|
-
});
|
|
210
|
-
var rateLimitSchema = z.union([
|
|
211
|
-
baseRateLimitSchema,
|
|
212
|
-
z.object({
|
|
213
|
-
default: baseRateLimitSchema.optional(),
|
|
214
|
-
routes: z.record(z.string(), baseRateLimitSchema).optional(),
|
|
215
|
-
keyBy: z.union([
|
|
216
|
-
z.enum(["ip", "session", "user"]),
|
|
217
|
-
z.function({ input: z.tuple([z.unknown()]), output: z.string() })
|
|
218
|
-
]).optional(),
|
|
219
|
-
cookieName: z.string().min(1).optional(),
|
|
220
|
-
/**
|
|
221
|
-
* How many reverse proxies sit in front of the app, for `keyBy: 'ip'`. `false` (default)
|
|
222
|
-
* trusts none; `true` means one; a number names a longer chain.
|
|
223
|
-
*
|
|
224
|
-
* Required for correct limiting behind Caddy/nginx/a load balancer — without it every visitor
|
|
225
|
-
* keys on the proxy address and shares a single bucket. Off by default because
|
|
226
|
-
* `x-forwarded-for` is client-writable.
|
|
227
|
-
*/
|
|
228
|
-
trustProxy: z.union([z.boolean(), z.number().int().min(0)]).optional()
|
|
229
|
-
})
|
|
230
|
-
]);
|
|
231
|
-
|
|
232
|
-
// src/config/schemas/upload.ts
|
|
233
|
-
import { z as z2 } from "zod";
|
|
234
|
-
var uploadSchema = z2.object({
|
|
235
|
-
maxFileSize: z2.number().min(1).default(10 * 1024 * 1024),
|
|
236
|
-
// 10MB
|
|
237
|
-
maxFiles: z2.number().int().min(1).default(10),
|
|
238
|
-
maxFieldSize: z2.number().min(1).default(1 * 1024 * 1024)
|
|
239
|
-
// 1MB
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// src/config/schemas/logging.ts
|
|
243
|
-
import { z as z3 } from "zod";
|
|
244
|
-
var loggingSchema = z3.object({
|
|
245
|
-
level: z3.enum(["debug", "info", "warn", "error", "silent"]).default("info")
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
// src/config/schemas/cache.ts
|
|
249
|
-
import { z as z4 } from "zod";
|
|
250
|
-
var routeRuleSchema = z4.object({
|
|
251
|
-
maxAge: z4.number().nonnegative().optional(),
|
|
252
|
-
swr: z4.number().nonnegative().optional(),
|
|
253
|
-
tags: z4.array(z4.string()).optional()
|
|
254
|
-
});
|
|
255
|
-
var cacheSchema = z4.object({
|
|
256
|
-
enabled: z4.boolean().default(true),
|
|
257
|
-
/** 'memory' uses InMemoryCacheAdapter; otherwise pass a custom adapter instance. */
|
|
258
|
-
storage: z4.union([z4.literal("memory"), z4.custom()]).default("memory"),
|
|
259
|
-
maxEntries: z4.number().int().positive().default(1e3),
|
|
260
|
-
defaults: z4.object({
|
|
261
|
-
maxAge: z4.number().nonnegative().default(1),
|
|
262
|
-
swr: z4.number().nonnegative().optional(),
|
|
263
|
-
cacheErrors: z4.boolean().default(false)
|
|
264
|
-
}).default({ maxAge: 1, cacheErrors: false }),
|
|
265
|
-
keyDerivation: z4.object({
|
|
266
|
-
excludeQuery: z4.array(z4.string()).optional(),
|
|
267
|
-
sortQuery: z4.boolean().default(true),
|
|
268
|
-
lowercaseHost: z4.boolean().default(true)
|
|
269
|
-
}).default({ sortQuery: true, lowercaseHost: true }),
|
|
270
|
-
routeRules: z4.record(z4.string(), routeRuleSchema).optional()
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
// src/config/schemas/security.ts
|
|
274
|
-
import { z as z6 } from "zod";
|
|
275
|
-
|
|
276
|
-
// src/config/schemas/header-safe.ts
|
|
277
|
-
import { z as z5 } from "zod";
|
|
278
|
-
var headerSafeString = z5.string().refine((s) => !/[\r\n]/.test(s), { message: "Header value must not contain CR/LF" });
|
|
279
|
-
|
|
280
|
-
// src/config/schemas/security.ts
|
|
281
|
-
var securityHeadersSchema = z6.object({
|
|
282
|
-
csp: z6.union([headerSafeString, z6.literal(false)]).optional(),
|
|
283
|
-
// T6.1 — default flipped from 'report-only' to 'enforce' for 0.3.0.
|
|
284
|
-
// Users who want the old behaviour set `cspMode: 'report-only'`
|
|
285
|
-
// explicitly.
|
|
286
|
-
cspMode: z6.enum(["enforce", "report-only", "off"]).default("enforce"),
|
|
287
|
-
hsts: z6.union([headerSafeString, z6.literal(false)]).optional(),
|
|
288
|
-
frameOptions: z6.enum(["DENY", "SAMEORIGIN"]).default("DENY"),
|
|
289
|
-
contentTypeOptions: z6.literal("nosniff").default("nosniff"),
|
|
290
|
-
referrerPolicy: headerSafeString.default("strict-origin-when-cross-origin"),
|
|
291
|
-
/**
|
|
292
|
-
* T1.1 — Permissions-Policy directive string. EC-3-refined: rejects CR/LF.
|
|
293
|
-
* Pass `false` to suppress the header.
|
|
294
|
-
*/
|
|
295
|
-
permissionsPolicy: z6.union([headerSafeString, z6.literal(false)]).optional()
|
|
296
|
-
});
|
|
297
|
-
var disallowedConfigSchema = z6.object({
|
|
298
|
-
routes: z6.array(z6.union([z6.string(), z6.instanceof(RegExp)])),
|
|
299
|
-
behavior: z6.enum(["warn", "raise"]).default("raise")
|
|
300
|
-
});
|
|
301
|
-
var corsSchema = z6.object({
|
|
302
|
-
origins: z6.union([
|
|
303
|
-
z6.literal("*"),
|
|
304
|
-
headerSafeString,
|
|
305
|
-
z6.instanceof(RegExp),
|
|
306
|
-
z6.array(z6.union([headerSafeString, z6.instanceof(RegExp)])),
|
|
307
|
-
z6.function({ input: z6.tuple([z6.string()]), output: z6.boolean() })
|
|
308
|
-
]),
|
|
309
|
-
methods: z6.array(z6.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"])).optional(),
|
|
310
|
-
allowedHeaders: z6.array(headerSafeString).optional(),
|
|
311
|
-
exposedHeaders: z6.array(headerSafeString).optional(),
|
|
312
|
-
credentials: z6.boolean().default(false),
|
|
313
|
-
maxAge: z6.number().int().min(0).max(86400).default(600)
|
|
314
|
-
}).refine((c) => !(c.origins === "*" && c.credentials), {
|
|
315
|
-
message: 'CORS spec forbids origins:"*" with credentials:true \u2014 browsers ignore the wildcard'
|
|
316
|
-
});
|
|
317
|
-
var securitySchema = z6.object({
|
|
318
|
-
// T6.1 — default flipped from 'warn' to 'strict' for 0.3.0. Apps that
|
|
319
|
-
// grep their warn-mode logs from 0.2.x already know which endpoints
|
|
320
|
-
// break; opt back into 'warn' globally OR use disallowedRoutes for
|
|
321
|
-
// surgical migration.
|
|
322
|
-
csrf: z6.enum(["off", "warn", "strict"]).default("strict"),
|
|
323
|
-
headers: securityHeadersSchema.optional(),
|
|
324
|
-
/** T5.1 — per-route escalation (Rails disallowed_warnings pattern). */
|
|
325
|
-
disallowed: disallowedConfigSchema.optional(),
|
|
326
|
-
/** T1.2 — Cross-Origin Resource Sharing. Single global config; runs first in pipeline. */
|
|
327
|
-
cors: corsSchema.optional()
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
// src/config/schemas/storage.ts
|
|
331
|
-
import { z as z7 } from "zod";
|
|
332
|
-
var tlsConfigSchema = z7.object({
|
|
333
|
-
rejectUnauthorized: z7.boolean().optional(),
|
|
334
|
-
caCert: z7.string().optional(),
|
|
335
|
-
clientCert: z7.string().optional(),
|
|
336
|
-
clientKey: z7.string().optional()
|
|
337
|
-
});
|
|
338
|
-
var serverConfigSchema = z7.object({
|
|
339
|
-
host: z7.string().min(1),
|
|
340
|
-
port: z7.number().int().positive().max(65535).optional(),
|
|
341
|
-
user: z7.string().min(1),
|
|
342
|
-
/** Password may be the empty string (some providers permit it). */
|
|
343
|
-
password: z7.string(),
|
|
344
|
-
tls: tlsConfigSchema.optional()
|
|
345
|
-
});
|
|
346
|
-
var postgresPoolConfigSchema = z7.object({
|
|
347
|
-
min: z7.number().int().nonnegative().optional(),
|
|
348
|
-
max: z7.number().int().positive().optional(),
|
|
349
|
-
connectionTimeoutMillis: z7.number().int().positive().optional(),
|
|
350
|
-
idleTimeoutMillis: z7.number().int().nonnegative().optional()
|
|
351
|
-
});
|
|
352
|
-
var postgresDatabaseConfigSchema = z7.object({
|
|
353
|
-
/** References a key in `storage.servers`. Resolved at `usePostgres()` call time. */
|
|
354
|
-
server: z7.string().min(1),
|
|
355
|
-
database: z7.string().min(1),
|
|
356
|
-
pool: postgresPoolConfigSchema.optional()
|
|
357
|
-
});
|
|
358
|
-
var redisServerConfigSchema = serverConfigSchema.extend({
|
|
359
|
-
db: z7.number().int().nonnegative().optional(),
|
|
360
|
-
maxRetriesPerRequest: z7.number().int().nonnegative().optional()
|
|
361
|
-
});
|
|
362
|
-
var storageSchema = z7.object({
|
|
363
|
-
servers: z7.record(z7.string(), serverConfigSchema).optional(),
|
|
364
|
-
databases: z7.record(z7.string(), postgresDatabaseConfigSchema).optional(),
|
|
365
|
-
redis: z7.record(z7.string(), redisServerConfigSchema).optional()
|
|
366
|
-
});
|
|
367
|
-
|
|
368
244
|
// src/config/schema.ts
|
|
369
|
-
var theoConfigSchema =
|
|
245
|
+
var theoConfigSchema = z.object({
|
|
370
246
|
/**
|
|
371
247
|
* Plan v1.2 T2.1 — project identifier propagated into
|
|
372
248
|
* `.theokit/services.json` v2 `project` field. DNS-1123 compatible (drives
|
|
@@ -374,27 +250,27 @@ var theoConfigSchema = z8.object({
|
|
|
374
250
|
* emits services.json v1 with the legacy `services-bundle` fallback
|
|
375
251
|
* (ADR D10) and logs a deprecation warning.
|
|
376
252
|
*/
|
|
377
|
-
name:
|
|
253
|
+
name: z.string().max(63).refine(
|
|
378
254
|
// DNS-1123 equivalent expressed as explicit single-char anchors so
|
|
379
255
|
// security/detect-unsafe-regex stays clean (no backtracking).
|
|
380
256
|
(value) => value.length > 0 && /^[a-z0-9-]+$/u.test(value) && !value.startsWith("-") && !value.endsWith("-"),
|
|
381
257
|
"name must match DNS-1123 (lowercase alphanumeric+hyphens, 1-63 chars, no leading/trailing hyphen)"
|
|
382
258
|
).optional(),
|
|
383
|
-
appDir:
|
|
384
|
-
serverDir:
|
|
259
|
+
appDir: z.string().default("app"),
|
|
260
|
+
serverDir: z.string().default("server"),
|
|
385
261
|
/**
|
|
386
262
|
* Directory (relative to the project root) holding `agents/<name>.ts` definitions, scanned by
|
|
387
263
|
* dev/build/terminal/mcp. Defaults to `"agents"` — apps that keep the canonical layout are
|
|
388
264
|
* unaffected. Set to e.g. `"core/agents"` to organize agents under a domain root (#95 follow-up).
|
|
389
265
|
*/
|
|
390
|
-
agentsDir:
|
|
266
|
+
agentsDir: z.string().default("agents"),
|
|
391
267
|
/**
|
|
392
268
|
* T2.2 / EC-4 — Build output directory. Must be a relative path inside
|
|
393
269
|
* the project root. Refused absolute or parent-relative paths to prevent
|
|
394
270
|
* `cleanOutDir` from wiping arbitrary locations (defense-in-depth on
|
|
395
271
|
* top of cleanOutDir's runtime EC-3 guard).
|
|
396
272
|
*/
|
|
397
|
-
distDir:
|
|
273
|
+
distDir: z.string().default(".theokit").refine(
|
|
398
274
|
(d) => !/^([A-Za-z]:)?[/\\]/.test(d) && !d.startsWith(".."),
|
|
399
275
|
'distDir must be a relative path inside the project root (e.g., ".theokit")'
|
|
400
276
|
),
|
|
@@ -413,73 +289,79 @@ var theoConfigSchema = z8.object({
|
|
|
413
289
|
* * `idleTimeoutMs` — auto-evict idle agents (default 30 min). 0 disables
|
|
414
290
|
* idle eviction (LRU only).
|
|
415
291
|
*/
|
|
416
|
-
agents:
|
|
417
|
-
maxRegistries:
|
|
418
|
-
registry:
|
|
292
|
+
agents: z.object({
|
|
293
|
+
maxRegistries: z.number().int().positive().default(100),
|
|
294
|
+
registry: z.object({
|
|
419
295
|
/** LRU cap — MUST be ≥ max-concurrent-active-conversations. */
|
|
420
|
-
maxAgents:
|
|
296
|
+
maxAgents: z.number().int().positive().max(1e4).default(100),
|
|
421
297
|
/** Idle eviction window in ms. 0 disables idle eviction (LRU only). */
|
|
422
|
-
idleTimeoutMs:
|
|
298
|
+
idleTimeoutMs: z.number().int().nonnegative().default(30 * 6e4)
|
|
423
299
|
}).optional()
|
|
424
300
|
}).optional(),
|
|
425
|
-
port:
|
|
301
|
+
port: z.number().int().min(1).max(65535).default(3e3),
|
|
426
302
|
/** Listen on all addresses (0.0.0.0) for LAN/mobile testing. */
|
|
427
|
-
host:
|
|
303
|
+
host: z.union([z.string(), z.boolean()]).default("localhost"),
|
|
428
304
|
/** Automatically open browser on `theokit dev`. */
|
|
429
|
-
open:
|
|
305
|
+
open: z.union([z.boolean(), z.string()]).default(false),
|
|
430
306
|
/** Exit if port is already in use instead of trying next available. */
|
|
431
|
-
strictPort:
|
|
307
|
+
strictPort: z.boolean().default(false),
|
|
432
308
|
/** Forward browser console/errors to terminal — useful for AI agent dev. */
|
|
433
|
-
forwardConsole:
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
unhandledErrors:
|
|
437
|
-
logLevels:
|
|
309
|
+
forwardConsole: z.union([
|
|
310
|
+
z.boolean(),
|
|
311
|
+
z.object({
|
|
312
|
+
unhandledErrors: z.boolean().optional(),
|
|
313
|
+
logLevels: z.array(z.enum(["error", "warn", "info", "log", "debug"])).optional()
|
|
438
314
|
})
|
|
439
315
|
]).default(false),
|
|
440
316
|
/** Pre-transform files on startup for faster first page load. */
|
|
441
|
-
warmup:
|
|
442
|
-
clientFiles:
|
|
443
|
-
ssrFiles:
|
|
317
|
+
warmup: z.object({
|
|
318
|
+
clientFiles: z.array(z.string()).optional(),
|
|
319
|
+
ssrFiles: z.array(z.string()).optional()
|
|
444
320
|
}).optional(),
|
|
445
|
-
ssr:
|
|
321
|
+
ssr: z.boolean().default(false),
|
|
446
322
|
/** When true (and ssr === true), use renderToPipeableStream with progressive
|
|
447
323
|
* shell flush instead of single-shot renderToString. Opt-in for streaming
|
|
448
324
|
* SSR; default false preserves the current behavior. */
|
|
449
|
-
ssrStreaming:
|
|
325
|
+
ssrStreaming: z.boolean().default(false),
|
|
450
326
|
rateLimit: rateLimitSchema.optional(),
|
|
451
327
|
upload: uploadSchema.optional(),
|
|
452
328
|
logging: loggingSchema.optional(),
|
|
453
329
|
security: securitySchema.optional(),
|
|
454
|
-
serialization:
|
|
330
|
+
serialization: z.enum(["json", "superjson"]).default("json"),
|
|
455
331
|
// Plugins are validated structurally at runtime by createPluginRunnerFromConfig.
|
|
456
332
|
// Zod only checks the shape minimally (must be array). Type-level safety is
|
|
457
333
|
// provided through defineConfig at the user surface.
|
|
458
|
-
|
|
334
|
+
//
|
|
335
|
+
// #425 — an entry MAY also be a module SPECIFIER (a string), resolved to that module's default
|
|
336
|
+
// export by `config/resolve-plugin-specifiers.ts`. A constructed plugin closes over state and
|
|
337
|
+
// therefore has no literal, so it is the string form — and only the string form — that a
|
|
338
|
+
// generated deploy entry can carry. Both shapes are accepted here for the same reason they are
|
|
339
|
+
// accepted at runtime: one declaration has to serve the local server and the deployed one.
|
|
340
|
+
plugins: z.array(z.unknown()).optional(),
|
|
459
341
|
/** Enable client-side batching of theoFetch calls and the
|
|
460
342
|
* /api/__theo_batch__ server endpoint. */
|
|
461
|
-
batching:
|
|
343
|
+
batching: z.union([z.boolean(), z.object({ max: z.number().int().positive().optional() })]).optional(),
|
|
462
344
|
/** T4.1 — Audit log. When `logger` is provided, framework events
|
|
463
345
|
* (csrf.warn, rate-limit.exceeded, session.rotated, csp.violation) are
|
|
464
346
|
* emitted to it. Default: noop. */
|
|
465
|
-
audit:
|
|
466
|
-
logger:
|
|
347
|
+
audit: z.object({
|
|
348
|
+
logger: z.unknown().optional()
|
|
467
349
|
}).optional(),
|
|
468
350
|
/** TheoUI auto-wire (T2.1). `false` = opt-out; object = explicit theme/fonts;
|
|
469
351
|
* undefined = enabled when @theokit/ui is detected in node_modules. */
|
|
470
|
-
ui:
|
|
471
|
-
|
|
472
|
-
|
|
352
|
+
ui: z.union([
|
|
353
|
+
z.literal(false),
|
|
354
|
+
z.object({
|
|
473
355
|
// Any theme @theokit/ui knows — built-in or from `defineTheme()`. This was a closed
|
|
474
356
|
// enum of `violet-forge | noir | paper`, two of which never existed in @theokit/ui, so
|
|
475
357
|
// the only accepted value was the default and every real theme was rejected. The pattern
|
|
476
358
|
// mirrors what @theokit/ui's ThemeProvider enforces, and it is load-bearing: the value is
|
|
477
359
|
// interpolated into the generated entry and into a CSS selector.
|
|
478
|
-
theme:
|
|
360
|
+
theme: z.string().regex(
|
|
479
361
|
THEME_NAME_PATTERN,
|
|
480
362
|
"must start with a letter and contain only lowercase letters, digits and hyphens"
|
|
481
363
|
).optional(),
|
|
482
|
-
fonts:
|
|
364
|
+
fonts: z.enum(["bundled", "cdn"]).optional()
|
|
483
365
|
})
|
|
484
366
|
]).optional(),
|
|
485
367
|
/**
|
|
@@ -488,6 +370,12 @@ var theoConfigSchema = z8.object({
|
|
|
488
370
|
* Pass `cache: {}` to opt in with defaults.
|
|
489
371
|
*/
|
|
490
372
|
cache: cacheSchema.optional(),
|
|
373
|
+
/**
|
|
374
|
+
* Observability (#353). Default `undefined` keeps telemetry off. Present and
|
|
375
|
+
* not `enabled: false` opts in; `provider` overrides the environment-derived
|
|
376
|
+
* adapter, which is the priority `adapter-registry.ts` has always documented.
|
|
377
|
+
*/
|
|
378
|
+
observability: observabilitySchema.optional(),
|
|
491
379
|
/**
|
|
492
380
|
* Devtools overlay (Phase 0.4.0+ —
|
|
493
381
|
*
|
|
@@ -498,11 +386,11 @@ var theoConfigSchema = z8.object({
|
|
|
498
386
|
* Tree-shaken to noop in prod via the dual-export pattern in
|
|
499
387
|
* `packages/theo/src/devtools/index.ts` (EC-17 positive prod check).
|
|
500
388
|
*/
|
|
501
|
-
devtools:
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
position:
|
|
505
|
-
theme:
|
|
389
|
+
devtools: z.union([
|
|
390
|
+
z.literal(false),
|
|
391
|
+
z.object({
|
|
392
|
+
position: z.enum(["top-left", "top-right", "bottom-left", "bottom-right"]).optional(),
|
|
393
|
+
theme: z.enum(["light", "dark", "system"]).optional()
|
|
506
394
|
})
|
|
507
395
|
]).optional(),
|
|
508
396
|
/**
|
|
@@ -511,7 +399,7 @@ var theoConfigSchema = z8.object({
|
|
|
511
399
|
* (EC-201 / ADR D2). If `config.adapters` includes a target NOT
|
|
512
400
|
* matching `--target`, `theokit build` emits a cross-reference note.
|
|
513
401
|
*/
|
|
514
|
-
adapters:
|
|
402
|
+
adapters: z.array(z.string()).optional(),
|
|
515
403
|
/**
|
|
516
404
|
* Extra package names to pre-bundle via Vite's `optimizeDeps.include`.
|
|
517
405
|
*
|
|
@@ -526,14 +414,14 @@ var theoConfigSchema = z8.object({
|
|
|
526
414
|
* Example:
|
|
527
415
|
* viteOptimizeDeps: ['mermaid']
|
|
528
416
|
*/
|
|
529
|
-
viteOptimizeDeps:
|
|
417
|
+
viteOptimizeDeps: z.array(z.string()).optional(),
|
|
530
418
|
/**
|
|
531
419
|
* Jobs backend (ADR D3 + T2.1). When configured, every request gets
|
|
532
420
|
* `ctx.queue.enqueue` auto-wired via the outbox lifecycle. Pass a
|
|
533
421
|
* `JobBackend` instance (InMemoryJobBackend, PostgresJobBackend, etc.).
|
|
534
422
|
*/
|
|
535
|
-
jobs:
|
|
536
|
-
backend:
|
|
423
|
+
jobs: z.object({
|
|
424
|
+
backend: z.custom((v) => typeof v === "object" && v !== null)
|
|
537
425
|
}).optional(),
|
|
538
426
|
/**
|
|
539
427
|
* StorageManager configuration (T1.1 / ADR-0007).
|
|
@@ -568,17 +456,17 @@ var theoConfigSchema = z8.object({
|
|
|
568
456
|
* The env var `THEOKIT_OPENAPI_SERVERS` (CSV of URLs) overrides
|
|
569
457
|
* `servers[].url` at emit time without rebuilding the config.
|
|
570
458
|
*/
|
|
571
|
-
openapi:
|
|
572
|
-
servers:
|
|
573
|
-
|
|
574
|
-
url:
|
|
575
|
-
description:
|
|
459
|
+
openapi: z.object({
|
|
460
|
+
servers: z.array(
|
|
461
|
+
z.object({
|
|
462
|
+
url: z.url(),
|
|
463
|
+
description: z.string().optional()
|
|
576
464
|
})
|
|
577
465
|
).default([{ url: "http://localhost:3000", description: "Local development" }]),
|
|
578
|
-
specVersion:
|
|
579
|
-
title:
|
|
580
|
-
version:
|
|
581
|
-
outDir:
|
|
466
|
+
specVersion: z.enum(["3.1.0", "3.0.3"]).default("3.1.0"),
|
|
467
|
+
title: z.string().default("TheoKit App"),
|
|
468
|
+
version: z.string().default("0.0.0"),
|
|
469
|
+
outDir: z.string().default(".theokit")
|
|
582
470
|
}).optional(),
|
|
583
471
|
/**
|
|
584
472
|
* G5 T1.3 — error envelope transformer hook (blueprint ADR D3).
|
|
@@ -595,7 +483,7 @@ var theoConfigSchema = z8.object({
|
|
|
595
483
|
* with a function-typed runtime guard preserves the call-site type
|
|
596
484
|
* without trading off Zod runtime validation.
|
|
597
485
|
*/
|
|
598
|
-
formatError:
|
|
486
|
+
formatError: z.custom((val) => typeof val === "function", {
|
|
599
487
|
message: "formatError must be a function"
|
|
600
488
|
}).optional()
|
|
601
489
|
}).refine((cfg) => !Object.values(cfg.services).some((s) => s.port === cfg.port), {
|
|
@@ -674,6 +562,46 @@ async function loadConfig(dir) {
|
|
|
674
562
|
return result.data;
|
|
675
563
|
}
|
|
676
564
|
|
|
565
|
+
// src/config/resolve-plugin-specifiers.ts
|
|
566
|
+
import { isAbsolute, resolve as resolve3 } from "path";
|
|
567
|
+
import { pathToFileURL } from "url";
|
|
568
|
+
var UnresolvablePluginSpecifierError = class extends Error {
|
|
569
|
+
constructor(index, specifier, reason) {
|
|
570
|
+
super(`plugins[${index}] (${specifier}) could not be loaded: ${reason}`);
|
|
571
|
+
this.name = "UnresolvablePluginSpecifierError";
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
async function resolvePluginSpecifiers(plugins, cwd) {
|
|
575
|
+
const resolved = [];
|
|
576
|
+
for (const [index, entry] of plugins.entries()) {
|
|
577
|
+
resolved.push(typeof entry === "string" ? await importPlugin(entry, index, cwd) : entry);
|
|
578
|
+
}
|
|
579
|
+
return resolved;
|
|
580
|
+
}
|
|
581
|
+
async function importPlugin(specifier, index, cwd) {
|
|
582
|
+
const target = isAbsolute(specifier) ? specifier : resolve3(cwd, specifier);
|
|
583
|
+
let mod;
|
|
584
|
+
try {
|
|
585
|
+
mod = await import(
|
|
586
|
+
/* @vite-ignore */
|
|
587
|
+
pathToFileURL(target).href
|
|
588
|
+
);
|
|
589
|
+
} catch (err) {
|
|
590
|
+
throw new UnresolvablePluginSpecifierError(index, specifier, messageOf(err));
|
|
591
|
+
}
|
|
592
|
+
if (mod.default === void 0) {
|
|
593
|
+
throw new UnresolvablePluginSpecifierError(
|
|
594
|
+
index,
|
|
595
|
+
specifier,
|
|
596
|
+
"the module has no default export; a plugin module must `export default` its plugin"
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
return mod.default;
|
|
600
|
+
}
|
|
601
|
+
function messageOf(err) {
|
|
602
|
+
return err instanceof Error ? err.message : String(err);
|
|
603
|
+
}
|
|
604
|
+
|
|
677
605
|
// src/vite-plugin/theoui-detect.ts
|
|
678
606
|
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
679
607
|
import { dirname, join } from "path";
|
|
@@ -773,7 +701,14 @@ var DEFAULT_RESOLVED = {
|
|
|
773
701
|
async function resolvePluginConfig(projectRoot) {
|
|
774
702
|
try {
|
|
775
703
|
const userConfig = await loadConfig(projectRoot);
|
|
776
|
-
const
|
|
704
|
+
const observabilityPlugin = createObservabilityPluginFromConfig(
|
|
705
|
+
userConfig.observability,
|
|
706
|
+
process.env
|
|
707
|
+
);
|
|
708
|
+
const declaredPlugins = await resolvePluginSpecifiers(userConfig.plugins ?? [], projectRoot);
|
|
709
|
+
const pluginRunner = await createPluginRunnerFromConfig(
|
|
710
|
+
observabilityPlugin === void 0 ? declaredPlugins : [observabilityPlugin, ...declaredPlugins]
|
|
711
|
+
);
|
|
777
712
|
const transformer = resolveTransformer(userConfig.serialization);
|
|
778
713
|
let resolvedBatching;
|
|
779
714
|
if (userConfig.batching === true) {
|
|
@@ -807,7 +742,7 @@ async function resolvePluginConfig(projectRoot) {
|
|
|
807
742
|
}
|
|
808
743
|
|
|
809
744
|
// src/vite-plugin/configure-server-hook.ts
|
|
810
|
-
import { resolve as
|
|
745
|
+
import { resolve as resolve8, basename } from "path";
|
|
811
746
|
|
|
812
747
|
// src/devtools/server-side/route-manifest.ts
|
|
813
748
|
function buildPath(parents, segment) {
|
|
@@ -845,7 +780,7 @@ function broadcastRouteManifest(tree) {
|
|
|
845
780
|
|
|
846
781
|
// src/router/scan.ts
|
|
847
782
|
import { readdirSync, statSync, existsSync as existsSync4 } from "fs";
|
|
848
|
-
import { join as join2, resolve as
|
|
783
|
+
import { join as join2, resolve as resolve4 } from "path";
|
|
849
784
|
|
|
850
785
|
// src/router/types.ts
|
|
851
786
|
var ROUTE_FILE_NAMES = ["page", "layout", "error", "loading", "not-found"];
|
|
@@ -886,7 +821,7 @@ function attachRouteFiles(node, dir) {
|
|
|
886
821
|
for (const ext of ROUTE_FILE_EXTENSIONS) {
|
|
887
822
|
const filename = `${name}${ext}`;
|
|
888
823
|
if (existsSync4(join2(dir, filename))) {
|
|
889
|
-
setRouteFile(node, key,
|
|
824
|
+
setRouteFile(node, key, resolve4(dir, filename));
|
|
890
825
|
break;
|
|
891
826
|
}
|
|
892
827
|
}
|
|
@@ -935,7 +870,13 @@ function scanChild(parentDir, dirName, routePath) {
|
|
|
935
870
|
function scanDir(dir, segment, routePath) {
|
|
936
871
|
const node = { segment, path: routePath, children: [] };
|
|
937
872
|
attachRouteFiles(node, dir);
|
|
938
|
-
|
|
873
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
874
|
+
entries.sort((a, b) => {
|
|
875
|
+
if (a.name < b.name) return -1;
|
|
876
|
+
if (a.name > b.name) return 1;
|
|
877
|
+
return 0;
|
|
878
|
+
});
|
|
879
|
+
for (const entry of entries) {
|
|
939
880
|
if (!entry.isDirectory()) continue;
|
|
940
881
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
941
882
|
const child = scanChild(dir, entry.name, routePath);
|
|
@@ -1089,6 +1030,11 @@ function handleAgentCard(mod, name, route, baseUrl) {
|
|
|
1089
1030
|
|
|
1090
1031
|
// src/server/agent/approve-agent.ts
|
|
1091
1032
|
var APPROVE_SEGMENT = "/approve/";
|
|
1033
|
+
var APPROVE_PATH = /^\/api\/agents\/([^/]+)\/approve\/([^/]+)$/;
|
|
1034
|
+
function parseApprovalAgentName(urlPath) {
|
|
1035
|
+
const match = APPROVE_PATH.exec(urlPath);
|
|
1036
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
1037
|
+
}
|
|
1092
1038
|
function parseApprovalId(urlPath) {
|
|
1093
1039
|
const at = urlPath.indexOf(APPROVE_SEGMENT);
|
|
1094
1040
|
if (at === -1) return null;
|
|
@@ -1121,7 +1067,17 @@ function parseApprovalBody(body) {
|
|
|
1121
1067
|
}
|
|
1122
1068
|
return decision;
|
|
1123
1069
|
}
|
|
1124
|
-
async function
|
|
1070
|
+
async function refuseIfNotOwner(registry, approvalId, resolveSubject, params) {
|
|
1071
|
+
const owner = registry.ownerOf(approvalId);
|
|
1072
|
+
if (owner === void 0) return void 0;
|
|
1073
|
+
const subject = resolveSubject === void 0 ? null : await resolveSubject();
|
|
1074
|
+
if (subject?.id === owner) return void 0;
|
|
1075
|
+
return agentAccessDenied(
|
|
1076
|
+
{ allowed: false, reason: "the approval belongs to another subject" },
|
|
1077
|
+
params
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
async function handleAgentApproval(request, urlPath, registry, csrfMode = "strict", access = {}) {
|
|
1125
1081
|
if (csrfMode !== "off") {
|
|
1126
1082
|
const csrf = validateCsrfRequest(request);
|
|
1127
1083
|
if (!csrf.valid && csrfMode === "strict") {
|
|
@@ -1132,6 +1088,15 @@ async function handleAgentApproval(request, urlPath, registry, csrfMode = "stric
|
|
|
1132
1088
|
if (approvalId === null) {
|
|
1133
1089
|
return jsonError(400, "BAD_REQUEST", "Approval path must be /api/agents/<name>/approve/<id>.");
|
|
1134
1090
|
}
|
|
1091
|
+
const params = {
|
|
1092
|
+
agent: parseApprovalAgentName(urlPath) ?? "unknown",
|
|
1093
|
+
endpoint: "approve",
|
|
1094
|
+
approvalId
|
|
1095
|
+
};
|
|
1096
|
+
const decision = await admitAgentRequest(access.policy, access.resolveSubject, params);
|
|
1097
|
+
if (!decision.allowed) return agentAccessDenied(decision, params);
|
|
1098
|
+
const notOwner = await refuseIfNotOwner(registry, approvalId, access.resolveSubject, params);
|
|
1099
|
+
if (notOwner !== void 0) return notOwner;
|
|
1135
1100
|
let body = null;
|
|
1136
1101
|
try {
|
|
1137
1102
|
body = await request.json();
|
|
@@ -1145,25 +1110,13 @@ async function handleAgentApproval(request, urlPath, registry, csrfMode = "stric
|
|
|
1145
1110
|
if (!resolved) {
|
|
1146
1111
|
return jsonError(404, "NOT_PENDING", `No pending approval for id '${approvalId}'.`);
|
|
1147
1112
|
}
|
|
1113
|
+
closePauseSpan(approvalId, { resumeObserved: true });
|
|
1148
1114
|
return new Response(JSON.stringify({ resolved: true }), {
|
|
1149
1115
|
status: 200,
|
|
1150
1116
|
headers: { "content-type": "application/json" }
|
|
1151
1117
|
});
|
|
1152
1118
|
}
|
|
1153
1119
|
|
|
1154
|
-
// src/server/agent/list-approvals-handler.ts
|
|
1155
|
-
var LIST_PATH = /^\/api\/agents\/([^/]+)\/approvals$/;
|
|
1156
|
-
function isListApprovalsPath(urlPath) {
|
|
1157
|
-
const match = LIST_PATH.exec(urlPath);
|
|
1158
|
-
return match ? decodeURIComponent(match[1]) : null;
|
|
1159
|
-
}
|
|
1160
|
-
function handleListApprovals(registry) {
|
|
1161
|
-
return new Response(JSON.stringify({ approvals: registry.list() }), {
|
|
1162
|
-
status: 200,
|
|
1163
|
-
headers: { "content-type": "application/json; charset=utf-8" }
|
|
1164
|
-
});
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
1120
|
// src/server/agent/handle-agent-run-reconnect.ts
|
|
1168
1121
|
var RUN_STREAM_PATH = /^\/api\/agents\/([^/]+)\/runs\/([^/]+)\/stream$/;
|
|
1169
1122
|
function isAgentRunStreamPath(urlPath) {
|
|
@@ -1328,7 +1281,7 @@ function jsonError2(status, code, message) {
|
|
|
1328
1281
|
});
|
|
1329
1282
|
}
|
|
1330
1283
|
async function handleThreadMessage(args) {
|
|
1331
|
-
const { mod, apiKey, sessionId, request, source, csrfMode = "strict" } = args;
|
|
1284
|
+
const { mod, apiKey, sessionId, request, source, agentName, csrfMode = "strict" } = args;
|
|
1332
1285
|
if (csrfMode === "strict") {
|
|
1333
1286
|
const csrf = validateCsrfRequest(request);
|
|
1334
1287
|
if (!csrf.valid) return jsonError2(403, "CSRF_FAILED", `CSRF check failed: ${csrf.reason}`);
|
|
@@ -1346,7 +1299,9 @@ async function handleThreadMessage(args) {
|
|
|
1346
1299
|
{
|
|
1347
1300
|
registry: getThreadRunRegistry(),
|
|
1348
1301
|
cache: getRunEventCache(),
|
|
1349
|
-
|
|
1302
|
+
// usetheokit/theokit#381 — the request goes with it, so the run's spans join the trace of
|
|
1303
|
+
// the caller that queued it instead of opening one of their own.
|
|
1304
|
+
startRun: makeThreadStartRun(mod, apiKey, source, agentName, request)
|
|
1350
1305
|
},
|
|
1351
1306
|
sessionId,
|
|
1352
1307
|
input.message
|
|
@@ -1424,6 +1379,19 @@ function waitThenAttachStream(sessionId, request, registry, cache, idleWaitMs) {
|
|
|
1424
1379
|
return new Response(stream, { headers: { ...SSE_BASE_HEADERS } });
|
|
1425
1380
|
}
|
|
1426
1381
|
|
|
1382
|
+
// src/server/agent/list-approvals-handler.ts
|
|
1383
|
+
var LIST_PATH = /^\/api\/agents\/([^/]+)\/approvals$/;
|
|
1384
|
+
function isListApprovalsPath(urlPath) {
|
|
1385
|
+
const match = LIST_PATH.exec(urlPath);
|
|
1386
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
1387
|
+
}
|
|
1388
|
+
function handleListApprovals(registry) {
|
|
1389
|
+
return new Response(JSON.stringify({ approvals: registry.list() }), {
|
|
1390
|
+
status: 200,
|
|
1391
|
+
headers: { "content-type": "application/json; charset=utf-8" }
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1427
1395
|
// src/server/agent/serve-aux-routes.ts
|
|
1428
1396
|
function jsonError3(status, code, message) {
|
|
1429
1397
|
return new Response(JSON.stringify({ error: { code, message } }), {
|
|
@@ -1431,73 +1399,135 @@ function jsonError3(status, code, message) {
|
|
|
1431
1399
|
headers: { "content-type": "application/json; charset=utf-8" }
|
|
1432
1400
|
});
|
|
1433
1401
|
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
const
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1402
|
+
function routeFor(deps, name, build) {
|
|
1403
|
+
if (name === null) return null;
|
|
1404
|
+
const agent = deps.agents.find((a) => a.name === name);
|
|
1405
|
+
return agent === void 0 ? null : build(agent);
|
|
1406
|
+
}
|
|
1407
|
+
function matchGetAuxRoute(verb, urlPath, deps) {
|
|
1408
|
+
if (verb !== "GET") return null;
|
|
1409
|
+
const card = routeFor(
|
|
1410
|
+
deps,
|
|
1411
|
+
isAgentCardPath(urlPath),
|
|
1412
|
+
(agent) => ({ kind: "card", agent })
|
|
1413
|
+
);
|
|
1414
|
+
if (card !== null) return card;
|
|
1415
|
+
const approvals = routeFor(
|
|
1416
|
+
deps,
|
|
1417
|
+
isListApprovalsPath(urlPath),
|
|
1418
|
+
(agent) => ({ kind: "approvals", agent })
|
|
1419
|
+
);
|
|
1420
|
+
if (approvals !== null) return approvals;
|
|
1421
|
+
const run = isAgentRunStreamPath(urlPath);
|
|
1422
|
+
if (run !== null) {
|
|
1423
|
+
return routeFor(
|
|
1424
|
+
deps,
|
|
1425
|
+
run.name,
|
|
1426
|
+
(agent) => ({ kind: "run-stream", agent, runId: run.runId })
|
|
1427
|
+
);
|
|
1459
1428
|
}
|
|
1460
|
-
return null;
|
|
1461
|
-
}
|
|
1462
|
-
async function serveThreadRoute(request, method, urlPath, deps) {
|
|
1463
1429
|
const stream = isThreadStreamPath(urlPath);
|
|
1464
|
-
if (stream
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1430
|
+
if (stream === null) return null;
|
|
1431
|
+
return routeFor(
|
|
1432
|
+
deps,
|
|
1433
|
+
stream.name,
|
|
1434
|
+
(agent) => ({ kind: "thread-stream", agent, sessionId: stream.sessionId })
|
|
1435
|
+
);
|
|
1436
|
+
}
|
|
1437
|
+
async function matchPostAuxRoute(verb, urlPath, deps) {
|
|
1438
|
+
if (verb !== "POST") return null;
|
|
1469
1439
|
const msg = isThreadMessagePath(urlPath);
|
|
1470
1440
|
if (msg !== null) {
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1441
|
+
return routeFor(
|
|
1442
|
+
deps,
|
|
1443
|
+
msg.name,
|
|
1444
|
+
(agent2) => ({ kind: "thread-message", agent: agent2, sessionId: msg.sessionId })
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
const agent = routeFor(deps, isMcpPath(urlPath), (found) => found);
|
|
1448
|
+
if (agent === null) return null;
|
|
1449
|
+
const mod = await deps.loadModule(agent.filePath);
|
|
1450
|
+
return isMcpExposed(mod) ? { kind: "mcp", agent, mod } : null;
|
|
1451
|
+
}
|
|
1452
|
+
async function matchAgentAuxRoute(method, urlPath, deps) {
|
|
1453
|
+
const verb = method.toUpperCase();
|
|
1454
|
+
return matchGetAuxRoute(verb, urlPath, deps) ?? await matchPostAuxRoute(verb, urlPath, deps);
|
|
1455
|
+
}
|
|
1456
|
+
async function admitAux(deps, agent, params, body) {
|
|
1457
|
+
const mod = await deps.loadModule(agent.filePath);
|
|
1458
|
+
const decision = await admitAgentRequest(
|
|
1459
|
+
readAgentPolicy(mod, agent.filePath),
|
|
1460
|
+
deps.resolveSubject,
|
|
1461
|
+
params,
|
|
1462
|
+
body
|
|
1463
|
+
);
|
|
1464
|
+
return decision.allowed ? null : agentAccessDenied(decision, params);
|
|
1465
|
+
}
|
|
1466
|
+
async function serveMatchedAuxRoute(route, request, deps) {
|
|
1467
|
+
if (route.kind === "card") {
|
|
1468
|
+
const mod = await deps.loadModule(route.agent.filePath);
|
|
1469
|
+
return handleAgentCard(mod, route.agent.name, route.agent.agentPath, deps.baseUrl);
|
|
1470
|
+
}
|
|
1471
|
+
if (route.kind === "approvals") {
|
|
1472
|
+
const refusal = await admitAux(deps, route.agent, {
|
|
1473
|
+
agent: route.agent.name,
|
|
1474
|
+
endpoint: "approvals"
|
|
1491
1475
|
});
|
|
1476
|
+
return refusal ?? handleListApprovals(getApprovalRegistry());
|
|
1492
1477
|
}
|
|
1493
|
-
|
|
1478
|
+
if (route.kind === "run-stream") {
|
|
1479
|
+
return handleAgentRunReconnect(route.runId, request, getRunEventCache());
|
|
1480
|
+
}
|
|
1481
|
+
if (route.kind === "mcp") return serveMcpRoute(route, request, deps);
|
|
1482
|
+
return serveThreadRoute(route, request, deps);
|
|
1494
1483
|
}
|
|
1495
|
-
async function
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1484
|
+
async function serveThreadRoute(route, request, deps) {
|
|
1485
|
+
const { agent, sessionId } = route;
|
|
1486
|
+
if (route.kind === "thread-stream") {
|
|
1487
|
+
const refusal2 = await admitAux(deps, agent, {
|
|
1488
|
+
agent: agent.name,
|
|
1489
|
+
endpoint: "thread-stream",
|
|
1490
|
+
sessionId
|
|
1491
|
+
});
|
|
1492
|
+
return refusal2 ?? handleThreadStream(sessionId, request);
|
|
1493
|
+
}
|
|
1494
|
+
const refusal = await admitAux(deps, agent, {
|
|
1495
|
+
agent: agent.name,
|
|
1496
|
+
endpoint: "thread-message",
|
|
1497
|
+
sessionId
|
|
1498
|
+
});
|
|
1499
|
+
if (refusal !== null) return refusal;
|
|
1500
|
+
if (deps.resolveApiKey === void 0) {
|
|
1501
|
+
return jsonError3(
|
|
1502
|
+
501,
|
|
1503
|
+
"NOT_CONFIGURED",
|
|
1504
|
+
"Thread follow-up requires a provider API key (resolveApiKey was not provided to serveMatchedAuxRoute)."
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1499
1507
|
const mod = await deps.loadModule(agent.filePath);
|
|
1500
|
-
|
|
1508
|
+
return handleThreadMessage({
|
|
1509
|
+
mod,
|
|
1510
|
+
// Passed unresolved: `makeThreadStartRun` calls it once the module is compiled and the
|
|
1511
|
+
// model is known (theokit#328).
|
|
1512
|
+
apiKey: deps.resolveApiKey,
|
|
1513
|
+
sessionId,
|
|
1514
|
+
request,
|
|
1515
|
+
source: `agent "${agent.name}"`,
|
|
1516
|
+
// usetheokit/theokit#406 — the label above reads well in an `AgentDefinitionError` and is not
|
|
1517
|
+
// a name; the spans get the name, so the same agent is one series whichever route started it.
|
|
1518
|
+
agentName: agent.name,
|
|
1519
|
+
csrfMode: deps.csrfMode ?? "strict"
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
async function serveMcpRoute(route, request, deps) {
|
|
1523
|
+
const { agent, mod } = route;
|
|
1524
|
+
const mcpParams = { agent: agent.name, endpoint: "mcp" };
|
|
1525
|
+
const mcpDecision = await admitAgentRequest(
|
|
1526
|
+
readAgentPolicy(mod, agent.filePath),
|
|
1527
|
+
deps.resolveSubject,
|
|
1528
|
+
mcpParams
|
|
1529
|
+
);
|
|
1530
|
+
if (!mcpDecision.allowed) return agentAccessDenied(mcpDecision, mcpParams);
|
|
1501
1531
|
const csrfMode = deps.csrfMode ?? "strict";
|
|
1502
1532
|
if (csrfMode === "strict") {
|
|
1503
1533
|
const csrf = validateCsrfRequest(request);
|
|
@@ -1514,38 +1544,53 @@ function isMcpExposed(mod) {
|
|
|
1514
1544
|
return mod?.mcp === true;
|
|
1515
1545
|
}
|
|
1516
1546
|
|
|
1517
|
-
// src/server/http/
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
res.writeHead(response.status, response.statusText, otherHeaders);
|
|
1529
|
-
if (response.body === null) {
|
|
1530
|
-
res.end();
|
|
1547
|
+
// src/server/http/plugin-lifecycle.ts
|
|
1548
|
+
function messageOf2(err, fallback) {
|
|
1549
|
+
return err instanceof Error ? err.message : fallback;
|
|
1550
|
+
}
|
|
1551
|
+
async function serveThroughPluginLifecycle(target, serve) {
|
|
1552
|
+
const { res, requestId, pluginRunner, failureMessage } = target;
|
|
1553
|
+
let request;
|
|
1554
|
+
try {
|
|
1555
|
+
request = target.source.toRequest();
|
|
1556
|
+
} catch (err) {
|
|
1557
|
+
sendError(res, "INTERNAL", messageOf2(err, failureMessage), 500, void 0, requestId);
|
|
1531
1558
|
return;
|
|
1532
1559
|
}
|
|
1533
|
-
const
|
|
1560
|
+
const pluginCtx = { request, response: res, ctx: {}, requestId };
|
|
1561
|
+
if (pluginRunner) {
|
|
1562
|
+
pluginRunner.applyDecorations(pluginCtx.ctx);
|
|
1563
|
+
const onRequest = await pluginRunner.runOnRequest(pluginCtx);
|
|
1564
|
+
if (onRequest.shortCircuited) return;
|
|
1565
|
+
}
|
|
1534
1566
|
try {
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
}
|
|
1540
|
-
res.end();
|
|
1541
|
-
} finally {
|
|
1542
|
-
reader.releaseLock();
|
|
1567
|
+
await serve(request, pluginCtx);
|
|
1568
|
+
} catch (err) {
|
|
1569
|
+
if (pluginRunner) await pluginRunner.runOnError(pluginCtx, err);
|
|
1570
|
+
sendError(res, "INTERNAL", messageOf2(err, failureMessage), 500, void 0, requestId);
|
|
1543
1571
|
}
|
|
1572
|
+
if (pluginRunner) await pluginRunner.runOnResponse(pluginCtx);
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
// src/server/http/resolve-agent-subject.ts
|
|
1576
|
+
function createAgentSubjectResolver(sources) {
|
|
1577
|
+
let pending;
|
|
1578
|
+
return () => {
|
|
1579
|
+
pending ??= resolve5(sources);
|
|
1580
|
+
return pending;
|
|
1581
|
+
};
|
|
1582
|
+
}
|
|
1583
|
+
async function resolve5(sources) {
|
|
1584
|
+
const { req, res, loadModule, serverDir, pluginRunner } = sources;
|
|
1585
|
+
const produced = serverDir === void 0 ? {} : await createServerContext(req, res, loadModule, serverDir);
|
|
1586
|
+
const ctx = produced ?? {};
|
|
1587
|
+
pluginRunner?.applyDecorations(ctx);
|
|
1588
|
+
return subjectFromContext(ctx);
|
|
1544
1589
|
}
|
|
1545
1590
|
|
|
1546
1591
|
// src/vite-plugin/agent-middleware.ts
|
|
1547
1592
|
var PREFIX2 = "/api/agents/";
|
|
1548
|
-
async function serveApprove(req, res, urlPath,
|
|
1593
|
+
async function serveApprove(req, res, urlPath, deps, log) {
|
|
1549
1594
|
const method = (req.method ?? "POST").toUpperCase();
|
|
1550
1595
|
if (method !== "POST") {
|
|
1551
1596
|
sendError(
|
|
@@ -1565,24 +1610,36 @@ async function serveApprove(req, res, urlPath, csrfMode, log) {
|
|
|
1565
1610
|
});
|
|
1566
1611
|
return;
|
|
1567
1612
|
}
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
urlPath,
|
|
1572
|
-
getApprovalRegistry(),
|
|
1573
|
-
csrfMode
|
|
1574
|
-
);
|
|
1575
|
-
await writeWebResponseToServerResponse(response, res);
|
|
1576
|
-
} catch (err) {
|
|
1577
|
-
sendError(
|
|
1613
|
+
await serveThroughPluginLifecycle(
|
|
1614
|
+
{
|
|
1615
|
+
source: createWebRequestSource(req),
|
|
1578
1616
|
res,
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1617
|
+
requestId: log.requestId,
|
|
1618
|
+
pluginRunner: deps.pluginRunner,
|
|
1619
|
+
failureMessage: "Approve handler failed"
|
|
1620
|
+
},
|
|
1621
|
+
async (request) => {
|
|
1622
|
+
const agent = scanAgents(deps.projectRoot, deps.agentsDir).find(
|
|
1623
|
+
(a) => a.name === parseApprovalAgentName(urlPath)
|
|
1624
|
+
);
|
|
1625
|
+
const resolveSubject = createAgentSubjectResolver({
|
|
1626
|
+
req,
|
|
1627
|
+
res,
|
|
1628
|
+
loadModule: deps.loadModule,
|
|
1629
|
+
serverDir: deps.serverDir,
|
|
1630
|
+
pluginRunner: deps.pluginRunner
|
|
1631
|
+
});
|
|
1632
|
+
const policy = agent === void 0 ? void 0 : readAgentPolicy(await deps.loadModule(agent.filePath), agent.filePath);
|
|
1633
|
+
const response = await handleAgentApproval(
|
|
1634
|
+
request,
|
|
1635
|
+
urlPath,
|
|
1636
|
+
getApprovalRegistry(),
|
|
1637
|
+
deps.csrfMode,
|
|
1638
|
+
{ policy, resolveSubject }
|
|
1639
|
+
);
|
|
1640
|
+
await writeWebResponseToServerResponse(response, res);
|
|
1641
|
+
}
|
|
1642
|
+
);
|
|
1586
1643
|
logRequest({
|
|
1587
1644
|
method,
|
|
1588
1645
|
url: req.url ?? "",
|
|
@@ -1594,54 +1651,69 @@ async function serveApprove(req, res, urlPath, csrfMode, log) {
|
|
|
1594
1651
|
async function serveAux(req, res, next, urlPath, deps) {
|
|
1595
1652
|
const requestId = randomUUID2();
|
|
1596
1653
|
const start = Date.now();
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
if (response === null) {
|
|
1609
|
-
next();
|
|
1610
|
-
return;
|
|
1611
|
-
}
|
|
1612
|
-
res.setHeader("x-request-id", requestId);
|
|
1613
|
-
await writeWebResponseToServerResponse(response, res);
|
|
1614
|
-
} catch (err) {
|
|
1615
|
-
res.setHeader("x-request-id", requestId);
|
|
1616
|
-
sendError(
|
|
1654
|
+
const auxDeps = {
|
|
1655
|
+
agents: scanAgents(deps.projectRoot, deps.agentsDir),
|
|
1656
|
+
loadModule: deps.loadModule,
|
|
1657
|
+
baseUrl: `http://${req.headers.host ?? "localhost"}`,
|
|
1658
|
+
csrfMode: deps.csrfMode,
|
|
1659
|
+
// M39 — the thread follow-up route drives the agent; resolve the key on demand.
|
|
1660
|
+
// theokit#328 — the thread route drives an agent, so its key follows the model too.
|
|
1661
|
+
resolveApiKey: (model) => resolveProvider(model).apiKey,
|
|
1662
|
+
// usetheokit/theokit#365 — parity with `theokit start`; lazy for the same reason.
|
|
1663
|
+
resolveSubject: createAgentSubjectResolver({
|
|
1664
|
+
req,
|
|
1617
1665
|
res,
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1666
|
+
loadModule: deps.loadModule,
|
|
1667
|
+
serverDir: deps.serverDir,
|
|
1668
|
+
pluginRunner: deps.pluginRunner
|
|
1669
|
+
})
|
|
1670
|
+
};
|
|
1671
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
1672
|
+
const route = await matchAgentAuxRoute(method, urlPath, auxDeps);
|
|
1673
|
+
if (route === null) {
|
|
1674
|
+
next();
|
|
1675
|
+
return;
|
|
1624
1676
|
}
|
|
1677
|
+
res.setHeader("x-request-id", requestId);
|
|
1678
|
+
await serveThroughPluginLifecycle(
|
|
1679
|
+
{
|
|
1680
|
+
source: createWebRequestSource(req),
|
|
1681
|
+
res,
|
|
1682
|
+
requestId,
|
|
1683
|
+
pluginRunner: deps.pluginRunner,
|
|
1684
|
+
failureMessage: "Agent aux handler failed"
|
|
1685
|
+
},
|
|
1686
|
+
async (request) => {
|
|
1687
|
+
await writeWebResponseToServerResponse(
|
|
1688
|
+
await serveMatchedAuxRoute(route, request, auxDeps),
|
|
1689
|
+
res
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
);
|
|
1625
1693
|
logRequest({
|
|
1626
|
-
method
|
|
1694
|
+
method,
|
|
1627
1695
|
url: req.url ?? "",
|
|
1628
1696
|
status: res.statusCode,
|
|
1629
1697
|
duration: Date.now() - start,
|
|
1630
1698
|
requestId
|
|
1631
1699
|
});
|
|
1632
1700
|
}
|
|
1633
|
-
function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir = "agents",
|
|
1701
|
+
function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir = "agents", deps = {}) {
|
|
1702
|
+
const { pluginRunner, serverDir } = deps;
|
|
1634
1703
|
const loadModule = createViteLoader(vite);
|
|
1704
|
+
const cardDeps = () => ({
|
|
1705
|
+
projectRoot,
|
|
1706
|
+
loadModule,
|
|
1707
|
+
agentsDir,
|
|
1708
|
+
csrfMode,
|
|
1709
|
+
serverDir,
|
|
1710
|
+
pluginRunner
|
|
1711
|
+
});
|
|
1635
1712
|
return (req, res, next) => {
|
|
1636
1713
|
void (async () => {
|
|
1637
1714
|
const url = req.url ?? "";
|
|
1638
1715
|
if (isAgentCardPath(url.split("?")[0]) !== null) {
|
|
1639
|
-
await serveAux(req, res, next, url.split("?")[0],
|
|
1640
|
-
projectRoot,
|
|
1641
|
-
loadModule,
|
|
1642
|
-
agentsDir,
|
|
1643
|
-
csrfMode
|
|
1644
|
-
});
|
|
1716
|
+
await serveAux(req, res, next, url.split("?")[0], cardDeps());
|
|
1645
1717
|
return;
|
|
1646
1718
|
}
|
|
1647
1719
|
if (!url.startsWith(PREFIX2)) {
|
|
@@ -1653,16 +1725,12 @@ function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir
|
|
|
1653
1725
|
res.setHeader("x-request-id", requestId);
|
|
1654
1726
|
const urlPath = url.split("?")[0];
|
|
1655
1727
|
if (isApprovalPath(urlPath)) {
|
|
1656
|
-
await serveApprove(req, res, urlPath,
|
|
1657
|
-
return;
|
|
1658
|
-
}
|
|
1659
|
-
if (isListApprovalsPath(urlPath) !== null || isMcpPath(urlPath) !== null) {
|
|
1660
|
-
await serveAux(req, res, next, urlPath, { projectRoot, loadModule, agentsDir, csrfMode });
|
|
1728
|
+
await serveApprove(req, res, urlPath, cardDeps(), { requestId, start });
|
|
1661
1729
|
return;
|
|
1662
1730
|
}
|
|
1663
1731
|
const agent = scanAgents(projectRoot, agentsDir).find((a) => a.agentPath === urlPath);
|
|
1664
1732
|
if (!agent) {
|
|
1665
|
-
next();
|
|
1733
|
+
await serveAux(req, res, next, urlPath, cardDeps());
|
|
1666
1734
|
return;
|
|
1667
1735
|
}
|
|
1668
1736
|
const method = (req.method ?? "POST").toUpperCase();
|
|
@@ -1689,7 +1757,8 @@ function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir
|
|
|
1689
1757
|
loadModule,
|
|
1690
1758
|
csrfMode,
|
|
1691
1759
|
projectRoot,
|
|
1692
|
-
pluginRunner
|
|
1760
|
+
pluginRunner,
|
|
1761
|
+
serverDir
|
|
1693
1762
|
});
|
|
1694
1763
|
})();
|
|
1695
1764
|
};
|
|
@@ -1706,65 +1775,44 @@ async function serveAgentTurn(t) {
|
|
|
1706
1775
|
loadModule,
|
|
1707
1776
|
csrfMode,
|
|
1708
1777
|
projectRoot,
|
|
1709
|
-
pluginRunner
|
|
1778
|
+
pluginRunner,
|
|
1779
|
+
serverDir
|
|
1710
1780
|
} = t;
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1781
|
+
const resolveSubject = createAgentSubjectResolver({
|
|
1782
|
+
req,
|
|
1783
|
+
res,
|
|
1784
|
+
loadModule,
|
|
1785
|
+
serverDir,
|
|
1786
|
+
pluginRunner
|
|
1787
|
+
});
|
|
1788
|
+
await serveThroughPluginLifecycle(
|
|
1789
|
+
{
|
|
1790
|
+
source: createWebRequestSource(req),
|
|
1718
1791
|
res,
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
url,
|
|
1735
|
-
status: res.statusCode,
|
|
1736
|
-
duration: Date.now() - start,
|
|
1737
|
-
requestId
|
|
1792
|
+
requestId,
|
|
1793
|
+
pluginRunner,
|
|
1794
|
+
failureMessage: "Agent handler failed"
|
|
1795
|
+
},
|
|
1796
|
+
async (request) => {
|
|
1797
|
+
const mod = await loadModule(agent.filePath);
|
|
1798
|
+
const apiKey = (model) => resolveProvider(model).apiKey;
|
|
1799
|
+
const response = await mountAgent(mod, request, apiKey, {
|
|
1800
|
+
source: agent.filePath,
|
|
1801
|
+
csrfMode,
|
|
1802
|
+
projectRoot,
|
|
1803
|
+
// usetheokit/theokit#365 — the policy comes off `mod`; the caller owes the identity.
|
|
1804
|
+
// usetheokit/theokit#406 — and the same name labels the run's spans.
|
|
1805
|
+
agentName: agent.name,
|
|
1806
|
+
resolveSubject
|
|
1738
1807
|
});
|
|
1739
|
-
|
|
1808
|
+
await writeWebResponseToServerResponse(response, res);
|
|
1740
1809
|
}
|
|
1741
|
-
|
|
1742
|
-
try {
|
|
1743
|
-
const mod = await loadModule(agent.filePath);
|
|
1744
|
-
const apiKey = (model) => resolveProvider(model).apiKey;
|
|
1745
|
-
const response = await mountAgent(mod, request, apiKey, {
|
|
1746
|
-
source: agent.filePath,
|
|
1747
|
-
csrfMode,
|
|
1748
|
-
projectRoot
|
|
1749
|
-
});
|
|
1750
|
-
await writeWebResponseToServerResponse(response, res);
|
|
1751
|
-
} catch (err) {
|
|
1752
|
-
if (pluginRunner) await pluginRunner.runOnError(pluginCtx, err);
|
|
1753
|
-
sendError(
|
|
1754
|
-
res,
|
|
1755
|
-
"INTERNAL",
|
|
1756
|
-
err instanceof Error ? err.message : "Agent handler failed",
|
|
1757
|
-
500,
|
|
1758
|
-
void 0,
|
|
1759
|
-
requestId
|
|
1760
|
-
);
|
|
1761
|
-
}
|
|
1762
|
-
if (pluginRunner) await pluginRunner.runOnResponse(pluginCtx);
|
|
1810
|
+
);
|
|
1763
1811
|
logRequest({ method, url, status: res.statusCode, duration: Date.now() - start, requestId });
|
|
1764
1812
|
}
|
|
1765
1813
|
|
|
1766
1814
|
// src/vite-plugin/api-middleware.ts
|
|
1767
|
-
import { resolve as
|
|
1815
|
+
import { resolve as resolve6 } from "path";
|
|
1768
1816
|
function shouldBypassApiMiddleware(url, prefixes) {
|
|
1769
1817
|
if (!url.startsWith("/api/")) return true;
|
|
1770
1818
|
if (prefixes.length === 0) return false;
|
|
@@ -1812,10 +1860,10 @@ async function handleBatchIfMatch(req, res, ctx) {
|
|
|
1812
1860
|
async function handleBatchInline(req, res, batching, requestId) {
|
|
1813
1861
|
try {
|
|
1814
1862
|
const chunks = [];
|
|
1815
|
-
await new Promise((
|
|
1863
|
+
await new Promise((resolve11, reject) => {
|
|
1816
1864
|
req.on("data", (c) => chunks.push(c));
|
|
1817
1865
|
req.on("end", () => {
|
|
1818
|
-
|
|
1866
|
+
resolve11();
|
|
1819
1867
|
});
|
|
1820
1868
|
req.on("error", reject);
|
|
1821
1869
|
});
|
|
@@ -1871,7 +1919,7 @@ async function runPluginsBeforeRouteMatch(pluginRunner, reqCtx) {
|
|
|
1871
1919
|
}
|
|
1872
1920
|
async function tryControllerFallthrough(ctx) {
|
|
1873
1921
|
const handled = await dispatchControllerRequest({
|
|
1874
|
-
controllersDir:
|
|
1922
|
+
controllersDir: resolve6(ctx.serverDir, "controllers"),
|
|
1875
1923
|
loadModule: ctx.loadModule,
|
|
1876
1924
|
req: ctx.req,
|
|
1877
1925
|
res: ctx.res,
|
|
@@ -1880,6 +1928,14 @@ async function tryControllerFallthrough(ctx) {
|
|
|
1880
1928
|
requestId: ctx.requestId,
|
|
1881
1929
|
// M47 — serve @Expose-bound agent routes via the ONE runtime (mountAgent). CSRF is already enforced
|
|
1882
1930
|
// once at the controller-dispatch boundary (G5), so mountAgent runs with csrfMode 'off' (no double gate).
|
|
1931
|
+
//
|
|
1932
|
+
// usetheokit/theokit#365 gated the CONVENTION endpoints (`agents/<name>.ts`) and deliberately
|
|
1933
|
+
// left this one to the decorator stack: an `@Expose` route is a controller method, so its
|
|
1934
|
+
// access decision is the controller's `@Guard` chain, which the dispatcher already runs before
|
|
1935
|
+
// it gets here. Passing a policy as well would give this one surface two authorization
|
|
1936
|
+
// mechanisms and no rule for which wins. What is NOT solved by that: an `@Expose`d agent shares
|
|
1937
|
+
// the conversation store with the convention endpoints, so a guard that admits a caller admits
|
|
1938
|
+
// them to whatever `sessionId` the body names — see the advisory.
|
|
1883
1939
|
serveAgent: (agent, request) => mountAgent(agent, request, (model) => resolveProvider(model).apiKey, {
|
|
1884
1940
|
source: "expose",
|
|
1885
1941
|
csrfMode: "off"
|
|
@@ -2007,7 +2063,7 @@ function createApiMiddleware(vite, serverDir, rateLimitConfigOrOptions) {
|
|
|
2007
2063
|
|
|
2008
2064
|
// src/vite-plugin/ssr-dev-middleware.ts
|
|
2009
2065
|
import { readFileSync as readFileSync2 } from "fs";
|
|
2010
|
-
import { resolve as
|
|
2066
|
+
import { resolve as resolve7 } from "path";
|
|
2011
2067
|
|
|
2012
2068
|
// src/core/contracts/find-root-div.ts
|
|
2013
2069
|
function maskHtmlComments(html) {
|
|
@@ -2098,7 +2154,7 @@ function setupSsrDevMiddleware(server, opts) {
|
|
|
2098
2154
|
return;
|
|
2099
2155
|
}
|
|
2100
2156
|
try {
|
|
2101
|
-
const indexPath =
|
|
2157
|
+
const indexPath = resolve7(opts.projectRoot, "index.html");
|
|
2102
2158
|
let template = readFileSync2(indexPath, "utf-8");
|
|
2103
2159
|
const nonce = generateNonce();
|
|
2104
2160
|
template = await server.transformIndexHtml(url, template);
|
|
@@ -2217,7 +2273,12 @@ async function runConfigureServer(server, ctx) {
|
|
|
2217
2273
|
})
|
|
2218
2274
|
);
|
|
2219
2275
|
server.middlewares.use(
|
|
2220
|
-
createAgentMiddleware(server, ctx.projectRoot, ctx.csrfMode, ctx.agentsDir,
|
|
2276
|
+
createAgentMiddleware(server, ctx.projectRoot, ctx.csrfMode, ctx.agentsDir, {
|
|
2277
|
+
pluginRunner: ctx.pluginRunner,
|
|
2278
|
+
// usetheokit/theokit#365 — the same backend root the route middleware scans, so an agent's
|
|
2279
|
+
// declared policy is judged against the identity `server/context.ts` establishes.
|
|
2280
|
+
serverDir
|
|
2281
|
+
})
|
|
2221
2282
|
);
|
|
2222
2283
|
const servicesProxyPrefixes = ctx.services && Object.keys(ctx.services).length > 0 ? Object.values(ctx.services).map((s) => s.proxy) : [];
|
|
2223
2284
|
const csrfReadinessStore = ctx.csrfReadinessStoreOverride ?? new CsrfReadinessStore();
|
|
@@ -2236,7 +2297,7 @@ async function runConfigureServer(server, ctx) {
|
|
|
2236
2297
|
csrfReadinessStore
|
|
2237
2298
|
})
|
|
2238
2299
|
);
|
|
2239
|
-
const configPath =
|
|
2300
|
+
const configPath = resolve8(ctx.projectRoot, "theo.config.ts");
|
|
2240
2301
|
server.watcher.on("change", (file) => {
|
|
2241
2302
|
if (file === configPath) {
|
|
2242
2303
|
console.warn(
|
|
@@ -2264,9 +2325,9 @@ async function runConfigureServer(server, ctx) {
|
|
|
2264
2325
|
server.watcher.on("unlink", handleRouteChange);
|
|
2265
2326
|
if (ctx.resolvedOpenApi !== void 0) {
|
|
2266
2327
|
const openApiCfg = ctx.resolvedOpenApi;
|
|
2267
|
-
const { reEmitOpenApi } = await import("./dev-emit-
|
|
2328
|
+
const { reEmitOpenApi } = await import("./dev-emit-MVAJAFGX.js");
|
|
2268
2329
|
const openApiServerDir = ctx.serverDir;
|
|
2269
|
-
const openApiDistDir =
|
|
2330
|
+
const openApiDistDir = resolve8(ctx.projectRoot, ctx.resolvedDistDir);
|
|
2270
2331
|
const isRouteFileForOpenApi = (file) => file.startsWith(openApiServerDir) && /\.(ts|tsx|js|mjs)$/.test(file);
|
|
2271
2332
|
void reEmitOpenApi(openApiServerDir, openApiDistDir, openApiCfg);
|
|
2272
2333
|
server.watcher.on("change", (file) => {
|
|
@@ -2316,7 +2377,7 @@ async function integrateStudio(importStudio = () => import(
|
|
|
2316
2377
|
// src/vite-plugin/integrate-ui.ts
|
|
2317
2378
|
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
|
|
2318
2379
|
import { dirname as dirname3, join as join4 } from "path";
|
|
2319
|
-
import { pathToFileURL } from "url";
|
|
2380
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
2320
2381
|
|
|
2321
2382
|
// src/vite-plugin/auto-detect.ts
|
|
2322
2383
|
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
@@ -2448,7 +2509,7 @@ function resolveConsumerImport(name, cwd) {
|
|
|
2448
2509
|
entry ??= pkg.module ?? pkg.main;
|
|
2449
2510
|
if (!entry) return null;
|
|
2450
2511
|
const cleaned = entry.replace(/^\.\//, "");
|
|
2451
|
-
return
|
|
2512
|
+
return pathToFileURL2(join4(pkgDir, cleaned)).href;
|
|
2452
2513
|
} catch {
|
|
2453
2514
|
return null;
|
|
2454
2515
|
}
|
|
@@ -2521,7 +2582,7 @@ async function integrateUseTheoUI(cwd, opts) {
|
|
|
2521
2582
|
return [];
|
|
2522
2583
|
}
|
|
2523
2584
|
try {
|
|
2524
|
-
uiMod = await import(
|
|
2585
|
+
uiMod = await import(pathToFileURL2(uiPluginPath).href);
|
|
2525
2586
|
} catch (err) {
|
|
2526
2587
|
console.warn(
|
|
2527
2588
|
`[theokit] @theokit/ui/vite-plugin dynamic import failed (${err.message}). Skipping auto-config.`
|
|
@@ -2571,19 +2632,9 @@ async function integrateUseTheoUI(cwd, opts) {
|
|
|
2571
2632
|
return [...tailwindPlugins, ...uiPlugins];
|
|
2572
2633
|
}
|
|
2573
2634
|
|
|
2574
|
-
// src/vite-plugin/resolve-theo-root.ts
|
|
2575
|
-
import { existsSync as existsSync7 } from "fs";
|
|
2576
|
-
import { resolve as resolve7 } from "path";
|
|
2577
|
-
function resolveTheoRootDir(currentDir) {
|
|
2578
|
-
if (existsSync7(resolve7(currentDir, "client"))) {
|
|
2579
|
-
return currentDir;
|
|
2580
|
-
}
|
|
2581
|
-
return resolve7(currentDir, "..");
|
|
2582
|
-
}
|
|
2583
|
-
|
|
2584
2635
|
// src/vite-plugin/transform-html-hook.ts
|
|
2585
|
-
import { existsSync as
|
|
2586
|
-
import { resolve as
|
|
2636
|
+
import { existsSync as existsSync7 } from "fs";
|
|
2637
|
+
import { resolve as resolve9 } from "path";
|
|
2587
2638
|
|
|
2588
2639
|
// src/vite-plugin/inject-devtools.ts
|
|
2589
2640
|
var DEVTOOLS_VIRTUAL_ID = "/@theo/devtools/entry.js";
|
|
@@ -2683,7 +2734,7 @@ function runTransformIndexHtml(html, ctx) {
|
|
|
2683
2734
|
next = devtools.html;
|
|
2684
2735
|
const styles = injectStylesheets(next, {
|
|
2685
2736
|
isDev: ctx.isDevMode.value,
|
|
2686
|
-
hasPackage: (name) =>
|
|
2737
|
+
hasPackage: (name) => existsSync7(resolve9(ctx.projectRoot, "node_modules", ...name.split("/")))
|
|
2687
2738
|
});
|
|
2688
2739
|
next = styles.html;
|
|
2689
2740
|
return next;
|
|
@@ -2786,6 +2837,46 @@ function generateSingleShotEntry(options) {
|
|
|
2786
2837
|
`}`
|
|
2787
2838
|
].join("\n");
|
|
2788
2839
|
}
|
|
2840
|
+
function streamingDocumentHelpers() {
|
|
2841
|
+
return [
|
|
2842
|
+
`function __theoHydrationScript(hydrationData, nonce) {`,
|
|
2843
|
+
// `<` is escaped rather than the whole payload: loader data is developer
|
|
2844
|
+
// data, and the only sequence that can break out of a script element is
|
|
2845
|
+
// `</script`. Mirrors what the non-streaming path does in request-handler.ts.
|
|
2846
|
+
` const json = JSON.stringify(hydrationData).replace(/</g, '\\u003c')`,
|
|
2847
|
+
` const attr = nonce ? ' nonce="' + nonce + '"' : ''`,
|
|
2848
|
+
` return '<script' + attr + '>window.__staticRouterHydrationData=' + json + '<' + '/script>'`,
|
|
2849
|
+
`}`,
|
|
2850
|
+
``,
|
|
2851
|
+
`function __theoDocumentStream(appStream, hydrationData, options) {`,
|
|
2852
|
+
` const encoder = new TextEncoder()`,
|
|
2853
|
+
` const head = options.htmlHead ?? ''`,
|
|
2854
|
+
` const tail = options.htmlTail ?? ''`,
|
|
2855
|
+
` return new ReadableStream({`,
|
|
2856
|
+
` async start(controller) {`,
|
|
2857
|
+
// Its own chunk: the reader gets <head> before React has rendered anything.
|
|
2858
|
+
` if (head) controller.enqueue(encoder.encode(head))`,
|
|
2859
|
+
` const reader = appStream.getReader()`,
|
|
2860
|
+
` try {`,
|
|
2861
|
+
` for (;;) {`,
|
|
2862
|
+
` const { done, value } = await reader.read()`,
|
|
2863
|
+
` if (done) break`,
|
|
2864
|
+
` controller.enqueue(value)`,
|
|
2865
|
+
` }`,
|
|
2866
|
+
` } finally {`,
|
|
2867
|
+
` reader.releaseLock()`,
|
|
2868
|
+
` }`,
|
|
2869
|
+
// The hydration script trails the app markup and precedes the tail, so it
|
|
2870
|
+
// still runs before the client entry the tail loads.
|
|
2871
|
+
` controller.enqueue(`,
|
|
2872
|
+
` encoder.encode(__theoHydrationScript(hydrationData, options.nonce) + tail),`,
|
|
2873
|
+
` )`,
|
|
2874
|
+
` controller.close()`,
|
|
2875
|
+
` },`,
|
|
2876
|
+
` })`,
|
|
2877
|
+
`}`
|
|
2878
|
+
];
|
|
2879
|
+
}
|
|
2789
2880
|
function streamingWebRenderer(appTree) {
|
|
2790
2881
|
return [
|
|
2791
2882
|
`// T2.3 \u2014 Web Standards streaming entry for edge runtimes (Cloudflare,`,
|
|
@@ -2805,13 +2896,16 @@ function streamingWebRenderer(appTree) {
|
|
|
2805
2896
|
// Streaming still applies to genuine data-fetching Suspense, which is where it earns its keep.
|
|
2806
2897
|
// A failed import is swallowed on purpose: React.lazy will retry and suspend as before, which
|
|
2807
2898
|
// is strictly no worse than not having preloaded at all.
|
|
2808
|
-
`
|
|
2899
|
+
// `url` is a URL here, not the string the other renderers receive as a parameter —
|
|
2900
|
+
// so the match key is `.pathname`, never `.split('?')`. Hoisting the declaration
|
|
2901
|
+
// without changing the accessor trades the TDZ for a TypeError (#344).
|
|
2902
|
+
` const url = new URL(request.url)`,
|
|
2903
|
+
` const __theoMatches = matchRoutes(routes, url.pathname) ?? []`,
|
|
2809
2904
|
` await Promise.all(`,
|
|
2810
2905
|
` __theoPreloadPathsFor(__theoMatches).map((p) => __theoPreloadMap[p]().catch(() => null)),`,
|
|
2811
2906
|
` )`,
|
|
2812
2907
|
``,
|
|
2813
2908
|
` const handler = createStaticHandler(routes)`,
|
|
2814
|
-
` const url = new URL(request.url)`,
|
|
2815
2909
|
` const context = await handler.query(request)`,
|
|
2816
2910
|
``,
|
|
2817
2911
|
` if (context instanceof Response) {`,
|
|
@@ -2821,12 +2915,14 @@ function streamingWebRenderer(appTree) {
|
|
|
2821
2915
|
` const router = createStaticRouter(handler.dataRoutes, context)`,
|
|
2822
2916
|
` const app = ${appTree}`,
|
|
2823
2917
|
``,
|
|
2918
|
+
hydrationDataExtractSnippet(),
|
|
2919
|
+
``,
|
|
2824
2920
|
` const stream = await renderToReadableStream(app, {`,
|
|
2825
2921
|
` signal: request.signal,`,
|
|
2826
2922
|
` nonce: options.nonce,`,
|
|
2827
2923
|
` onError(err) { console.error('[SSR Web Stream Error]', err) },`,
|
|
2828
2924
|
` })`,
|
|
2829
|
-
` return new Response(stream, {`,
|
|
2925
|
+
` return new Response(__theoDocumentStream(stream, hydrationData, options), {`,
|
|
2830
2926
|
` status: 200,`,
|
|
2831
2927
|
` headers: {`,
|
|
2832
2928
|
` 'Content-Type': 'text/html; charset=utf-8',`,
|
|
@@ -2870,15 +2966,29 @@ function streamingNodeRenderer(appTree) {
|
|
|
2870
2966
|
` const router = createStaticRouter(handler.dataRoutes, context)`,
|
|
2871
2967
|
` const app = ${appTree}`,
|
|
2872
2968
|
``,
|
|
2969
|
+
hydrationDataExtractSnippet(),
|
|
2970
|
+
``,
|
|
2971
|
+
` const { PassThrough } = await import('node:stream')`,
|
|
2873
2972
|
` return new Promise((resolve, reject) => {`,
|
|
2874
2973
|
` let didError = false`,
|
|
2974
|
+
// React's `pipe(dest)` ends `dest` when the source ends, which would close the
|
|
2975
|
+
// response before the hydration script could be written. Piping into a
|
|
2976
|
+
// PassThrough keeps the response open for the tail.
|
|
2977
|
+
` const passthrough = new PassThrough()`,
|
|
2978
|
+
` passthrough.on('data', (chunk) => { response.write(chunk) })`,
|
|
2979
|
+
` passthrough.on('end', () => {`,
|
|
2980
|
+
` response.end(__theoHydrationScript(hydrationData, options.nonce) + (options.htmlTail ?? ''))`,
|
|
2981
|
+
` })`,
|
|
2982
|
+
` passthrough.on('error', reject)`,
|
|
2875
2983
|
` const stream = renderToPipeableStream(app, {`,
|
|
2876
2984
|
` nonce: options.nonce,`,
|
|
2877
2985
|
` onShellReady() {`,
|
|
2878
2986
|
` response.statusCode = didError ? 500 : 200`,
|
|
2879
2987
|
` response.setHeader('Content-Type', 'text/html; charset=utf-8')`,
|
|
2880
2988
|
` response.setHeader('Transfer-Encoding', 'chunked')`,
|
|
2881
|
-
|
|
2989
|
+
// The head goes out on its own write, before any React byte.
|
|
2990
|
+
` if (options.htmlHead) response.write(options.htmlHead)`,
|
|
2991
|
+
` stream.pipe(passthrough)`,
|
|
2882
2992
|
` resolve({ streaming: true })`,
|
|
2883
2993
|
` },`,
|
|
2884
2994
|
` onShellError(err) { reject(err) },`,
|
|
@@ -2962,6 +3072,8 @@ function generateStreamingEntry(options) {
|
|
|
2962
3072
|
`import { routes, __theoPreloadMap, __theoPreloadPathsFor } from '/@theo/route-manifest'`,
|
|
2963
3073
|
theoUiImport,
|
|
2964
3074
|
``,
|
|
3075
|
+
...streamingDocumentHelpers(),
|
|
3076
|
+
``,
|
|
2965
3077
|
...streamingWebRenderer(appTree),
|
|
2966
3078
|
``,
|
|
2967
3079
|
...streamingNodeRenderer(appTree),
|
|
@@ -3071,7 +3183,6 @@ function walkRouteTree(node, parents, acc) {
|
|
|
3071
3183
|
routePath
|
|
3072
3184
|
});
|
|
3073
3185
|
}
|
|
3074
|
-
if (node.layout !== void 0) acc.layoutState.found = true;
|
|
3075
3186
|
pushIf(acc.staticImports, node.layout, safeVarName(seg, "Layout"));
|
|
3076
3187
|
pushIf(acc.staticImports, node.error, safeVarName(seg, "Error"));
|
|
3077
3188
|
pushIf(acc.staticImports, node.loading, safeVarName(seg, "Loading"));
|
|
@@ -3086,18 +3197,20 @@ function generateRouteManifest(tree, options = {}) {
|
|
|
3086
3197
|
const lazyPages_ = options.lazyPages !== false;
|
|
3087
3198
|
const acc = {
|
|
3088
3199
|
staticImports: [],
|
|
3089
|
-
lazyPages: []
|
|
3090
|
-
layoutState: { found: false }
|
|
3200
|
+
lazyPages: []
|
|
3091
3201
|
};
|
|
3092
3202
|
walkRouteTree(tree, [], acc);
|
|
3093
3203
|
const staticImports = acc.staticImports;
|
|
3094
3204
|
const lazyPages = acc.lazyPages;
|
|
3095
|
-
const layoutState = acc.layoutState;
|
|
3096
3205
|
const lines = [`import React, { Suspense } from 'react'`];
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3206
|
+
lines.push(
|
|
3207
|
+
`import { Outlet, ScrollRestoration } from 'react-router'`,
|
|
3208
|
+
// #421 — react-router restores the DOCUMENT. The layout this framework scaffolds scrolls an
|
|
3209
|
+
// inner element, so the restoration that was mounted and running restored nothing. Both are
|
|
3210
|
+
// emitted: one owns the document, the other owns the elements the app marked.
|
|
3211
|
+
`import { ElementScrollRestoration } from 'theokit/router/element-scroll-restoration'`,
|
|
3212
|
+
""
|
|
3213
|
+
);
|
|
3101
3214
|
for (const imp of staticImports) {
|
|
3102
3215
|
lines.push(`import ${imp.varName} from '${imp.importPath}'`);
|
|
3103
3216
|
}
|
|
@@ -3151,16 +3264,20 @@ function generateRouteManifest(tree, options = {}) {
|
|
|
3151
3264
|
function genRouteConfig(node, isRoot) {
|
|
3152
3265
|
const seg = node.segment || "root";
|
|
3153
3266
|
const childrenArray = buildChildrenArray(node, seg);
|
|
3267
|
+
const withScrollRestoration = (element) => `React.createElement(React.Fragment, null, React.createElement(ScrollRestoration), React.createElement(ElementScrollRestoration), ${element})`;
|
|
3154
3268
|
if (node.layout) {
|
|
3155
3269
|
const layoutVar = safeVarName(seg, "Layout");
|
|
3156
3270
|
const pathPart = isRoot ? `path: '/'` : `path: '${segmentPath(node)}'`;
|
|
3157
|
-
|
|
3271
|
+
const layoutElement = `React.createElement(${layoutVar}, { children: React.createElement(Outlet) })`;
|
|
3272
|
+
const element = isRoot ? withScrollRestoration(layoutElement) : layoutElement;
|
|
3273
|
+
return `{ ${pathPart}, element: ${element}, children: ${childrenArray} }`;
|
|
3158
3274
|
}
|
|
3159
3275
|
if (isRoot) {
|
|
3276
|
+
const rootElement = withScrollRestoration(`React.createElement(Outlet)`);
|
|
3160
3277
|
if (node.children.length === 0 && !node.page && !node.notFound && !node.error) {
|
|
3161
|
-
return `{ path: '/', children: [] }`;
|
|
3278
|
+
return `{ path: '/', element: ${rootElement}, children: [] }`;
|
|
3162
3279
|
}
|
|
3163
|
-
return `{ path: '/', children: ${childrenArray} }`;
|
|
3280
|
+
return `{ path: '/', element: ${rootElement}, children: ${childrenArray} }`;
|
|
3164
3281
|
}
|
|
3165
3282
|
if (node.page && node.children.length === 0 && !node.error && !node.notFound) {
|
|
3166
3283
|
const pageVar = safeVarName(seg, "Page");
|
|
@@ -3328,8 +3445,8 @@ function findConsumerConfig(projectRoot, basename2) {
|
|
|
3328
3445
|
let dir = projectRoot;
|
|
3329
3446
|
for (let level = 0; level < 3; level++) {
|
|
3330
3447
|
for (const ext of extensions) {
|
|
3331
|
-
const candidate =
|
|
3332
|
-
if (
|
|
3448
|
+
const candidate = resolve10(dir, `${basename2}${ext}`);
|
|
3449
|
+
if (existsSync8(candidate)) return candidate;
|
|
3333
3450
|
}
|
|
3334
3451
|
const parent = dirname4(dir);
|
|
3335
3452
|
if (parent === dir) break;
|
|
@@ -3340,7 +3457,7 @@ function findConsumerConfig(projectRoot, basename2) {
|
|
|
3340
3457
|
async function theoPluginAsync(rootOrOptions) {
|
|
3341
3458
|
const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions ?? {};
|
|
3342
3459
|
const projectRoot = options.root ?? process.cwd();
|
|
3343
|
-
const serverDirAbs =
|
|
3460
|
+
const serverDirAbs = resolve10(projectRoot, options.serverDir ?? "server");
|
|
3344
3461
|
const agentsDirName = options.agentsDir ?? "agents";
|
|
3345
3462
|
const consumerTailwindConfig = findConsumerConfig(projectRoot, "tailwind.config");
|
|
3346
3463
|
const consumerPostcssConfig = findConsumerConfig(projectRoot, "postcss.config");
|
|
@@ -3359,23 +3476,23 @@ async function theoPluginAsync(rootOrOptions) {
|
|
|
3359
3476
|
})
|
|
3360
3477
|
);
|
|
3361
3478
|
}
|
|
3362
|
-
const { appTypedClientPlugin } = await import("./app-typed-client-
|
|
3479
|
+
const { appTypedClientPlugin } = await import("./app-typed-client-XGDZKH73.js");
|
|
3363
3480
|
const appClientPlugin = appTypedClientPlugin({
|
|
3364
3481
|
cwd: projectRoot,
|
|
3365
3482
|
serverDir: serverDirAbs,
|
|
3366
|
-
distDir:
|
|
3483
|
+
distDir: resolve10(projectRoot, ".theokit")
|
|
3367
3484
|
});
|
|
3368
|
-
const { actionsVirtualModule } = await import("./actions-virtual-module-
|
|
3485
|
+
const { actionsVirtualModule } = await import("./actions-virtual-module-RXL2RJTW.js");
|
|
3369
3486
|
const actionsPlugin = actionsVirtualModule({
|
|
3370
3487
|
serverDir: serverDirAbs,
|
|
3371
|
-
distDir:
|
|
3488
|
+
distDir: resolve10(projectRoot, ".theokit")
|
|
3372
3489
|
});
|
|
3373
3490
|
const { agentsTypedClientPlugin } = await import("./agents-typed-client-INR2E7B3.js");
|
|
3374
|
-
const { generateManifest } = await import("./internal-api-
|
|
3491
|
+
const { generateManifest } = await import("./internal-api-XQHU5JKY.js");
|
|
3375
3492
|
const agentsClientPlugin = agentsTypedClientPlugin({
|
|
3376
3493
|
projectRoot,
|
|
3377
3494
|
agentsDir: agentsDirName,
|
|
3378
|
-
distDir:
|
|
3495
|
+
distDir: resolve10(projectRoot, ".theokit"),
|
|
3379
3496
|
// Agents live at <projectRoot>/<agentsDir>; generateManifest scans them via the server dir's
|
|
3380
3497
|
// parent (projectRoot for the canonical layout) + the agents dir name (#95 follow-up).
|
|
3381
3498
|
scanManifest: () => generateManifest(serverDirAbs, projectRoot, agentsDirName)
|
|
@@ -3388,11 +3505,17 @@ async function theoPluginAsync(rootOrOptions) {
|
|
|
3388
3505
|
const controllerTransformPlugin = controllerSwcTransformPlugin({
|
|
3389
3506
|
serverDir: serverDirAbs
|
|
3390
3507
|
});
|
|
3508
|
+
const { serverOnlyImportBoundary } = await import("./server-boundary-2WFT546S.js");
|
|
3509
|
+
const serverBoundaryPlugin = serverOnlyImportBoundary({
|
|
3510
|
+
projectRoot,
|
|
3511
|
+
serverDir: serverDirAbs
|
|
3512
|
+
});
|
|
3391
3513
|
return [
|
|
3392
3514
|
theoPlugin(rootOrOptions),
|
|
3393
3515
|
...uiPlugins,
|
|
3394
3516
|
...studioPlugins,
|
|
3395
3517
|
...servicesPlugins,
|
|
3518
|
+
serverBoundaryPlugin,
|
|
3396
3519
|
// #122 — swc-compile controllers/** (enforce:'pre'; order-independent).
|
|
3397
3520
|
controllerTransformPlugin,
|
|
3398
3521
|
appClientPlugin,
|
|
@@ -3403,10 +3526,10 @@ async function theoPluginAsync(rootOrOptions) {
|
|
|
3403
3526
|
}
|
|
3404
3527
|
function buildOptimizeDepsInclude(projectRoot, viteOptimizeDeps) {
|
|
3405
3528
|
const include = [];
|
|
3406
|
-
if (
|
|
3529
|
+
if (existsSync8(resolve10(projectRoot, "node_modules", "@theokit", "ui"))) {
|
|
3407
3530
|
include.push("@theokit/ui");
|
|
3408
3531
|
}
|
|
3409
|
-
if (
|
|
3532
|
+
if (existsSync8(resolve10(projectRoot, "node_modules", "lucide-react"))) {
|
|
3410
3533
|
include.push("lucide-react");
|
|
3411
3534
|
}
|
|
3412
3535
|
include.push("devalue");
|
|
@@ -3432,8 +3555,8 @@ var VIRTUAL_MODULE_IDS = {
|
|
|
3432
3555
|
function theoPlugin(rootOrOptions) {
|
|
3433
3556
|
const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions ?? {};
|
|
3434
3557
|
const projectRoot = options.root ?? process.cwd();
|
|
3435
|
-
const appDir =
|
|
3436
|
-
const serverDir =
|
|
3558
|
+
const appDir = resolve10(projectRoot, options.appDir ?? "app");
|
|
3559
|
+
const serverDir = resolve10(projectRoot, options.serverDir ?? "server");
|
|
3437
3560
|
const agentsDir = options.agentsDir ?? "agents";
|
|
3438
3561
|
const ssrEnabled = options.ssr ?? false;
|
|
3439
3562
|
const currentDir = dirname4(fileURLToPath(import.meta.url));
|
|
@@ -3565,4 +3688,4 @@ export {
|
|
|
3565
3688
|
theoPluginAsync,
|
|
3566
3689
|
theoPlugin
|
|
3567
3690
|
};
|
|
3568
|
-
//# sourceMappingURL=chunk-
|
|
3691
|
+
//# sourceMappingURL=chunk-7AEBH52I.js.map
|