theokit 0.48.13 → 0.50.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/README.md +1 -0
- package/dist/{actions-virtual-module-YQXRSSMW.js → actions-virtual-module-5WBVSDOM.js} +22 -12
- package/dist/actions-virtual-module-5WBVSDOM.js.map +1 -0
- package/dist/{actions-virtual-module-LB4NGONI.js → actions-virtual-module-ZYLMNW6K.js} +13 -8
- package/dist/{actions-virtual-module-LB4NGONI.js.map → actions-virtual-module-ZYLMNW6K.js.map} +1 -1
- package/dist/adapters/agent-mount.d.ts +127 -0
- package/dist/adapters/agent-mount.js +24 -0
- package/dist/adapters/security-headers.d.ts +132 -0
- package/dist/adapters/security-headers.js +64 -0
- package/dist/adapters/security-headers.js.map +1 -0
- package/dist/adapters/web-shim.d.ts +100 -13
- package/dist/adapters/web-shim.js +158 -54
- package/dist/adapters/web-shim.js.map +1 -1
- package/dist/agent-GKUEL6OH.js +15 -0
- package/dist/agent-scan-BZa-pagG.d.ts +16 -0
- package/dist/{app-typed-client-GHO3EWZK.js → app-typed-client-4LAIEGFX.js} +23 -13
- package/dist/app-typed-client-4LAIEGFX.js.map +1 -0
- package/dist/{app-typed-client-G3J5G7E5.js → app-typed-client-DQM3Y6YY.js} +14 -9
- package/dist/app-typed-client-DQM3Y6YY.js.map +1 -0
- package/dist/aws-lambda-VKMYUMP2.js +261 -0
- package/dist/aws-lambda-VKMYUMP2.js.map +1 -0
- package/dist/{build-WU6AKKIB.js → build-FLX6VF7Q.js} +71 -26
- package/dist/build-FLX6VF7Q.js.map +1 -0
- package/dist/{bun-33RD6K7O.js → bun-L7PP6ID5.js} +105 -13
- package/dist/bun-L7PP6ID5.js.map +1 -0
- package/dist/{check-45NKUVSQ.js → check-GIPZBFTX.js} +2 -2
- package/dist/{chunk-KD5G3YXI.js → chunk-2AMLGJJA.js} +35 -9
- package/dist/chunk-2AMLGJJA.js.map +1 -0
- package/dist/chunk-3PBAN2YE.js +146 -0
- package/dist/chunk-3PBAN2YE.js.map +1 -0
- package/dist/{chunk-HBU2GIMZ.js → chunk-3QPVEJ7D.js} +15 -9
- package/dist/chunk-3QPVEJ7D.js.map +1 -0
- package/dist/{chunk-47CINLWF.js → chunk-44J2ANQC.js} +2 -2
- package/dist/{chunk-IEES3CHD.js → chunk-47MM2JUK.js} +8 -2
- package/dist/chunk-47MM2JUK.js.map +1 -0
- package/dist/chunk-4X6H2BXP.js +108 -0
- package/dist/chunk-4X6H2BXP.js.map +1 -0
- package/dist/{chunk-A7JBF5FO.js → chunk-5K4TDLRG.js} +8 -5
- package/dist/chunk-5K4TDLRG.js.map +1 -0
- package/dist/chunk-5YPXXSYY.js +181 -0
- package/dist/chunk-5YPXXSYY.js.map +1 -0
- package/dist/{chunk-YGAXV5HR.js → chunk-6J4JWHDJ.js} +191 -112
- package/dist/chunk-6J4JWHDJ.js.map +1 -0
- package/dist/chunk-72DMJBXI.js +424 -0
- package/dist/chunk-72DMJBXI.js.map +1 -0
- package/dist/chunk-7PM6K5EV.js +513 -0
- package/dist/chunk-7PM6K5EV.js.map +1 -0
- package/dist/{chunk-MTEWLGVY.js → chunk-BPYMC7SU.js} +4 -48
- package/dist/chunk-BPYMC7SU.js.map +1 -0
- package/dist/chunk-BU6RJPPJ.js +421 -0
- package/dist/chunk-BU6RJPPJ.js.map +1 -0
- package/dist/{chunk-FB2HBNIC.js → chunk-BX6EUYHU.js} +6 -2
- package/dist/chunk-BX6EUYHU.js.map +1 -0
- package/dist/{chunk-BIVCP6X5.js → chunk-C62IZEJI.js} +465 -202
- package/dist/chunk-C62IZEJI.js.map +1 -0
- package/dist/chunk-D4VP2QPR.js +16 -0
- package/dist/chunk-D4VP2QPR.js.map +1 -0
- package/dist/{chunk-J5MXCGKA.js → chunk-DHAD2O3S.js} +6 -6
- package/dist/chunk-DHAD2O3S.js.map +1 -0
- package/dist/chunk-E43VJ3E5.js +188 -0
- package/dist/chunk-E43VJ3E5.js.map +1 -0
- package/dist/chunk-EVZKNA2W.js +110 -0
- package/dist/chunk-EVZKNA2W.js.map +1 -0
- package/dist/chunk-FD4ZDTQ6.js +181 -0
- package/dist/chunk-FD4ZDTQ6.js.map +1 -0
- package/dist/chunk-FDOOBTXJ.js +17 -0
- package/dist/chunk-FDOOBTXJ.js.map +1 -0
- package/dist/chunk-FH3SQR6P.js +275 -0
- package/dist/chunk-FH3SQR6P.js.map +1 -0
- package/dist/chunk-HJHGTFEJ.js +23 -0
- package/dist/chunk-HJHGTFEJ.js.map +1 -0
- package/dist/{chunk-LXAESF4Y.js → chunk-HK4AZBKX.js} +7 -4
- package/dist/chunk-HK4AZBKX.js.map +1 -0
- package/dist/{chunk-T5C46IIU.js → chunk-HWBRS4DZ.js} +28 -269
- package/dist/chunk-HWBRS4DZ.js.map +1 -0
- package/dist/chunk-IRQGAC4L.js +52 -0
- package/dist/chunk-IRQGAC4L.js.map +1 -0
- package/dist/{chunk-FNTLKHZ7.js → chunk-JDN5SAAD.js} +7 -4
- package/dist/chunk-JDN5SAAD.js.map +1 -0
- package/dist/{chunk-GXEX4CBH.js → chunk-JIKNR5LX.js} +673 -484
- package/dist/chunk-JIKNR5LX.js.map +1 -0
- package/dist/{chunk-GRI4XHBJ.js → chunk-JWRCZIA4.js} +266 -108
- package/dist/chunk-JWRCZIA4.js.map +1 -0
- package/dist/{chunk-E576KYYT.js → chunk-KI4DOTN4.js} +25 -2
- package/dist/chunk-KI4DOTN4.js.map +1 -0
- package/dist/{chunk-ZB7D62OA.js → chunk-KUZVRJ7M.js} +3 -3
- package/dist/chunk-L4VFNFDL.js +248 -0
- package/dist/chunk-L4VFNFDL.js.map +1 -0
- package/dist/chunk-M2WC5MF7.js +127 -0
- package/dist/chunk-M2WC5MF7.js.map +1 -0
- package/dist/{chunk-O3JIAU3V.js → chunk-MCTC6HSE.js} +157 -103
- package/dist/chunk-MCTC6HSE.js.map +1 -0
- package/dist/{chunk-PXFXSFJL.js → chunk-NZ5JU6D3.js} +9 -9
- package/dist/{chunk-YRBR424R.js → chunk-OAUI273L.js} +338 -165
- package/dist/chunk-OAUI273L.js.map +1 -0
- package/dist/chunk-OGLS76RN.js +43 -0
- package/dist/chunk-OGLS76RN.js.map +1 -0
- package/dist/{chunk-7LVM22VG.js → chunk-OQCRCXCP.js} +6 -6
- package/dist/chunk-OQCRCXCP.js.map +1 -0
- package/dist/{chunk-OLGPYOLO.js → chunk-P6OS7652.js} +5 -2
- package/dist/chunk-P6OS7652.js.map +1 -0
- package/dist/chunk-Q5L5EGWZ.js +26 -0
- package/dist/chunk-Q5L5EGWZ.js.map +1 -0
- package/dist/{chunk-S433N3CT.js → chunk-QTHVHNJJ.js} +6 -36
- package/dist/chunk-QTHVHNJJ.js.map +1 -0
- package/dist/chunk-RPET332G.js +84 -0
- package/dist/chunk-RPET332G.js.map +1 -0
- package/dist/{chunk-646CA6RV.js → chunk-RQW5YMH7.js} +12 -4
- package/dist/chunk-RQW5YMH7.js.map +1 -0
- package/dist/{chunk-XALU5LCU.js → chunk-RWNYIU6A.js} +550 -146
- package/dist/chunk-RWNYIU6A.js.map +1 -0
- package/dist/chunk-SL7YUHPV.js +111 -0
- package/dist/chunk-SL7YUHPV.js.map +1 -0
- package/dist/chunk-U5PWXS3J.js +39 -0
- package/dist/chunk-U5PWXS3J.js.map +1 -0
- package/dist/chunk-ULDCFL2O.js +273 -0
- package/dist/chunk-ULDCFL2O.js.map +1 -0
- package/dist/{chunk-RWNSW4FM.js → chunk-UMNXCU3K.js} +12 -6
- package/dist/{chunk-RWNSW4FM.js.map → chunk-UMNXCU3K.js.map} +1 -1
- package/dist/chunk-VI7ZANB3.js +193 -0
- package/dist/chunk-VI7ZANB3.js.map +1 -0
- package/dist/chunk-VQPHPQ5L.js +14 -0
- package/dist/chunk-VQPHPQ5L.js.map +1 -0
- package/dist/chunk-WNJTJRM6.js +147 -0
- package/dist/chunk-WNJTJRM6.js.map +1 -0
- package/dist/chunk-WOBSEO75.js +790 -0
- package/dist/chunk-WOBSEO75.js.map +1 -0
- package/dist/{chunk-BMHS4WAN.js → chunk-XS7EX55U.js} +156 -42
- package/dist/chunk-XS7EX55U.js.map +1 -0
- package/dist/chunk-YN4W7LCX.js +31 -0
- package/dist/chunk-YN4W7LCX.js.map +1 -0
- package/dist/chunk-YSJOZEI6.js +1 -0
- package/dist/{chunk-JA2ZAT5Q.js → chunk-Z4PJMZLM.js} +2 -2
- package/dist/chunk-Z4PJMZLM.js.map +1 -0
- package/dist/{chunk-7VPQHEAJ.js → chunk-ZNZISJDZ.js} +6 -2
- package/dist/chunk-ZNZISJDZ.js.map +1 -0
- package/dist/chunk-ZWN3AODA.js +11 -0
- package/dist/chunk-ZWN3AODA.js.map +1 -0
- package/dist/cli/index.js +25 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/client/core.d.ts +1 -1
- package/dist/client/core.js +2 -0
- package/dist/client/core.js.map +1 -1
- package/dist/client/index.d.ts +44 -10
- package/dist/client/index.js +35 -0
- package/dist/client/index.js.map +1 -1
- package/dist/cloudflare-SIG42OIW.js +335 -0
- package/dist/cloudflare-SIG42OIW.js.map +1 -0
- package/dist/config-support-WQHQIJTA.js +104 -0
- package/dist/config-support-WQHQIJTA.js.map +1 -0
- package/dist/{csrf-BBrEZSBW.d.ts → csrf-Dgot9qSM.d.ts} +1 -1
- package/dist/deno-deploy-LQAYOOPW.js +196 -0
- package/dist/deno-deploy-LQAYOOPW.js.map +1 -0
- package/dist/{dev-MUWJAZRD.js → dev-ANDSEVLB.js} +28 -18
- package/dist/dev-ANDSEVLB.js.map +1 -0
- package/dist/{dev-emit-GWD6IXV7.js → dev-emit-BFNMDCPB.js} +5 -5
- package/dist/{dev-emit-NBT6JD7R.js → dev-emit-MVAJAFGX.js} +5 -3
- package/dist/dev-emit-MVAJAFGX.js.map +1 -0
- package/dist/engine-singleton-X4R7AZBJ.js +315 -0
- package/dist/engine-singleton-X4R7AZBJ.js.map +1 -0
- package/dist/{generate-Y3GWM57K.js → generate-EN6EDITF.js} +43 -4
- package/dist/generate-EN6EDITF.js.map +1 -0
- package/dist/index-CzxtQcnp.d.ts +1058 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +24 -13
- package/dist/index.js.map +1 -1
- package/dist/{info-XW7HGUPH.js → info-Y55RWS42.js} +8 -6
- package/dist/{info-XW7HGUPH.js.map → info-Y55RWS42.js.map} +1 -1
- package/dist/{internal-api-V5L65YSJ.js → internal-api-IP35YU3G.js} +22 -12
- package/dist/{internal-api-WEOSTMSN.js → internal-api-OPU456AT.js} +30 -16
- package/dist/internal-api-OPU456AT.js.map +1 -0
- package/dist/load-config-4ATXQUN3.js +16 -0
- package/dist/match-DmGgxjIU.d.ts +44 -0
- package/dist/{mcp-ULUFJNSZ.js → mcp-5LLNAGKA.js} +7 -7
- package/dist/netlify-C2IRCZKI.js +245 -0
- package/dist/netlify-C2IRCZKI.js.map +1 -0
- package/dist/node-OSVPYQ3D.js +10 -0
- package/dist/nonce-BXt7Qu_C.d.ts +31 -0
- package/dist/observability-bootstrap-MZMSOE66.js +15 -0
- package/dist/{openapi-HZXR335W.js → openapi-VFPEZSRI.js} +13 -11
- package/dist/{openapi-HZXR335W.js.map → openapi-VFPEZSRI.js.map} +1 -1
- package/dist/{plugin-runner-BFEcgtmJ.d.ts → plugin-runner-BVMOSxvb.d.ts} +1 -1
- package/dist/{plugin-types-D69-lJZ9.d.ts → plugin-types-BUVfUQ0V.d.ts} +13 -1
- package/dist/preview-GHPT2EQ5.js +23 -0
- package/dist/preview-GHPT2EQ5.js.map +1 -0
- package/dist/provider-resolver-Dx6QuWrw.d.ts +128 -0
- package/dist/registry-KBZDCFVQ.js +23 -0
- package/dist/route-config-Cm_ZMA1C.d.ts +72 -0
- package/dist/route-policy-BxOycCDq.d.ts +65 -0
- package/dist/router/element-scroll-restoration.d.ts +28 -0
- package/dist/router/element-scroll-restoration.js +96 -0
- package/dist/router/element-scroll-restoration.js.map +1 -0
- package/dist/{routes-OLNQX7CT.js → routes-BPLU3ISV.js} +11 -9
- package/dist/{routes-OLNQX7CT.js.map → routes-BPLU3ISV.js.map} +1 -1
- package/dist/{scan-7MJC6PYU.js → scan-YJEE4KQK.js} +2 -2
- package/dist/{schema-ZO3OSWVG.js → schema-SOAD43RQ.js} +7 -5
- package/dist/schemas-4AXHQMV3.js +25 -0
- package/dist/schemas-4AXHQMV3.js.map +1 -0
- package/dist/security-headers-Ccj7ncNx.d.ts +129 -0
- package/dist/server/agent/index.d.ts +2 -90
- package/dist/server/agent/index.js +1 -1
- package/dist/server/auth/index.d.ts +2 -21
- package/dist/server/auth/index.js +3 -2
- package/dist/server/cron/index.js +4 -3
- package/dist/server/define/index.d.ts +51 -57
- package/dist/server/define/index.js +10 -1
- package/dist/server/http/index.d.ts +7 -5
- package/dist/server/http/index.js +56 -12
- package/dist/server/index.d.ts +47 -439
- package/dist/server/index.js +119 -201
- package/dist/server/index.js.map +1 -1
- package/dist/server/jobs/index.js +4 -3
- package/dist/server/observability/index.d.ts +109 -35
- package/dist/server/observability/index.js +10 -7
- package/dist/server/plugins/index.d.ts +3 -3
- package/dist/server/scan/index.d.ts +47 -12
- package/dist/server/scan/index.js +13 -4
- package/dist/server/security/index.d.ts +61 -103
- package/dist/server/security/index.js +15 -6
- package/dist/server/webhook/index.d.ts +90 -3
- package/dist/server/webhook/index.js +12 -2
- package/dist/server-boundary-6B4ZQUY7.js +148 -0
- package/dist/server-boundary-6B4ZQUY7.js.map +1 -0
- package/dist/server-boundary-7VZQRPPX.js +133 -0
- package/dist/server-boundary-7VZQRPPX.js.map +1 -0
- package/dist/{services-typed-client-PSAGRPFF.js → services-typed-client-XGT5SUUN.js} +2 -2
- package/dist/{start-KR2JJR7K.js → start-UZDMOT7I.js} +342 -111
- package/dist/start-UZDMOT7I.js.map +1 -0
- package/dist/{static-M2W4HUWS.js → static-SVDWIOXJ.js} +24 -13
- package/dist/static-SVDWIOXJ.js.map +1 -0
- package/dist/{theo-cloud-XAHWOUFK.js → theo-cloud-3ET4G5T6.js} +9 -2
- package/dist/theo-cloud-3ET4G5T6.js.map +1 -0
- package/dist/vercel-BMCQKCWE.js +277 -0
- package/dist/vercel-BMCQKCWE.js.map +1 -0
- package/dist/vite-plugin/index.js +24 -13
- package/dist/vite-plugin-VKCT2LF2.js +42 -0
- package/dist/vite-plugin-VKCT2LF2.js.map +1 -0
- package/package.json +19 -6
- package/dist/actions-virtual-module-YQXRSSMW.js.map +0 -1
- package/dist/agent-7JJW3TPB.js +0 -15
- package/dist/app-typed-client-G3J5G7E5.js.map +0 -1
- package/dist/app-typed-client-GHO3EWZK.js.map +0 -1
- package/dist/aws-lambda-CYNDGU5O.js +0 -172
- package/dist/aws-lambda-CYNDGU5O.js.map +0 -1
- package/dist/build-WU6AKKIB.js.map +0 -1
- package/dist/bun-33RD6K7O.js.map +0 -1
- package/dist/chunk-646CA6RV.js.map +0 -1
- package/dist/chunk-6E5WKMDS.js +0 -67
- package/dist/chunk-6E5WKMDS.js.map +0 -1
- package/dist/chunk-6GGWS7J3.js +0 -91
- package/dist/chunk-6GGWS7J3.js.map +0 -1
- package/dist/chunk-7LVM22VG.js.map +0 -1
- package/dist/chunk-7VPQHEAJ.js.map +0 -1
- package/dist/chunk-A7JBF5FO.js.map +0 -1
- package/dist/chunk-AM3QABW5.js +0 -161
- package/dist/chunk-AM3QABW5.js.map +0 -1
- package/dist/chunk-BIVCP6X5.js.map +0 -1
- package/dist/chunk-BMHS4WAN.js.map +0 -1
- package/dist/chunk-E576KYYT.js.map +0 -1
- package/dist/chunk-FB2HBNIC.js.map +0 -1
- package/dist/chunk-FNTLKHZ7.js.map +0 -1
- package/dist/chunk-GRI4XHBJ.js.map +0 -1
- package/dist/chunk-GVW5EKEU.js +0 -422
- package/dist/chunk-GVW5EKEU.js.map +0 -1
- package/dist/chunk-GXEX4CBH.js.map +0 -1
- package/dist/chunk-HBU2GIMZ.js.map +0 -1
- package/dist/chunk-IEES3CHD.js.map +0 -1
- package/dist/chunk-J5MXCGKA.js.map +0 -1
- package/dist/chunk-JA2ZAT5Q.js.map +0 -1
- package/dist/chunk-KD5G3YXI.js.map +0 -1
- package/dist/chunk-LNVMHQ2Z.js +0 -54
- package/dist/chunk-LNVMHQ2Z.js.map +0 -1
- package/dist/chunk-LXAESF4Y.js.map +0 -1
- package/dist/chunk-MTEWLGVY.js.map +0 -1
- package/dist/chunk-O3JIAU3V.js.map +0 -1
- package/dist/chunk-OJLL4YD6.js +0 -403
- package/dist/chunk-OJLL4YD6.js.map +0 -1
- package/dist/chunk-OLGPYOLO.js.map +0 -1
- package/dist/chunk-S433N3CT.js.map +0 -1
- package/dist/chunk-T5C46IIU.js.map +0 -1
- package/dist/chunk-U267AOWS.js +0 -28
- package/dist/chunk-U267AOWS.js.map +0 -1
- package/dist/chunk-UW2TEAGR.js +0 -77
- package/dist/chunk-UW2TEAGR.js.map +0 -1
- package/dist/chunk-WPJOTQA5.js +0 -1
- package/dist/chunk-XALU5LCU.js.map +0 -1
- package/dist/chunk-XR74JD4M.js +0 -457
- package/dist/chunk-XR74JD4M.js.map +0 -1
- package/dist/chunk-YGAXV5HR.js.map +0 -1
- package/dist/chunk-YRBR424R.js.map +0 -1
- package/dist/cloudflare-KYUWCEPL.js +0 -122
- package/dist/cloudflare-KYUWCEPL.js.map +0 -1
- package/dist/deno-deploy-CCTB7HGS.js +0 -107
- package/dist/deno-deploy-CCTB7HGS.js.map +0 -1
- package/dist/dev-MUWJAZRD.js.map +0 -1
- package/dist/dev-emit-NBT6JD7R.js.map +0 -1
- package/dist/generate-Y3GWM57K.js.map +0 -1
- package/dist/index-BEtEv6ZH.d.ts +0 -575
- package/dist/load-config-VKD6LKWU.js +0 -14
- package/dist/match-CfbEFRG4.d.ts +0 -26
- package/dist/netlify-AFMDNKT4.js +0 -150
- package/dist/netlify-AFMDNKT4.js.map +0 -1
- package/dist/node-ZJQEJSP3.js +0 -10
- package/dist/registry-GKR3EWRW.js +0 -23
- package/dist/start-KR2JJR7K.js.map +0 -1
- package/dist/static-M2W4HUWS.js.map +0 -1
- package/dist/theo-cloud-XAHWOUFK.js.map +0 -1
- package/dist/vercel-SRS2DH6O.js +0 -133
- package/dist/vercel-SRS2DH6O.js.map +0 -1
- package/dist/vite-plugin-VPJFD4HK.js +0 -36
- /package/dist/{chunk-WPJOTQA5.js.map → adapters/agent-mount.js.map} +0 -0
- /package/dist/{agent-7JJW3TPB.js.map → agent-GKUEL6OH.js.map} +0 -0
- /package/dist/{check-45NKUVSQ.js.map → check-GIPZBFTX.js.map} +0 -0
- /package/dist/{chunk-47CINLWF.js.map → chunk-44J2ANQC.js.map} +0 -0
- /package/dist/{chunk-ZB7D62OA.js.map → chunk-KUZVRJ7M.js.map} +0 -0
- /package/dist/{chunk-PXFXSFJL.js.map → chunk-NZ5JU6D3.js.map} +0 -0
- /package/dist/{internal-api-WEOSTMSN.js.map → chunk-YSJOZEI6.js.map} +0 -0
- /package/dist/{dev-emit-GWD6IXV7.js.map → dev-emit-BFNMDCPB.js.map} +0 -0
- /package/dist/{internal-api-V5L65YSJ.js.map → internal-api-IP35YU3G.js.map} +0 -0
- /package/dist/{load-config-VKD6LKWU.js.map → load-config-4ATXQUN3.js.map} +0 -0
- /package/dist/{mcp-ULUFJNSZ.js.map → mcp-5LLNAGKA.js.map} +0 -0
- /package/dist/{node-ZJQEJSP3.js.map → node-OSVPYQ3D.js.map} +0 -0
- /package/dist/{scan-7MJC6PYU.js.map → observability-bootstrap-MZMSOE66.js.map} +0 -0
- /package/dist/{registry-GKR3EWRW.js.map → registry-KBZDCFVQ.js.map} +0 -0
- /package/dist/{schema-ZO3OSWVG.js.map → scan-YJEE4KQK.js.map} +0 -0
- /package/dist/{vite-plugin-VPJFD4HK.js.map → schema-SOAD43RQ.js.map} +0 -0
- /package/dist/{services-typed-client-PSAGRPFF.js.map → services-typed-client-XGT5SUUN.js.map} +0 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "tsx/esm";
|
|
3
|
+
import {
|
|
4
|
+
warnOnce
|
|
5
|
+
} from "./chunk-2AMLGJJA.js";
|
|
6
|
+
import {
|
|
7
|
+
observabilitySchema
|
|
8
|
+
} from "./chunk-VI7ZANB3.js";
|
|
9
|
+
|
|
10
|
+
// src/server/observability/trace-context-propagation.ts
|
|
11
|
+
function generateNewTraceContext() {
|
|
12
|
+
return {
|
|
13
|
+
trace_id: newTraceId(),
|
|
14
|
+
span_id: newSpanId(),
|
|
15
|
+
flags: "01"
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function newTraceId() {
|
|
19
|
+
return randomHex(16);
|
|
20
|
+
}
|
|
21
|
+
function newSpanId() {
|
|
22
|
+
return randomHex(8);
|
|
23
|
+
}
|
|
24
|
+
function randomHex(bytes) {
|
|
25
|
+
for (; ; ) {
|
|
26
|
+
const buf = new Uint8Array(bytes);
|
|
27
|
+
globalThis.crypto.getRandomValues(buf);
|
|
28
|
+
let hex = "";
|
|
29
|
+
for (const b of buf) hex += b.toString(16).padStart(2, "0");
|
|
30
|
+
if (!/^0+$/.test(hex)) return hex;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/server/observability/span.ts
|
|
35
|
+
var SpanImpl = class {
|
|
36
|
+
data;
|
|
37
|
+
ended = false;
|
|
38
|
+
constructor(name, attributes, context) {
|
|
39
|
+
this.data = {
|
|
40
|
+
name,
|
|
41
|
+
traceId: context?.traceId ?? newTraceId(),
|
|
42
|
+
spanId: context?.spanId ?? newSpanId(),
|
|
43
|
+
attributes: {},
|
|
44
|
+
status: "ok",
|
|
45
|
+
startTimeMs: Date.now()
|
|
46
|
+
};
|
|
47
|
+
if (context?.parentSpanId !== void 0) this.data.parentSpanId = context.parentSpanId;
|
|
48
|
+
if (attributes) {
|
|
49
|
+
for (const [k, v] of Object.entries(attributes)) {
|
|
50
|
+
if (v !== void 0) this.data.attributes[k] = v;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
setAttribute(key, value) {
|
|
55
|
+
if (!this.ended) this.data.attributes[key] = value;
|
|
56
|
+
}
|
|
57
|
+
setStatus(status, message) {
|
|
58
|
+
if (!this.ended) {
|
|
59
|
+
this.data.status = status;
|
|
60
|
+
this.data.statusMessage = message;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
end() {
|
|
64
|
+
if (this.ended) return;
|
|
65
|
+
this.ended = true;
|
|
66
|
+
this.data.endTimeMs = Date.now();
|
|
67
|
+
this.data.durationMs = this.data.endTimeMs - this.data.startTimeMs;
|
|
68
|
+
}
|
|
69
|
+
/** Read-only access to span data (for adapters to export). */
|
|
70
|
+
getData() {
|
|
71
|
+
return { ...this.data, attributes: { ...this.data.attributes } };
|
|
72
|
+
}
|
|
73
|
+
isEnded() {
|
|
74
|
+
return this.ended;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var NoopSpan = class {
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function -- Null Object, see above
|
|
79
|
+
setAttribute() {
|
|
80
|
+
}
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function -- Null Object, see above
|
|
82
|
+
setStatus() {
|
|
83
|
+
}
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function -- Null Object, see above
|
|
85
|
+
end() {
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/server/observability/adapters/console.ts
|
|
90
|
+
var ConsoleObservabilityAdapter = class {
|
|
91
|
+
name = "console";
|
|
92
|
+
write;
|
|
93
|
+
isShutdown = false;
|
|
94
|
+
spans = [];
|
|
95
|
+
constructor(options = {}) {
|
|
96
|
+
this.write = options.write ?? ((line) => process.stderr.write(line + "\n"));
|
|
97
|
+
}
|
|
98
|
+
startSpan(name, attributes, context) {
|
|
99
|
+
if (this.isShutdown) return new NoopSpan();
|
|
100
|
+
const span = new SpanImpl(name, attributes, context);
|
|
101
|
+
this.spans.push(span);
|
|
102
|
+
return {
|
|
103
|
+
setAttribute: (k, v) => {
|
|
104
|
+
span.setAttribute(k, v);
|
|
105
|
+
},
|
|
106
|
+
setStatus: (s, m) => {
|
|
107
|
+
span.setStatus(s, m);
|
|
108
|
+
},
|
|
109
|
+
end: () => {
|
|
110
|
+
span.end();
|
|
111
|
+
this.emitSpan(span.getData());
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
counter(name, value, attributes) {
|
|
116
|
+
if (this.isShutdown) return;
|
|
117
|
+
this.emit({
|
|
118
|
+
type: "counter",
|
|
119
|
+
metric: name,
|
|
120
|
+
value,
|
|
121
|
+
attributes: attributes ?? {},
|
|
122
|
+
timestamp: Date.now()
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
histogram(name, value, attributes) {
|
|
126
|
+
if (this.isShutdown) return;
|
|
127
|
+
this.emit({
|
|
128
|
+
type: "histogram",
|
|
129
|
+
metric: name,
|
|
130
|
+
value,
|
|
131
|
+
attributes: attributes ?? {},
|
|
132
|
+
timestamp: Date.now()
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
log(level, message, attributes) {
|
|
136
|
+
if (this.isShutdown) return;
|
|
137
|
+
this.emit({ type: "log", level, message, attributes: attributes ?? {}, timestamp: Date.now() });
|
|
138
|
+
}
|
|
139
|
+
// Not `async`: this adapter writes synchronously, so there is nothing to await.
|
|
140
|
+
flush() {
|
|
141
|
+
return Promise.resolve();
|
|
142
|
+
}
|
|
143
|
+
shutdown() {
|
|
144
|
+
this.isShutdown = true;
|
|
145
|
+
return Promise.resolve();
|
|
146
|
+
}
|
|
147
|
+
emitSpan(data) {
|
|
148
|
+
this.emit({
|
|
149
|
+
type: "span",
|
|
150
|
+
name: data.name,
|
|
151
|
+
status: data.status,
|
|
152
|
+
duration_ms: data.durationMs ?? 0,
|
|
153
|
+
attributes: data.attributes,
|
|
154
|
+
timestamp: data.startTimeMs
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
emit(record) {
|
|
158
|
+
this.write(JSON.stringify(record));
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// src/server/observability/adapters/noop.ts
|
|
163
|
+
var NoopObservabilityAdapter = class {
|
|
164
|
+
name = "noop";
|
|
165
|
+
isShutdown = false;
|
|
166
|
+
startSpan(_name, _attributes) {
|
|
167
|
+
return new NoopSpan();
|
|
168
|
+
}
|
|
169
|
+
// Null Object: discarding the call IS the behaviour. An empty body is the honest
|
|
170
|
+
// implementation — a fabricated one would only hide that from the next reader.
|
|
171
|
+
/* eslint-disable @typescript-eslint/no-empty-function -- no-op adapter by design */
|
|
172
|
+
counter(_name, _value, _attributes) {
|
|
173
|
+
}
|
|
174
|
+
histogram(_name, _value, _attributes) {
|
|
175
|
+
}
|
|
176
|
+
log(_level, _message, _attributes) {
|
|
177
|
+
}
|
|
178
|
+
/* eslint-enable @typescript-eslint/no-empty-function */
|
|
179
|
+
// Not `async`: there is nothing to await, and declaring it so would claim otherwise.
|
|
180
|
+
flush() {
|
|
181
|
+
return Promise.resolve();
|
|
182
|
+
}
|
|
183
|
+
shutdown() {
|
|
184
|
+
this.isShutdown = true;
|
|
185
|
+
return Promise.resolve();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// src/server/observability/otlp-serializer.ts
|
|
190
|
+
function paraValorOtlp(value) {
|
|
191
|
+
switch (typeof value) {
|
|
192
|
+
case "string":
|
|
193
|
+
return { stringValue: value };
|
|
194
|
+
case "number":
|
|
195
|
+
return Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value };
|
|
196
|
+
default:
|
|
197
|
+
return { boolValue: value };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function serializeSpansToOtlp(spans, serviceName = "theokit") {
|
|
201
|
+
const otlpSpans = spans.map((s) => ({
|
|
202
|
+
// #368 — read, never minted. This used to call `randomHex` for both, which
|
|
203
|
+
// gave every span a trace of its own and made a multi-span run unreadable at
|
|
204
|
+
// the collector. The ids now arrive on the span, decided when it started.
|
|
205
|
+
traceId: s.traceId,
|
|
206
|
+
spanId: s.spanId,
|
|
207
|
+
...s.parentSpanId === void 0 ? {} : { parentSpanId: s.parentSpanId },
|
|
208
|
+
name: s.name,
|
|
209
|
+
kind: 2,
|
|
210
|
+
// SPAN_KIND_SERVER
|
|
211
|
+
startTimeUnixNano: String(s.startTimeMs * 1e6),
|
|
212
|
+
endTimeUnixNano: String((s.endTimeMs ?? s.startTimeMs) * 1e6),
|
|
213
|
+
attributes: Object.entries(s.attributes).map(([key, value]) => ({
|
|
214
|
+
key,
|
|
215
|
+
value: paraValorOtlp(value)
|
|
216
|
+
})),
|
|
217
|
+
status: { code: s.status === "ok" ? 1 : 2, message: s.statusMessage }
|
|
218
|
+
}));
|
|
219
|
+
const request = {
|
|
220
|
+
resourceSpans: [
|
|
221
|
+
{
|
|
222
|
+
scopeSpans: [
|
|
223
|
+
{
|
|
224
|
+
scope: { name: serviceName, version: "1.0.0" },
|
|
225
|
+
spans: otlpSpans
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
};
|
|
231
|
+
return new TextEncoder().encode(JSON.stringify(request));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/server/observability/adapters/theo-cloud.ts
|
|
235
|
+
var TheoCloudObservabilityAdapter = class {
|
|
236
|
+
name = "theo-cloud";
|
|
237
|
+
pendingSpans = [];
|
|
238
|
+
isShutdown = false;
|
|
239
|
+
dropped = 0;
|
|
240
|
+
flushTimer;
|
|
241
|
+
opts;
|
|
242
|
+
constructor(options) {
|
|
243
|
+
this.opts = { flushIntervalMs: 5e3, maxPendingSpans: 1e4, ...options };
|
|
244
|
+
this.flushTimer = setInterval(() => {
|
|
245
|
+
void this.flush();
|
|
246
|
+
}, this.opts.flushIntervalMs);
|
|
247
|
+
this.flushTimer.unref();
|
|
248
|
+
}
|
|
249
|
+
/** How many spans were dropped because the buffer was full. */
|
|
250
|
+
droppedSpanCount() {
|
|
251
|
+
return this.dropped;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Whether the periodic flush is unref'd. A test seam: "the timer does not hold
|
|
255
|
+
* the process open" is otherwise only observable by hanging.
|
|
256
|
+
*/
|
|
257
|
+
hasUnrefdFlushTimer() {
|
|
258
|
+
return !this.flushTimer.hasRef();
|
|
259
|
+
}
|
|
260
|
+
startSpan(name, attributes, context) {
|
|
261
|
+
if (this.isShutdown) return new NoopSpan();
|
|
262
|
+
const span = new SpanImpl(name, attributes, context);
|
|
263
|
+
return {
|
|
264
|
+
setAttribute: (k, v) => {
|
|
265
|
+
span.setAttribute(k, v);
|
|
266
|
+
},
|
|
267
|
+
setStatus: (s, m) => {
|
|
268
|
+
span.setStatus(s, m);
|
|
269
|
+
},
|
|
270
|
+
end: () => {
|
|
271
|
+
span.end();
|
|
272
|
+
if (this.pendingSpans.length >= this.opts.maxPendingSpans) {
|
|
273
|
+
this.pendingSpans.shift();
|
|
274
|
+
this.dropped++;
|
|
275
|
+
}
|
|
276
|
+
this.pendingSpans.push(span.getData());
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/* eslint-disable @typescript-eslint/no-empty-function -- metrics not shipped by this adapter yet; an empty body is honest, a fabricated one is not */
|
|
281
|
+
counter(_name, _value, _attributes) {
|
|
282
|
+
}
|
|
283
|
+
histogram(_name, _value, _attributes) {
|
|
284
|
+
}
|
|
285
|
+
log(_level, _message, _attributes) {
|
|
286
|
+
}
|
|
287
|
+
/* eslint-enable @typescript-eslint/no-empty-function */
|
|
288
|
+
async flush() {
|
|
289
|
+
if (this.isShutdown || this.pendingSpans.length === 0) return;
|
|
290
|
+
const spans = this.pendingSpans.splice(0);
|
|
291
|
+
const body = serializeSpansToOtlp(spans);
|
|
292
|
+
const fetchFn = this.opts._mockFetch ?? globalThis.fetch;
|
|
293
|
+
try {
|
|
294
|
+
await fetchFn(this.opts.ingestUrl, {
|
|
295
|
+
method: "POST",
|
|
296
|
+
headers: {
|
|
297
|
+
"content-type": "application/json",
|
|
298
|
+
authorization: `Bearer ${this.opts.token}`
|
|
299
|
+
},
|
|
300
|
+
body
|
|
301
|
+
});
|
|
302
|
+
} catch (err) {
|
|
303
|
+
console.error(
|
|
304
|
+
`[theokit:observability] flush failed: ${err instanceof Error ? err.message : "unknown error"}`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async shutdown() {
|
|
309
|
+
if (this.isShutdown) return;
|
|
310
|
+
clearInterval(this.flushTimer);
|
|
311
|
+
await this.flush();
|
|
312
|
+
this.isShutdown = true;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// src/server/observability/adapter-registry.ts
|
|
317
|
+
function resolveAdapter(options) {
|
|
318
|
+
if (options.config?.provider) {
|
|
319
|
+
return options.config.provider;
|
|
320
|
+
}
|
|
321
|
+
const ingestUrl = options.env.THEO_CLOUD_INGEST_URL;
|
|
322
|
+
const apiKey = options.env.THEO_CLOUD_API_KEY;
|
|
323
|
+
if (ingestUrl && apiKey) {
|
|
324
|
+
return new TheoCloudObservabilityAdapter({ ingestUrl, token: apiKey });
|
|
325
|
+
}
|
|
326
|
+
if (options.env.NODE_ENV === "development") {
|
|
327
|
+
return new ConsoleObservabilityAdapter();
|
|
328
|
+
}
|
|
329
|
+
return new NoopObservabilityAdapter();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/server/http/trace-context.ts
|
|
333
|
+
var TRACE_HEADER = "x-trace-id";
|
|
334
|
+
var TRACE_PARENT_HEADER = "traceparent";
|
|
335
|
+
var REQUEST_ID_HEADER = "x-request-id";
|
|
336
|
+
var TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
|
|
337
|
+
function parseTraceparentContext(value) {
|
|
338
|
+
if (!value) return null;
|
|
339
|
+
const m = TRACEPARENT_RE.exec(value);
|
|
340
|
+
if (!m) return null;
|
|
341
|
+
const traceId = m[1];
|
|
342
|
+
if (/^0+$/.test(traceId)) return null;
|
|
343
|
+
const parentSpanId = m[2];
|
|
344
|
+
return /^0+$/.test(parentSpanId) ? { traceId } : { traceId, parentSpanId };
|
|
345
|
+
}
|
|
346
|
+
function parseTraceparent(value) {
|
|
347
|
+
return parseTraceparentContext(value)?.traceId ?? null;
|
|
348
|
+
}
|
|
349
|
+
var REQUEST_ID_RE = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
350
|
+
function isTrustedRequestId(value) {
|
|
351
|
+
return REQUEST_ID_RE.test(value);
|
|
352
|
+
}
|
|
353
|
+
function pickHeader(value, isTrusted = () => true) {
|
|
354
|
+
if (Array.isArray(value)) {
|
|
355
|
+
for (const v of value) {
|
|
356
|
+
if (typeof v === "string" && v.length > 0 && isTrusted(v)) return v;
|
|
357
|
+
}
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
if (typeof value === "string" && value.length > 0 && isTrusted(value)) return value;
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
function resolveTraceIdFromHeaders(traceparent, requestId) {
|
|
364
|
+
if (traceparent !== null) {
|
|
365
|
+
const parsed = parseTraceparent(traceparent);
|
|
366
|
+
if (parsed !== null) return parsed;
|
|
367
|
+
}
|
|
368
|
+
if (requestId !== null) return requestId;
|
|
369
|
+
return globalThis.crypto.randomUUID();
|
|
370
|
+
}
|
|
371
|
+
function extractTraceId(req) {
|
|
372
|
+
return resolveTraceIdFromHeaders(
|
|
373
|
+
pickHeader(req.headers[TRACE_PARENT_HEADER]),
|
|
374
|
+
pickHeader(req.headers[REQUEST_ID_HEADER], isTrustedRequestId)
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
function extractW3CTraceContext(request) {
|
|
378
|
+
const traceparent = request.headers.get(TRACE_PARENT_HEADER);
|
|
379
|
+
if (traceparent === null) return void 0;
|
|
380
|
+
return parseTraceparentContext(traceparent) ?? void 0;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/server/observability/request-trace.ts
|
|
384
|
+
var resolved = /* @__PURE__ */ new WeakMap();
|
|
385
|
+
function requestTrace(request) {
|
|
386
|
+
const existing = resolved.get(request);
|
|
387
|
+
if (existing !== void 0) return existing;
|
|
388
|
+
const trace = resolve(request);
|
|
389
|
+
resolved.set(request, trace);
|
|
390
|
+
return trace;
|
|
391
|
+
}
|
|
392
|
+
function resolve(request) {
|
|
393
|
+
const inbound = extractW3CTraceContext(request);
|
|
394
|
+
if (inbound === void 0) return { traceId: newTraceId() };
|
|
395
|
+
if (inbound.parentSpanId === void 0) return { traceId: inbound.traceId };
|
|
396
|
+
return { traceId: inbound.traceId, parentSpanId: inbound.parentSpanId };
|
|
397
|
+
}
|
|
398
|
+
function recordOutermostSpan(request, spanId) {
|
|
399
|
+
const trace = requestTrace(request);
|
|
400
|
+
trace.outermostSpanId ??= spanId;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// src/server/observability/middleware.ts
|
|
404
|
+
var DEFAULT_MAX_ACTIVE_SPANS = 1024;
|
|
405
|
+
function createObservabilityPlugin(adapter, options = {}) {
|
|
406
|
+
const maxActiveSpans = options.maxActiveSpans ?? DEFAULT_MAX_ACTIVE_SPANS;
|
|
407
|
+
const activeSpans = /* @__PURE__ */ new Map();
|
|
408
|
+
function evictUntilRoom() {
|
|
409
|
+
while (activeSpans.size >= maxActiveSpans) {
|
|
410
|
+
const oldest = activeSpans.keys().next();
|
|
411
|
+
if (oldest.done === true) return;
|
|
412
|
+
const span = activeSpans.get(oldest.value);
|
|
413
|
+
activeSpans.delete(oldest.value);
|
|
414
|
+
if (span === void 0) continue;
|
|
415
|
+
span.setAttribute("span.abandoned", true);
|
|
416
|
+
span.setStatus("error", "span abandoned: onResponse never fired for this request");
|
|
417
|
+
span.end();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
function requestSpanContext(request) {
|
|
421
|
+
const trace = requestTrace(request);
|
|
422
|
+
const spanId = newSpanId();
|
|
423
|
+
recordOutermostSpan(request, spanId);
|
|
424
|
+
return trace.parentSpanId === void 0 ? { traceId: trace.traceId, spanId } : { traceId: trace.traceId, spanId, parentSpanId: trace.parentSpanId };
|
|
425
|
+
}
|
|
426
|
+
function claim(requestId) {
|
|
427
|
+
const span = activeSpans.get(requestId);
|
|
428
|
+
if (span === void 0) return void 0;
|
|
429
|
+
activeSpans.delete(requestId);
|
|
430
|
+
return span;
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
name: "theokit:observability",
|
|
434
|
+
register(app) {
|
|
435
|
+
app.addHook("onRequest", (ctx) => {
|
|
436
|
+
evictUntilRoom();
|
|
437
|
+
const span = adapter.startSpan(
|
|
438
|
+
"http.request",
|
|
439
|
+
{
|
|
440
|
+
method: ctx.request.method,
|
|
441
|
+
// `ctx.request.url` is absolute, because that is what a Web `Request`
|
|
442
|
+
// carries (`plugin-types.ts` says so, at length, for this reason).
|
|
443
|
+
path: new URL(ctx.request.url).pathname,
|
|
444
|
+
requestId: ctx.requestId
|
|
445
|
+
},
|
|
446
|
+
requestSpanContext(ctx.request)
|
|
447
|
+
);
|
|
448
|
+
activeSpans.set(ctx.requestId, span);
|
|
449
|
+
});
|
|
450
|
+
app.addHook("onResponse", (ctx) => {
|
|
451
|
+
const span = claim(ctx.requestId);
|
|
452
|
+
if (span === void 0) return;
|
|
453
|
+
const status = ctx.response.statusCode;
|
|
454
|
+
span.setAttribute("status", status);
|
|
455
|
+
span.setStatus("ok");
|
|
456
|
+
span.end();
|
|
457
|
+
adapter.counter("http.requests", 1, { method: ctx.request.method, status });
|
|
458
|
+
});
|
|
459
|
+
app.addHook("onError", (ctx) => {
|
|
460
|
+
const span = claim(ctx.requestId);
|
|
461
|
+
if (span === void 0) return;
|
|
462
|
+
const message = ctx.error instanceof Error ? ctx.error.message : "unknown error";
|
|
463
|
+
span.setAttribute("error", true);
|
|
464
|
+
span.setStatus("error", message);
|
|
465
|
+
span.end();
|
|
466
|
+
adapter.counter("http.errors", 1, { method: ctx.request.method });
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// src/server/observability-bootstrap.ts
|
|
473
|
+
var activeAdapter;
|
|
474
|
+
function getObservabilityAdapter() {
|
|
475
|
+
return activeAdapter;
|
|
476
|
+
}
|
|
477
|
+
function _resetObservabilityAdapter() {
|
|
478
|
+
activeAdapter = void 0;
|
|
479
|
+
}
|
|
480
|
+
function createObservabilityPluginFromConfig(observabilityConfig, env) {
|
|
481
|
+
const parsed = observabilityConfig === void 0 || observabilityConfig === null ? void 0 : observabilitySchema.parse(observabilityConfig);
|
|
482
|
+
if (parsed?.enabled === false) return void 0;
|
|
483
|
+
const cloudConfigured = Boolean(env.THEO_CLOUD_INGEST_URL) && Boolean(env.THEO_CLOUD_API_KEY);
|
|
484
|
+
if (parsed === void 0 && !cloudConfigured) return void 0;
|
|
485
|
+
const adapter = resolveAdapter({
|
|
486
|
+
env,
|
|
487
|
+
config: { provider: parsed?.provider }
|
|
488
|
+
});
|
|
489
|
+
if (adapter.name === "noop") {
|
|
490
|
+
if (parsed !== void 0) {
|
|
491
|
+
warnOnce("observability.no_exporter", {
|
|
492
|
+
event: "observability.no_exporter",
|
|
493
|
+
message: "observability is configured but no exporter resolved, so no spans will be recorded. Set THEO_CLOUD_INGEST_URL and THEO_CLOUD_API_KEY, or pass observability.provider with your own adapter. In development, NODE_ENV=development resolves the console exporter."
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
return void 0;
|
|
497
|
+
}
|
|
498
|
+
activeAdapter = adapter;
|
|
499
|
+
return createObservabilityPlugin(adapter);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
export {
|
|
503
|
+
TRACE_HEADER,
|
|
504
|
+
extractTraceId,
|
|
505
|
+
generateNewTraceContext,
|
|
506
|
+
newTraceId,
|
|
507
|
+
newSpanId,
|
|
508
|
+
requestTrace,
|
|
509
|
+
getObservabilityAdapter,
|
|
510
|
+
_resetObservabilityAdapter,
|
|
511
|
+
createObservabilityPluginFromConfig
|
|
512
|
+
};
|
|
513
|
+
//# sourceMappingURL=chunk-7PM6K5EV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/observability/trace-context-propagation.ts","../src/server/observability/span.ts","../src/server/observability/adapters/console.ts","../src/server/observability/adapters/noop.ts","../src/server/observability/otlp-serializer.ts","../src/server/observability/adapters/theo-cloud.ts","../src/server/observability/adapter-registry.ts","../src/server/http/trace-context.ts","../src/server/observability/request-trace.ts","../src/server/observability/middleware.ts","../src/server/observability-bootstrap.ts"],"sourcesContent":["// T5a.1a — Web Standards migration (leaf-first slice). Web Crypto's\n// `crypto.getRandomValues()` is available on globalThis in every supported\n// runtime per ADR-0028 (Node 22+, CF Workers, Bun, Deno, browsers). No\n// node:crypto import needed — Web Crypto returns a typed array filled with\n// CSPRNG bytes, which we hex-encode locally instead of relying on Buffer.\n\n/**\n * W3C Trace Context propagation helpers for non-HTTP carriers (job\n * leases, webhook reply headers, agent SSE frames). Works against any\n * `Headers`-shaped carrier — Web Standards only.\n *\n * The HTTP-side extractor `extractTraceId` in `../http/trace-context.ts`\n * is request-scoped and returns only the trace_id string. This module\n * exposes the full `TraceContext` shape (trace_id + span_id + flags)\n * because downstream jobs/webhooks need to propagate a NEW span_id\n * (child span) while keeping the same trace_id.\n *\n * Format spec (W3C Trace Context Level 2):\n * traceparent: version-trace_id-parent_id-trace_flags\n * - version = '00' (current)\n * - trace_id = 32 hex chars (128-bit)\n * - parent_id = 16 hex chars (64-bit) — \"span_id\" of the producer\n * - trace_flags = 2 hex chars (sampled bit)\n *\n * @see https://www.w3.org/TR/trace-context/\n */\n\nexport interface TraceContext {\n /** 32 hex chars. NEVER the reserved all-zeros value. */\n readonly trace_id: string\n /** 16 hex chars. NEVER the reserved all-zeros value. */\n readonly span_id: string\n /** 2 hex chars. Sampled bit + reserved. */\n readonly flags: string\n}\n\nconst TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/\nconst ALL_ZEROS_TRACE = '00000000000000000000000000000000'\nconst ALL_ZEROS_SPAN = '0000000000000000'\n\n/**\n * Extract a TraceContext from a Web Headers object. Returns `null` for:\n * - missing header\n * - malformed (not matching the version-trace-span-flags regex)\n * - reserved all-zeros trace_id (W3C-invalid)\n * - reserved all-zeros span_id (W3C-invalid)\n *\n * NEVER throws — defensive read.\n */\nexport function extractTraceContext(headers: Headers): TraceContext | null {\n const value = headers.get('traceparent')\n if (!value) return null\n const m = TRACEPARENT_RE.exec(value)\n if (!m) return null\n const trace_id = m[1]\n const span_id = m[2]\n const flags = m[3]\n if (trace_id === ALL_ZEROS_TRACE) return null\n if (span_id === ALL_ZEROS_SPAN) return null\n return { trace_id, span_id, flags }\n}\n\n/**\n * Write a canonical traceparent into a Web Headers object. Always\n * succeeds (defensive write — the caller is responsible for passing\n * a valid TraceContext; passing malformed input is a programming bug).\n */\nexport function injectTraceContext(headers: Headers, ctx: TraceContext): void {\n headers.set('traceparent', `00-${ctx.trace_id}-${ctx.span_id}-${ctx.flags}`)\n}\n\n/**\n * Generate a fresh TraceContext (new trace_id + span_id, flags='01' for\n * sampled). Used when no upstream traceparent exists — e.g., when a\n * cron fires or a webhook arrives without an upstream tracer.\n */\nexport function generateNewTraceContext(): TraceContext {\n return {\n trace_id: newTraceId(),\n span_id: newSpanId(),\n flags: '01',\n }\n}\n\n/**\n * A fresh 128-bit trace id, 32 hex chars, never the reserved all-zeros.\n *\n * Exported next to its span-id sibling because span identity needs the two\n * halves separately: a child span mints only an id and inherits the trace, and\n * a caller that had to mint a whole `TraceContext` to get one span id would be\n * discarding a trace id it never used. `span.ts` is the consumer.\n */\nexport function newTraceId(): string {\n return randomHex(16) // 16 bytes = 32 hex chars\n}\n\n/** A fresh 64-bit span id, 16 hex chars, never the reserved all-zeros. */\nexport function newSpanId(): string {\n return randomHex(8) // 8 bytes = 16 hex chars\n}\n\nfunction randomHex(bytes: number): string {\n // crypto.getRandomValues is overwhelmingly unlikely to produce all-zeros,\n // but we guard anyway — the W3C spec rejects all-zeros and tests assert\n // this. Web Crypto API returns a Uint8Array; we hex-encode without Buffer\n // to stay runtime-agnostic (CF Workers / Bun / Deno have no Buffer global).\n for (;;) {\n const buf = new Uint8Array(bytes)\n globalThis.crypto.getRandomValues(buf)\n let hex = ''\n for (const b of buf) hex += b.toString(16).padStart(2, '0')\n if (!/^0+$/.test(hex)) return hex\n }\n}\n","/**\n * SpanHandle implementation — records timing + attributes.\n *\n * Used by console and theo-cloud adapters. Noop adapter uses NoopSpan.\n */\nimport type { SpanHandle, SpanAttributes, SpanContextInput } from './adapters/types.js'\nimport { newSpanId, newTraceId } from './trace-context-propagation.js'\n\nexport interface SpanData {\n name: string\n /**\n * The trace this span belongs to, and the span's own id within it.\n *\n * These used to not exist, and the OTLP serializer minted a `traceId` per span\n * at export time. Every export was well-formed and every span was an island: a\n * five-span agent run reached the collector as five unrelated single-span\n * traces, so \"read the run back from an exported trace\" had nothing to read\n * (usetheokit/theokit#368). Identity belongs to the span, decided when it\n * starts, not to the exporter, guessed when it leaves.\n */\n traceId: string\n spanId: string\n /** Absent on the root span of a trace. */\n parentSpanId?: string\n attributes: Record<string, string | number | boolean>\n status: 'ok' | 'error'\n statusMessage?: string\n startTimeMs: number\n endTimeMs?: number\n durationMs?: number\n}\n\nexport class SpanImpl implements SpanHandle {\n private readonly data: SpanData\n private ended = false\n\n constructor(name: string, attributes?: SpanAttributes, context?: SpanContextInput) {\n this.data = {\n name,\n traceId: context?.traceId ?? newTraceId(),\n spanId: context?.spanId ?? newSpanId(),\n attributes: {},\n status: 'ok',\n startTimeMs: Date.now(),\n }\n if (context?.parentSpanId !== undefined) this.data.parentSpanId = context.parentSpanId\n if (attributes) {\n for (const [k, v] of Object.entries(attributes)) {\n if (v !== undefined) this.data.attributes[k] = v\n }\n }\n }\n\n setAttribute(key: string, value: string | number | boolean): void {\n if (!this.ended) this.data.attributes[key] = value\n }\n\n setStatus(status: 'ok' | 'error', message?: string): void {\n if (!this.ended) {\n this.data.status = status\n this.data.statusMessage = message\n }\n }\n\n end(): void {\n if (this.ended) return // idempotent\n this.ended = true\n this.data.endTimeMs = Date.now()\n this.data.durationMs = this.data.endTimeMs - this.data.startTimeMs\n }\n\n /** Read-only access to span data (for adapters to export). */\n getData(): SpanData {\n return { ...this.data, attributes: { ...this.data.attributes } }\n }\n\n isEnded(): boolean {\n return this.ended\n }\n}\n\n/**\n * Noop span — used by NoopAdapter and post-shutdown fallback (EC-2).\n *\n * The three empty bodies are the Null Object, not forgetfulness (agent-builder#319): **doing\n * nothing** is the contracted behaviour. Filling them with a `void 0` or a log just to silence the\n * lint would trade a readable intention for noise — and a log here would run on the post-shutdown\n * path, which is precisely where there must be no effect at all.\n */\nexport class NoopSpan implements SpanHandle {\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- Null Object, see above\n setAttribute(): void {}\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- Null Object, see above\n setStatus(): void {}\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- Null Object, see above\n end(): void {}\n}\n","/**\n * ConsoleObservabilityAdapter — dev-mode console output.\n *\n * Emits JSON-structured lines to a configurable writer (default: process.stderr).\n * Inspired by Hono middleware timing pattern.\n */\nimport { SpanImpl, NoopSpan, type SpanData } from '../span.js'\n\nimport type { ObservabilityAdapter, SpanHandle, SpanAttributes, SpanContextInput } from './types.js'\n\ninterface ConsoleAdapterOptions {\n /** Writer function — defaults to process.stderr.write. */\n write?: (line: string) => void\n}\n\nexport class ConsoleObservabilityAdapter implements ObservabilityAdapter {\n readonly name = 'console'\n private write: (line: string) => void\n private isShutdown = false\n private spans: SpanImpl[] = []\n\n constructor(options: ConsoleAdapterOptions = {}) {\n this.write = options.write ?? ((line: string) => process.stderr.write(line + '\\n'))\n }\n\n startSpan(name: string, attributes?: SpanAttributes, context?: SpanContextInput): SpanHandle {\n if (this.isShutdown) return new NoopSpan()\n const span = new SpanImpl(name, attributes, context)\n this.spans.push(span)\n return {\n setAttribute: (k, v) => {\n span.setAttribute(k, v)\n },\n setStatus: (s, m) => {\n span.setStatus(s, m)\n },\n end: () => {\n span.end()\n this.emitSpan(span.getData())\n },\n }\n }\n\n counter(name: string, value: number, attributes?: SpanAttributes): void {\n if (this.isShutdown) return\n this.emit({\n type: 'counter',\n metric: name,\n value,\n attributes: attributes ?? {},\n timestamp: Date.now(),\n })\n }\n\n histogram(name: string, value: number, attributes?: SpanAttributes): void {\n if (this.isShutdown) return\n this.emit({\n type: 'histogram',\n metric: name,\n value,\n attributes: attributes ?? {},\n timestamp: Date.now(),\n })\n }\n\n log(\n level: 'debug' | 'info' | 'warn' | 'error',\n message: string,\n attributes?: SpanAttributes,\n ): void {\n if (this.isShutdown) return\n this.emit({ type: 'log', level, message, attributes: attributes ?? {}, timestamp: Date.now() })\n }\n\n // Not `async`: this adapter writes synchronously, so there is nothing to await.\n flush(): Promise<void> {\n return Promise.resolve()\n }\n\n shutdown(): Promise<void> {\n this.isShutdown = true\n return Promise.resolve()\n }\n\n private emitSpan(data: SpanData): void {\n this.emit({\n type: 'span',\n name: data.name,\n status: data.status,\n duration_ms: data.durationMs ?? 0,\n attributes: data.attributes,\n timestamp: data.startTimeMs,\n })\n }\n\n private emit(record: Record<string, unknown>): void {\n this.write(JSON.stringify(record))\n }\n}\n","/**\n * NoopObservabilityAdapter — silent fallback.\n *\n * All methods are no-ops. Never throws, never blocks.\n * Used as the default when no other adapter is configured.\n * EC-2: startSpan after shutdown returns a noop span (no crash).\n */\nimport { NoopSpan } from '../span.js'\n\nimport type { ObservabilityAdapter, SpanHandle, SpanAttributes } from './types.js'\n\nexport class NoopObservabilityAdapter implements ObservabilityAdapter {\n readonly name = 'noop'\n private isShutdown = false\n\n startSpan(_name: string, _attributes?: SpanAttributes): SpanHandle {\n return new NoopSpan()\n }\n\n // Null Object: discarding the call IS the behaviour. An empty body is the honest\n // implementation — a fabricated one would only hide that from the next reader.\n /* eslint-disable @typescript-eslint/no-empty-function -- no-op adapter by design */\n counter(_name: string, _value: number, _attributes?: SpanAttributes): void {}\n histogram(_name: string, _value: number, _attributes?: SpanAttributes): void {}\n log(\n _level: 'debug' | 'info' | 'warn' | 'error',\n _message: string,\n _attributes?: SpanAttributes,\n ): void {}\n /* eslint-enable @typescript-eslint/no-empty-function */\n\n // Not `async`: there is nothing to await, and declaring it so would claim otherwise.\n flush(): Promise<void> {\n return Promise.resolve()\n }\n\n shutdown(): Promise<void> {\n this.isShutdown = true\n return Promise.resolve()\n }\n}\n","/**\n * Lightweight OTLP JSON serializer — ~50 LoC, no @opentelemetry/* dependency.\n *\n * Per ADR D456: in-house serializer for the theo-cloud adapter.\n * Produces valid ExportTraceServiceRequest JSON (OTLP v1.0).\n * Pinned to OTLP JSON v1.0 (stable since 2023).\n */\nimport type { SpanData } from './span.js'\n\ninterface OtlpSpan {\n traceId: string\n spanId: string\n /** Omitted on the root span — OTLP reads an absent parent as \"this is the root\". */\n parentSpanId?: string\n name: string\n kind: number\n startTimeUnixNano: string\n endTimeUnixNano: string\n attributes: {\n key: string\n value: { stringValue?: string; intValue?: string; doubleValue?: number; boolValue?: boolean }\n }[]\n status: { code: number; message?: string }\n}\n\ninterface ExportTraceServiceRequest {\n resourceSpans: [\n {\n scopeSpans: [\n {\n scope: { name: string; version: string }\n spans: OtlpSpan[]\n },\n ]\n },\n ]\n}\n\ninterface OtlpAttributeValue {\n stringValue?: string\n intValue?: string\n doubleValue?: number\n boolValue?: boolean\n}\n\n/**\n * OTLP's `AnyValue`: one field filled in, the others absent.\n *\n * It was an inline nested ternary (agent-builder#319). Extracted with a `switch`, and not flattened\n * into a cleverer ternary, because OTLP's type list is open — `arrayValue`, `doubleValue` and\n * `kvlistValue` exist in the spec and are not emitted here yet. With the `switch`, each becomes a new\n * `case`; with the ternary, each would become one more level of nesting.\n */\nfunction paraValorOtlp(value: string | number | boolean): OtlpAttributeValue {\n switch (typeof value) {\n case 'string':\n return { stringValue: value }\n case 'number':\n // usetheokit/theokit#380 — every number used to go out as `intValue`, so\n // `cost.usd` reached the collector as `{\"intValue\":\"0.0031\"}`: a string\n // that is not an integer, in the field reserved for integers. A collector\n // may reject it, coerce it to 0, or keep the string; none of those is the\n // number, and cost is the one attribute that answers what a run cost.\n //\n // `Number.isInteger` and not a decimal-point test: `2.0` IS `2` in\n // JavaScript, and making the wire shape depend on how a literal was typed\n // rather than on the value would be a stranger rule than the bug.\n return Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value }\n default:\n return { boolValue: value }\n }\n}\n\n/** Convert SpanData[] to OTLP JSON bytes (Uint8Array). */\nexport function serializeSpansToOtlp(spans: SpanData[], serviceName = 'theokit'): Uint8Array {\n const otlpSpans: OtlpSpan[] = spans.map((s) => ({\n // #368 — read, never minted. This used to call `randomHex` for both, which\n // gave every span a trace of its own and made a multi-span run unreadable at\n // the collector. The ids now arrive on the span, decided when it started.\n traceId: s.traceId,\n spanId: s.spanId,\n ...(s.parentSpanId === undefined ? {} : { parentSpanId: s.parentSpanId }),\n name: s.name,\n kind: 2, // SPAN_KIND_SERVER\n startTimeUnixNano: String(s.startTimeMs * 1_000_000),\n endTimeUnixNano: String((s.endTimeMs ?? s.startTimeMs) * 1_000_000),\n attributes: Object.entries(s.attributes).map(([key, value]) => ({\n key,\n value: paraValorOtlp(value),\n })),\n status: { code: s.status === 'ok' ? 1 : 2, message: s.statusMessage },\n }))\n\n const request: ExportTraceServiceRequest = {\n resourceSpans: [\n {\n scopeSpans: [\n {\n scope: { name: serviceName, version: '1.0.0' },\n spans: otlpSpans,\n },\n ],\n },\n ],\n }\n\n return new TextEncoder().encode(JSON.stringify(request))\n}\n","/**\n * TheoCloudObservabilityAdapter — OTLP/HTTP batched export for TheoCloud.\n *\n * Zero-config via env vars (THEO_CLOUD_INGEST_URL, THEO_CLOUD_API_KEY).\n * Batches spans and flushes via native fetch() POST.\n *\n * EC-1: flush failure logs warning, does NOT throw, does NOT retry (KISS).\n * EC-2: startSpan after shutdown returns noop span.\n */\nimport { serializeSpansToOtlp } from '../otlp-serializer.js'\nimport { SpanImpl, NoopSpan, type SpanData } from '../span.js'\n\nimport type { ObservabilityAdapter, SpanHandle, SpanAttributes, SpanContextInput } from './types.js'\n\ninterface TheoCloudAdapterOptions {\n /** TheoCloud ingest endpoint URL. */\n ingestUrl: string\n /** TheoCloud API key for authentication. */\n token: string\n /** Flush interval in ms (default: 5000). */\n flushIntervalMs?: number\n /**\n * Most spans held before the oldest are dropped (default: 10 000).\n *\n * A collector that is unreachable does not make the spans stop arriving, and a\n * buffer with no ceiling turns a telemetry outage into an out-of-memory. The\n * drop is counted rather than silent: losing data is a real cost, losing it\n * without saying so is a worse one.\n */\n maxPendingSpans?: number\n /** Mock fetch for testing (never in production). */\n _mockFetch?: typeof globalThis.fetch\n}\n\nexport class TheoCloudObservabilityAdapter implements ObservabilityAdapter {\n readonly name = 'theo-cloud'\n private pendingSpans: SpanData[] = []\n private isShutdown = false\n private dropped = 0\n private readonly flushTimer: ReturnType<typeof setInterval>\n private readonly opts: Required<\n Pick<TheoCloudAdapterOptions, 'ingestUrl' | 'token' | 'flushIntervalMs' | 'maxPendingSpans'>\n > &\n TheoCloudAdapterOptions\n\n constructor(options: TheoCloudAdapterOptions) {\n this.opts = { flushIntervalMs: 5000, maxPendingSpans: 10_000, ...options }\n\n // `flushIntervalMs` was accepted and defaulted here and read nowhere — there\n // was no timer in the file. `shutdown()` was the only drain, and nothing\n // called it, so a long-running server exported nothing at all\n // (usetheokit/theokit#353).\n //\n // `unref()` is not optional: a telemetry exporter that pins the event loop\n // turns a clean process exit into a hang, which is worse than the defect it\n // was added to fix.\n this.flushTimer = setInterval(() => {\n void this.flush()\n }, this.opts.flushIntervalMs)\n this.flushTimer.unref()\n }\n\n /** How many spans were dropped because the buffer was full. */\n droppedSpanCount(): number {\n return this.dropped\n }\n\n /**\n * Whether the periodic flush is unref'd. A test seam: \"the timer does not hold\n * the process open\" is otherwise only observable by hanging.\n */\n hasUnrefdFlushTimer(): boolean {\n return !this.flushTimer.hasRef()\n }\n\n startSpan(name: string, attributes?: SpanAttributes, context?: SpanContextInput): SpanHandle {\n if (this.isShutdown) return new NoopSpan()\n const span = new SpanImpl(name, attributes, context)\n return {\n setAttribute: (k, v) => {\n span.setAttribute(k, v)\n },\n setStatus: (s, m) => {\n span.setStatus(s, m)\n },\n end: () => {\n span.end()\n if (this.pendingSpans.length >= this.opts.maxPendingSpans) {\n this.pendingSpans.shift()\n this.dropped++\n }\n this.pendingSpans.push(span.getData())\n },\n }\n }\n\n /* eslint-disable @typescript-eslint/no-empty-function -- metrics not shipped by this adapter yet; an empty body is honest, a fabricated one is not */\n counter(_name: string, _value: number, _attributes?: SpanAttributes): void {}\n histogram(_name: string, _value: number, _attributes?: SpanAttributes): void {}\n log(\n _level: 'debug' | 'info' | 'warn' | 'error',\n _message: string,\n _attributes?: SpanAttributes,\n ): void {}\n /* eslint-enable @typescript-eslint/no-empty-function */\n\n async flush(): Promise<void> {\n if (this.isShutdown || this.pendingSpans.length === 0) return\n\n const spans = this.pendingSpans.splice(0)\n const body = serializeSpansToOtlp(spans) as unknown as BodyInit\n const fetchFn = this.opts._mockFetch ?? globalThis.fetch\n\n try {\n await fetchFn(this.opts.ingestUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${this.opts.token}`,\n },\n body,\n })\n } catch (err) {\n // EC-1: log warning, don't throw, don't retry\n console.error(\n `[theokit:observability] flush failed: ${err instanceof Error ? err.message : 'unknown error'}`,\n )\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.isShutdown) return\n // Cleared, not merely ignored: `isShutdown` would make later ticks no-ops,\n // and a live handle on a process that is trying to exit is the thing to\n // remove rather than to tolerate.\n clearInterval(this.flushTimer)\n await this.flush()\n this.isShutdown = true\n }\n}\n","/**\n * Adapter registry — resolves the active observability adapter.\n *\n * Per ADR D457 (v1.1) priority chain:\n * 1. Explicit config (theo.config.ts observability.provider) — ALWAYS wins\n * 2. THEO_CLOUD_INGEST_URL env → theo-cloud adapter\n * 3. NODE_ENV=development → console adapter\n * 4. Fallback → noop adapter\n */\nimport { ConsoleObservabilityAdapter } from './adapters/console.js'\nimport { NoopObservabilityAdapter } from './adapters/noop.js'\nimport { TheoCloudObservabilityAdapter } from './adapters/theo-cloud.js'\nimport type { ObservabilityAdapter } from './adapters/types.js'\n\ninterface ResolveAdapterOptions {\n env: Record<string, string | undefined>\n config?: {\n provider?: ObservabilityAdapter\n }\n}\n\n/**\n * Resolve the observability adapter from config + env.\n * Called once at boot — returns the active adapter for the process lifetime.\n */\nexport function resolveAdapter(options: ResolveAdapterOptions): ObservabilityAdapter {\n // 1. Explicit config ALWAYS wins (EC-4)\n if (options.config?.provider) {\n return options.config.provider\n }\n\n // 2. TheoCloud env vars → theo-cloud adapter\n const ingestUrl = options.env.THEO_CLOUD_INGEST_URL\n const apiKey = options.env.THEO_CLOUD_API_KEY\n if (ingestUrl && apiKey) {\n return new TheoCloudObservabilityAdapter({ ingestUrl, token: apiKey })\n }\n\n // 3. Development → console adapter\n if (options.env.NODE_ENV === 'development') {\n return new ConsoleObservabilityAdapter()\n }\n\n // 4. Fallback → noop\n return new NoopObservabilityAdapter()\n}\n","// T5a.1b — Web Crypto migration. randomUUID() moved to globalThis.crypto.\n// IncomingMessage stays as a type-only import (runtime-clean — TS erases at\n// build); full IncomingMessage→Request boundary migration deferred to a\n// later T5a.1c+ slice per ADR-0028 incremental leaf-first sequence.\nimport type { IncomingMessage } from 'node:http'\n\n/**\n * Phase 7 — Observability: traceId propagation (D7).\n *\n * Extract a stable identifier from incoming requests so a single value\n * correlates the client request, every server log line, the response\n * envelope, and any downstream span. Precedence:\n *\n * 1. `traceparent` (W3C Trace Context — `00-{32-hex}-{16-hex}-{flags}`)\n * 2. `x-request-id` (Heroku / GCP / generic proxy header)\n * 3. Generated UUID (fresh per request)\n *\n * UUIDs are accepted as trace identifiers by every major vendor that\n * does not enforce strict 32-hex (Datadog, Honeycomb, Sentry, Logflare,\n * Axiom, etc). We don't need ULIDs to ship this surface.\n */\n\nexport const TRACE_HEADER = 'x-trace-id'\nexport const TRACE_PARENT_HEADER = 'traceparent'\nconst REQUEST_ID_HEADER = 'x-request-id'\n\n// W3C Trace Context: 00-<trace-id 32 hex>-<span-id 16 hex>-<flags 2 hex>\nconst TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/\n\n/**\n * What a valid `traceparent` says: the trace to join, and the caller's span\n * inside it.\n *\n * Both halves are on the wire and only the first was ever read, so a span this\n * process opened for an incoming request became a SECOND root of the caller's\n * trace instead of a child of the caller's span — the trace correlated and the\n * waterfall lost its shape (usetheokit/theokit#385).\n */\nexport interface W3CTraceContext {\n /** The trace this request belongs to. 32 hex chars. */\n readonly traceId: string\n /**\n * The caller's span, which a span opened for this request hangs under.\n *\n * Absent when the caller sent the reserved all-zero parent id, which W3C\n * defines as \"no parent\" rather than as a span to point at.\n */\n readonly parentSpanId?: string\n}\n\n/**\n * Parse a W3C Trace Context `traceparent` header value into the trace it names\n * and the caller's span within it. `null` when the value is not a well-formed\n * `traceparent` or names the reserved all-zero trace.\n */\nexport function parseTraceparentContext(value: string): W3CTraceContext | null {\n if (!value) return null\n const m = TRACEPARENT_RE.exec(value)\n if (!m) return null\n const traceId = m[1]\n // W3C: trace-id of all zeroes is invalid by spec\n if (/^0+$/.test(traceId)) return null\n const parentSpanId = m[2]\n // Same rule one field over: an all-zero parent-id is the spec's way of saying\n // there is no parent, so it is dropped rather than exported as a span id no\n // backend can resolve.\n return /^0+$/.test(parentSpanId) ? { traceId } : { traceId, parentSpanId }\n}\n\n/**\n * Parse a W3C Trace Context `traceparent` header value. Returns the\n * 32-hex trace-id when valid (and not the reserved all-zeros), else\n * `null`.\n */\nexport function parseTraceparent(value: string): string | null {\n return parseTraceparentContext(value)?.traceId ?? null\n}\n\n/**\n * Shape a correlation id must have to be trusted: printable, unpunctuated beyond\n * the separators real id formats use, and bounded.\n *\n * `x-request-id` is chosen by the caller and ends up in the structured logs an\n * operator reads. Unvalidated, a newline in it splits one log line into two with\n * the second forged, and a megabyte of it is a megabyte per request through the\n * whole log pipeline (usetheokit/theokit#353). The character set covers what real\n * id formats use — UUID, ULID, hex, dotted and colon-separated ids — and excludes\n * whitespace and control characters, which no id format needs and every injection\n * does.\n *\n * 128 is comfortably above any of those formats and far below a payload.\n */\nconst REQUEST_ID_RE = /^[A-Za-z0-9_.:-]{1,128}$/\n\nfunction isTrustedRequestId(value: string): boolean {\n return REQUEST_ID_RE.test(value)\n}\n\n/**\n * Pick the first TRUSTED string value out of an IncomingMessage header. Node\n * collapses repeated headers into arrays; proxies sometimes do this for\n * `x-request-id`. Empty strings count as absent.\n *\n * \"First trusted\" rather than \"first non-empty\": taking the first value and\n * validating afterwards would let a proxy prepending a hostile value defeat a\n * good one sitting behind it.\n */\nfunction pickHeader(\n value: string | string[] | undefined,\n isTrusted: (candidate: string) => boolean = () => true,\n): string | null {\n if (Array.isArray(value)) {\n for (const v of value) {\n if (typeof v === 'string' && v.length > 0 && isTrusted(v)) return v\n }\n return null\n }\n if (typeof value === 'string' && value.length > 0 && isTrusted(value)) return value\n return null\n}\n\n/**\n * T5a.2 Phase C slice 1/2 — pure traceId resolution from pre-extracted\n * header values. Shared between IncomingMessage and Web Request wrappers.\n */\nfunction resolveTraceIdFromHeaders(traceparent: string | null, requestId: string | null): string {\n if (traceparent !== null) {\n const parsed = parseTraceparent(traceparent)\n if (parsed !== null) return parsed\n }\n if (requestId !== null) return requestId\n return globalThis.crypto.randomUUID()\n}\n\n/**\n * Resolve the request's traceId following the precedence above.\n */\nexport function extractTraceId(req: IncomingMessage): string {\n return resolveTraceIdFromHeaders(\n pickHeader(req.headers[TRACE_PARENT_HEADER]),\n pickHeader(req.headers[REQUEST_ID_HEADER], isTrustedRequestId),\n )\n}\n\n/**\n * T5a.2 Phase C slice 1/2 — Web-Standards-shaped traceId resolver.\n *\n * Mirror of `extractTraceId(req: IncomingMessage)` for the Web `Request`\n * shape. Same precedence (`traceparent` → `x-request-id` → generated\n * UUID). Uses `request.headers.get(name)` (native Web `Headers` API)\n * instead of the Node indexer.\n *\n * **Multi-value note:** Web `Headers` collapses repeated headers into a\n * single comma-separated string at parse. The IncomingMessage path's\n * `pickHeader` \"first non-empty value\" semantic is naturally satisfied\n * because there's no array to pick from on the Web side — `.get()`\n * returns the comma-joined value, which for `traceparent` / `x-request-id`\n * is treated as a single string anyway (both headers are conventionally\n * single-valued).\n */\n/**\n * The request's W3C trace context — the trace to join and the caller's span\n * within it — or `undefined` when the caller supplied no usable `traceparent`.\n *\n * Deliberately narrower than {@link extractTraceIdFromRequest}, which always\n * returns something and may return an `x-request-id` or a generated UUID. Those\n * are fine as a log correlation key and are NOT trace ids: OTLP wants 32 hex\n * characters, and a dashed UUID exported as a `traceId` is a malformed span.\n *\n * So a span-emitting caller asks this question instead — \"is there a real trace\n * to join?\" — and mints its own when the answer is no (usetheokit/theokit#368).\n *\n * It answers with the whole context rather than the trace id alone, because a\n * span opened for this request belongs in the caller's trace AND under the\n * caller's span. Returning only the first half is what made one request arrive\n * as a trace with two roots (usetheokit/theokit#385).\n */\nexport function extractW3CTraceContext(request: Request): W3CTraceContext | undefined {\n const traceparent = request.headers.get(TRACE_PARENT_HEADER)\n if (traceparent === null) return undefined\n return parseTraceparentContext(traceparent) ?? undefined\n}\n\nexport function extractTraceIdFromRequest(request: Request): string {\n const requestId = request.headers.get(REQUEST_ID_HEADER)\n return resolveTraceIdFromHeaders(\n request.headers.get(TRACE_PARENT_HEADER),\n // Same policy on both resolvers. A validation living on one side only is the\n // gap an attacker picks the other transport to reach.\n requestId !== null && isTrustedRequestId(requestId) ? requestId : null,\n )\n}\n","/**\n * One request, one trace — the side table both consumers read (usetheokit/theokit#404).\n *\n * ## The defect this exists to remove\n *\n * Two places decide what trace a request belongs to: the observability plugin, which opens the\n * `http.request` span, and `observeServedRun`, which opens `agent.run`. Both used to answer the\n * question the same way and *independently* — by reading the inbound `traceparent` header. That\n * agrees only while the header is there. A browser sends none, and neither does `curl` or an\n * uninstrumented `fetch`, so on the majority path each side took its own `?? newTraceId()` branch\n * and one request reached the collector as two disconnected traces, neither naming the other.\n *\n * Reading the same header is not sharing. This module is the sharing: the request's trace is\n * resolved ONCE, on first ask, and every later ask gets the same answer.\n *\n * ## Why a `WeakMap` keyed on the `Request`\n *\n * The two consumers already hold the same `Request` object — `serveThroughPluginLifecycle` builds\n * it once and hands that instance both to the hooks (as `PluginContext.request`) and to the\n * handler that calls `mountAgent`. So the request itself is already the shared thing, and a side\n * table keyed on it needs no new parameter threaded through `mountAgent`, no decoration contract,\n * and no signature change on either side.\n *\n * The two alternatives were weighed and rejected for reasons that outlive this comment:\n *\n * - `AsyncLocalStorage` is what an OTel Node SDK does, and it would work here — but it imports\n * `node:async_hooks`, and `server/` holds a no-`node:*` invariant precisely so the same code\n * serves the Web, Tauri and TUI targets (`rules/three-target-parity.md`). A `WeakMap` is plain\n * ECMAScript and runs unchanged on every one of them.\n * - Threading a resolved context through `mountAgent`'s options is explicit, and it puts a\n * telemetry concern in the signature of every route that might one day open a span. The entry\n * above is the same value, reachable without the parameter.\n *\n * Keying on the object also disposes of the entry: the record dies with the request, with no cap,\n * no eviction and no leak — unlike the plugin's own span map, which is keyed by `requestId` and\n * needs `evictUntilRoom` for exactly that reason.\n *\n * ## What this does NOT do\n *\n * It does not open a span, and it does not claim one was opened. `outermostSpanId` stays unset\n * until something actually emits the request's outermost span, so a run with no `http.request`\n * span in scope stays the root of its own trace rather than naming a parent this process never\n * emitted. A dangling parent reads as a span that was lost in transit, which is a worse report\n * than an honest root.\n */\nimport { extractW3CTraceContext } from '../http/trace-context.js'\n\nimport { newTraceId } from './trace-context-propagation.js'\n\nexport interface RequestTrace {\n /** The trace every span caused by this request belongs to. 32 hex chars. */\n readonly traceId: string\n /** The CALLER's span, when the caller sent a well-formed `traceparent`. */\n readonly parentSpanId?: string\n /**\n * The outermost span THIS process opened for the request, once one has been opened.\n *\n * Undefined means nothing opened one — no observability plugin on this path, or a run started\n * outside an HTTP turn. Consumers treat it as \"no local parent\", never as an id to point at.\n */\n outermostSpanId?: string\n}\n\nconst resolved = new WeakMap<Request, RequestTrace>()\n\n/**\n * The request's trace, resolved once and memoized on the request itself.\n *\n * Idempotent by construction: the first caller decides — from the inbound `traceparent` when there\n * is one, from a fresh mint when there is not — and every caller after it, on either side of the\n * request, is handed that same decision.\n */\nexport function requestTrace(request: Request): RequestTrace {\n const existing = resolved.get(request)\n if (existing !== undefined) return existing\n\n const trace = resolve(request)\n resolved.set(request, trace)\n return trace\n}\n\n/** Decide a request's trace from what it carries. Called once per request, by `requestTrace`. */\nfunction resolve(request: Request): RequestTrace {\n const inbound = extractW3CTraceContext(request)\n if (inbound === undefined) return { traceId: newTraceId() }\n if (inbound.parentSpanId === undefined) return { traceId: inbound.traceId }\n return { traceId: inbound.traceId, parentSpanId: inbound.parentSpanId }\n}\n\n/**\n * Record the span this process opened as the request's outermost one, so spans opened later in the\n * same request hang under it instead of beside it.\n *\n * First writer wins. A second outermost span for one request is a bug in the caller, and silently\n * re-pointing every later child at it would hide that bug behind a plausible waterfall.\n */\nexport function recordOutermostSpan(request: Request, spanId: string): void {\n const trace = requestTrace(request)\n trace.outermostSpanId ??= spanId\n}\n","/**\n * Auto-instrumentation plugin — one span per HTTP request.\n *\n * Per blueprint Pattern 2 (Hono middleware timing):\n * - onRequest: start span with method + path\n * - onResponse: end span with status + duration\n * - onError: set span status to error\n *\n * ## It used to be unregistrable, and nothing said so\n *\n * This returned `{ name, onRequest, onResponse, onError }` against a plugin\n * contract of `{ name, register }`, so the obvious wiring — putting it in\n * `config.plugins` — threw `InvalidPluginShapeError` at boot\n * (`../plugins/load-plugins.ts:20`). Its own context type was a second, narrower\n * invention: `request: { method, url }` where the real hook receives a Web\n * `Request` with an ABSOLUTE url, and `response?: { statusCode }` where the real\n * one is a `ServerResponse`. The tests passed because they called the hooks\n * directly with the invented shape, which verified the implementation and never\n * the contract (usetheokit/theokit#353).\n *\n * ## Span state is per-instance, and bounded\n *\n * The active-span map used to be a module-level `Map` with no cap and no TTL.\n * Two consequences, both real once anything registered this:\n *\n * - two plugin instances shared one map, so one app's response closed\n * another's span;\n * - a request whose `onResponse` never fires leaked its span forever. That is\n * not an edge case here: the SSE path is exactly where `onResponse` does not\n * fire on stream open, and an agent run is the longest-lived stream the\n * framework serves.\n *\n * The map now lives in the closure and is capped. An evicted span is ENDED with\n * an `span.abandoned` attribute rather than dropped, so it still reaches the\n * exporter carrying the reason it was cut — trading a memory leak for a silent\n * hole in the trace would be the worse bargain.\n */\nimport type { PluginContext, PluginErrorContext, TheoApp, TheoPlugin } from '../plugin-types.js'\n\nimport type { ObservabilityAdapter, SpanContextInput, SpanHandle } from './adapters/types.js'\nimport { recordOutermostSpan, requestTrace } from './request-trace.js'\nimport { newSpanId } from './trace-context-propagation.js'\n\n/**\n * How many requests may be in flight with an unclosed span before the oldest is\n * force-ended. Sized to be far above any real concurrent-request count on a\n * single Node process, so eviction signals a leak rather than back-pressure.\n */\nconst DEFAULT_MAX_ACTIVE_SPANS = 1024\n\nexport interface ObservabilityPluginOptions {\n /** Override the in-flight span cap. Mainly a test seam. */\n maxActiveSpans?: number\n}\n\nexport function createObservabilityPlugin(\n adapter: ObservabilityAdapter,\n options: ObservabilityPluginOptions = {},\n): TheoPlugin {\n const maxActiveSpans = options.maxActiveSpans ?? DEFAULT_MAX_ACTIVE_SPANS\n const activeSpans = new Map<string, SpanHandle>()\n\n /** Force-end the oldest spans until there is room for one more. */\n function evictUntilRoom(): void {\n while (activeSpans.size >= maxActiveSpans) {\n const oldest = activeSpans.keys().next()\n if (oldest.done === true) return\n const span = activeSpans.get(oldest.value)\n activeSpans.delete(oldest.value)\n if (span === undefined) continue\n span.setAttribute('span.abandoned', true)\n span.setStatus('error', 'span abandoned: onResponse never fired for this request')\n span.end()\n }\n }\n\n /**\n * Where the request's span sits: in the request's trace — the caller's when the caller sent a\n * `traceparent` (usetheokit/theokit#385), a freshly minted one otherwise — under the caller's\n * span when there is one.\n *\n * This is the OUTERMOST span of a request, which makes it precisely the caller\n * `startSpan`'s optional `context` was written for — and precisely the caller\n * that went on passing the two-argument form. The consequence was worse than\n * \"the HTTP span is a root\": once `mountAgent` learned to continue an incoming\n * trace, one request that ran an agent reached the collector as TWO\n * disconnected traces, and the caller's trace id was present on the HTTP span\n * as the `requestId` attribute rather than as its `traceId` — resolved,\n * carried, and written to a field no tracing backend correlates on.\n *\n * No `traceparent` (or a malformed one) mints a fresh trace, which is the\n * correct answer for a request nothing upstream traced — and it is minted by\n * `requestTrace`, ONCE, so the run joins that trace instead of minting a\n * second one of its own (usetheokit/theokit#404). The extraction there\n * deliberately refuses `x-request-id` and dashed UUIDs: those are fine\n * correlation keys and are not trace ids.\n */\n function requestSpanContext(request: Request): SpanContextInput {\n const trace = requestTrace(request)\n // Pinned rather than left to the adapter, because this id is what everything else the request\n // causes hangs under — `SpanContextInput.spanId` exists for exactly this caller. Recording it\n // is what makes the run a child instead of a second root (usetheokit/theokit#404).\n const spanId = newSpanId()\n recordOutermostSpan(request, spanId)\n return trace.parentSpanId === undefined\n ? { traceId: trace.traceId, spanId }\n : { traceId: trace.traceId, spanId, parentSpanId: trace.parentSpanId }\n }\n\n /** Take the span for a request, if one is still open. */\n function claim(requestId: string): SpanHandle | undefined {\n const span = activeSpans.get(requestId)\n if (span === undefined) return undefined\n activeSpans.delete(requestId)\n return span\n }\n\n return {\n name: 'theokit:observability',\n\n register(app: TheoApp): void {\n app.addHook('onRequest', (ctx: PluginContext) => {\n evictUntilRoom()\n const span = adapter.startSpan(\n 'http.request',\n {\n method: ctx.request.method,\n // `ctx.request.url` is absolute, because that is what a Web `Request`\n // carries (`plugin-types.ts` says so, at length, for this reason).\n path: new URL(ctx.request.url).pathname,\n requestId: ctx.requestId,\n },\n requestSpanContext(ctx.request),\n )\n activeSpans.set(ctx.requestId, span)\n })\n\n app.addHook('onResponse', (ctx: PluginContext) => {\n const span = claim(ctx.requestId)\n if (span === undefined) return\n\n const status = ctx.response.statusCode\n span.setAttribute('status', status)\n span.setStatus('ok')\n span.end()\n\n // Deliberately no `path` label: a counter is an aggregated series, and\n // a dynamic route would mint one series per id.\n adapter.counter('http.requests', 1, { method: ctx.request.method, status })\n })\n\n app.addHook('onError', (ctx: PluginErrorContext) => {\n const span = claim(ctx.requestId)\n if (span === undefined) return\n\n const message = ctx.error instanceof Error ? ctx.error.message : 'unknown error'\n span.setAttribute('error', true)\n span.setStatus('error', message)\n span.end()\n\n adapter.counter('http.errors', 1, { method: ctx.request.method })\n })\n },\n }\n}\n","/**\n * Build the observability plugin from `theo.config.ts > observability` + the\n * environment (#353).\n *\n * Until this existed, `createObservabilityPlugin` had no production caller and\n * `startSpan` was invoked in exactly one production file — the one nothing\n * called. Every adapter, the OTLP serializer and the span implementation were\n * tested, published and unreachable: the framework emitted no spans at all.\n *\n * ## When the plugin is wired, and one deliberate divergence\n *\n * `adapter-registry.ts` documents a four-step chain: explicit config, then\n * TheoCloud env vars, then `NODE_ENV=development` → console, then noop. This\n * function honours the first two and does NOT treat the third as an opt-in.\n *\n * The reason is that step 3 would turn telemetry on for every `theo dev` that\n * never asked for it, and the console adapter writes JSON lines to `stderr`\n * (`adapters/console.ts:23`) — the same stream `observability/logger.ts` already\n * writes a different JSON shape to. Two interleaved formats on one stream is a\n * downgrade for every developer, bought in exchange for telemetry nobody\n * requested.\n *\n * So: `observability: {}` in the config turns it on, and in dev that still\n * resolves to the console adapter exactly as the chain says. What changes is\n * that `NODE_ENV=development` alone no longer counts as asking.\n *\n * Returns `undefined` when nothing asked for telemetry, which preserves the\n * zero-plugin path for applications that configure none.\n */\nimport { observabilitySchema } from '../config/schemas/index.js'\n\nimport { resolveAdapter } from './observability/adapter-registry.js'\nimport type { ObservabilityAdapter } from './observability/adapters/types.js'\nimport { warnOnce } from './observability/logger.js'\nimport { createObservabilityPlugin } from './observability/middleware.js'\nimport type { TheoPlugin } from './plugin-types.js'\n\n/**\n * The adapter resolved at boot, for callers that are not the HTTP plugin.\n *\n * An agent run is the case that forced this: its spans are produced by\n * `observeAgentRun` from the wire chunk stream, far from the request hooks, and\n * it must be the SAME adapter — two independently resolved adapters mean two\n * exporters and two half-complete pictures of one run.\n *\n * `undefined` when nothing asked for telemetry, which is what keeps the\n * zero-cost path zero-cost.\n */\nlet activeAdapter: ObservabilityAdapter | undefined\n\nexport function getObservabilityAdapter(): ObservabilityAdapter | undefined {\n return activeAdapter\n}\n\n/** Test-only: forget the boot-resolved adapter. Production code must not call this. */\nexport function _resetObservabilityAdapter(): void {\n activeAdapter = undefined\n}\n\nexport function createObservabilityPluginFromConfig(\n observabilityConfig: unknown,\n env: Record<string, string | undefined>,\n): TheoPlugin | undefined {\n const parsed =\n observabilityConfig === undefined || observabilityConfig === null\n ? undefined\n : observabilitySchema.parse(observabilityConfig)\n\n if (parsed?.enabled === false) return undefined\n\n // An ingest URL plus a key is an explicit deployment decision, so it opts in\n // on its own — that is what makes the env half of the documented chain reachable\n // without a config file.\n const cloudConfigured = Boolean(env.THEO_CLOUD_INGEST_URL) && Boolean(env.THEO_CLOUD_API_KEY)\n if (parsed === undefined && !cloudConfigured) return undefined\n\n const adapter = resolveAdapter({\n env,\n config: { provider: parsed?.provider as ObservabilityAdapter | undefined },\n })\n\n // The registry never fails; it falls back to noop. Wiring a plugin whose every\n // hook is a no-op would cost a runner on the request path and buy nothing.\n if (adapter.name === 'noop') {\n // Silence here is the defect. An application that WROTE `observability: {}`\n // asked for telemetry, and returning quietly gives it a passing boot, no\n // spans, and nothing to search for — the config-validates-and-does-nothing\n // shape usetheokit/theokit#321 recorded for `rateLimit`.\n //\n // Only when it was asked for: an application that configured nothing is not\n // owed a warning about a thing it never requested.\n if (parsed !== undefined) {\n warnOnce('observability.no_exporter', {\n event: 'observability.no_exporter',\n message:\n 'observability is configured but no exporter resolved, so no spans will be recorded. ' +\n 'Set THEO_CLOUD_INGEST_URL and THEO_CLOUD_API_KEY, or pass observability.provider with ' +\n 'your own adapter. In development, NODE_ENV=development resolves the console exporter.',\n })\n }\n return undefined\n }\n\n activeAdapter = adapter\n return createObservabilityPlugin(adapter)\n}\n"],"mappings":";;;;;;;;;;AA4EO,SAAS,0BAAwC;AACtD,SAAO;AAAA,IACL,UAAU,WAAW;AAAA,IACrB,SAAS,UAAU;AAAA,IACnB,OAAO;AAAA,EACT;AACF;AAUO,SAAS,aAAqB;AACnC,SAAO,UAAU,EAAE;AACrB;AAGO,SAAS,YAAoB;AAClC,SAAO,UAAU,CAAC;AACpB;AAEA,SAAS,UAAU,OAAuB;AAKxC,aAAS;AACP,UAAM,MAAM,IAAI,WAAW,KAAK;AAChC,eAAW,OAAO,gBAAgB,GAAG;AACrC,QAAI,MAAM;AACV,eAAW,KAAK,IAAK,QAAO,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC1D,QAAI,CAAC,OAAO,KAAK,GAAG,EAAG,QAAO;AAAA,EAChC;AACF;;;ACjFO,IAAM,WAAN,MAAqC;AAAA,EACzB;AAAA,EACT,QAAQ;AAAA,EAEhB,YAAY,MAAc,YAA6B,SAA4B;AACjF,SAAK,OAAO;AAAA,MACV;AAAA,MACA,SAAS,SAAS,WAAW,WAAW;AAAA,MACxC,QAAQ,SAAS,UAAU,UAAU;AAAA,MACrC,YAAY,CAAC;AAAA,MACb,QAAQ;AAAA,MACR,aAAa,KAAK,IAAI;AAAA,IACxB;AACA,QAAI,SAAS,iBAAiB,OAAW,MAAK,KAAK,eAAe,QAAQ;AAC1E,QAAI,YAAY;AACd,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC/C,YAAI,MAAM,OAAW,MAAK,KAAK,WAAW,CAAC,IAAI;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa,KAAa,OAAwC;AAChE,QAAI,CAAC,KAAK,MAAO,MAAK,KAAK,WAAW,GAAG,IAAI;AAAA,EAC/C;AAAA,EAEA,UAAU,QAAwB,SAAwB;AACxD,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,KAAK,SAAS;AACnB,WAAK,KAAK,gBAAgB;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,MAAY;AACV,QAAI,KAAK,MAAO;AAChB,SAAK,QAAQ;AACb,SAAK,KAAK,YAAY,KAAK,IAAI;AAC/B,SAAK,KAAK,aAAa,KAAK,KAAK,YAAY,KAAK,KAAK;AAAA,EACzD;AAAA;AAAA,EAGA,UAAoB;AAClB,WAAO,EAAE,GAAG,KAAK,MAAM,YAAY,EAAE,GAAG,KAAK,KAAK,WAAW,EAAE;AAAA,EACjE;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK;AAAA,EACd;AACF;AAUO,IAAM,WAAN,MAAqC;AAAA;AAAA,EAE1C,eAAqB;AAAA,EAAC;AAAA;AAAA,EAEtB,YAAkB;AAAA,EAAC;AAAA;AAAA,EAEnB,MAAY;AAAA,EAAC;AACf;;;ACjFO,IAAM,8BAAN,MAAkE;AAAA,EAC9D,OAAO;AAAA,EACR;AAAA,EACA,aAAa;AAAA,EACb,QAAoB,CAAC;AAAA,EAE7B,YAAY,UAAiC,CAAC,GAAG;AAC/C,SAAK,QAAQ,QAAQ,UAAU,CAAC,SAAiB,QAAQ,OAAO,MAAM,OAAO,IAAI;AAAA,EACnF;AAAA,EAEA,UAAU,MAAc,YAA6B,SAAwC;AAC3F,QAAI,KAAK,WAAY,QAAO,IAAI,SAAS;AACzC,UAAM,OAAO,IAAI,SAAS,MAAM,YAAY,OAAO;AACnD,SAAK,MAAM,KAAK,IAAI;AACpB,WAAO;AAAA,MACL,cAAc,CAAC,GAAG,MAAM;AACtB,aAAK,aAAa,GAAG,CAAC;AAAA,MACxB;AAAA,MACA,WAAW,CAAC,GAAG,MAAM;AACnB,aAAK,UAAU,GAAG,CAAC;AAAA,MACrB;AAAA,MACA,KAAK,MAAM;AACT,aAAK,IAAI;AACT,aAAK,SAAS,KAAK,QAAQ,CAAC;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAQ,MAAc,OAAe,YAAmC;AACtE,QAAI,KAAK,WAAY;AACrB,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,QAAQ;AAAA,MACR;AAAA,MACA,YAAY,cAAc,CAAC;AAAA,MAC3B,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,MAAc,OAAe,YAAmC;AACxE,QAAI,KAAK,WAAY;AACrB,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,QAAQ;AAAA,MACR;AAAA,MACA,YAAY,cAAc,CAAC;AAAA,MAC3B,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEA,IACE,OACA,SACA,YACM;AACN,QAAI,KAAK,WAAY;AACrB,SAAK,KAAK,EAAE,MAAM,OAAO,OAAO,SAAS,YAAY,cAAc,CAAC,GAAG,WAAW,KAAK,IAAI,EAAE,CAAC;AAAA,EAChG;AAAA;AAAA,EAGA,QAAuB;AACrB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,WAA0B;AACxB,SAAK,aAAa;AAClB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEQ,SAAS,MAAsB;AACrC,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,aAAa,KAAK,cAAc;AAAA,MAChC,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,IAClB,CAAC;AAAA,EACH;AAAA,EAEQ,KAAK,QAAuC;AAClD,SAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AAAA,EACnC;AACF;;;ACvFO,IAAM,2BAAN,MAA+D;AAAA,EAC3D,OAAO;AAAA,EACR,aAAa;AAAA,EAErB,UAAU,OAAe,aAA0C;AACjE,WAAO,IAAI,SAAS;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,OAAe,QAAgB,aAAoC;AAAA,EAAC;AAAA,EAC5E,UAAU,OAAe,QAAgB,aAAoC;AAAA,EAAC;AAAA,EAC9E,IACE,QACA,UACA,aACM;AAAA,EAAC;AAAA;AAAA;AAAA,EAIT,QAAuB;AACrB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,WAA0B;AACxB,SAAK,aAAa;AAClB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;;;ACaA,SAAS,cAAc,OAAsD;AAC3E,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AACH,aAAO,EAAE,aAAa,MAAM;AAAA,IAC9B,KAAK;AAUH,aAAO,OAAO,UAAU,KAAK,IAAI,EAAE,UAAU,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,MAAM;AAAA,IACtF;AACE,aAAO,EAAE,WAAW,MAAM;AAAA,EAC9B;AACF;AAGO,SAAS,qBAAqB,OAAmB,cAAc,WAAuB;AAC3F,QAAM,YAAwB,MAAM,IAAI,CAAC,OAAO;AAAA;AAAA;AAAA;AAAA,IAI9C,SAAS,EAAE;AAAA,IACX,QAAQ,EAAE;AAAA,IACV,GAAI,EAAE,iBAAiB,SAAY,CAAC,IAAI,EAAE,cAAc,EAAE,aAAa;AAAA,IACvE,MAAM,EAAE;AAAA,IACR,MAAM;AAAA;AAAA,IACN,mBAAmB,OAAO,EAAE,cAAc,GAAS;AAAA,IACnD,iBAAiB,QAAQ,EAAE,aAAa,EAAE,eAAe,GAAS;AAAA,IAClE,YAAY,OAAO,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO;AAAA,MAC9D;AAAA,MACA,OAAO,cAAc,KAAK;AAAA,IAC5B,EAAE;AAAA,IACF,QAAQ,EAAE,MAAM,EAAE,WAAW,OAAO,IAAI,GAAG,SAAS,EAAE,cAAc;AAAA,EACtE,EAAE;AAEF,QAAM,UAAqC;AAAA,IACzC,eAAe;AAAA,MACb;AAAA,QACE,YAAY;AAAA,UACV;AAAA,YACE,OAAO,EAAE,MAAM,aAAa,SAAS,QAAQ;AAAA,YAC7C,OAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,IAAI,YAAY,EAAE,OAAO,KAAK,UAAU,OAAO,CAAC;AACzD;;;ACzEO,IAAM,gCAAN,MAAoE;AAAA,EAChE,OAAO;AAAA,EACR,eAA2B,CAAC;AAAA,EAC5B,aAAa;AAAA,EACb,UAAU;AAAA,EACD;AAAA,EACA;AAAA,EAKjB,YAAY,SAAkC;AAC5C,SAAK,OAAO,EAAE,iBAAiB,KAAM,iBAAiB,KAAQ,GAAG,QAAQ;AAUzE,SAAK,aAAa,YAAY,MAAM;AAClC,WAAK,KAAK,MAAM;AAAA,IAClB,GAAG,KAAK,KAAK,eAAe;AAC5B,SAAK,WAAW,MAAM;AAAA,EACxB;AAAA;AAAA,EAGA,mBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,sBAA+B;AAC7B,WAAO,CAAC,KAAK,WAAW,OAAO;AAAA,EACjC;AAAA,EAEA,UAAU,MAAc,YAA6B,SAAwC;AAC3F,QAAI,KAAK,WAAY,QAAO,IAAI,SAAS;AACzC,UAAM,OAAO,IAAI,SAAS,MAAM,YAAY,OAAO;AACnD,WAAO;AAAA,MACL,cAAc,CAAC,GAAG,MAAM;AACtB,aAAK,aAAa,GAAG,CAAC;AAAA,MACxB;AAAA,MACA,WAAW,CAAC,GAAG,MAAM;AACnB,aAAK,UAAU,GAAG,CAAC;AAAA,MACrB;AAAA,MACA,KAAK,MAAM;AACT,aAAK,IAAI;AACT,YAAI,KAAK,aAAa,UAAU,KAAK,KAAK,iBAAiB;AACzD,eAAK,aAAa,MAAM;AACxB,eAAK;AAAA,QACP;AACA,aAAK,aAAa,KAAK,KAAK,QAAQ,CAAC;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,QAAQ,OAAe,QAAgB,aAAoC;AAAA,EAAC;AAAA,EAC5E,UAAU,OAAe,QAAgB,aAAoC;AAAA,EAAC;AAAA,EAC9E,IACE,QACA,UACA,aACM;AAAA,EAAC;AAAA;AAAA,EAGT,MAAM,QAAuB;AAC3B,QAAI,KAAK,cAAc,KAAK,aAAa,WAAW,EAAG;AAEvD,UAAM,QAAQ,KAAK,aAAa,OAAO,CAAC;AACxC,UAAM,OAAO,qBAAqB,KAAK;AACvC,UAAM,UAAU,KAAK,KAAK,cAAc,WAAW;AAEnD,QAAI;AACF,YAAM,QAAQ,KAAK,KAAK,WAAW;AAAA,QACjC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,KAAK,KAAK,KAAK;AAAA,QAC1C;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,yCAAyC,eAAe,QAAQ,IAAI,UAAU,eAAe;AAAA,MAC/F;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAC9B,QAAI,KAAK,WAAY;AAIrB,kBAAc,KAAK,UAAU;AAC7B,UAAM,KAAK,MAAM;AACjB,SAAK,aAAa;AAAA,EACpB;AACF;;;AClHO,SAAS,eAAe,SAAsD;AAEnF,MAAI,QAAQ,QAAQ,UAAU;AAC5B,WAAO,QAAQ,OAAO;AAAA,EACxB;AAGA,QAAM,YAAY,QAAQ,IAAI;AAC9B,QAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,aAAa,QAAQ;AACvB,WAAO,IAAI,8BAA8B,EAAE,WAAW,OAAO,OAAO,CAAC;AAAA,EACvE;AAGA,MAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,WAAO,IAAI,4BAA4B;AAAA,EACzC;AAGA,SAAO,IAAI,yBAAyB;AACtC;;;ACvBO,IAAM,eAAe;AACrB,IAAM,sBAAsB;AACnC,IAAM,oBAAoB;AAG1B,IAAM,iBAAiB;AA4BhB,SAAS,wBAAwB,OAAuC;AAC7E,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,IAAI,eAAe,KAAK,KAAK;AACnC,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,UAAU,EAAE,CAAC;AAEnB,MAAI,OAAO,KAAK,OAAO,EAAG,QAAO;AACjC,QAAM,eAAe,EAAE,CAAC;AAIxB,SAAO,OAAO,KAAK,YAAY,IAAI,EAAE,QAAQ,IAAI,EAAE,SAAS,aAAa;AAC3E;AAOO,SAAS,iBAAiB,OAA8B;AAC7D,SAAO,wBAAwB,KAAK,GAAG,WAAW;AACpD;AAgBA,IAAM,gBAAgB;AAEtB,SAAS,mBAAmB,OAAwB;AAClD,SAAO,cAAc,KAAK,KAAK;AACjC;AAWA,SAAS,WACP,OACA,YAA4C,MAAM,MACnC;AACf,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAW,KAAK,OAAO;AACrB,UAAI,OAAO,MAAM,YAAY,EAAE,SAAS,KAAK,UAAU,CAAC,EAAG,QAAO;AAAA,IACpE;AACA,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY,MAAM,SAAS,KAAK,UAAU,KAAK,EAAG,QAAO;AAC9E,SAAO;AACT;AAMA,SAAS,0BAA0B,aAA4B,WAAkC;AAC/F,MAAI,gBAAgB,MAAM;AACxB,UAAM,SAAS,iBAAiB,WAAW;AAC3C,QAAI,WAAW,KAAM,QAAO;AAAA,EAC9B;AACA,MAAI,cAAc,KAAM,QAAO;AAC/B,SAAO,WAAW,OAAO,WAAW;AACtC;AAKO,SAAS,eAAe,KAA8B;AAC3D,SAAO;AAAA,IACL,WAAW,IAAI,QAAQ,mBAAmB,CAAC;AAAA,IAC3C,WAAW,IAAI,QAAQ,iBAAiB,GAAG,kBAAkB;AAAA,EAC/D;AACF;AAmCO,SAAS,uBAAuB,SAA+C;AACpF,QAAM,cAAc,QAAQ,QAAQ,IAAI,mBAAmB;AAC3D,MAAI,gBAAgB,KAAM,QAAO;AACjC,SAAO,wBAAwB,WAAW,KAAK;AACjD;;;ACtHA,IAAM,WAAW,oBAAI,QAA+B;AAS7C,SAAS,aAAa,SAAgC;AAC3D,QAAM,WAAW,SAAS,IAAI,OAAO;AACrC,MAAI,aAAa,OAAW,QAAO;AAEnC,QAAM,QAAQ,QAAQ,OAAO;AAC7B,WAAS,IAAI,SAAS,KAAK;AAC3B,SAAO;AACT;AAGA,SAAS,QAAQ,SAAgC;AAC/C,QAAM,UAAU,uBAAuB,OAAO;AAC9C,MAAI,YAAY,OAAW,QAAO,EAAE,SAAS,WAAW,EAAE;AAC1D,MAAI,QAAQ,iBAAiB,OAAW,QAAO,EAAE,SAAS,QAAQ,QAAQ;AAC1E,SAAO,EAAE,SAAS,QAAQ,SAAS,cAAc,QAAQ,aAAa;AACxE;AASO,SAAS,oBAAoB,SAAkB,QAAsB;AAC1E,QAAM,QAAQ,aAAa,OAAO;AAClC,QAAM,oBAAoB;AAC5B;;;ACnDA,IAAM,2BAA2B;AAO1B,SAAS,0BACd,SACA,UAAsC,CAAC,GAC3B;AACZ,QAAM,iBAAiB,QAAQ,kBAAkB;AACjD,QAAM,cAAc,oBAAI,IAAwB;AAGhD,WAAS,iBAAuB;AAC9B,WAAO,YAAY,QAAQ,gBAAgB;AACzC,YAAM,SAAS,YAAY,KAAK,EAAE,KAAK;AACvC,UAAI,OAAO,SAAS,KAAM;AAC1B,YAAM,OAAO,YAAY,IAAI,OAAO,KAAK;AACzC,kBAAY,OAAO,OAAO,KAAK;AAC/B,UAAI,SAAS,OAAW;AACxB,WAAK,aAAa,kBAAkB,IAAI;AACxC,WAAK,UAAU,SAAS,yDAAyD;AACjF,WAAK,IAAI;AAAA,IACX;AAAA,EACF;AAuBA,WAAS,mBAAmB,SAAoC;AAC9D,UAAM,QAAQ,aAAa,OAAO;AAIlC,UAAM,SAAS,UAAU;AACzB,wBAAoB,SAAS,MAAM;AACnC,WAAO,MAAM,iBAAiB,SAC1B,EAAE,SAAS,MAAM,SAAS,OAAO,IACjC,EAAE,SAAS,MAAM,SAAS,QAAQ,cAAc,MAAM,aAAa;AAAA,EACzE;AAGA,WAAS,MAAM,WAA2C;AACxD,UAAM,OAAO,YAAY,IAAI,SAAS;AACtC,QAAI,SAAS,OAAW,QAAO;AAC/B,gBAAY,OAAO,SAAS;AAC5B,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,SAAS,KAAoB;AAC3B,UAAI,QAAQ,aAAa,CAAC,QAAuB;AAC/C,uBAAe;AACf,cAAM,OAAO,QAAQ;AAAA,UACnB;AAAA,UACA;AAAA,YACE,QAAQ,IAAI,QAAQ;AAAA;AAAA;AAAA,YAGpB,MAAM,IAAI,IAAI,IAAI,QAAQ,GAAG,EAAE;AAAA,YAC/B,WAAW,IAAI;AAAA,UACjB;AAAA,UACA,mBAAmB,IAAI,OAAO;AAAA,QAChC;AACA,oBAAY,IAAI,IAAI,WAAW,IAAI;AAAA,MACrC,CAAC;AAED,UAAI,QAAQ,cAAc,CAAC,QAAuB;AAChD,cAAM,OAAO,MAAM,IAAI,SAAS;AAChC,YAAI,SAAS,OAAW;AAExB,cAAM,SAAS,IAAI,SAAS;AAC5B,aAAK,aAAa,UAAU,MAAM;AAClC,aAAK,UAAU,IAAI;AACnB,aAAK,IAAI;AAIT,gBAAQ,QAAQ,iBAAiB,GAAG,EAAE,QAAQ,IAAI,QAAQ,QAAQ,OAAO,CAAC;AAAA,MAC5E,CAAC;AAED,UAAI,QAAQ,WAAW,CAAC,QAA4B;AAClD,cAAM,OAAO,MAAM,IAAI,SAAS;AAChC,YAAI,SAAS,OAAW;AAExB,cAAM,UAAU,IAAI,iBAAiB,QAAQ,IAAI,MAAM,UAAU;AACjE,aAAK,aAAa,SAAS,IAAI;AAC/B,aAAK,UAAU,SAAS,OAAO;AAC/B,aAAK,IAAI;AAET,gBAAQ,QAAQ,eAAe,GAAG,EAAE,QAAQ,IAAI,QAAQ,OAAO,CAAC;AAAA,MAClE,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;ACpHA,IAAI;AAEG,SAAS,0BAA4D;AAC1E,SAAO;AACT;AAGO,SAAS,6BAAmC;AACjD,kBAAgB;AAClB;AAEO,SAAS,oCACd,qBACA,KACwB;AACxB,QAAM,SACJ,wBAAwB,UAAa,wBAAwB,OACzD,SACA,oBAAoB,MAAM,mBAAmB;AAEnD,MAAI,QAAQ,YAAY,MAAO,QAAO;AAKtC,QAAM,kBAAkB,QAAQ,IAAI,qBAAqB,KAAK,QAAQ,IAAI,kBAAkB;AAC5F,MAAI,WAAW,UAAa,CAAC,gBAAiB,QAAO;AAErD,QAAM,UAAU,eAAe;AAAA,IAC7B;AAAA,IACA,QAAQ,EAAE,UAAU,QAAQ,SAA6C;AAAA,EAC3E,CAAC;AAID,MAAI,QAAQ,SAAS,QAAQ;AAQ3B,QAAI,WAAW,QAAW;AACxB,eAAS,6BAA6B;AAAA,QACpC,OAAO;AAAA,QACP,SACE;AAAA,MAGJ,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAEA,kBAAgB;AAChB,SAAO,0BAA0B,OAAO;AAC1C;","names":[]}
|