theokit 0.2.4 → 0.4.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-6GC6VWXS.js → app-typed-client-OUJO3V5J.js} +10 -5
- package/dist/{app-typed-client-6GC6VWXS.js.map → app-typed-client-OUJO3V5J.js.map} +1 -1
- package/dist/{app-typed-client-US2ZXBEC.js → app-typed-client-YOMWSA3F.js} +11 -6
- package/dist/{app-typed-client-US2ZXBEC.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-MREW6MVS.js → build-D4J7XECU.js} +33 -24
- 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-5OKZY2VL.js → chunk-2F4FROEQ.js} +1695 -1522
- 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-X2OLD264.js → chunk-M2EY7KDR.js} +1228 -1124
- package/dist/chunk-M2EY7KDR.js.map +1 -0
- package/dist/{chunk-YWWHK7R6.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-2BQYEBCK.js → chunk-OLPB36O2.js} +87 -5
- package/dist/chunk-OLPB36O2.js.map +1 -0
- 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-SNDZQ64K.js → chunk-VBZCVFSA.js} +85 -3
- package/dist/chunk-VBZCVFSA.js.map +1 -0
- package/dist/chunk-VMEWD57H.js +137 -0
- package/dist/chunk-VMEWD57H.js.map +1 -0
- package/dist/{chunk-BE2LKDI7.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 +44 -9
- 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-6P2DM33Q.js → dev-MJVSRZGF.js} +13 -13
- package/dist/{dev-emit-MLDFOLUU.js → dev-emit-5VPRCHOD.js} +39 -142
- package/dist/dev-emit-5VPRCHOD.js.map +1 -0
- package/dist/{dev-emit-PRSRPDHA.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-E6BL4ZVY.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-SOKZTFE3.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 +274 -0
- package/dist/router-RGZFX75G.js.map +1 -0
- package/dist/{routes-XVRAUH6H.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 +44 -0
- package/dist/server-routes-hmr-GZJGPWMS.js.map +1 -0
- package/dist/server-routes-hmr-PBHSKCQJ.js +42 -0
- package/dist/server-routes-hmr-PBHSKCQJ.js.map +1 -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-R7XSQL5L.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-6MPHTKIW.js → vite-plugin-CR4JDFUQ.js} +9 -9
- package/dist/vite-plugin-CR4JDFUQ.js.map +1 -0
- package/package.json +59 -10
- package/LICENSE +0 -201
- package/dist/build-MREW6MVS.js.map +0 -1
- package/dist/chunk-2BQYEBCK.js.map +0 -1
- package/dist/chunk-5OFPQK6N.js.map +0 -1
- package/dist/chunk-5OKZY2VL.js.map +0 -1
- package/dist/chunk-64JI5LTO.js.map +0 -1
- package/dist/chunk-7TOMTMHT.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-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-SNDZQ64K.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-X2OLD264.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-MLDFOLUU.js.map +0 -1
- package/dist/dispatcher-E6QV32BO.js.map +0 -1
- package/dist/dist-E6BL4ZVY.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-5QFTLOL2.js +0 -25
- package/dist/schema-CjVly9c_.d.ts +0 -274
- package/dist/sqlite-vec-ARPNUBWT.js.map +0 -1
- package/dist/start-R7XSQL5L.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-YWWHK7R6.js.map → chunk-MR7OLIC6.js.map} +0 -0
- /package/dist/{scan-C2BOKLSY.js.map → chunk-NPMCKOX4.js.map} +0 -0
- /package/dist/{chunk-BE2LKDI7.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-6P2DM33Q.js.map → dev-MJVSRZGF.js.map} +0 -0
- /package/dist/{dev-emit-PRSRPDHA.js.map → dev-emit-HHP2XJXE.js.map} +0 -0
- /package/dist/{vite-plugin-6MPHTKIW.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-SOKZTFE3.js.map → openapi-NFLSNNVQ.js.map} +0 -0
- /package/dist/{registry-5QFTLOL2.js.map → registry-QHEZ3BWB.js.map} +0 -0
- /package/dist/{routes-XVRAUH6H.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
|
@@ -1,135 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "tsx/esm";
|
|
3
3
|
|
|
4
|
-
// src/server/scan/module-loader.ts
|
|
5
|
-
import { pathToFileURL } from "url";
|
|
6
|
-
function createViteLoader(vite) {
|
|
7
|
-
return (path) => vite.ssrLoadModule(path);
|
|
8
|
-
}
|
|
9
|
-
function createProductionLoader() {
|
|
10
|
-
return async (path) => {
|
|
11
|
-
const url = pathToFileURL(path).href;
|
|
12
|
-
return import(url);
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// src/server/rate-limit/rate-limit-store.ts
|
|
17
|
-
var InMemoryStore = class _InMemoryStore {
|
|
18
|
-
store = /* @__PURE__ */ new Map();
|
|
19
|
-
/** Bound the map to prevent unbounded growth from pathological inputs. */
|
|
20
|
-
static MAX_ENTRIES = 1e5;
|
|
21
|
-
/** GC sweep interval, milliseconds. */
|
|
22
|
-
static GC_INTERVAL_MS = 3e4;
|
|
23
|
-
gcTimer = null;
|
|
24
|
-
constructor() {
|
|
25
|
-
if (typeof setInterval !== "undefined") {
|
|
26
|
-
const timer = setInterval(() => {
|
|
27
|
-
this.sweepExpired();
|
|
28
|
-
}, _InMemoryStore.GC_INTERVAL_MS);
|
|
29
|
-
this.gcTimer = timer;
|
|
30
|
-
const maybeUnref = timer.unref;
|
|
31
|
-
if (typeof maybeUnref === "function") maybeUnref.call(timer);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Synchronous fast-path used by the legacy sync `createRateLimiter`
|
|
36
|
-
* surface (`api-middleware.ts` is sync). The async `incr` delegates to
|
|
37
|
-
* this for in-memory; external adapters override `incr` directly.
|
|
38
|
-
*/
|
|
39
|
-
incrSync(key, windowMs) {
|
|
40
|
-
if (!Number.isFinite(windowMs) || windowMs <= 0) {
|
|
41
|
-
throw new Error(
|
|
42
|
-
`InMemoryStore.incr: windowMs must be a positive finite number (got ${windowMs})`
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
const now = Date.now();
|
|
46
|
-
if (this.store.size >= _InMemoryStore.MAX_ENTRIES) {
|
|
47
|
-
const first = this.store.keys().next().value;
|
|
48
|
-
if (first !== void 0) this.store.delete(first);
|
|
49
|
-
}
|
|
50
|
-
const entry = this.store.get(key);
|
|
51
|
-
if (!entry || now >= entry.resetAt) {
|
|
52
|
-
const fresh = { count: 1, resetAt: now + windowMs };
|
|
53
|
-
this.store.set(key, fresh);
|
|
54
|
-
return { ...fresh };
|
|
55
|
-
}
|
|
56
|
-
entry.count++;
|
|
57
|
-
return { count: entry.count, resetAt: entry.resetAt };
|
|
58
|
-
}
|
|
59
|
-
/** Sweep expired entries. Called by the GC timer; safe to call manually. */
|
|
60
|
-
sweepExpired() {
|
|
61
|
-
const now = Date.now();
|
|
62
|
-
for (const [k, v] of this.store) {
|
|
63
|
-
if (v.resetAt <= now) this.store.delete(k);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Stop the GC timer. Call from tests or when discarding the store. After
|
|
68
|
-
* `dispose`, the store still works but no longer auto-sweeps.
|
|
69
|
-
*/
|
|
70
|
-
dispose() {
|
|
71
|
-
if (this.gcTimer) {
|
|
72
|
-
clearInterval(this.gcTimer);
|
|
73
|
-
this.gcTimer = null;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
// The async surface is required by the `RateLimitStore` interface
|
|
77
|
-
// (Redis/etc. adapters are inherently async). For the in-memory case
|
|
78
|
-
// we just adapt the sync implementations to Promises.
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/require-await -- interface contract: async return
|
|
80
|
-
async incr(key, windowMs) {
|
|
81
|
-
return this.incrSync(key, windowMs);
|
|
82
|
-
}
|
|
83
|
-
// eslint-disable-next-line @typescript-eslint/require-await -- interface contract: async return
|
|
84
|
-
async get(key) {
|
|
85
|
-
const now = Date.now();
|
|
86
|
-
const entry = this.store.get(key);
|
|
87
|
-
if (!entry) return null;
|
|
88
|
-
if (now >= entry.resetAt) return null;
|
|
89
|
-
return { count: entry.count, resetAt: entry.resetAt };
|
|
90
|
-
}
|
|
91
|
-
// eslint-disable-next-line @typescript-eslint/require-await -- interface contract: async return
|
|
92
|
-
async reset(key) {
|
|
93
|
-
this.store.delete(key);
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// src/server/rate-limit/rate-limit.ts
|
|
98
|
-
function createRateLimiter(config, opts = {}) {
|
|
99
|
-
const store = opts.store ?? new InMemoryStore();
|
|
100
|
-
const isInMemory = store instanceof InMemoryStore;
|
|
101
|
-
return function checkRateLimit(req) {
|
|
102
|
-
const key = req.socket?.remoteAddress ?? "unknown";
|
|
103
|
-
if (isInMemory) {
|
|
104
|
-
const state = store.incrSync(key, config.windowMs);
|
|
105
|
-
return resultFromState(state, config);
|
|
106
|
-
}
|
|
107
|
-
throw new Error(
|
|
108
|
-
"createRateLimiter: async RateLimitStore implementations are not supported by this sync fa\xE7ade. Use the InMemoryStore default or build a custom middleware around the async store directly."
|
|
109
|
-
);
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
function resultFromState(state, config) {
|
|
113
|
-
if (state.count > config.max) {
|
|
114
|
-
const retryAfter = Math.ceil((state.resetAt - Date.now()) / 1e3);
|
|
115
|
-
return {
|
|
116
|
-
limited: true,
|
|
117
|
-
headers: {
|
|
118
|
-
"X-RateLimit-Limit": String(config.max),
|
|
119
|
-
"X-RateLimit-Remaining": "0",
|
|
120
|
-
"Retry-After": String(retryAfter)
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
return {
|
|
125
|
-
limited: false,
|
|
126
|
-
headers: {
|
|
127
|
-
"X-RateLimit-Limit": String(config.max),
|
|
128
|
-
"X-RateLimit-Remaining": String(Math.max(0, config.max - state.count))
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
4
|
// src/server/plugins/plugin-runner.ts
|
|
134
5
|
var DuplicatePluginError = class extends Error {
|
|
135
6
|
constructor(name) {
|
|
@@ -137,66 +8,156 @@ var DuplicatePluginError = class extends Error {
|
|
|
137
8
|
this.name = "DuplicatePluginError";
|
|
138
9
|
}
|
|
139
10
|
};
|
|
140
|
-
var DuplicateDecorationError = class extends Error {
|
|
141
|
-
constructor(key, existingPlugin, newPlugin) {
|
|
142
|
-
super(
|
|
143
|
-
`Plugin "${newPlugin}" tried to decorate ctx.${key}, but it is already declared by plugin "${existingPlugin}".`
|
|
144
|
-
);
|
|
145
|
-
this.name = "DuplicateDecorationError";
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
11
|
var PluginRunner = class {
|
|
149
12
|
plugins = /* @__PURE__ */ new Set();
|
|
13
|
+
pluginScopes = /* @__PURE__ */ new Map();
|
|
150
14
|
onRequestHooks = [];
|
|
151
15
|
preHandlerHooks = [];
|
|
152
16
|
onResponseHooks = [];
|
|
153
17
|
onErrorHooks = [];
|
|
154
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Parent app — proto-chain root for all child scopes. Has its OWN empty
|
|
20
|
+
* decorations map (parent never receives `decorateRequest` calls under
|
|
21
|
+
* the T3.1 contract; only child scopes do).
|
|
22
|
+
*/
|
|
23
|
+
parentDecorations = /* @__PURE__ */ new Map();
|
|
24
|
+
parentApp = this.buildParentAppFacade();
|
|
155
25
|
has(name) {
|
|
156
26
|
return this.plugins.has(name);
|
|
157
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Per T3.1 (C1 plugin scope encapsulation):
|
|
30
|
+
* 1. Reserve the plugin name (still rejects duplicates).
|
|
31
|
+
* 2. Build a CHILD TheoApp via `Object.create(parentApp)` — Fastify
|
|
32
|
+
* `plugin-override.js:38` pattern. The child's own `decorateRequest`
|
|
33
|
+
* populates per-scope `decorations`; the child's `addHook` still
|
|
34
|
+
* forwards into the shared hook lists (hooks ARE process-global —
|
|
35
|
+
* only decorations are scoped, mirroring Fastify's decoration vs
|
|
36
|
+
* hook semantics).
|
|
37
|
+
* 3. Invoke `plugin.register(childApp)`.
|
|
38
|
+
*
|
|
39
|
+
* Cross-plugin decoration-key collisions are PERMITTED (per blueprint
|
|
40
|
+
* D1). The legacy `DuplicateDecorationError` is no longer thrown.
|
|
41
|
+
*/
|
|
158
42
|
async register(plugin) {
|
|
159
43
|
if (this.plugins.has(plugin.name)) {
|
|
160
44
|
throw new DuplicatePluginError(plugin.name);
|
|
161
45
|
}
|
|
162
46
|
this.plugins.add(plugin.name);
|
|
163
|
-
const
|
|
47
|
+
const scope = this.buildPluginScope(plugin.name);
|
|
48
|
+
this.pluginScopes.set(plugin.name, scope);
|
|
49
|
+
try {
|
|
50
|
+
await plugin.register(scope.app);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
this.plugins.delete(plugin.name);
|
|
53
|
+
this.pluginScopes.delete(plugin.name);
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Build the parent app facade. Hooks forward to shared lists.
|
|
59
|
+
* `decorateRequest` writes into the parent decorations map — used only
|
|
60
|
+
* if a future consumer registers a non-plugin "app-level" decoration
|
|
61
|
+
* directly. T3.1 contract: plugins decorate ONLY through child scopes.
|
|
62
|
+
*/
|
|
63
|
+
buildParentAppFacade() {
|
|
64
|
+
const facade = {
|
|
164
65
|
addHook: (name, fn) => {
|
|
165
|
-
|
|
166
|
-
case "onRequest":
|
|
167
|
-
this.onRequestHooks.push(fn);
|
|
168
|
-
return;
|
|
169
|
-
case "preHandler":
|
|
170
|
-
this.preHandlerHooks.push(fn);
|
|
171
|
-
return;
|
|
172
|
-
case "onResponse":
|
|
173
|
-
this.onResponseHooks.push(fn);
|
|
174
|
-
return;
|
|
175
|
-
case "onError":
|
|
176
|
-
this.onErrorHooks.push(fn);
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
66
|
+
this.routeHookByName(name, fn);
|
|
179
67
|
},
|
|
180
|
-
// `T` lets call sites bind a stronger value type via the plugin API.
|
|
181
|
-
// The runtime body stores `value` without inspection, so T appears
|
|
182
|
-
// only on the parameter — that is the intended contract.
|
|
183
68
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- T documents the per-decoration type for consumers
|
|
184
69
|
decorateRequest: (key, value) => {
|
|
185
|
-
|
|
186
|
-
if (existing) {
|
|
187
|
-
this.plugins.delete(plugin.name);
|
|
188
|
-
throw new DuplicateDecorationError(key, existing.pluginName, plugin.name);
|
|
189
|
-
}
|
|
190
|
-
this.decorations.set(key, { pluginName: plugin.name, value });
|
|
70
|
+
this.parentDecorations.set(key, value);
|
|
191
71
|
}
|
|
192
72
|
};
|
|
193
|
-
|
|
73
|
+
return facade;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Build a child scope via `Object.create(parentApp)` so the child
|
|
77
|
+
* inherits the parent's facade methods through the prototype chain.
|
|
78
|
+
* Then override `decorateRequest` on the child instance so writes
|
|
79
|
+
* land in the per-scope `decorations` map (parent is NOT mutated).
|
|
80
|
+
*/
|
|
81
|
+
buildPluginScope(_pluginName) {
|
|
82
|
+
const decorations = /* @__PURE__ */ new Map();
|
|
83
|
+
const childApp = Object.create(this.parentApp);
|
|
84
|
+
Object.defineProperty(childApp, "decorateRequest", {
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- T documents the per-decoration type for consumers
|
|
86
|
+
value: (key, value) => {
|
|
87
|
+
if (typeof key !== "string") {
|
|
88
|
+
throw new TypeError(
|
|
89
|
+
`decorateRequest: invalid key (expected string, got ${typeof key}). Plugin authors MUST pass string keys.`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
decorations.set(key, value);
|
|
93
|
+
},
|
|
94
|
+
enumerable: false,
|
|
95
|
+
writable: false,
|
|
96
|
+
configurable: false
|
|
97
|
+
});
|
|
98
|
+
Object.defineProperty(childApp, "decorations", {
|
|
99
|
+
get: () => Object.fromEntries(decorations),
|
|
100
|
+
enumerable: false,
|
|
101
|
+
configurable: false
|
|
102
|
+
});
|
|
103
|
+
return { app: childApp, decorations };
|
|
104
|
+
}
|
|
105
|
+
routeHookByName(name, fn) {
|
|
106
|
+
switch (name) {
|
|
107
|
+
case "onRequest":
|
|
108
|
+
this.onRequestHooks.push(fn);
|
|
109
|
+
return;
|
|
110
|
+
case "preHandler":
|
|
111
|
+
this.preHandlerHooks.push(fn);
|
|
112
|
+
return;
|
|
113
|
+
case "onResponse":
|
|
114
|
+
this.onResponseHooks.push(fn);
|
|
115
|
+
return;
|
|
116
|
+
case "onError":
|
|
117
|
+
this.onErrorHooks.push(fn);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
194
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Apply ALL plugin scopes' decorations into the request ctx. Per T3.1,
|
|
123
|
+
* sibling plugins MAY decorate the same key — last-writer-wins at apply
|
|
124
|
+
* time (ordering = registration order). This keeps the legacy
|
|
125
|
+
* `ctx.<key>` flat surface working for consumers that already aggregate
|
|
126
|
+
* decorations into a single bag.
|
|
127
|
+
*/
|
|
195
128
|
applyDecorations(ctx) {
|
|
196
|
-
for (const
|
|
197
|
-
|
|
129
|
+
for (const scope of this.pluginScopes.values()) {
|
|
130
|
+
for (const [key, value] of scope.decorations.entries()) {
|
|
131
|
+
ctx[key] = value;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Apply ONLY one plugin's scoped decorations into `target`. Used by
|
|
137
|
+
* the T1.1 RED-3 test (sibling isolation proof) and by future scope-aware
|
|
138
|
+
* dispatch paths. Throws if the plugin name isn't registered.
|
|
139
|
+
*/
|
|
140
|
+
applyScopedDecorations(pluginName, target) {
|
|
141
|
+
const scope = this.pluginScopes.get(pluginName);
|
|
142
|
+
if (!scope) throw new Error(`PluginRunner: unknown plugin "${pluginName}"`);
|
|
143
|
+
for (const [key, value] of scope.decorations.entries()) {
|
|
144
|
+
target[key] = value;
|
|
198
145
|
}
|
|
199
146
|
}
|
|
147
|
+
/** T1.1 RED-1/RED-4 introspection: returns the child TheoApp built for `pluginName`. */
|
|
148
|
+
getPluginScope(pluginName) {
|
|
149
|
+
const scope = this.pluginScopes.get(pluginName);
|
|
150
|
+
if (!scope) throw new Error(`PluginRunner: unknown plugin "${pluginName}"`);
|
|
151
|
+
return scope.app;
|
|
152
|
+
}
|
|
153
|
+
/** T1.1 RED-4: returns the parent TheoApp (root of every child's proto chain). */
|
|
154
|
+
getParentApp() {
|
|
155
|
+
return this.parentApp;
|
|
156
|
+
}
|
|
157
|
+
/** T1.1 RED-2: returns the parent's decorations map (NEVER touched by plugin decorate calls under T3.1 contract). */
|
|
158
|
+
getParentDecorations() {
|
|
159
|
+
return this.parentDecorations;
|
|
160
|
+
}
|
|
200
161
|
async runOnRequest(ctx) {
|
|
201
162
|
return this.runHookList(this.onRequestHooks, ctx);
|
|
202
163
|
}
|
|
@@ -317,6 +278,135 @@ function resolveTransformer(selector) {
|
|
|
317
278
|
return selector;
|
|
318
279
|
}
|
|
319
280
|
|
|
281
|
+
// src/server/scan/module-loader.ts
|
|
282
|
+
import { pathToFileURL } from "url";
|
|
283
|
+
function createViteLoader(vite) {
|
|
284
|
+
return (path) => vite.ssrLoadModule(path);
|
|
285
|
+
}
|
|
286
|
+
function createProductionLoader() {
|
|
287
|
+
return async (path) => {
|
|
288
|
+
const url = pathToFileURL(path).href;
|
|
289
|
+
return import(url);
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/server/rate-limit/rate-limit-store.ts
|
|
294
|
+
var InMemoryStore = class _InMemoryStore {
|
|
295
|
+
store = /* @__PURE__ */ new Map();
|
|
296
|
+
/** Bound the map to prevent unbounded growth from pathological inputs. */
|
|
297
|
+
static MAX_ENTRIES = 1e5;
|
|
298
|
+
/** GC sweep interval, milliseconds. */
|
|
299
|
+
static GC_INTERVAL_MS = 3e4;
|
|
300
|
+
gcTimer = null;
|
|
301
|
+
constructor() {
|
|
302
|
+
if (typeof setInterval !== "undefined") {
|
|
303
|
+
const timer = setInterval(() => {
|
|
304
|
+
this.sweepExpired();
|
|
305
|
+
}, _InMemoryStore.GC_INTERVAL_MS);
|
|
306
|
+
this.gcTimer = timer;
|
|
307
|
+
const maybeUnref = timer.unref;
|
|
308
|
+
if (typeof maybeUnref === "function") maybeUnref.call(timer);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Synchronous fast-path used by the legacy sync `createRateLimiter`
|
|
313
|
+
* surface (`api-middleware.ts` is sync). The async `incr` delegates to
|
|
314
|
+
* this for in-memory; external adapters override `incr` directly.
|
|
315
|
+
*/
|
|
316
|
+
incrSync(key, windowMs) {
|
|
317
|
+
if (!Number.isFinite(windowMs) || windowMs <= 0) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
`InMemoryStore.incr: windowMs must be a positive finite number (got ${windowMs})`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
const now = Date.now();
|
|
323
|
+
if (this.store.size >= _InMemoryStore.MAX_ENTRIES) {
|
|
324
|
+
const first = this.store.keys().next().value;
|
|
325
|
+
if (first !== void 0) this.store.delete(first);
|
|
326
|
+
}
|
|
327
|
+
const entry = this.store.get(key);
|
|
328
|
+
if (!entry || now >= entry.resetAt) {
|
|
329
|
+
const fresh = { count: 1, resetAt: now + windowMs };
|
|
330
|
+
this.store.set(key, fresh);
|
|
331
|
+
return { ...fresh };
|
|
332
|
+
}
|
|
333
|
+
entry.count++;
|
|
334
|
+
return { count: entry.count, resetAt: entry.resetAt };
|
|
335
|
+
}
|
|
336
|
+
/** Sweep expired entries. Called by the GC timer; safe to call manually. */
|
|
337
|
+
sweepExpired() {
|
|
338
|
+
const now = Date.now();
|
|
339
|
+
for (const [k, v] of this.store) {
|
|
340
|
+
if (v.resetAt <= now) this.store.delete(k);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Stop the GC timer. Call from tests or when discarding the store. After
|
|
345
|
+
* `dispose`, the store still works but no longer auto-sweeps.
|
|
346
|
+
*/
|
|
347
|
+
dispose() {
|
|
348
|
+
if (this.gcTimer) {
|
|
349
|
+
clearInterval(this.gcTimer);
|
|
350
|
+
this.gcTimer = null;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// The async surface is required by the `RateLimitStore` interface
|
|
354
|
+
// (Redis/etc. adapters are inherently async). For the in-memory case
|
|
355
|
+
// we just adapt the sync implementations to Promises.
|
|
356
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- interface contract: async return
|
|
357
|
+
async incr(key, windowMs) {
|
|
358
|
+
return this.incrSync(key, windowMs);
|
|
359
|
+
}
|
|
360
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- interface contract: async return
|
|
361
|
+
async get(key) {
|
|
362
|
+
const now = Date.now();
|
|
363
|
+
const entry = this.store.get(key);
|
|
364
|
+
if (!entry) return null;
|
|
365
|
+
if (now >= entry.resetAt) return null;
|
|
366
|
+
return { count: entry.count, resetAt: entry.resetAt };
|
|
367
|
+
}
|
|
368
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- interface contract: async return
|
|
369
|
+
async reset(key) {
|
|
370
|
+
this.store.delete(key);
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
// src/server/rate-limit/rate-limit.ts
|
|
375
|
+
function createRateLimiter(config, opts = {}) {
|
|
376
|
+
const store = opts.store ?? new InMemoryStore();
|
|
377
|
+
const isInMemory = store instanceof InMemoryStore;
|
|
378
|
+
return function checkRateLimit(req) {
|
|
379
|
+
const key = req.socket?.remoteAddress ?? "unknown";
|
|
380
|
+
if (isInMemory) {
|
|
381
|
+
const state = store.incrSync(key, config.windowMs);
|
|
382
|
+
return resultFromState(state, config);
|
|
383
|
+
}
|
|
384
|
+
throw new Error(
|
|
385
|
+
"createRateLimiter: async RateLimitStore implementations are not supported by this sync fa\xE7ade. Use the InMemoryStore default or build a custom middleware around the async store directly."
|
|
386
|
+
);
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
function resultFromState(state, config) {
|
|
390
|
+
if (state.count > config.max) {
|
|
391
|
+
const retryAfter = Math.ceil((state.resetAt - Date.now()) / 1e3);
|
|
392
|
+
return {
|
|
393
|
+
limited: true,
|
|
394
|
+
headers: {
|
|
395
|
+
"X-RateLimit-Limit": String(config.max),
|
|
396
|
+
"X-RateLimit-Remaining": "0",
|
|
397
|
+
"Retry-After": String(retryAfter)
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
limited: false,
|
|
403
|
+
headers: {
|
|
404
|
+
"X-RateLimit-Limit": String(config.max),
|
|
405
|
+
"X-RateLimit-Remaining": String(Math.max(0, config.max - state.count))
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
320
410
|
// src/server/body-parser.ts
|
|
321
411
|
import { basename } from "path";
|
|
322
412
|
import Busboy from "busboy";
|
|
@@ -495,14 +585,7 @@ function logRequest(info, customLogger, req) {
|
|
|
495
585
|
function randomRequestId() {
|
|
496
586
|
return `req-${String(Date.now())}-${Math.random().toString(36).slice(2, 8)}`;
|
|
497
587
|
}
|
|
498
|
-
function
|
|
499
|
-
const headers = req?.headers ? Object.fromEntries(
|
|
500
|
-
Object.entries(req.headers).map(([k, v]) => [
|
|
501
|
-
k,
|
|
502
|
-
Array.isArray(v) ? v.join(", ") : v ?? ""
|
|
503
|
-
])
|
|
504
|
-
) : void 0;
|
|
505
|
-
const stashedBody = req ? req[DEVTOOLS_BODY_PREVIEW] : void 0;
|
|
588
|
+
function broadcastToDevtoolsCore(info, headers, stashedBody) {
|
|
506
589
|
void Promise.all([
|
|
507
590
|
import("./broadcast-QOQGUNNK.js"),
|
|
508
591
|
import("./build-request-body-preview-II2235E6.js")
|
|
@@ -526,6 +609,16 @@ function broadcastRequestToDevtools(info, req) {
|
|
|
526
609
|
}).catch(() => {
|
|
527
610
|
});
|
|
528
611
|
}
|
|
612
|
+
function broadcastRequestToDevtools(info, req) {
|
|
613
|
+
const headers = req?.headers ? Object.fromEntries(
|
|
614
|
+
Object.entries(req.headers).map(([k, v]) => [
|
|
615
|
+
k,
|
|
616
|
+
Array.isArray(v) ? v.join(", ") : v ?? ""
|
|
617
|
+
])
|
|
618
|
+
) : void 0;
|
|
619
|
+
const stashedBody = req ? req[DEVTOOLS_BODY_PREVIEW] : void 0;
|
|
620
|
+
broadcastToDevtoolsCore(info, headers, stashedBody);
|
|
621
|
+
}
|
|
529
622
|
|
|
530
623
|
// src/server/observability/logger.ts
|
|
531
624
|
var _warnOnceSeen = /* @__PURE__ */ new Set();
|
|
@@ -637,6 +730,88 @@ function sendError(res, codeOrInput, message, status, issues, requestId, options
|
|
|
637
730
|
);
|
|
638
731
|
}
|
|
639
732
|
|
|
733
|
+
// src/server/security/security-headers.ts
|
|
734
|
+
var DEFAULT_CSP = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss:; frame-ancestors 'none'; report-uri /__theo/csp-report";
|
|
735
|
+
var DEFAULT_PERMISSIONS_POLICY = "geolocation=(), camera=(), microphone=(), payment=(), usb=(), accelerometer=(), gyroscope=()";
|
|
736
|
+
var DEFAULT_HSTS = "max-age=31536000; includeSubDomains";
|
|
737
|
+
function applyNonceToCsp(policy, nonce) {
|
|
738
|
+
return policy.split(";").map((directive) => {
|
|
739
|
+
const trimmed = directive.trim();
|
|
740
|
+
if (!trimmed.startsWith("script-src")) return directive;
|
|
741
|
+
if (trimmed.includes("'unsafe-inline'")) {
|
|
742
|
+
return directive.replace("'unsafe-inline'", `'nonce-${nonce}'`);
|
|
743
|
+
}
|
|
744
|
+
return `${directive} 'nonce-${nonce}'`;
|
|
745
|
+
}).join(";");
|
|
746
|
+
}
|
|
747
|
+
function applyCsp(out, config, effectiveNonce) {
|
|
748
|
+
if (config.csp === false || config.cspMode === "off") return;
|
|
749
|
+
let policy = typeof config.csp === "string" ? config.csp : DEFAULT_CSP;
|
|
750
|
+
if (effectiveNonce) {
|
|
751
|
+
policy = applyNonceToCsp(policy, effectiveNonce);
|
|
752
|
+
}
|
|
753
|
+
const mode = config.cspMode ?? "enforce";
|
|
754
|
+
if (mode === "enforce") {
|
|
755
|
+
out["Content-Security-Policy"] = policy;
|
|
756
|
+
} else {
|
|
757
|
+
out["Content-Security-Policy-Report-Only"] = policy;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
function buildSecurityHeaders(config, env, options = {}) {
|
|
761
|
+
const out = {};
|
|
762
|
+
const effectiveNonce = options.prerender ? void 0 : options.nonce;
|
|
763
|
+
applyCsp(out, config, effectiveNonce);
|
|
764
|
+
out["X-Frame-Options"] = config.frameOptions ?? "DENY";
|
|
765
|
+
out["X-Content-Type-Options"] = config.contentTypeOptions ?? "nosniff";
|
|
766
|
+
out["Referrer-Policy"] = config.referrerPolicy ?? "strict-origin-when-cross-origin";
|
|
767
|
+
if (config.permissionsPolicy !== false) {
|
|
768
|
+
out["Permissions-Policy"] = typeof config.permissionsPolicy === "string" ? config.permissionsPolicy : DEFAULT_PERMISSIONS_POLICY;
|
|
769
|
+
}
|
|
770
|
+
if (env.production && config.hsts !== false) {
|
|
771
|
+
out["Strict-Transport-Security"] = typeof config.hsts === "string" ? config.hsts : DEFAULT_HSTS;
|
|
772
|
+
}
|
|
773
|
+
if (effectiveNonce) {
|
|
774
|
+
out["Cache-Control"] = "private, no-store";
|
|
775
|
+
}
|
|
776
|
+
return out;
|
|
777
|
+
}
|
|
778
|
+
function applySecurityHeaders(res, config, env, options = {}) {
|
|
779
|
+
const headers = buildSecurityHeaders(config, env, options);
|
|
780
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
781
|
+
res.setHeader(key, value);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/server/auth/nonce.ts
|
|
786
|
+
function bytesToBase64(bytes) {
|
|
787
|
+
if (typeof Buffer !== "undefined") {
|
|
788
|
+
return Buffer.from(bytes).toString("base64");
|
|
789
|
+
}
|
|
790
|
+
let binary = "";
|
|
791
|
+
for (const b of bytes) {
|
|
792
|
+
binary += String.fromCharCode(b);
|
|
793
|
+
}
|
|
794
|
+
return btoa(binary);
|
|
795
|
+
}
|
|
796
|
+
var cachedWebCrypto;
|
|
797
|
+
function getWebCrypto() {
|
|
798
|
+
if (cachedWebCrypto === void 0) {
|
|
799
|
+
const candidate = globalThis.crypto;
|
|
800
|
+
cachedWebCrypto = candidate && typeof candidate.getRandomValues === "function" ? candidate : null;
|
|
801
|
+
}
|
|
802
|
+
if (!cachedWebCrypto) {
|
|
803
|
+
throw new Error(
|
|
804
|
+
"generateNonce: Web Crypto unavailable. TheoKit requires Node.js 19+, Bun, Deno, or any modern Edge runtime where `globalThis.crypto.getRandomValues` is present."
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
return cachedWebCrypto;
|
|
808
|
+
}
|
|
809
|
+
function generateNonce() {
|
|
810
|
+
const buf = new Uint8Array(16);
|
|
811
|
+
getWebCrypto().getRandomValues(buf);
|
|
812
|
+
return bytesToBase64(buf);
|
|
813
|
+
}
|
|
814
|
+
|
|
640
815
|
// src/server/auth/auth.ts
|
|
641
816
|
var AuthRequiredError = class extends Error {
|
|
642
817
|
code = "AUTH_REQUIRED";
|
|
@@ -785,31 +960,36 @@ function pickHeader(value) {
|
|
|
785
960
|
if (Array.isArray(value) && value.length > 0) return value[0];
|
|
786
961
|
return "";
|
|
787
962
|
}
|
|
788
|
-
function
|
|
789
|
-
if (
|
|
963
|
+
function isCsrfValidFromHeaders(opts) {
|
|
964
|
+
if (opts.csrfActionHeader !== "1") {
|
|
790
965
|
return { valid: false, reason: "Missing X-Theo-Action header" };
|
|
791
966
|
}
|
|
792
|
-
|
|
793
|
-
if (!origin) {
|
|
967
|
+
if (opts.origin === null || opts.origin === "") {
|
|
794
968
|
return { valid: true };
|
|
795
969
|
}
|
|
796
|
-
|
|
797
|
-
if (!host) {
|
|
970
|
+
if (opts.host === null || opts.host === "") {
|
|
798
971
|
return { valid: true };
|
|
799
972
|
}
|
|
800
|
-
const originStr = pickHeader(origin);
|
|
801
|
-
const hostStr = pickHeader(host);
|
|
802
|
-
if (originStr === "" || hostStr === "") return { valid: true };
|
|
803
973
|
try {
|
|
804
|
-
const originHost = new URL(
|
|
805
|
-
if (originHost !==
|
|
806
|
-
return { valid: false, reason: `Origin ${
|
|
974
|
+
const originHost = new URL(opts.origin).host;
|
|
975
|
+
if (originHost !== opts.host) {
|
|
976
|
+
return { valid: false, reason: `Origin ${opts.origin} does not match host ${opts.host}` };
|
|
807
977
|
}
|
|
808
978
|
} catch {
|
|
809
|
-
return { valid: false, reason: `Invalid origin: ${
|
|
979
|
+
return { valid: false, reason: `Invalid origin: ${opts.origin}` };
|
|
810
980
|
}
|
|
811
981
|
return { valid: true };
|
|
812
982
|
}
|
|
983
|
+
function validateCsrf(req) {
|
|
984
|
+
const action = req.headers["x-theo-action"];
|
|
985
|
+
const origin = req.headers.origin;
|
|
986
|
+
const host = req.headers.host;
|
|
987
|
+
return isCsrfValidFromHeaders({
|
|
988
|
+
csrfActionHeader: typeof action === "string" ? action : null,
|
|
989
|
+
origin: origin !== void 0 ? pickHeader(origin) || null : null,
|
|
990
|
+
host: host !== void 0 ? pickHeader(host) || null : null
|
|
991
|
+
});
|
|
992
|
+
}
|
|
813
993
|
function dispatchCsrfWarn2(req, reason, logger, auditLogger, pathFallback = "") {
|
|
814
994
|
const payload = {
|
|
815
995
|
event: "csrf.warn",
|
|
@@ -1268,6 +1448,29 @@ var ActionError = class _ActionError extends Error {
|
|
|
1268
1448
|
this.stack = params.stack;
|
|
1269
1449
|
}
|
|
1270
1450
|
}
|
|
1451
|
+
/**
|
|
1452
|
+
* G5 T2.4 — canonical envelope view of the action error. Maps the G3
|
|
1453
|
+
* ActionErrorCode to a canonical TheoErrorCode (VALIDATION_ERROR ↔
|
|
1454
|
+
* UNPROCESSABLE_ENTITY, CONTENT_TOO_LARGE ↔ PAYLOAD_TOO_LARGE) so consumer
|
|
1455
|
+
* UI / SDK code can switch on the unified envelope.
|
|
1456
|
+
*
|
|
1457
|
+
* Subclasses override to populate `ext` (see `ActionInputError.envelope`).
|
|
1458
|
+
*/
|
|
1459
|
+
get envelope() {
|
|
1460
|
+
return {
|
|
1461
|
+
code: _ActionError.toTheoErrorCode(this.code),
|
|
1462
|
+
message: this.message
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Translate G3 ActionErrorCode → canonical TheoErrorCode (blueprint
|
|
1467
|
+
* Recommendations § "G3 ActionError becomes inaugural envelope user").
|
|
1468
|
+
*/
|
|
1469
|
+
static toTheoErrorCode(code) {
|
|
1470
|
+
if (code === "VALIDATION_ERROR") return "UNPROCESSABLE_ENTITY";
|
|
1471
|
+
if (code === "CONTENT_TOO_LARGE") return "PAYLOAD_TOO_LARGE";
|
|
1472
|
+
return code;
|
|
1473
|
+
}
|
|
1271
1474
|
static codeToStatus(code) {
|
|
1272
1475
|
return CODE_TO_STATUS[code];
|
|
1273
1476
|
}
|
|
@@ -1307,6 +1510,18 @@ var ActionInputError = class extends ActionError {
|
|
|
1307
1510
|
this.issues = extractUniversalIssues(rawIssues);
|
|
1308
1511
|
this.fields = buildFieldsMap(this.issues);
|
|
1309
1512
|
}
|
|
1513
|
+
/**
|
|
1514
|
+
* G5 T2.4 — envelope view with ValidationFieldsExt populated from .fields.
|
|
1515
|
+
* UI consumers can `switch (env.code)` on `UNPROCESSABLE_ENTITY` and read
|
|
1516
|
+
* `(env.ext as ValidationFieldsExt).fields` for field-level rendering.
|
|
1517
|
+
*/
|
|
1518
|
+
get envelope() {
|
|
1519
|
+
return {
|
|
1520
|
+
code: "UNPROCESSABLE_ENTITY",
|
|
1521
|
+
message: this.message,
|
|
1522
|
+
ext: { fields: this.fields }
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1310
1525
|
};
|
|
1311
1526
|
function buildFieldsMap(issues) {
|
|
1312
1527
|
const fields = {};
|
|
@@ -1664,7 +1879,7 @@ function writeSerialized(res, serialized) {
|
|
|
1664
1879
|
async function emitActionCallTelemetry(name, startedAt, input, outcome) {
|
|
1665
1880
|
if (!__IS_DEV) return;
|
|
1666
1881
|
try {
|
|
1667
|
-
const mod = await import("./dispatcher-
|
|
1882
|
+
const mod = await import("./dispatcher-EJME6C6M.js");
|
|
1668
1883
|
mod.dispatcher.onActionCall({
|
|
1669
1884
|
// eslint-disable-next-line sonarjs/pseudo-random -- non-secret correlation id
|
|
1670
1885
|
id: `act-${String(Date.now())}-${Math.random().toString(36).slice(2, 8)}`,
|
|
@@ -1838,89 +2053,9 @@ function findSuggestion(input, candidates, maxDistance = 3) {
|
|
|
1838
2053
|
return best;
|
|
1839
2054
|
}
|
|
1840
2055
|
|
|
1841
|
-
// src/server/security/security-headers.ts
|
|
1842
|
-
var DEFAULT_CSP = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss:; frame-ancestors 'none'; report-uri /__theo/csp-report";
|
|
1843
|
-
var DEFAULT_PERMISSIONS_POLICY = "geolocation=(), camera=(), microphone=(), payment=(), usb=(), accelerometer=(), gyroscope=()";
|
|
1844
|
-
var DEFAULT_HSTS = "max-age=31536000; includeSubDomains";
|
|
1845
|
-
function applyNonceToCsp(policy, nonce) {
|
|
1846
|
-
return policy.split(";").map((directive) => {
|
|
1847
|
-
const trimmed = directive.trim();
|
|
1848
|
-
if (!trimmed.startsWith("script-src")) return directive;
|
|
1849
|
-
if (trimmed.includes("'unsafe-inline'")) {
|
|
1850
|
-
return directive.replace("'unsafe-inline'", `'nonce-${nonce}'`);
|
|
1851
|
-
}
|
|
1852
|
-
return `${directive} 'nonce-${nonce}'`;
|
|
1853
|
-
}).join(";");
|
|
1854
|
-
}
|
|
1855
|
-
function applyCsp(out, config, effectiveNonce) {
|
|
1856
|
-
if (config.csp === false || config.cspMode === "off") return;
|
|
1857
|
-
let policy = typeof config.csp === "string" ? config.csp : DEFAULT_CSP;
|
|
1858
|
-
if (effectiveNonce) {
|
|
1859
|
-
policy = applyNonceToCsp(policy, effectiveNonce);
|
|
1860
|
-
}
|
|
1861
|
-
const mode = config.cspMode ?? "enforce";
|
|
1862
|
-
if (mode === "enforce") {
|
|
1863
|
-
out["Content-Security-Policy"] = policy;
|
|
1864
|
-
} else {
|
|
1865
|
-
out["Content-Security-Policy-Report-Only"] = policy;
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
function buildSecurityHeaders(config, env, options = {}) {
|
|
1869
|
-
const out = {};
|
|
1870
|
-
const effectiveNonce = options.prerender ? void 0 : options.nonce;
|
|
1871
|
-
applyCsp(out, config, effectiveNonce);
|
|
1872
|
-
out["X-Frame-Options"] = config.frameOptions ?? "DENY";
|
|
1873
|
-
out["X-Content-Type-Options"] = config.contentTypeOptions ?? "nosniff";
|
|
1874
|
-
out["Referrer-Policy"] = config.referrerPolicy ?? "strict-origin-when-cross-origin";
|
|
1875
|
-
if (config.permissionsPolicy !== false) {
|
|
1876
|
-
out["Permissions-Policy"] = typeof config.permissionsPolicy === "string" ? config.permissionsPolicy : DEFAULT_PERMISSIONS_POLICY;
|
|
1877
|
-
}
|
|
1878
|
-
if (env.production && config.hsts !== false) {
|
|
1879
|
-
out["Strict-Transport-Security"] = typeof config.hsts === "string" ? config.hsts : DEFAULT_HSTS;
|
|
1880
|
-
}
|
|
1881
|
-
if (effectiveNonce) {
|
|
1882
|
-
out["Cache-Control"] = "private, no-store";
|
|
1883
|
-
}
|
|
1884
|
-
return out;
|
|
1885
|
-
}
|
|
1886
|
-
function applySecurityHeaders(res, config, env, options = {}) {
|
|
1887
|
-
const headers = buildSecurityHeaders(config, env, options);
|
|
1888
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
1889
|
-
res.setHeader(key, value);
|
|
1890
|
-
}
|
|
1891
|
-
}
|
|
1892
|
-
|
|
1893
|
-
// src/server/auth/nonce.ts
|
|
1894
|
-
function bytesToBase64(bytes) {
|
|
1895
|
-
if (typeof Buffer !== "undefined") {
|
|
1896
|
-
return Buffer.from(bytes).toString("base64");
|
|
1897
|
-
}
|
|
1898
|
-
let binary = "";
|
|
1899
|
-
for (const b of bytes) {
|
|
1900
|
-
binary += String.fromCharCode(b);
|
|
1901
|
-
}
|
|
1902
|
-
return btoa(binary);
|
|
1903
|
-
}
|
|
1904
|
-
var cachedWebCrypto;
|
|
1905
|
-
function getWebCrypto() {
|
|
1906
|
-
if (cachedWebCrypto === void 0) {
|
|
1907
|
-
const candidate = globalThis.crypto;
|
|
1908
|
-
cachedWebCrypto = candidate && typeof candidate.getRandomValues === "function" ? candidate : null;
|
|
1909
|
-
}
|
|
1910
|
-
if (!cachedWebCrypto) {
|
|
1911
|
-
throw new Error(
|
|
1912
|
-
"generateNonce: Web Crypto unavailable. TheoKit requires Node.js 19+, Bun, Deno, or any modern Edge runtime where `globalThis.crypto.getRandomValues` is present."
|
|
1913
|
-
);
|
|
1914
|
-
}
|
|
1915
|
-
return cachedWebCrypto;
|
|
1916
|
-
}
|
|
1917
|
-
function generateNonce() {
|
|
1918
|
-
const buf = new Uint8Array(16);
|
|
1919
|
-
getWebCrypto().getRandomValues(buf);
|
|
1920
|
-
return bytesToBase64(buf);
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
2056
|
export {
|
|
2057
|
+
createPluginRunnerFromConfig,
|
|
2058
|
+
resolveTransformer,
|
|
1924
2059
|
logRequest,
|
|
1925
2060
|
warnOnce,
|
|
1926
2061
|
safeAudit,
|
|
@@ -1933,8 +2068,6 @@ export {
|
|
|
1933
2068
|
createRateLimiter,
|
|
1934
2069
|
buildSecurityHeaders,
|
|
1935
2070
|
applySecurityHeaders,
|
|
1936
|
-
createPluginRunnerFromConfig,
|
|
1937
|
-
resolveTransformer,
|
|
1938
2071
|
generateNonce
|
|
1939
2072
|
};
|
|
1940
|
-
//# sourceMappingURL=chunk-
|
|
2073
|
+
//# sourceMappingURL=chunk-ABVITXFH.js.map
|