@rynx-ai/server 0.1.11-beta.3 → 0.1.11-beta.30
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/control-api.d.ts +16 -4
- package/dist/control-api.js +676 -83
- package/dist/control-web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/control-web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/control-web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/control-web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/control-web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/control-web/assets/abap-BdImnpbu.js +1 -0
- package/dist/control-web/assets/abnfDiagram-VRR7QNED-COu02MlJ.js +1 -0
- package/dist/control-web/assets/actionscript-3-CoDkCxhg.js +1 -0
- package/dist/control-web/assets/ada-bCR0ucgS.js +1 -0
- package/dist/control-web/assets/andromeeda-C4gqWexZ.js +1 -0
- package/dist/control-web/assets/angular-html-CU67Zn6k.js +1 -0
- package/dist/control-web/assets/angular-ts-BwZT4LLn.js +1 -0
- package/dist/control-web/assets/apache-Pmp26Uib.js +1 -0
- package/dist/control-web/assets/apex-D8_7TLub.js +1 -0
- package/dist/control-web/assets/apl-dKokRX4l.js +1 -0
- package/dist/control-web/assets/applescript-Co6uUVPk.js +1 -0
- package/dist/control-web/assets/ara-BRHolxvo.js +1 -0
- package/dist/control-web/assets/arc-DqiFeYAM.js +1 -0
- package/dist/control-web/assets/architectureDiagram-ZJ3FMSHR-BWFGgUV4.js +36 -0
- package/dist/control-web/assets/asciidoc-Ve4PFQV2.js +1 -0
- package/dist/control-web/assets/asm-D_Q5rh1f.js +1 -0
- package/dist/control-web/assets/astro-CbQHKStN.js +1 -0
- package/dist/control-web/assets/aurora-x-D-2ljcwZ.js +1 -0
- package/dist/control-web/assets/awk-DMzUqQB5.js +1 -0
- package/dist/control-web/assets/ayu-dark-DYE7WIF3.js +1 -0
- package/dist/control-web/assets/ayu-light-BA47KaF1.js +1 -0
- package/dist/control-web/assets/ayu-mirage-32ctXXKs.js +1 -0
- package/dist/control-web/assets/ballerina-BFfxhgS-.js +1 -0
- package/dist/control-web/assets/bat-BkioyH1T.js +1 -0
- package/dist/control-web/assets/beancount-k_qm7-4y.js +1 -0
- package/dist/control-web/assets/berry-uYugtg8r.js +1 -0
- package/dist/control-web/assets/bibtex-CHM0blh-.js +1 -0
- package/dist/control-web/assets/bicep-Bmn6On1c.js +1 -0
- package/dist/control-web/assets/bird2-DPOp833l.js +1 -0
- package/dist/control-web/assets/blade-D4QpJJKB.js +1 -0
- package/dist/control-web/assets/blockDiagram-677ZJIJ3-ZC0bXDzB.js +132 -0
- package/dist/control-web/assets/bsl-BO_Y6i37.js +1 -0
- package/dist/control-web/assets/c-BIGW1oBm.js +1 -0
- package/dist/control-web/assets/c3-eo99z4R2.js +1 -0
- package/dist/control-web/assets/c4Diagram-LMCZKHZV-Uupq5I-s.js +10 -0
- package/dist/control-web/assets/cadence-Bv_4Rxtq.js +1 -0
- package/dist/control-web/assets/cairo-KRGpt6FW.js +1 -0
- package/dist/control-web/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- package/dist/control-web/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- package/dist/control-web/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- package/dist/control-web/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- package/dist/control-web/assets/channel-3HG15wfa.js +1 -0
- package/dist/control-web/assets/chunk-2Q5K7J3B-C77vwuDM.js +1 -0
- package/dist/control-web/assets/chunk-32BRIVSS-BkfLE_TX.js +1 -0
- package/dist/control-web/assets/chunk-5VM5RSS4-By6zfDWW.js +15 -0
- package/dist/control-web/assets/chunk-EX3LRPZG-CO439p_3.js +231 -0
- package/dist/control-web/assets/chunk-JWPE2WC7-B9BPEwug.js +1 -0
- package/dist/control-web/assets/chunk-MOJQB5TN-CYKygWZz.js +88 -0
- package/dist/control-web/assets/chunk-RYQCIY6F-ug-An4HG.js +1 -0
- package/dist/control-web/assets/chunk-V7JOEXUC-3UFQGnKX.js +206 -0
- package/dist/control-web/assets/chunk-VR4S4FIN-DjspjYUb.js +1 -0
- package/dist/control-web/assets/chunk-XXDRQBXY-3znnutie.js +1 -0
- package/dist/control-web/assets/clarity-D53aC0YG.js +1 -0
- package/dist/control-web/assets/classDiagram-OUVF2IWQ-WmU4L9YT.js +1 -0
- package/dist/control-web/assets/classDiagram-v2-EOCWNBFH-WmU4L9YT.js +1 -0
- package/dist/control-web/assets/clojure-P80f7IUj.js +1 -0
- package/dist/control-web/assets/cmake-D1j8_8rp.js +1 -0
- package/dist/control-web/assets/cobol-nwyudZeR.js +1 -0
- package/dist/control-web/assets/codeowners-Bp6g37R7.js +1 -0
- package/dist/control-web/assets/codeql-DsOJ9woJ.js +1 -0
- package/dist/control-web/assets/coffee-Ch7k5sss.js +1 -0
- package/dist/control-web/assets/common-lisp-Cg-RD9OK.js +1 -0
- package/dist/control-web/assets/coq-DkFqJrB1.js +1 -0
- package/dist/control-web/assets/cose-bilkent-JH36ORCC-Dr28goCd.js +1 -0
- package/dist/control-web/assets/cpp-CofmeUqb.js +1 -0
- package/dist/control-web/assets/crystal-tKQVLTB8.js +1 -0
- package/dist/control-web/assets/csharp-COcwbKMJ.js +1 -0
- package/dist/control-web/assets/css-DPfMkruS.js +1 -0
- package/dist/control-web/assets/csv-fuZLfV_i.js +1 -0
- package/dist/control-web/assets/cue-D82EKSYY.js +1 -0
- package/dist/control-web/assets/cynefin-VYW2F7L2-Be5uJhnw.js +178 -0
- package/dist/control-web/assets/cynefinDiagram-TSTJHNR4-BLxtSvL6.js +62 -0
- package/dist/control-web/assets/cypher-COkxafJQ.js +1 -0
- package/dist/control-web/assets/cytoscape.esm-DTSO7Bv0.js +331 -0
- package/dist/control-web/assets/d-85-TOEBH.js +1 -0
- package/dist/control-web/assets/dagre-VKFMJZFB-DPRuDV5p.js +4 -0
- package/dist/control-web/assets/dark-plus-C3mMm8J8.js +1 -0
- package/dist/control-web/assets/dart-CF10PKvl.js +1 -0
- package/dist/control-web/assets/dax-CEL-wOlO.js +1 -0
- package/dist/control-web/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/control-web/assets/desktop-BmXAJ9_W.js +1 -0
- package/dist/control-web/assets/diagram-FQU43EPY-Cybg22U0.js +3 -0
- package/dist/control-web/assets/diagram-G47NLZAW-CGeIKUfW.js +24 -0
- package/dist/control-web/assets/diagram-NH7WQ7WH-BJq5MBRm.js +24 -0
- package/dist/control-web/assets/diagram-OA4YK3LP-DquOQGwg.js +30 -0
- package/dist/control-web/assets/diagram-WEI45ONY-Cblb4xP2.js +41 -0
- package/dist/control-web/assets/diff-D97Zzqfu.js +1 -0
- package/dist/control-web/assets/docker-BcOcwvcX.js +1 -0
- package/dist/control-web/assets/dotenv-Da5cRb03.js +1 -0
- package/dist/control-web/assets/dracula-BzJJZx-M.js +1 -0
- package/dist/control-web/assets/dracula-soft-BXkSAIEj.js +1 -0
- package/dist/control-web/assets/dream-maker-BtqSS_iP.js +1 -0
- package/dist/control-web/assets/ebnfDiagram-CCIWWBDH-CQjHiOqj.js +1 -0
- package/dist/control-web/assets/edge-BkV0erSs.js +1 -0
- package/dist/control-web/assets/elixir-CDX3lj18.js +1 -0
- package/dist/control-web/assets/elm-DbKCFpqz.js +1 -0
- package/dist/control-web/assets/emacs-lisp-C9XAeP06.js +1 -0
- package/dist/control-web/assets/erDiagram-Q63AITRT-Bspr3uKJ.js +85 -0
- package/dist/control-web/assets/erb-B12qg9BL.js +1 -0
- package/dist/control-web/assets/erlang-DsQrWhSR.js +1 -0
- package/dist/control-web/assets/everforest-dark-BgDCqdQA.js +1 -0
- package/dist/control-web/assets/everforest-light-C8M2exoo.js +1 -0
- package/dist/control-web/assets/fennel-BYunw83y.js +1 -0
- package/dist/control-web/assets/fish-BvzEVeQv.js +1 -0
- package/dist/control-web/assets/flowDiagram-23GEKE2U-CxcZyBA-.js +156 -0
- package/dist/control-web/assets/fluent-C4IJs8-o.js +1 -0
- package/dist/control-web/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
- package/dist/control-web/assets/fortran-free-form-BxgE0vQu.js +1 -0
- package/dist/control-web/assets/fsharp-CXgrBDvD.js +1 -0
- package/dist/control-web/assets/ganttDiagram-NO4QXBWP-qBdh7A-P.js +292 -0
- package/dist/control-web/assets/gdresource-BOOCDP_w.js +1 -0
- package/dist/control-web/assets/gdscript-C5YyOfLZ.js +1 -0
- package/dist/control-web/assets/gdshader-DkwncUOv.js +1 -0
- package/dist/control-web/assets/genie-D0YGMca9.js +1 -0
- package/dist/control-web/assets/gherkin-DyxjwDmM.js +1 -0
- package/dist/control-web/assets/git-commit-F4YmCXRG.js +1 -0
- package/dist/control-web/assets/git-rebase-r7XF79zn.js +1 -0
- package/dist/control-web/assets/gitGraphDiagram-IHSO6WYX-BTYub2KT.js +106 -0
- package/dist/control-web/assets/github-dark-DHJKELXO.js +1 -0
- package/dist/control-web/assets/github-dark-default-Cuk6v7N8.js +1 -0
- package/dist/control-web/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- package/dist/control-web/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- package/dist/control-web/assets/github-light-DAi9KRSo.js +1 -0
- package/dist/control-web/assets/github-light-default-D7oLnXFd.js +1 -0
- package/dist/control-web/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- package/dist/control-web/assets/gleam-BspZqrRM.js +1 -0
- package/dist/control-web/assets/glimmer-js-Rg0-pVw9.js +1 -0
- package/dist/control-web/assets/glimmer-ts-U6CK756n.js +1 -0
- package/dist/control-web/assets/glsl-DplSGwfg.js +1 -0
- package/dist/control-web/assets/gn-n2N0HUVH.js +1 -0
- package/dist/control-web/assets/gnuplot-DdkO51Og.js +1 -0
- package/dist/control-web/assets/go-CxLEBnE3.js +1 -0
- package/dist/control-web/assets/graph-C9eacEi8.js +1 -0
- package/dist/control-web/assets/graphql-ChdNCCLP.js +1 -0
- package/dist/control-web/assets/groovy-gcz8RCvz.js +1 -0
- package/dist/control-web/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- package/dist/control-web/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- package/dist/control-web/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- package/dist/control-web/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- package/dist/control-web/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- package/dist/control-web/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- package/dist/control-web/assets/hack-CaT9iCJl.js +1 -0
- package/dist/control-web/assets/haml-B8DHNrY2.js +1 -0
- package/dist/control-web/assets/handlebars-BL8al0AC.js +1 -0
- package/dist/control-web/assets/haskell-Df6bDoY_.js +1 -0
- package/dist/control-web/assets/haxe-CzTSHFRz.js +1 -0
- package/dist/control-web/assets/hcl-BWvSN4gD.js +1 -0
- package/dist/control-web/assets/{highlighted-body-OFNGDK62-DWWsUtHF.js → highlighted-body-OFNGDK62-DyksUrwu.js} +1 -1
- package/dist/control-web/assets/hjson-D5-asLiD.js +1 -0
- package/dist/control-web/assets/hlsl-D3lLCCz7.js +1 -0
- package/dist/control-web/assets/horizon-BUw7H-hv.js +1 -0
- package/dist/control-web/assets/horizon-bright-Cn-bp-IR.js +1 -0
- package/dist/control-web/assets/houston-DnULxvSX.js +1 -0
- package/dist/control-web/assets/html-GMplVEZG.js +1 -0
- package/dist/control-web/assets/html-derivative-BFtXZ54Q.js +1 -0
- package/dist/control-web/assets/http-jrhK8wxY.js +1 -0
- package/dist/control-web/assets/hurl-irOxFIW8.js +1 -0
- package/dist/control-web/assets/hxml-Bvhsp5Yf.js +1 -0
- package/dist/control-web/assets/hy-DFXneXwc.js +1 -0
- package/dist/control-web/assets/imba-DGztddWO.js +1 -0
- package/dist/control-web/assets/index-B9SAq_63.js +718 -0
- package/dist/control-web/assets/index-BDaSctIT.js +153 -0
- package/dist/control-web/assets/index-CtaYRNgJ.css +32 -0
- package/dist/control-web/assets/infoDiagram-FWYZ7A6U-ChbQR3Zo.js +2 -0
- package/dist/control-web/assets/ini-BEwlwnbL.js +1 -0
- package/dist/control-web/assets/init-Gi6I4Gst.js +1 -0
- package/dist/control-web/assets/ishikawaDiagram-FXEZZL3T-C-4_qGzn.js +70 -0
- package/dist/control-web/assets/java-CylS5w8V.js +1 -0
- package/dist/control-web/assets/javascript-wDzz0qaB.js +1 -0
- package/dist/control-web/assets/jinja-4LBKfQ-Z.js +1 -0
- package/dist/control-web/assets/jison-wvAkD_A8.js +1 -0
- package/dist/control-web/assets/journeyDiagram-5HDEW3XC-B090zN18.js +139 -0
- package/dist/control-web/assets/json-Cp-IABpG.js +1 -0
- package/dist/control-web/assets/json5-C9tS-k6U.js +1 -0
- package/dist/control-web/assets/jsonc-Des-eS-w.js +1 -0
- package/dist/control-web/assets/jsonl-DcaNXYhu.js +1 -0
- package/dist/control-web/assets/jsonnet-DFQXde-d.js +1 -0
- package/dist/control-web/assets/jssm-C2t-YnRu.js +1 -0
- package/dist/control-web/assets/jsx-g9-lgVsj.js +1 -0
- package/dist/control-web/assets/julia-CxzCAyBv.js +1 -0
- package/dist/control-web/assets/just-Cw27pwNe.js +1 -0
- package/dist/control-web/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- package/dist/control-web/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- package/dist/control-web/assets/kanagawa-wave-DWedfzmr.js +1 -0
- package/dist/control-web/assets/kanban-definition-HUTT4EX6-RlTcRbPs.js +89 -0
- package/dist/control-web/assets/kdl-DV7GczEv.js +1 -0
- package/dist/control-web/assets/kotlin-BdnUsdx6.js +1 -0
- package/dist/control-web/assets/kusto-DZf3V79B.js +1 -0
- package/dist/control-web/assets/laserwave-DUszq2jm.js +1 -0
- package/dist/control-web/assets/latex-CWtU0Tv5.js +1 -0
- package/dist/control-web/assets/layout-DEXfKzaS.js +1 -0
- package/dist/control-web/assets/lean-BZvkOJ9d.js +1 -0
- package/dist/control-web/assets/less-B1dDrJ26.js +1 -0
- package/dist/control-web/assets/light-plus-B7mTdjB0.js +1 -0
- package/dist/control-web/assets/linear-DTuNxDqu.js +1 -0
- package/dist/control-web/assets/liquid-DYVedYrR.js +1 -0
- package/dist/control-web/assets/llvm-DjAJT7YJ.js +1 -0
- package/dist/control-web/assets/log-2UxHyX5q.js +1 -0
- package/dist/control-web/assets/logo-BtOb2qkB.js +1 -0
- package/dist/control-web/assets/lua-BaeVxFsk.js +1 -0
- package/dist/control-web/assets/luau-C-HG3fhB.js +1 -0
- package/dist/control-web/assets/make-CHLpvVh8.js +1 -0
- package/dist/control-web/assets/map-Czzmt4hB.js +1 -0
- package/dist/control-web/assets/markdown-Cvjx9yec.js +1 -0
- package/dist/control-web/assets/marko-CnJfTvn9.js +1 -0
- package/dist/control-web/assets/material-theme-D5KoaKCx.js +1 -0
- package/dist/control-web/assets/material-theme-darker-BfHTSMKl.js +1 -0
- package/dist/control-web/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- package/dist/control-web/assets/material-theme-ocean-CyktbL80.js +1 -0
- package/dist/control-web/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- package/dist/control-web/assets/matlab-D7o27uSR.js +1 -0
- package/dist/control-web/assets/mdc-BMNejdWA.js +1 -0
- package/dist/control-web/assets/mdx-Cmh6b_Ma.js +1 -0
- package/dist/control-web/assets/mermaid-GHXKKRXX-BYZTj3zW.css +1 -0
- package/dist/control-web/assets/mermaid-GHXKKRXX-BkcV3dgg.js +710 -0
- package/dist/control-web/assets/mermaid-mWjccvbQ.js +1 -0
- package/dist/control-web/assets/min-dark-CafNBF8u.js +1 -0
- package/dist/control-web/assets/min-light-CTRr51gU.js +1 -0
- package/dist/control-web/assets/mindmap-definition-LN4V7U3C-DYby41E9.js +96 -0
- package/dist/control-web/assets/mipsasm-CKIfxQSi.js +1 -0
- package/dist/control-web/assets/mojo-rZm6bMo-.js +1 -0
- package/dist/control-web/assets/monokai-D4h5O-jR.js +1 -0
- package/dist/control-web/assets/moonbit-_H4v1dQx.js +1 -0
- package/dist/control-web/assets/move-IF9eRakj.js +1 -0
- package/dist/control-web/assets/narrat-DRg8JJMk.js +1 -0
- package/dist/control-web/assets/nextflow-Zz6hmt5N.js +1 -0
- package/dist/control-web/assets/nextflow-groovy-BeH2EWoN.js +1 -0
- package/dist/control-web/assets/nginx-BpAMiNFr.js +1 -0
- package/dist/control-web/assets/night-owl-C39BiMTA.js +1 -0
- package/dist/control-web/assets/night-owl-light-CMTm3GFP.js +1 -0
- package/dist/control-web/assets/nim-CVrawwO9.js +1 -0
- package/dist/control-web/assets/nix-CwoSXNpI.js +1 -0
- package/dist/control-web/assets/nord-Ddv68eIx.js +1 -0
- package/dist/control-web/assets/nushell-Cz2AlsmD.js +1 -0
- package/dist/control-web/assets/objective-c-DXmwc3jG.js +1 -0
- package/dist/control-web/assets/objective-cpp-CLxacb5B.js +1 -0
- package/dist/control-web/assets/ocaml-C0hk2d4L.js +1 -0
- package/dist/control-web/assets/odin-BBf5iR-q.js +1 -0
- package/dist/control-web/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- package/dist/control-web/assets/one-light-C3Wv6jpd.js +1 -0
- package/dist/control-web/assets/openscad-C4EeE6gA.js +1 -0
- package/dist/control-web/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/control-web/assets/pascal-D93ZcfNL.js +1 -0
- package/dist/control-web/assets/pegDiagram-2B236MQR-CPK6GaEv.js +1 -0
- package/dist/control-web/assets/perl-C0TMdlhV.js +1 -0
- package/dist/control-web/assets/php-Dhbhpdrm.js +1 -0
- package/dist/control-web/assets/pieDiagram-ENE6RG2P-DLCmXuji.js +39 -0
- package/dist/control-web/assets/pkl-u5AG7uiY.js +1 -0
- package/dist/control-web/assets/plastic-3e1v2bzS.js +1 -0
- package/dist/control-web/assets/plsql-ChMvpjG-.js +1 -0
- package/dist/control-web/assets/po-BTJTHyun.js +1 -0
- package/dist/control-web/assets/poimandres-CS3Unz2-.js +1 -0
- package/dist/control-web/assets/polar-C0HS_06l.js +1 -0
- package/dist/control-web/assets/postcss-CXtECtnM.js +1 -0
- package/dist/control-web/assets/powerquery-CEu0bR-o.js +1 -0
- package/dist/control-web/assets/powershell-Dpen1YoG.js +1 -0
- package/dist/control-web/assets/prisma-Dd19v3D-.js +1 -0
- package/dist/control-web/assets/prolog-CbFg5uaA.js +1 -0
- package/dist/control-web/assets/proto-C7zT0LnQ.js +1 -0
- package/dist/control-web/assets/pug-CGlum2m_.js +1 -0
- package/dist/control-web/assets/puppet-BMWR74SV.js +1 -0
- package/dist/control-web/assets/purescript-CklMAg4u.js +1 -0
- package/dist/control-web/assets/python-B6aJPvgy.js +1 -0
- package/dist/control-web/assets/qml-3beO22l8.js +1 -0
- package/dist/control-web/assets/qmldir-C8lEn-DE.js +1 -0
- package/dist/control-web/assets/qss-IeuSbFQv.js +1 -0
- package/dist/control-web/assets/quadrantDiagram-ABIIQ3AL-RIS8r7CA.js +7 -0
- package/dist/control-web/assets/r-Dspwwk_N.js +1 -0
- package/dist/control-web/assets/racket-BqYA7rlc.js +1 -0
- package/dist/control-web/assets/railroadDiagram-RFXS5EU6-B1HB7xsg.js +1 -0
- package/dist/control-web/assets/raku-DXvB9xmW.js +1 -0
- package/dist/control-web/assets/razor-Uh8Bk_45.js +1 -0
- package/dist/control-web/assets/red-bN70gL4F.js +1 -0
- package/dist/control-web/assets/reg-C-SQnVFl.js +1 -0
- package/dist/control-web/assets/regexp-CDVJQ6XC.js +1 -0
- package/dist/control-web/assets/rel-C3B-1QV4.js +1 -0
- package/dist/control-web/assets/requirementDiagram-TGXJPOKE-Inh_4hU0.js +84 -0
- package/dist/control-web/assets/riscv-BM1_JUlF.js +1 -0
- package/dist/control-web/assets/ron-D8l8udqQ.js +1 -0
- package/dist/control-web/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
- package/dist/control-web/assets/rose-pine-moon-D4_iv3hh.js +1 -0
- package/dist/control-web/assets/rose-pine-qdsjHGoJ.js +1 -0
- package/dist/control-web/assets/rosmsg-BJDFO7_C.js +1 -0
- package/dist/control-web/assets/rst-BrH8l1NY.js +1 -0
- package/dist/control-web/assets/ruby-Dw2BHqvy.js +1 -0
- package/dist/control-web/assets/rust-B1yitclQ.js +1 -0
- package/dist/control-web/assets/sankeyDiagram-HTMAVEWB-DPF33kPB.js +40 -0
- package/dist/control-web/assets/sas-cz2c8ADy.js +1 -0
- package/dist/control-web/assets/sass-Cj5Yp3dK.js +1 -0
- package/dist/control-web/assets/scala-C151Ov-r.js +1 -0
- package/dist/control-web/assets/scheme-C98Dy4si.js +1 -0
- package/dist/control-web/assets/scss-OYdSNvt2.js +1 -0
- package/dist/control-web/assets/sdbl-DVxCFoDh.js +1 -0
- package/dist/control-web/assets/sequenceDiagram-DBY2YBRQ-iywKWoYc.js +162 -0
- package/dist/control-web/assets/shaderlab-Dg9Lc6iA.js +1 -0
- package/dist/control-web/assets/shellscript-Yzrsuije.js +1 -0
- package/dist/control-web/assets/shellsession-BADoaaVG.js +1 -0
- package/dist/control-web/assets/sizeCapture-X5ZJPWSS-DlnHubz9.js +1 -0
- package/dist/control-web/assets/slack-dark-BthQWCQV.js +1 -0
- package/dist/control-web/assets/slack-ochin-DqwNpetd.js +1 -0
- package/dist/control-web/assets/smalltalk-BERRCDM3.js +1 -0
- package/dist/control-web/assets/snazzy-light-Bw305WKR.js +1 -0
- package/dist/control-web/assets/solarized-dark-DXbdFlpD.js +1 -0
- package/dist/control-web/assets/solarized-light-L9t79GZl.js +1 -0
- package/dist/control-web/assets/solidity-rGO070M0.js +1 -0
- package/dist/control-web/assets/soy-Brmx7dQM.js +1 -0
- package/dist/control-web/assets/sparql-rVzFXLq3.js +1 -0
- package/dist/control-web/assets/splunk-BtCnVYZw.js +1 -0
- package/dist/control-web/assets/sql-BLtJtn59.js +1 -0
- package/dist/control-web/assets/ssh-config-_ykCGR6B.js +1 -0
- package/dist/control-web/assets/stata-BH5u7GGu.js +1 -0
- package/dist/control-web/assets/stateDiagram-2N3HPSRC-CShzll2N.js +1 -0
- package/dist/control-web/assets/stateDiagram-v2-6OUMAXLB-Cdx0fWna.js +1 -0
- package/dist/control-web/assets/stylus-BEDo0Tqx.js +1 -0
- package/dist/control-web/assets/surrealql-Bq5Q-fJD.js +1 -0
- package/dist/control-web/assets/svelte-C_ipcX3V.js +1 -0
- package/dist/control-web/assets/swift-D82vCrfD.js +1 -0
- package/dist/control-web/assets/swimlanes-5IMT3BWC-CxlQpFBv.js +2 -0
- package/dist/control-web/assets/swimlanesDiagram-G3AALYLV-CoX0jnUu.js +8 -0
- package/dist/control-web/assets/synthwave-84-CbfX1IO0.js +1 -0
- package/dist/control-web/assets/system-verilog-CnnmHF94.js +1 -0
- package/dist/control-web/assets/systemd-4A_iFExJ.js +1 -0
- package/dist/control-web/assets/talonscript-CkByrt1z.js +1 -0
- package/dist/control-web/assets/tasl-QIJgUcNo.js +1 -0
- package/dist/control-web/assets/tcl-dwOrl1Do.js +1 -0
- package/dist/control-web/assets/templ-P3uqSqPl.js +1 -0
- package/dist/control-web/assets/terraform-BETggiCN.js +1 -0
- package/dist/control-web/assets/tex-idrVyKtj.js +1 -0
- package/dist/control-web/assets/timeline-definition-FHXFAJF6-Dlx59Xc3.js +120 -0
- package/dist/control-web/assets/tokyo-night-hegEt444.js +1 -0
- package/dist/control-web/assets/toml-vGWfd6FD.js +1 -0
- package/dist/control-web/assets/ts-tags-zn1MmPIZ.js +1 -0
- package/dist/control-web/assets/tsv-B_m7g4N7.js +1 -0
- package/dist/control-web/assets/tsx-COt5Ahok.js +1 -0
- package/dist/control-web/assets/turtle-BsS91CYL.js +1 -0
- package/dist/control-web/assets/twig-DNn4PbVi.js +1 -0
- package/dist/control-web/assets/typescript-BPQ3VLAy.js +1 -0
- package/dist/control-web/assets/typespec-BGHnOYBU.js +1 -0
- package/dist/control-web/assets/typst-DHCkPAjA.js +1 -0
- package/dist/control-web/assets/v-BcVCzyr7.js +1 -0
- package/dist/control-web/assets/vala-CsfeWuGM.js +1 -0
- package/dist/control-web/assets/vb-D17OF-Vu.js +1 -0
- package/dist/control-web/assets/vennDiagram-L72KCM5P-DLsv4i_t.js +34 -0
- package/dist/control-web/assets/verilog-BQ8w6xss.js +1 -0
- package/dist/control-web/assets/vesper-DU1UobuO.js +1 -0
- package/dist/control-web/assets/vhdl-CeAyd5Ju.js +1 -0
- package/dist/control-web/assets/viml-CJc9bBzg.js +1 -0
- package/dist/control-web/assets/vitesse-black-Bkuqu6BP.js +1 -0
- package/dist/control-web/assets/vitesse-dark-D0r3Knsf.js +1 -0
- package/dist/control-web/assets/vitesse-light-CVO1_9PV.js +1 -0
- package/dist/control-web/assets/vue-DN_0RTcg.js +1 -0
- package/dist/control-web/assets/vue-html-AaS7Mt5G.js +1 -0
- package/dist/control-web/assets/vue-vine-CQOfvN7w.js +1 -0
- package/dist/control-web/assets/vyper-CDx5xZoG.js +1 -0
- package/dist/control-web/assets/wardleyDiagram-EHGQE667-BazV8fpH.js +78 -0
- package/dist/control-web/assets/wasm-CG6Dc4jp.js +1 -0
- package/dist/control-web/assets/wasm-MzD3tlZU.js +1 -0
- package/dist/control-web/assets/wenyan-BV7otONQ.js +1 -0
- package/dist/control-web/assets/wgsl-Dx-B1_4e.js +1 -0
- package/dist/control-web/assets/wikitext-BhOHFoWU.js +1 -0
- package/dist/control-web/assets/wit-5i3qLPDT.js +1 -0
- package/dist/control-web/assets/wolfram-lXgVvXCa.js +1 -0
- package/dist/control-web/assets/xml-sdJ4AIDG.js +1 -0
- package/dist/control-web/assets/xsl-CtQFsRM5.js +1 -0
- package/dist/control-web/assets/xychartDiagram-FW5EYKEG-Bx9uDlYu.js +7 -0
- package/dist/control-web/assets/yaml-Buea-lGh.js +1 -0
- package/dist/control-web/assets/zenscript-DVFEvuxE.js +1 -0
- package/dist/control-web/assets/zig-VOosw3JB.js +1 -0
- package/dist/control-web/index.html +2 -2
- package/dist/control-web-dist.d.ts +1 -1
- package/dist/control-web-dist.js +4 -2
- package/dist/machine-session-service.d.ts +82 -15
- package/dist/machine-session-service.js +670 -80
- package/dist/remote-runtime-dispatcher.d.ts +1 -1
- package/dist/remote-runtime-dispatcher.js +16 -1
- package/dist/remote-runtime-session-projection.js +5 -0
- package/dist/server.d.ts +24 -7
- package/dist/server.js +207 -46
- package/dist/session-portal.d.ts +42 -0
- package/dist/session-portal.js +746 -0
- package/dist/session-runtime-index.d.ts +2 -6
- package/dist/session-runtime-index.js +70 -38
- package/dist/terminal-ws.js +8 -6
- package/package.json +7 -7
- package/dist/control-web/assets/index-BnX7NWJX.js +0 -689
- package/dist/control-web/assets/index-CUoWRX2i.css +0 -32
- package/dist/control-web/assets/mermaid-GHXKKRXX-C1fxAgiw.js +0 -131
package/dist/control-api.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* owns that state and exposes its own management application.
|
|
8
8
|
*/
|
|
9
9
|
import { timingSafeEqual } from "node:crypto";
|
|
10
|
+
import { Readable } from "node:stream";
|
|
10
11
|
import Router from "@koa/router";
|
|
11
12
|
import { skillInstallRecipeSchema, } from "@rynx-ai/core";
|
|
12
13
|
import { DAEMON_BROWSER_ARTIFACT_CLEAN_PATH, DAEMON_BROWSER_ARTIFACT_INSTALL_PATH, DAEMON_BROWSER_ARTIFACT_UPDATE_PATH, DAEMON_BROWSER_ARTIFACT_VERSION_PATH, DAEMON_CHROME_INSPECTION_PATH, DAEMON_CLEANUP_SESSIONS_PATH, DAEMON_MAINTENANCE_LEASE_HEADER, DAEMON_MAINTENANCE_LEASE_RELEASE_PATH, DAEMON_SHUTDOWN_IF_IDLE_PATH, parseDaemonBrowserArtifactInstallInput, parseDaemonBrowserArtifactUpdateInput, parseDaemonChromeInspectionConfigureInput, parseDaemonCleanupSessionsInput, } from "@rynx-ai/protocol/control";
|
|
@@ -19,6 +20,7 @@ import { parseRuntimeBrowserStateGetParams } from "@rynx-ai/protocol/runtime-bro
|
|
|
19
20
|
import { encodeDaemonStatus } from "./remote-runtime.js";
|
|
20
21
|
import { SessionRuntimeIndex } from "./session-runtime-index.js";
|
|
21
22
|
import { authorizeRuntimeWebRequest, RUNTIME_WEB_CAPABILITY, RUNTIME_WEB_CAPABILITY_HEADER, } from "./runtime-web-auth.js";
|
|
23
|
+
import { MachineSessionServiceFailure, } from "./machine-session-service.js";
|
|
22
24
|
const PLUGIN_CLI_BODY_MAX_BYTES = 512 * 1024;
|
|
23
25
|
const PLUGIN_CLI_STDIN_MAX_BYTES = 256 * 1024;
|
|
24
26
|
const PLUGIN_CLI_ARG_MAX_BYTES = 4 * 1024;
|
|
@@ -724,6 +726,30 @@ export function createControlRouter(opts) {
|
|
|
724
726
|
if (outcome.ok)
|
|
725
727
|
ctx.body = outcome.result;
|
|
726
728
|
};
|
|
729
|
+
const runtimeSessionExecutionSettings = async (ctx) => {
|
|
730
|
+
const outcome = await runtimeCall(ctx, "session.execution.get", {
|
|
731
|
+
sessionId: ctx.params.id,
|
|
732
|
+
});
|
|
733
|
+
if (outcome.ok)
|
|
734
|
+
ctx.body = outcome.result;
|
|
735
|
+
};
|
|
736
|
+
const runtimeSessionExecutionSettingsUpdate = async (ctx) => {
|
|
737
|
+
const body = await readRuntimeBody(ctx);
|
|
738
|
+
if (!body)
|
|
739
|
+
return;
|
|
740
|
+
if (!acceptRuntimeBodyKeys(ctx, body, ["model", "reasoningEffort", "collaborationMode"]))
|
|
741
|
+
return;
|
|
742
|
+
const outcome = await runtimeCall(ctx, "session.execution.update", {
|
|
743
|
+
sessionId: ctx.params.id,
|
|
744
|
+
model: body.model,
|
|
745
|
+
reasoningEffort: body.reasoningEffort,
|
|
746
|
+
...(body.collaborationMode === undefined
|
|
747
|
+
? {}
|
|
748
|
+
: { collaborationMode: body.collaborationMode }),
|
|
749
|
+
});
|
|
750
|
+
if (outcome.ok)
|
|
751
|
+
ctx.body = outcome.result;
|
|
752
|
+
};
|
|
727
753
|
const runtimeSessionCreate = async (ctx) => {
|
|
728
754
|
const body = await readRuntimeBody(ctx);
|
|
729
755
|
if (!body)
|
|
@@ -834,7 +860,13 @@ export function createControlRouter(opts) {
|
|
|
834
860
|
};
|
|
835
861
|
const runtimeSessionResourceUpload = async (ctx) => {
|
|
836
862
|
const uploadStarted = performance.now();
|
|
837
|
-
const mediaType = ctx.get("content-type").split(";", 1)[0]?.trim();
|
|
863
|
+
const mediaType = ctx.get("content-type").split(";", 1)[0]?.trim().toLowerCase();
|
|
864
|
+
const requestedType = ctx.get("x-rynx-resource-type").trim();
|
|
865
|
+
const resourceType = requestedType === "input_image" || requestedType === "input_file"
|
|
866
|
+
? requestedType
|
|
867
|
+
: SESSION_IMAGE_MEDIA_TYPES.includes(mediaType)
|
|
868
|
+
? "input_image"
|
|
869
|
+
: "input_file";
|
|
838
870
|
const clientUploadId = ctx.get("x-rynx-upload-id").trim();
|
|
839
871
|
const encodedFilename = ctx.get("x-rynx-filename").trim();
|
|
840
872
|
let filename = "";
|
|
@@ -847,7 +879,9 @@ export function createControlRouter(opts) {
|
|
|
847
879
|
return;
|
|
848
880
|
}
|
|
849
881
|
if (!mediaType ||
|
|
850
|
-
!
|
|
882
|
+
!isMediaType(mediaType) ||
|
|
883
|
+
(resourceType === "input_image" &&
|
|
884
|
+
!SESSION_IMAGE_MEDIA_TYPES.includes(mediaType)) ||
|
|
851
885
|
!clientUploadId ||
|
|
852
886
|
!filename ||
|
|
853
887
|
filename.length > SESSION_RESOURCE_MAX_FILENAME_CHARS) {
|
|
@@ -855,23 +889,21 @@ export function createControlRouter(opts) {
|
|
|
855
889
|
ctx.body = { error: "invalid_resource_upload" };
|
|
856
890
|
return;
|
|
857
891
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
}
|
|
863
|
-
catch (error) {
|
|
864
|
-
ctx.status = error instanceof RequestBodyTooLargeError ? 413 : 400;
|
|
865
|
-
ctx.body = {
|
|
866
|
-
error: error instanceof RequestBodyTooLargeError
|
|
867
|
-
? "request_too_large"
|
|
868
|
-
: "invalid_resource_upload",
|
|
869
|
-
};
|
|
892
|
+
const contentLengthHeader = ctx.get("content-length").trim();
|
|
893
|
+
if (!contentLengthHeader) {
|
|
894
|
+
ctx.status = 411;
|
|
895
|
+
ctx.body = { error: "content_length_required" };
|
|
870
896
|
return;
|
|
871
897
|
}
|
|
872
|
-
|
|
898
|
+
const byteLength = Number(contentLengthHeader);
|
|
899
|
+
if (!Number.isSafeInteger(byteLength) || byteLength <= 0) {
|
|
873
900
|
ctx.status = 400;
|
|
874
|
-
ctx.body = { error: "
|
|
901
|
+
ctx.body = { error: "invalid_content_length" };
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
if (resourceType === "input_image" && byteLength > SESSION_RESOURCE_MAX_IMAGE_BYTES) {
|
|
905
|
+
ctx.status = 413;
|
|
906
|
+
ctx.body = { error: "request_too_large" };
|
|
875
907
|
return;
|
|
876
908
|
}
|
|
877
909
|
const sessionId = ctx.params.id;
|
|
@@ -879,9 +911,7 @@ export function createControlRouter(opts) {
|
|
|
879
911
|
const lease = local ? undefined : await acquireRuntimeLease(ctx);
|
|
880
912
|
if (!local && !lease)
|
|
881
913
|
return;
|
|
882
|
-
const timings = new Map(
|
|
883
|
-
["body", performance.now() - bodyReadStarted],
|
|
884
|
-
]);
|
|
914
|
+
const timings = new Map();
|
|
885
915
|
const timed = async (name, operation) => {
|
|
886
916
|
const started = performance.now();
|
|
887
917
|
try {
|
|
@@ -898,16 +928,18 @@ export function createControlRouter(opts) {
|
|
|
898
928
|
? local.beginResourceUpload({
|
|
899
929
|
sessionId,
|
|
900
930
|
clientUploadId,
|
|
931
|
+
type: resourceType,
|
|
901
932
|
filename,
|
|
902
933
|
mediaType,
|
|
903
|
-
byteLength
|
|
934
|
+
byteLength,
|
|
904
935
|
})
|
|
905
936
|
: lease.call("session.resource.upload.begin", {
|
|
906
937
|
sessionId,
|
|
907
938
|
clientUploadId,
|
|
939
|
+
type: resourceType,
|
|
908
940
|
filename,
|
|
909
941
|
mediaType,
|
|
910
|
-
byteLength
|
|
942
|
+
byteLength,
|
|
911
943
|
}, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS }));
|
|
912
944
|
const writeChunk = (uploadId, offset, data) => timed("chunks", () => local
|
|
913
945
|
? local.writeResourceUploadChunk({ sessionId, uploadId, offset, data })
|
|
@@ -915,44 +947,72 @@ export function createControlRouter(opts) {
|
|
|
915
947
|
const commit = (uploadId) => timed("commit", () => local
|
|
916
948
|
? local.commitResourceUpload({ sessionId, uploadId })
|
|
917
949
|
: lease.call("session.resource.upload.commit", { sessionId, uploadId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS }));
|
|
950
|
+
const discardPartial = (resourceId) => timed("restart", () => local
|
|
951
|
+
? local.deleteResource({ sessionId, resourceId })
|
|
952
|
+
: lease.call("session.resource.delete", { sessionId, resourceId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS }));
|
|
953
|
+
let requestResourceId;
|
|
954
|
+
let resourceCommitted = false;
|
|
918
955
|
try {
|
|
919
956
|
const resourcePolicy = await policy();
|
|
920
957
|
if (!resourcePolicy.enabled ||
|
|
921
|
-
|
|
922
|
-
|
|
958
|
+
(resourceType === "input_image" &&
|
|
959
|
+
(!resourcePolicy.mediaTypes.includes(mediaType) ||
|
|
960
|
+
byteLength > resourcePolicy.maxImageBytes))) {
|
|
923
961
|
ctx.status = 413;
|
|
924
962
|
ctx.body = { error: "resource_policy_rejected" };
|
|
925
963
|
return;
|
|
926
964
|
}
|
|
927
|
-
|
|
965
|
+
let begun = await begin();
|
|
928
966
|
if (begun.complete && begun.resource) {
|
|
967
|
+
ctx.req.resume();
|
|
929
968
|
ctx.set("Cache-Control", "no-store");
|
|
930
969
|
ctx.body = { resource: begun.resource };
|
|
931
970
|
return;
|
|
932
971
|
}
|
|
933
|
-
if (begun.offset < 0 || begun.offset >
|
|
972
|
+
if (begun.offset < 0 || begun.offset > byteLength) {
|
|
934
973
|
throw runtimeProtocolError("Runtime Session resource upload offset is invalid");
|
|
935
974
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
975
|
+
// Browser retries send the complete File body again. A target-side
|
|
976
|
+
// partial cannot be blindly combined with the new body's suffix: the
|
|
977
|
+
// caller may have reused an upload id for changed bytes. Restart the
|
|
978
|
+
// incomplete upload so committed content always matches this request.
|
|
979
|
+
if (begun.offset > 0) {
|
|
980
|
+
const discarded = await discardPartial(begun.resourceId);
|
|
981
|
+
if (!discarded.deleted) {
|
|
982
|
+
throw runtimeProtocolError("Runtime Session partial upload could not be restarted");
|
|
983
|
+
}
|
|
984
|
+
begun = await begin();
|
|
985
|
+
if (begun.complete || begun.offset !== 0) {
|
|
986
|
+
throw runtimeProtocolError("Runtime Session resource upload did not restart");
|
|
942
987
|
}
|
|
943
|
-
offset = written.offset;
|
|
944
988
|
}
|
|
989
|
+
requestResourceId = begun.resourceId;
|
|
990
|
+
const bodyStarted = performance.now();
|
|
991
|
+
await forwardResourceUploadBody(ctx, begun.uploadId, begun.offset, byteLength, writeChunk);
|
|
992
|
+
timings.set("body", performance.now() - bodyStarted);
|
|
945
993
|
const committed = await commit(begun.uploadId);
|
|
946
994
|
if (committed.resource.resourceId !== begun.resourceId ||
|
|
995
|
+
committed.resource.type !== resourceType ||
|
|
947
996
|
committed.resource.mediaType !== mediaType ||
|
|
948
|
-
committed.resource.byteLength !==
|
|
997
|
+
committed.resource.byteLength !== byteLength) {
|
|
949
998
|
throw runtimeProtocolError("Runtime Session resource upload identity changed");
|
|
950
999
|
}
|
|
1000
|
+
resourceCommitted = true;
|
|
951
1001
|
ctx.status = 201;
|
|
952
1002
|
ctx.set("Cache-Control", "no-store");
|
|
953
1003
|
ctx.body = committed;
|
|
954
1004
|
}
|
|
955
1005
|
catch (error) {
|
|
1006
|
+
if (requestResourceId && !resourceCommitted) {
|
|
1007
|
+
try {
|
|
1008
|
+
await discardPartial(requestResourceId);
|
|
1009
|
+
}
|
|
1010
|
+
catch {
|
|
1011
|
+
// The original error remains authoritative. Targets also reap stale
|
|
1012
|
+
// uploads, so a disconnected target cannot make cleanup block the
|
|
1013
|
+
// browser response indefinitely.
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
956
1016
|
runtimeTargetHostError(ctx, error);
|
|
957
1017
|
}
|
|
958
1018
|
finally {
|
|
@@ -968,7 +1028,7 @@ export function createControlRouter(opts) {
|
|
|
968
1028
|
event: "session.resource.upload.slow",
|
|
969
1029
|
selector: ctx.params.selector,
|
|
970
1030
|
sessionId,
|
|
971
|
-
byteLength
|
|
1031
|
+
byteLength,
|
|
972
1032
|
status: ctx.status,
|
|
973
1033
|
timings: Object.fromEntries([...timings.entries()].map(([name, duration]) => [
|
|
974
1034
|
name,
|
|
@@ -1012,16 +1072,32 @@ export function createControlRouter(opts) {
|
|
|
1012
1072
|
const sessionId = ctx.params.id;
|
|
1013
1073
|
const resourceId = ctx.params.resourceId;
|
|
1014
1074
|
const local = ctx.params.selector === "local" ? localSessionResources : undefined;
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1075
|
+
const invocation = downloadInvocationAbortScope(ctx, shutdownSignal);
|
|
1076
|
+
const lease = local ? undefined : await acquireRuntimeLease(ctx, invocation.signal);
|
|
1077
|
+
if (!local && !lease) {
|
|
1078
|
+
invocation.dispose();
|
|
1017
1079
|
return;
|
|
1080
|
+
}
|
|
1081
|
+
let streamOwnsLease = false;
|
|
1082
|
+
let cleanedUp = false;
|
|
1083
|
+
const cleanup = () => {
|
|
1084
|
+
if (cleanedUp)
|
|
1085
|
+
return;
|
|
1086
|
+
cleanedUp = true;
|
|
1087
|
+
lease?.release();
|
|
1088
|
+
invocation.dispose();
|
|
1089
|
+
};
|
|
1018
1090
|
try {
|
|
1019
1091
|
const { resource } = local
|
|
1020
1092
|
? await local.getResource({ sessionId, resourceId })
|
|
1021
|
-
: await lease.call("session.resource.get", { sessionId, resourceId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS });
|
|
1093
|
+
: await lease.call("session.resource.get", { sessionId, resourceId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1022
1094
|
if (resource.resourceId !== resourceId) {
|
|
1023
1095
|
throw runtimeProtocolError("Runtime Session resource identity changed");
|
|
1024
1096
|
}
|
|
1097
|
+
const byteLength = resource.byteLength;
|
|
1098
|
+
if (!Number.isSafeInteger(byteLength) || !byteLength || byteLength < 1) {
|
|
1099
|
+
throw runtimeProtocolError("Runtime Session resource length is invalid");
|
|
1100
|
+
}
|
|
1025
1101
|
const etag = `"sha256-${resource.sha256}"`;
|
|
1026
1102
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
|
1027
1103
|
ctx.set("ETag", etag);
|
|
@@ -1029,48 +1105,68 @@ export function createControlRouter(opts) {
|
|
|
1029
1105
|
ctx.status = 304;
|
|
1030
1106
|
return;
|
|
1031
1107
|
}
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
})
|
|
1042
|
-
: await lease.call("session.resource.read", {
|
|
1043
|
-
sessionId,
|
|
1044
|
-
resourceId,
|
|
1045
|
-
offset,
|
|
1046
|
-
length: SESSION_RESOURCE_TRANSFER_CHUNK_BYTES,
|
|
1047
|
-
}, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS });
|
|
1048
|
-
const chunk = Buffer.from(result.data, "base64");
|
|
1049
|
-
if (result.offset !== offset + chunk.byteLength || (!result.eof && chunk.byteLength === 0)) {
|
|
1050
|
-
throw runtimeProtocolError("Runtime Session resource read did not advance");
|
|
1051
|
-
}
|
|
1052
|
-
chunks.push(chunk);
|
|
1053
|
-
offset = result.offset;
|
|
1054
|
-
if (result.eof)
|
|
1055
|
-
break;
|
|
1056
|
-
}
|
|
1057
|
-
const body = Buffer.concat(chunks);
|
|
1058
|
-
if (body.byteLength !== resource.byteLength) {
|
|
1059
|
-
throw runtimeProtocolError("Runtime Session resource length changed");
|
|
1108
|
+
const requestedRange = ctx.get("range");
|
|
1109
|
+
const ifRange = ctx.get("if-range");
|
|
1110
|
+
const range = ifRange && ifRange !== etag
|
|
1111
|
+
? undefined
|
|
1112
|
+
: parseSingleByteRange(requestedRange, byteLength);
|
|
1113
|
+
if (range === "unsatisfiable") {
|
|
1114
|
+
ctx.status = 416;
|
|
1115
|
+
ctx.set("Content-Range", `bytes */${byteLength}`);
|
|
1116
|
+
return;
|
|
1060
1117
|
}
|
|
1118
|
+
const start = range?.start ?? 0;
|
|
1119
|
+
const end = range?.end ?? byteLength - 1;
|
|
1120
|
+
const responseLength = end - start + 1;
|
|
1061
1121
|
ctx.set("Content-Security-Policy", "default-src 'none'; sandbox");
|
|
1062
1122
|
ctx.set("Cross-Origin-Resource-Policy", "same-origin");
|
|
1063
1123
|
ctx.set("X-Content-Type-Options", "nosniff");
|
|
1064
|
-
ctx.set("
|
|
1124
|
+
ctx.set("Accept-Ranges", "bytes");
|
|
1125
|
+
ctx.set("Content-Disposition", contentDisposition(resource.filename));
|
|
1126
|
+
if (range) {
|
|
1127
|
+
ctx.status = 206;
|
|
1128
|
+
ctx.set("Content-Range", `bytes ${start}-${end}/${byteLength}`);
|
|
1129
|
+
}
|
|
1065
1130
|
ctx.type = resource.mediaType;
|
|
1066
|
-
ctx.length =
|
|
1131
|
+
ctx.length = responseLength;
|
|
1132
|
+
if (ctx.method === "HEAD") {
|
|
1133
|
+
ctx.status = range ? 206 : 200;
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
streamOwnsLease = true;
|
|
1137
|
+
const body = Readable.from((async function* () {
|
|
1138
|
+
let offset = start;
|
|
1139
|
+
try {
|
|
1140
|
+
while (offset <= end) {
|
|
1141
|
+
const length = Math.min(SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, end - offset + 1);
|
|
1142
|
+
const result = local
|
|
1143
|
+
? await local.readResource({ sessionId, resourceId, offset, length })
|
|
1144
|
+
: await lease.call("session.resource.read", { sessionId, resourceId, offset, length }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1145
|
+
const chunk = Buffer.from(result.data, "base64");
|
|
1146
|
+
if (result.offset !== offset + chunk.byteLength || chunk.byteLength === 0) {
|
|
1147
|
+
throw runtimeProtocolError("Runtime Session resource read did not advance");
|
|
1148
|
+
}
|
|
1149
|
+
offset = result.offset;
|
|
1150
|
+
yield chunk;
|
|
1151
|
+
}
|
|
1152
|
+
if (offset !== end + 1) {
|
|
1153
|
+
throw runtimeProtocolError("Runtime Session resource length changed");
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
finally {
|
|
1157
|
+
cleanup();
|
|
1158
|
+
}
|
|
1159
|
+
})());
|
|
1160
|
+
body.once("close", cleanup);
|
|
1067
1161
|
ctx.body = body;
|
|
1068
1162
|
}
|
|
1069
1163
|
catch (error) {
|
|
1070
1164
|
runtimeTargetHostError(ctx, error);
|
|
1071
1165
|
}
|
|
1072
1166
|
finally {
|
|
1073
|
-
|
|
1167
|
+
if (!streamOwnsLease) {
|
|
1168
|
+
cleanup();
|
|
1169
|
+
}
|
|
1074
1170
|
}
|
|
1075
1171
|
};
|
|
1076
1172
|
const runtimeSessionResourceDelete = async (ctx) => {
|
|
@@ -1094,6 +1190,243 @@ export function createControlRouter(opts) {
|
|
|
1094
1190
|
if (outcome.ok)
|
|
1095
1191
|
ctx.body = outcome.result;
|
|
1096
1192
|
};
|
|
1193
|
+
const runtimeSessionItemFileContent = async (ctx) => {
|
|
1194
|
+
const sessionId = ctx.params.id;
|
|
1195
|
+
const itemId = ctx.params.itemId;
|
|
1196
|
+
const partIndex = Number(ctx.params.partIndex);
|
|
1197
|
+
if (!Number.isSafeInteger(partIndex) || partIndex < 0 || partIndex > 1_024) {
|
|
1198
|
+
ctx.status = 400;
|
|
1199
|
+
ctx.body = { error: "invalid_part_index" };
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
const local = ctx.params.selector === "local" ? localMachineSessions : undefined;
|
|
1203
|
+
const invocation = downloadInvocationAbortScope(ctx, shutdownSignal);
|
|
1204
|
+
const lease = local ? undefined : await acquireRuntimeLease(ctx, invocation.signal);
|
|
1205
|
+
if (!local && !lease) {
|
|
1206
|
+
invocation.dispose();
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
let streamOwnsLease = false;
|
|
1210
|
+
let cleanedUp = false;
|
|
1211
|
+
const cleanup = () => {
|
|
1212
|
+
if (cleanedUp)
|
|
1213
|
+
return;
|
|
1214
|
+
cleanedUp = true;
|
|
1215
|
+
lease?.release();
|
|
1216
|
+
invocation.dispose();
|
|
1217
|
+
};
|
|
1218
|
+
try {
|
|
1219
|
+
const { file } = local
|
|
1220
|
+
? await local.getFile({ sessionId, itemId, partIndex })
|
|
1221
|
+
: await lease.call("session.file.get", { sessionId, itemId, partIndex }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1222
|
+
if (file.itemId !== itemId || file.partIndex !== partIndex) {
|
|
1223
|
+
throw runtimeProtocolError("Runtime Session file identity changed");
|
|
1224
|
+
}
|
|
1225
|
+
const etag = `"file-${file.version}"`;
|
|
1226
|
+
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
|
1227
|
+
ctx.set("ETag", etag);
|
|
1228
|
+
if (ctx.get("if-none-match").split(",").map((value) => value.trim()).includes(etag)) {
|
|
1229
|
+
ctx.status = 304;
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
const requestedRange = ctx.get("range");
|
|
1233
|
+
const ifRange = ctx.get("if-range");
|
|
1234
|
+
const range = ifRange && ifRange !== etag
|
|
1235
|
+
? undefined
|
|
1236
|
+
: parseSingleByteRange(requestedRange, file.byteLength);
|
|
1237
|
+
if (range === "unsatisfiable") {
|
|
1238
|
+
ctx.status = 416;
|
|
1239
|
+
ctx.set("Content-Range", `bytes */${file.byteLength}`);
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
const start = range?.start ?? 0;
|
|
1243
|
+
const end = range?.end ?? file.byteLength - 1;
|
|
1244
|
+
ctx.set("Content-Security-Policy", "default-src 'none'; sandbox");
|
|
1245
|
+
ctx.set("Cross-Origin-Resource-Policy", "same-origin");
|
|
1246
|
+
ctx.set("X-Content-Type-Options", "nosniff");
|
|
1247
|
+
ctx.set("Accept-Ranges", "bytes");
|
|
1248
|
+
ctx.set("Content-Disposition", contentDisposition(file.filename));
|
|
1249
|
+
if (range) {
|
|
1250
|
+
ctx.status = 206;
|
|
1251
|
+
ctx.set("Content-Range", `bytes ${start}-${end}/${file.byteLength}`);
|
|
1252
|
+
}
|
|
1253
|
+
ctx.type = file.mediaType;
|
|
1254
|
+
ctx.length = end - start + 1;
|
|
1255
|
+
if (ctx.method === "HEAD") {
|
|
1256
|
+
ctx.status = range ? 206 : 200;
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
streamOwnsLease = true;
|
|
1260
|
+
const body = Readable.from((async function* () {
|
|
1261
|
+
let offset = start;
|
|
1262
|
+
try {
|
|
1263
|
+
while (offset <= end) {
|
|
1264
|
+
const length = Math.min(SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, end - offset + 1);
|
|
1265
|
+
const result = local
|
|
1266
|
+
? await local.readFile({
|
|
1267
|
+
sessionId,
|
|
1268
|
+
itemId,
|
|
1269
|
+
partIndex,
|
|
1270
|
+
version: file.version,
|
|
1271
|
+
offset,
|
|
1272
|
+
length,
|
|
1273
|
+
})
|
|
1274
|
+
: await lease.call("session.file.read", {
|
|
1275
|
+
sessionId,
|
|
1276
|
+
itemId,
|
|
1277
|
+
partIndex,
|
|
1278
|
+
version: file.version,
|
|
1279
|
+
offset,
|
|
1280
|
+
length,
|
|
1281
|
+
}, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1282
|
+
const chunk = Buffer.from(result.data, "base64");
|
|
1283
|
+
if (result.offset !== offset + chunk.byteLength || chunk.byteLength === 0) {
|
|
1284
|
+
throw runtimeProtocolError("Runtime Session file read did not advance");
|
|
1285
|
+
}
|
|
1286
|
+
offset = result.offset;
|
|
1287
|
+
yield chunk;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
finally {
|
|
1291
|
+
cleanup();
|
|
1292
|
+
}
|
|
1293
|
+
})());
|
|
1294
|
+
body.once("close", cleanup);
|
|
1295
|
+
ctx.body = body;
|
|
1296
|
+
}
|
|
1297
|
+
catch (error) {
|
|
1298
|
+
runtimeTargetHostError(ctx, error);
|
|
1299
|
+
}
|
|
1300
|
+
finally {
|
|
1301
|
+
if (!streamOwnsLease) {
|
|
1302
|
+
cleanup();
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
const runtimeSessionWorkspaceFileContent = async (ctx) => {
|
|
1307
|
+
const sessionId = ctx.params.id;
|
|
1308
|
+
const path = ctx.query.path;
|
|
1309
|
+
if (typeof path !== "string" ||
|
|
1310
|
+
path.length === 0 ||
|
|
1311
|
+
path.length > 4_096 ||
|
|
1312
|
+
path.includes("\0")) {
|
|
1313
|
+
ctx.status = 400;
|
|
1314
|
+
ctx.body = { error: "invalid_workspace_file_path" };
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
const local = ctx.params.selector === "local" ? localMachineSessions : undefined;
|
|
1318
|
+
const invocation = downloadInvocationAbortScope(ctx, shutdownSignal);
|
|
1319
|
+
const lease = local ? undefined : await acquireRuntimeLease(ctx, invocation.signal);
|
|
1320
|
+
if (!local && !lease) {
|
|
1321
|
+
invocation.dispose();
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
let streamOwnsLease = false;
|
|
1325
|
+
let cleanedUp = false;
|
|
1326
|
+
const cleanup = () => {
|
|
1327
|
+
if (cleanedUp)
|
|
1328
|
+
return;
|
|
1329
|
+
cleanedUp = true;
|
|
1330
|
+
lease?.release();
|
|
1331
|
+
invocation.dispose();
|
|
1332
|
+
};
|
|
1333
|
+
try {
|
|
1334
|
+
const { file } = local
|
|
1335
|
+
? await local.getWorkspaceFile({ sessionId, path })
|
|
1336
|
+
: await lease.call("session.workspace.file.get", { sessionId, path }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1337
|
+
if (file.path !== path) {
|
|
1338
|
+
throw runtimeProtocolError("Runtime Session workspace file identity changed");
|
|
1339
|
+
}
|
|
1340
|
+
const etag = `"workspace-file-${file.version}"`;
|
|
1341
|
+
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
|
1342
|
+
ctx.set("ETag", etag);
|
|
1343
|
+
if (ctx.get("if-none-match").split(",").map((value) => value.trim()).includes(etag)) {
|
|
1344
|
+
ctx.status = 304;
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
ctx.set("Content-Security-Policy", "default-src 'none'; sandbox");
|
|
1348
|
+
ctx.set("Cross-Origin-Resource-Policy", "same-origin");
|
|
1349
|
+
ctx.set("X-Content-Type-Options", "nosniff");
|
|
1350
|
+
ctx.set("Accept-Ranges", "bytes");
|
|
1351
|
+
ctx.set("Content-Disposition", contentDisposition(file.filename));
|
|
1352
|
+
ctx.type = file.mediaType;
|
|
1353
|
+
if (file.byteLength === 0) {
|
|
1354
|
+
if (ctx.get("range")) {
|
|
1355
|
+
ctx.status = 416;
|
|
1356
|
+
ctx.set("Content-Range", "bytes */0");
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
ctx.status = 200;
|
|
1360
|
+
ctx.length = 0;
|
|
1361
|
+
if (ctx.method !== "HEAD")
|
|
1362
|
+
ctx.body = Buffer.alloc(0);
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
const requestedRange = ctx.get("range");
|
|
1366
|
+
const ifRange = ctx.get("if-range");
|
|
1367
|
+
const range = ifRange && ifRange !== etag
|
|
1368
|
+
? undefined
|
|
1369
|
+
: parseSingleByteRange(requestedRange, file.byteLength);
|
|
1370
|
+
if (range === "unsatisfiable") {
|
|
1371
|
+
ctx.status = 416;
|
|
1372
|
+
ctx.set("Content-Range", `bytes */${file.byteLength}`);
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
const start = range?.start ?? 0;
|
|
1376
|
+
const end = range?.end ?? file.byteLength - 1;
|
|
1377
|
+
if (range) {
|
|
1378
|
+
ctx.status = 206;
|
|
1379
|
+
ctx.set("Content-Range", `bytes ${start}-${end}/${file.byteLength}`);
|
|
1380
|
+
}
|
|
1381
|
+
ctx.length = end - start + 1;
|
|
1382
|
+
if (ctx.method === "HEAD") {
|
|
1383
|
+
ctx.status = range ? 206 : 200;
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
streamOwnsLease = true;
|
|
1387
|
+
const body = Readable.from((async function* () {
|
|
1388
|
+
let offset = start;
|
|
1389
|
+
try {
|
|
1390
|
+
while (offset <= end) {
|
|
1391
|
+
const length = Math.min(SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, end - offset + 1);
|
|
1392
|
+
const result = local
|
|
1393
|
+
? await local.readWorkspaceFile({
|
|
1394
|
+
sessionId,
|
|
1395
|
+
path,
|
|
1396
|
+
version: file.version,
|
|
1397
|
+
offset,
|
|
1398
|
+
length,
|
|
1399
|
+
})
|
|
1400
|
+
: await lease.call("session.workspace.file.read", {
|
|
1401
|
+
sessionId,
|
|
1402
|
+
path,
|
|
1403
|
+
version: file.version,
|
|
1404
|
+
offset,
|
|
1405
|
+
length,
|
|
1406
|
+
}, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1407
|
+
const chunk = Buffer.from(result.data, "base64");
|
|
1408
|
+
if (result.offset !== offset + chunk.byteLength || chunk.byteLength === 0) {
|
|
1409
|
+
throw runtimeProtocolError("Runtime Session workspace file read did not advance");
|
|
1410
|
+
}
|
|
1411
|
+
offset = result.offset;
|
|
1412
|
+
yield chunk;
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
finally {
|
|
1416
|
+
cleanup();
|
|
1417
|
+
}
|
|
1418
|
+
})());
|
|
1419
|
+
body.once("close", cleanup);
|
|
1420
|
+
ctx.body = body;
|
|
1421
|
+
}
|
|
1422
|
+
catch (error) {
|
|
1423
|
+
runtimeTargetHostError(ctx, error);
|
|
1424
|
+
}
|
|
1425
|
+
finally {
|
|
1426
|
+
if (!streamOwnsLease)
|
|
1427
|
+
cleanup();
|
|
1428
|
+
}
|
|
1429
|
+
};
|
|
1097
1430
|
const runtimeSessionMessageEnqueue = async (ctx) => {
|
|
1098
1431
|
const body = await readRuntimeBody(ctx);
|
|
1099
1432
|
if (!body)
|
|
@@ -1714,6 +2047,8 @@ export function createControlRouter(opts) {
|
|
|
1714
2047
|
router.get("/api/runtimes/:selector/sessions/launch-options", publicRuntimeRead(runtimeSessionLaunchOptions));
|
|
1715
2048
|
router.post("/api/runtimes/:selector/sessions", publicRuntimeMutation(runtimeSessionCreate));
|
|
1716
2049
|
router.post("/api/runtimes/:selector/sessions/:id/fork", publicRuntimeMutation(runtimeSessionFork));
|
|
2050
|
+
router.get("/api/runtimes/:selector/sessions/:id/execution", publicRuntimeRead(runtimeSessionExecutionSettings));
|
|
2051
|
+
router.put("/api/runtimes/:selector/sessions/:id/execution", publicRuntimeMutation(runtimeSessionExecutionSettingsUpdate));
|
|
1717
2052
|
router.get("/api/runtimes/:selector/sessions/:id/snapshot", publicRuntimeRead(runtimeSessionSnapshot));
|
|
1718
2053
|
router.get("/api/runtimes/:selector/sessions/:id/snapshot-page", publicRuntimeRead(runtimeSessionSnapshotPage));
|
|
1719
2054
|
router.get("/api/runtimes/:selector/sessions/:id/stream", publicRuntimeRead(runtimeSessionStream));
|
|
@@ -1723,6 +2058,11 @@ export function createControlRouter(opts) {
|
|
|
1723
2058
|
router.post("/api/runtimes/:selector/sessions/:id/resources", publicRuntimeMutation(runtimeSessionResourceUpload));
|
|
1724
2059
|
router.get("/api/runtimes/:selector/sessions/:id/resources/:resourceId", publicRuntimeRead(runtimeSessionResourceMetadata));
|
|
1725
2060
|
router.get("/api/runtimes/:selector/sessions/:id/resources/:resourceId/content", publicRuntimeRead(runtimeSessionResourceContent));
|
|
2061
|
+
router.head("/api/runtimes/:selector/sessions/:id/resources/:resourceId/content", publicRuntimeRead(runtimeSessionResourceContent));
|
|
2062
|
+
router.get("/api/runtimes/:selector/sessions/:id/items/:itemId/files/:partIndex/content", publicRuntimeRead(runtimeSessionItemFileContent));
|
|
2063
|
+
router.head("/api/runtimes/:selector/sessions/:id/items/:itemId/files/:partIndex/content", publicRuntimeRead(runtimeSessionItemFileContent));
|
|
2064
|
+
router.get("/api/runtimes/:selector/sessions/:id/workspace/files/content", publicRuntimeRead(runtimeSessionWorkspaceFileContent));
|
|
2065
|
+
router.head("/api/runtimes/:selector/sessions/:id/workspace/files/content", publicRuntimeRead(runtimeSessionWorkspaceFileContent));
|
|
1726
2066
|
router.delete("/api/runtimes/:selector/sessions/:id/resources/:resourceId", publicRuntimeMutation(runtimeSessionResourceDelete));
|
|
1727
2067
|
router.post("/api/runtimes/:selector/sessions/:id/messages/queue", publicRuntimeMutation(runtimeSessionMessageEnqueue));
|
|
1728
2068
|
router.post("/api/runtimes/:selector/sessions/:id/terminal/start", publicRuntimeMutation(runtimeSessionTerminalStart));
|
|
@@ -2711,6 +3051,14 @@ export function createControlRouter(opts) {
|
|
|
2711
3051
|
router.get("/api/agents", async (ctx) => {
|
|
2712
3052
|
ctx.body = { agents: await deps.listAgents() };
|
|
2713
3053
|
});
|
|
3054
|
+
router.get("/api/agents/runtime-options", async (ctx) => {
|
|
3055
|
+
if (!deps.listAgentRuntimeOptions)
|
|
3056
|
+
return notFound(ctx, "local runtime discovery is unavailable");
|
|
3057
|
+
ctx.set("Cache-Control", "no-store");
|
|
3058
|
+
ctx.body = {
|
|
3059
|
+
runtimes: await deps.listAgentRuntimeOptions({ refresh: asString(ctx.query.refresh) === "1" }),
|
|
3060
|
+
};
|
|
3061
|
+
});
|
|
2714
3062
|
router.get("/api/agents/:id", async (ctx) => {
|
|
2715
3063
|
const spec = await deps.getAgent(ctx.params.id);
|
|
2716
3064
|
if (!spec)
|
|
@@ -2723,6 +3071,11 @@ export function createControlRouter(opts) {
|
|
|
2723
3071
|
if (!id)
|
|
2724
3072
|
return bad(ctx, "missing agent id");
|
|
2725
3073
|
try {
|
|
3074
|
+
if (await deps.getAgent(id)) {
|
|
3075
|
+
ctx.status = 409;
|
|
3076
|
+
ctx.body = { error: "agent id already exists" };
|
|
3077
|
+
return;
|
|
3078
|
+
}
|
|
2726
3079
|
deps.writeAgent(id, body);
|
|
2727
3080
|
}
|
|
2728
3081
|
catch (error) {
|
|
@@ -2730,6 +3083,19 @@ export function createControlRouter(opts) {
|
|
|
2730
3083
|
}
|
|
2731
3084
|
ctx.body = { ok: true };
|
|
2732
3085
|
});
|
|
3086
|
+
router.put("/api/agents/:id", async (ctx) => {
|
|
3087
|
+
const id = ctx.params.id;
|
|
3088
|
+
const body = await readJson(ctx);
|
|
3089
|
+
if (!await deps.getAgent(id))
|
|
3090
|
+
return notFound(ctx, "agent not found");
|
|
3091
|
+
try {
|
|
3092
|
+
deps.writeAgent(id, { ...body, id });
|
|
3093
|
+
}
|
|
3094
|
+
catch (error) {
|
|
3095
|
+
return bad(ctx, error instanceof Error ? error.message : String(error));
|
|
3096
|
+
}
|
|
3097
|
+
ctx.body = { ok: true };
|
|
3098
|
+
});
|
|
2733
3099
|
router.delete("/api/agents/:id", (ctx) => {
|
|
2734
3100
|
ctx.body = { ok: deps.removeAgent(ctx.params.id) };
|
|
2735
3101
|
});
|
|
@@ -2769,6 +3135,64 @@ export function createControlRouter(opts) {
|
|
|
2769
3135
|
return bad(ctx, error instanceof Error ? error.message : String(error));
|
|
2770
3136
|
}
|
|
2771
3137
|
});
|
|
3138
|
+
router.post("/api/skills/local-scan", async (ctx) => {
|
|
3139
|
+
if (!deps.scanLocalSkills)
|
|
3140
|
+
return notFound(ctx, "local Skill discovery is unavailable");
|
|
3141
|
+
const body = await readJson(ctx);
|
|
3142
|
+
const runtime = parseProviderCliId(body.runtime);
|
|
3143
|
+
if (!runtime)
|
|
3144
|
+
return bad(ctx, "runtime must be codex, traex, or claude");
|
|
3145
|
+
try {
|
|
3146
|
+
ctx.body = { candidates: await deps.scanLocalSkills(runtime) };
|
|
3147
|
+
}
|
|
3148
|
+
catch (error) {
|
|
3149
|
+
return bad(ctx, error instanceof Error ? error.message : String(error));
|
|
3150
|
+
}
|
|
3151
|
+
});
|
|
3152
|
+
router.post("/api/skills/local-import", async (ctx) => {
|
|
3153
|
+
if (!deps.importLocalSkills)
|
|
3154
|
+
return notFound(ctx, "local Skill import is unavailable");
|
|
3155
|
+
const body = await readJson(ctx);
|
|
3156
|
+
const runtime = parseProviderCliId(body.runtime);
|
|
3157
|
+
const rawKeys = Array.isArray(body.keys) ? body.keys : [];
|
|
3158
|
+
const keys = rawKeys.length > 0
|
|
3159
|
+
? rawKeys.filter((value) => typeof value === "string" && value.length > 0)
|
|
3160
|
+
: [];
|
|
3161
|
+
if (!runtime)
|
|
3162
|
+
return bad(ctx, "runtime must be codex, traex, or claude");
|
|
3163
|
+
if (keys.length === 0 || keys.length !== rawKeys.length || keys.length > 100) {
|
|
3164
|
+
return bad(ctx, "keys must contain 1-100 non-empty candidate keys");
|
|
3165
|
+
}
|
|
3166
|
+
try {
|
|
3167
|
+
ctx.body = { results: await deps.importLocalSkills(runtime, keys) };
|
|
3168
|
+
}
|
|
3169
|
+
catch (error) {
|
|
3170
|
+
return bad(ctx, error instanceof Error ? error.message : String(error));
|
|
3171
|
+
}
|
|
3172
|
+
});
|
|
3173
|
+
router.post("/api/skills/import-archive", async (ctx) => {
|
|
3174
|
+
if (!deps.importSkillArchive)
|
|
3175
|
+
return notFound(ctx, "Skill archive import is unavailable");
|
|
3176
|
+
let body;
|
|
3177
|
+
try {
|
|
3178
|
+
body = await readJson(ctx, 29 * 1024 * 1024);
|
|
3179
|
+
}
|
|
3180
|
+
catch (error) {
|
|
3181
|
+
return bad(ctx, error instanceof Error ? error.message : String(error));
|
|
3182
|
+
}
|
|
3183
|
+
const filename = asString(body.filename);
|
|
3184
|
+
const contentBase64 = asString(body.contentBase64);
|
|
3185
|
+
if (!filename || !contentBase64)
|
|
3186
|
+
return bad(ctx, "filename and contentBase64 are required");
|
|
3187
|
+
if (contentBase64.length > 28 * 1024 * 1024)
|
|
3188
|
+
return bad(ctx, "archive payload is too large");
|
|
3189
|
+
try {
|
|
3190
|
+
ctx.body = { results: await deps.importSkillArchive(filename, contentBase64) };
|
|
3191
|
+
}
|
|
3192
|
+
catch (error) {
|
|
3193
|
+
return bad(ctx, error instanceof Error ? error.message : String(error));
|
|
3194
|
+
}
|
|
3195
|
+
});
|
|
2772
3196
|
router.delete("/api/skills/:name", async (ctx) => {
|
|
2773
3197
|
try {
|
|
2774
3198
|
ctx.body = { ok: await deps.removeSkill(ctx.params.name) };
|
|
@@ -3107,12 +3531,16 @@ export function createControlRouter(opts) {
|
|
|
3107
3531
|
const body = await readJson(ctx);
|
|
3108
3532
|
const agent = asString(body.agent);
|
|
3109
3533
|
const provider = asString(body.provider);
|
|
3534
|
+
const permissionPreset = parseSessionPermissionPreset(body.permissionPreset);
|
|
3110
3535
|
if (body.config != null) {
|
|
3111
3536
|
return bad(ctx, "inline Agent configs are no longer supported; save an Agent first");
|
|
3112
3537
|
}
|
|
3113
3538
|
if (Boolean(agent) === Boolean(provider)) {
|
|
3114
3539
|
return bad(ctx, "provide exactly one Agent or Provider");
|
|
3115
3540
|
}
|
|
3541
|
+
if (body.permissionPreset !== undefined && !permissionPreset) {
|
|
3542
|
+
return bad(ctx, "permissionPreset must be default, read-only, workspace-write, or full-access");
|
|
3543
|
+
}
|
|
3116
3544
|
try {
|
|
3117
3545
|
ctx.body = await localMachineSessions.create({
|
|
3118
3546
|
...(agent ? { agent } : { provider: provider }),
|
|
@@ -3120,6 +3548,7 @@ export function createControlRouter(opts) {
|
|
|
3120
3548
|
...(asString(body.reasoningEffort)
|
|
3121
3549
|
? { reasoningEffort: asString(body.reasoningEffort) }
|
|
3122
3550
|
: {}),
|
|
3551
|
+
...(permissionPreset ? { permissionPreset } : {}),
|
|
3123
3552
|
...(asString(body.title) ? { title: asString(body.title) } : {}),
|
|
3124
3553
|
...(asString(body.projectId) ? { projectId: asString(body.projectId) } : {}),
|
|
3125
3554
|
});
|
|
@@ -3140,7 +3569,20 @@ export function createControlRouter(opts) {
|
|
|
3140
3569
|
}
|
|
3141
3570
|
catch (error) {
|
|
3142
3571
|
ctx.status = 503;
|
|
3143
|
-
|
|
3572
|
+
const runtimeFailure = error instanceof MachineSessionServiceFailure
|
|
3573
|
+
? error.runtimeFailure
|
|
3574
|
+
: undefined;
|
|
3575
|
+
const message = runtimeFailure?.message
|
|
3576
|
+
?? (error instanceof MachineSessionServiceFailure ? error.detail : undefined)
|
|
3577
|
+
?? (error instanceof Error ? error.message : String(error));
|
|
3578
|
+
ctx.body = {
|
|
3579
|
+
error: message,
|
|
3580
|
+
code: runtimeFailure?.code
|
|
3581
|
+
?? (error instanceof MachineSessionServiceFailure ? error.code : "runtime_error"),
|
|
3582
|
+
outcome: error instanceof MachineSessionServiceFailure && error.code === "outcome_unknown"
|
|
3583
|
+
? "unknown"
|
|
3584
|
+
: "not_started",
|
|
3585
|
+
};
|
|
3144
3586
|
}
|
|
3145
3587
|
return;
|
|
3146
3588
|
}
|
|
@@ -3159,26 +3601,31 @@ export function createControlRouter(opts) {
|
|
|
3159
3601
|
execution: structuredClone(meta.execution),
|
|
3160
3602
|
});
|
|
3161
3603
|
if (!live) {
|
|
3604
|
+
const failure = runnerManager.lastLiveSessionFailure?.(id);
|
|
3162
3605
|
ctx.status = 503;
|
|
3163
3606
|
ctx.body = {
|
|
3164
|
-
error:
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3607
|
+
error: failure?.message
|
|
3608
|
+
?? runnerManager.lastLiveSessionError?.(id)
|
|
3609
|
+
?? `live session unavailable (${meta.execution.provider})`,
|
|
3610
|
+
code: failure?.code ?? "live_unavailable",
|
|
3611
|
+
outcome: "not_started",
|
|
3168
3612
|
};
|
|
3169
3613
|
return;
|
|
3170
3614
|
}
|
|
3171
|
-
const
|
|
3172
|
-
|
|
3615
|
+
const result = await runnerManager.injectMessage(id, message);
|
|
3616
|
+
const outcome = result.outcome;
|
|
3617
|
+
if (outcome === "injected" || outcome === "steered") {
|
|
3173
3618
|
ctx.body = { ok: true, injected: true };
|
|
3174
3619
|
return;
|
|
3175
3620
|
}
|
|
3176
3621
|
ctx.status = 503;
|
|
3622
|
+
const failure = runnerManager.lastLiveSessionFailure?.(id);
|
|
3177
3623
|
ctx.body = {
|
|
3178
|
-
error:
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3624
|
+
error: failure?.message
|
|
3625
|
+
?? runnerManager.lastLiveSessionError?.(id)
|
|
3626
|
+
?? `live injection ${outcome}`,
|
|
3627
|
+
code: failure?.code ?? "live_inject_failed",
|
|
3628
|
+
outcome: outcome === "failed" ? "unknown" : "not_started",
|
|
3182
3629
|
};
|
|
3183
3630
|
});
|
|
3184
3631
|
// Stop the session's active turn (the web Stop button). For a live native
|
|
@@ -3399,11 +3846,28 @@ export function synthesizeSessionTitle(message, limit = 60) {
|
|
|
3399
3846
|
return collapsed;
|
|
3400
3847
|
return `${collapsed.slice(0, limit - 1).trimEnd()}…`;
|
|
3401
3848
|
}
|
|
3402
|
-
async function readJson(ctx) {
|
|
3849
|
+
async function readJson(ctx, maxBytes) {
|
|
3403
3850
|
const raw = await new Promise((resolve, reject) => {
|
|
3404
3851
|
let data = "";
|
|
3405
|
-
|
|
3406
|
-
|
|
3852
|
+
let bytes = 0;
|
|
3853
|
+
let exceeded = false;
|
|
3854
|
+
ctx.req.on("data", (chunk) => {
|
|
3855
|
+
if (exceeded)
|
|
3856
|
+
return;
|
|
3857
|
+
bytes += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.byteLength;
|
|
3858
|
+
if (maxBytes !== undefined && bytes > maxBytes) {
|
|
3859
|
+
exceeded = true;
|
|
3860
|
+
data = "";
|
|
3861
|
+
return;
|
|
3862
|
+
}
|
|
3863
|
+
data += chunk;
|
|
3864
|
+
});
|
|
3865
|
+
ctx.req.on("end", () => {
|
|
3866
|
+
if (exceeded)
|
|
3867
|
+
reject(new Error("request body is too large"));
|
|
3868
|
+
else
|
|
3869
|
+
resolve(data);
|
|
3870
|
+
});
|
|
3407
3871
|
ctx.req.on("error", reject);
|
|
3408
3872
|
});
|
|
3409
3873
|
if (!raw.trim())
|
|
@@ -3424,6 +3888,14 @@ function parseProviderCliId(value) {
|
|
|
3424
3888
|
? value
|
|
3425
3889
|
: undefined;
|
|
3426
3890
|
}
|
|
3891
|
+
function parseSessionPermissionPreset(value) {
|
|
3892
|
+
return value === "default" ||
|
|
3893
|
+
value === "read-only" ||
|
|
3894
|
+
value === "workspace-write" ||
|
|
3895
|
+
value === "full-access"
|
|
3896
|
+
? value
|
|
3897
|
+
: undefined;
|
|
3898
|
+
}
|
|
3427
3899
|
function parseProviderCliOperation(value) {
|
|
3428
3900
|
return value === "install" || value === "update" ? value : undefined;
|
|
3429
3901
|
}
|
|
@@ -3439,6 +3911,14 @@ function optionalRuntimeDevice(body) {
|
|
|
3439
3911
|
return body.device === undefined ? {} : { device: body.device };
|
|
3440
3912
|
}
|
|
3441
3913
|
function remoteRuntimeRpcTimeoutMs(method, params) {
|
|
3914
|
+
// Native startup/delivery owns phase-specific deadlines and returns their
|
|
3915
|
+
// concrete failures. A BFF deadline here would race those phases and replace
|
|
3916
|
+
// the real error with an ambiguous generic RPC timeout. The setup queue also
|
|
3917
|
+
// awaits Terminal startup before acknowledging the request.
|
|
3918
|
+
if (method === "session.message.send" ||
|
|
3919
|
+
method === "session.message.enqueue" ||
|
|
3920
|
+
method === "session.terminal.start")
|
|
3921
|
+
return null;
|
|
3442
3922
|
if (method === "session.emulator.attach")
|
|
3443
3923
|
return REMOTE_RUNTIME_EMULATOR_ATTACH_TIMEOUT_MS;
|
|
3444
3924
|
if (method === "session.emulator.type") {
|
|
@@ -3542,6 +4022,36 @@ function pluginInstallInvocationAbortScope(ctx, shutdownSignal) {
|
|
|
3542
4022
|
function browserArtifactInvocationAbortScope(ctx, shutdownSignal) {
|
|
3543
4023
|
return managementInvocationAbortScope(ctx, shutdownSignal, BROWSER_ARTIFACT_OPERATION_TIMEOUT_MS, "Browser artifact operation");
|
|
3544
4024
|
}
|
|
4025
|
+
function downloadInvocationAbortScope(ctx, shutdownSignal) {
|
|
4026
|
+
const controller = new AbortController();
|
|
4027
|
+
const abort = (reason) => {
|
|
4028
|
+
if (!controller.signal.aborted)
|
|
4029
|
+
controller.abort(reason);
|
|
4030
|
+
};
|
|
4031
|
+
const onRequestAborted = () => abort(namedError("download request aborted", "AbortError"));
|
|
4032
|
+
const onResponseClose = () => {
|
|
4033
|
+
if (!ctx.res.writableEnded) {
|
|
4034
|
+
abort(namedError("download client disconnected", "AbortError"));
|
|
4035
|
+
}
|
|
4036
|
+
};
|
|
4037
|
+
const onShutdown = () => abort(shutdownSignal?.reason ?? namedError("daemon is shutting down", "AbortError"));
|
|
4038
|
+
ctx.req.once("aborted", onRequestAborted);
|
|
4039
|
+
ctx.res.once("close", onResponseClose);
|
|
4040
|
+
if (shutdownSignal?.aborted)
|
|
4041
|
+
onShutdown();
|
|
4042
|
+
else
|
|
4043
|
+
shutdownSignal?.addEventListener("abort", onShutdown, { once: true });
|
|
4044
|
+
if (ctx.req.aborted)
|
|
4045
|
+
onRequestAborted();
|
|
4046
|
+
return {
|
|
4047
|
+
signal: controller.signal,
|
|
4048
|
+
dispose() {
|
|
4049
|
+
ctx.req.removeListener("aborted", onRequestAborted);
|
|
4050
|
+
ctx.res.removeListener("close", onResponseClose);
|
|
4051
|
+
shutdownSignal?.removeEventListener("abort", onShutdown);
|
|
4052
|
+
},
|
|
4053
|
+
};
|
|
4054
|
+
}
|
|
3545
4055
|
function managementInvocationAbortScope(ctx, shutdownSignal, timeoutMs, label) {
|
|
3546
4056
|
const controller = new AbortController();
|
|
3547
4057
|
const abort = (reason) => {
|
|
@@ -3762,8 +4272,14 @@ function runtimeTargetHostError(ctx, error, forcedOutcome) {
|
|
|
3762
4272
|
const status = runtimeTargetHttpStatus(code);
|
|
3763
4273
|
ctx.status = status;
|
|
3764
4274
|
const outcome = forcedOutcome ?? runtimeTargetErrorOutcome(error);
|
|
4275
|
+
const applicationMessage = error instanceof Error && error.name === "DirectRuntimeRpcError"
|
|
4276
|
+
? error.message.replace(/^Remote Runtime RPC failed: [^:]+: /, "")
|
|
4277
|
+
: undefined;
|
|
3765
4278
|
ctx.body = {
|
|
3766
|
-
error: status === 500 ? "internal_error" : code,
|
|
4279
|
+
error: applicationMessage ?? (status === 500 ? "internal_error" : code),
|
|
4280
|
+
...(applicationMessage
|
|
4281
|
+
? { code: status === 500 ? "internal_error" : code }
|
|
4282
|
+
: {}),
|
|
3767
4283
|
...(outcome === undefined ? {} : { outcome }),
|
|
3768
4284
|
};
|
|
3769
4285
|
}
|
|
@@ -3851,6 +4367,83 @@ function publicRuntimeStreamError(error) {
|
|
|
3851
4367
|
}
|
|
3852
4368
|
class RequestBodyTooLargeError extends Error {
|
|
3853
4369
|
}
|
|
4370
|
+
function isMediaType(value) {
|
|
4371
|
+
return value.length <= 255 && /^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/.test(value);
|
|
4372
|
+
}
|
|
4373
|
+
async function forwardResourceUploadBody(ctx, uploadId, resumeOffset, expectedBytes, writeChunk) {
|
|
4374
|
+
let received = 0;
|
|
4375
|
+
let remoteOffset = resumeOffset;
|
|
4376
|
+
let carry = Buffer.alloc(0);
|
|
4377
|
+
for await (const raw of ctx.req) {
|
|
4378
|
+
const incoming = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
|
|
4379
|
+
if (received + incoming.byteLength > expectedBytes) {
|
|
4380
|
+
throw runtimeProtocolError("Resource upload exceeds Content-Length");
|
|
4381
|
+
}
|
|
4382
|
+
const skip = Math.min(incoming.byteLength, Math.max(0, resumeOffset - received));
|
|
4383
|
+
received += incoming.byteLength;
|
|
4384
|
+
let cursor = skip;
|
|
4385
|
+
while (cursor < incoming.byteLength) {
|
|
4386
|
+
const needed = SESSION_RESOURCE_TRANSFER_CHUNK_BYTES - carry.byteLength;
|
|
4387
|
+
const take = Math.min(needed, incoming.byteLength - cursor);
|
|
4388
|
+
carry = carry.byteLength === 0
|
|
4389
|
+
? incoming.subarray(cursor, cursor + take)
|
|
4390
|
+
: Buffer.concat([carry, incoming.subarray(cursor, cursor + take)]);
|
|
4391
|
+
cursor += take;
|
|
4392
|
+
if (carry.byteLength < SESSION_RESOURCE_TRANSFER_CHUNK_BYTES)
|
|
4393
|
+
continue;
|
|
4394
|
+
const written = await writeChunk(uploadId, remoteOffset, carry.toString("base64"));
|
|
4395
|
+
if (written.offset !== remoteOffset + carry.byteLength) {
|
|
4396
|
+
throw runtimeProtocolError("Runtime Session resource upload did not advance");
|
|
4397
|
+
}
|
|
4398
|
+
remoteOffset = written.offset;
|
|
4399
|
+
carry = Buffer.alloc(0);
|
|
4400
|
+
}
|
|
4401
|
+
}
|
|
4402
|
+
if (received !== expectedBytes) {
|
|
4403
|
+
throw runtimeProtocolError("Resource upload ended before Content-Length");
|
|
4404
|
+
}
|
|
4405
|
+
if (carry.byteLength > 0) {
|
|
4406
|
+
const written = await writeChunk(uploadId, remoteOffset, carry.toString("base64"));
|
|
4407
|
+
if (written.offset !== remoteOffset + carry.byteLength) {
|
|
4408
|
+
throw runtimeProtocolError("Runtime Session resource upload did not advance");
|
|
4409
|
+
}
|
|
4410
|
+
remoteOffset = written.offset;
|
|
4411
|
+
}
|
|
4412
|
+
if (remoteOffset !== expectedBytes) {
|
|
4413
|
+
throw runtimeProtocolError("Runtime Session resource upload length changed");
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
function parseSingleByteRange(header, byteLength) {
|
|
4417
|
+
if (!header)
|
|
4418
|
+
return undefined;
|
|
4419
|
+
const match = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
|
|
4420
|
+
if (!match || byteLength <= 0)
|
|
4421
|
+
return "unsatisfiable";
|
|
4422
|
+
const [, startText, endText] = match;
|
|
4423
|
+
if (!startText && !endText)
|
|
4424
|
+
return "unsatisfiable";
|
|
4425
|
+
if (!startText) {
|
|
4426
|
+
const suffix = Number(endText);
|
|
4427
|
+
if (!Number.isSafeInteger(suffix) || suffix <= 0)
|
|
4428
|
+
return "unsatisfiable";
|
|
4429
|
+
return { start: Math.max(0, byteLength - suffix), end: byteLength - 1 };
|
|
4430
|
+
}
|
|
4431
|
+
const start = Number(startText);
|
|
4432
|
+
const requestedEnd = endText ? Number(endText) : byteLength - 1;
|
|
4433
|
+
if (!Number.isSafeInteger(start) ||
|
|
4434
|
+
!Number.isSafeInteger(requestedEnd) ||
|
|
4435
|
+
start < 0 ||
|
|
4436
|
+
requestedEnd < start ||
|
|
4437
|
+
start >= byteLength) {
|
|
4438
|
+
return "unsatisfiable";
|
|
4439
|
+
}
|
|
4440
|
+
return { start, end: Math.min(requestedEnd, byteLength - 1) };
|
|
4441
|
+
}
|
|
4442
|
+
function contentDisposition(filename) {
|
|
4443
|
+
if (!filename)
|
|
4444
|
+
return "inline";
|
|
4445
|
+
return `inline; filename*=UTF-8''${encodeURIComponent(filename)}`;
|
|
4446
|
+
}
|
|
3854
4447
|
async function readBoundedBinary(ctx, maxBytes) {
|
|
3855
4448
|
const declaredLength = Number(ctx.get("content-length"));
|
|
3856
4449
|
if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
|