theokit 0.4.0-beta.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{actions-virtual-module-HWNTIEPI.js → actions-virtual-module-IY46EEEX.js} +2 -2
- package/dist/{actions-virtual-module-SEIPACG5.js → actions-virtual-module-XNHDNCZ6.js} +2 -2
- package/dist/add-2ZFFGGE4.js +0 -0
- package/dist/{app-typed-client-ITIYTBXO.js → app-typed-client-OUJO3V5J.js} +10 -5
- package/dist/{app-typed-client-62FYBLVJ.js.map → app-typed-client-OUJO3V5J.js.map} +1 -1
- package/dist/{app-typed-client-62FYBLVJ.js → app-typed-client-YOMWSA3F.js} +11 -6
- package/dist/{app-typed-client-ITIYTBXO.js.map → app-typed-client-YOMWSA3F.js.map} +1 -1
- package/dist/audit-log-BQWM5YLG.d.ts +60 -0
- package/dist/{aws-lambda-XYCGZH3I.js → aws-lambda-GKSTX6HD.js} +3 -3
- package/dist/body-parser-web-MUWBKZ3F.js +70 -0
- package/dist/body-parser-web-MUWBKZ3F.js.map +1 -0
- package/dist/broadcast-QOQGUNNK.js +0 -0
- package/dist/{build-HIGHJQQV.js → build-D4J7XECU.js} +31 -22
- package/dist/build-D4J7XECU.js.map +1 -0
- package/dist/build-request-body-preview-II2235E6.js +0 -0
- package/dist/{bun-K73TQEWC.js → bun-ISHSNFIO.js} +3 -3
- package/dist/{check-PZR67OY5.js → check-NXYPLM6M.js} +2 -2
- package/dist/{chunk-WZ7CPVQB.js → chunk-27LWMYNK.js} +28 -24
- package/dist/chunk-27LWMYNK.js.map +1 -0
- package/dist/{chunk-BIGBFZSU.js → chunk-2F4FROEQ.js} +1689 -1521
- package/dist/chunk-2F4FROEQ.js.map +1 -0
- package/dist/chunk-4HBI7DHP.js +20 -0
- package/dist/chunk-4HBI7DHP.js.map +1 -0
- package/dist/{chunk-X4JAX2U3.js → chunk-4S2UCILN.js} +180 -125
- package/dist/chunk-4S2UCILN.js.map +1 -0
- package/dist/{chunk-C52GSJPF.js → chunk-4S6YHNG2.js} +11 -8
- package/dist/chunk-4S6YHNG2.js.map +1 -0
- package/dist/chunk-5ODOE6EF.js +0 -0
- package/dist/{chunk-KJVEJILQ.js → chunk-5PU65T5W.js} +9 -3
- package/dist/chunk-5PU65T5W.js.map +1 -0
- package/dist/chunk-5QW7IQQU.js +36 -0
- package/dist/chunk-5QW7IQQU.js.map +1 -0
- package/dist/chunk-5Z2727GV.js +1324 -0
- package/dist/chunk-5Z2727GV.js.map +1 -0
- package/dist/{chunk-YLBSSEHX.js → chunk-6NEXVBPY.js} +5 -15
- package/dist/chunk-6NEXVBPY.js.map +1 -0
- package/dist/chunk-7MQOHNHE.js +36 -0
- package/dist/chunk-7MQOHNHE.js.map +1 -0
- package/dist/{chunk-TPCT3MXV.js → chunk-ABVITXFH.js} +405 -272
- package/dist/chunk-ABVITXFH.js.map +1 -0
- package/dist/chunk-ASDXVRJD.js +185 -0
- package/dist/chunk-ASDXVRJD.js.map +1 -0
- package/dist/chunk-B3L3TJVF.js +406 -0
- package/dist/chunk-B3L3TJVF.js.map +1 -0
- package/dist/{chunk-PB4GR7EP.js → chunk-C3ZZ56YZ.js} +1 -18
- package/dist/chunk-C3ZZ56YZ.js.map +1 -0
- package/dist/{chunk-O7335ZGH.js → chunk-CG563V5M.js} +5 -3
- package/dist/chunk-CG563V5M.js.map +1 -0
- package/dist/{chunk-5OFPQK6N.js → chunk-COXLEZCN.js} +2 -1
- package/dist/chunk-COXLEZCN.js.map +1 -0
- package/dist/{chunk-O4BLVPML.js → chunk-DNMSV3R3.js} +22 -28
- package/dist/chunk-DNMSV3R3.js.map +1 -0
- package/dist/chunk-E3JH6YUM.js +1 -0
- package/dist/chunk-ESC54TAK.js +220 -0
- package/dist/chunk-ESC54TAK.js.map +1 -0
- package/dist/chunk-FI7MPTJW.js +77 -0
- package/dist/chunk-FI7MPTJW.js.map +1 -0
- package/dist/chunk-H4J2LECY.js +201 -0
- package/dist/chunk-H4J2LECY.js.map +1 -0
- package/dist/chunk-IAJ2JVEH.js +256 -0
- package/dist/chunk-IAJ2JVEH.js.map +1 -0
- package/dist/{chunk-F3TG5FJV.js → chunk-IEZCAT2I.js} +7 -1
- package/dist/{chunk-F3TG5FJV.js.map → chunk-IEZCAT2I.js.map} +1 -1
- package/dist/chunk-JHEAWR3L.js +1 -0
- package/dist/chunk-JQSKBMXP.js +17 -0
- package/dist/chunk-JQSKBMXP.js.map +1 -0
- package/dist/{chunk-4QTKSLTO.js → chunk-K4M64WD6.js} +9 -5
- package/dist/{chunk-4QTKSLTO.js.map → chunk-K4M64WD6.js.map} +1 -1
- package/dist/chunk-KI7OWQUX.js +293 -0
- package/dist/chunk-KI7OWQUX.js.map +1 -0
- package/dist/chunk-KT3MWNZG.js +0 -0
- package/dist/{chunk-ZJW5FFYJ.js → chunk-LC5PYNJP.js} +2 -2
- package/dist/{chunk-JAAHOGKI.js → chunk-M2EY7KDR.js} +1223 -1124
- package/dist/chunk-M2EY7KDR.js.map +1 -0
- package/dist/{chunk-2VQKDRVF.js → chunk-MR7OLIC6.js} +3 -3
- package/dist/chunk-NM4WF3XD.js +63 -0
- package/dist/chunk-NM4WF3XD.js.map +1 -0
- package/dist/chunk-NPMCKOX4.js +1 -0
- package/dist/{chunk-VRHXOKRP.js → chunk-NZXH2LQQ.js} +86 -83
- package/dist/chunk-NZXH2LQQ.js.map +1 -0
- package/dist/{chunk-B6RP57M3.js → chunk-OLPB36O2.js} +4 -4
- package/dist/chunk-PIVX3DYW.js +142 -0
- package/dist/chunk-PIVX3DYW.js.map +1 -0
- package/dist/{chunk-7TOMTMHT.js → chunk-R7OC6UDK.js} +2 -1
- package/dist/chunk-R7OC6UDK.js.map +1 -0
- package/dist/chunk-RESN62GB.js +269 -0
- package/dist/chunk-RESN62GB.js.map +1 -0
- package/dist/{chunk-64JI5LTO.js → chunk-RMU7EBRO.js} +2 -2
- package/dist/chunk-RMU7EBRO.js.map +1 -0
- package/dist/chunk-TQYSPYKU.js +131 -0
- package/dist/chunk-TQYSPYKU.js.map +1 -0
- package/dist/chunk-TSLSIRBR.js +107 -0
- package/dist/chunk-TSLSIRBR.js.map +1 -0
- package/dist/{chunk-XP7YXRHO.js → chunk-U6TPSW4L.js} +37 -5
- package/dist/chunk-U6TPSW4L.js.map +1 -0
- package/dist/chunk-UD3LFGDL.js +45 -0
- package/dist/chunk-UD3LFGDL.js.map +1 -0
- package/dist/chunk-UUFYP2UM.js +161 -0
- package/dist/chunk-UUFYP2UM.js.map +1 -0
- package/dist/{chunk-OXIQI2XZ.js → chunk-VBZCVFSA.js} +2 -2
- package/dist/chunk-VMEWD57H.js +137 -0
- package/dist/chunk-VMEWD57H.js.map +1 -0
- package/dist/{chunk-TRH2L3FI.js → chunk-WEGALZEU.js} +3 -3
- package/dist/{chunk-ZOXNJV2O.js → chunk-WGHJD6I7.js} +35 -138
- package/dist/chunk-WGHJD6I7.js.map +1 -0
- package/dist/chunk-XMS5VRIK.js +0 -0
- package/dist/chunk-Y4H3JNVK.js +18 -0
- package/dist/chunk-Y4H3JNVK.js.map +1 -0
- package/dist/chunk-Z5IGLBWE.js +329 -0
- package/dist/chunk-Z5IGLBWE.js.map +1 -0
- package/dist/chunk-ZEGYW52B.js +26 -0
- package/dist/chunk-ZEGYW52B.js.map +1 -0
- package/dist/chunk-ZJQ4O76G.js +87 -0
- package/dist/chunk-ZJQ4O76G.js.map +1 -0
- package/dist/cli/index.js +32 -21
- package/dist/cli/index.js.map +1 -1
- package/dist/client/index.d.ts +107 -1
- package/dist/client/index.js +152 -6
- package/dist/client/index.js.map +1 -1
- package/dist/{cloudflare-LCAOTRYZ.js → cloudflare-OJGJ7R2D.js} +3 -3
- package/dist/configure-agent-registry-6YGTJYBC.js +0 -0
- package/dist/cookies-MJKMGJ7N.js +22 -0
- package/dist/csrf-BBrEZSBW.d.ts +107 -0
- package/dist/csrf-readiness-store-CjIoub3U.d.ts +43 -0
- package/dist/define-websocket-CdK94O-D.d.ts +64 -0
- package/dist/{deno-deploy-ZN4RE5HF.js → deno-deploy-BHWKFTOW.js} +3 -3
- package/dist/{dev-266MVCVA.js → dev-MJVSRZGF.js} +11 -11
- package/dist/{dev-emit-RBSFZZNO.js → dev-emit-5VPRCHOD.js} +39 -142
- package/dist/dev-emit-5VPRCHOD.js.map +1 -0
- package/dist/{dev-emit-NO6OZJOQ.js → dev-emit-HHP2XJXE.js} +5 -5
- package/dist/devtools/entry.js +185 -131
- package/dist/devtools/entry.js.map +1 -1
- package/dist/{dispatcher-AQJGI3HU.js → dispatcher-63LBXYLE.js} +2 -2
- package/dist/{dispatcher-E6QV32BO.js → dispatcher-EJME6C6M.js} +5 -2
- package/dist/dispatcher-EJME6C6M.js.map +1 -0
- package/dist/{dist-5V77Z223.js → dist-KRW6OVD4.js} +7 -7
- package/dist/dist-KRW6OVD4.js.map +1 -0
- package/dist/docker-EZDA5FT7.js +0 -0
- package/dist/error-envelope-BsNzzAV5.d.ts +62 -0
- package/dist/{generate-DT4IIAHF.js → generate-AZ2K6Z2Z.js} +75 -2
- package/dist/generate-AZ2K6Z2Z.js.map +1 -0
- package/dist/index-DWWEdFh5.d.ts +399 -0
- package/dist/index.d.ts +161 -1391
- package/dist/index.js +20 -8
- package/dist/index.js.map +1 -1
- package/dist/{info-FJ4NXKTB.js → info-47VB62MV.js} +5 -5
- package/dist/job-backend-CgC8Xf33.d.ts +68 -0
- package/dist/{lib-NL5JXGEB.js → lib-NST3PNZX.js} +31 -31
- package/dist/lib-NST3PNZX.js.map +1 -0
- package/dist/module-loader-Cfz7dgCP.d.ts +26 -0
- package/dist/{netlify-5VQ22Z2P.js → netlify-GSNSJGMN.js} +3 -3
- package/dist/{node-3APTLGWB.js → node-6I5B6RL3.js} +3 -3
- package/dist/node-6I5B6RL3.js.map +1 -0
- package/dist/{openapi-FNVSWZOL.js → openapi-NFLSNNVQ.js} +10 -10
- package/dist/plugin-runner-BGBkzgi0.d.ts +95 -0
- package/dist/plugin-types-DNJGxr4Z.d.ts +79 -0
- package/dist/{proper-lockfile-4Y3DP3RP.js → proper-lockfile-MVKMQGFK.js} +27 -27
- package/dist/proper-lockfile-MVKMQGFK.js.map +1 -0
- package/dist/rate-limit-BdNDZ3vt.d.ts +58 -0
- package/dist/registry-QHEZ3BWB.js +25 -0
- package/dist/router-RGZFX75G.js +0 -0
- package/dist/{routes-H4SPLFHJ.js → routes-3A4XGIEJ.js} +6 -6
- package/dist/{scan-C2BOKLSY.js → scan-NQFI5S7P.js} +2 -2
- package/dist/scan-NQFI5S7P.js.map +1 -0
- package/dist/schema-D3v8VB7o.d.ts +76 -0
- package/dist/{schema-VR6YNVLQ.js → schema-KZVOV333.js} +5 -3
- package/dist/schema-KZVOV333.js.map +1 -0
- package/dist/server/agent/index.d.ts +229 -0
- package/dist/server/agent/index.js +16 -0
- package/dist/server/agent/index.js.map +1 -0
- package/dist/server/auth/index.d.ts +46 -1
- package/dist/server/auth/index.js +10 -3
- package/dist/server/cost/index.d.ts +1 -3
- package/dist/server/cost/index.js +1 -1
- package/dist/server/cron/index.js +4 -2
- package/dist/server/define/index.d.ts +281 -0
- package/dist/server/define/index.js +26 -0
- package/dist/server/define/index.js.map +1 -0
- package/dist/server/http/index.d.ts +10 -0
- package/dist/server/http/index.js +74 -0
- package/dist/server/http/index.js.map +1 -0
- package/dist/server/index.d.ts +151 -1677
- package/dist/server/index.js +558 -1102
- package/dist/server/index.js.map +1 -1
- package/dist/server/jobs/index.d.ts +348 -2
- package/dist/server/jobs/index.js +5 -3
- package/dist/server/observability/index.d.ts +324 -0
- package/dist/server/observability/index.js +48 -0
- package/dist/server/observability/index.js.map +1 -0
- package/dist/server/plugins/index.d.ts +17 -0
- package/dist/server/plugins/index.js +17 -0
- package/dist/server/plugins/index.js.map +1 -0
- package/dist/server/rate-limit/index.d.ts +105 -0
- package/dist/server/rate-limit/index.js +25 -0
- package/dist/server/rate-limit/index.js.map +1 -0
- package/dist/server/realtime/index.d.ts +15 -0
- package/dist/server/realtime/index.js +8 -0
- package/dist/server/realtime/index.js.map +1 -0
- package/dist/server/scan/index.d.ts +106 -0
- package/dist/server/scan/index.js +43 -0
- package/dist/server/scan/index.js.map +1 -0
- package/dist/server/security/index.d.ts +193 -0
- package/dist/server/security/index.js +50 -0
- package/dist/server/security/index.js.map +1 -0
- package/dist/server/storage/index.d.ts +22 -0
- package/dist/server/storage/index.js +14 -0
- package/dist/server/storage/index.js.map +1 -0
- package/dist/server/webhook/index.d.ts +148 -0
- package/dist/server/webhook/index.js +19 -0
- package/dist/server/webhook/index.js.map +1 -0
- package/dist/server-error-to-envelope-NO4CCAFQ.js +8 -0
- package/dist/server-error-to-envelope-NO4CCAFQ.js.map +1 -0
- package/dist/server-error-to-envelope-UJK6OWDJ.js +134 -0
- package/dist/server-error-to-envelope-UJK6OWDJ.js.map +1 -0
- package/dist/server-routes-hmr-GZJGPWMS.js +0 -0
- package/dist/services-json-Z2QNGVPW.js +142 -0
- package/dist/services-json-Z2QNGVPW.js.map +1 -0
- package/dist/{services-typed-client-XWYYBWGW.js → services-typed-client-KK6RHRDG.js} +2 -2
- package/dist/{services-typed-client-ZX5JUHH3.js → services-typed-client-T7M5VPBP.js} +2 -2
- package/dist/{sqlite-vec-ARPNUBWT.js → sqlite-vec-54KB4RD3.js} +2 -2
- package/dist/sqlite-vec-54KB4RD3.js.map +1 -0
- package/dist/{start-HX3QUSOS.js → start-CGSZPBAG.js} +23 -23
- package/dist/start-CGSZPBAG.js.map +1 -0
- package/dist/{static-TZBVBDTB.js → static-QI5NQT2X.js} +6 -6
- package/dist/storage-manager-C4jsO0Tp.d.ts +89 -0
- package/dist/storage-manager-D5KBXXKB.js +0 -0
- package/dist/{storage-types-DtIVejC1.d.ts → storage-types-DsDTCPbp.d.ts} +1 -1
- package/dist/{theo-cloud-3K4DGB3S.js → theo-cloud-RSQCBNXL.js} +4 -4
- package/dist/theo-cloud-RSQCBNXL.js.map +1 -0
- package/dist/upgrade-readiness-GUJBCJIS.js +0 -0
- package/dist/{vercel-MWW24ABC.js → vercel-TKPZK62A.js} +3 -3
- package/dist/vite-plugin/index.d.ts +3 -1
- package/dist/vite-plugin/index.js +20 -8
- package/dist/{vite-plugin-IK3NOWXS.js → vite-plugin-CR4JDFUQ.js} +9 -9
- package/dist/vite-plugin-CR4JDFUQ.js.map +1 -0
- package/package.json +61 -9
- package/LICENSE +0 -201
- package/dist/build-HIGHJQQV.js.map +0 -1
- package/dist/chunk-5OFPQK6N.js.map +0 -1
- package/dist/chunk-64JI5LTO.js.map +0 -1
- package/dist/chunk-7TOMTMHT.js.map +0 -1
- package/dist/chunk-BIGBFZSU.js.map +0 -1
- package/dist/chunk-C52GSJPF.js.map +0 -1
- package/dist/chunk-CZM6WWWS.js +0 -2450
- package/dist/chunk-CZM6WWWS.js.map +0 -1
- package/dist/chunk-JAAHOGKI.js.map +0 -1
- package/dist/chunk-KJVEJILQ.js.map +0 -1
- package/dist/chunk-O4BLVPML.js.map +0 -1
- package/dist/chunk-O7335ZGH.js.map +0 -1
- package/dist/chunk-PB4GR7EP.js.map +0 -1
- package/dist/chunk-TPCT3MXV.js.map +0 -1
- package/dist/chunk-VRHXOKRP.js.map +0 -1
- package/dist/chunk-WZ7CPVQB.js.map +0 -1
- package/dist/chunk-X4JAX2U3.js.map +0 -1
- package/dist/chunk-XP7YXRHO.js.map +0 -1
- package/dist/chunk-YLBSSEHX.js.map +0 -1
- package/dist/chunk-ZOXNJV2O.js.map +0 -1
- package/dist/dev-emit-RBSFZZNO.js.map +0 -1
- package/dist/dispatcher-E6QV32BO.js.map +0 -1
- package/dist/dist-5V77Z223.js.map +0 -1
- package/dist/generate-DT4IIAHF.js.map +0 -1
- package/dist/index-li83Swxa.d.ts +0 -506
- package/dist/lib-NL5JXGEB.js.map +0 -1
- package/dist/proper-lockfile-4Y3DP3RP.js.map +0 -1
- package/dist/registry-4MZ26TZD.js +0 -25
- package/dist/schema-CjVly9c_.d.ts +0 -274
- package/dist/sqlite-vec-ARPNUBWT.js.map +0 -1
- package/dist/start-HX3QUSOS.js.map +0 -1
- package/dist/theo-cloud-3K4DGB3S.js.map +0 -1
- /package/dist/{actions-virtual-module-HWNTIEPI.js.map → actions-virtual-module-IY46EEEX.js.map} +0 -0
- /package/dist/{actions-virtual-module-SEIPACG5.js.map → actions-virtual-module-XNHDNCZ6.js.map} +0 -0
- /package/dist/{aws-lambda-XYCGZH3I.js.map → aws-lambda-GKSTX6HD.js.map} +0 -0
- /package/dist/{bun-K73TQEWC.js.map → bun-ISHSNFIO.js.map} +0 -0
- /package/dist/{check-PZR67OY5.js.map → check-NXYPLM6M.js.map} +0 -0
- /package/dist/{dispatcher-AQJGI3HU.js.map → chunk-E3JH6YUM.js.map} +0 -0
- /package/dist/{node-3APTLGWB.js.map → chunk-JHEAWR3L.js.map} +0 -0
- /package/dist/{chunk-ZJW5FFYJ.js.map → chunk-LC5PYNJP.js.map} +0 -0
- /package/dist/{chunk-2VQKDRVF.js.map → chunk-MR7OLIC6.js.map} +0 -0
- /package/dist/{scan-C2BOKLSY.js.map → chunk-NPMCKOX4.js.map} +0 -0
- /package/dist/{chunk-B6RP57M3.js.map → chunk-OLPB36O2.js.map} +0 -0
- /package/dist/{chunk-OXIQI2XZ.js.map → chunk-VBZCVFSA.js.map} +0 -0
- /package/dist/{chunk-TRH2L3FI.js.map → chunk-WEGALZEU.js.map} +0 -0
- /package/dist/{cloudflare-LCAOTRYZ.js.map → cloudflare-OJGJ7R2D.js.map} +0 -0
- /package/dist/{schema-VR6YNVLQ.js.map → cookies-MJKMGJ7N.js.map} +0 -0
- /package/dist/{deno-deploy-ZN4RE5HF.js.map → deno-deploy-BHWKFTOW.js.map} +0 -0
- /package/dist/{dev-266MVCVA.js.map → dev-MJVSRZGF.js.map} +0 -0
- /package/dist/{dev-emit-NO6OZJOQ.js.map → dev-emit-HHP2XJXE.js.map} +0 -0
- /package/dist/{vite-plugin-IK3NOWXS.js.map → dispatcher-63LBXYLE.js.map} +0 -0
- /package/dist/{info-FJ4NXKTB.js.map → info-47VB62MV.js.map} +0 -0
- /package/dist/{netlify-5VQ22Z2P.js.map → netlify-GSNSJGMN.js.map} +0 -0
- /package/dist/{openapi-FNVSWZOL.js.map → openapi-NFLSNNVQ.js.map} +0 -0
- /package/dist/{registry-4MZ26TZD.js.map → registry-QHEZ3BWB.js.map} +0 -0
- /package/dist/{routes-H4SPLFHJ.js.map → routes-3A4XGIEJ.js.map} +0 -0
- /package/dist/{services-typed-client-XWYYBWGW.js.map → services-typed-client-KK6RHRDG.js.map} +0 -0
- /package/dist/{services-typed-client-ZX5JUHH3.js.map → services-typed-client-T7M5VPBP.js.map} +0 -0
- /package/dist/{static-TZBVBDTB.js.map → static-QI5NQT2X.js.map} +0 -0
- /package/dist/{vercel-MWW24ABC.js.map → vercel-TKPZK62A.js.map} +0 -0
package/dist/server/index.js
CHANGED
|
@@ -1,16 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
serverErrorToEnvelope
|
|
3
|
+
} from "../chunk-TQYSPYKU.js";
|
|
4
|
+
import {
|
|
5
|
+
BodyTooLargeError,
|
|
6
|
+
DEFAULT_MAX_BODY_BYTES,
|
|
7
|
+
defineWebhook,
|
|
8
|
+
dispatchWebhook,
|
|
9
|
+
readRawBody,
|
|
10
|
+
timingSafeEqual
|
|
11
|
+
} from "../chunk-UUFYP2UM.js";
|
|
12
|
+
import {
|
|
13
|
+
DuplicateJobNameError,
|
|
14
|
+
InMemoryJobBackend,
|
|
15
|
+
JOB_MANIFEST_SCHEMA_VERSION,
|
|
16
|
+
NonRetryableError,
|
|
17
|
+
PostgresJobBackend,
|
|
18
|
+
buildJobManifest,
|
|
19
|
+
createJobRunner,
|
|
20
|
+
defineJob,
|
|
21
|
+
scanJobs,
|
|
22
|
+
writeJobManifest
|
|
23
|
+
} from "../chunk-4S6YHNG2.js";
|
|
24
|
+
import {
|
|
25
|
+
ConsoleObservabilityAdapter,
|
|
26
|
+
NoopObservabilityAdapter,
|
|
27
|
+
NoopSpan,
|
|
28
|
+
SpanImpl,
|
|
29
|
+
TheoCloudObservabilityAdapter,
|
|
30
|
+
createObservabilityPlugin,
|
|
31
|
+
defineObservabilityAdapter,
|
|
32
|
+
resolveAdapter,
|
|
33
|
+
serializeSpansToOtlp
|
|
34
|
+
} from "../chunk-KI7OWQUX.js";
|
|
35
|
+
import "../chunk-NPMCKOX4.js";
|
|
36
|
+
import {
|
|
37
|
+
createRouteRateLimiter,
|
|
38
|
+
createRouteRateLimiterWeb,
|
|
39
|
+
deriveKey,
|
|
40
|
+
deriveKeyFromRequest,
|
|
41
|
+
matchRoutePattern
|
|
42
|
+
} from "../chunk-ASDXVRJD.js";
|
|
43
|
+
import {
|
|
44
|
+
ChannelManager
|
|
45
|
+
} from "../chunk-NM4WF3XD.js";
|
|
46
|
+
import "../chunk-E3JH6YUM.js";
|
|
1
47
|
import {
|
|
2
48
|
generateManifest,
|
|
3
49
|
loadManifest,
|
|
4
50
|
writeManifest
|
|
5
|
-
} from "../chunk-
|
|
51
|
+
} from "../chunk-MR7OLIC6.js";
|
|
52
|
+
import "../chunk-JHEAWR3L.js";
|
|
53
|
+
import {
|
|
54
|
+
StorageManager,
|
|
55
|
+
getStorageManager,
|
|
56
|
+
useDatabase,
|
|
57
|
+
useUnstorage
|
|
58
|
+
} from "../chunk-ESC54TAK.js";
|
|
59
|
+
import {
|
|
60
|
+
_resetEnvCache,
|
|
61
|
+
jsonTransformer,
|
|
62
|
+
loadEnv,
|
|
63
|
+
resolveTransformer,
|
|
64
|
+
superjsonTransformer
|
|
65
|
+
} from "../chunk-PIVX3DYW.js";
|
|
66
|
+
import {
|
|
67
|
+
findSuggestion,
|
|
68
|
+
levenshtein
|
|
69
|
+
} from "../chunk-5QW7IQQU.js";
|
|
70
|
+
import {
|
|
71
|
+
DuplicateDecorationError,
|
|
72
|
+
DuplicatePluginError,
|
|
73
|
+
InvalidPluginShapeError,
|
|
74
|
+
PluginRunner,
|
|
75
|
+
createPluginRunnerFromConfig
|
|
76
|
+
} from "../chunk-IAJ2JVEH.js";
|
|
77
|
+
import {
|
|
78
|
+
InMemoryStore,
|
|
79
|
+
createRateLimiter,
|
|
80
|
+
createRateLimiterWeb
|
|
81
|
+
} from "../chunk-VMEWD57H.js";
|
|
82
|
+
import {
|
|
83
|
+
createProductionLoader,
|
|
84
|
+
createViteLoader
|
|
85
|
+
} from "../chunk-JQSKBMXP.js";
|
|
86
|
+
import {
|
|
87
|
+
compilePattern,
|
|
88
|
+
matchRoute,
|
|
89
|
+
scanServerRoutes,
|
|
90
|
+
scanWebSocketRoutes
|
|
91
|
+
} from "../chunk-OLPB36O2.js";
|
|
92
|
+
import {
|
|
93
|
+
ActionScanError,
|
|
94
|
+
scanServerActions,
|
|
95
|
+
scanServerActionsEnriched
|
|
96
|
+
} from "../chunk-R7OC6UDK.js";
|
|
97
|
+
import "../chunk-WSJKACWB.js";
|
|
98
|
+
import {
|
|
99
|
+
CSP_REPORT_PATH,
|
|
100
|
+
CSRF_READINESS_PATH,
|
|
101
|
+
CSRF_READINESS_RESET_PATH,
|
|
102
|
+
CsrfReadinessStore,
|
|
103
|
+
DEFAULT_CSP,
|
|
104
|
+
DEFAULT_PERMISSIONS_POLICY,
|
|
105
|
+
applySecurityHeaders,
|
|
106
|
+
buildSecurityHeaders,
|
|
107
|
+
handleCspReport,
|
|
108
|
+
handleCspReportRequest,
|
|
109
|
+
handleCsrfReadiness,
|
|
110
|
+
handleCsrfReadinessRequest,
|
|
111
|
+
normalizeLegacy,
|
|
112
|
+
normalizeNew
|
|
113
|
+
} from "../chunk-B3L3TJVF.js";
|
|
114
|
+
import {
|
|
115
|
+
__resetSdkForTests,
|
|
116
|
+
__setSdkForTests,
|
|
117
|
+
createConversationHistory,
|
|
118
|
+
errorToEvent,
|
|
119
|
+
streamAgentRun
|
|
120
|
+
} from "../chunk-RESN62GB.js";
|
|
6
121
|
import {
|
|
7
122
|
_resetKeyCacheForTests,
|
|
8
123
|
assertProductionSecret,
|
|
9
124
|
checkThrottle,
|
|
10
125
|
clearOidcCache,
|
|
11
126
|
createSessionManager,
|
|
127
|
+
createSessionManagerWeb,
|
|
12
128
|
decrypt,
|
|
13
|
-
deleteCookie,
|
|
14
129
|
discoverOidcProvider,
|
|
15
130
|
encrypt,
|
|
16
131
|
generateBackupCodes,
|
|
@@ -18,22 +133,23 @@ import {
|
|
|
18
133
|
generatePkceChallenge,
|
|
19
134
|
generateTotp,
|
|
20
135
|
generateTotpSecret,
|
|
21
|
-
getCookie,
|
|
22
|
-
parseCookieHeader,
|
|
23
136
|
pkceChallengeFromVerifier,
|
|
24
137
|
recordAttempt,
|
|
25
138
|
rotateIfNeeded,
|
|
26
|
-
|
|
139
|
+
rotateIfNeededWeb,
|
|
27
140
|
totpUri,
|
|
28
141
|
verifyBackupCode,
|
|
29
142
|
verifyOAuthState,
|
|
30
143
|
verifyTotp
|
|
31
|
-
} from "../chunk-
|
|
144
|
+
} from "../chunk-NZXH2LQQ.js";
|
|
145
|
+
import {
|
|
146
|
+
generateNonce
|
|
147
|
+
} from "../chunk-C3ZZ56YZ.js";
|
|
32
148
|
import {
|
|
33
149
|
InMemoryUsageStorage,
|
|
34
150
|
trackAgentRun,
|
|
35
151
|
trackAgentTools
|
|
36
|
-
} from "../chunk-
|
|
152
|
+
} from "../chunk-RMU7EBRO.js";
|
|
37
153
|
import {
|
|
38
154
|
CRON_MANIFEST_SCHEMA_VERSION,
|
|
39
155
|
DuplicateCronNameError,
|
|
@@ -49,1144 +165,176 @@ import {
|
|
|
49
165
|
translateCronToVercel,
|
|
50
166
|
validateCronSchedule,
|
|
51
167
|
writeCronManifest
|
|
52
|
-
} from "../chunk-
|
|
168
|
+
} from "../chunk-K4M64WD6.js";
|
|
169
|
+
import "../chunk-Y4H3JNVK.js";
|
|
170
|
+
import "../chunk-6NEXVBPY.js";
|
|
171
|
+
import "../chunk-7MQOHNHE.js";
|
|
172
|
+
import "../chunk-X2VVCJ4V.js";
|
|
53
173
|
import {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
} from "../chunk-
|
|
174
|
+
defineAction,
|
|
175
|
+
defineAgentEndpoint,
|
|
176
|
+
defineAgentTool,
|
|
177
|
+
defineChannel,
|
|
178
|
+
defineMiddleware,
|
|
179
|
+
defineRoute,
|
|
180
|
+
defineTheoPlugin,
|
|
181
|
+
defineWebChannel,
|
|
182
|
+
defineWebSocket,
|
|
183
|
+
defineWebSocketWeb
|
|
184
|
+
} from "../chunk-H4J2LECY.js";
|
|
65
185
|
import {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
186
|
+
MAX_ERROR_HTML_BYTES,
|
|
187
|
+
loadCustomErrorPages,
|
|
188
|
+
serveStaticFile
|
|
189
|
+
} from "../chunk-FI7MPTJW.js";
|
|
69
190
|
import {
|
|
70
191
|
ActionError,
|
|
71
192
|
ActionInputError,
|
|
72
193
|
BATCH_PATH,
|
|
73
194
|
BatchPathConflictError,
|
|
74
|
-
CSP_REPORT_PATH,
|
|
75
|
-
CSRF_READINESS_PATH,
|
|
76
|
-
CSRF_READINESS_RESET_PATH,
|
|
77
|
-
CSRF_WARN_CODE,
|
|
78
|
-
CSRF_WARN_DOCS_URL,
|
|
79
|
-
CsrfReadinessStore,
|
|
80
|
-
DEFAULT_CSP,
|
|
81
|
-
DEFAULT_PERMISSIONS_POLICY,
|
|
82
|
-
DuplicateDecorationError,
|
|
83
|
-
DuplicatePluginError,
|
|
84
|
-
FileTooLargeError,
|
|
85
|
-
InMemoryStore,
|
|
86
|
-
InvalidPluginShapeError,
|
|
87
|
-
JsonStdoutSink,
|
|
88
|
-
PluginRunner,
|
|
89
195
|
STRIPPED_HEADERS,
|
|
90
196
|
TRACE_HEADER,
|
|
91
197
|
TRACE_PARENT_HEADER,
|
|
92
|
-
_resetEnvCache,
|
|
93
198
|
_resetMiddlewareCacheForTests,
|
|
94
|
-
_resetWarnOnceForTests,
|
|
95
|
-
applySecurityHeaders,
|
|
96
|
-
buildSecurityHeaders,
|
|
97
199
|
createCorsHandler,
|
|
98
|
-
|
|
99
|
-
createNoOpLogger,
|
|
100
|
-
createPluginRunnerFromConfig,
|
|
101
|
-
createProductionLoader,
|
|
102
|
-
createRateLimiter,
|
|
103
|
-
createViteLoader,
|
|
104
|
-
enforceCsrf,
|
|
200
|
+
createCorsWebHandler,
|
|
105
201
|
executeAction,
|
|
106
202
|
executeRoute,
|
|
107
203
|
extractTraceId,
|
|
204
|
+
extractTraceIdFromRequest,
|
|
108
205
|
extractUniversalIssues,
|
|
109
|
-
findSuggestion,
|
|
110
206
|
handleBatchRequest,
|
|
111
|
-
handleCspReport,
|
|
112
|
-
handleCsrfReadiness,
|
|
113
207
|
isActionError,
|
|
114
208
|
isInputError,
|
|
115
|
-
jsonTransformer,
|
|
116
|
-
levenshtein,
|
|
117
|
-
loadEnv,
|
|
118
|
-
logRequest,
|
|
119
|
-
matchDisallowed,
|
|
120
209
|
matchesOrigin,
|
|
121
|
-
normalizeLegacy,
|
|
122
|
-
normalizeNew,
|
|
123
|
-
parseRequestBody,
|
|
124
210
|
parseTraceparent,
|
|
125
|
-
resolveTransformer,
|
|
126
211
|
runMiddlewareAndContext,
|
|
127
|
-
safeAudit,
|
|
128
|
-
scanMiddlewares,
|
|
129
212
|
sendError,
|
|
130
|
-
sendJson
|
|
131
|
-
|
|
132
|
-
validateCsrf,
|
|
133
|
-
warnOnce
|
|
134
|
-
} from "../chunk-CZM6WWWS.js";
|
|
135
|
-
import {
|
|
136
|
-
compilePattern,
|
|
137
|
-
matchRoute,
|
|
138
|
-
scanServerRoutes,
|
|
139
|
-
scanWebSocketRoutes
|
|
140
|
-
} from "../chunk-B6RP57M3.js";
|
|
141
|
-
import {
|
|
142
|
-
ActionScanError,
|
|
143
|
-
scanServerActions,
|
|
144
|
-
scanServerActionsEnriched
|
|
145
|
-
} from "../chunk-7TOMTMHT.js";
|
|
146
|
-
import {
|
|
147
|
-
AuthRequiredError,
|
|
148
|
-
generateNonce,
|
|
149
|
-
requireAuth
|
|
150
|
-
} from "../chunk-PB4GR7EP.js";
|
|
213
|
+
sendJson
|
|
214
|
+
} from "../chunk-5Z2727GV.js";
|
|
151
215
|
import {
|
|
152
216
|
DuplicateContextKeyError,
|
|
153
217
|
createOutbox,
|
|
154
218
|
createOutboxDispatcher,
|
|
155
219
|
createQueueClient
|
|
156
220
|
} from "../chunk-GY5Q27BJ.js";
|
|
157
|
-
import "../chunk-X2VVCJ4V.js";
|
|
158
|
-
import "../chunk-WSJKACWB.js";
|
|
159
221
|
import {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (r.aborted === true) controller.abort();
|
|
199
|
-
if (typeof r.on === "function") {
|
|
200
|
-
r.on("close", () => {
|
|
201
|
-
if (!controller.signal.aborted) controller.abort();
|
|
202
|
-
});
|
|
203
|
-
r.on("aborted", () => {
|
|
204
|
-
if (!controller.signal.aborted) controller.abort();
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
return controller.signal;
|
|
208
|
-
}
|
|
209
|
-
function defineAgentEndpoint(config) {
|
|
210
|
-
return {
|
|
211
|
-
handler: async ({ request, ctx, body, query, params }) => {
|
|
212
|
-
const cookieHeaders = new Headers();
|
|
213
|
-
const signal = resolveAbortSignal(request);
|
|
214
|
-
const generator = config.handler({
|
|
215
|
-
request,
|
|
216
|
-
ctx,
|
|
217
|
-
body,
|
|
218
|
-
query,
|
|
219
|
-
params,
|
|
220
|
-
cookieHeaders,
|
|
221
|
-
signal
|
|
222
|
-
});
|
|
223
|
-
let firstResult;
|
|
224
|
-
let primeError;
|
|
225
|
-
try {
|
|
226
|
-
firstResult = await generator.next();
|
|
227
|
-
} catch (err) {
|
|
228
|
-
primeError = err;
|
|
229
|
-
firstResult = { value: void 0, done: true };
|
|
230
|
-
}
|
|
231
|
-
const responseHeaders = new Headers(SSE_HEADERS);
|
|
232
|
-
for (const value of cookieHeaders.getSetCookie()) {
|
|
233
|
-
responseHeaders.append("set-cookie", value);
|
|
234
|
-
}
|
|
235
|
-
const stream = new ReadableStream({
|
|
236
|
-
async start(controller) {
|
|
237
|
-
const onAbort = () => {
|
|
238
|
-
void generator.return(void 0);
|
|
239
|
-
};
|
|
240
|
-
if (signal.aborted) {
|
|
241
|
-
controller.close();
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
245
|
-
try {
|
|
246
|
-
if (primeError !== void 0) {
|
|
247
|
-
let message;
|
|
248
|
-
if (primeError instanceof Error) {
|
|
249
|
-
message = primeError.message;
|
|
250
|
-
} else if (typeof primeError === "string") {
|
|
251
|
-
message = primeError;
|
|
252
|
-
} else {
|
|
253
|
-
message = "agent handler failed during setup";
|
|
254
|
-
}
|
|
255
|
-
controller.enqueue(encodeSSE({ type: "error", message }));
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
if (firstResult.done !== true) {
|
|
259
|
-
controller.enqueue(encodeSSE(firstResult.value));
|
|
260
|
-
} else {
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
for await (const event of generator) {
|
|
264
|
-
if (signal.aborted) break;
|
|
265
|
-
controller.enqueue(encodeSSE(event));
|
|
266
|
-
}
|
|
267
|
-
} catch (err) {
|
|
268
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
269
|
-
controller.enqueue(encodeSSE({ type: "error", message }));
|
|
270
|
-
} finally {
|
|
271
|
-
signal.removeEventListener("abort", onAbort);
|
|
272
|
-
controller.close();
|
|
273
|
-
}
|
|
274
|
-
},
|
|
275
|
-
cancel() {
|
|
276
|
-
void generator.return(void 0);
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
return new Response(stream, { headers: responseHeaders });
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// src/server/define/define-agent-tool.ts
|
|
285
|
-
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
286
|
-
var TOOL_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/;
|
|
287
|
-
function isZodObject(schema) {
|
|
288
|
-
let current = schema;
|
|
289
|
-
for (let depth = 0; depth < 10; depth++) {
|
|
290
|
-
const def = current._def;
|
|
291
|
-
if (def?.typeName === "ZodObject") return true;
|
|
292
|
-
if (def?.schema !== void 0) {
|
|
293
|
-
current = def.schema;
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
if (def?.innerType !== void 0) {
|
|
297
|
-
current = def.innerType;
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
return false;
|
|
301
|
-
}
|
|
302
|
-
return false;
|
|
303
|
-
}
|
|
304
|
-
function defineAgentTool(spec) {
|
|
305
|
-
if (!TOOL_NAME_REGEX.test(spec.name)) {
|
|
306
|
-
throw new Error(
|
|
307
|
-
`defineAgentTool: name must match ${TOOL_NAME_REGEX.source}. Got: ${JSON.stringify(spec.name)}`
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
if (!isZodObject(spec.inputSchema)) {
|
|
311
|
-
throw new Error("defineAgentTool: inputSchema must be a ZodObject (z.object({...}))");
|
|
312
|
-
}
|
|
313
|
-
if (spec.description.length === 0) {
|
|
314
|
-
console.warn(
|
|
315
|
-
`defineAgentTool(${JSON.stringify(spec.name)}): empty description degrades LLM tool selection \u2014 provide a one-sentence summary.`
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
const rawSchema = zodToJsonSchema(spec.inputSchema, {
|
|
319
|
-
target: "jsonSchema7",
|
|
320
|
-
$refStrategy: "none"
|
|
321
|
-
});
|
|
322
|
-
const { $schema: _$schema, ...inputSchema } = rawSchema;
|
|
323
|
-
return {
|
|
324
|
-
name: spec.name,
|
|
325
|
-
description: spec.description,
|
|
326
|
-
inputSchema,
|
|
327
|
-
handler: async (input) => {
|
|
328
|
-
const parsed = spec.inputSchema.parse(input);
|
|
329
|
-
return await spec.handler(parsed);
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// src/server/define/define-websocket.ts
|
|
335
|
-
function defineWebSocket(handler) {
|
|
336
|
-
return handler;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// src/server/define/define-channel.ts
|
|
340
|
-
function defineChannel(handler) {
|
|
341
|
-
return handler;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// src/server/define/define-plugin.ts
|
|
345
|
-
function defineTheoPlugin(plugin) {
|
|
346
|
-
return plugin;
|
|
347
|
-
}
|
|
222
|
+
FileTooLargeError,
|
|
223
|
+
_resetWarnOnceForTests,
|
|
224
|
+
createLogger,
|
|
225
|
+
logRequest,
|
|
226
|
+
parseRequestBody,
|
|
227
|
+
warnOnce
|
|
228
|
+
} from "../chunk-Z5IGLBWE.js";
|
|
229
|
+
import {
|
|
230
|
+
scanMiddlewares
|
|
231
|
+
} from "../chunk-ZEGYW52B.js";
|
|
232
|
+
import {
|
|
233
|
+
CSRF_WARN_CODE,
|
|
234
|
+
CSRF_WARN_DOCS_URL,
|
|
235
|
+
enforceCsrf,
|
|
236
|
+
matchDisallowed,
|
|
237
|
+
validateCsrf,
|
|
238
|
+
validateCsrfRequest
|
|
239
|
+
} from "../chunk-TSLSIRBR.js";
|
|
240
|
+
import {
|
|
241
|
+
JsonStdoutSink,
|
|
242
|
+
createNoOpLogger,
|
|
243
|
+
safeAudit
|
|
244
|
+
} from "../chunk-UD3LFGDL.js";
|
|
245
|
+
import {
|
|
246
|
+
appendCookieToHeaders,
|
|
247
|
+
appendDeleteCookieToHeaders,
|
|
248
|
+
deleteCookie,
|
|
249
|
+
getCookie,
|
|
250
|
+
getCookieFromRequest,
|
|
251
|
+
parseCookieHeader,
|
|
252
|
+
serializeCookie,
|
|
253
|
+
setCookie
|
|
254
|
+
} from "../chunk-ZJQ4O76G.js";
|
|
255
|
+
import {
|
|
256
|
+
AuthRequiredError,
|
|
257
|
+
requireAuth
|
|
258
|
+
} from "../chunk-4HBI7DHP.js";
|
|
259
|
+
import "../chunk-DGUM43GV.js";
|
|
348
260
|
|
|
349
|
-
// src/server/
|
|
261
|
+
// src/server/openapi/serve-docs.ts
|
|
350
262
|
import { existsSync, readFileSync, statSync } from "fs";
|
|
351
263
|
import { resolve } from "path";
|
|
352
|
-
var
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
custom500Html: loadIfSafe(clientDir, "500.html")
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// src/server/http/static.ts
|
|
378
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
379
|
-
import { resolve as resolve2, extname } from "path";
|
|
380
|
-
var MIME_TYPES = {
|
|
381
|
-
".html": "text/html",
|
|
382
|
-
".js": "application/javascript",
|
|
383
|
-
".mjs": "application/javascript",
|
|
384
|
-
".css": "text/css",
|
|
385
|
-
".json": "application/json",
|
|
386
|
-
".png": "image/png",
|
|
387
|
-
".jpg": "image/jpeg",
|
|
388
|
-
".jpeg": "image/jpeg",
|
|
389
|
-
".gif": "image/gif",
|
|
390
|
-
".svg": "image/svg+xml",
|
|
391
|
-
".ico": "image/x-icon",
|
|
392
|
-
".woff": "font/woff",
|
|
393
|
-
".woff2": "font/woff2",
|
|
394
|
-
".ttf": "font/ttf",
|
|
395
|
-
".txt": "text/plain",
|
|
396
|
-
".map": "application/json"
|
|
397
|
-
};
|
|
398
|
-
function serveStaticFile(req, res, clientDir) {
|
|
399
|
-
const urlPath = (req.url ?? "/").split("?")[0];
|
|
400
|
-
const filePath = resolve2(clientDir, "." + urlPath);
|
|
401
|
-
if (!filePath.startsWith(clientDir)) {
|
|
402
|
-
res.writeHead(403);
|
|
403
|
-
res.end("Forbidden");
|
|
404
|
-
return true;
|
|
405
|
-
}
|
|
406
|
-
if (!existsSync2(filePath)) return false;
|
|
407
|
-
const stat = statSync2(filePath);
|
|
408
|
-
if (!stat.isFile()) return false;
|
|
409
|
-
const ext = extname(filePath);
|
|
410
|
-
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
411
|
-
const content = readFileSync2(filePath);
|
|
412
|
-
res.writeHead(200, {
|
|
413
|
-
"Content-Type": contentType,
|
|
414
|
-
"Content-Length": content.length
|
|
415
|
-
});
|
|
416
|
-
res.end(content);
|
|
417
|
-
return true;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// src/server/agent/stream-agent-run.ts
|
|
421
|
-
function safeJsonStringify(value) {
|
|
422
|
-
try {
|
|
423
|
-
return JSON.stringify(value);
|
|
424
|
-
} catch {
|
|
425
|
-
return "[Unserializable]";
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
function safeArgs(args) {
|
|
429
|
-
if (typeof args === "object" && args !== null && !Array.isArray(args)) {
|
|
430
|
-
return args;
|
|
431
|
-
}
|
|
432
|
-
return {};
|
|
433
|
-
}
|
|
434
|
-
function isAssistant(msg) {
|
|
435
|
-
const m = msg;
|
|
436
|
-
return m.type === "assistant" && m.message != null && typeof m.message === "object" && Array.isArray(m.message.content);
|
|
437
|
-
}
|
|
438
|
-
function isToolCall(msg) {
|
|
439
|
-
const t = msg;
|
|
440
|
-
return t.type === "tool_call" && typeof t.name === "string" && typeof t.call_id === "string" && (t.status === "running" || t.status === "completed" || t.status === "error");
|
|
441
|
-
}
|
|
442
|
-
function isAgentRunError(err) {
|
|
443
|
-
if (!(err instanceof Error)) return false;
|
|
444
|
-
const e = err;
|
|
445
|
-
return "code" in e && typeof e.code === "string";
|
|
446
|
-
}
|
|
447
|
-
function errorToEvent(err, id) {
|
|
448
|
-
if (isAgentRunError(err)) {
|
|
449
|
-
const event2 = {
|
|
450
|
-
type: "error",
|
|
451
|
-
message: err.message,
|
|
452
|
-
code: err.code
|
|
453
|
-
};
|
|
454
|
-
if (err.provider !== void 0) event2.provider = err.provider;
|
|
455
|
-
if (err.retriable !== void 0) event2.retriable = err.retriable;
|
|
456
|
-
if (err.retryAfterMs !== void 0) event2.retryAfterMs = err.retryAfterMs;
|
|
457
|
-
if (id !== void 0) event2.id = id;
|
|
458
|
-
return event2;
|
|
459
|
-
}
|
|
460
|
-
let message;
|
|
461
|
-
if (err instanceof Error) {
|
|
462
|
-
message = err.message;
|
|
463
|
-
} else if (typeof err === "string") {
|
|
464
|
-
message = err;
|
|
465
|
-
} else if (err !== null && typeof err === "object" && "message" in err) {
|
|
466
|
-
const candidate = err.message;
|
|
467
|
-
message = typeof candidate === "string" ? candidate : "[object Object]";
|
|
468
|
-
} else if (err === null || err === void 0) {
|
|
469
|
-
message = String(err);
|
|
470
|
-
} else {
|
|
471
|
-
message = "[non-stringifiable error]";
|
|
472
|
-
}
|
|
473
|
-
const event = { type: "error", message };
|
|
474
|
-
if (id !== void 0) event.id = id;
|
|
475
|
-
return event;
|
|
476
|
-
}
|
|
477
|
-
function yieldFromToolCall(msg) {
|
|
478
|
-
if (msg.status === "running") {
|
|
479
|
-
return {
|
|
480
|
-
type: "tool_call",
|
|
481
|
-
name: msg.name,
|
|
482
|
-
args: safeArgs(msg.args),
|
|
483
|
-
id: msg.call_id
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
if (msg.status === "completed") {
|
|
487
|
-
const data = typeof msg.result === "string" ? msg.result : safeJsonStringify(msg.result);
|
|
488
|
-
return {
|
|
489
|
-
type: "tool_result",
|
|
490
|
-
name: msg.name,
|
|
491
|
-
data,
|
|
492
|
-
id: msg.call_id
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
const message = typeof msg.result === "string" ? msg.result : `Tool ${msg.name} failed`;
|
|
496
|
-
return { type: "error", message, id: msg.call_id };
|
|
497
|
-
}
|
|
498
|
-
async function* streamAgentRun(run) {
|
|
499
|
-
for await (const msg of run.stream()) {
|
|
500
|
-
if (isAssistant(msg)) {
|
|
501
|
-
for (const block of msg.message.content) {
|
|
502
|
-
if (block.type === "text" && typeof block.text === "string" && block.text.length > 0) {
|
|
503
|
-
yield { type: "message", content: block.text };
|
|
264
|
+
var MAX_SPEC_BYTES = 10 * 1024 * 1024;
|
|
265
|
+
var DEFAULT_CDN = "https://cdn.jsdelivr.net/npm/@scalar/api-reference";
|
|
266
|
+
function createOpenApiHandler(opts = {}) {
|
|
267
|
+
const docsPath = opts.docsPath ?? "/api/docs";
|
|
268
|
+
const jsonPath = opts.openapiJsonPath ?? "/api/docs/openapi.json";
|
|
269
|
+
const specFile = resolve(opts.specFilePath ?? ".theo/openapi.json");
|
|
270
|
+
const title = opts.pageTitle ?? "API Reference";
|
|
271
|
+
const cdn = opts.cdnUrl ?? DEFAULT_CDN;
|
|
272
|
+
if (specFile.includes("..")) {
|
|
273
|
+
throw new Error(`[theokit:openapi] specFilePath must not contain ".." segments: ${specFile}`);
|
|
274
|
+
}
|
|
275
|
+
return (request) => {
|
|
276
|
+
if (request.method !== "GET") return null;
|
|
277
|
+
const url = new URL(request.url);
|
|
278
|
+
if (url.pathname === docsPath) {
|
|
279
|
+
const cdnHost = new URL(cdn).host;
|
|
280
|
+
return new Response(renderScalarHtml(title, jsonPath, cdn), {
|
|
281
|
+
status: 200,
|
|
282
|
+
headers: {
|
|
283
|
+
"content-type": "text/html; charset=utf-8",
|
|
284
|
+
"content-security-policy": `script-src 'self' 'unsafe-eval' ${cdnHost}; style-src 'self' 'unsafe-inline'; img-src 'self' data: ${cdnHost}; font-src 'self' data: ${cdnHost}; connect-src 'self' ${cdnHost}`
|
|
504
285
|
}
|
|
505
|
-
}
|
|
506
|
-
} else if (isToolCall(msg)) {
|
|
507
|
-
yield yieldFromToolCall(msg);
|
|
286
|
+
});
|
|
508
287
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
if (result.status === "error" && result.error !== void 0) {
|
|
512
|
-
yield errorToEvent(result.error);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// src/server/agent/provider-resolver.ts
|
|
517
|
-
var DEFAULT_REGISTRY = [
|
|
518
|
-
{
|
|
519
|
-
name: "openrouter",
|
|
520
|
-
envKey: "OPENROUTER_API_KEY",
|
|
521
|
-
baseUrl: "https://openrouter.ai/api/v1",
|
|
522
|
-
priority: 1
|
|
523
|
-
},
|
|
524
|
-
{
|
|
525
|
-
name: "openai",
|
|
526
|
-
envKey: "OPENAI_API_KEY",
|
|
527
|
-
baseUrl: "https://api.openai.com/v1",
|
|
528
|
-
priority: 2
|
|
529
|
-
},
|
|
530
|
-
{
|
|
531
|
-
name: "anthropic",
|
|
532
|
-
envKey: "ANTHROPIC_API_KEY",
|
|
533
|
-
baseUrl: "https://api.anthropic.com",
|
|
534
|
-
priority: 3
|
|
535
|
-
}
|
|
536
|
-
];
|
|
537
|
-
var registry = [...DEFAULT_REGISTRY];
|
|
538
|
-
function resolveProvider() {
|
|
539
|
-
const sorted = [...registry].sort((a, b) => a.priority - b.priority);
|
|
540
|
-
for (const desc of sorted) {
|
|
541
|
-
const apiKey = process.env[desc.envKey];
|
|
542
|
-
if (apiKey && apiKey.length > 0) {
|
|
543
|
-
return {
|
|
544
|
-
name: desc.name,
|
|
545
|
-
apiKey,
|
|
546
|
-
baseUrl: desc.baseUrl
|
|
547
|
-
};
|
|
288
|
+
if (url.pathname === jsonPath) {
|
|
289
|
+
return serveSpecFile(specFile);
|
|
548
290
|
}
|
|
549
|
-
}
|
|
550
|
-
const envKeys = sorted.map((p) => p.envKey).join(" OR ");
|
|
551
|
-
throw new Error(
|
|
552
|
-
`No LLM provider API key found in environment. Set one of: ${envKeys}. Get a free OpenRouter key at https://openrouter.ai/keys (recommended \u2014 one key, many models).`
|
|
553
|
-
);
|
|
554
|
-
}
|
|
555
|
-
function tryResolveProvider() {
|
|
556
|
-
try {
|
|
557
|
-
return resolveProvider();
|
|
558
|
-
} catch {
|
|
559
291
|
return null;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// src/server/agent/create-conversation-history.ts
|
|
564
|
-
var sdkOverride = void 0;
|
|
565
|
-
function __setSdkForTests(sdk) {
|
|
566
|
-
sdkOverride = sdk;
|
|
567
|
-
}
|
|
568
|
-
function __resetSdkForTests() {
|
|
569
|
-
sdkOverride = void 0;
|
|
570
|
-
}
|
|
571
|
-
async function loadSdk() {
|
|
572
|
-
if (sdkOverride === null) {
|
|
573
|
-
throw new Error(
|
|
574
|
-
"createConversationHistory requires @theokit/sdk. Install: pnpm add @theokit/sdk"
|
|
575
|
-
);
|
|
576
|
-
}
|
|
577
|
-
if (sdkOverride !== void 0) return sdkOverride;
|
|
578
|
-
try {
|
|
579
|
-
const { createRequire } = await import("module");
|
|
580
|
-
const requireFn = createRequire(import.meta.url);
|
|
581
|
-
const spec = "@theokit/sdk";
|
|
582
|
-
const mod = requireFn(spec);
|
|
583
|
-
return mod;
|
|
584
|
-
} catch (cause) {
|
|
585
|
-
throw new Error(
|
|
586
|
-
"createConversationHistory requires @theokit/sdk. Install: pnpm add @theokit/sdk",
|
|
587
|
-
{ cause }
|
|
588
|
-
);
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
var DEFAULT_COOKIE_NAME = "theo_conversation";
|
|
592
|
-
var DEFAULT_COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
|
|
593
|
-
var AGENT_ID_REGEX = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
594
|
-
function isValidAgentId(s) {
|
|
595
|
-
return typeof s === "string" && AGENT_ID_REGEX.test(s);
|
|
596
|
-
}
|
|
597
|
-
function readCookieValue(request, name) {
|
|
598
|
-
let raw;
|
|
599
|
-
const h = request.headers;
|
|
600
|
-
if (h === void 0) return void 0;
|
|
601
|
-
if (typeof h.get === "function") {
|
|
602
|
-
raw = h.get("cookie") ?? void 0;
|
|
603
|
-
} else {
|
|
604
|
-
raw = h.cookie;
|
|
605
|
-
}
|
|
606
|
-
if (raw === void 0 || raw.length === 0) return void 0;
|
|
607
|
-
const pairs = raw.split(/[;,]/);
|
|
608
|
-
for (const pair of pairs) {
|
|
609
|
-
const eq = pair.indexOf("=");
|
|
610
|
-
if (eq < 0) continue;
|
|
611
|
-
const k = pair.slice(0, eq).trim();
|
|
612
|
-
if (k === name) return pair.slice(eq + 1).trim();
|
|
613
|
-
}
|
|
614
|
-
return void 0;
|
|
615
|
-
}
|
|
616
|
-
function serializeCookie(name, value, options) {
|
|
617
|
-
const parts = [`${name}=${value}`];
|
|
618
|
-
if (options.path !== void 0) parts.push(`Path=${options.path}`);
|
|
619
|
-
if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
|
|
620
|
-
if (options.sameSite !== void 0) {
|
|
621
|
-
const v = options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1);
|
|
622
|
-
parts.push(`SameSite=${v}`);
|
|
623
|
-
}
|
|
624
|
-
if (options.httpOnly === true) parts.push("HttpOnly");
|
|
625
|
-
return parts.join("; ");
|
|
626
|
-
}
|
|
627
|
-
async function createConversationHistory(args) {
|
|
628
|
-
const cookieName = args.cookieName ?? DEFAULT_COOKIE_NAME;
|
|
629
|
-
const rawMaxAge = args.cookieMaxAge;
|
|
630
|
-
const cookieMaxAge = typeof rawMaxAge === "number" && rawMaxAge > 0 ? rawMaxAge : DEFAULT_COOKIE_MAX_AGE;
|
|
631
|
-
let conversationId;
|
|
632
|
-
let isNew = false;
|
|
633
|
-
const cookieOnRequest = readCookieValue(args.request, cookieName);
|
|
634
|
-
if (isValidAgentId(args.agentId)) {
|
|
635
|
-
conversationId = args.agentId;
|
|
636
|
-
} else if (args.session !== null && args.session !== void 0) {
|
|
637
|
-
const sId = args.session.conversationId;
|
|
638
|
-
if (isValidAgentId(sId)) conversationId = sId;
|
|
639
|
-
}
|
|
640
|
-
if (conversationId === void 0 && isValidAgentId(cookieOnRequest)) {
|
|
641
|
-
conversationId = cookieOnRequest;
|
|
642
|
-
}
|
|
643
|
-
if (conversationId === void 0) {
|
|
644
|
-
conversationId = crypto.randomUUID();
|
|
645
|
-
isNew = true;
|
|
646
|
-
}
|
|
647
|
-
const shouldIssueCookie = isNew || cookieOnRequest !== conversationId;
|
|
648
|
-
if (shouldIssueCookie && args.response !== void 0) {
|
|
649
|
-
const cookie = serializeCookie(cookieName, conversationId, {
|
|
650
|
-
httpOnly: true,
|
|
651
|
-
sameSite: "lax",
|
|
652
|
-
maxAge: cookieMaxAge,
|
|
653
|
-
path: "/"
|
|
654
|
-
});
|
|
655
|
-
args.response.headers.append("set-cookie", cookie);
|
|
656
|
-
}
|
|
657
|
-
const resolvedOptions = autoResolveProviderIfNeeded(args.options);
|
|
658
|
-
const sdk = await loadSdk();
|
|
659
|
-
const agent = await sdk.Agent.getOrCreate(conversationId, resolvedOptions);
|
|
660
|
-
return { agent, conversationId, isNew };
|
|
661
|
-
}
|
|
662
|
-
function autoResolveProviderIfNeeded(options) {
|
|
663
|
-
if (typeof options.apiKey === "string" && options.apiKey.length > 0) {
|
|
664
|
-
return options;
|
|
665
|
-
}
|
|
666
|
-
const resolved = tryResolveProvider();
|
|
667
|
-
if (resolved === null) {
|
|
668
|
-
throw new Error(
|
|
669
|
-
"No LLM provider API key found in environment. Set OPENROUTER_API_KEY (recommended \u2014 gateway to many models) OR OPENAI_API_KEY OR ANTHROPIC_API_KEY in your .env. Get a free OpenRouter key at https://openrouter.ai/keys. (Pass `options.apiKey` explicitly to bypass auto-resolution.)"
|
|
670
|
-
);
|
|
671
|
-
}
|
|
672
|
-
return {
|
|
673
|
-
...options,
|
|
674
|
-
apiKey: resolved.apiKey,
|
|
675
|
-
providers: {
|
|
676
|
-
routes: [{ capability: "chat", provider: resolved.name, baseUrl: resolved.baseUrl }]
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// src/server/rate-limit/rate-limit-per-route.ts
|
|
682
|
-
import { createHash } from "crypto";
|
|
683
|
-
function normalizePath(input) {
|
|
684
|
-
const noQuery = input.split("?")[0];
|
|
685
|
-
if (noQuery.length > 1 && noQuery.endsWith("/")) return noQuery.slice(0, -1);
|
|
686
|
-
return noQuery;
|
|
687
|
-
}
|
|
688
|
-
function matchRoutePattern(path, pattern) {
|
|
689
|
-
const canonical = normalizePath(path);
|
|
690
|
-
if (typeof pattern === "string") {
|
|
691
|
-
return canonical === normalizePath(pattern);
|
|
692
|
-
}
|
|
693
|
-
pattern.lastIndex = 0;
|
|
694
|
-
return pattern.test(canonical);
|
|
695
|
-
}
|
|
696
|
-
function hashFragment(input) {
|
|
697
|
-
return createHash("sha256").update(input).digest("base64url").slice(0, 16);
|
|
698
|
-
}
|
|
699
|
-
function readCookie(req, name) {
|
|
700
|
-
return parseCookieHeader(req.headers.cookie ?? void 0).get(name);
|
|
701
|
-
}
|
|
702
|
-
function deriveKey(req, keyBy, cookieName) {
|
|
703
|
-
if (typeof keyBy === "function") return keyBy(req);
|
|
704
|
-
const ip = req.socket?.remoteAddress ?? "unknown";
|
|
705
|
-
switch (keyBy) {
|
|
706
|
-
case "session": {
|
|
707
|
-
const cookie = readCookie(req, cookieName);
|
|
708
|
-
return cookie ? `session:${hashFragment(cookie)}` : `ip:${ip}`;
|
|
709
|
-
}
|
|
710
|
-
case "user": {
|
|
711
|
-
const userId = req.user?.id;
|
|
712
|
-
return userId ? `user:${userId}` : `ip:${ip}`;
|
|
713
|
-
}
|
|
714
|
-
case "ip":
|
|
715
|
-
default:
|
|
716
|
-
return `ip:${ip}`;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
function createRouteRateLimiter(config) {
|
|
720
|
-
const isFlat = "windowMs" in config && "max" in config && !("default" in config) && !("routes" in config);
|
|
721
|
-
const cfg = isFlat ? { default: config } : config;
|
|
722
|
-
const store = cfg.store ?? new InMemoryStore();
|
|
723
|
-
if (!(store instanceof InMemoryStore)) {
|
|
724
|
-
throw new Error(
|
|
725
|
-
"createRouteRateLimiter: async RateLimitStore implementations require a dedicated async middleware path. Use the InMemoryStore default for the sync fa\xE7ade."
|
|
726
|
-
);
|
|
727
|
-
}
|
|
728
|
-
const inMemoryStore = store;
|
|
729
|
-
const keyBy = cfg.keyBy ?? "ip";
|
|
730
|
-
const cookieName = cfg.cookieName ?? "theo_session";
|
|
731
|
-
const patternList = [];
|
|
732
|
-
if (cfg.routes) {
|
|
733
|
-
for (const [pattern, c] of Object.entries(cfg.routes)) patternList.push([pattern, c]);
|
|
734
|
-
}
|
|
735
|
-
if (cfg.routePatterns) {
|
|
736
|
-
for (const tuple of cfg.routePatterns) patternList.push(tuple);
|
|
737
|
-
}
|
|
738
|
-
return function checkRouteRateLimit(req) {
|
|
739
|
-
const url = req.url ?? "";
|
|
740
|
-
let matched;
|
|
741
|
-
for (const [pattern, c] of patternList) {
|
|
742
|
-
if (matchRoutePattern(url, pattern)) {
|
|
743
|
-
matched = c;
|
|
744
|
-
break;
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
const effective = matched ?? cfg.default;
|
|
748
|
-
if (!effective) {
|
|
749
|
-
return { limited: false, headers: {} };
|
|
750
|
-
}
|
|
751
|
-
const bucketSuffix = typeof matched === "undefined" ? "*default*" : normalizePath(url);
|
|
752
|
-
const key = `${deriveKey(req, keyBy, cookieName)}|${bucketSuffix}`;
|
|
753
|
-
const state = inMemoryStore.incrSync(key, effective.windowMs);
|
|
754
|
-
if (state.count > effective.max) {
|
|
755
|
-
const retryAfter = Math.ceil((state.resetAt - Date.now()) / 1e3);
|
|
756
|
-
return {
|
|
757
|
-
limited: true,
|
|
758
|
-
headers: {
|
|
759
|
-
"X-RateLimit-Limit": String(effective.max),
|
|
760
|
-
"X-RateLimit-Remaining": "0",
|
|
761
|
-
"Retry-After": String(retryAfter)
|
|
762
|
-
}
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
return {
|
|
766
|
-
limited: false,
|
|
767
|
-
headers: {
|
|
768
|
-
"X-RateLimit-Limit": String(effective.max),
|
|
769
|
-
"X-RateLimit-Remaining": String(Math.max(0, effective.max - state.count))
|
|
770
|
-
}
|
|
771
|
-
};
|
|
772
292
|
};
|
|
773
293
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
if (this.rooms.get(room)?.size === 0) this.rooms.delete(room);
|
|
796
|
-
this.wsRooms.get(ws)?.delete(room);
|
|
797
|
-
if (this.wsRooms.get(ws)?.size === 0) this.wsRooms.delete(ws);
|
|
798
|
-
}
|
|
799
|
-
broadcast(room, data, exclude) {
|
|
800
|
-
const clients = this.rooms.get(room);
|
|
801
|
-
if (!clients) return;
|
|
802
|
-
const msg = JSON.stringify(data);
|
|
803
|
-
for (const ws of clients) {
|
|
804
|
-
if (ws !== exclude) ws.send(msg);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
broadcastAll(data) {
|
|
808
|
-
const msg = JSON.stringify(data);
|
|
809
|
-
const seen = /* @__PURE__ */ new Set();
|
|
810
|
-
for (const clients of this.rooms.values()) {
|
|
811
|
-
for (const ws of clients) {
|
|
812
|
-
if (!seen.has(ws)) {
|
|
813
|
-
ws.send(msg);
|
|
814
|
-
seen.add(ws);
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
getRoomSize(room) {
|
|
820
|
-
return this.rooms.get(room)?.size ?? 0;
|
|
821
|
-
}
|
|
822
|
-
cleanup(ws) {
|
|
823
|
-
const rooms = this.wsRooms.get(ws);
|
|
824
|
-
if (rooms) {
|
|
825
|
-
for (const room of rooms) {
|
|
826
|
-
this.rooms.get(room)?.delete(ws);
|
|
827
|
-
if (this.rooms.get(room)?.size === 0) this.rooms.delete(room);
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
this.wsRooms.delete(ws);
|
|
831
|
-
}
|
|
832
|
-
};
|
|
833
|
-
|
|
834
|
-
// src/server/storage/storage-manager.ts
|
|
835
|
-
var StorageManager = class {
|
|
836
|
-
#config;
|
|
837
|
-
#dbPools = /* @__PURE__ */ new Map();
|
|
838
|
-
#redisClients = /* @__PURE__ */ new Map();
|
|
839
|
-
#genericClients = /* @__PURE__ */ new Map();
|
|
840
|
-
#adapters = /* @__PURE__ */ new Set();
|
|
841
|
-
#disposed = false;
|
|
842
|
-
/**
|
|
843
|
-
* Apply the storage config block from `theo.config.ts`. Second call warns
|
|
844
|
-
* and is ignored (D3). Reset only via `__resetForTests()`.
|
|
845
|
-
*/
|
|
846
|
-
configure(config) {
|
|
847
|
-
if (this.#config !== void 0) {
|
|
848
|
-
console.warn("[theokit] StorageManager already configured; ignoring second configure() call");
|
|
849
|
-
return;
|
|
850
|
-
}
|
|
851
|
-
this.#config = config;
|
|
852
|
-
}
|
|
853
|
-
/**
|
|
854
|
-
* Generic cache + factory for ANY client (MySQL, Mongo, Turso, DynamoDB, …).
|
|
855
|
-
* Returns the cached client OR invokes the factory and caches its return.
|
|
856
|
-
*
|
|
857
|
-
* EC-1 FIX: cache-hit check uses `Map.has(name)`, NOT `cached !== undefined`.
|
|
858
|
-
* Factories returning `null` or `undefined` are valid (lazy connect, stubs);
|
|
859
|
-
* the `!== undefined` check would re-invoke the factory infinitely for
|
|
860
|
-
* undefined returns AND silently cache `null` cast as `T`.
|
|
861
|
-
*
|
|
862
|
-
* EC-2 (documented type hole): `useStorage<A>('x', fA)` followed by
|
|
863
|
-
* `useStorage<B>('x', fB)` returns the cached A cast as B. Same trade-off
|
|
864
|
-
* as `Map<string, unknown>` — caller is responsible for using unique names
|
|
865
|
-
* per type.
|
|
866
|
-
*
|
|
867
|
-
* Lifecycle: generic clients are NOT auto-drained by `dispose()`. Call
|
|
868
|
-
* `manager.register({ name, dispose })` separately to participate.
|
|
869
|
-
*
|
|
870
|
-
* Reserved name prefixes (do NOT use): `__pg:`, `__redis:`, `__unstorage:`,
|
|
871
|
-
* `__db0:` — these are used internally by the typed helpers.
|
|
872
|
-
*/
|
|
873
|
-
useStorage(name, factory) {
|
|
874
|
-
if (this.#disposed) throw new Error("StorageManager is disposed");
|
|
875
|
-
if (this.#genericClients.has(name)) return this.#genericClients.get(name);
|
|
876
|
-
const client = factory();
|
|
877
|
-
this.#genericClients.set(name, client);
|
|
878
|
-
return client;
|
|
879
|
-
}
|
|
880
|
-
/**
|
|
881
|
-
* Return a Postgres pool for the named database. Lazy + cached. Factory
|
|
882
|
-
* invoked exactly once per `dbName` (D2).
|
|
883
|
-
*
|
|
884
|
-
* Throws if:
|
|
885
|
-
* - manager is disposed
|
|
886
|
-
* - `dbName` is not in `config.databases`
|
|
887
|
-
* - the referenced server is not in `config.servers` (EC-2: deferred
|
|
888
|
-
* cross-field validation surfaces here, not at configure time)
|
|
889
|
-
*/
|
|
890
|
-
usePostgres(dbName, factory) {
|
|
891
|
-
if (this.#disposed) throw new Error("StorageManager is disposed");
|
|
892
|
-
const cached = this.#dbPools.get(dbName);
|
|
893
|
-
if (cached !== void 0) return cached;
|
|
894
|
-
const dbConfig = this.#config?.databases?.[dbName];
|
|
895
|
-
if (dbConfig === void 0) {
|
|
896
|
-
throw new Error(
|
|
897
|
-
`Database "${dbName}" not configured. Add it to theo.config.ts > storage.databases.`
|
|
898
|
-
);
|
|
899
|
-
}
|
|
900
|
-
const server = this.#config?.servers?.[dbConfig.server];
|
|
901
|
-
if (server === void 0) {
|
|
902
|
-
throw new Error(
|
|
903
|
-
`Server "${dbConfig.server}" referenced by database "${dbName}" not found in theo.config.ts > storage.servers.`
|
|
904
|
-
);
|
|
905
|
-
}
|
|
906
|
-
const pool = factory(server, dbConfig);
|
|
907
|
-
this.#dbPools.set(dbName, pool);
|
|
908
|
-
return pool;
|
|
909
|
-
}
|
|
910
|
-
/**
|
|
911
|
-
* Return a Redis client for the named server. Lazy + cached. Factory
|
|
912
|
-
* invoked exactly once per `serverName`.
|
|
913
|
-
*/
|
|
914
|
-
useRedis(serverName, factory) {
|
|
915
|
-
if (this.#disposed) throw new Error("StorageManager is disposed");
|
|
916
|
-
const cached = this.#redisClients.get(serverName);
|
|
917
|
-
if (cached !== void 0) return cached;
|
|
918
|
-
const serverConfig = this.#config?.redis?.[serverName];
|
|
919
|
-
if (serverConfig === void 0) {
|
|
920
|
-
throw new Error(
|
|
921
|
-
`Redis server "${serverName}" not configured. Add it to theo.config.ts > storage.redis.`
|
|
922
|
-
);
|
|
923
|
-
}
|
|
924
|
-
const client = factory(serverConfig);
|
|
925
|
-
this.#redisClients.set(serverName, client);
|
|
926
|
-
return client;
|
|
927
|
-
}
|
|
928
|
-
/**
|
|
929
|
-
* Register an adapter for graceful shutdown coordination (D6).
|
|
930
|
-
*
|
|
931
|
-
* EC-4: throws if the manager is already disposed — prevents silent
|
|
932
|
-
* leaks in test seams that reset+reuse the manager.
|
|
933
|
-
*/
|
|
934
|
-
register(adapter) {
|
|
935
|
-
if (this.#disposed) {
|
|
936
|
-
throw new Error(
|
|
937
|
-
"StorageManager is disposed; cannot register new adapter. Call __resetForTests() in test setup."
|
|
938
|
-
);
|
|
939
|
-
}
|
|
940
|
-
this.#adapters.add(adapter);
|
|
941
|
-
}
|
|
942
|
-
/**
|
|
943
|
-
* Drain in parallel — registered adapters, then PG pools, then Redis
|
|
944
|
-
* clients. Idempotent (D5). Errors per resource are logged and swallowed
|
|
945
|
-
* — they do NOT prevent shutdown of the remaining resources.
|
|
946
|
-
*
|
|
947
|
-
* Caller must wrap in a timeout if a bound is needed (EC-7: documented).
|
|
948
|
-
* In production, `start.ts` wraps the whole shutdown sequence in a 25 s
|
|
949
|
-
* force-exit timer.
|
|
950
|
-
*/
|
|
951
|
-
async dispose() {
|
|
952
|
-
if (this.#disposed) return;
|
|
953
|
-
this.#disposed = true;
|
|
954
|
-
const adapterDrains = Array.from(this.#adapters).map(
|
|
955
|
-
(a) => a.dispose().catch((err) => {
|
|
956
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
957
|
-
console.warn(`[theokit] adapter "${a.name}" dispose failed: ${msg}`);
|
|
958
|
-
})
|
|
959
|
-
);
|
|
960
|
-
await Promise.all(adapterDrains);
|
|
961
|
-
const poolCloses = Array.from(this.#dbPools.values()).map((pool) => {
|
|
962
|
-
if (pool.end === void 0) return Promise.resolve();
|
|
963
|
-
return pool.end().catch((err) => {
|
|
964
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
965
|
-
console.warn(`[theokit] PG pool close failed: ${msg}`);
|
|
966
|
-
});
|
|
967
|
-
});
|
|
968
|
-
await Promise.all(poolCloses);
|
|
969
|
-
const redisCloses = Array.from(this.#redisClients.values()).map(
|
|
970
|
-
(c) => c.quit().catch((err) => {
|
|
971
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
972
|
-
console.warn(`[theokit] Redis quit failed, falling back to disconnect: ${msg}`);
|
|
973
|
-
c.disconnect();
|
|
974
|
-
})
|
|
975
|
-
);
|
|
976
|
-
await Promise.all(redisCloses);
|
|
977
|
-
this.#dbPools.clear();
|
|
978
|
-
this.#redisClients.clear();
|
|
979
|
-
this.#genericClients.clear();
|
|
980
|
-
this.#adapters.clear();
|
|
981
|
-
}
|
|
982
|
-
/** @internal Testing seam — resets state so a single test file can re-use the singleton across `it` blocks (EC-3). */
|
|
983
|
-
__resetForTests() {
|
|
984
|
-
this.#config = void 0;
|
|
985
|
-
this.#dbPools.clear();
|
|
986
|
-
this.#redisClients.clear();
|
|
987
|
-
this.#genericClients.clear();
|
|
988
|
-
this.#adapters.clear();
|
|
989
|
-
this.#disposed = false;
|
|
990
|
-
}
|
|
991
|
-
/** @internal Introspection helper for tests. */
|
|
992
|
-
__isConfiguredForTests() {
|
|
993
|
-
return this.#config !== void 0;
|
|
994
|
-
}
|
|
995
|
-
/** @internal Introspection helper for tests. */
|
|
996
|
-
__isDisposedForTests() {
|
|
997
|
-
return this.#disposed;
|
|
998
|
-
}
|
|
999
|
-
};
|
|
1000
|
-
var __singleton;
|
|
1001
|
-
function getStorageManager() {
|
|
1002
|
-
__singleton ??= new StorageManager();
|
|
1003
|
-
return __singleton;
|
|
1004
|
-
}
|
|
1005
|
-
function __resetSingletonForTests() {
|
|
1006
|
-
__singleton = void 0;
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
// src/server/storage/use-unstorage.ts
|
|
1010
|
-
async function useUnstorage(name, driver) {
|
|
1011
|
-
const mod = await import("unstorage").catch(() => null);
|
|
1012
|
-
if (mod === null) {
|
|
1013
|
-
throw new Error(
|
|
1014
|
-
"useUnstorage requires the 'unstorage' package. Install via: pnpm add unstorage"
|
|
1015
|
-
);
|
|
1016
|
-
}
|
|
1017
|
-
const manager = getStorageManager();
|
|
1018
|
-
return manager.useStorage(`__unstorage:${name}`, () => {
|
|
1019
|
-
const storage = mod.createStorage({ driver });
|
|
1020
|
-
manager.register({
|
|
1021
|
-
name: `unstorage:${name}`,
|
|
1022
|
-
dispose: () => storage.dispose?.() ?? Promise.resolve()
|
|
294
|
+
function escapeHtml(s) {
|
|
295
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
296
|
+
}
|
|
297
|
+
function renderScalarHtml(title, specUrl, cdnUrl) {
|
|
298
|
+
return `<!DOCTYPE html>
|
|
299
|
+
<html>
|
|
300
|
+
<head>
|
|
301
|
+
<meta charset="utf-8">
|
|
302
|
+
<title>${escapeHtml(title)}</title>
|
|
303
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
304
|
+
</head>
|
|
305
|
+
<body>
|
|
306
|
+
<script id="api-reference" data-url="${escapeHtml(specUrl)}"></script>
|
|
307
|
+
<script src="${escapeHtml(cdnUrl)}"></script>
|
|
308
|
+
</body>
|
|
309
|
+
</html>`;
|
|
310
|
+
}
|
|
311
|
+
function serveSpecFile(filePath) {
|
|
312
|
+
if (!existsSync(filePath)) {
|
|
313
|
+
return jsonResponse(503, {
|
|
314
|
+
error: { code: "OPENAPI_NOT_EMITTED", message: "OpenAPI spec not generated yet. Start the dev server and visit a route first." }
|
|
1023
315
|
});
|
|
1024
|
-
return storage;
|
|
1025
|
-
});
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
// src/server/storage/use-database.ts
|
|
1029
|
-
function detectUninvokedFactory(connector) {
|
|
1030
|
-
if (typeof connector === "function") {
|
|
1031
|
-
const fn = connector;
|
|
1032
|
-
if ((fn.length ?? 0) > 0) {
|
|
1033
|
-
const name = fn.name !== void 0 && fn.name !== "" ? fn.name : "connector";
|
|
1034
|
-
return `useDatabase: connector argument looks like an un-invoked factory (function with ${String(fn.length)} parameter(s)). Did you forget to call the factory? Pass \`${name}({...})\` not \`${name}\`. Example: useDatabase('main', sqlite({ name: ':memory:' }))`;
|
|
1035
|
-
}
|
|
1036
316
|
}
|
|
1037
|
-
return null;
|
|
1038
|
-
}
|
|
1039
|
-
async function useDatabase(name, connector) {
|
|
1040
|
-
const factoryError = detectUninvokedFactory(connector);
|
|
1041
|
-
if (factoryError !== null) throw new Error(factoryError);
|
|
1042
|
-
const mod = await import("db0").catch(() => null);
|
|
1043
|
-
if (mod === null) {
|
|
1044
|
-
throw new Error("useDatabase requires the 'db0' package. Install via: pnpm add db0");
|
|
1045
|
-
}
|
|
1046
|
-
const manager = getStorageManager();
|
|
1047
|
-
return manager.useStorage(`__db0:${name}`, () => mod.createDatabase(connector));
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
// src/server/webhook/timing-safe-equal.ts
|
|
1051
|
-
var cachedNodeImpl;
|
|
1052
|
-
function resolveNodeImpl() {
|
|
1053
|
-
if (cachedNodeImpl !== void 0) return cachedNodeImpl;
|
|
1054
317
|
try {
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
}
|
|
1060
|
-
return cachedNodeImpl;
|
|
1061
|
-
}
|
|
1062
|
-
function timingSafeEqual(a, b) {
|
|
1063
|
-
if (!(a instanceof Uint8Array) || !(b instanceof Uint8Array)) {
|
|
1064
|
-
throw new TypeError(
|
|
1065
|
-
`timingSafeEqual expects Uint8Array arguments (got ${typeof a} and ${typeof b})`
|
|
1066
|
-
);
|
|
1067
|
-
}
|
|
1068
|
-
if (a.length !== b.length) return false;
|
|
1069
|
-
if (a.length === 0) return true;
|
|
1070
|
-
const nodeImpl = resolveNodeImpl();
|
|
1071
|
-
if (nodeImpl) return nodeImpl(a, b);
|
|
1072
|
-
let diff = 0;
|
|
1073
|
-
for (let i = 0; i < a.length; i++) {
|
|
1074
|
-
diff |= a[i] ^ b[i];
|
|
1075
|
-
}
|
|
1076
|
-
return diff === 0;
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
// src/server/webhook/raw-body.ts
|
|
1080
|
-
var DEFAULT_MAX_BODY_BYTES = 1e6;
|
|
1081
|
-
var BodyTooLargeError = class extends Error {
|
|
1082
|
-
constructor(limit, actualSeen) {
|
|
1083
|
-
super(`Request body exceeds maxBodyBytes: seen ${actualSeen} bytes, limit ${limit} bytes`);
|
|
1084
|
-
this.limit = limit;
|
|
1085
|
-
this.actualSeen = actualSeen;
|
|
1086
|
-
this.name = "BodyTooLargeError";
|
|
1087
|
-
}
|
|
1088
|
-
limit;
|
|
1089
|
-
actualSeen;
|
|
1090
|
-
status = 413;
|
|
1091
|
-
code = "BODY_TOO_LARGE";
|
|
1092
|
-
};
|
|
1093
|
-
async function readRawBody(request, options = {}) {
|
|
1094
|
-
const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
1095
|
-
const clone = request.clone();
|
|
1096
|
-
if (clone.body === null) {
|
|
1097
|
-
return { rawBody: "", bodyClone: request };
|
|
1098
|
-
}
|
|
1099
|
-
const reader = clone.body.getReader();
|
|
1100
|
-
const chunks = [];
|
|
1101
|
-
let total = 0;
|
|
1102
|
-
try {
|
|
1103
|
-
for (; ; ) {
|
|
1104
|
-
const { value, done } = await reader.read();
|
|
1105
|
-
if (done) break;
|
|
1106
|
-
total += value.byteLength;
|
|
1107
|
-
if (total > maxBodyBytes) {
|
|
1108
|
-
void reader.cancel();
|
|
1109
|
-
throw new BodyTooLargeError(maxBodyBytes, total);
|
|
1110
|
-
}
|
|
1111
|
-
chunks.push(value);
|
|
1112
|
-
}
|
|
1113
|
-
} finally {
|
|
1114
|
-
try {
|
|
1115
|
-
reader.releaseLock();
|
|
1116
|
-
} catch {
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
const bytes = new Uint8Array(total);
|
|
1120
|
-
let offset = 0;
|
|
1121
|
-
for (const chunk of chunks) {
|
|
1122
|
-
bytes.set(chunk, offset);
|
|
1123
|
-
offset += chunk.byteLength;
|
|
1124
|
-
}
|
|
1125
|
-
const rawBody = new TextDecoder().decode(bytes);
|
|
1126
|
-
return { rawBody, bodyClone: request };
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
// src/server/webhook/define-webhook.ts
|
|
1130
|
-
function defineWebhook(opts) {
|
|
1131
|
-
return {
|
|
1132
|
-
verify: opts.verify,
|
|
1133
|
-
handler: opts.handler,
|
|
1134
|
-
maxBodyBytes: opts.maxBodyBytes,
|
|
1135
|
-
__theokit_kind: "webhook"
|
|
1136
|
-
};
|
|
1137
|
-
}
|
|
1138
|
-
async function dispatchWebhook(def, request) {
|
|
1139
|
-
let rawBody;
|
|
1140
|
-
let bodyClone;
|
|
1141
|
-
try {
|
|
1142
|
-
const result2 = await readRawBody(request, { maxBodyBytes: def.maxBodyBytes });
|
|
1143
|
-
rawBody = result2.rawBody;
|
|
1144
|
-
bodyClone = result2.bodyClone;
|
|
1145
|
-
} catch (err) {
|
|
1146
|
-
if (err instanceof BodyTooLargeError) {
|
|
1147
|
-
return new Response(JSON.stringify({ error: err.code, message: err.message }), {
|
|
1148
|
-
status: 413,
|
|
1149
|
-
headers: { "content-type": "application/json" }
|
|
318
|
+
const stat = statSync(filePath);
|
|
319
|
+
if (stat.size > MAX_SPEC_BYTES) {
|
|
320
|
+
return jsonResponse(413, {
|
|
321
|
+
error: { code: "OPENAPI_TOO_LARGE", message: `Spec file exceeds ${MAX_SPEC_BYTES / 1024 / 1024}MB limit` }
|
|
1150
322
|
});
|
|
1151
323
|
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
{ status: 400, headers: { "content-type": "application/json" } }
|
|
1158
|
-
);
|
|
1159
|
-
}
|
|
1160
|
-
const incomingTrace = extractTraceContext(request.headers);
|
|
1161
|
-
const traceId = incomingTrace?.trace_id ?? generateNewTraceContext().trace_id;
|
|
1162
|
-
let verifyResult;
|
|
1163
|
-
try {
|
|
1164
|
-
verifyResult = await def.verify(bodyClone);
|
|
324
|
+
const content = readFileSync(filePath, "utf-8");
|
|
325
|
+
return new Response(content, {
|
|
326
|
+
status: 200,
|
|
327
|
+
headers: { "content-type": "application/json", "cache-control": "no-cache" }
|
|
328
|
+
});
|
|
1165
329
|
} catch (err) {
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
};
|
|
1170
|
-
}
|
|
1171
|
-
if (!verifyResult.ok) {
|
|
1172
|
-
return new Response(
|
|
1173
|
-
JSON.stringify({ error: "WEBHOOK_VERIFY_FAILED", message: verifyResult.reason }),
|
|
1174
|
-
{ status: 401, headers: { "content-type": "application/json" } }
|
|
1175
|
-
);
|
|
1176
|
-
}
|
|
1177
|
-
const ctx = {
|
|
1178
|
-
request: bodyClone,
|
|
1179
|
-
rawBody,
|
|
1180
|
-
traceId,
|
|
1181
|
-
signal: request.signal
|
|
1182
|
-
};
|
|
1183
|
-
const result = await def.handler(ctx);
|
|
1184
|
-
if (result instanceof Response) return result;
|
|
1185
|
-
if (result === void 0 || result === null) {
|
|
1186
|
-
return new Response(null, { status: 204 });
|
|
330
|
+
return jsonResponse(500, {
|
|
331
|
+
error: { code: "OPENAPI_READ_FAILED", message: "Failed to read OpenAPI spec file" }
|
|
332
|
+
});
|
|
1187
333
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
334
|
+
}
|
|
335
|
+
function jsonResponse(status, body) {
|
|
336
|
+
return new Response(JSON.stringify(body), {
|
|
337
|
+
status,
|
|
1190
338
|
headers: { "content-type": "application/json" }
|
|
1191
339
|
});
|
|
1192
340
|
}
|
|
@@ -1601,8 +749,8 @@ function createCacheEngine(opts) {
|
|
|
1601
749
|
function claimAndRun(key, fn, options, skipWrite) {
|
|
1602
750
|
let resolveOuter;
|
|
1603
751
|
let rejectOuter;
|
|
1604
|
-
const outerPromise = new Promise((
|
|
1605
|
-
resolveOuter =
|
|
752
|
+
const outerPromise = new Promise((resolve2, reject) => {
|
|
753
|
+
resolveOuter = resolve2;
|
|
1606
754
|
rejectOuter = reject;
|
|
1607
755
|
});
|
|
1608
756
|
void outerPromise.catch(() => {
|
|
@@ -1940,10 +1088,292 @@ function deserializeResponse(serialized) {
|
|
|
1940
1088
|
return superjson.deserialize(serialized);
|
|
1941
1089
|
}
|
|
1942
1090
|
|
|
1091
|
+
// src/server/web-handler.ts
|
|
1092
|
+
function searchParamsToObject(params) {
|
|
1093
|
+
const out = {};
|
|
1094
|
+
for (const [key, value] of params.entries()) {
|
|
1095
|
+
if (!Object.hasOwn(out, key)) {
|
|
1096
|
+
out[key] = value;
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
const existing = out[key];
|
|
1100
|
+
if (Array.isArray(existing)) {
|
|
1101
|
+
existing.push(value);
|
|
1102
|
+
} else {
|
|
1103
|
+
out[key] = [existing, value];
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
return out;
|
|
1107
|
+
}
|
|
1108
|
+
async function parseBodyInline(request) {
|
|
1109
|
+
if (request.method === "GET" || request.method === "HEAD") return void 0;
|
|
1110
|
+
const contentType = request.headers.get("content-type") ?? "";
|
|
1111
|
+
if (contentType.includes("application/json")) {
|
|
1112
|
+
const text = await request.text();
|
|
1113
|
+
if (text.length === 0) return void 0;
|
|
1114
|
+
try {
|
|
1115
|
+
return JSON.parse(text);
|
|
1116
|
+
} catch {
|
|
1117
|
+
return void 0;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
if (contentType.startsWith("text/")) {
|
|
1121
|
+
const text = await request.text();
|
|
1122
|
+
return text.length === 0 ? void 0 : text;
|
|
1123
|
+
}
|
|
1124
|
+
return void 0;
|
|
1125
|
+
}
|
|
1126
|
+
async function parseBodyFull(request) {
|
|
1127
|
+
if (request.method === "GET" || request.method === "HEAD") return void 0;
|
|
1128
|
+
const { parseWebRequestBody } = await import("../body-parser-web-MUWBKZ3F.js");
|
|
1129
|
+
try {
|
|
1130
|
+
const parsed = await parseWebRequestBody(request);
|
|
1131
|
+
if (parsed.json === void 0 && Object.keys(parsed.fields).length === 0 && parsed.files.length === 0) {
|
|
1132
|
+
return void 0;
|
|
1133
|
+
}
|
|
1134
|
+
return parsed;
|
|
1135
|
+
} catch {
|
|
1136
|
+
return void 0;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
function validationErrorResponse(zodError, field) {
|
|
1140
|
+
const envelope = {
|
|
1141
|
+
code: "BAD_REQUEST",
|
|
1142
|
+
message: `Validation failed: ${field}`,
|
|
1143
|
+
ext: {
|
|
1144
|
+
fields: zodError.issues.map((issue) => ({
|
|
1145
|
+
path: issue.path.join("."),
|
|
1146
|
+
message: issue.message
|
|
1147
|
+
}))
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
return new Response(JSON.stringify(envelope), {
|
|
1151
|
+
status: 400,
|
|
1152
|
+
headers: { "content-type": "application/json" }
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
async function runHandler(config, request, bodyParser = "inline") {
|
|
1156
|
+
const url = new URL(request.url);
|
|
1157
|
+
const queryRaw = searchParamsToObject(url.searchParams);
|
|
1158
|
+
const bodyRaw = bodyParser === "full" ? await parseBodyFull(request) : await parseBodyInline(request);
|
|
1159
|
+
const paramsRaw = {};
|
|
1160
|
+
let query = queryRaw;
|
|
1161
|
+
if (config.query !== void 0) {
|
|
1162
|
+
const parsed = config.query.safeParse(queryRaw);
|
|
1163
|
+
if (!parsed.success)
|
|
1164
|
+
return { ok: false, response: validationErrorResponse(parsed.error, "query") };
|
|
1165
|
+
query = parsed.data;
|
|
1166
|
+
}
|
|
1167
|
+
let body = bodyRaw;
|
|
1168
|
+
if (config.body !== void 0) {
|
|
1169
|
+
const parsed = config.body.safeParse(bodyRaw);
|
|
1170
|
+
if (!parsed.success)
|
|
1171
|
+
return { ok: false, response: validationErrorResponse(parsed.error, "body") };
|
|
1172
|
+
body = parsed.data;
|
|
1173
|
+
}
|
|
1174
|
+
let params = paramsRaw;
|
|
1175
|
+
if (config.params !== void 0) {
|
|
1176
|
+
const parsed = config.params.safeParse(paramsRaw);
|
|
1177
|
+
if (!parsed.success)
|
|
1178
|
+
return { ok: false, response: validationErrorResponse(parsed.error, "params") };
|
|
1179
|
+
params = parsed.data;
|
|
1180
|
+
}
|
|
1181
|
+
const result = await config.handler({ query, body, params, request });
|
|
1182
|
+
return { ok: true, result };
|
|
1183
|
+
}
|
|
1184
|
+
function toResponse(result) {
|
|
1185
|
+
if (result === void 0) {
|
|
1186
|
+
return new Response(null, { status: 204 });
|
|
1187
|
+
}
|
|
1188
|
+
if (result instanceof Response) {
|
|
1189
|
+
return result;
|
|
1190
|
+
}
|
|
1191
|
+
return new Response(JSON.stringify(result), {
|
|
1192
|
+
status: 200,
|
|
1193
|
+
headers: { "content-type": "application/json" }
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
function handlerErrorResponse(err) {
|
|
1197
|
+
const envelope = serverErrorToEnvelope(err);
|
|
1198
|
+
const status = envelopeCodeToStatus(envelope.code);
|
|
1199
|
+
return new Response(JSON.stringify(envelope), {
|
|
1200
|
+
status,
|
|
1201
|
+
headers: { "content-type": "application/json" }
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
function envelopeCodeToStatus(code) {
|
|
1205
|
+
switch (code) {
|
|
1206
|
+
case "BAD_REQUEST":
|
|
1207
|
+
return 400;
|
|
1208
|
+
case "UNAUTHORIZED":
|
|
1209
|
+
return 401;
|
|
1210
|
+
case "FORBIDDEN":
|
|
1211
|
+
return 403;
|
|
1212
|
+
case "NOT_FOUND":
|
|
1213
|
+
return 404;
|
|
1214
|
+
case "METHOD_NOT_ALLOWED":
|
|
1215
|
+
return 405;
|
|
1216
|
+
case "PAYLOAD_TOO_LARGE":
|
|
1217
|
+
return 413;
|
|
1218
|
+
case "UNPROCESSABLE_ENTITY":
|
|
1219
|
+
return 422;
|
|
1220
|
+
case "TOO_MANY_REQUESTS":
|
|
1221
|
+
case "RATE_LIMITED":
|
|
1222
|
+
return 429;
|
|
1223
|
+
case "BAD_GATEWAY":
|
|
1224
|
+
return 502;
|
|
1225
|
+
case "SERVICE_UNAVAILABLE":
|
|
1226
|
+
return 503;
|
|
1227
|
+
case "GATEWAY_TIMEOUT":
|
|
1228
|
+
return 504;
|
|
1229
|
+
case "INTERNAL_SERVER_ERROR":
|
|
1230
|
+
default:
|
|
1231
|
+
return 500;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
var CSRF_PROTECTED_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
1235
|
+
function mergeHookHeaders(response, hookHeaders) {
|
|
1236
|
+
if ([...hookHeaders].length === 0) return response;
|
|
1237
|
+
const merged = new Headers(response.headers);
|
|
1238
|
+
for (const [k, v] of hookHeaders.entries()) {
|
|
1239
|
+
if (k.toLowerCase() === "set-cookie") continue;
|
|
1240
|
+
if (!merged.has(k)) merged.set(k, v);
|
|
1241
|
+
}
|
|
1242
|
+
for (const sc of hookHeaders.getSetCookie()) {
|
|
1243
|
+
merged.append("Set-Cookie", sc);
|
|
1244
|
+
}
|
|
1245
|
+
return new Response(response.body, {
|
|
1246
|
+
status: response.status,
|
|
1247
|
+
statusText: response.statusText,
|
|
1248
|
+
headers: merged
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
function methodNotAllowedResponse(method) {
|
|
1252
|
+
const envelope = {
|
|
1253
|
+
code: "METHOD_NOT_ALLOWED",
|
|
1254
|
+
message: `Method ${method} not allowed`
|
|
1255
|
+
};
|
|
1256
|
+
return new Response(JSON.stringify(envelope), {
|
|
1257
|
+
status: 405,
|
|
1258
|
+
headers: { "content-type": "application/json" }
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
function csrfFailedResponse(reason) {
|
|
1262
|
+
const envelope = {
|
|
1263
|
+
code: "FORBIDDEN",
|
|
1264
|
+
message: `CSRF check failed: ${reason}`
|
|
1265
|
+
};
|
|
1266
|
+
return new Response(JSON.stringify(envelope), {
|
|
1267
|
+
status: 403,
|
|
1268
|
+
headers: { "content-type": "application/json" }
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
async function executeWebRequest(request, routeModule, opts = {}) {
|
|
1272
|
+
const method = request.method.toUpperCase();
|
|
1273
|
+
const config = routeModule[method];
|
|
1274
|
+
if (opts.hooks === void 0) {
|
|
1275
|
+
if (config === void 0 || typeof config.handler !== "function") {
|
|
1276
|
+
return methodNotAllowedResponse(method);
|
|
1277
|
+
}
|
|
1278
|
+
if (opts.csrfMode === "strict" && CSRF_PROTECTED_METHODS.has(method)) {
|
|
1279
|
+
const csrfCheck = validateCsrfRequest(request);
|
|
1280
|
+
if (!csrfCheck.valid) return csrfFailedResponse(csrfCheck.reason);
|
|
1281
|
+
}
|
|
1282
|
+
try {
|
|
1283
|
+
const outcome = await runHandler(config, request, opts.bodyParser ?? "inline");
|
|
1284
|
+
if (!outcome.ok) return outcome.response;
|
|
1285
|
+
return toResponse(outcome.result);
|
|
1286
|
+
} catch (err) {
|
|
1287
|
+
return handlerErrorResponse(err);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
return runWithHooks(request, config, opts, opts.hooks);
|
|
1291
|
+
}
|
|
1292
|
+
async function runPreHandlerPipeline(hookCtx, request, config, opts, hooks) {
|
|
1293
|
+
const method = request.method.toUpperCase();
|
|
1294
|
+
const runList = async (list) => {
|
|
1295
|
+
for (const hook of list) {
|
|
1296
|
+
if (hookCtx.response !== void 0) return;
|
|
1297
|
+
await hook(hookCtx);
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
if (hooks.onRequest) await runList(hooks.onRequest);
|
|
1301
|
+
if (hookCtx.response === void 0 && opts.csrfMode === "strict" && CSRF_PROTECTED_METHODS.has(method)) {
|
|
1302
|
+
const csrfCheck = validateCsrfRequest(request);
|
|
1303
|
+
if (!csrfCheck.valid) hookCtx.response = csrfFailedResponse(csrfCheck.reason);
|
|
1304
|
+
}
|
|
1305
|
+
if (hookCtx.response === void 0 && hooks.preHandler) {
|
|
1306
|
+
await runList(hooks.preHandler);
|
|
1307
|
+
}
|
|
1308
|
+
if (hookCtx.response === void 0) {
|
|
1309
|
+
if (config === void 0 || typeof config.handler !== "function") {
|
|
1310
|
+
hookCtx.response = methodNotAllowedResponse(method);
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
const outcome = await runHandler(config, request, opts.bodyParser ?? "inline");
|
|
1314
|
+
hookCtx.response = outcome.ok ? toResponse(outcome.result) : outcome.response;
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
async function runWithHooks(request, config, opts, hooks) {
|
|
1318
|
+
const hookCtx = {
|
|
1319
|
+
request,
|
|
1320
|
+
responseHeaders: new Headers(),
|
|
1321
|
+
ctx: {},
|
|
1322
|
+
requestId: opts.requestId ?? globalThis.crypto.randomUUID()
|
|
1323
|
+
};
|
|
1324
|
+
try {
|
|
1325
|
+
await runPreHandlerPipeline(hookCtx, request, config, opts, hooks);
|
|
1326
|
+
if (hooks.onResponse) {
|
|
1327
|
+
for (const hook of hooks.onResponse) {
|
|
1328
|
+
await hook(hookCtx);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
const finalResponse = hookCtx.response ?? new Response(
|
|
1332
|
+
JSON.stringify({ code: "INTERNAL_SERVER_ERROR", message: "No response built" }),
|
|
1333
|
+
{
|
|
1334
|
+
status: 500,
|
|
1335
|
+
headers: { "content-type": "application/json" }
|
|
1336
|
+
}
|
|
1337
|
+
);
|
|
1338
|
+
return mergeHookHeaders(finalResponse, hookCtx.responseHeaders);
|
|
1339
|
+
} catch (err) {
|
|
1340
|
+
return runErrorHooks(err, hookCtx, hooks.onError);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
async function runErrorHooks(err, hookCtx, onError) {
|
|
1344
|
+
const errorResponse = handlerErrorResponse(err);
|
|
1345
|
+
if (onError !== void 0) {
|
|
1346
|
+
const errorCtx = {
|
|
1347
|
+
...hookCtx,
|
|
1348
|
+
response: errorResponse,
|
|
1349
|
+
error: err
|
|
1350
|
+
};
|
|
1351
|
+
for (const hook of onError) {
|
|
1352
|
+
try {
|
|
1353
|
+
await hook(errorCtx);
|
|
1354
|
+
} catch {
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
return mergeHookHeaders(errorResponse, hookCtx.responseHeaders);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1943
1361
|
// src/server/plugin-types.ts
|
|
1944
1362
|
function definePlugin(plugin) {
|
|
1945
1363
|
return plugin;
|
|
1946
1364
|
}
|
|
1365
|
+
|
|
1366
|
+
// src/server/index.ts
|
|
1367
|
+
if (typeof globalThis !== "undefined") {
|
|
1368
|
+
const WARN_KEY = "__theokit_server_umbrella_warn_emitted__";
|
|
1369
|
+
const g = globalThis;
|
|
1370
|
+
if (g[WARN_KEY] !== true) {
|
|
1371
|
+
g[WARN_KEY] = true;
|
|
1372
|
+
console.warn(
|
|
1373
|
+
'[theokit] umbrella import "theokit/server" is DEPRECATED. Use sub-paths (theokit/server/<domain>): auth, jobs, http, security, observability, etc. See packages/theo/package.json#exports for the full list. Removal scheduled for 0.x+2.'
|
|
1374
|
+
);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1947
1377
|
export {
|
|
1948
1378
|
ActionError,
|
|
1949
1379
|
ActionInputError,
|
|
@@ -1964,6 +1394,7 @@ export {
|
|
|
1964
1394
|
CSRF_WARN_CODE,
|
|
1965
1395
|
CSRF_WARN_DOCS_URL,
|
|
1966
1396
|
ChannelManager,
|
|
1397
|
+
ConsoleObservabilityAdapter,
|
|
1967
1398
|
CsrfReadinessStore,
|
|
1968
1399
|
DEFAULT_CSP,
|
|
1969
1400
|
DEFAULT_EXCLUDED_QUERY_PARAMS,
|
|
@@ -1985,21 +1416,26 @@ export {
|
|
|
1985
1416
|
JsonStdoutSink,
|
|
1986
1417
|
MAX_ERROR_HTML_BYTES,
|
|
1987
1418
|
NonRetryableError,
|
|
1419
|
+
NoopObservabilityAdapter,
|
|
1420
|
+
NoopSpan,
|
|
1988
1421
|
PluginRunner,
|
|
1989
1422
|
PostgresJobBackend,
|
|
1990
1423
|
STRIPPED_HEADERS,
|
|
1424
|
+
SpanImpl,
|
|
1991
1425
|
StorageManager,
|
|
1992
1426
|
THEO_T_PREFIX,
|
|
1993
1427
|
TRACE_HEADER,
|
|
1994
1428
|
TRACE_PARENT_HEADER,
|
|
1429
|
+
TheoCloudObservabilityAdapter,
|
|
1995
1430
|
__resetSdkForTests,
|
|
1996
|
-
__resetSingletonForTests,
|
|
1997
1431
|
__setSdkForTests,
|
|
1998
1432
|
_resetCacheEngine,
|
|
1999
1433
|
_resetEnvCache,
|
|
2000
1434
|
_resetKeyCacheForTests,
|
|
2001
1435
|
_resetMiddlewareCacheForTests,
|
|
2002
1436
|
_resetWarnOnceForTests,
|
|
1437
|
+
appendCookieToHeaders,
|
|
1438
|
+
appendDeleteCookieToHeaders,
|
|
2003
1439
|
applySecurityHeaders,
|
|
2004
1440
|
assertProductionSecret,
|
|
2005
1441
|
buildCronManifest,
|
|
@@ -2013,18 +1449,24 @@ export {
|
|
|
2013
1449
|
createCacheEngine,
|
|
2014
1450
|
createConversationHistory,
|
|
2015
1451
|
createCorsHandler,
|
|
1452
|
+
createCorsWebHandler,
|
|
2016
1453
|
createCronScheduler,
|
|
2017
1454
|
createJobRunner,
|
|
2018
1455
|
createLogger,
|
|
2019
1456
|
createNoOpLogger,
|
|
1457
|
+
createObservabilityPlugin,
|
|
1458
|
+
createOpenApiHandler,
|
|
2020
1459
|
createOutbox,
|
|
2021
1460
|
createOutboxDispatcher,
|
|
2022
1461
|
createPluginRunnerFromConfig,
|
|
2023
1462
|
createProductionLoader,
|
|
2024
1463
|
createQueueClient,
|
|
2025
1464
|
createRateLimiter,
|
|
1465
|
+
createRateLimiterWeb,
|
|
2026
1466
|
createRouteRateLimiter,
|
|
1467
|
+
createRouteRateLimiterWeb,
|
|
2027
1468
|
createSessionManager,
|
|
1469
|
+
createSessionManagerWeb,
|
|
2028
1470
|
createViteLoader,
|
|
2029
1471
|
decrypt,
|
|
2030
1472
|
defineAction,
|
|
@@ -2036,14 +1478,18 @@ export {
|
|
|
2036
1478
|
defineCron,
|
|
2037
1479
|
defineJob,
|
|
2038
1480
|
defineMiddleware,
|
|
1481
|
+
defineObservabilityAdapter,
|
|
2039
1482
|
definePlugin,
|
|
2040
1483
|
defineRoute,
|
|
2041
1484
|
defineTheoPlugin,
|
|
1485
|
+
defineWebChannel,
|
|
2042
1486
|
defineWebSocket,
|
|
1487
|
+
defineWebSocketWeb,
|
|
2043
1488
|
defineWebhook,
|
|
2044
1489
|
deleteCookie,
|
|
2045
1490
|
deriveKey2 as deriveCacheKey,
|
|
2046
1491
|
deriveKey,
|
|
1492
|
+
deriveKeyFromRequest,
|
|
2047
1493
|
deserializeResponse,
|
|
2048
1494
|
discoverOidcProvider,
|
|
2049
1495
|
dispatchWebhook,
|
|
@@ -2052,7 +1498,9 @@ export {
|
|
|
2052
1498
|
errorToEvent,
|
|
2053
1499
|
executeAction,
|
|
2054
1500
|
executeRoute,
|
|
1501
|
+
executeWebRequest,
|
|
2055
1502
|
extractTraceId,
|
|
1503
|
+
extractTraceIdFromRequest,
|
|
2056
1504
|
extractUniversalIssues,
|
|
2057
1505
|
findSuggestion,
|
|
2058
1506
|
generateBackupCodes,
|
|
@@ -2065,10 +1513,13 @@ export {
|
|
|
2065
1513
|
getCacheControlHeader,
|
|
2066
1514
|
getCacheEngine,
|
|
2067
1515
|
getCookie,
|
|
1516
|
+
getCookieFromRequest,
|
|
2068
1517
|
getStorageManager,
|
|
2069
1518
|
handleBatchRequest,
|
|
2070
1519
|
handleCspReport,
|
|
1520
|
+
handleCspReportRequest,
|
|
2071
1521
|
handleCsrfReadiness,
|
|
1522
|
+
handleCsrfReadinessRequest,
|
|
2072
1523
|
initCacheEngine,
|
|
2073
1524
|
isActionError,
|
|
2074
1525
|
isInputError,
|
|
@@ -2091,11 +1542,13 @@ export {
|
|
|
2091
1542
|
readRawBody,
|
|
2092
1543
|
recordAttempt,
|
|
2093
1544
|
requireAuth,
|
|
1545
|
+
resolveAdapter,
|
|
2094
1546
|
resolveRouteRule,
|
|
2095
1547
|
resolveTransformer,
|
|
2096
1548
|
revalidatePath,
|
|
2097
1549
|
revalidateTag,
|
|
2098
1550
|
rotateIfNeeded,
|
|
1551
|
+
rotateIfNeededWeb,
|
|
2099
1552
|
runMiddlewareAndContext,
|
|
2100
1553
|
safeAudit,
|
|
2101
1554
|
scanCrons,
|
|
@@ -2107,7 +1560,9 @@ export {
|
|
|
2107
1560
|
scanWebSocketRoutes,
|
|
2108
1561
|
sendError,
|
|
2109
1562
|
sendJson,
|
|
1563
|
+
serializeCookie,
|
|
2110
1564
|
serializeResponse,
|
|
1565
|
+
serializeSpansToOtlp,
|
|
2111
1566
|
serveStaticFile,
|
|
2112
1567
|
setCookie,
|
|
2113
1568
|
streamAgentRun,
|
|
@@ -2128,6 +1583,7 @@ export {
|
|
|
2128
1583
|
validateTags as validateCacheTags,
|
|
2129
1584
|
validateCronSchedule,
|
|
2130
1585
|
validateCsrf,
|
|
1586
|
+
validateCsrfRequest,
|
|
2131
1587
|
verifyBackupCode,
|
|
2132
1588
|
verifyOAuthState,
|
|
2133
1589
|
verifyTotp,
|