@cc-monitoring/proxy-core 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/__tests__/commands.test.js +19 -0
- package/dist/cli/commands/repair.d.ts +1 -0
- package/dist/cli/commands/repair.js +15 -0
- package/dist/cli/index.js +30 -0
- package/dist/docs/404.html +1 -1
- package/dist/docs/assets/{app.DtYNT5zS.js → app.vxoC6jUT.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.lKm6N3Ik.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.DpXF9ZAI.js → VPLocalSearchBox.DrfGpz86.js} +1 -1
- package/dist/docs/assets/chunks/{theme.TS_gUyc7.js → theme.CCmzbSn9.js} +2 -2
- package/dist/docs/index.html +2 -2
- package/dist/docs/overview.html +2 -2
- package/dist/docs/packages-utils.html +2 -2
- package/dist/docs/proxy-admin/env-and-build.html +2 -2
- package/dist/docs/proxy-admin/index.html +2 -2
- package/dist/docs/proxy-admin/layout-and-menu.html +2 -2
- package/dist/docs/proxy-admin/pages.html +2 -2
- package/dist/docs/proxy-admin/routing-and-auth.html +2 -2
- package/dist/docs/proxy-admin/services-and-mock.html +2 -2
- package/dist/docs/proxy-cli/api-layer.html +2 -2
- package/dist/docs/proxy-cli/app-shell.html +2 -2
- package/dist/docs/proxy-cli/components-common.html +2 -2
- package/dist/docs/proxy-cli/components-config.html +2 -2
- package/dist/docs/proxy-cli/components-requests.html +2 -2
- package/dist/docs/proxy-cli/components-stats.html +2 -2
- package/dist/docs/proxy-cli/components-status.html +2 -2
- package/dist/docs/proxy-cli/data-hooks.html +2 -2
- package/dist/docs/proxy-cli/index.html +2 -2
- package/dist/docs/proxy-cli/utils-and-i18n.html +2 -2
- package/dist/docs/proxy-core/chat-api.html +2 -2
- package/dist/docs/proxy-core/cli.html +2 -2
- package/dist/docs/proxy-core/config.html +2 -2
- package/dist/docs/proxy-core/data-layer.html +2 -2
- package/dist/docs/proxy-core/entry.html +2 -2
- package/dist/docs/proxy-core/index.html +2 -2
- package/dist/docs/proxy-core/pm2.html +2 -2
- package/dist/docs/proxy-core/providers.html +2 -2
- package/dist/docs/proxy-core/proxy.html +2 -2
- package/dist/docs/proxy-core/stats.html +2 -2
- package/dist/docs/proxy-core/tool.html +2 -2
- package/dist/docs/proxy-core/ui-routes.html +2 -2
- package/dist/docs/proxy-core/utilities.html +2 -2
- package/dist/docs/quickstart.html +2 -2
- package/dist/docs/request-flow.html +2 -2
- package/dist/server/__tests__/data-push.test.js +44 -0
- package/dist/server/__tests__/proxy.test.js +365 -2
- package/dist/server/__tests__/server.test.js +15 -10
- package/dist/server/__tests__/ui-route.test.js +43 -0
- package/dist/server/chat-route.js +3 -3
- package/dist/server/data-push.d.ts +2 -0
- package/dist/server/data-push.js +22 -0
- package/dist/server/index.js +4 -3
- package/dist/server/proxy.js +127 -23
- package/dist/server/ui-route.js +8 -1
- package/dist/ui/assets/{1c-CCx-FOtz.js → 1c-BdWVxVKv.js} +1 -1
- package/dist/ui/assets/{abnf-Bwbi42Z8.js → abnf-hHBtR6kN.js} +1 -1
- package/dist/ui/assets/{abnfDiagram-VRR7QNED-Dm1-8q0E.js → abnfDiagram-VRR7QNED-B0E8zzLB.js} +1 -1
- package/dist/ui/assets/{accesslog-DCytz_-m.js → accesslog-BZmvPz-q.js} +1 -1
- package/dist/ui/assets/{actionscript-3udf15oh.js → actionscript-XtUFCVQF.js} +1 -1
- package/dist/ui/assets/{ada-M5Xa74xG.js → ada-DDsWH3P3.js} +1 -1
- package/dist/ui/assets/{angelscript-qlrFxfW-.js → angelscript-CGLPsuae.js} +1 -1
- package/dist/ui/assets/{apache-B-sF-DQH.js → apache-eGe6GEfx.js} +1 -1
- package/dist/ui/assets/{applescript-4FdcBnbI.js → applescript-Ch2Hdkz_.js} +1 -1
- package/dist/ui/assets/{arc-BB3K1enp.js → arc-Bi_rJJly.js} +1 -1
- package/dist/ui/assets/{arcade-B_yqWaaG.js → arcade-BAeq_5jU.js} +1 -1
- package/dist/ui/assets/{architectureDiagram-ZJ3FMSHR-B39vkY8V.js → architectureDiagram-ZJ3FMSHR-D3rUGwDS.js} +1 -1
- package/dist/ui/assets/{arduino-yAcBoTWU.js → arduino-DJR8nayp.js} +1 -1
- package/dist/ui/assets/{armasm-wIcY84bI.js → armasm-DqDD_ZDN.js} +1 -1
- package/dist/ui/assets/{asciidoc-Bxnu28-Z.js → asciidoc-CgBdhmR5.js} +1 -1
- package/dist/ui/assets/{aspectj-B2cKJA_O.js → aspectj-Dbm_6mY0.js} +1 -1
- package/dist/ui/assets/{autohotkey-B_rMWTtE.js → autohotkey-BkbluSS8.js} +1 -1
- package/dist/ui/assets/{autoit-DwcuvMwv.js → autoit-qUepyZBT.js} +1 -1
- package/dist/ui/assets/{avrasm-heGX1PXK.js → avrasm-2snPxE5L.js} +1 -1
- package/dist/ui/assets/{awk-BiqCQAEf.js → awk-oPcQTdJK.js} +1 -1
- package/dist/ui/assets/{axapta-Cv8M-Ih6.js → axapta-CCu7hfQ-.js} +1 -1
- package/dist/ui/assets/{bash-Divgn3JV.js → bash-CmWN3rPR.js} +1 -1
- package/dist/ui/assets/{basic-B9dnAP55.js → basic-Dg8KcxuC.js} +1 -1
- package/dist/ui/assets/{blockDiagram-677ZJIJ3-DQ1mf7A_.js → blockDiagram-677ZJIJ3-Dusa5zr8.js} +1 -1
- package/dist/ui/assets/{bnf-kIL5mSsP.js → bnf-Zmfygl9A.js} +1 -1
- package/dist/ui/assets/{brainfuck-DqB7xDjH.js → brainfuck-K4-sBD6i.js} +1 -1
- package/dist/ui/assets/{coq-6aKUn3zn.js → c-BGtacyfP.js} +1 -1
- package/dist/ui/assets/{c-like-De5MhE7G.js → c-like-FRDCqB2X.js} +1 -1
- package/dist/ui/assets/{c4Diagram-LMCZKHZV-DQxtYsAx.js → c4Diagram-LMCZKHZV-C4Vo5RAI.js} +1 -1
- package/dist/ui/assets/{cal-mYdfz9en.js → cal-BibfnL8Q.js} +1 -1
- package/dist/ui/assets/{capnproto-D04CRlOt.js → capnproto-D4sJA0ax.js} +1 -1
- package/dist/ui/assets/{ceylon-pi9lFCja.js → ceylon-DuI5ot57.js} +1 -1
- package/dist/ui/assets/channel-CviGbONW.js +1 -0
- package/dist/ui/assets/{chunk-2Q5K7J3B-BDD1nPt8.js → chunk-2Q5K7J3B-C0UTs_LW.js} +1 -1
- package/dist/ui/assets/{chunk-32BRIVSS-DgeQFBb5.js → chunk-32BRIVSS-BMqPhehD.js} +1 -1
- package/dist/ui/assets/{chunk-5VM5RSS4-C7Xf2SnI.js → chunk-5VM5RSS4-CKN4Vw1w.js} +1 -1
- package/dist/ui/assets/{chunk-EX3LRPZG-B_3p1HEv.js → chunk-EX3LRPZG-BYHH22fs.js} +1 -1
- package/dist/ui/assets/{chunk-JWPE2WC7-Dvs7u8eY.js → chunk-JWPE2WC7-b55Vo5mo.js} +1 -1
- package/dist/ui/assets/{chunk-MOJQB5TN-By21wDCN.js → chunk-MOJQB5TN-CvtnHxi4.js} +1 -1
- package/dist/ui/assets/{chunk-RYQCIY6F-6NC700r1.js → chunk-RYQCIY6F-Bi9_eYfb.js} +1 -1
- package/dist/ui/assets/{chunk-V7JOEXUC-vEUqZ3rh.js → chunk-V7JOEXUC-C3ujZT8O.js} +1 -1
- package/dist/ui/assets/{chunk-VR4S4FIN-6tX2dNN9.js → chunk-VR4S4FIN-D4pfDh-j.js} +1 -1
- package/dist/ui/assets/{chunk-XXDRQBXY-qDb2jxAR.js → chunk-XXDRQBXY-DQAjg3aO.js} +1 -1
- package/dist/ui/assets/classDiagram-OUVF2IWQ-BlFcpmEd.js +1 -0
- package/dist/ui/assets/classDiagram-v2-EOCWNBFH-BlFcpmEd.js +1 -0
- package/dist/ui/assets/{clean-CLCsDUl1.js → clean-BVmfQBBV.js} +1 -1
- package/dist/ui/assets/{clojure-dVi5Xifj.js → clojure-BN3C1fnU.js} +1 -1
- package/dist/ui/assets/{clojure-repl-BO_FpFmF.js → clojure-repl-C7Gg0UPF.js} +1 -1
- package/dist/ui/assets/{cmake-CP5aJbyK.js → cmake-CTQFRyul.js} +1 -1
- package/dist/ui/assets/{coffeescript-ZEfu_9pF.js → coffeescript-DGWU3k3W.js} +1 -1
- package/dist/ui/assets/{c-HmsCM6sx.js → coq-Bv9CXGly.js} +1 -1
- package/dist/ui/assets/{cos-BohCnRN2.js → cos-JXNeNyLn.js} +1 -1
- package/dist/ui/assets/{cose-bilkent-JH36ORCC-DyXCbbro.js → cose-bilkent-JH36ORCC-B2e-rPVN.js} +1 -1
- package/dist/ui/assets/{cpp-FOgPWPEt.js → cpp-DVS4QZP-.js} +1 -1
- package/dist/ui/assets/{crmsh-B0OYb-Oe.js → crmsh-CFD7lrxk.js} +1 -1
- package/dist/ui/assets/{crystal-CuWb_dXm.js → crystal-D7vS7dho.js} +1 -1
- package/dist/ui/assets/{csharp-BbcqM09j.js → csharp-BgeVxKaT.js} +1 -1
- package/dist/ui/assets/{csp-rgHnTaDq.js → csp-CmAkjXvi.js} +1 -1
- package/dist/ui/assets/{css-C-ibh7ZG.js → css-DtEkZRCq.js} +1 -1
- package/dist/ui/assets/{cynefin-VYW2F7L2-CkuBhgC4.js → cynefin-VYW2F7L2-bhneX2QQ.js} +1 -1
- package/dist/ui/assets/{cynefinDiagram-TSTJHNR4-eycFyDao.js → cynefinDiagram-TSTJHNR4-BvtRhsVM.js} +1 -1
- package/dist/ui/assets/{d-C0gXxJ0O.js → d-ov1MlWJx.js} +1 -1
- package/dist/ui/assets/{dagre-VKFMJZFB-DzqX9e49.js → dagre-VKFMJZFB-nxN1qAKi.js} +1 -1
- package/dist/ui/assets/{dart-C-fTpuUV.js → dart-DX6s604e.js} +1 -1
- package/dist/ui/assets/{delphi-Chm0B9xv.js → delphi-D0oU57Jt.js} +1 -1
- package/dist/ui/assets/{diagram-FQU43EPY-BEgCqfg1.js → diagram-FQU43EPY-CWkdysy2.js} +1 -1
- package/dist/ui/assets/{diagram-G47NLZAW-Cw11Vs2v.js → diagram-G47NLZAW-L7jPJ-r1.js} +1 -1
- package/dist/ui/assets/{diagram-NH7WQ7WH-DSG_UWpP.js → diagram-NH7WQ7WH-fhOp1mr9.js} +1 -1
- package/dist/ui/assets/{diagram-OA4YK3LP-CJz-WOaJ.js → diagram-OA4YK3LP-B7UMZ-5d.js} +1 -1
- package/dist/ui/assets/{diagram-WEI45ONY-CBXjBCvc.js → diagram-WEI45ONY-B-toJrZu.js} +1 -1
- package/dist/ui/assets/{diff-C-vyuMSL.js → diff-CAzYRr8i.js} +1 -1
- package/dist/ui/assets/{django-CJK7lReT.js → django-DPFPMDLP.js} +1 -1
- package/dist/ui/assets/{dns-D02SHjSy.js → dns-kf25JjIl.js} +1 -1
- package/dist/ui/assets/{dockerfile-trKL1Bqu.js → dockerfile-GP7x-Ptc.js} +1 -1
- package/dist/ui/assets/{dos-C52dy-sK.js → dos-DlXSYH18.js} +1 -1
- package/dist/ui/assets/{dsconfig-MzHgzVrt.js → dsconfig-DrXWPwZN.js} +1 -1
- package/dist/ui/assets/{dts-B137dHyX.js → dts-B9QdwGCS.js} +1 -1
- package/dist/ui/assets/{dust-BcbM0r5C.js → dust-CdplAbVJ.js} +1 -1
- package/dist/ui/assets/{ebnf-DkbpI7bK.js → ebnf-BdCAaKiH.js} +1 -1
- package/dist/ui/assets/{ebnfDiagram-CCIWWBDH-aI5uQ7w1.js → ebnfDiagram-CCIWWBDH-l1kXQDgJ.js} +1 -1
- package/dist/ui/assets/{elixir-BOtDuqQy.js → elixir-WekcTu8c.js} +1 -1
- package/dist/ui/assets/{elm-DS8Tyyu-.js → elm-DKbQ6Ryz.js} +1 -1
- package/dist/ui/assets/{erDiagram-Q63AITRT-2vCbd4Mm.js → erDiagram-Q63AITRT-CCeU8uXM.js} +1 -1
- package/dist/ui/assets/{erb-CSXECRbn.js → erb-DvQ2S9Q6.js} +1 -1
- package/dist/ui/assets/{erlang-BMxlgKPJ.js → erlang-C4cAvWW8.js} +1 -1
- package/dist/ui/assets/{erlang-repl-DPzlolPg.js → erlang-repl-BMKmccqv.js} +1 -1
- package/dist/ui/assets/{excel-CW2Uxed3.js → excel-Cz9AeP71.js} +1 -1
- package/dist/ui/assets/{fix-UW84SlCs.js → fix-BFQxvtLz.js} +1 -1
- package/dist/ui/assets/{flix-4UGiPULd.js → flix-D3TgVgHZ.js} +1 -1
- package/dist/ui/assets/{flowDiagram-23GEKE2U-R5PbCbZI.js → flowDiagram-23GEKE2U-CWYmXYgW.js} +1 -1
- package/dist/ui/assets/{fortran-nhHsngdu.js → fortran-CWmklLY8.js} +1 -1
- package/dist/ui/assets/{fsharp-CDyZ1ST5.js → fsharp-V2Eau__H.js} +1 -1
- package/dist/ui/assets/{gams-DHzkkUie.js → gams-KwiGZby9.js} +1 -1
- package/dist/ui/assets/{ganttDiagram-NO4QXBWP-CGcq4Ie_.js → ganttDiagram-NO4QXBWP-Bw1obkG5.js} +1 -1
- package/dist/ui/assets/{gauss-DdhFGyBv.js → gauss-CRI2FQhz.js} +1 -1
- package/dist/ui/assets/{gcode-ImHh8OLA.js → gcode-Bh0f80Zp.js} +1 -1
- package/dist/ui/assets/{gherkin-CTWAW-XR.js → gherkin-DEjcfzYc.js} +1 -1
- package/dist/ui/assets/{gitGraphDiagram-IHSO6WYX-8nM2Z9lD.js → gitGraphDiagram-IHSO6WYX-OfPpsImd.js} +1 -1
- package/dist/ui/assets/{glsl-0_W_27G2.js → glsl-BrYpeP6h.js} +1 -1
- package/dist/ui/assets/{gml-BoDggu2z.js → gml-m818HPGO.js} +1 -1
- package/dist/ui/assets/{go-DYfFygwl.js → go-BX431CyL.js} +1 -1
- package/dist/ui/assets/{golo-Mlq-TCg9.js → golo-D4m-zAId.js} +1 -1
- package/dist/ui/assets/{gradle-BALAinEB.js → gradle-Cq6wabEA.js} +1 -1
- package/dist/ui/assets/{groovy-Dht--dWU.js → groovy-TjcpUbQS.js} +1 -1
- package/dist/ui/assets/{haml-DpMrxg0d.js → haml-DrCR34E5.js} +1 -1
- package/dist/ui/assets/{handlebars-DqHzujNj.js → handlebars-CVS3O2t9.js} +1 -1
- package/dist/ui/assets/{haskell-DZSchhkY.js → haskell-B8q0nv1_.js} +1 -1
- package/dist/ui/assets/{haxe-C0zBRjdy.js → haxe-DXPsSA4C.js} +1 -1
- package/dist/ui/assets/{hsp-D_PwbSv2.js → hsp-CzpLpdV9.js} +1 -1
- package/dist/ui/assets/{htmlbars-DxAFMG8u.js → htmlbars-Cs_-HclQ.js} +1 -1
- package/dist/ui/assets/{http-DvTRF0Do.js → http-CHD9pG0v.js} +1 -1
- package/dist/ui/assets/{hy-lVO-kNyp.js → hy-B-a7tYC4.js} +1 -1
- package/dist/ui/assets/{index-Ci23SMK2.js → index-CJEzcYeX.js} +21 -21
- package/dist/ui/assets/{index-BbMRVVGt.js → index-DBPwq3d-.js} +3 -3
- package/dist/ui/assets/{infoDiagram-FWYZ7A6U-C7WYDlvc.js → infoDiagram-FWYZ7A6U-DNrZutb1.js} +1 -1
- package/dist/ui/assets/{inform7-B8Tf2n8v.js → inform7-47bZAprM.js} +1 -1
- package/dist/ui/assets/{ini-DSoYMaLF.js → ini-D00zSJOc.js} +1 -1
- package/dist/ui/assets/{irpf90-RCPdkB14.js → irpf90-Cb5adfDu.js} +1 -1
- package/dist/ui/assets/{isbl-C2p75PPj.js → isbl-NcFXKDCH.js} +1 -1
- package/dist/ui/assets/{ishikawaDiagram-FXEZZL3T-Cm6jsPlc.js → ishikawaDiagram-FXEZZL3T-DodxL_A3.js} +1 -1
- package/dist/ui/assets/{java-DeY4Yuia.js → java-DdNdnIDI.js} +1 -1
- package/dist/ui/assets/{javascript-3uX1CO-H.js → javascript-CauBsBfA.js} +1 -1
- package/dist/ui/assets/{jboss-cli-DgnD8mEc.js → jboss-cli-Ce_9aKRs.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-5HDEW3XC-DEGV1uA5.js → journeyDiagram-5HDEW3XC-CaegxpYw.js} +1 -1
- package/dist/ui/assets/{json-BV2PmJJp.js → json-BKT_pfo1.js} +1 -1
- package/dist/ui/assets/{julia-B-m8kQm7.js → julia-bWGt_b_o.js} +1 -1
- package/dist/ui/assets/{julia-repl-C51atU2X.js → julia-repl-D-rjMsRC.js} +1 -1
- package/dist/ui/assets/{kanban-definition-HUTT4EX6-BJ4k5iTX.js → kanban-definition-HUTT4EX6-DocIVGMy.js} +1 -1
- package/dist/ui/assets/{kotlin-CYBziIgl.js → kotlin-CW5ChHJw.js} +1 -1
- package/dist/ui/assets/{lasso-Dw2SBMDW.js → lasso-1z4Xsh4l.js} +1 -1
- package/dist/ui/assets/{latex-Dpd35yke.js → latex-DRw0gvLT.js} +1 -1
- package/dist/ui/assets/{ldif-Ce9EZU__.js → ldif-CC6n1ZWZ.js} +1 -1
- package/dist/ui/assets/{leaf-CpkZzQtC.js → leaf-DtycGYP2.js} +1 -1
- package/dist/ui/assets/{less-Uzo7M0FD.js → less-DHfDdpLT.js} +1 -1
- package/dist/ui/assets/{lisp-DWXDlJYm.js → lisp-F7y5QBiG.js} +1 -1
- package/dist/ui/assets/{livecodeserver-uEyPEgVJ.js → livecodeserver-B4rL97ZE.js} +1 -1
- package/dist/ui/assets/{livescript-BQ5f07oK.js → livescript-C1A66vR3.js} +1 -1
- package/dist/ui/assets/{llvm-BAvP-skE.js → llvm-DrJc4jDQ.js} +1 -1
- package/dist/ui/assets/{lsl-DhbiIKu6.js → lsl-ByygfQlb.js} +1 -1
- package/dist/ui/assets/{lua-COxeUeLx.js → lua-C93sHZoB.js} +1 -1
- package/dist/ui/assets/{makefile-DhDx-IgL.js → makefile-CymUCipv.js} +1 -1
- package/dist/ui/assets/{markdown-DX5_kSxq.js → markdown-BLwVli7a.js} +1 -1
- package/dist/ui/assets/{mathematica-D351ZddB.js → mathematica-DMmVw4oA.js} +1 -1
- package/dist/ui/assets/{matlab-CELqIiwF.js → matlab-DJPyR0-0.js} +1 -1
- package/dist/ui/assets/{maxima-B_YljrMm.js → maxima-B_5tEBD-.js} +1 -1
- package/dist/ui/assets/{mel-DltsbNS8.js → mel-B5AJmhET.js} +1 -1
- package/dist/ui/assets/{mercury-axX-5Vjj.js → mercury-DDm_HlP5.js} +1 -1
- package/dist/ui/assets/{mindmap-definition-LN4V7U3C-Bl1EJo6p.js → mindmap-definition-LN4V7U3C-Ck5xDFhg.js} +1 -1
- package/dist/ui/assets/{mipsasm-BxmerVwX.js → mipsasm-BBf0KZxo.js} +1 -1
- package/dist/ui/assets/{mizar-XNHfbpL2.js → mizar-BvkTEip4.js} +1 -1
- package/dist/ui/assets/{mojolicious-BR0U_7zk.js → mojolicious-t81pYOLs.js} +1 -1
- package/dist/ui/assets/{monkey-lLuu9_f-.js → monkey-B5URMcLy.js} +1 -1
- package/dist/ui/assets/{moonscript-DoaZ3DRQ.js → moonscript-Bbi3L3V5.js} +1 -1
- package/dist/ui/assets/{n1ql-C6TId6Iu.js → n1ql-DE8gguiN.js} +1 -1
- package/dist/ui/assets/{nginx-BezSG-JT.js → nginx-ytmzvrnA.js} +1 -1
- package/dist/ui/assets/{nim-Bb0rfXie.js → nim-28PFAP2a.js} +1 -1
- package/dist/ui/assets/{nix-o3sJ5-54.js → nix-DPGZqLl2.js} +1 -1
- package/dist/ui/assets/{node-repl-Sv5hhcTf.js → node-repl-77Ag73Mp.js} +1 -1
- package/dist/ui/assets/{nsis-B45BJFhF.js → nsis-Bd-Jh2mn.js} +1 -1
- package/dist/ui/assets/{objectivec-CzS6zVgh.js → objectivec-Dut0JGtJ.js} +1 -1
- package/dist/ui/assets/{ocaml-Bqux7PyP.js → ocaml-B8NbbL7d.js} +1 -1
- package/dist/ui/assets/{openscad-4Wf6mF84.js → openscad-3haKn8_6.js} +1 -1
- package/dist/ui/assets/{oxygene-Fvwqgkkt.js → oxygene-CzZcXgOW.js} +1 -1
- package/dist/ui/assets/{parser3-zEfzT5wv.js → parser3-B9_LTx13.js} +1 -1
- package/dist/ui/assets/{pegDiagram-2B236MQR-Dd4rIztM.js → pegDiagram-2B236MQR-CnkbIPdt.js} +1 -1
- package/dist/ui/assets/{perl-CsS1Gs6o.js → perl-CJHWWgIf.js} +1 -1
- package/dist/ui/assets/{pf-BNH1jO0R.js → pf-BpbQ2FKx.js} +1 -1
- package/dist/ui/assets/{pgsql-DqPigHrq.js → pgsql-DNFfp1qF.js} +1 -1
- package/dist/ui/assets/{php-CdOl9bRs.js → php-BHGIfWOP.js} +1 -1
- package/dist/ui/assets/{php-template-DPfirJg2.js → php-template-CajBP9Ht.js} +1 -1
- package/dist/ui/assets/{pieDiagram-ENE6RG2P-DGaJNf4S.js → pieDiagram-ENE6RG2P-BOBkdC1f.js} +1 -1
- package/dist/ui/assets/{plaintext-EHbgBKzw.js → plaintext-CdRaKh_-.js} +1 -1
- package/dist/ui/assets/{pony-DmJajtp2.js → pony-BTFZduq1.js} +1 -1
- package/dist/ui/assets/{powershell-DfGzdWR6.js → powershell-gWcxiMpD.js} +1 -1
- package/dist/ui/assets/{processing-BT0ETgPG.js → processing-DbryYP4B.js} +1 -1
- package/dist/ui/assets/{profile-B3I-x5Lt.js → profile-CHL6RTDR.js} +1 -1
- package/dist/ui/assets/{prolog-B_4QJIvI.js → prolog-CAz3V1M6.js} +1 -1
- package/dist/ui/assets/{properties-BFVI8weS.js → properties-BLvgyNqZ.js} +1 -1
- package/dist/ui/assets/{protobuf-PaF39oZZ.js → protobuf-C-bEtiAJ.js} +1 -1
- package/dist/ui/assets/{puppet-BDC6Q8VF.js → puppet-67xqXQgg.js} +1 -1
- package/dist/ui/assets/{purebasic-B2ejrOZK.js → purebasic-DAwxmhyv.js} +1 -1
- package/dist/ui/assets/{python-repl-BslBh_Mx.js → python-repl-BJmGMIGi.js} +1 -1
- package/dist/ui/assets/{python-BOxtIk9H.js → python-z-wrDm9i.js} +1 -1
- package/dist/ui/assets/{q-BPe8WLGW.js → q-CDMPAvF9.js} +1 -1
- package/dist/ui/assets/{qml-BazRR6fz.js → qml-CbE9R2YT.js} +1 -1
- package/dist/ui/assets/{quadrantDiagram-ABIIQ3AL-BQ7aPkHk.js → quadrantDiagram-ABIIQ3AL-BHAhzSkD.js} +1 -1
- package/dist/ui/assets/{r-C09pGNJC.js → r-B1k7RrWh.js} +1 -1
- package/dist/ui/assets/{railroadDiagram-RFXS5EU6-sCO9VGvE.js → railroadDiagram-RFXS5EU6-CsQep5fB.js} +1 -1
- package/dist/ui/assets/{reasonml-S7dzwVL9.js → reasonml-CghNJ9wO.js} +1 -1
- package/dist/ui/assets/{requirementDiagram-TGXJPOKE-CfT5aVZg.js → requirementDiagram-TGXJPOKE-BTTRG_C-.js} +1 -1
- package/dist/ui/assets/{rib-fM2EwQd4.js → rib-BzZqpngB.js} +1 -1
- package/dist/ui/assets/{roboconf-D7AaeyrW.js → roboconf-Bn6vqIcm.js} +1 -1
- package/dist/ui/assets/{routeros-c6Q7mKuq.js → routeros-CWiIB6Sc.js} +1 -1
- package/dist/ui/assets/{rsl-sCpEQBxh.js → rsl-8XzLd-ex.js} +1 -1
- package/dist/ui/assets/{ruby-lcKhz2w9.js → ruby-CMsox328.js} +1 -1
- package/dist/ui/assets/{ruleslanguage-BW4ATOuX.js → ruleslanguage-sJ93c6T4.js} +1 -1
- package/dist/ui/assets/{rust-BbpU-0VY.js → rust-q4W6ksGp.js} +1 -1
- package/dist/ui/assets/{sankeyDiagram-HTMAVEWB-CaweCpvN.js → sankeyDiagram-HTMAVEWB-_xUP3uiO.js} +1 -1
- package/dist/ui/assets/{sas-BPt5R0dx.js → sas-JzGZkjB8.js} +1 -1
- package/dist/ui/assets/{scala-DxW_vqXs.js → scala-BBRUB1bT.js} +1 -1
- package/dist/ui/assets/{scheme-T2Q_jWzT.js → scheme-gFzNu8q5.js} +1 -1
- package/dist/ui/assets/{scilab-DMORg9lV.js → scilab-0XjfEPk4.js} +1 -1
- package/dist/ui/assets/{scss-t0VsosqT.js → scss-CuET4vU_.js} +1 -1
- package/dist/ui/assets/{sequenceDiagram-DBY2YBRQ-o-H_R4zb.js → sequenceDiagram-DBY2YBRQ-DYM-Lf_t.js} +1 -1
- package/dist/ui/assets/{shell-CnCDa1s9.js → shell-DozhgmQz.js} +1 -1
- package/dist/ui/assets/{sizeCapture-X5ZJPWSS-BNLkHGDS.js → sizeCapture-X5ZJPWSS-enn2ctEl.js} +1 -1
- package/dist/ui/assets/{smali-_n-BxJyG.js → smali-DCS5Fxk1.js} +1 -1
- package/dist/ui/assets/{smalltalk-B90PXJwK.js → smalltalk-BHQ0G1rO.js} +1 -1
- package/dist/ui/assets/{sml-fuY7bj-n.js → sml-Bj9p_O7l.js} +1 -1
- package/dist/ui/assets/{sqf-COpwkyuo.js → sqf-VjHINPVc.js} +1 -1
- package/dist/ui/assets/{sql-CXIT0j-x.js → sql-DNYdjhOa.js} +1 -1
- package/dist/ui/assets/{sql_more-C1Oxq4rx.js → sql_more-DF9pwFii.js} +1 -1
- package/dist/ui/assets/{stan-BZEpaHeC.js → stan-DQ7LiXhT.js} +1 -1
- package/dist/ui/assets/{stata-CkBwaiZM.js → stata-4eQacDMD.js} +1 -1
- package/dist/ui/assets/{stateDiagram-2N3HPSRC-BkdnNF7I.js → stateDiagram-2N3HPSRC-CX-Qz4n7.js} +1 -1
- package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-Ch54U9zs.js +1 -0
- package/dist/ui/assets/{step21-fs9N_U3O.js → step21-BgYnjmFD.js} +1 -1
- package/dist/ui/assets/{stylus-Bs_9cvKZ.js → stylus-ZZ5CxZ05.js} +1 -1
- package/dist/ui/assets/{subunit-DvgcOCqJ.js → subunit-Ci5aUEE2.js} +1 -1
- package/dist/ui/assets/{swift-BE4ONsur.js → swift-DQJ4QPRG.js} +1 -1
- package/dist/ui/assets/{swimlanes-5IMT3BWC-uqTAc7o7.js → swimlanes-5IMT3BWC-vO-7dG2V.js} +2 -2
- package/dist/ui/assets/swimlanesDiagram-G3AALYLV-DxwJcNf4.js +8 -0
- package/dist/ui/assets/{taggerscript-BhmPJ64C.js → taggerscript-DM07ScL_.js} +1 -1
- package/dist/ui/assets/{tap-DkueIVKV.js → tap-C6aPKgww.js} +1 -1
- package/dist/ui/assets/{tcl-DyXOOkFi.js → tcl-DjtvddtN.js} +1 -1
- package/dist/ui/assets/{thrift-Dhgbk56T.js → thrift-BoJuHfsC.js} +1 -1
- package/dist/ui/assets/{timeline-definition-FHXFAJF6-DBAk9Ouc.js → timeline-definition-FHXFAJF6-Cn7z-Bqh.js} +1 -1
- package/dist/ui/assets/{tp-BsXyrRGH.js → tp-7mrfAfpj.js} +1 -1
- package/dist/ui/assets/{twig-J0HqIuHw.js → twig-DOOUfGqf.js} +1 -1
- package/dist/ui/assets/{typescript-Dkwvul39.js → typescript-BbC9hUFK.js} +1 -1
- package/dist/ui/assets/{vala-CRGnf8aY.js → vala-XjKwsdD0.js} +1 -1
- package/dist/ui/assets/{vbnet-BtJAUe3z.js → vbnet-Da3MfWx9.js} +1 -1
- package/dist/ui/assets/{vbscript-RgFFNuM3.js → vbscript-DT_81k7v.js} +1 -1
- package/dist/ui/assets/{vbscript-html-DO32Io9Y.js → vbscript-html-DUFh3J5N.js} +1 -1
- package/dist/ui/assets/{vennDiagram-L72KCM5P-BJi6y0hh.js → vennDiagram-L72KCM5P-BnjZCady.js} +1 -1
- package/dist/ui/assets/{verilog-C4h6MLcI.js → verilog-D5Okzav9.js} +1 -1
- package/dist/ui/assets/{vhdl-DOafePyU.js → vhdl-_hcd5jXC.js} +1 -1
- package/dist/ui/assets/{vim-BAdTA9TY.js → vim-BuKTsAic.js} +1 -1
- package/dist/ui/assets/{wardleyDiagram-EHGQE667-C7c_4IJ6.js → wardleyDiagram-EHGQE667-Bgp49v0-.js} +1 -1
- package/dist/ui/assets/{x86asm-BCL6__QH.js → x86asm-DWOIgEnP.js} +1 -1
- package/dist/ui/assets/{xl-qIzE4HOe.js → xl-D6TFf1q5.js} +1 -1
- package/dist/ui/assets/{xml-DE2sJXYU.js → xml-_5JZFtHD.js} +1 -1
- package/dist/ui/assets/{xquery-CQ35t92y.js → xquery-BC0pvaic.js} +1 -1
- package/dist/ui/assets/{xychartDiagram-FW5EYKEG-D2ILn0jL.js → xychartDiagram-FW5EYKEG-DmyzmXyI.js} +1 -1
- package/dist/ui/assets/{yaml-5KaAvG5C.js → yaml-CLzRjl8_.js} +1 -1
- package/dist/ui/assets/{zephir-CbR3Ryfq.js → zephir-nZ6mLYuU.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/utils/__tests__/db-maintenance.test.d.ts +1 -0
- package/dist/utils/__tests__/db-maintenance.test.js +55 -0
- package/dist/utils/__tests__/db-migration.test.js +79 -1
- package/dist/utils/__tests__/request-writer.test.js +264 -3
- package/dist/utils/__tests__/stats-aggregator.test.d.ts +1 -0
- package/dist/utils/__tests__/stats-aggregator.test.js +114 -0
- package/dist/utils/db-maintenance.d.ts +8 -0
- package/dist/utils/db-maintenance.js +18 -0
- package/dist/utils/db.d.ts +1 -0
- package/dist/utils/db.js +62 -0
- package/dist/utils/request-writer.d.ts +23 -1
- package/dist/utils/request-writer.js +200 -14
- package/dist/utils/stats-aggregator.d.ts +1 -1
- package/dist/utils/stats-aggregator.js +44 -27
- package/ecosystem.config.cjs +2 -1
- package/package.json +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.C4sjikMO.js +0 -1
- package/dist/server/middleware/__tests__/request-id.test.js +0 -28
- package/dist/server/middleware/request-id.d.ts +0 -2
- package/dist/server/middleware/request-id.js +0 -12
- package/dist/ui/assets/channel-ChTtxQDg.js +0 -1
- package/dist/ui/assets/classDiagram-OUVF2IWQ-Ccbvamlu.js +0 -1
- package/dist/ui/assets/classDiagram-v2-EOCWNBFH-Ccbvamlu.js +0 -1
- package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-0JnZ1VSQ.js +0 -1
- package/dist/ui/assets/swimlanesDiagram-G3AALYLV-DQRIIEmi.js +0 -8
- /package/dist/server/{middleware/__tests__/request-id.test.d.ts → __tests__/data-push.test.d.ts} +0 -0
|
@@ -20,7 +20,7 @@ function flushEventBatch(sessionId, requestId, batch, startIndex) {
|
|
|
20
20
|
const db = getDatabase();
|
|
21
21
|
ensureStmtCacheValid(db);
|
|
22
22
|
if (!insertEventStmt) {
|
|
23
|
-
insertEventStmt = db.prepare('INSERT INTO response_events (request_id, session_id, event_index, event_type, event_data) VALUES (?, ?, ?, ?, ?)');
|
|
23
|
+
insertEventStmt = db.prepare('INSERT OR IGNORE INTO response_events (request_id, session_id, event_index, event_type, event_data) VALUES (?, ?, ?, ?, ?)');
|
|
24
24
|
}
|
|
25
25
|
for (let i = 0; i < batch.length; i++) {
|
|
26
26
|
const event = batch[i];
|
|
@@ -33,6 +33,118 @@ function extractUsage(events) {
|
|
|
33
33
|
const messageDelta = events.find((e) => e?.type === 'message_delta');
|
|
34
34
|
return messageDelta?.usage;
|
|
35
35
|
}
|
|
36
|
+
// --- 流完整性判定与 usage 重建(纯函数,事件数组入参)---
|
|
37
|
+
/**
|
|
38
|
+
* 判断事件集合是否构成一条完整返回的流。
|
|
39
|
+
* Claude:出现 type === 'message_stop'。
|
|
40
|
+
* OpenAI 兼容:chunk 内 choices[0].finish_reason 非空
|
|
41
|
+
* ([DONE] 不入库,不能作为 DB 判定依据)。
|
|
42
|
+
*/
|
|
43
|
+
export function isStreamCompleteEvents(events) {
|
|
44
|
+
if (!Array.isArray(events))
|
|
45
|
+
return false;
|
|
46
|
+
return events.some(e => {
|
|
47
|
+
if (!e || typeof e !== 'object')
|
|
48
|
+
return false;
|
|
49
|
+
if (e.type === 'message_stop')
|
|
50
|
+
return true;
|
|
51
|
+
const finishReason = e.choices?.[0]?.finish_reason;
|
|
52
|
+
return finishReason !== undefined && finishReason !== null && finishReason !== '';
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 从事件集合按字段合并重建 usage,不做整体覆盖。
|
|
57
|
+
* Claude:message_start.usage(input_tokens / cache_*)为底;
|
|
58
|
+
* message_delta.usage 的字段优先(output_tokens 为主,cache 字段也合入)。
|
|
59
|
+
* OpenAI:取带 .usage 的 chunk(prompt_tokens/completion_tokens)。
|
|
60
|
+
*/
|
|
61
|
+
export function reconstructUsageFromEvents(events) {
|
|
62
|
+
if (!Array.isArray(events))
|
|
63
|
+
return undefined;
|
|
64
|
+
const usage = {};
|
|
65
|
+
let found = false;
|
|
66
|
+
const merge = (field, value, precedence) => {
|
|
67
|
+
if (typeof value !== 'number')
|
|
68
|
+
return;
|
|
69
|
+
if (precedence || usage[field] === undefined) {
|
|
70
|
+
usage[field] = value;
|
|
71
|
+
found = true;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
for (const e of events) {
|
|
75
|
+
if (!e || typeof e !== 'object')
|
|
76
|
+
continue;
|
|
77
|
+
if (e.type === 'message_start' || e.type === 'message_delta') {
|
|
78
|
+
const u = e.usage;
|
|
79
|
+
if (u && typeof u === 'object') {
|
|
80
|
+
const isDelta = e.type === 'message_delta';
|
|
81
|
+
merge('input_tokens', u.input_tokens, isDelta);
|
|
82
|
+
merge('output_tokens', u.output_tokens, isDelta);
|
|
83
|
+
merge('cache_read_input_tokens', u.cache_read_input_tokens, isDelta);
|
|
84
|
+
merge('cache_creation_input_tokens', u.cache_creation_input_tokens, isDelta);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// OpenAI 兼容:带 usage 的 chunk(event_type 通常为 NULL)
|
|
88
|
+
if (e.usage && typeof e.usage === 'object' && e.type !== 'message_start' && e.type !== 'message_delta') {
|
|
89
|
+
const u = e.usage;
|
|
90
|
+
merge('input_tokens', u.input_tokens ?? u.prompt_tokens, false);
|
|
91
|
+
merge('output_tokens', u.output_tokens ?? u.completion_tokens, false);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return found ? usage : undefined;
|
|
95
|
+
}
|
|
96
|
+
// 定向加载重建所需事件,禁止全量加载事件流(实测有 8000+ 行):
|
|
97
|
+
// 1) Claude 锚点事件(message_start/message_delta/message_stop,通常仅数行)
|
|
98
|
+
// 2) 尾部 10 条事件(覆盖 OpenAI 的 finish_reason / usage,其 event_type 可能为 NULL)
|
|
99
|
+
function loadTargetedEvents(db, requestId, sessionId) {
|
|
100
|
+
const anchorRows = db.prepare(`
|
|
101
|
+
SELECT event_data FROM response_events
|
|
102
|
+
WHERE request_id = ? AND session_id = ?
|
|
103
|
+
AND event_type IN ('message_start', 'message_delta', 'message_stop')
|
|
104
|
+
ORDER BY event_index ASC
|
|
105
|
+
`).all(requestId, sessionId);
|
|
106
|
+
const tailRows = db.prepare(`
|
|
107
|
+
SELECT event_data FROM response_events
|
|
108
|
+
WHERE request_id = ? AND session_id = ?
|
|
109
|
+
ORDER BY event_index DESC
|
|
110
|
+
LIMIT 10
|
|
111
|
+
`).all(requestId, sessionId);
|
|
112
|
+
const seen = new Set();
|
|
113
|
+
const events = [];
|
|
114
|
+
for (const row of [...anchorRows, ...tailRows]) {
|
|
115
|
+
if (seen.has(row.event_data))
|
|
116
|
+
continue;
|
|
117
|
+
seen.add(row.event_data);
|
|
118
|
+
try {
|
|
119
|
+
events.push(JSON.parse(row.event_data));
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// 忽略损坏行
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return events;
|
|
126
|
+
}
|
|
127
|
+
// 按字段回填 token 列(只补 NULL 列),返回是否有列被更新
|
|
128
|
+
function fillTokenColumns(db, requestId, sessionId, usage) {
|
|
129
|
+
const current = db.prepare(`
|
|
130
|
+
SELECT input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens
|
|
131
|
+
FROM requests WHERE request_id = ? AND session_id = ?
|
|
132
|
+
`).get(requestId, sessionId);
|
|
133
|
+
if (!current)
|
|
134
|
+
return false;
|
|
135
|
+
const pairs = [
|
|
136
|
+
['input_tokens', usage.input_tokens],
|
|
137
|
+
['output_tokens', usage.output_tokens],
|
|
138
|
+
['cache_read_tokens', usage.cache_read_input_tokens],
|
|
139
|
+
['cache_creation_tokens', usage.cache_creation_input_tokens]
|
|
140
|
+
];
|
|
141
|
+
const updatable = pairs.filter(([col, v]) => current[col] === null && typeof v === 'number');
|
|
142
|
+
if (updatable.length === 0)
|
|
143
|
+
return false;
|
|
144
|
+
const setSql = updatable.map(([col]) => `${col} = ?`).join(', ');
|
|
145
|
+
db.prepare(`UPDATE requests SET ${setSql} WHERE request_id = ? AND session_id = ?`).run(...updatable.map(([, v]) => v), requestId, sessionId);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
36
148
|
function writeCompletedRow(args) {
|
|
37
149
|
const db = getDatabase();
|
|
38
150
|
const { meta } = args;
|
|
@@ -76,6 +188,13 @@ export function createRequestRecorder(meta) {
|
|
|
76
188
|
let eventIndex = 0;
|
|
77
189
|
const startTime = Date.now();
|
|
78
190
|
let pendingCalled = false;
|
|
191
|
+
// recorder 生命周期开始前的事件行下界。complete() 把事件从 localRequestId 迁到
|
|
192
|
+
// cloudRequestId 时只允许迁移 id 大于它的行:request_id(req-N 计数器)在进程
|
|
193
|
+
// 重启后可能复用,同 localRequestId 的历史残留事件属于别的请求,不能被一起迁走。
|
|
194
|
+
const startRow = getDatabase()
|
|
195
|
+
.prepare('SELECT MAX(id) AS m FROM response_events')
|
|
196
|
+
.get();
|
|
197
|
+
const startEventRowId = startRow.m ?? 0;
|
|
79
198
|
function flushRemaining() {
|
|
80
199
|
if (eventBatch.length > 0) {
|
|
81
200
|
flushEventBatch(meta.sessionId, meta.localRequestId, eventBatch, eventIndex - eventBatch.length);
|
|
@@ -141,7 +260,9 @@ export function createRequestRecorder(meta) {
|
|
|
141
260
|
const db = getDatabase();
|
|
142
261
|
if (finalId !== meta.localRequestId) {
|
|
143
262
|
const replace = db.transaction(() => {
|
|
144
|
-
|
|
263
|
+
// id > startEventRowId:只迁本 recorder 创建后写入的事件,
|
|
264
|
+
// 不迁同 localRequestId 的历史残留事件
|
|
265
|
+
db.prepare('UPDATE response_events SET request_id = ? WHERE request_id = ? AND session_id = ? AND id > ?').run(finalId, meta.localRequestId, meta.sessionId, startEventRowId);
|
|
145
266
|
writeCompletedRow({
|
|
146
267
|
meta, requestId: finalId, statusCode, responseTime, headers, usage, completedAt
|
|
147
268
|
});
|
|
@@ -156,13 +277,20 @@ export function createRequestRecorder(meta) {
|
|
|
156
277
|
}
|
|
157
278
|
pushNewRequest(buildSummary(meta, finalId, statusCode, responseTime, usage, finalId !== meta.localRequestId), 'completed');
|
|
158
279
|
},
|
|
159
|
-
// 流被截断/挂死:保留真实 status_code,通过 closed_at + error
|
|
280
|
+
// 流被截断/挂死:保留真实 status_code,通过 closed_at + error 标记中断;
|
|
281
|
+
// 同时通过定向 SQL(锚点事件 + 尾部事件)重建 usage 并按字段回填 token
|
|
160
282
|
interrupt({ statusCode, error }) {
|
|
161
283
|
flushRemaining();
|
|
284
|
+
const db = getDatabase();
|
|
162
285
|
const responseTime = Date.now() - startTime;
|
|
163
286
|
const closedAt = new Date().toISOString();
|
|
164
|
-
|
|
165
|
-
|
|
287
|
+
db.prepare('UPDATE requests SET status_code = ?, response_time = ?, closed_at = ?, error = ? WHERE request_id = ? AND session_id = ?').run(statusCode, responseTime, closedAt, error, meta.localRequestId, meta.sessionId);
|
|
288
|
+
const events = loadTargetedEvents(db, meta.localRequestId, meta.sessionId);
|
|
289
|
+
const usage = reconstructUsageFromEvents(events);
|
|
290
|
+
if (usage) {
|
|
291
|
+
fillTokenColumns(db, meta.localRequestId, meta.sessionId, usage);
|
|
292
|
+
}
|
|
293
|
+
pushNewRequest(buildSummary(meta, meta.localRequestId, statusCode, responseTime, usage, false, closedAt), 'completed');
|
|
166
294
|
},
|
|
167
295
|
fail({ statusCode, error }) {
|
|
168
296
|
const responseTime = Date.now() - startTime;
|
|
@@ -275,7 +403,7 @@ export async function listRequestDB(limit = 1000, before) {
|
|
|
275
403
|
SELECT
|
|
276
404
|
request_id, session_id, timestamp, method, path, status_code, response_time,
|
|
277
405
|
api_key, proxy_api_key, base_url, model, machine_id, user_agent,
|
|
278
|
-
input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, closed_at
|
|
406
|
+
input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, closed_at, error
|
|
279
407
|
FROM requests
|
|
280
408
|
${whereClause}
|
|
281
409
|
ORDER BY timestamp DESC
|
|
@@ -305,7 +433,8 @@ export async function listRequestDB(limit = 1000, before) {
|
|
|
305
433
|
cache_read_input_tokens: row.cache_read_tokens,
|
|
306
434
|
cache_creation_input_tokens: row.cache_creation_tokens
|
|
307
435
|
} : undefined,
|
|
308
|
-
closedAt: row.closed_at || undefined
|
|
436
|
+
closedAt: row.closed_at || undefined,
|
|
437
|
+
error: row.error || undefined
|
|
309
438
|
})),
|
|
310
439
|
hasMore
|
|
311
440
|
};
|
|
@@ -322,23 +451,80 @@ export async function cleanOldRequestsDB(daysToKeep = 7) {
|
|
|
322
451
|
// Delete response_events first (foreign data), then requests
|
|
323
452
|
db.prepare(`DELETE FROM response_events WHERE request_id IN (SELECT request_id FROM requests WHERE timestamp < ?)`).run(cutoff);
|
|
324
453
|
db.prepare(`DELETE FROM requests WHERE timestamp < ?`).run(cutoff);
|
|
454
|
+
// 例行还页:auto_vacuum 未开启时为 no-op;经 ccm vacuum 开启
|
|
455
|
+
// INCREMENTAL 后,删除产生的空闲页在此廉价归还文件系统。
|
|
456
|
+
db.pragma('incremental_vacuum');
|
|
325
457
|
}
|
|
326
|
-
// 启动时回收上次进程遗留的僵尸 SSE
|
|
327
|
-
// (status_code
|
|
458
|
+
// 启动时回收上次进程遗留的僵尸 SSE 行:未完成、未关闭且超龄,逐行分流
|
|
459
|
+
// (status_code 保持原值不动)——事件流完整(message_stop / OpenAI finish_reason)
|
|
460
|
+
// 的走完成语义:写 completed_at,不写 closed_at/error;不完整的维持
|
|
461
|
+
// closed_at + 'interrupted: proxy restarted'。两条路径都按字段回填 token 列。
|
|
328
462
|
export function interruptStaleRequestsOnStartup(maxAgeMs = 5 * 60000) {
|
|
329
463
|
const db = initDatabase();
|
|
330
464
|
const cutoff = new Date(Date.now() - maxAgeMs).toISOString();
|
|
331
465
|
const rows = db.prepare(`
|
|
332
|
-
SELECT request_id, session_id
|
|
466
|
+
SELECT request_id, session_id, timestamp, response_time
|
|
333
467
|
FROM requests
|
|
334
468
|
WHERE completed_at IS NULL AND closed_at IS NULL AND timestamp < ?
|
|
335
469
|
`).all(cutoff);
|
|
336
|
-
|
|
337
|
-
|
|
470
|
+
let completed = 0;
|
|
471
|
+
let interrupted = 0;
|
|
472
|
+
const nowIso = new Date().toISOString();
|
|
338
473
|
for (const row of rows) {
|
|
339
|
-
|
|
474
|
+
const events = loadTargetedEvents(db, row.request_id, row.session_id);
|
|
475
|
+
const usage = reconstructUsageFromEvents(events);
|
|
476
|
+
if (isStreamCompleteEvents(events)) {
|
|
477
|
+
// response_time 原值为 0(pending 占位)时,用 timestamp→现在给合理值
|
|
478
|
+
const responseTime = row.response_time > 0
|
|
479
|
+
? row.response_time
|
|
480
|
+
: Math.max(0, Date.now() - Date.parse(row.timestamp));
|
|
481
|
+
db.prepare('UPDATE requests SET completed_at = ?, response_time = ? WHERE request_id = ? AND session_id = ?').run(nowIso, responseTime, row.request_id, row.session_id);
|
|
482
|
+
completed += 1;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
db.prepare('UPDATE requests SET closed_at = ?, error = ? WHERE request_id = ? AND session_id = ?').run(nowIso, 'interrupted: proxy restarted', row.request_id, row.session_id);
|
|
486
|
+
interrupted += 1;
|
|
487
|
+
}
|
|
488
|
+
if (usage) {
|
|
489
|
+
fillTokenColumns(db, row.request_id, row.session_id, usage);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return { completed, interrupted };
|
|
493
|
+
}
|
|
494
|
+
// 存量回填(供 CLI repair-requests 使用),幂等可重跑:
|
|
495
|
+
// 扫描 closed_at 非空的行——事件流完整且 completed_at 为空的:清 closed_at/error、
|
|
496
|
+
// 写 completed_at(completed_at 已非空的跳过);对 token 全 NULL 但事件可恢复
|
|
497
|
+
// usage 的行按字段补 token。同样只走定向 SQL。
|
|
498
|
+
export function repairClosedRequests() {
|
|
499
|
+
const db = initDatabase();
|
|
500
|
+
const rows = db.prepare(`
|
|
501
|
+
SELECT
|
|
502
|
+
request_id, session_id, completed_at,
|
|
503
|
+
input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens
|
|
504
|
+
FROM requests
|
|
505
|
+
WHERE closed_at IS NOT NULL
|
|
506
|
+
`).all();
|
|
507
|
+
let recovered = 0;
|
|
508
|
+
let tokensFilled = 0;
|
|
509
|
+
const nowIso = new Date().toISOString();
|
|
510
|
+
for (const row of rows) {
|
|
511
|
+
const events = loadTargetedEvents(db, row.request_id, row.session_id);
|
|
512
|
+
if (row.completed_at === null && isStreamCompleteEvents(events)) {
|
|
513
|
+
db.prepare('UPDATE requests SET closed_at = NULL, error = NULL, completed_at = ? WHERE request_id = ? AND session_id = ?').run(nowIso, row.request_id, row.session_id);
|
|
514
|
+
recovered += 1;
|
|
515
|
+
}
|
|
516
|
+
const allTokensNull = row.input_tokens === null &&
|
|
517
|
+
row.output_tokens === null &&
|
|
518
|
+
row.cache_read_tokens === null &&
|
|
519
|
+
row.cache_creation_tokens === null;
|
|
520
|
+
if (allTokensNull) {
|
|
521
|
+
const usage = reconstructUsageFromEvents(events);
|
|
522
|
+
if (usage && fillTokenColumns(db, row.request_id, row.session_id, usage)) {
|
|
523
|
+
tokensFilled += 1;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
340
526
|
}
|
|
341
|
-
return
|
|
527
|
+
return { recovered, tokensFilled };
|
|
342
528
|
}
|
|
343
529
|
// Load session history for multi-turn chat resume
|
|
344
530
|
// Returns the last request's messages + assistant response, to prepend to new messages
|
|
@@ -16,6 +16,6 @@ export interface TodayStats {
|
|
|
16
16
|
request_count: number;
|
|
17
17
|
models: Record<string, number>;
|
|
18
18
|
}
|
|
19
|
-
export declare function aggregateStats(): void;
|
|
19
|
+
export declare function aggregateStats(maxDays?: number): void;
|
|
20
20
|
export declare function getStatsData(since?: string): StatsData;
|
|
21
21
|
export declare function getTodayStats(since: string): TodayStats;
|
|
@@ -1,27 +1,47 @@
|
|
|
1
1
|
import { initDatabase } from './db.js';
|
|
2
|
+
// 共用 token 聚合列:小时聚合与今日 totals 同口径,避免列漂移
|
|
3
|
+
const TOKEN_AGG_COLUMNS = `
|
|
4
|
+
SUM(input_tokens) as input_tokens,
|
|
5
|
+
SUM(output_tokens) as output_tokens,
|
|
6
|
+
SUM(cache_read_tokens) as cache_read_tokens,
|
|
7
|
+
SUM(cache_creation_tokens) as cache_creation_tokens,
|
|
8
|
+
COUNT(*) as request_count
|
|
9
|
+
`;
|
|
10
|
+
// Build the UTC hourly key ('YYYY-MM-DD-HH') used as stats.period_key
|
|
11
|
+
function toHourKey(date) {
|
|
12
|
+
return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}-${String(date.getUTCDate()).padStart(2, '0')}-${String(date.getUTCHours()).padStart(2, '0')}`;
|
|
13
|
+
}
|
|
2
14
|
// Aggregate stats from requests table (called periodically)
|
|
3
15
|
// Only stores hourly (UTC) entries — daily aggregation is done on the frontend
|
|
4
16
|
// using the user's local timezone.
|
|
5
|
-
|
|
17
|
+
// maxDays: hourly retention window in days. A positive integer shrinks the
|
|
18
|
+
// window (capped at 30); undefined / <=0 falls back to the default 30 days.
|
|
19
|
+
export function aggregateStats(maxDays) {
|
|
6
20
|
const db = initDatabase();
|
|
7
21
|
const now = new Date();
|
|
8
22
|
const nowIso = now.toISOString();
|
|
9
|
-
//
|
|
10
|
-
const
|
|
23
|
+
// windowDays days of hourly data (30 days = 720 entries)
|
|
24
|
+
const windowDays = Number.isInteger(maxDays) && maxDays > 0
|
|
25
|
+
? Math.min(30, maxDays)
|
|
26
|
+
: 30;
|
|
27
|
+
const hourlyCutoff = new Date(now.getTime() - windowDays * 86400000).toISOString();
|
|
11
28
|
// Aggregate hourly stats using SQLite's built-in strftime (UTC)
|
|
12
29
|
const hourlyRows = db.prepare(`
|
|
13
30
|
SELECT
|
|
14
31
|
strftime('%Y-%m-%d-%H', timestamp) as hour,
|
|
15
|
-
|
|
16
|
-
SUM(output_tokens) as output_tokens,
|
|
17
|
-
SUM(cache_read_tokens) as cache_read_tokens,
|
|
18
|
-
SUM(cache_creation_tokens) as cache_creation_tokens,
|
|
19
|
-
COUNT(*) as request_count
|
|
32
|
+
${TOKEN_AGG_COLUMNS}
|
|
20
33
|
FROM requests
|
|
21
34
|
WHERE timestamp >= ?
|
|
22
|
-
AND closed_at IS NULL
|
|
23
35
|
GROUP BY hour
|
|
24
36
|
`).all(hourlyCutoff);
|
|
37
|
+
// Recompute the whole window atomically: drop every hourly snapshot inside
|
|
38
|
+
// the window first (source rows may already have been deleted by cleanup, so
|
|
39
|
+
// an upsert-only pass would leave stale snapshots frozen forever), then
|
|
40
|
+
// re-insert from the requests table.
|
|
41
|
+
// Cutoff key uses UTC methods to match the UTC keys stored in the DB.
|
|
42
|
+
// The two deletes (< key / >= key) together clear every hourly row.
|
|
43
|
+
const cutoffKey = toHourKey(new Date(hourlyCutoff));
|
|
44
|
+
const deleteWindow = db.prepare(`DELETE FROM stats WHERE period = 'hourly' AND period_key >= ?`);
|
|
25
45
|
// Upsert hourly stats
|
|
26
46
|
const upsertHourly = db.prepare(`
|
|
27
47
|
INSERT OR REPLACE INTO stats (
|
|
@@ -29,16 +49,19 @@ export function aggregateStats() {
|
|
|
29
49
|
cache_read_tokens, cache_creation_tokens, request_count, updated_at
|
|
30
50
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
31
51
|
`);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
// Clean old hourly entries: compute cutoff key using UTC methods
|
|
36
|
-
// to match the UTC keys stored in the DB
|
|
37
|
-
const cutoffDate = new Date(hourlyCutoff);
|
|
38
|
-
const cutoffKey = `${cutoffDate.getUTCFullYear()}-${String(cutoffDate.getUTCMonth() + 1).padStart(2, '0')}-${String(cutoffDate.getUTCDate()).padStart(2, '0')}-${String(cutoffDate.getUTCHours()).padStart(2, '0')}`;
|
|
39
|
-
db.prepare(`DELETE FROM stats WHERE period = 'hourly' AND period_key < ?`).run(cutoffKey);
|
|
52
|
+
// Clean hourly entries outside the recomputation window
|
|
53
|
+
const deleteOldKeys = db.prepare(`DELETE FROM stats WHERE period = 'hourly' AND period_key < ?`);
|
|
40
54
|
// Clean ALL daily entries (legacy data from old +8h approach)
|
|
41
|
-
db.prepare(`DELETE FROM stats WHERE period = 'daily'`)
|
|
55
|
+
const deleteDaily = db.prepare(`DELETE FROM stats WHERE period = 'daily'`);
|
|
56
|
+
const recompute = db.transaction(() => {
|
|
57
|
+
deleteWindow.run(cutoffKey);
|
|
58
|
+
for (const row of hourlyRows) {
|
|
59
|
+
upsertHourly.run('hourly', row.hour, row.input_tokens || 0, row.output_tokens || 0, row.cache_read_tokens || 0, row.cache_creation_tokens || 0, row.request_count, nowIso);
|
|
60
|
+
}
|
|
61
|
+
deleteOldKeys.run(cutoffKey);
|
|
62
|
+
deleteDaily.run();
|
|
63
|
+
});
|
|
64
|
+
recompute();
|
|
42
65
|
// WAL checkpoint to keep WAL file size bounded
|
|
43
66
|
db.pragma('wal_checkpoint(TRUNCATE)');
|
|
44
67
|
}
|
|
@@ -48,8 +71,7 @@ export function getStatsData(since) {
|
|
|
48
71
|
let hourlyRows;
|
|
49
72
|
if (since) {
|
|
50
73
|
// Convert since (ISO UTC) to UTC hourly key format for filtering
|
|
51
|
-
const
|
|
52
|
-
const sinceKey = `${sinceDate.getUTCFullYear()}-${String(sinceDate.getUTCMonth() + 1).padStart(2, '0')}-${String(sinceDate.getUTCDate()).padStart(2, '0')}-${String(sinceDate.getUTCHours()).padStart(2, '0')}`;
|
|
74
|
+
const sinceKey = toHourKey(new Date(since));
|
|
53
75
|
hourlyRows = db.prepare(`
|
|
54
76
|
SELECT * FROM stats WHERE period = 'hourly' AND period_key >= ? ORDER BY period_key ASC
|
|
55
77
|
`).all(sinceKey);
|
|
@@ -83,22 +105,17 @@ export function getStatsData(since) {
|
|
|
83
105
|
export function getTodayStats(since) {
|
|
84
106
|
const db = initDatabase();
|
|
85
107
|
// Totals: SUM tokens + COUNT requests since local midnight
|
|
108
|
+
// 多选的 cache_creation_tokens 在返回映射时忽略
|
|
86
109
|
const totalRow = db.prepare(`
|
|
87
|
-
SELECT
|
|
88
|
-
SUM(input_tokens) as input_tokens,
|
|
89
|
-
SUM(output_tokens) as output_tokens,
|
|
90
|
-
SUM(cache_read_tokens) as cache_read_tokens,
|
|
91
|
-
COUNT(*) as request_count
|
|
110
|
+
SELECT ${TOKEN_AGG_COLUMNS}
|
|
92
111
|
FROM requests
|
|
93
112
|
WHERE timestamp >= ?
|
|
94
|
-
AND closed_at IS NULL
|
|
95
113
|
`).get(since);
|
|
96
114
|
// Per-model usage count since local midnight
|
|
97
115
|
const modelRows = db.prepare(`
|
|
98
116
|
SELECT model, COUNT(*) as count
|
|
99
117
|
FROM requests
|
|
100
118
|
WHERE timestamp >= ?
|
|
101
|
-
AND closed_at IS NULL
|
|
102
119
|
AND model IS NOT NULL AND model != ''
|
|
103
120
|
GROUP BY model
|
|
104
121
|
ORDER BY count DESC
|
package/ecosystem.config.cjs
CHANGED
|
@@ -15,7 +15,8 @@ module.exports = {
|
|
|
15
15
|
exec_mode: 'fork', // Use fork mode for ESM compatibility
|
|
16
16
|
autorestart: true,
|
|
17
17
|
watch: false,
|
|
18
|
-
|
|
18
|
+
// 进程 baseline ~184MB 贴近 200M 线导致频繁 OOM kill,内存增长另排查
|
|
19
|
+
max_memory_restart: '600M',
|
|
19
20
|
env: {
|
|
20
21
|
NODE_ENV: 'production',
|
|
21
22
|
CONFIG_PATH: configPath,
|