@selvajs/selva 4.20.0-beta.14 → 4.20.0-beta.16
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/build/client/_app/immutable/assets/0.D1rXwE-H.css +2 -0
- package/build/client/_app/immutable/assets/0.D1rXwE-H.css.br +0 -0
- package/build/client/_app/immutable/assets/0.D1rXwE-H.css.gz +0 -0
- package/build/client/_app/immutable/assets/21.jbAJ3qFw.css +1 -0
- package/build/client/_app/immutable/assets/21.jbAJ3qFw.css.br +0 -0
- package/build/client/_app/immutable/assets/21.jbAJ3qFw.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BCch4665.js +1 -0
- package/build/client/_app/immutable/chunks/BCch4665.js.br +1 -0
- package/build/client/_app/immutable/chunks/BCch4665.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BCliE8WI.js +1 -0
- package/build/client/_app/immutable/chunks/BCliE8WI.js.br +0 -0
- package/build/client/_app/immutable/chunks/BCliE8WI.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BQAnKYth.js +1 -0
- package/build/client/_app/immutable/chunks/BQAnKYth.js.br +0 -0
- package/build/client/_app/immutable/chunks/BQAnKYth.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bga9Qxze.js +55 -0
- package/build/client/_app/immutable/chunks/Bga9Qxze.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bga9Qxze.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BqYuJpCe.js +2 -0
- package/build/client/_app/immutable/chunks/BqYuJpCe.js.br +0 -0
- package/build/client/_app/immutable/chunks/BqYuJpCe.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Br-hDqZV.js +1 -0
- package/build/client/_app/immutable/chunks/Br-hDqZV.js.br +0 -0
- package/build/client/_app/immutable/chunks/Br-hDqZV.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BsFJ4Tkb.js +1 -0
- package/build/client/_app/immutable/chunks/BsFJ4Tkb.js.br +0 -0
- package/build/client/_app/immutable/chunks/BsFJ4Tkb.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bv4sOmO3.js +1 -0
- package/build/client/_app/immutable/chunks/Bv4sOmO3.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bv4sOmO3.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CcWwBvi8.js +1 -0
- package/build/client/_app/immutable/chunks/CcWwBvi8.js.br +0 -0
- package/build/client/_app/immutable/chunks/CcWwBvi8.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CkT0pz42.js +1 -0
- package/build/client/_app/immutable/chunks/CkT0pz42.js.br +0 -0
- package/build/client/_app/immutable/chunks/CkT0pz42.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cq8baQYl.js +1 -0
- package/build/client/_app/immutable/chunks/Cq8baQYl.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cq8baQYl.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CxjDNptA.js +1 -0
- package/build/client/_app/immutable/chunks/CxjDNptA.js.br +0 -0
- package/build/client/_app/immutable/chunks/CxjDNptA.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D1qLYIn2.js +1 -0
- package/build/client/_app/immutable/chunks/D1qLYIn2.js.br +1 -0
- package/build/client/_app/immutable/chunks/D1qLYIn2.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DKELOm5C.js +1 -0
- package/build/client/_app/immutable/chunks/DKELOm5C.js.br +0 -0
- package/build/client/_app/immutable/chunks/DKELOm5C.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dw1oeR41.js +1 -0
- package/build/client/_app/immutable/chunks/Dw1oeR41.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dw1oeR41.js.gz +0 -0
- package/build/client/_app/immutable/chunks/I4bYfY0F.js +1 -0
- package/build/client/_app/immutable/chunks/I4bYfY0F.js.br +0 -0
- package/build/client/_app/immutable/chunks/I4bYfY0F.js.gz +0 -0
- package/build/client/_app/immutable/chunks/TtW8qOd8.js +1 -0
- package/build/client/_app/immutable/chunks/TtW8qOd8.js.br +2 -0
- package/build/client/_app/immutable/chunks/TtW8qOd8.js.gz +0 -0
- package/build/client/_app/immutable/chunks/ZUuL_8U2.js +5668 -0
- package/build/client/_app/immutable/chunks/ZUuL_8U2.js.br +0 -0
- package/build/client/_app/immutable/chunks/ZUuL_8U2.js.gz +0 -0
- package/build/client/_app/immutable/chunks/rPzey9q1.js +1 -0
- package/build/client/_app/immutable/chunks/rPzey9q1.js.br +0 -0
- package/build/client/_app/immutable/chunks/rPzey9q1.js.gz +0 -0
- package/build/client/_app/immutable/chunks/t5TAza2h.js +1 -0
- package/build/client/_app/immutable/chunks/t5TAza2h.js.br +0 -0
- package/build/client/_app/immutable/chunks/t5TAza2h.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.BXdMlN1l.js +2 -0
- package/build/client/_app/immutable/entry/app.BXdMlN1l.js.br +0 -0
- package/build/client/_app/immutable/entry/app.BXdMlN1l.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.C4-a3B_z.js +1 -0
- package/build/client/_app/immutable/entry/start.C4-a3B_z.js.br +1 -0
- package/build/client/_app/immutable/entry/start.C4-a3B_z.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.CuqH6Mt0.js +1 -0
- package/build/client/_app/immutable/nodes/1.CuqH6Mt0.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.CuqH6Mt0.js.gz +0 -0
- package/build/client/_app/immutable/nodes/11.C6drypmp.js +3 -0
- package/build/client/_app/immutable/nodes/11.C6drypmp.js.br +0 -0
- package/build/client/_app/immutable/nodes/11.C6drypmp.js.gz +0 -0
- package/build/client/_app/immutable/nodes/13.DwNvl9MK.js +2 -0
- package/build/client/_app/immutable/nodes/13.DwNvl9MK.js.br +0 -0
- package/build/client/_app/immutable/nodes/13.DwNvl9MK.js.gz +0 -0
- package/build/client/_app/immutable/nodes/14.C7gRFljQ.js +2 -0
- package/build/client/_app/immutable/nodes/14.C7gRFljQ.js.br +0 -0
- package/build/client/_app/immutable/nodes/14.C7gRFljQ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/15.UcjJOSY-.js +28 -0
- package/build/client/_app/immutable/nodes/15.UcjJOSY-.js.br +0 -0
- package/build/client/_app/immutable/nodes/15.UcjJOSY-.js.gz +0 -0
- package/build/client/_app/immutable/nodes/16.D7NsPsuY.js +5 -0
- package/build/client/_app/immutable/nodes/16.D7NsPsuY.js.br +0 -0
- package/build/client/_app/immutable/nodes/16.D7NsPsuY.js.gz +0 -0
- package/build/client/_app/immutable/nodes/17.BXuiEdk0.js +2 -0
- package/build/client/_app/immutable/nodes/17.BXuiEdk0.js.br +0 -0
- package/build/client/_app/immutable/nodes/17.BXuiEdk0.js.gz +0 -0
- package/build/client/_app/immutable/nodes/19.CnVVQQgJ.js +7 -0
- package/build/client/_app/immutable/nodes/19.CnVVQQgJ.js.br +0 -0
- package/build/client/_app/immutable/nodes/19.CnVVQQgJ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.DPbfY1ur.js +1 -0
- package/build/client/_app/immutable/nodes/2.DPbfY1ur.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.DPbfY1ur.js.gz +0 -0
- package/build/client/_app/immutable/nodes/20.pDAY8z9B.js +2 -0
- package/build/client/_app/immutable/nodes/20.pDAY8z9B.js.br +0 -0
- package/build/client/_app/immutable/nodes/20.pDAY8z9B.js.gz +0 -0
- package/build/client/_app/immutable/nodes/21.CXC2uv3j.js +1 -0
- package/build/client/_app/immutable/nodes/21.CXC2uv3j.js.br +1 -0
- package/build/client/_app/immutable/nodes/21.CXC2uv3j.js.gz +0 -0
- package/build/client/_app/immutable/nodes/22.BIOFTxwg.js +6 -0
- package/build/client/_app/immutable/nodes/22.BIOFTxwg.js.br +0 -0
- package/build/client/_app/immutable/nodes/22.BIOFTxwg.js.gz +0 -0
- package/build/client/_app/immutable/nodes/24.Clf63xDP.js +3 -0
- package/build/client/_app/immutable/nodes/24.Clf63xDP.js.br +0 -0
- package/build/client/_app/immutable/nodes/24.Clf63xDP.js.gz +0 -0
- package/build/client/_app/immutable/nodes/25.CKAywN8T.js +16 -0
- package/build/client/_app/immutable/nodes/25.CKAywN8T.js.br +0 -0
- package/build/client/_app/immutable/nodes/25.CKAywN8T.js.gz +0 -0
- package/build/client/_app/immutable/nodes/26.D88_-NW5.js +6 -0
- package/build/client/_app/immutable/nodes/26.D88_-NW5.js.br +0 -0
- package/build/client/_app/immutable/nodes/26.D88_-NW5.js.gz +0 -0
- package/build/client/_app/immutable/nodes/29.BNZv8HeX.js +4 -0
- package/build/client/_app/immutable/nodes/29.BNZv8HeX.js.br +0 -0
- package/build/client/_app/immutable/nodes/29.BNZv8HeX.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3._SKx-VPP.js +1 -0
- package/build/client/_app/immutable/nodes/3._SKx-VPP.js.br +0 -0
- package/build/client/_app/immutable/nodes/3._SKx-VPP.js.gz +0 -0
- package/build/client/_app/immutable/nodes/30.C5eDo44s.js +6 -0
- package/build/client/_app/immutable/nodes/30.C5eDo44s.js.br +0 -0
- package/build/client/_app/immutable/nodes/30.C5eDo44s.js.gz +0 -0
- package/build/client/_app/immutable/nodes/31.CopfqRzD.js +2 -0
- package/build/client/_app/immutable/nodes/31.CopfqRzD.js.br +0 -0
- package/build/client/_app/immutable/nodes/31.CopfqRzD.js.gz +0 -0
- package/build/client/_app/immutable/nodes/32.DLSXVX1o.js +2 -0
- package/build/client/_app/immutable/nodes/32.DLSXVX1o.js.br +0 -0
- package/build/client/_app/immutable/nodes/32.DLSXVX1o.js.gz +0 -0
- package/build/client/_app/immutable/nodes/34.DN3j7Owo.js +1 -0
- package/build/client/_app/immutable/nodes/34.DN3j7Owo.js.br +0 -0
- package/build/client/_app/immutable/nodes/34.DN3j7Owo.js.gz +0 -0
- package/build/client/_app/immutable/nodes/35.Cr1EcvDM.js +5 -0
- package/build/client/_app/immutable/nodes/35.Cr1EcvDM.js.br +0 -0
- package/build/client/_app/immutable/nodes/35.Cr1EcvDM.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.DjlShbtw.js +1 -0
- package/build/client/_app/immutable/nodes/5.DjlShbtw.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.DjlShbtw.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.BdNb13Z8.js +1 -0
- package/build/client/_app/immutable/nodes/6.BdNb13Z8.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.BdNb13Z8.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.DWRt3LiX.js +1 -0
- package/build/client/_app/immutable/nodes/7.DWRt3LiX.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.DWRt3LiX.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.CiWjIWKl.js +3 -0
- package/build/client/_app/immutable/nodes/8.CiWjIWKl.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.CiWjIWKl.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.DnRaYIJC.js +1 -0
- package/build/client/_app/immutable/nodes/9.DnRaYIJC.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.DnRaYIJC.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/handler.js +17 -16
- package/build/handler.js.map +1 -1
- package/build/index.js +17 -16
- package/build/index.js.map +1 -1
- package/build/server/chunks/chunks/AppHeader.js-CNfKgz87.js +315 -0
- package/build/server/chunks/chunks/AppHeader.js-CNfKgz87.js.map +1 -0
- package/build/server/chunks/chunks/Callout.js-Bs8qA73B.js +57 -0
- package/build/server/chunks/chunks/Callout.js-Bs8qA73B.js.map +1 -0
- package/build/server/chunks/chunks/ConfirmDialog.js-HFdP27IY.js +151 -0
- package/build/server/chunks/chunks/ConfirmDialog.js-HFdP27IY.js.map +1 -0
- package/build/server/chunks/chunks/DataTable.js-KtE-5lx7.js +33 -0
- package/build/server/chunks/chunks/DataTable.js-KtE-5lx7.js.map +1 -0
- package/build/server/chunks/chunks/DefinitionCard.js-Bk58QdKw.js +141 -0
- package/build/server/chunks/chunks/DefinitionCard.js-Bk58QdKw.js.map +1 -0
- package/build/server/chunks/chunks/EmptyState.js-u9Skjkej.js +36 -0
- package/build/server/chunks/chunks/EmptyState.js-u9Skjkej.js.map +1 -0
- package/build/server/chunks/chunks/ErrorScreen.js-Cxf4pUnH.js +116 -0
- package/build/server/chunks/chunks/ErrorScreen.js-Cxf4pUnH.js.map +1 -0
- package/build/server/chunks/chunks/FilterableDropdown.js-COxcZtMW.js +2722 -0
- package/build/server/chunks/chunks/FilterableDropdown.js-COxcZtMW.js.map +1 -0
- package/build/server/chunks/chunks/PageContent.js-DOlTfr05.js +12 -0
- package/build/server/chunks/chunks/PageContent.js-DOlTfr05.js.map +1 -0
- package/build/server/chunks/chunks/SectionHeader.js-BxE_OjCU.js +22 -0
- package/build/server/chunks/chunks/SectionHeader.js-BxE_OjCU.js.map +1 -0
- package/build/server/chunks/chunks/SettingsMenu.js-bAsytzfC.js +2644 -0
- package/build/server/chunks/chunks/SettingsMenu.js-bAsytzfC.js.map +1 -0
- package/build/server/chunks/chunks/SideNav.js-Btm37Q62.js +194 -0
- package/build/server/chunks/chunks/SideNav.js-Btm37Q62.js.map +1 -0
- package/build/server/chunks/chunks/StatCard.js-Bd6qctS_.js +52 -0
- package/build/server/chunks/chunks/StatCard.js-Bd6qctS_.js.map +1 -0
- package/build/server/chunks/chunks/UserAvatar.js-DApEF2jf.js +14 -0
- package/build/server/chunks/chunks/UserAvatar.js-DApEF2jf.js.map +1 -0
- package/build/server/chunks/chunks/UserRowIdentity.js-DXGKkQbe.js +112 -0
- package/build/server/chunks/chunks/UserRowIdentity.js-DXGKkQbe.js.map +1 -0
- package/build/server/chunks/chunks/ViewToggle.js-Br51zZmF.js +138 -0
- package/build/server/chunks/chunks/ViewToggle.js-Br51zZmF.js.map +1 -0
- package/build/server/chunks/chunks/access.js-BfMTTCTH.js +828 -0
- package/build/server/chunks/chunks/access.js-BfMTTCTH.js.map +1 -0
- package/build/server/chunks/chunks/access.server.js-CwcMbS6y.js +15 -0
- package/build/server/chunks/chunks/access.server.js-CwcMbS6y.js.map +1 -0
- package/build/server/chunks/chunks/access2.server.js-CGXEalQg.js +64 -0
- package/build/server/chunks/chunks/access2.server.js-CGXEalQg.js.map +1 -0
- package/build/server/chunks/chunks/activity.js-BUIPDWt1.js +17 -0
- package/build/server/chunks/chunks/activity.js-BUIPDWt1.js.map +1 -0
- package/build/server/chunks/chunks/admin-auth.server.js-CuH8RmWr.js +353 -0
- package/build/server/chunks/chunks/admin-auth.server.js-CuH8RmWr.js.map +1 -0
- package/build/server/chunks/chunks/alert-dialog.js-BG8Wa5yR.js +461 -0
- package/build/server/chunks/chunks/alert-dialog.js-BG8Wa5yR.js.map +1 -0
- package/build/server/chunks/chunks/api-errors.js-YdxnrmH7.js +55 -0
- package/build/server/chunks/chunks/api-errors.js-YdxnrmH7.js.map +1 -0
- package/build/server/chunks/chunks/api.js-Chw-vSDJ.js +882 -0
- package/build/server/chunks/chunks/api.js-Chw-vSDJ.js.map +1 -0
- package/build/server/chunks/chunks/arrow-left.js-C91xD_i2.js +17 -0
- package/build/server/chunks/chunks/arrow-left.js-C91xD_i2.js.map +1 -0
- package/build/server/chunks/chunks/arrow-right.js-Dd2VzUvu.js +17 -0
- package/build/server/chunks/chunks/arrow-right.js-Dd2VzUvu.js.map +1 -0
- package/build/server/chunks/chunks/auth-bootstrap.server.js-x03Oudbh.js +154 -0
- package/build/server/chunks/chunks/auth-bootstrap.server.js-x03Oudbh.js.map +1 -0
- package/build/server/chunks/chunks/badge.js-D2XQ42hh.js +35 -0
- package/build/server/chunks/chunks/badge.js-D2XQ42hh.js.map +1 -0
- package/build/server/chunks/chunks/bootHealth.server.js-DlFiVgGw.js +90 -0
- package/build/server/chunks/chunks/bootHealth.server.js-DlFiVgGw.js.map +1 -0
- package/build/server/chunks/chunks/building-complex.js-B0vpG_9C.js +24 -0
- package/build/server/chunks/chunks/building-complex.js-B0vpG_9C.js.map +1 -0
- package/build/server/chunks/chunks/button.js-BtRm7eTa.js +71 -0
- package/build/server/chunks/chunks/button.js-BtRm7eTa.js.map +1 -0
- package/build/server/chunks/chunks/card-content.js-kmmdF2Cw.js +20 -0
- package/build/server/chunks/chunks/card-content.js-kmmdF2Cw.js.map +1 -0
- package/build/server/chunks/chunks/card-description.js-B0JIeUuh.js +20 -0
- package/build/server/chunks/chunks/card-description.js-B0JIeUuh.js.map +1 -0
- package/build/server/chunks/chunks/card-header.js-Di5TKNrh.js +20 -0
- package/build/server/chunks/chunks/card-header.js-Di5TKNrh.js.map +1 -0
- package/build/server/chunks/chunks/card-title.js-DeKvsY4g.js +20 -0
- package/build/server/chunks/chunks/card-title.js-DeKvsY4g.js.map +1 -0
- package/build/server/chunks/chunks/card.js-BT6mpXa3.js +29 -0
- package/build/server/chunks/chunks/card.js-BT6mpXa3.js.map +1 -0
- package/build/server/chunks/chunks/chevron-down.js-D8rHJiBK.js +17 -0
- package/build/server/chunks/chunks/chevron-down.js-D8rHJiBK.js.map +1 -0
- package/build/server/chunks/chunks/chevron-left.js-wPz7Rdd5.js +17 -0
- package/build/server/chunks/chunks/chevron-left.js-wPz7Rdd5.js.map +1 -0
- package/build/server/chunks/chunks/chevron-right.js-sBa57tvn.js +17 -0
- package/build/server/chunks/chunks/chevron-right.js-sBa57tvn.js.map +1 -0
- package/build/server/chunks/chunks/chevron-up.js-CvJhUr7u.js +17 -0
- package/build/server/chunks/chunks/chevron-up.js-CvJhUr7u.js.map +1 -0
- package/build/server/chunks/chunks/circle.js-x2f20FaO.js +21 -0
- package/build/server/chunks/chunks/circle.js-x2f20FaO.js.map +1 -0
- package/build/server/chunks/chunks/client.js-BPazvdMV.js +58 -0
- package/build/server/chunks/chunks/client.js-BPazvdMV.js.map +1 -0
- package/build/server/chunks/chunks/compute.js-DjSMKp-h.js +2 -0
- package/build/server/chunks/chunks/compute.js-DjSMKp-h.js.map +1 -0
- package/build/server/chunks/chunks/computeLimits.js-VrKZoyew.js +40 -0
- package/build/server/chunks/chunks/computeLimits.js-VrKZoyew.js.map +1 -0
- package/build/server/chunks/chunks/computeRateLimit.server.js-U3-mdORL.js +28 -0
- package/build/server/chunks/chunks/computeRateLimit.server.js-U3-mdORL.js.map +1 -0
- package/build/server/chunks/chunks/context.js-DgF3EFGQ.js +103 -0
- package/build/server/chunks/chunks/context.js-DgF3EFGQ.js.map +1 -0
- package/build/server/chunks/chunks/copy.js-Buda3qiy.js +24 -0
- package/build/server/chunks/chunks/copy.js-Buda3qiy.js.map +1 -0
- package/build/server/chunks/chunks/create-id.js-alvgun-Y.js +796 -0
- package/build/server/chunks/chunks/create-id.js-alvgun-Y.js.map +1 -0
- package/build/server/chunks/chunks/create-project.js-C4Bp9O0w.js +48 -0
- package/build/server/chunks/chunks/create-project.js-C4Bp9O0w.js.map +1 -0
- package/build/server/chunks/chunks/definitions.js-sHh4E-La.js +88 -0
- package/build/server/chunks/chunks/definitions.js-sHh4E-La.js.map +1 -0
- package/build/server/chunks/chunks/delete-with-blobs.js-BZ_YRCWH.js +48 -0
- package/build/server/chunks/chunks/delete-with-blobs.js-BZ_YRCWH.js.map +1 -0
- package/build/server/chunks/chunks/dialog-description.js-aWg_zdFU.js +489 -0
- package/build/server/chunks/chunks/dialog-description.js-aWg_zdFU.js.map +1 -0
- package/build/server/chunks/chunks/dialog.js-BBIK66Og.js +360 -0
- package/build/server/chunks/chunks/dialog.js-BBIK66Og.js.map +1 -0
- package/build/server/chunks/chunks/dom-typeahead.svelte.js-DFW_4amM.js +211 -0
- package/build/server/chunks/chunks/dom-typeahead.svelte.js-DFW_4amM.js.map +1 -0
- package/build/server/chunks/chunks/engine.server.js-DpF9P7gj.js +24852 -0
- package/build/server/chunks/chunks/engine.server.js-DpF9P7gj.js.map +1 -0
- package/build/server/chunks/chunks/esm.js-CRiT7ECX.js +7 -0
- package/build/server/chunks/chunks/esm.js-CRiT7ECX.js.map +1 -0
- package/build/server/chunks/chunks/esm2.js-LSVMBS_E.js +1027 -0
- package/build/server/chunks/chunks/esm2.js-LSVMBS_E.js.map +1 -0
- package/build/server/chunks/chunks/events.js-IByrOSdq.js +136 -0
- package/build/server/chunks/chunks/events.js-IByrOSdq.js.map +1 -0
- package/build/server/chunks/chunks/exports.js-DrbIB7dk.js +149 -0
- package/build/server/chunks/chunks/exports.js-DrbIB7dk.js.map +1 -0
- package/build/server/chunks/chunks/external-link.js-CmobumMv.js +21 -0
- package/build/server/chunks/chunks/external-link.js-CmobumMv.js.map +1 -0
- package/build/server/chunks/chunks/folder-kanban.js-DVTCXCw-.js +22 -0
- package/build/server/chunks/chunks/folder-kanban.js-DVTCXCw-.js.map +1 -0
- package/build/server/chunks/chunks/folder-open.js-Dsp0uMQi.js +17 -0
- package/build/server/chunks/chunks/folder-open.js-Dsp0uMQi.js.map +1 -0
- package/build/server/chunks/chunks/folders.js-szSgfXnr.js +17 -0
- package/build/server/chunks/chunks/folders.js-szSgfXnr.js.map +1 -0
- package/build/server/chunks/chunks/footerContext.svelte.js-Ct2HYJeX.js +681 -0
- package/build/server/chunks/chunks/footerContext.svelte.js-Ct2HYJeX.js.map +1 -0
- package/build/server/chunks/chunks/forms.js-DAn853gP.js +2 -0
- package/build/server/chunks/chunks/forms.js-DAn853gP.js.map +1 -0
- package/build/server/chunks/chunks/gauge.js-SLkYK4hz.js +17 -0
- package/build/server/chunks/chunks/gauge.js-SLkYK4hz.js.map +1 -0
- package/build/server/chunks/chunks/grasshopper.js-BTMLax71.js +4332 -0
- package/build/server/chunks/chunks/grasshopper.js-BTMLax71.js.map +1 -0
- package/build/server/chunks/chunks/handlers.js-Bal7QqCB.js +1733 -0
- package/build/server/chunks/chunks/handlers.js-Bal7QqCB.js.map +1 -0
- package/build/server/chunks/chunks/http.js-B_KreOo5.js +60 -0
- package/build/server/chunks/chunks/http.js-B_KreOo5.js.map +1 -0
- package/build/server/chunks/chunks/index-server.js-8gyiABQp.js +143 -0
- package/build/server/chunks/chunks/index-server.js-8gyiABQp.js.map +1 -0
- package/build/server/chunks/chunks/input-group.js-DhqokDEu.js +65 -0
- package/build/server/chunks/chunks/input-group.js-DhqokDEu.js.map +1 -0
- package/build/server/chunks/chunks/input.js-CJQGQBPJ.js +31 -0
- package/build/server/chunks/chunks/input.js-CJQGQBPJ.js.map +1 -0
- package/build/server/chunks/chunks/instanceAdmins.server.js-Dcr7q2YW.js +70 -0
- package/build/server/chunks/chunks/instanceAdmins.server.js-Dcr7q2YW.js.map +1 -0
- package/build/server/chunks/chunks/internal.js-CqxI2xnJ.js +27 -0
- package/build/server/chunks/chunks/internal.js-CqxI2xnJ.js.map +1 -0
- package/build/server/chunks/chunks/internal2.js-D2DmOxP3.js +220 -0
- package/build/server/chunks/chunks/internal2.js-D2DmOxP3.js.map +1 -0
- package/build/server/chunks/chunks/key-round.js-Jk6uvqXa.js +22 -0
- package/build/server/chunks/chunks/key-round.js-Jk6uvqXa.js.map +1 -0
- package/build/server/chunks/chunks/label.js-B8mS-1sW.js +105 -0
- package/build/server/chunks/chunks/label.js-B8mS-1sW.js.map +1 -0
- package/build/server/chunks/chunks/legacy-client.js-BC5X9EwI.js +771 -0
- package/build/server/chunks/chunks/legacy-client.js-BC5X9EwI.js.map +1 -0
- package/build/server/chunks/chunks/link-2.js-BE2hKaIq.js +26 -0
- package/build/server/chunks/chunks/link-2.js-BE2hKaIq.js.map +1 -0
- package/build/server/chunks/chunks/list-all-members.js--iFhSDCz.js +34 -0
- package/build/server/chunks/chunks/list-all-members.js--iFhSDCz.js.map +1 -0
- package/build/server/chunks/chunks/liveSolve.server.js-sAaSK5B8.js +70 -0
- package/build/server/chunks/chunks/liveSolve.server.js-sAaSK5B8.js.map +1 -0
- package/build/server/chunks/chunks/localeContext.svelte.js-B6949xvd.js +411 -0
- package/build/server/chunks/chunks/localeContext.svelte.js-B6949xvd.js.map +1 -0
- package/build/server/chunks/chunks/mail.js-CZUt_ZEY.js +23 -0
- package/build/server/chunks/chunks/mail.js-CZUt_ZEY.js.map +1 -0
- package/build/server/chunks/chunks/minus.js-cnHKAopL.js +17 -0
- package/build/server/chunks/chunks/minus.js-cnHKAopL.js.map +1 -0
- package/build/server/chunks/chunks/navigation.js-DAn853gP.js +2 -0
- package/build/server/chunks/chunks/navigation.js-DAn853gP.js.map +1 -0
- package/build/server/chunks/chunks/oauth.js-DS-eyMD8.js +418 -0
- package/build/server/chunks/chunks/oauth.js-DS-eyMD8.js.map +1 -0
- package/build/server/chunks/chunks/oauthState.server.js-DXhkuq3r.js +53 -0
- package/build/server/chunks/chunks/oauthState.server.js-DXhkuq3r.js.map +1 -0
- package/build/server/chunks/chunks/openapi.js-COzYxaUH.js +314 -0
- package/build/server/chunks/chunks/openapi.js-COzYxaUH.js.map +1 -0
- package/build/server/chunks/chunks/outcome-ai_9fm43.js-DZScWgwt.js +165 -0
- package/build/server/chunks/chunks/outcome-ai_9fm43.js-DZScWgwt.js.map +1 -0
- package/build/server/chunks/chunks/package.js-CMlGHcJA.js +85 -0
- package/build/server/chunks/chunks/package.js-CMlGHcJA.js.map +1 -0
- package/build/server/chunks/chunks/pagination.js-D7_W7hTe.js +17 -0
- package/build/server/chunks/chunks/pagination.js-D7_W7hTe.js.map +1 -0
- package/build/server/chunks/chunks/paths.js-CR5sGHxm.js +19 -0
- package/build/server/chunks/chunks/paths.js-CR5sGHxm.js.map +1 -0
- package/build/server/chunks/chunks/permissions.server.js-CiU6uN80.js +22 -0
- package/build/server/chunks/chunks/permissions.server.js-CiU6uN80.js.map +1 -0
- package/build/server/chunks/chunks/plus.js-D5v7Bn9c.js +17 -0
- package/build/server/chunks/chunks/plus.js-D5v7Bn9c.js.map +1 -0
- package/build/server/chunks/chunks/popper-layer-force-mount.js-CP6hayn4.js +1908 -0
- package/build/server/chunks/chunks/popper-layer-force-mount.js-CP6hayn4.js.map +1 -0
- package/build/server/chunks/chunks/presets.server.js-B1LV7Ua6.js +21 -0
- package/build/server/chunks/chunks/presets.server.js-B1LV7Ua6.js.map +1 -0
- package/build/server/chunks/chunks/providers.server.js-NBgteuX7.js +6781 -0
- package/build/server/chunks/chunks/providers.server.js-NBgteuX7.js.map +1 -0
- package/build/server/chunks/chunks/randomId.js-agS6xuQo.js +22 -0
- package/build/server/chunks/chunks/randomId.js-agS6xuQo.js.map +1 -0
- package/build/server/chunks/chunks/redirect.js-CQ5k329S.js +16 -0
- package/build/server/chunks/chunks/redirect.js-CQ5k329S.js.map +1 -0
- package/build/server/chunks/chunks/refresh-cw.js-13va2nAy.js +22 -0
- package/build/server/chunks/chunks/refresh-cw.js-13va2nAy.js.map +1 -0
- package/build/server/chunks/chunks/registry.js-Cf_zc2fh.js +656 -0
- package/build/server/chunks/chunks/registry.js-Cf_zc2fh.js.map +1 -0
- package/build/server/chunks/chunks/remote-definition.js-Bad5iO9R.js +90 -0
- package/build/server/chunks/chunks/remote-definition.js-Bad5iO9R.js.map +1 -0
- package/build/server/chunks/chunks/request-context.js-IxX3HuOZ.js +28 -0
- package/build/server/chunks/chunks/request-context.js-IxX3HuOZ.js.map +1 -0
- package/build/server/chunks/chunks/resolve-server.js-DDfDV9cI.js +37 -0
- package/build/server/chunks/chunks/resolve-server.js-DDfDV9cI.js.map +1 -0
- package/build/server/chunks/chunks/resolve.server.js-DrVxsuL6.js +59 -0
- package/build/server/chunks/chunks/resolve.server.js-DrVxsuL6.js.map +1 -0
- package/build/server/chunks/chunks/rolldown-runtime.js-DdctNlVB.js +18 -0
- package/build/server/chunks/chunks/rolldown-runtime.js-DdctNlVB.js.map +1 -0
- package/build/server/chunks/chunks/rotate-ccw.js-BsvoT11y.js +17 -0
- package/build/server/chunks/chunks/rotate-ccw.js-BsvoT11y.js.map +1 -0
- package/build/server/chunks/chunks/routing.js-B7coZqxY.js +264 -0
- package/build/server/chunks/chunks/routing.js-B7coZqxY.js.map +1 -0
- package/build/server/chunks/chunks/roving-focus-group.js-CfqColTY.js +142 -0
- package/build/server/chunks/chunks/roving-focus-group.js-CfqColTY.js.map +1 -0
- package/build/server/chunks/chunks/safe-url.js-CGp87nKy.js +220 -0
- package/build/server/chunks/chunks/safe-url.js-CGp87nKy.js.map +1 -0
- package/build/server/chunks/chunks/schema-extraction.js-CDuq9Z4H.js +142 -0
- package/build/server/chunks/chunks/schema-extraction.js-CDuq9Z4H.js.map +1 -0
- package/build/server/chunks/chunks/schemas.js-CEHDw4oF.js +67 -0
- package/build/server/chunks/chunks/schemas.js-CEHDw4oF.js.map +1 -0
- package/build/server/chunks/chunks/scroll-lock.js-By--_Rp9.js +1956 -0
- package/build/server/chunks/chunks/scroll-lock.js-By--_Rp9.js.map +1 -0
- package/build/server/chunks/chunks/scroll-text.js-Cj8_5Qn1.js +22 -0
- package/build/server/chunks/chunks/scroll-text.js-Cj8_5Qn1.js.map +1 -0
- package/build/server/chunks/chunks/search.js-5cmK2jkz.js +21 -0
- package/build/server/chunks/chunks/search.js-5cmK2jkz.js.map +1 -0
- package/build/server/chunks/chunks/select.js-DcXRaO5q.js +1757 -0
- package/build/server/chunks/chunks/select.js-DcXRaO5q.js.map +1 -0
- package/build/server/chunks/chunks/selfUpdate.server.js-CowyoJjZ.js +144 -0
- package/build/server/chunks/chunks/selfUpdate.server.js-CowyoJjZ.js.map +1 -0
- package/build/server/chunks/chunks/separator.js-B3M4aY8E.js +187 -0
- package/build/server/chunks/chunks/separator.js-B3M4aY8E.js.map +1 -0
- package/build/server/chunks/chunks/server-config-write.js-C5u4cxJl.js +131 -0
- package/build/server/chunks/chunks/server-config-write.js-C5u4cxJl.js.map +1 -0
- package/build/server/chunks/chunks/server.js-D3MqDbVt.js +3921 -0
- package/build/server/chunks/chunks/server.js-D3MqDbVt.js.map +1 -0
- package/build/server/chunks/chunks/server2.js-zrAQqaix.js +105 -0
- package/build/server/chunks/chunks/server2.js-zrAQqaix.js.map +1 -0
- package/build/server/chunks/chunks/server3.js-DcmIj9YT.js +20754 -0
- package/build/server/chunks/chunks/server3.js-DcmIj9YT.js.map +1 -0
- package/build/server/chunks/chunks/server4.js-DKRrXtyZ.js +46 -0
- package/build/server/chunks/chunks/server4.js-DKRrXtyZ.js.map +1 -0
- package/build/server/chunks/chunks/serverStats.server.js-a-3j4RWH.js +19 -0
- package/build/server/chunks/chunks/serverStats.server.js-a-3j4RWH.js.map +1 -0
- package/build/server/chunks/chunks/settings.js-CNQpDE8D.js +21 -0
- package/build/server/chunks/chunks/settings.js-CNQpDE8D.js.map +1 -0
- package/build/server/chunks/chunks/severity.js-C0NeLw7v.js +117 -0
- package/build/server/chunks/chunks/severity.js-C0NeLw7v.js.map +1 -0
- package/build/server/chunks/chunks/shared-server.js-CX8yV6G4.js +22 -0
- package/build/server/chunks/chunks/shared-server.js-CX8yV6G4.js.map +1 -0
- package/build/server/chunks/chunks/shared.js-DSkns_OG.js +709 -0
- package/build/server/chunks/chunks/shared.js-DSkns_OG.js.map +1 -0
- package/build/server/chunks/chunks/shared2.js-UmpDkNsI.js +88 -0
- package/build/server/chunks/chunks/shared2.js-UmpDkNsI.js.map +1 -0
- package/build/server/chunks/chunks/shield-check.js-BZhVuaHj.js +17 -0
- package/build/server/chunks/chunks/shield-check.js-BZhVuaHj.js.map +1 -0
- package/build/server/chunks/chunks/shield.js-BLi0_7a2.js +17 -0
- package/build/server/chunks/chunks/shield.js-BLi0_7a2.js.map +1 -0
- package/build/server/chunks/chunks/solve.server.js-DG3CZ__n.js +334 -0
- package/build/server/chunks/chunks/solve.server.js-DG3CZ__n.js.map +1 -0
- package/build/server/chunks/chunks/sr-only-styles.js-CgNXGZ9C.js +19 -0
- package/build/server/chunks/chunks/sr-only-styles.js-CgNXGZ9C.js.map +1 -0
- package/build/server/chunks/chunks/star.js-iocG1yaM.js +17 -0
- package/build/server/chunks/chunks/star.js-iocG1yaM.js.map +1 -0
- package/build/server/chunks/chunks/state.js-B6BoHGCe.js +75 -0
- package/build/server/chunks/chunks/state.js-B6BoHGCe.js.map +1 -0
- package/build/server/chunks/chunks/stores.js--FiPN6jK.js +36 -0
- package/build/server/chunks/chunks/stores.js--FiPN6jK.js.map +1 -0
- package/build/server/chunks/chunks/sveltekit.js-DJdcVNs2.js +193 -0
- package/build/server/chunks/chunks/sveltekit.js-DJdcVNs2.js.map +1 -0
- package/build/server/chunks/chunks/tabs-trigger.js-DI-yv4IP.js +502 -0
- package/build/server/chunks/chunks/tabs-trigger.js-DI-yv4IP.js.map +1 -0
- package/build/server/chunks/chunks/textarea.js-DstXofBD.js +24 -0
- package/build/server/chunks/chunks/textarea.js-DstXofBD.js.map +1 -0
- package/build/server/chunks/chunks/toast-state.svelte.js-B77BdEle.js +285 -0
- package/build/server/chunks/chunks/toast-state.svelte.js-B77BdEle.js.map +1 -0
- package/build/server/chunks/chunks/toggle-group-item.js-BUV4sYM9.js +401 -0
- package/build/server/chunks/chunks/toggle-group-item.js-BUV4sYM9.js.map +1 -0
- package/build/server/chunks/chunks/token.server.js-BihmkUmu.js +131 -0
- package/build/server/chunks/chunks/token.server.js-BihmkUmu.js.map +1 -0
- package/build/server/chunks/chunks/token2.server.js-DaAVo3Gq.js +51 -0
- package/build/server/chunks/chunks/token2.server.js-DaAVo3Gq.js.map +1 -0
- package/build/server/chunks/chunks/token3.server.js-CuyMT-M4.js +42 -0
- package/build/server/chunks/chunks/token3.server.js-CuyMT-M4.js.map +1 -0
- package/build/server/chunks/chunks/token4.server.js-DUK9D5vc.js +25 -0
- package/build/server/chunks/chunks/token4.server.js-DUK9D5vc.js.map +1 -0
- package/build/server/chunks/chunks/tokens.js-CwDDHAj0.js +26 -0
- package/build/server/chunks/chunks/tokens.js-CwDDHAj0.js.map +1 -0
- package/build/server/chunks/chunks/trash.js-BG3wZbiW.js +24 -0
- package/build/server/chunks/chunks/trash.js-BG3wZbiW.js.map +1 -0
- package/build/server/chunks/chunks/types.js-g5F0W_ER.js +71 -0
- package/build/server/chunks/chunks/types.js-g5F0W_ER.js.map +1 -0
- package/build/server/chunks/chunks/types2.js-ZWmoZn1t.js +28 -0
- package/build/server/chunks/chunks/types2.js-ZWmoZn1t.js.map +1 -0
- package/build/server/chunks/chunks/types3.js-BS6pAwdK.js +29 -0
- package/build/server/chunks/chunks/types3.js-BS6pAwdK.js.map +1 -0
- package/build/server/chunks/chunks/types4.js-C7gj_Qvn.js +10 -0
- package/build/server/chunks/chunks/types4.js-C7gj_Qvn.js.map +1 -0
- package/build/server/chunks/chunks/updateCheck.server.js-C5itsGib.js +203 -0
- package/build/server/chunks/chunks/updateCheck.server.js-C5itsGib.js.map +1 -0
- package/build/server/chunks/chunks/user-plus.js-qSc6ZC5c.js +36 -0
- package/build/server/chunks/chunks/user-plus.js-qSc6ZC5c.js.map +1 -0
- package/build/server/chunks/chunks/users.js-D8PmGm71.js +26 -0
- package/build/server/chunks/chunks/users.js-D8PmGm71.js.map +1 -0
- package/build/server/chunks/chunks/utils.js-BltBkspC.js +745 -0
- package/build/server/chunks/chunks/utils.js-BltBkspC.js.map +1 -0
- package/build/server/chunks/chunks/utils2.js-j8wahBau.js +100 -0
- package/build/server/chunks/chunks/utils2.js-j8wahBau.js.map +1 -0
- package/build/server/chunks/chunks/utils3.js-DANle-lS.js +175 -0
- package/build/server/chunks/chunks/utils3.js-DANle-lS.js.map +1 -0
- package/build/server/chunks/chunks/visibility.js-D_48QE1C.js +198 -0
- package/build/server/chunks/chunks/visibility.js-D_48QE1C.js.map +1 -0
- package/build/server/chunks/chunks/x.js-BZdroOIk.js +17 -0
- package/build/server/chunks/chunks/x.js-BZdroOIk.js.map +1 -0
- package/build/server/chunks/entries/endpoints/.well-known/oauth-authorization-server/_server.ts.js-Y4FNmUgo.js +22 -0
- package/build/server/chunks/entries/endpoints/.well-known/oauth-authorization-server/_server.ts.js-Y4FNmUgo.js.map +1 -0
- package/build/server/chunks/entries/endpoints/.well-known/oauth-protected-resource/_server.ts.js-j6at35lG.js +22 -0
- package/build/server/chunks/entries/endpoints/.well-known/oauth-protected-resource/_server.ts.js-j6at35lG.js.map +1 -0
- package/build/server/chunks/entries/endpoints/.well-known/oauth-protected-resource/mcp/_server.ts.js-BL-en2rL.js +22 -0
- package/build/server/chunks/entries/endpoints/.well-known/oauth-protected-resource/mcp/_server.ts.js-BL-en2rL.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/compute/_server.ts.js-C38i1X4J.js +106 -0
- package/build/server/chunks/entries/endpoints/api/admin/compute/_server.ts.js-C38i1X4J.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/compute/actions/_server.ts.js-DMVKwgGx.js +93 -0
- package/build/server/chunks/entries/endpoints/api/admin/compute/actions/_server.ts.js-DMVKwgGx.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/compute/status/_server.ts.js-DyztvOsn.js +112 -0
- package/build/server/chunks/entries/endpoints/api/admin/compute/status/_server.ts.js-DyztvOsn.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/orgs/_id_/_server.ts.js-i5xcJ2zV.js +55 -0
- package/build/server/chunks/entries/endpoints/api/admin/orgs/_id_/_server.ts.js-i5xcJ2zV.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/orgs/_server.ts.js-D7cYcptw.js +72 -0
- package/build/server/chunks/entries/endpoints/api/admin/orgs/_server.ts.js-D7cYcptw.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/_server.ts.js-tMO36lWs.js +71 -0
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/_server.ts.js-tMO36lWs.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/grants/_grantId_/_server.ts.js-l8YVf5sM.js +37 -0
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/grants/_grantId_/_server.ts.js-l8YVf5sM.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/grants/_server.ts.js-CTk5egeL.js +68 -0
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/grants/_server.ts.js-CTk5egeL.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/projects/_server.ts.js-CzGCUDs9.js +83 -0
- package/build/server/chunks/entries/endpoints/api/admin/projects/_server.ts.js-CzGCUDs9.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/system/health/_server.ts.js-Dv7Qpfzu.js +373 -0
- package/build/server/chunks/entries/endpoints/api/admin/system/health/_server.ts.js-Dv7Qpfzu.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/system/throughput/_server.ts.js-D0H3LOoP.js +88 -0
- package/build/server/chunks/entries/endpoints/api/admin/system/throughput/_server.ts.js-D0H3LOoP.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/system/update/_server.ts.js-CVu46dA1.js +609 -0
- package/build/server/chunks/entries/endpoints/api/admin/system/update/_server.ts.js-CVu46dA1.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/users/_id_/_server.ts.js-CGw-NzwG.js +68 -0
- package/build/server/chunks/entries/endpoints/api/admin/users/_id_/_server.ts.js-CGw-NzwG.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/users/_id_/disable/_server.ts.js-B8pySiI6.js +85 -0
- package/build/server/chunks/entries/endpoints/api/admin/users/_id_/disable/_server.ts.js-B8pySiI6.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/admin/users/_server.ts.js-agHv2gf2.js +87 -0
- package/build/server/chunks/entries/endpoints/api/admin/users/_server.ts.js-agHv2gf2.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/diag/throughput/_server.ts.js-DvYVATxV.js +68 -0
- package/build/server/chunks/entries/endpoints/api/diag/throughput/_server.ts.js-DvYVATxV.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/files/_...path_/_server.ts.js-CHQmqBWH.js +86 -0
- package/build/server/chunks/entries/endpoints/api/files/_...path_/_server.ts.js-CHQmqBWH.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/health/_server.ts.js-yuOzWsE8.js +61 -0
- package/build/server/chunks/entries/endpoints/api/health/_server.ts.js-yuOzWsE8.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/health/ready/_server.ts.js-ULeO0DYe.js +64 -0
- package/build/server/chunks/entries/endpoints/api/health/ready/_server.ts.js-ULeO0DYe.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/compute/_server.ts.js-BD1RwQTA.js +103 -0
- package/build/server/chunks/entries/endpoints/api/v1/compute/_server.ts.js-BD1RwQTA.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/compute/schema/_server.ts.js-BZprVTVf.js +84 -0
- package/build/server/chunks/entries/endpoints/api/v1/compute/schema/_server.ts.js-BZprVTVf.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/_server.ts.js-SHP8vaWU.js +59 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/_server.ts.js-SHP8vaWU.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/image/_server.ts.js-BUv_eD9D.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/image/_server.ts.js-BUv_eD9D.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/publish/_server.ts.js-B3yc1cw3.js +60 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/publish/_server.ts.js-B3yc1cw3.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/schema/_server.ts.js-D6XBcggf.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/schema/_server.ts.js-D6XBcggf.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/share-links/_linkId_/_server.ts.js-D99MFAb4.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/share-links/_linkId_/_server.ts.js-D99MFAb4.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/share-links/_server.ts.js-BhmWyQ-k.js +61 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/share-links/_server.ts.js-BhmWyQ-k.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/solve/_server.ts.js-KFurrqrS.js +113 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/solve/_server.ts.js-KFurrqrS.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_server.ts.js-BKzappNU.js +62 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_server.ts.js-BKzappNU.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_versionId_/_server.ts.js-CUNVO93x.js +58 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_versionId_/_server.ts.js-CUNVO93x.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_versionId_/schema/_server.ts.js-BRb4wv48.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_versionId_/schema/_server.ts.js-BRb4wv48.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_server.ts.js-DYloVHJK.js +60 -0
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_server.ts.js-DYloVHJK.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/me/_server.ts.js-DUrEaQ9R.js +56 -0
- package/build/server/chunks/entries/endpoints/api/v1/me/_server.ts.js-DUrEaQ9R.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/me/starred/_guid_/_server.ts.js-BhZQU4xc.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/me/starred/_guid_/_server.ts.js-BhZQU4xc.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/me/token/_server.ts.js-yyHpOhdC.js +56 -0
- package/build/server/chunks/entries/endpoints/api/v1/me/token/_server.ts.js-yyHpOhdC.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/openapi.json/_server.ts.js-DQ5S-7hT.js +51 -0
- package/build/server/chunks/entries/endpoints/api/v1/openapi.json/_server.ts.js-DQ5S-7hT.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/_server.ts.js-BlYSLmz0.js +56 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/_server.ts.js-BlYSLmz0.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/assets/_kind_/_server.ts.js-DMR9Nnlk.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/assets/_kind_/_server.ts.js-DMR9Nnlk.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/compute/_server.ts.js-ZTwRpPyd.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/compute/_server.ts.js-ZTwRpPyd.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_id_/_server.ts.js-DaEsmasg.js +56 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_id_/_server.ts.js-DaEsmasg.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_id_/resend/_server.ts.js-BKI_EoxY.js +56 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_id_/resend/_server.ts.js-BKI_EoxY.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_server.ts.js-BTwIxUbs.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_server.ts.js-BTwIxUbs.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/members/_server.ts.js-Bpox8XIL.js +56 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/members/_server.ts.js-Bpox8XIL.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/members/_userId_/_server.ts.js-cdYBK2Y6.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/members/_userId_/_server.ts.js-cdYBK2Y6.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/tokens/_server.ts.js-CizguGuR.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/tokens/_server.ts.js-CizguGuR.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/tokens/_tokenId_/_server.ts.js-5GbCw5Ss.js +56 -0
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/tokens/_tokenId_/_server.ts.js-5GbCw5Ss.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/_server.ts.js-czGn1vGZ.js +59 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/_server.ts.js-czGn1vGZ.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/members/_server.ts.js-uQT-DdgK.js +58 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/members/_server.ts.js-uQT-DdgK.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/members/_userId_/_server.ts.js-DO-TosdX.js +58 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/members/_userId_/_server.ts.js-DO-TosdX.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/reclaim/_server.ts.js-C7rY7UF-.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/reclaim/_server.ts.js-C7rY7UF-.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_server.ts.js-aXVcI2X7.js +57 -0
- package/build/server/chunks/entries/endpoints/api/v1/projects/_server.ts.js-aXVcI2X7.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/solve/_solveId_/cancel/_server.ts.js-CTNXcTG2.js +53 -0
- package/build/server/chunks/entries/endpoints/api/v1/solve/_solveId_/cancel/_server.ts.js-CTNXcTG2.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/solve-events/_server.ts.js-D8wj8cuC.js +113 -0
- package/build/server/chunks/entries/endpoints/api/v1/solve-events/_server.ts.js-D8wj8cuC.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/v1/solve-events/_solveId_/_server.ts.js-CFUbszn6.js +68 -0
- package/build/server/chunks/entries/endpoints/api/v1/solve-events/_solveId_/_server.ts.js-CFUbszn6.js.map +1 -0
- package/build/server/chunks/entries/endpoints/auth/email/callback/_server.ts.js-Cus6ontA.js +57 -0
- package/build/server/chunks/entries/endpoints/auth/email/callback/_server.ts.js-Cus6ontA.js.map +1 -0
- package/build/server/chunks/entries/endpoints/auth/supabase/callback/_server.ts.js-_7wdO0Y5.js +63 -0
- package/build/server/chunks/entries/endpoints/auth/supabase/callback/_server.ts.js-_7wdO0Y5.js.map +1 -0
- package/build/server/chunks/entries/endpoints/auth/supabase/start/_server.ts.js-B36Q0fjD.js +68 -0
- package/build/server/chunks/entries/endpoints/auth/supabase/start/_server.ts.js-B36Q0fjD.js.map +1 -0
- package/build/server/chunks/entries/endpoints/mcp/_server.ts.js-B5uHA9Un.js +29 -0
- package/build/server/chunks/entries/endpoints/mcp/_server.ts.js-B5uHA9Un.js.map +1 -0
- package/build/server/chunks/entries/endpoints/oauth/register/_server.ts.js-BQCyVuY5.js +33 -0
- package/build/server/chunks/entries/endpoints/oauth/register/_server.ts.js-BQCyVuY5.js.map +1 -0
- package/build/server/chunks/entries/endpoints/oauth/token/_server.ts.js-BHSnsHeO.js +36 -0
- package/build/server/chunks/entries/endpoints/oauth/token/_server.ts.js-BHSnsHeO.js.map +1 -0
- package/build/server/chunks/entries/hooks.server.js-D7z2wfOe.js +371 -0
- package/build/server/chunks/entries/hooks.server.js-D7z2wfOe.js.map +1 -0
- package/build/server/chunks/entries/pages/_error.svelte.js-DcAooRf9.js +40 -0
- package/build/server/chunks/entries/pages/_error.svelte.js-DcAooRf9.js.map +1 -0
- package/build/server/chunks/entries/pages/_layout.server.ts.js-DdxfSnO9.js +37 -0
- package/build/server/chunks/entries/pages/_layout.server.ts.js-DdxfSnO9.js.map +1 -0
- package/build/server/chunks/entries/pages/_layout.svelte.js-DLKjfBe9.js +627 -0
- package/build/server/chunks/entries/pages/_layout.svelte.js-DLKjfBe9.js.map +1 -0
- package/build/server/chunks/entries/pages/_page.server.ts.js-DPqP9hHw.js +57 -0
- package/build/server/chunks/entries/pages/_page.server.ts.js-DPqP9hHw.js.map +1 -0
- package/build/server/chunks/entries/pages/_page.svelte.js-CrlCM_Ta.js +164 -0
- package/build/server/chunks/entries/pages/_page.svelte.js-CrlCM_Ta.js.map +1 -0
- package/build/server/chunks/entries/pages/accept-invite/_page.server.ts.js-DplYvYbn.js +185 -0
- package/build/server/chunks/entries/pages/accept-invite/_page.server.ts.js-DplYvYbn.js.map +1 -0
- package/build/server/chunks/entries/pages/accept-invite/_page.svelte.js-DqROVIBb.js +137 -0
- package/build/server/chunks/entries/pages/accept-invite/_page.svelte.js-DqROVIBb.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/_error.svelte.js-BzYWy3BU.js +42 -0
- package/build/server/chunks/entries/pages/admin/_error.svelte.js-BzYWy3BU.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/_layout.server.ts.js-DM-DiNwe.js +31 -0
- package/build/server/chunks/entries/pages/admin/_layout.server.ts.js-DM-DiNwe.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/_layout.svelte.js-BFQeJsER.js +127 -0
- package/build/server/chunks/entries/pages/admin/_layout.svelte.js-BFQeJsER.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/_page.server.ts.js-Db0W-ij6.js +76 -0
- package/build/server/chunks/entries/pages/admin/_page.server.ts.js-Db0W-ij6.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/_page.svelte.js-DhhVao5-.js +398 -0
- package/build/server/chunks/entries/pages/admin/_page.svelte.js-DhhVao5-.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/audit/_page.server.ts.js-Bvtum5V0.js +269 -0
- package/build/server/chunks/entries/pages/admin/audit/_page.server.ts.js-Bvtum5V0.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/audit/_page.svelte.js-DdopSLBD.js +460 -0
- package/build/server/chunks/entries/pages/admin/audit/_page.svelte.js-DdopSLBD.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/compute/_page.server.ts.js-LOLemi4X.js +73 -0
- package/build/server/chunks/entries/pages/admin/compute/_page.server.ts.js-LOLemi4X.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/compute/_page.svelte.js-Pzxu0RIV.js +844 -0
- package/build/server/chunks/entries/pages/admin/compute/_page.svelte.js-Pzxu0RIV.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/organizations/_page.server.ts.js-DW7chloI.js +35 -0
- package/build/server/chunks/entries/pages/admin/organizations/_page.server.ts.js-DW7chloI.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/organizations/_page.svelte.js-BpI4ERfU.js +100 -0
- package/build/server/chunks/entries/pages/admin/organizations/_page.svelte.js-BpI4ERfU.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/projects/_id_/_page.server.ts.js-Nr3QA7TW.js +86 -0
- package/build/server/chunks/entries/pages/admin/projects/_id_/_page.server.ts.js-Nr3QA7TW.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/projects/_id_/_page.svelte.js-BU5Mo6DA.js +643 -0
- package/build/server/chunks/entries/pages/admin/projects/_id_/_page.svelte.js-BU5Mo6DA.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/projects/_page.server.ts.js-BOsSF0Nk.js +42 -0
- package/build/server/chunks/entries/pages/admin/projects/_page.server.ts.js-BOsSF0Nk.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/projects/_page.svelte.js-x1y_D8Ak.js +288 -0
- package/build/server/chunks/entries/pages/admin/projects/_page.svelte.js-x1y_D8Ak.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/system/_page.server.ts.js-CKEEXGK3.js +87 -0
- package/build/server/chunks/entries/pages/admin/system/_page.server.ts.js-CKEEXGK3.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/system/_page.svelte.js-Cn8pmw_n.js +1391 -0
- package/build/server/chunks/entries/pages/admin/system/_page.svelte.js-Cn8pmw_n.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/users/_page.server.ts.js-DVIjhA2b.js +80 -0
- package/build/server/chunks/entries/pages/admin/users/_page.server.ts.js-DVIjhA2b.js.map +1 -0
- package/build/server/chunks/entries/pages/admin/users/_page.svelte.js-Dtqm8Fz6.js +638 -0
- package/build/server/chunks/entries/pages/admin/users/_page.svelte.js-Dtqm8Fz6.js.map +1 -0
- package/build/server/chunks/entries/pages/auth/email/sent/_page.svelte.js-CMy7hdWz.js +48 -0
- package/build/server/chunks/entries/pages/auth/email/sent/_page.svelte.js-CMy7hdWz.js.map +1 -0
- package/build/server/chunks/entries/pages/auth/email/start/_page.server.ts.js-Cr4z0_XV.js +62 -0
- package/build/server/chunks/entries/pages/auth/email/start/_page.server.ts.js-Cr4z0_XV.js.map +1 -0
- package/build/server/chunks/entries/pages/auth/email/start/_page.svelte.js-CsCJycox.js +15 -0
- package/build/server/chunks/entries/pages/auth/email/start/_page.svelte.js-CsCJycox.js.map +1 -0
- package/build/server/chunks/entries/pages/docs/api/_page.server.ts.js-C8Noz5WA.js +59 -0
- package/build/server/chunks/entries/pages/docs/api/_page.server.ts.js-C8Noz5WA.js.map +1 -0
- package/build/server/chunks/entries/pages/docs/api/_page.svelte.js-B1GTwpET.js +86 -0
- package/build/server/chunks/entries/pages/docs/api/_page.svelte.js-B1GTwpET.js.map +1 -0
- package/build/server/chunks/entries/pages/library/_guid_/_page.server.ts.js-Dizyr7qx.js +255 -0
- package/build/server/chunks/entries/pages/library/_guid_/_page.server.ts.js-Dizyr7qx.js.map +1 -0
- package/build/server/chunks/entries/pages/library/_guid_/_page.svelte.js-DAd6WLRk.js +16125 -0
- package/build/server/chunks/entries/pages/library/_guid_/_page.svelte.js-DAd6WLRk.js.map +1 -0
- package/build/server/chunks/entries/pages/library/_page.server.ts.js-DTHdnSTg.js +52 -0
- package/build/server/chunks/entries/pages/library/_page.server.ts.js-DTHdnSTg.js.map +1 -0
- package/build/server/chunks/entries/pages/library/_page.svelte.js-CxrjAzrQ.js +305 -0
- package/build/server/chunks/entries/pages/library/_page.svelte.js-CxrjAzrQ.js.map +1 -0
- package/build/server/chunks/entries/pages/login/_page.server.ts.js-A50kGHkz.js +101 -0
- package/build/server/chunks/entries/pages/login/_page.server.ts.js-A50kGHkz.js.map +1 -0
- package/build/server/chunks/entries/pages/login/_page.svelte.js-C9UquPB3.js +216 -0
- package/build/server/chunks/entries/pages/login/_page.svelte.js-C9UquPB3.js.map +1 -0
- package/build/server/chunks/entries/pages/logout/_page.server.ts.js-BVRdNFaV.js +19 -0
- package/build/server/chunks/entries/pages/logout/_page.server.ts.js-BVRdNFaV.js.map +1 -0
- package/build/server/chunks/entries/pages/oauth/authorize/_page.server.ts.js-CdjkGV1C.js +103 -0
- package/build/server/chunks/entries/pages/oauth/authorize/_page.server.ts.js-CdjkGV1C.js.map +1 -0
- package/build/server/chunks/entries/pages/oauth/authorize/_page.svelte.js-DfDRfWIV.js +135 -0
- package/build/server/chunks/entries/pages/oauth/authorize/_page.svelte.js-DfDRfWIV.js.map +1 -0
- package/build/server/chunks/entries/pages/projects/_layout.server.ts.js-DOFsO3cm.js +22 -0
- package/build/server/chunks/entries/pages/projects/_layout.server.ts.js-DOFsO3cm.js.map +1 -0
- package/build/server/chunks/entries/pages/projects/_layout.svelte.js-CtnJbI_b.js +54 -0
- package/build/server/chunks/entries/pages/projects/_layout.svelte.js-CtnJbI_b.js.map +1 -0
- package/build/server/chunks/entries/pages/projects/_page.server.ts.js-BMF9mAIL.js +94 -0
- package/build/server/chunks/entries/pages/projects/_page.server.ts.js-BMF9mAIL.js.map +1 -0
- package/build/server/chunks/entries/pages/projects/_page.svelte.js-CaaavD0a.js +3634 -0
- package/build/server/chunks/entries/pages/projects/_page.svelte.js-CaaavD0a.js.map +1 -0
- package/build/server/chunks/entries/pages/setup/_page.server.ts.js-CyEvoES6.js +117 -0
- package/build/server/chunks/entries/pages/setup/_page.server.ts.js-CyEvoES6.js.map +1 -0
- package/build/server/chunks/entries/pages/setup/_page.svelte.js-BVUL2wt9.js +251 -0
- package/build/server/chunks/entries/pages/setup/_page.svelte.js-BVUL2wt9.js.map +1 -0
- package/build/server/chunks/entries/pages/team/_layout.server.ts.js-Cc8j4fj_.js +28 -0
- package/build/server/chunks/entries/pages/team/_layout.server.ts.js-Cc8j4fj_.js.map +1 -0
- package/build/server/chunks/entries/pages/team/_layout.svelte.js-BKcyGxgg.js +180 -0
- package/build/server/chunks/entries/pages/team/_layout.svelte.js-BKcyGxgg.js.map +1 -0
- package/build/server/chunks/entries/pages/team/_page.server.ts.js-BcVnxaRf.js +35 -0
- package/build/server/chunks/entries/pages/team/_page.server.ts.js-BcVnxaRf.js.map +1 -0
- package/build/server/chunks/entries/pages/team/_page.svelte.js-6qxmCK84.js +113 -0
- package/build/server/chunks/entries/pages/team/_page.svelte.js-6qxmCK84.js.map +1 -0
- package/build/server/chunks/entries/pages/team/activity/_page.svelte.js-CAtYLE7m.js +125 -0
- package/build/server/chunks/entries/pages/team/activity/_page.svelte.js-CAtYLE7m.js.map +1 -0
- package/build/server/chunks/entries/pages/team/compute/_page.server.ts.js-BNv_7kxv.js +42 -0
- package/build/server/chunks/entries/pages/team/compute/_page.server.ts.js-BNv_7kxv.js.map +1 -0
- package/build/server/chunks/entries/pages/team/compute/_page.svelte.js-HZy3y0QU.js +619 -0
- package/build/server/chunks/entries/pages/team/compute/_page.svelte.js-HZy3y0QU.js.map +1 -0
- package/build/server/chunks/entries/pages/team/members/_page.server.ts.js-DSMmkpzH.js +62 -0
- package/build/server/chunks/entries/pages/team/members/_page.server.ts.js-DSMmkpzH.js.map +1 -0
- package/build/server/chunks/entries/pages/team/members/_page.svelte.js-BlMCPKzd.js +809 -0
- package/build/server/chunks/entries/pages/team/members/_page.svelte.js-BlMCPKzd.js.map +1 -0
- package/build/server/chunks/entries/pages/team/projects/_page.server.ts.js-3VRyIDx1.js +59 -0
- package/build/server/chunks/entries/pages/team/projects/_page.server.ts.js-3VRyIDx1.js.map +1 -0
- package/build/server/chunks/entries/pages/team/projects/_page.svelte.js-BBKJG4NP.js +426 -0
- package/build/server/chunks/entries/pages/team/projects/_page.svelte.js-BBKJG4NP.js.map +1 -0
- package/build/server/chunks/entries/pages/team/reclaim/_page.server.ts.js-BVcsK0M_.js +67 -0
- package/build/server/chunks/entries/pages/team/reclaim/_page.server.ts.js-BVcsK0M_.js.map +1 -0
- package/build/server/chunks/entries/pages/team/reclaim/_page.svelte.js-Dz3RP8ty.js +268 -0
- package/build/server/chunks/entries/pages/team/reclaim/_page.svelte.js-Dz3RP8ty.js.map +1 -0
- package/build/server/chunks/entries/pages/team/settings/_page.server.ts.js-DLNDwV67.js +34 -0
- package/build/server/chunks/entries/pages/team/settings/_page.server.ts.js-DLNDwV67.js.map +1 -0
- package/build/server/chunks/entries/pages/team/settings/_page.svelte.js-XIO1me8K.js +309 -0
- package/build/server/chunks/entries/pages/team/settings/_page.svelte.js-XIO1me8K.js.map +1 -0
- package/build/server/chunks/entries/pages/team/shares/_page.server.ts.js-B_X9Os5m.js +29 -0
- package/build/server/chunks/entries/pages/team/shares/_page.server.ts.js-B_X9Os5m.js.map +1 -0
- package/build/server/chunks/entries/pages/team/shares/_page.svelte.js-k7tSDsnp.js +316 -0
- package/build/server/chunks/entries/pages/team/shares/_page.svelte.js-k7tSDsnp.js.map +1 -0
- package/build/server/chunks/entries/pages/team/tokens/_page.server.ts.js-DTs5SzTp.js +65 -0
- package/build/server/chunks/entries/pages/team/tokens/_page.server.ts.js-DTs5SzTp.js.map +1 -0
- package/build/server/chunks/entries/pages/team/tokens/_page.svelte.js-DxnOnIWE.js +956 -0
- package/build/server/chunks/entries/pages/team/tokens/_page.svelte.js-DxnOnIWE.js.map +1 -0
- package/build/server/chunks/handler-Bx5iEZ29.js +1206 -0
- package/build/server/chunks/handler-Bx5iEZ29.js.map +1 -0
- package/build/server/chunks/index.js-Co4ze87n.js +3743 -0
- package/build/server/chunks/index.js-Co4ze87n.js.map +1 -0
- package/build/server/chunks/manifest.js--UTIhb45.js +719 -0
- package/build/server/chunks/manifest.js--UTIhb45.js.map +1 -0
- package/build/server/chunks/nodes/0.js-CsffbC0H.js +64 -0
- package/build/server/chunks/nodes/0.js-CsffbC0H.js.map +1 -0
- package/build/server/chunks/nodes/1.js-1M_czfIE.js +9 -0
- package/build/server/chunks/nodes/1.js-1M_czfIE.js.map +1 -0
- package/build/server/chunks/nodes/10.js-9eineyBX.js +33 -0
- package/build/server/chunks/nodes/10.js-9eineyBX.js.map +1 -0
- package/build/server/chunks/nodes/11.js-BKOfZHSf.js +40 -0
- package/build/server/chunks/nodes/11.js-BKOfZHSf.js.map +1 -0
- package/build/server/chunks/nodes/12.js-D0iYCbdB.js +30 -0
- package/build/server/chunks/nodes/12.js-D0iYCbdB.js.map +1 -0
- package/build/server/chunks/nodes/13.js-DS3dCGzm.js +30 -0
- package/build/server/chunks/nodes/13.js-DS3dCGzm.js.map +1 -0
- package/build/server/chunks/nodes/14.js-DtpHh9Ei.js +30 -0
- package/build/server/chunks/nodes/14.js-DtpHh9Ei.js.map +1 -0
- package/build/server/chunks/nodes/15.js-C_zywGat.js +38 -0
- package/build/server/chunks/nodes/15.js-C_zywGat.js.map +1 -0
- package/build/server/chunks/nodes/16.js-DESQ1vhu.js +34 -0
- package/build/server/chunks/nodes/16.js-DESQ1vhu.js.map +1 -0
- package/build/server/chunks/nodes/17.js-BQ14YL5Q.js +9 -0
- package/build/server/chunks/nodes/17.js-BQ14YL5Q.js.map +1 -0
- package/build/server/chunks/nodes/18.js-CngSMa3v.js +39 -0
- package/build/server/chunks/nodes/18.js-CngSMa3v.js.map +1 -0
- package/build/server/chunks/nodes/19.js-Bs85z3mz.js +24 -0
- package/build/server/chunks/nodes/19.js-Bs85z3mz.js.map +1 -0
- package/build/server/chunks/nodes/2.js-Dflj9i6a.js +33 -0
- package/build/server/chunks/nodes/2.js-Dflj9i6a.js.map +1 -0
- package/build/server/chunks/nodes/20.js-5C076ZPn.js +24 -0
- package/build/server/chunks/nodes/20.js-5C076ZPn.js.map +1 -0
- package/build/server/chunks/nodes/21.js-r9WaeaFU.js +46 -0
- package/build/server/chunks/nodes/21.js-r9WaeaFU.js.map +1 -0
- package/build/server/chunks/nodes/22.js-gdMWRDn8.js +39 -0
- package/build/server/chunks/nodes/22.js-gdMWRDn8.js.map +1 -0
- package/build/server/chunks/nodes/23.js-DWnXnKx-.js +36 -0
- package/build/server/chunks/nodes/23.js-DWnXnKx-.js.map +1 -0
- package/build/server/chunks/nodes/24.js-DrAi8A4i.js +64 -0
- package/build/server/chunks/nodes/24.js-DrAi8A4i.js.map +1 -0
- package/build/server/chunks/nodes/25.js-COwyuGav.js +32 -0
- package/build/server/chunks/nodes/25.js-COwyuGav.js.map +1 -0
- package/build/server/chunks/nodes/26.js-DDD-upfu.js +39 -0
- package/build/server/chunks/nodes/26.js-DDD-upfu.js.map +1 -0
- package/build/server/chunks/nodes/27.js-BWk5YriL.js +30 -0
- package/build/server/chunks/nodes/27.js-BWk5YriL.js.map +1 -0
- package/build/server/chunks/nodes/28.js-YNQTXbDQ.js +9 -0
- package/build/server/chunks/nodes/28.js-YNQTXbDQ.js.map +1 -0
- package/build/server/chunks/nodes/29.js-CtM1lXTE.js +30 -0
- package/build/server/chunks/nodes/29.js-CtM1lXTE.js.map +1 -0
- package/build/server/chunks/nodes/3.js-VtV7TxL1.js +9 -0
- package/build/server/chunks/nodes/3.js-VtV7TxL1.js.map +1 -0
- package/build/server/chunks/nodes/30.js-HuKHzr9Q.js +30 -0
- package/build/server/chunks/nodes/30.js-HuKHzr9Q.js.map +1 -0
- package/build/server/chunks/nodes/31.js-DkqRepK3.js +33 -0
- package/build/server/chunks/nodes/31.js-DkqRepK3.js.map +1 -0
- package/build/server/chunks/nodes/32.js-C1CcTXlw.js +30 -0
- package/build/server/chunks/nodes/32.js-C1CcTXlw.js.map +1 -0
- package/build/server/chunks/nodes/33.js-m2eeuHjs.js +30 -0
- package/build/server/chunks/nodes/33.js-m2eeuHjs.js.map +1 -0
- package/build/server/chunks/nodes/34.js-8v1opvXq.js +30 -0
- package/build/server/chunks/nodes/34.js-8v1opvXq.js.map +1 -0
- package/build/server/chunks/nodes/35.js-DJIEXvyl.js +64 -0
- package/build/server/chunks/nodes/35.js-DJIEXvyl.js.map +1 -0
- package/build/server/chunks/nodes/5.js-D0GcirfV.js +17 -0
- package/build/server/chunks/nodes/5.js-D0GcirfV.js.map +1 -0
- package/build/server/chunks/nodes/6.js-wM6qNHlj.js +30 -0
- package/build/server/chunks/nodes/6.js-wM6qNHlj.js.map +1 -0
- package/build/server/chunks/nodes/7.js-Cjym7aMM.js +24 -0
- package/build/server/chunks/nodes/7.js-Cjym7aMM.js.map +1 -0
- package/build/server/chunks/nodes/8.js-gB6nefGU.js +40 -0
- package/build/server/chunks/nodes/8.js-gB6nefGU.js.map +1 -0
- package/build/server/chunks/nodes/9.js-Dwq5Kgp8.js +30 -0
- package/build/server/chunks/nodes/9.js-Dwq5Kgp8.js.map +1 -0
- package/package.json +11 -11
- package/templates/.env.example +6 -12
- package/build/client/_app/immutable/assets/0.BrZX-8-0.css +0 -2
- package/build/client/_app/immutable/assets/0.BrZX-8-0.css.br +0 -0
- package/build/client/_app/immutable/assets/0.BrZX-8-0.css.gz +0 -0
- package/build/client/_app/immutable/assets/21.DNz0YXuf.css +0 -1
- package/build/client/_app/immutable/assets/21.DNz0YXuf.css.br +0 -0
- package/build/client/_app/immutable/assets/21.DNz0YXuf.css.gz +0 -0
- package/build/client/_app/immutable/chunks/1XP9mPh6.js +0 -1
- package/build/client/_app/immutable/chunks/1XP9mPh6.js.br +0 -0
- package/build/client/_app/immutable/chunks/1XP9mPh6.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BPeQB-N1.js +0 -1
- package/build/client/_app/immutable/chunks/BPeQB-N1.js.br +0 -1
- package/build/client/_app/immutable/chunks/BPeQB-N1.js.gz +0 -0
- package/build/client/_app/immutable/chunks/B_-Zu3pc.js +0 -1
- package/build/client/_app/immutable/chunks/B_-Zu3pc.js.br +0 -0
- package/build/client/_app/immutable/chunks/B_-Zu3pc.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CaReqmG-.js +0 -1
- package/build/client/_app/immutable/chunks/CaReqmG-.js.br +0 -0
- package/build/client/_app/immutable/chunks/CaReqmG-.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cd7PUBAe.js +0 -1
- package/build/client/_app/immutable/chunks/Cd7PUBAe.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cd7PUBAe.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cdogoo-J.js +0 -55
- package/build/client/_app/immutable/chunks/Cdogoo-J.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cdogoo-J.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DDIgcaP1.js +0 -1
- package/build/client/_app/immutable/chunks/DDIgcaP1.js.br +0 -2
- package/build/client/_app/immutable/chunks/DDIgcaP1.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DEjZ2Xq_.js +0 -5668
- package/build/client/_app/immutable/chunks/DEjZ2Xq_.js.br +0 -0
- package/build/client/_app/immutable/chunks/DEjZ2Xq_.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DXNhJzNO.js +0 -1
- package/build/client/_app/immutable/chunks/DXNhJzNO.js.br +0 -0
- package/build/client/_app/immutable/chunks/DXNhJzNO.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dr6Ivc7X.js +0 -1
- package/build/client/_app/immutable/chunks/Dr6Ivc7X.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dr6Ivc7X.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Mc0Lifi0.js +0 -1
- package/build/client/_app/immutable/chunks/Mc0Lifi0.js.br +0 -1
- package/build/client/_app/immutable/chunks/Mc0Lifi0.js.gz +0 -0
- package/build/client/_app/immutable/chunks/RLIzEY_h.js +0 -1
- package/build/client/_app/immutable/chunks/RLIzEY_h.js.br +0 -0
- package/build/client/_app/immutable/chunks/RLIzEY_h.js.gz +0 -0
- package/build/client/_app/immutable/chunks/T2IMcJcx.js +0 -2
- package/build/client/_app/immutable/chunks/T2IMcJcx.js.br +0 -0
- package/build/client/_app/immutable/chunks/T2IMcJcx.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Vb6iWNh-.js +0 -1
- package/build/client/_app/immutable/chunks/Vb6iWNh-.js.br +0 -0
- package/build/client/_app/immutable/chunks/Vb6iWNh-.js.gz +0 -0
- package/build/client/_app/immutable/chunks/bpGbYRN6.js +0 -1
- package/build/client/_app/immutable/chunks/bpGbYRN6.js.br +0 -0
- package/build/client/_app/immutable/chunks/bpGbYRN6.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.BxlG4D6v.js +0 -2
- package/build/client/_app/immutable/entry/app.BxlG4D6v.js.br +0 -0
- package/build/client/_app/immutable/entry/app.BxlG4D6v.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BdQOmgbe.js +0 -1
- package/build/client/_app/immutable/entry/start.BdQOmgbe.js.br +0 -1
- package/build/client/_app/immutable/entry/start.BdQOmgbe.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.BnoMaMbT.js +0 -1
- package/build/client/_app/immutable/nodes/1.BnoMaMbT.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.BnoMaMbT.js.gz +0 -0
- package/build/client/_app/immutable/nodes/11.Bf5JPk5c.js +0 -3
- package/build/client/_app/immutable/nodes/11.Bf5JPk5c.js.br +0 -0
- package/build/client/_app/immutable/nodes/11.Bf5JPk5c.js.gz +0 -0
- package/build/client/_app/immutable/nodes/13.8WOI_Rny.js +0 -2
- package/build/client/_app/immutable/nodes/13.8WOI_Rny.js.br +0 -0
- package/build/client/_app/immutable/nodes/13.8WOI_Rny.js.gz +0 -0
- package/build/client/_app/immutable/nodes/14.BIEikz7T.js +0 -2
- package/build/client/_app/immutable/nodes/14.BIEikz7T.js.br +0 -0
- package/build/client/_app/immutable/nodes/14.BIEikz7T.js.gz +0 -0
- package/build/client/_app/immutable/nodes/15.wtJxaZEU.js +0 -28
- package/build/client/_app/immutable/nodes/15.wtJxaZEU.js.br +0 -0
- package/build/client/_app/immutable/nodes/15.wtJxaZEU.js.gz +0 -0
- package/build/client/_app/immutable/nodes/16.DlJ0NfFV.js +0 -5
- package/build/client/_app/immutable/nodes/16.DlJ0NfFV.js.br +0 -0
- package/build/client/_app/immutable/nodes/16.DlJ0NfFV.js.gz +0 -0
- package/build/client/_app/immutable/nodes/17.DoKtyWVA.js +0 -2
- package/build/client/_app/immutable/nodes/17.DoKtyWVA.js.br +0 -0
- package/build/client/_app/immutable/nodes/17.DoKtyWVA.js.gz +0 -0
- package/build/client/_app/immutable/nodes/19.D1GC6b46.js +0 -7
- package/build/client/_app/immutable/nodes/19.D1GC6b46.js.br +0 -0
- package/build/client/_app/immutable/nodes/19.D1GC6b46.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.BoOsgbEN.js +0 -1
- package/build/client/_app/immutable/nodes/2.BoOsgbEN.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.BoOsgbEN.js.gz +0 -0
- package/build/client/_app/immutable/nodes/20.BvEc3BRn.js +0 -2
- package/build/client/_app/immutable/nodes/20.BvEc3BRn.js.br +0 -0
- package/build/client/_app/immutable/nodes/20.BvEc3BRn.js.gz +0 -0
- package/build/client/_app/immutable/nodes/21.CwUymu96.js +0 -1
- package/build/client/_app/immutable/nodes/21.CwUymu96.js.br +0 -0
- package/build/client/_app/immutable/nodes/21.CwUymu96.js.gz +0 -0
- package/build/client/_app/immutable/nodes/22.UiyBrpx4.js +0 -6
- package/build/client/_app/immutable/nodes/22.UiyBrpx4.js.br +0 -0
- package/build/client/_app/immutable/nodes/22.UiyBrpx4.js.gz +0 -0
- package/build/client/_app/immutable/nodes/24.Cf7f4Dk4.js +0 -3
- package/build/client/_app/immutable/nodes/24.Cf7f4Dk4.js.br +0 -0
- package/build/client/_app/immutable/nodes/24.Cf7f4Dk4.js.gz +0 -0
- package/build/client/_app/immutable/nodes/25.BGrOKfHq.js +0 -16
- package/build/client/_app/immutable/nodes/25.BGrOKfHq.js.br +0 -0
- package/build/client/_app/immutable/nodes/25.BGrOKfHq.js.gz +0 -0
- package/build/client/_app/immutable/nodes/26.CXajQRFk.js +0 -6
- package/build/client/_app/immutable/nodes/26.CXajQRFk.js.br +0 -0
- package/build/client/_app/immutable/nodes/26.CXajQRFk.js.gz +0 -0
- package/build/client/_app/immutable/nodes/29.BMMCB4MR.js +0 -4
- package/build/client/_app/immutable/nodes/29.BMMCB4MR.js.br +0 -0
- package/build/client/_app/immutable/nodes/29.BMMCB4MR.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.B5RsIbc5.js +0 -1
- package/build/client/_app/immutable/nodes/3.B5RsIbc5.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.B5RsIbc5.js.gz +0 -0
- package/build/client/_app/immutable/nodes/30.BSbx9NvB.js +0 -6
- package/build/client/_app/immutable/nodes/30.BSbx9NvB.js.br +0 -0
- package/build/client/_app/immutable/nodes/30.BSbx9NvB.js.gz +0 -0
- package/build/client/_app/immutable/nodes/31.CHh6ichW.js +0 -2
- package/build/client/_app/immutable/nodes/31.CHh6ichW.js.br +0 -0
- package/build/client/_app/immutable/nodes/31.CHh6ichW.js.gz +0 -0
- package/build/client/_app/immutable/nodes/32.DYlZfSfy.js +0 -2
- package/build/client/_app/immutable/nodes/32.DYlZfSfy.js.br +0 -0
- package/build/client/_app/immutable/nodes/32.DYlZfSfy.js.gz +0 -0
- package/build/client/_app/immutable/nodes/34.BFmAh534.js +0 -1
- package/build/client/_app/immutable/nodes/34.BFmAh534.js.br +0 -0
- package/build/client/_app/immutable/nodes/34.BFmAh534.js.gz +0 -0
- package/build/client/_app/immutable/nodes/35.DHp9Oq2h.js +0 -2
- package/build/client/_app/immutable/nodes/35.DHp9Oq2h.js.br +0 -0
- package/build/client/_app/immutable/nodes/35.DHp9Oq2h.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.Qz5m15ys.js +0 -1
- package/build/client/_app/immutable/nodes/5.Qz5m15ys.js.br +0 -1
- package/build/client/_app/immutable/nodes/5.Qz5m15ys.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.DHRda_iS.js +0 -1
- package/build/client/_app/immutable/nodes/6.DHRda_iS.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.DHRda_iS.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.CtyhQ_s_.js +0 -1
- package/build/client/_app/immutable/nodes/7.CtyhQ_s_.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.CtyhQ_s_.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.BVv9Nt3U.js +0 -3
- package/build/client/_app/immutable/nodes/8.BVv9Nt3U.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.BVv9Nt3U.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.B5FjGjtL.js +0 -1
- package/build/client/_app/immutable/nodes/9.B5FjGjtL.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.B5FjGjtL.js.gz +0 -0
- package/build/server/chunks/chunks/AppHeader.js-C6ROq5Qm.js +0 -315
- package/build/server/chunks/chunks/AppHeader.js-C6ROq5Qm.js.map +0 -1
- package/build/server/chunks/chunks/Callout.js-Ci3u4XSa.js +0 -57
- package/build/server/chunks/chunks/Callout.js-Ci3u4XSa.js.map +0 -1
- package/build/server/chunks/chunks/ConfirmDialog.js-BhGAyH1N.js +0 -151
- package/build/server/chunks/chunks/ConfirmDialog.js-BhGAyH1N.js.map +0 -1
- package/build/server/chunks/chunks/DataTable.js-1FokYGvY.js +0 -33
- package/build/server/chunks/chunks/DataTable.js-1FokYGvY.js.map +0 -1
- package/build/server/chunks/chunks/DefinitionCard.js-DkODwwms.js +0 -141
- package/build/server/chunks/chunks/DefinitionCard.js-DkODwwms.js.map +0 -1
- package/build/server/chunks/chunks/EmptyState.js-db0SQWDN.js +0 -36
- package/build/server/chunks/chunks/EmptyState.js-db0SQWDN.js.map +0 -1
- package/build/server/chunks/chunks/ErrorScreen.js-B0rqpGyR.js +0 -116
- package/build/server/chunks/chunks/ErrorScreen.js-B0rqpGyR.js.map +0 -1
- package/build/server/chunks/chunks/FilterableDropdown.js-B4nYR1Mw.js +0 -2722
- package/build/server/chunks/chunks/FilterableDropdown.js-B4nYR1Mw.js.map +0 -1
- package/build/server/chunks/chunks/PageContent.js-CtU1_JG7.js +0 -12
- package/build/server/chunks/chunks/PageContent.js-CtU1_JG7.js.map +0 -1
- package/build/server/chunks/chunks/SectionHeader.js-CjW0_0vg.js +0 -22
- package/build/server/chunks/chunks/SectionHeader.js-CjW0_0vg.js.map +0 -1
- package/build/server/chunks/chunks/SettingsMenu.js-CjM22Nav.js +0 -2642
- package/build/server/chunks/chunks/SettingsMenu.js-CjM22Nav.js.map +0 -1
- package/build/server/chunks/chunks/SideNav.js-B-U6drKT.js +0 -194
- package/build/server/chunks/chunks/SideNav.js-B-U6drKT.js.map +0 -1
- package/build/server/chunks/chunks/StatCard.js-CN5-wy2A.js +0 -52
- package/build/server/chunks/chunks/StatCard.js-CN5-wy2A.js.map +0 -1
- package/build/server/chunks/chunks/UserAvatar.js-RJK9KiIw.js +0 -14
- package/build/server/chunks/chunks/UserAvatar.js-RJK9KiIw.js.map +0 -1
- package/build/server/chunks/chunks/UserRowIdentity.js-ovE6ITKg.js +0 -112
- package/build/server/chunks/chunks/UserRowIdentity.js-ovE6ITKg.js.map +0 -1
- package/build/server/chunks/chunks/ViewToggle.js-CaamGGXn.js +0 -138
- package/build/server/chunks/chunks/ViewToggle.js-CaamGGXn.js.map +0 -1
- package/build/server/chunks/chunks/access.js-DbWaEG7Y.js +0 -804
- package/build/server/chunks/chunks/access.js-DbWaEG7Y.js.map +0 -1
- package/build/server/chunks/chunks/access.server.js-DyEho9RH.js +0 -15
- package/build/server/chunks/chunks/access.server.js-DyEho9RH.js.map +0 -1
- package/build/server/chunks/chunks/access2.server.js-CGK2l9hh.js +0 -63
- package/build/server/chunks/chunks/access2.server.js-CGK2l9hh.js.map +0 -1
- package/build/server/chunks/chunks/activity.js-Cq5CR0qS.js +0 -17
- package/build/server/chunks/chunks/activity.js-Cq5CR0qS.js.map +0 -1
- package/build/server/chunks/chunks/admin-auth.server.js-Df9QJc2P.js +0 -352
- package/build/server/chunks/chunks/admin-auth.server.js-Df9QJc2P.js.map +0 -1
- package/build/server/chunks/chunks/alert-dialog.js-BC5IIsYS.js +0 -461
- package/build/server/chunks/chunks/alert-dialog.js-BC5IIsYS.js.map +0 -1
- package/build/server/chunks/chunks/api-errors.js-Byazqvy4.js +0 -57
- package/build/server/chunks/chunks/api-errors.js-Byazqvy4.js.map +0 -1
- package/build/server/chunks/chunks/api.js-CWQeuHWw.js +0 -1165
- package/build/server/chunks/chunks/api.js-CWQeuHWw.js.map +0 -1
- package/build/server/chunks/chunks/arrow-left.js-DXlCPnHO.js +0 -17
- package/build/server/chunks/chunks/arrow-left.js-DXlCPnHO.js.map +0 -1
- package/build/server/chunks/chunks/arrow-right.js-CGAfq_wi.js +0 -17
- package/build/server/chunks/chunks/arrow-right.js-CGAfq_wi.js.map +0 -1
- package/build/server/chunks/chunks/auth-bootstrap.server.js-MKkcsRfh.js +0 -152
- package/build/server/chunks/chunks/auth-bootstrap.server.js-MKkcsRfh.js.map +0 -1
- package/build/server/chunks/chunks/badge.js-DVfiDfVJ.js +0 -35
- package/build/server/chunks/chunks/badge.js-DVfiDfVJ.js.map +0 -1
- package/build/server/chunks/chunks/bootHealth.server.js-C87XV-z4.js +0 -90
- package/build/server/chunks/chunks/bootHealth.server.js-C87XV-z4.js.map +0 -1
- package/build/server/chunks/chunks/building-complex.js-JHR0jolW.js +0 -24
- package/build/server/chunks/chunks/building-complex.js-JHR0jolW.js.map +0 -1
- package/build/server/chunks/chunks/button.js-DKfs3Boy.js +0 -71
- package/build/server/chunks/chunks/button.js-DKfs3Boy.js.map +0 -1
- package/build/server/chunks/chunks/card-content.js-CBUsYBjk.js +0 -20
- package/build/server/chunks/chunks/card-content.js-CBUsYBjk.js.map +0 -1
- package/build/server/chunks/chunks/card-description.js-BOcmCPPd.js +0 -20
- package/build/server/chunks/chunks/card-description.js-BOcmCPPd.js.map +0 -1
- package/build/server/chunks/chunks/card-header.js-m0c0MMMI.js +0 -20
- package/build/server/chunks/chunks/card-header.js-m0c0MMMI.js.map +0 -1
- package/build/server/chunks/chunks/card-title.js-BolYlULC.js +0 -20
- package/build/server/chunks/chunks/card-title.js-BolYlULC.js.map +0 -1
- package/build/server/chunks/chunks/card.js-B4rH_m-Y.js +0 -29
- package/build/server/chunks/chunks/card.js-B4rH_m-Y.js.map +0 -1
- package/build/server/chunks/chunks/chevron-down.js-DFG8JZ5a.js +0 -17
- package/build/server/chunks/chunks/chevron-down.js-DFG8JZ5a.js.map +0 -1
- package/build/server/chunks/chunks/chevron-left.js-D9wIzL7j.js +0 -17
- package/build/server/chunks/chunks/chevron-left.js-D9wIzL7j.js.map +0 -1
- package/build/server/chunks/chunks/chevron-right.js-BKtNlHM6.js +0 -17
- package/build/server/chunks/chunks/chevron-right.js-BKtNlHM6.js.map +0 -1
- package/build/server/chunks/chunks/chevron-up.js-Cd-VfN2m.js +0 -17
- package/build/server/chunks/chunks/chevron-up.js-Cd-VfN2m.js.map +0 -1
- package/build/server/chunks/chunks/circle.js-BF319LN2.js +0 -21
- package/build/server/chunks/chunks/circle.js-BF319LN2.js.map +0 -1
- package/build/server/chunks/chunks/client.js-D26R0bt6.js +0 -58
- package/build/server/chunks/chunks/client.js-D26R0bt6.js.map +0 -1
- package/build/server/chunks/chunks/compute.js-srroNvr-.js +0 -501
- package/build/server/chunks/chunks/compute.js-srroNvr-.js.map +0 -1
- package/build/server/chunks/chunks/computeLimits.js-CQyJFKqu.js +0 -44
- package/build/server/chunks/chunks/computeLimits.js-CQyJFKqu.js.map +0 -1
- package/build/server/chunks/chunks/computeRateLimit.server.js-DnvPu8b5.js +0 -31
- package/build/server/chunks/chunks/computeRateLimit.server.js-DnvPu8b5.js.map +0 -1
- package/build/server/chunks/chunks/copy.js-CX74BNXO.js +0 -24
- package/build/server/chunks/chunks/copy.js-CX74BNXO.js.map +0 -1
- package/build/server/chunks/chunks/create-id.js-DyutBmRB.js +0 -795
- package/build/server/chunks/chunks/create-id.js-DyutBmRB.js.map +0 -1
- package/build/server/chunks/chunks/definitions.js-B_LZcC8G.js +0 -387
- package/build/server/chunks/chunks/definitions.js-B_LZcC8G.js.map +0 -1
- package/build/server/chunks/chunks/dialog-description.js-BNCA58Uf.js +0 -489
- package/build/server/chunks/chunks/dialog-description.js-BNCA58Uf.js.map +0 -1
- package/build/server/chunks/chunks/dialog.js-KzUC_lV4.js +0 -360
- package/build/server/chunks/chunks/dialog.js-KzUC_lV4.js.map +0 -1
- package/build/server/chunks/chunks/dom-typeahead.svelte.js-CIQZpPMg.js +0 -211
- package/build/server/chunks/chunks/dom-typeahead.svelte.js-CIQZpPMg.js.map +0 -1
- package/build/server/chunks/chunks/engine.server.js-BaQbE4CG.js +0 -584
- package/build/server/chunks/chunks/engine.server.js-BaQbE4CG.js.map +0 -1
- package/build/server/chunks/chunks/esm.js-CVe0D3tO.js +0 -7
- package/build/server/chunks/chunks/esm.js-CVe0D3tO.js.map +0 -1
- package/build/server/chunks/chunks/esm2.js-CJwXaTbP.js +0 -987
- package/build/server/chunks/chunks/esm2.js-CJwXaTbP.js.map +0 -1
- package/build/server/chunks/chunks/events.js-BD_zKIav.js +0 -136
- package/build/server/chunks/chunks/events.js-BD_zKIav.js.map +0 -1
- package/build/server/chunks/chunks/evict-changed-servers.js-Dw8HdMyj.js +0 -18
- package/build/server/chunks/chunks/evict-changed-servers.js-Dw8HdMyj.js.map +0 -1
- package/build/server/chunks/chunks/exports.js-Bl7JH3d7.js +0 -149
- package/build/server/chunks/chunks/exports.js-Bl7JH3d7.js.map +0 -1
- package/build/server/chunks/chunks/external-link.js-CDKacmCr.js +0 -21
- package/build/server/chunks/chunks/external-link.js-CDKacmCr.js.map +0 -1
- package/build/server/chunks/chunks/folder-kanban.js-JM2vWrBr.js +0 -22
- package/build/server/chunks/chunks/folder-kanban.js-JM2vWrBr.js.map +0 -1
- package/build/server/chunks/chunks/folder-open.js-DZAgByKM.js +0 -17
- package/build/server/chunks/chunks/folder-open.js-DZAgByKM.js.map +0 -1
- package/build/server/chunks/chunks/folders.js-L-79cuap.js +0 -17
- package/build/server/chunks/chunks/folders.js-L-79cuap.js.map +0 -1
- package/build/server/chunks/chunks/footerContext.svelte.js-DZauzsZK.js +0 -680
- package/build/server/chunks/chunks/footerContext.svelte.js-DZauzsZK.js.map +0 -1
- package/build/server/chunks/chunks/forms.js-CCPK1Yl5.js +0 -2
- package/build/server/chunks/chunks/forms.js-CCPK1Yl5.js.map +0 -1
- package/build/server/chunks/chunks/gauge.js-ByoSKYeR.js +0 -17
- package/build/server/chunks/chunks/gauge.js-ByoSKYeR.js.map +0 -1
- package/build/server/chunks/chunks/grasshopper.js-CdYz2gPd.js +0 -2655
- package/build/server/chunks/chunks/grasshopper.js-CdYz2gPd.js.map +0 -1
- package/build/server/chunks/chunks/handlers.js-BpDAlScc.js +0 -1590
- package/build/server/chunks/chunks/handlers.js-BpDAlScc.js.map +0 -1
- package/build/server/chunks/chunks/http.js-BNvBCntZ.js +0 -60
- package/build/server/chunks/chunks/http.js-BNvBCntZ.js.map +0 -1
- package/build/server/chunks/chunks/index-server.js-DQcI4Uf0.js +0 -154
- package/build/server/chunks/chunks/index-server.js-DQcI4Uf0.js.map +0 -1
- package/build/server/chunks/chunks/input-group.js-CvIv_pYF.js +0 -65
- package/build/server/chunks/chunks/input-group.js-CvIv_pYF.js.map +0 -1
- package/build/server/chunks/chunks/input.js-BmyEYEb_.js +0 -31
- package/build/server/chunks/chunks/input.js-BmyEYEb_.js.map +0 -1
- package/build/server/chunks/chunks/instanceAdmins.server.js-DxkF1Z8y.js +0 -24
- package/build/server/chunks/chunks/instanceAdmins.server.js-DxkF1Z8y.js.map +0 -1
- package/build/server/chunks/chunks/internal.js-BFfHHam5.js +0 -27
- package/build/server/chunks/chunks/internal.js-BFfHHam5.js.map +0 -1
- package/build/server/chunks/chunks/internal2.js-Dx1x8Dv4.js +0 -219
- package/build/server/chunks/chunks/internal2.js-Dx1x8Dv4.js.map +0 -1
- package/build/server/chunks/chunks/key-round.js-30Lmuz0K.js +0 -22
- package/build/server/chunks/chunks/key-round.js-30Lmuz0K.js.map +0 -1
- package/build/server/chunks/chunks/label.js-yA32z5eG.js +0 -105
- package/build/server/chunks/chunks/label.js-yA32z5eG.js.map +0 -1
- package/build/server/chunks/chunks/legacy-client.js-C_nl-7NA.js +0 -771
- package/build/server/chunks/chunks/legacy-client.js-C_nl-7NA.js.map +0 -1
- package/build/server/chunks/chunks/link-2.js-BqFCdaAg.js +0 -26
- package/build/server/chunks/chunks/link-2.js-BqFCdaAg.js.map +0 -1
- package/build/server/chunks/chunks/liveSolve.server.js-DpRBaHA5.js +0 -70
- package/build/server/chunks/chunks/liveSolve.server.js-DpRBaHA5.js.map +0 -1
- package/build/server/chunks/chunks/localeContext.svelte.js-Ci_EHhgS.js +0 -410
- package/build/server/chunks/chunks/localeContext.svelte.js-Ci_EHhgS.js.map +0 -1
- package/build/server/chunks/chunks/mail.js-C4TGUsgv.js +0 -23
- package/build/server/chunks/chunks/mail.js-C4TGUsgv.js.map +0 -1
- package/build/server/chunks/chunks/minus.js-CoYdbRTv.js +0 -17
- package/build/server/chunks/chunks/minus.js-CoYdbRTv.js.map +0 -1
- package/build/server/chunks/chunks/navigation.js-CCPK1Yl5.js +0 -2
- package/build/server/chunks/chunks/navigation.js-CCPK1Yl5.js.map +0 -1
- package/build/server/chunks/chunks/oauth.js-WZFWOYa1.js +0 -415
- package/build/server/chunks/chunks/oauth.js-WZFWOYa1.js.map +0 -1
- package/build/server/chunks/chunks/oauthState.server.js-DXP7KiF3.js +0 -53
- package/build/server/chunks/chunks/oauthState.server.js-DXP7KiF3.js.map +0 -1
- package/build/server/chunks/chunks/openapi.js-g360-BRe.js +0 -61
- package/build/server/chunks/chunks/openapi.js-g360-BRe.js.map +0 -1
- package/build/server/chunks/chunks/outcome-BOrAeRAQ.js-DpkjLw3I.js +0 -77
- package/build/server/chunks/chunks/outcome-BOrAeRAQ.js-DpkjLw3I.js.map +0 -1
- package/build/server/chunks/chunks/package.js-B8ojgJpE.js +0 -85
- package/build/server/chunks/chunks/package.js-B8ojgJpE.js.map +0 -1
- package/build/server/chunks/chunks/paths.js-KeZkYLzj.js +0 -19
- package/build/server/chunks/chunks/paths.js-KeZkYLzj.js.map +0 -1
- package/build/server/chunks/chunks/permissions.server.js-B5seqY1O.js +0 -24
- package/build/server/chunks/chunks/permissions.server.js-B5seqY1O.js.map +0 -1
- package/build/server/chunks/chunks/plus.js-DIp8WjjL.js +0 -17
- package/build/server/chunks/chunks/plus.js-DIp8WjjL.js.map +0 -1
- package/build/server/chunks/chunks/popper-layer-force-mount.js-B_6OYm07.js +0 -1907
- package/build/server/chunks/chunks/popper-layer-force-mount.js-B_6OYm07.js.map +0 -1
- package/build/server/chunks/chunks/presets.server.js-DvBaWEr5.js +0 -21
- package/build/server/chunks/chunks/presets.server.js-DvBaWEr5.js.map +0 -1
- package/build/server/chunks/chunks/projects.js-D6fN9oey.js +0 -47
- package/build/server/chunks/chunks/projects.js-D6fN9oey.js.map +0 -1
- package/build/server/chunks/chunks/providers.server.js-DbrdtkJK.js +0 -6337
- package/build/server/chunks/chunks/providers.server.js-DbrdtkJK.js.map +0 -1
- package/build/server/chunks/chunks/randomId.js-dgVOFSi4.js +0 -22
- package/build/server/chunks/chunks/randomId.js-dgVOFSi4.js.map +0 -1
- package/build/server/chunks/chunks/redirect.js-oP6lj4tJ.js +0 -15
- package/build/server/chunks/chunks/redirect.js-oP6lj4tJ.js.map +0 -1
- package/build/server/chunks/chunks/refresh-cw.js-7jhDx15C.js +0 -22
- package/build/server/chunks/chunks/refresh-cw.js-7jhDx15C.js.map +0 -1
- package/build/server/chunks/chunks/registry.js-C2zKBHg3.js +0 -656
- package/build/server/chunks/chunks/registry.js-C2zKBHg3.js.map +0 -1
- package/build/server/chunks/chunks/request-context.js-BlxaBgml.js +0 -28
- package/build/server/chunks/chunks/request-context.js-BlxaBgml.js.map +0 -1
- package/build/server/chunks/chunks/resolve.server.js-B04dvujb.js +0 -59
- package/build/server/chunks/chunks/resolve.server.js-B04dvujb.js.map +0 -1
- package/build/server/chunks/chunks/rotate-ccw.js--ALnMG6X.js +0 -17
- package/build/server/chunks/chunks/rotate-ccw.js--ALnMG6X.js.map +0 -1
- package/build/server/chunks/chunks/routing.js-jOE0ETFb.js +0 -264
- package/build/server/chunks/chunks/routing.js-jOE0ETFb.js.map +0 -1
- package/build/server/chunks/chunks/roving-focus-group.js-D-_tnELv.js +0 -158
- package/build/server/chunks/chunks/roving-focus-group.js-D-_tnELv.js.map +0 -1
- package/build/server/chunks/chunks/schema-extraction.js-DxFeK69H.js +0 -141
- package/build/server/chunks/chunks/schema-extraction.js-DxFeK69H.js.map +0 -1
- package/build/server/chunks/chunks/scroll-lock.js-C7gtgy_s.js +0 -1956
- package/build/server/chunks/chunks/scroll-lock.js-C7gtgy_s.js.map +0 -1
- package/build/server/chunks/chunks/scroll-text.js-DzkCYNV2.js +0 -22
- package/build/server/chunks/chunks/scroll-text.js-DzkCYNV2.js.map +0 -1
- package/build/server/chunks/chunks/search.js-DAtjxvTA.js +0 -21
- package/build/server/chunks/chunks/search.js-DAtjxvTA.js.map +0 -1
- package/build/server/chunks/chunks/select.js-IP6mtWOr.js +0 -1756
- package/build/server/chunks/chunks/select.js-IP6mtWOr.js.map +0 -1
- package/build/server/chunks/chunks/selfUpdate.server.js-DDD13rVB.js +0 -144
- package/build/server/chunks/chunks/selfUpdate.server.js-DDD13rVB.js.map +0 -1
- package/build/server/chunks/chunks/separator.js-Bh3r_kbL.js +0 -187
- package/build/server/chunks/chunks/separator.js-Bh3r_kbL.js.map +0 -1
- package/build/server/chunks/chunks/server.js-Bn3s-cVB.js +0 -3921
- package/build/server/chunks/chunks/server.js-Bn3s-cVB.js.map +0 -1
- package/build/server/chunks/chunks/server2.js-BvOT__v3.js +0 -103
- package/build/server/chunks/chunks/server2.js-BvOT__v3.js.map +0 -1
- package/build/server/chunks/chunks/server3.js-Zec4zH4z.js +0 -20753
- package/build/server/chunks/chunks/server3.js-Zec4zH4z.js.map +0 -1
- package/build/server/chunks/chunks/server4.js-CP6bBl1P.js +0 -46
- package/build/server/chunks/chunks/server4.js-CP6bBl1P.js.map +0 -1
- package/build/server/chunks/chunks/severity.js-yRcFOGQ7.js +0 -117
- package/build/server/chunks/chunks/severity.js-yRcFOGQ7.js.map +0 -1
- package/build/server/chunks/chunks/shared-server.js-CJsQadj4.js +0 -22
- package/build/server/chunks/chunks/shared-server.js-CJsQadj4.js.map +0 -1
- package/build/server/chunks/chunks/shared.js-BT6FYGEZ.js +0 -709
- package/build/server/chunks/chunks/shared.js-BT6FYGEZ.js.map +0 -1
- package/build/server/chunks/chunks/shared2.js-BFuk6QhH.js +0 -88
- package/build/server/chunks/chunks/shared2.js-BFuk6QhH.js.map +0 -1
- package/build/server/chunks/chunks/shield-check.js-D7xC3rmX.js +0 -17
- package/build/server/chunks/chunks/shield-check.js-D7xC3rmX.js.map +0 -1
- package/build/server/chunks/chunks/shield.js-LckTyJGe.js +0 -17
- package/build/server/chunks/chunks/shield.js-LckTyJGe.js.map +0 -1
- package/build/server/chunks/chunks/solve.server.js-DvmmuTYF.js +0 -315
- package/build/server/chunks/chunks/solve.server.js-DvmmuTYF.js.map +0 -1
- package/build/server/chunks/chunks/sr-only-styles.js-Drt1VGf2.js +0 -19
- package/build/server/chunks/chunks/sr-only-styles.js-Drt1VGf2.js.map +0 -1
- package/build/server/chunks/chunks/src.js-BQFsdJf3.js +0 -518
- package/build/server/chunks/chunks/src.js-BQFsdJf3.js.map +0 -1
- package/build/server/chunks/chunks/star.js-CJspSS5m.js +0 -17
- package/build/server/chunks/chunks/star.js-CJspSS5m.js.map +0 -1
- package/build/server/chunks/chunks/state.js-DaNGuhKE.js +0 -74
- package/build/server/chunks/chunks/state.js-DaNGuhKE.js.map +0 -1
- package/build/server/chunks/chunks/stores.js-BAFlDJra.js +0 -35
- package/build/server/chunks/chunks/stores.js-BAFlDJra.js.map +0 -1
- package/build/server/chunks/chunks/sveltekit.js-CwkcUXXi.js +0 -102
- package/build/server/chunks/chunks/sveltekit.js-CwkcUXXi.js.map +0 -1
- package/build/server/chunks/chunks/tabs-trigger.js-C5zvXOhB.js +0 -520
- package/build/server/chunks/chunks/tabs-trigger.js-C5zvXOhB.js.map +0 -1
- package/build/server/chunks/chunks/toast-state.svelte.js-CzgVAa8I.js +0 -284
- package/build/server/chunks/chunks/toast-state.svelte.js-CzgVAa8I.js.map +0 -1
- package/build/server/chunks/chunks/toggle-group-item.js-lgtVgqs5.js +0 -400
- package/build/server/chunks/chunks/toggle-group-item.js-lgtVgqs5.js.map +0 -1
- package/build/server/chunks/chunks/token.server.js-9F6kDRtE.js +0 -131
- package/build/server/chunks/chunks/token.server.js-9F6kDRtE.js.map +0 -1
- package/build/server/chunks/chunks/token2.server.js-Dv9oGmUn.js +0 -50
- package/build/server/chunks/chunks/token2.server.js-Dv9oGmUn.js.map +0 -1
- package/build/server/chunks/chunks/token3.server.js-CHgzJAXs.js +0 -41
- package/build/server/chunks/chunks/token3.server.js-CHgzJAXs.js.map +0 -1
- package/build/server/chunks/chunks/token4.server.js-2COCjTDd.js +0 -24
- package/build/server/chunks/chunks/token4.server.js-2COCjTDd.js.map +0 -1
- package/build/server/chunks/chunks/tokens.js-C1iFCpCz.js +0 -25
- package/build/server/chunks/chunks/tokens.js-C1iFCpCz.js.map +0 -1
- package/build/server/chunks/chunks/trash.js-D6PEuXeo.js +0 -24
- package/build/server/chunks/chunks/trash.js-D6PEuXeo.js.map +0 -1
- package/build/server/chunks/chunks/types.js-C7gj_Qvn.js +0 -10
- package/build/server/chunks/chunks/types.js-C7gj_Qvn.js.map +0 -1
- package/build/server/chunks/chunks/updateCheck.server.js-D9givfAy.js +0 -203
- package/build/server/chunks/chunks/updateCheck.server.js-D9givfAy.js.map +0 -1
- package/build/server/chunks/chunks/user-plus.js-D8wR6i9h.js +0 -36
- package/build/server/chunks/chunks/user-plus.js-D8wR6i9h.js.map +0 -1
- package/build/server/chunks/chunks/users.js-CrOt_3Af.js +0 -26
- package/build/server/chunks/chunks/users.js-CrOt_3Af.js.map +0 -1
- package/build/server/chunks/chunks/utils.js-CdicmAy3.js +0 -745
- package/build/server/chunks/chunks/utils.js-CdicmAy3.js.map +0 -1
- package/build/server/chunks/chunks/utils2.js-BMDNJPPH.js +0 -174
- package/build/server/chunks/chunks/utils2.js-BMDNJPPH.js.map +0 -1
- package/build/server/chunks/chunks/visibility.js-DHIz9MAP.js +0 -198
- package/build/server/chunks/chunks/visibility.js-DHIz9MAP.js.map +0 -1
- package/build/server/chunks/chunks/x.js-CUMpi5o0.js +0 -17
- package/build/server/chunks/chunks/x.js-CUMpi5o0.js.map +0 -1
- package/build/server/chunks/entries/endpoints/.well-known/oauth-authorization-server/_server.ts.js-BxOaGAKh.js +0 -18
- package/build/server/chunks/entries/endpoints/.well-known/oauth-authorization-server/_server.ts.js-BxOaGAKh.js.map +0 -1
- package/build/server/chunks/entries/endpoints/.well-known/oauth-protected-resource/_server.ts.js-DIxEFeXu.js +0 -18
- package/build/server/chunks/entries/endpoints/.well-known/oauth-protected-resource/_server.ts.js-DIxEFeXu.js.map +0 -1
- package/build/server/chunks/entries/endpoints/.well-known/oauth-protected-resource/mcp/_server.ts.js-1kMLbj9B.js +0 -18
- package/build/server/chunks/entries/endpoints/.well-known/oauth-protected-resource/mcp/_server.ts.js-1kMLbj9B.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/compute/_server.ts.js-DCscdvEV.js +0 -98
- package/build/server/chunks/entries/endpoints/api/admin/compute/_server.ts.js-DCscdvEV.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/compute/actions/_server.ts.js-0Mj_mcJt.js +0 -87
- package/build/server/chunks/entries/endpoints/api/admin/compute/actions/_server.ts.js-0Mj_mcJt.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/compute/status/_server.ts.js-DLYgk9sQ.js +0 -98
- package/build/server/chunks/entries/endpoints/api/admin/compute/status/_server.ts.js-DLYgk9sQ.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/orgs/_id_/_server.ts.js-wP88tWFd.js +0 -47
- package/build/server/chunks/entries/endpoints/api/admin/orgs/_id_/_server.ts.js-wP88tWFd.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/orgs/_server.ts.js-DigenazL.js +0 -70
- package/build/server/chunks/entries/endpoints/api/admin/orgs/_server.ts.js-DigenazL.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/_server.ts.js-DIh4cPwS.js +0 -63
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/_server.ts.js-DIh4cPwS.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/grants/_grantId_/_server.ts.js-llcZQfj0.js +0 -35
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/grants/_grantId_/_server.ts.js-llcZQfj0.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/grants/_server.ts.js-C3mOC3fF.js +0 -66
- package/build/server/chunks/entries/endpoints/api/admin/projects/_id_/grants/_server.ts.js-C3mOC3fF.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/projects/_server.ts.js-C-MftkJL.js +0 -81
- package/build/server/chunks/entries/endpoints/api/admin/projects/_server.ts.js-C-MftkJL.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/system/health/_server.ts.js-Bs5H8axR.js +0 -366
- package/build/server/chunks/entries/endpoints/api/admin/system/health/_server.ts.js-Bs5H8axR.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/system/throughput/_server.ts.js-Bah8G82h.js +0 -87
- package/build/server/chunks/entries/endpoints/api/admin/system/throughput/_server.ts.js-Bah8G82h.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/system/update/_server.ts.js-Dteez7Cv.js +0 -610
- package/build/server/chunks/entries/endpoints/api/admin/system/update/_server.ts.js-Dteez7Cv.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/users/_id_/_server.ts.js-ClKfsbNv.js +0 -59
- package/build/server/chunks/entries/endpoints/api/admin/users/_id_/_server.ts.js-ClKfsbNv.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/users/_id_/disable/_server.ts.js-CQqSb0fT.js +0 -77
- package/build/server/chunks/entries/endpoints/api/admin/users/_id_/disable/_server.ts.js-CQqSb0fT.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/admin/users/_server.ts.js-o-X8J9FJ.js +0 -84
- package/build/server/chunks/entries/endpoints/api/admin/users/_server.ts.js-o-X8J9FJ.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/diag/throughput/_server.ts.js-3RODCsN1.js +0 -64
- package/build/server/chunks/entries/endpoints/api/diag/throughput/_server.ts.js-3RODCsN1.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/files/_...path_/_server.ts.js-DcpGuVwa.js +0 -95
- package/build/server/chunks/entries/endpoints/api/files/_...path_/_server.ts.js-DcpGuVwa.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/health/_server.ts.js-BU-ZKLU7.js +0 -62
- package/build/server/chunks/entries/endpoints/api/health/_server.ts.js-BU-ZKLU7.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/health/ready/_server.ts.js-h7cVEhJP.js +0 -65
- package/build/server/chunks/entries/endpoints/api/health/ready/_server.ts.js-h7cVEhJP.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/compute/_server.ts.js-D1ku_J7c.js +0 -94
- package/build/server/chunks/entries/endpoints/api/v1/compute/_server.ts.js-D1ku_J7c.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/compute/schema/_server.ts.js-ChQW_QNl.js +0 -79
- package/build/server/chunks/entries/endpoints/api/v1/compute/schema/_server.ts.js-ChQW_QNl.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/_server.ts.js-BKePykE0.js +0 -49
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/_server.ts.js-BKePykE0.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/image/_server.ts.js-CHG-ElNV.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/image/_server.ts.js-CHG-ElNV.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/publish/_server.ts.js-X-qJvWpy.js +0 -50
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/publish/_server.ts.js-X-qJvWpy.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/schema/_server.ts.js-Cp5s2PJY.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/schema/_server.ts.js-Cp5s2PJY.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/share-links/_linkId_/_server.ts.js-NPTY3bc-.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/share-links/_linkId_/_server.ts.js-NPTY3bc-.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/share-links/_server.ts.js-9KOm0qBe.js +0 -51
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/share-links/_server.ts.js-9KOm0qBe.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/solve/_server.ts.js-B6xk07be.js +0 -98
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/solve/_server.ts.js-B6xk07be.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_server.ts.js-B4Q3VhGH.js +0 -52
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_server.ts.js-B4Q3VhGH.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_versionId_/_server.ts.js-BYdFz8uv.js +0 -48
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_versionId_/_server.ts.js-BYdFz8uv.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_versionId_/schema/_server.ts.js-ClkMh71D.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_guid_/versions/_versionId_/schema/_server.ts.js-ClkMh71D.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_server.ts.js-CQ7MWiDU.js +0 -50
- package/build/server/chunks/entries/endpoints/api/v1/definitions/_server.ts.js-CQ7MWiDU.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/me/_server.ts.js-UFnJTA69.js +0 -46
- package/build/server/chunks/entries/endpoints/api/v1/me/_server.ts.js-UFnJTA69.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/me/starred/_guid_/_server.ts.js-DEi4iWdw.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/me/starred/_guid_/_server.ts.js-DEi4iWdw.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/me/token/_server.ts.js-v3-TzqWz.js +0 -46
- package/build/server/chunks/entries/endpoints/api/v1/me/token/_server.ts.js-v3-TzqWz.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/openapi.json/_server.ts.js-BQaOmPav.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/openapi.json/_server.ts.js-BQaOmPav.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/_server.ts.js-hbeX5VQf.js +0 -46
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/_server.ts.js-hbeX5VQf.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/assets/_kind_/_server.ts.js-Ho6gZUbD.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/assets/_kind_/_server.ts.js-Ho6gZUbD.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/compute/_server.ts.js-R9DF-QVO.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/compute/_server.ts.js-R9DF-QVO.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_id_/_server.ts.js-J_7u9_KN.js +0 -46
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_id_/_server.ts.js-J_7u9_KN.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_id_/resend/_server.ts.js-Dsqk-mkR.js +0 -46
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_id_/resend/_server.ts.js-Dsqk-mkR.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_server.ts.js-BmGEfDxn.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/invites/_server.ts.js-BmGEfDxn.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/members/_server.ts.js-CIuO-a_b.js +0 -46
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/members/_server.ts.js-CIuO-a_b.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/members/_userId_/_server.ts.js-DlFtEkDG.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/members/_userId_/_server.ts.js-DlFtEkDG.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/tokens/_server.ts.js-BFgCmiOg.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/tokens/_server.ts.js-BFgCmiOg.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/tokens/_tokenId_/_server.ts.js-DVZxyTje.js +0 -46
- package/build/server/chunks/entries/endpoints/api/v1/orgs/_orgId_/tokens/_tokenId_/_server.ts.js-DVZxyTje.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/_server.ts.js-C_SQsTm4.js +0 -49
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/_server.ts.js-C_SQsTm4.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/members/_server.ts.js-7n3xjWS8.js +0 -48
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/members/_server.ts.js-7n3xjWS8.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/members/_userId_/_server.ts.js-DtD7ztOa.js +0 -48
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/members/_userId_/_server.ts.js-DtD7ztOa.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/reclaim/_server.ts.js-DU1zIks1.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/projects/_id_/reclaim/_server.ts.js-DU1zIks1.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/projects/_server.ts.js-CZp_uEF7.js +0 -47
- package/build/server/chunks/entries/endpoints/api/v1/projects/_server.ts.js-CZp_uEF7.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/solve/_solveId_/cancel/_server.ts.js-18Z61Qvh.js +0 -49
- package/build/server/chunks/entries/endpoints/api/v1/solve/_solveId_/cancel/_server.ts.js-18Z61Qvh.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/solve-events/_server.ts.js-Sv3CtyRZ.js +0 -109
- package/build/server/chunks/entries/endpoints/api/v1/solve-events/_server.ts.js-Sv3CtyRZ.js.map +0 -1
- package/build/server/chunks/entries/endpoints/api/v1/solve-events/_solveId_/_server.ts.js-COl6nqRv.js +0 -67
- package/build/server/chunks/entries/endpoints/api/v1/solve-events/_solveId_/_server.ts.js-COl6nqRv.js.map +0 -1
- package/build/server/chunks/entries/endpoints/auth/email/callback/_server.ts.js-BIQtmwhS.js +0 -55
- package/build/server/chunks/entries/endpoints/auth/email/callback/_server.ts.js-BIQtmwhS.js.map +0 -1
- package/build/server/chunks/entries/endpoints/auth/supabase/callback/_server.ts.js-zOe_S-al.js +0 -61
- package/build/server/chunks/entries/endpoints/auth/supabase/callback/_server.ts.js-zOe_S-al.js.map +0 -1
- package/build/server/chunks/entries/endpoints/auth/supabase/start/_server.ts.js-6-slNAw_.js +0 -66
- package/build/server/chunks/entries/endpoints/auth/supabase/start/_server.ts.js-6-slNAw_.js.map +0 -1
- package/build/server/chunks/entries/endpoints/mcp/_server.ts.js-DKNjGBRy.js +0 -28
- package/build/server/chunks/entries/endpoints/mcp/_server.ts.js-DKNjGBRy.js.map +0 -1
- package/build/server/chunks/entries/endpoints/oauth/register/_server.ts.js-S_S09lGo.js +0 -29
- package/build/server/chunks/entries/endpoints/oauth/register/_server.ts.js-S_S09lGo.js.map +0 -1
- package/build/server/chunks/entries/endpoints/oauth/token/_server.ts.js-HqZfcLWV.js +0 -32
- package/build/server/chunks/entries/endpoints/oauth/token/_server.ts.js-HqZfcLWV.js.map +0 -1
- package/build/server/chunks/entries/hooks.server.js-BIZRBlZI.js +0 -376
- package/build/server/chunks/entries/hooks.server.js-BIZRBlZI.js.map +0 -1
- package/build/server/chunks/entries/pages/_error.svelte.js-CR3ZMzSv.js +0 -38
- package/build/server/chunks/entries/pages/_error.svelte.js-CR3ZMzSv.js.map +0 -1
- package/build/server/chunks/entries/pages/_layout.server.ts.js-BD_gDYVJ.js +0 -37
- package/build/server/chunks/entries/pages/_layout.server.ts.js-BD_gDYVJ.js.map +0 -1
- package/build/server/chunks/entries/pages/_layout.svelte.js-DrB_Yvov.js +0 -626
- package/build/server/chunks/entries/pages/_layout.svelte.js-DrB_Yvov.js.map +0 -1
- package/build/server/chunks/entries/pages/_page.server.ts.js-BwjbAhOA.js +0 -56
- package/build/server/chunks/entries/pages/_page.server.ts.js-BwjbAhOA.js.map +0 -1
- package/build/server/chunks/entries/pages/_page.svelte.js-DeW0z6uB.js +0 -160
- package/build/server/chunks/entries/pages/_page.svelte.js-DeW0z6uB.js.map +0 -1
- package/build/server/chunks/entries/pages/accept-invite/_page.server.ts.js-BG63dUmh.js +0 -180
- package/build/server/chunks/entries/pages/accept-invite/_page.server.ts.js-BG63dUmh.js.map +0 -1
- package/build/server/chunks/entries/pages/accept-invite/_page.svelte.js-8p3P5tRV.js +0 -135
- package/build/server/chunks/entries/pages/accept-invite/_page.svelte.js-8p3P5tRV.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/_error.svelte.js-K13l_c7B.js +0 -40
- package/build/server/chunks/entries/pages/admin/_error.svelte.js-K13l_c7B.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/_layout.server.ts.js-CzYxoMn4.js +0 -31
- package/build/server/chunks/entries/pages/admin/_layout.server.ts.js-CzYxoMn4.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/_layout.svelte.js-CtCF11Mx.js +0 -123
- package/build/server/chunks/entries/pages/admin/_layout.svelte.js-CtCF11Mx.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/_page.server.ts.js-k8xyK-0r.js +0 -76
- package/build/server/chunks/entries/pages/admin/_page.server.ts.js-k8xyK-0r.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/_page.svelte.js-CHb4pbbG.js +0 -396
- package/build/server/chunks/entries/pages/admin/_page.svelte.js-CHb4pbbG.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/audit/_page.server.ts.js-DmbG-JDV.js +0 -269
- package/build/server/chunks/entries/pages/admin/audit/_page.server.ts.js-DmbG-JDV.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/audit/_page.svelte.js-CcAaPTYj.js +0 -458
- package/build/server/chunks/entries/pages/admin/audit/_page.svelte.js-CcAaPTYj.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/compute/_page.server.ts.js-BpynPgSW.js +0 -74
- package/build/server/chunks/entries/pages/admin/compute/_page.server.ts.js-BpynPgSW.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/compute/_page.svelte.js-2EyONotW.js +0 -841
- package/build/server/chunks/entries/pages/admin/compute/_page.svelte.js-2EyONotW.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/organizations/_page.server.ts.js-By_wlwvD.js +0 -35
- package/build/server/chunks/entries/pages/admin/organizations/_page.server.ts.js-By_wlwvD.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/organizations/_page.svelte.js-D0t7iVIE.js +0 -99
- package/build/server/chunks/entries/pages/admin/organizations/_page.svelte.js-D0t7iVIE.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/projects/_id_/_page.server.ts.js-CxcLfOOB.js +0 -86
- package/build/server/chunks/entries/pages/admin/projects/_id_/_page.server.ts.js-CxcLfOOB.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/projects/_id_/_page.svelte.js-DJollvmK.js +0 -639
- package/build/server/chunks/entries/pages/admin/projects/_id_/_page.svelte.js-DJollvmK.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/projects/_page.server.ts.js-DAQ9tm4R.js +0 -42
- package/build/server/chunks/entries/pages/admin/projects/_page.server.ts.js-DAQ9tm4R.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/projects/_page.svelte.js-D7IYFtKB.js +0 -286
- package/build/server/chunks/entries/pages/admin/projects/_page.svelte.js-D7IYFtKB.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/system/_page.server.ts.js-XVGE4_SA.js +0 -87
- package/build/server/chunks/entries/pages/admin/system/_page.server.ts.js-XVGE4_SA.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/system/_page.svelte.js-D5CFBrZl.js +0 -1389
- package/build/server/chunks/entries/pages/admin/system/_page.svelte.js-D5CFBrZl.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/users/_page.server.ts.js-CEQCsHhA.js +0 -79
- package/build/server/chunks/entries/pages/admin/users/_page.server.ts.js-CEQCsHhA.js.map +0 -1
- package/build/server/chunks/entries/pages/admin/users/_page.svelte.js-B9r69hfP.js +0 -636
- package/build/server/chunks/entries/pages/admin/users/_page.svelte.js-B9r69hfP.js.map +0 -1
- package/build/server/chunks/entries/pages/auth/email/sent/_page.svelte.js-Dk8pTxVa.js +0 -46
- package/build/server/chunks/entries/pages/auth/email/sent/_page.svelte.js-Dk8pTxVa.js.map +0 -1
- package/build/server/chunks/entries/pages/auth/email/start/_page.server.ts.js-DqfD9TXW.js +0 -62
- package/build/server/chunks/entries/pages/auth/email/start/_page.server.ts.js-DqfD9TXW.js.map +0 -1
- package/build/server/chunks/entries/pages/auth/email/start/_page.svelte.js-C9IWTavI.js +0 -15
- package/build/server/chunks/entries/pages/auth/email/start/_page.svelte.js-C9IWTavI.js.map +0 -1
- package/build/server/chunks/entries/pages/docs/api/_page.server.ts.js-FybPSZ7O.js +0 -62
- package/build/server/chunks/entries/pages/docs/api/_page.server.ts.js-FybPSZ7O.js.map +0 -1
- package/build/server/chunks/entries/pages/docs/api/_page.svelte.js-aorD3DQs.js +0 -85
- package/build/server/chunks/entries/pages/docs/api/_page.svelte.js-aorD3DQs.js.map +0 -1
- package/build/server/chunks/entries/pages/library/_guid_/_page.server.ts.js-CXkNtj9Q.js +0 -119
- package/build/server/chunks/entries/pages/library/_guid_/_page.server.ts.js-CXkNtj9Q.js.map +0 -1
- package/build/server/chunks/entries/pages/library/_guid_/_page.svelte.js-uQpR3GHm.js +0 -14439
- package/build/server/chunks/entries/pages/library/_guid_/_page.svelte.js-uQpR3GHm.js.map +0 -1
- package/build/server/chunks/entries/pages/library/_page.server.ts.js-B2c2vX6l.js +0 -51
- package/build/server/chunks/entries/pages/library/_page.server.ts.js-B2c2vX6l.js.map +0 -1
- package/build/server/chunks/entries/pages/library/_page.svelte.js-CqOdymIO.js +0 -301
- package/build/server/chunks/entries/pages/library/_page.svelte.js-CqOdymIO.js.map +0 -1
- package/build/server/chunks/entries/pages/login/_page.server.ts.js-DIgVeHOJ.js +0 -101
- package/build/server/chunks/entries/pages/login/_page.server.ts.js-DIgVeHOJ.js.map +0 -1
- package/build/server/chunks/entries/pages/login/_page.svelte.js-DrUgnKb0.js +0 -214
- package/build/server/chunks/entries/pages/login/_page.svelte.js-DrUgnKb0.js.map +0 -1
- package/build/server/chunks/entries/pages/logout/_page.server.ts.js-DBfzDyQO.js +0 -19
- package/build/server/chunks/entries/pages/logout/_page.server.ts.js-DBfzDyQO.js.map +0 -1
- package/build/server/chunks/entries/pages/oauth/authorize/_page.server.ts.js-BYm9z99H.js +0 -103
- package/build/server/chunks/entries/pages/oauth/authorize/_page.server.ts.js-BYm9z99H.js.map +0 -1
- package/build/server/chunks/entries/pages/oauth/authorize/_page.svelte.js-Y_pwq4PL.js +0 -133
- package/build/server/chunks/entries/pages/oauth/authorize/_page.svelte.js-Y_pwq4PL.js.map +0 -1
- package/build/server/chunks/entries/pages/projects/_layout.server.ts.js-BG5rMy0l.js +0 -22
- package/build/server/chunks/entries/pages/projects/_layout.server.ts.js-BG5rMy0l.js.map +0 -1
- package/build/server/chunks/entries/pages/projects/_layout.svelte.js-pzcP1UHQ.js +0 -50
- package/build/server/chunks/entries/pages/projects/_layout.svelte.js-pzcP1UHQ.js.map +0 -1
- package/build/server/chunks/entries/pages/projects/_page.server.ts.js-9bIgSAoI.js +0 -93
- package/build/server/chunks/entries/pages/projects/_page.server.ts.js-9bIgSAoI.js.map +0 -1
- package/build/server/chunks/entries/pages/projects/_page.svelte.js-QeRk767A.js +0 -3635
- package/build/server/chunks/entries/pages/projects/_page.svelte.js-QeRk767A.js.map +0 -1
- package/build/server/chunks/entries/pages/setup/_page.server.ts.js-DTVXv4_5.js +0 -116
- package/build/server/chunks/entries/pages/setup/_page.server.ts.js-DTVXv4_5.js.map +0 -1
- package/build/server/chunks/entries/pages/setup/_page.svelte.js-CH8fkvVN.js +0 -249
- package/build/server/chunks/entries/pages/setup/_page.svelte.js-CH8fkvVN.js.map +0 -1
- package/build/server/chunks/entries/pages/team/_layout.server.ts.js-CVc9agc3.js +0 -28
- package/build/server/chunks/entries/pages/team/_layout.server.ts.js-CVc9agc3.js.map +0 -1
- package/build/server/chunks/entries/pages/team/_layout.svelte.js-BFipXO9z.js +0 -176
- package/build/server/chunks/entries/pages/team/_layout.svelte.js-BFipXO9z.js.map +0 -1
- package/build/server/chunks/entries/pages/team/_page.server.ts.js-BKsGPBu7.js +0 -35
- package/build/server/chunks/entries/pages/team/_page.server.ts.js-BKsGPBu7.js.map +0 -1
- package/build/server/chunks/entries/pages/team/_page.svelte.js-DSuCRstj.js +0 -112
- package/build/server/chunks/entries/pages/team/_page.svelte.js-DSuCRstj.js.map +0 -1
- package/build/server/chunks/entries/pages/team/activity/_page.svelte.js-B9o2_AK4.js +0 -124
- package/build/server/chunks/entries/pages/team/activity/_page.svelte.js-B9o2_AK4.js.map +0 -1
- package/build/server/chunks/entries/pages/team/compute/_page.server.ts.js-nJ5oUEdJ.js +0 -42
- package/build/server/chunks/entries/pages/team/compute/_page.server.ts.js-nJ5oUEdJ.js.map +0 -1
- package/build/server/chunks/entries/pages/team/compute/_page.svelte.js-HvTh1Vab.js +0 -616
- package/build/server/chunks/entries/pages/team/compute/_page.svelte.js-HvTh1Vab.js.map +0 -1
- package/build/server/chunks/entries/pages/team/members/_page.server.ts.js-DG45szX9.js +0 -62
- package/build/server/chunks/entries/pages/team/members/_page.server.ts.js-DG45szX9.js.map +0 -1
- package/build/server/chunks/entries/pages/team/members/_page.svelte.js-CociwG1M.js +0 -807
- package/build/server/chunks/entries/pages/team/members/_page.svelte.js-CociwG1M.js.map +0 -1
- package/build/server/chunks/entries/pages/team/projects/_page.server.ts.js-CkjHotCp.js +0 -60
- package/build/server/chunks/entries/pages/team/projects/_page.server.ts.js-CkjHotCp.js.map +0 -1
- package/build/server/chunks/entries/pages/team/projects/_page.svelte.js-DjN7l3UT.js +0 -424
- package/build/server/chunks/entries/pages/team/projects/_page.svelte.js-DjN7l3UT.js.map +0 -1
- package/build/server/chunks/entries/pages/team/reclaim/_page.server.ts.js-BcOmEaIB.js +0 -67
- package/build/server/chunks/entries/pages/team/reclaim/_page.server.ts.js-BcOmEaIB.js.map +0 -1
- package/build/server/chunks/entries/pages/team/reclaim/_page.svelte.js-DyW7kVAk.js +0 -266
- package/build/server/chunks/entries/pages/team/reclaim/_page.svelte.js-DyW7kVAk.js.map +0 -1
- package/build/server/chunks/entries/pages/team/settings/_page.server.ts.js-5fhbiXJW.js +0 -34
- package/build/server/chunks/entries/pages/team/settings/_page.server.ts.js-5fhbiXJW.js.map +0 -1
- package/build/server/chunks/entries/pages/team/settings/_page.svelte.js-Ea_XWCio.js +0 -308
- package/build/server/chunks/entries/pages/team/settings/_page.svelte.js-Ea_XWCio.js.map +0 -1
- package/build/server/chunks/entries/pages/team/shares/_page.server.ts.js-COEiWSTf.js +0 -29
- package/build/server/chunks/entries/pages/team/shares/_page.server.ts.js-COEiWSTf.js.map +0 -1
- package/build/server/chunks/entries/pages/team/shares/_page.svelte.js-DsJl3T7V.js +0 -314
- package/build/server/chunks/entries/pages/team/shares/_page.svelte.js-DsJl3T7V.js.map +0 -1
- package/build/server/chunks/entries/pages/team/tokens/_page.server.ts.js-Cv-jmBVK.js +0 -65
- package/build/server/chunks/entries/pages/team/tokens/_page.server.ts.js-Cv-jmBVK.js.map +0 -1
- package/build/server/chunks/entries/pages/team/tokens/_page.svelte.js-BXR5pHwv.js +0 -736
- package/build/server/chunks/entries/pages/team/tokens/_page.svelte.js-BXR5pHwv.js.map +0 -1
- package/build/server/chunks/handler-BVJg1IbX.js +0 -1206
- package/build/server/chunks/handler-BVJg1IbX.js.map +0 -1
- package/build/server/chunks/index.js-CrJG7a-_.js +0 -3743
- package/build/server/chunks/index.js-CrJG7a-_.js.map +0 -1
- package/build/server/chunks/manifest.js-9CYdbyKr.js +0 -719
- package/build/server/chunks/manifest.js-9CYdbyKr.js.map +0 -1
- package/build/server/chunks/nodes/0.js-3pmtvMZq.js +0 -54
- package/build/server/chunks/nodes/0.js-3pmtvMZq.js.map +0 -1
- package/build/server/chunks/nodes/1.js-Cj0DPEY2.js +0 -9
- package/build/server/chunks/nodes/1.js-Cj0DPEY2.js.map +0 -1
- package/build/server/chunks/nodes/10.js-DjJqD8cC.js +0 -34
- package/build/server/chunks/nodes/10.js-DjJqD8cC.js.map +0 -1
- package/build/server/chunks/nodes/11.js-CXJhGhH3.js +0 -38
- package/build/server/chunks/nodes/11.js-CXJhGhH3.js.map +0 -1
- package/build/server/chunks/nodes/12.js-BhEuW4Gs.js +0 -31
- package/build/server/chunks/nodes/12.js-BhEuW4Gs.js.map +0 -1
- package/build/server/chunks/nodes/13.js-BV8SZoKH.js +0 -31
- package/build/server/chunks/nodes/13.js-BV8SZoKH.js.map +0 -1
- package/build/server/chunks/nodes/14.js-DwKbOIK2.js +0 -31
- package/build/server/chunks/nodes/14.js-DwKbOIK2.js.map +0 -1
- package/build/server/chunks/nodes/15.js-EuOVmGiZ.js +0 -39
- package/build/server/chunks/nodes/15.js-EuOVmGiZ.js.map +0 -1
- package/build/server/chunks/nodes/16.js-DIp1sACa.js +0 -34
- package/build/server/chunks/nodes/16.js-DIp1sACa.js.map +0 -1
- package/build/server/chunks/nodes/17.js-8oTQG_-2.js +0 -9
- package/build/server/chunks/nodes/17.js-8oTQG_-2.js.map +0 -1
- package/build/server/chunks/nodes/18.js-BXLHGlSH.js +0 -40
- package/build/server/chunks/nodes/18.js-BXLHGlSH.js.map +0 -1
- package/build/server/chunks/nodes/19.js-BlFIJsgl.js +0 -25
- package/build/server/chunks/nodes/19.js-BlFIJsgl.js.map +0 -1
- package/build/server/chunks/nodes/2.js-KGh3WMtg.js +0 -34
- package/build/server/chunks/nodes/2.js-KGh3WMtg.js.map +0 -1
- package/build/server/chunks/nodes/20.js-DPBpuWGP.js +0 -24
- package/build/server/chunks/nodes/20.js-DPBpuWGP.js.map +0 -1
- package/build/server/chunks/nodes/21.js-rCVkOJ5W.js +0 -41
- package/build/server/chunks/nodes/21.js-rCVkOJ5W.js.map +0 -1
- package/build/server/chunks/nodes/22.js-XqaqffTZ.js +0 -40
- package/build/server/chunks/nodes/22.js-XqaqffTZ.js.map +0 -1
- package/build/server/chunks/nodes/23.js-BaYXe7NW.js +0 -37
- package/build/server/chunks/nodes/23.js-BaYXe7NW.js.map +0 -1
- package/build/server/chunks/nodes/24.js-Bz0uTBJa.js +0 -53
- package/build/server/chunks/nodes/24.js-Bz0uTBJa.js.map +0 -1
- package/build/server/chunks/nodes/25.js-BWX6nfsg.js +0 -33
- package/build/server/chunks/nodes/25.js-BWX6nfsg.js.map +0 -1
- package/build/server/chunks/nodes/26.js-Dup_ter0.js +0 -40
- package/build/server/chunks/nodes/26.js-Dup_ter0.js.map +0 -1
- package/build/server/chunks/nodes/27.js-BEUAmtL6.js +0 -31
- package/build/server/chunks/nodes/27.js-BEUAmtL6.js.map +0 -1
- package/build/server/chunks/nodes/28.js-D19p7Yo7.js +0 -9
- package/build/server/chunks/nodes/28.js-D19p7Yo7.js.map +0 -1
- package/build/server/chunks/nodes/29.js-hVNcerml.js +0 -31
- package/build/server/chunks/nodes/29.js-hVNcerml.js.map +0 -1
- package/build/server/chunks/nodes/3.js-CJRnGuBX.js +0 -9
- package/build/server/chunks/nodes/3.js-CJRnGuBX.js.map +0 -1
- package/build/server/chunks/nodes/30.js-CrpIx0yO.js +0 -31
- package/build/server/chunks/nodes/30.js-CrpIx0yO.js.map +0 -1
- package/build/server/chunks/nodes/31.js-CfatoH1-.js +0 -34
- package/build/server/chunks/nodes/31.js-CfatoH1-.js.map +0 -1
- package/build/server/chunks/nodes/32.js-u84xoe5E.js +0 -31
- package/build/server/chunks/nodes/32.js-u84xoe5E.js.map +0 -1
- package/build/server/chunks/nodes/33.js-DiC1927s.js +0 -31
- package/build/server/chunks/nodes/33.js-DiC1927s.js.map +0 -1
- package/build/server/chunks/nodes/34.js-cPddK-8A.js +0 -31
- package/build/server/chunks/nodes/34.js-cPddK-8A.js.map +0 -1
- package/build/server/chunks/nodes/35.js-RpNpvUFE.js +0 -54
- package/build/server/chunks/nodes/35.js-RpNpvUFE.js.map +0 -1
- package/build/server/chunks/nodes/5.js-WjwWIk7-.js +0 -15
- package/build/server/chunks/nodes/5.js-WjwWIk7-.js.map +0 -1
- package/build/server/chunks/nodes/6.js-6mJBLIGs.js +0 -31
- package/build/server/chunks/nodes/6.js-6mJBLIGs.js.map +0 -1
- package/build/server/chunks/nodes/7.js-BjHeLfau.js +0 -24
- package/build/server/chunks/nodes/7.js-BjHeLfau.js.map +0 -1
- package/build/server/chunks/nodes/8.js-eiZc7Xpf.js +0 -41
- package/build/server/chunks/nodes/8.js-eiZc7Xpf.js.map +0 -1
- package/build/server/chunks/nodes/9.js-DwjqUHv3.js +0 -31
- package/build/server/chunks/nodes/9.js-DwjqUHv3.js.map +0 -1
- /package/build/client/_app/immutable/nodes/{0.B7xg1wnA.js → 0.DIdNka1f.js} +0 -0
- /package/build/client/_app/immutable/nodes/{0.B7xg1wnA.js.br → 0.DIdNka1f.js.br} +0 -0
- /package/build/client/_app/immutable/nodes/{0.B7xg1wnA.js.gz → 0.DIdNka1f.js.gz} +0 -0
|
@@ -0,0 +1,4332 @@
|
|
|
1
|
+
// ../compute/dist/handle-files-DSwM21jz.js
|
|
2
|
+
var DEFAULT_RETRY = {
|
|
3
|
+
attempts: 0,
|
|
4
|
+
baseDelayMs: 500,
|
|
5
|
+
maxDelayMs: 3e4,
|
|
6
|
+
retryOn429: true
|
|
7
|
+
};
|
|
8
|
+
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([
|
|
9
|
+
502,
|
|
10
|
+
503,
|
|
11
|
+
504
|
|
12
|
+
]);
|
|
13
|
+
/**
|
|
14
|
+
* Ceiling on a server-sent `Retry-After` wait. The server's window outranks
|
|
15
|
+
* `RetryPolicy.maxDelayMs` (retrying sooner all but guarantees another 429), but a bad or hostile
|
|
16
|
+
* header must not park the client for minutes. A `maxDelayMs` above this cap raises it.
|
|
17
|
+
*/
|
|
18
|
+
var RETRY_AFTER_CAP_MS = 6e4;
|
|
19
|
+
function resolveRetryPolicy(policy) {
|
|
20
|
+
if (!policy) return DEFAULT_RETRY;
|
|
21
|
+
return {
|
|
22
|
+
attempts: policy.attempts ?? DEFAULT_RETRY.attempts,
|
|
23
|
+
baseDelayMs: policy.baseDelayMs ?? DEFAULT_RETRY.baseDelayMs,
|
|
24
|
+
maxDelayMs: policy.maxDelayMs ?? DEFAULT_RETRY.maxDelayMs,
|
|
25
|
+
retryOn429: policy.retryOn429 ?? DEFAULT_RETRY.retryOn429
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function isRetryableStatus(status, policy) {
|
|
29
|
+
return RETRYABLE_STATUS.has(status) || policy.retryOn429 && status === 429;
|
|
30
|
+
}
|
|
31
|
+
/** Delay before the next attempt: the server's `Retry-After` when it sent one, else backoff. */
|
|
32
|
+
function retryDelay(retryAfter, attempt, policy) {
|
|
33
|
+
const retryAfterMs = parseRetryAfter(retryAfter);
|
|
34
|
+
return retryAfterMs === null ? backoffDelay(attempt, policy) : Math.min(retryAfterMs, Math.max(policy.maxDelayMs, RETRY_AFTER_CAP_MS));
|
|
35
|
+
}
|
|
36
|
+
/** A `Retry-After` value (seconds or HTTP-date) in ms; null when missing or unparseable. */
|
|
37
|
+
function parseRetryAfter(headerValue) {
|
|
38
|
+
if (!headerValue) return null;
|
|
39
|
+
const seconds = Number(headerValue);
|
|
40
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
|
|
41
|
+
const dateMs = Date.parse(headerValue);
|
|
42
|
+
if (Number.isFinite(dateMs)) {
|
|
43
|
+
const delta = dateMs - Date.now();
|
|
44
|
+
return delta > 0 ? delta : 0;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function backoffDelay(attempt, policy) {
|
|
49
|
+
const exponential = policy.baseDelayMs * Math.pow(2, attempt);
|
|
50
|
+
const jitter = Math.random() * policy.baseDelayMs;
|
|
51
|
+
return Math.min(exponential + jitter, policy.maxDelayMs);
|
|
52
|
+
}
|
|
53
|
+
function sleep(ms, signal) {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
if (signal?.aborted) {
|
|
56
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const id = setTimeout(() => {
|
|
60
|
+
signal?.removeEventListener("abort", onAbort);
|
|
61
|
+
resolve();
|
|
62
|
+
}, ms);
|
|
63
|
+
const onAbort = () => {
|
|
64
|
+
clearTimeout(id);
|
|
65
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
66
|
+
};
|
|
67
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
var ErrorCodes = {
|
|
71
|
+
/** Connection failure, a gateway status (502/503/504), or a 2xx body cut off mid-stream. */
|
|
72
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
73
|
+
/** HTTP 401 or 403: the server rejected the credentials. */
|
|
74
|
+
AUTH_ERROR: "AUTH_ERROR",
|
|
75
|
+
/** The server rejected the request (HTTP 400, 413), or an input failed a client-side check. */
|
|
76
|
+
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
77
|
+
/** The server failed the solve (HTTP 500), or the solve reported errors. */
|
|
78
|
+
COMPUTATION_ERROR: "COMPUTATION_ERROR",
|
|
79
|
+
/** No response within `ComputeConfig.timeoutMs`. */
|
|
80
|
+
TIMEOUT_ERROR: "TIMEOUT_ERROR",
|
|
81
|
+
/** A browser fetch failed with no response: most often CORS, which the browser hides. */
|
|
82
|
+
CORS_ERROR: "CORS_ERROR",
|
|
83
|
+
/** HTTP 404: the endpoint doesn't exist on this server. Never retried. */
|
|
84
|
+
NOT_FOUND: "NOT_FOUND",
|
|
85
|
+
/** HTTP 429. Retried, honouring `Retry-After`, when the policy allows (`RetryPolicy.retryOn429`). */
|
|
86
|
+
RATE_LIMIT: "RATE_LIMIT",
|
|
87
|
+
/**
|
|
88
|
+
* A 2xx with a body the client can't use: declared non-JSON (a captive portal, a proxy login page)
|
|
89
|
+
* or JSON that isn't an object. Never retried.
|
|
90
|
+
*/
|
|
91
|
+
INVALID_RESPONSE: "INVALID_RESPONSE",
|
|
92
|
+
/**
|
|
93
|
+
* The response body passed `ComputeConfig.maxResponseBytes`; the download was cancelled there.
|
|
94
|
+
* Never retried. `context` carries `{ maxResponseBytes }`.
|
|
95
|
+
*/
|
|
96
|
+
RESPONSE_TOO_LARGE: "RESPONSE_TOO_LARGE",
|
|
97
|
+
/** Any failure not classified by another code. */
|
|
98
|
+
UNKNOWN_ERROR: "UNKNOWN_ERROR",
|
|
99
|
+
/** An object was used after `dispose()`, or a file download failed part-way. */
|
|
100
|
+
INVALID_STATE: "INVALID_STATE",
|
|
101
|
+
/** A caller-supplied argument is unusable: an empty definition, an unserializable body. */
|
|
102
|
+
INVALID_INPUT: "INVALID_INPUT",
|
|
103
|
+
/**
|
|
104
|
+
* Bad configuration: an invalid `serverUrl`, an unsendable header, an unusable number, a server
|
|
105
|
+
* that answers with a redirect, an incomplete logger, an interval out of range.
|
|
106
|
+
*/
|
|
107
|
+
INVALID_CONFIG: "INVALID_CONFIG",
|
|
108
|
+
/** A browser-only API (file download) was called outside a browser. */
|
|
109
|
+
BROWSER_ONLY: "BROWSER_ONLY",
|
|
110
|
+
/** The runtime has no base64 codec: neither `Buffer` nor `atob`/`btoa`. */
|
|
111
|
+
ENVIRONMENT_ERROR: "ENVIRONMENT_ERROR",
|
|
112
|
+
/** A string that should be base64 isn't. */
|
|
113
|
+
ENCODING_ERROR: "ENCODING_ERROR",
|
|
114
|
+
/** An input's `default` had a shape the normalizer didn't recognize. */
|
|
115
|
+
MALFORMED_DEFAULT: "MALFORMED_DEFAULT",
|
|
116
|
+
/** Latest-wins scheduling: a newer call replaced this one. */
|
|
117
|
+
SUPERSEDED: "SUPERSEDED",
|
|
118
|
+
/** The scheduler or a caller-supplied `AbortSignal` aborted this call. */
|
|
119
|
+
ABORTED: "ABORTED",
|
|
120
|
+
/**
|
|
121
|
+
* The queue was at `maxQueueDepth`, so the call was rejected without queueing. Retryable after a
|
|
122
|
+
* back-off. `context` carries `{ queueDepth, maxQueueDepth }`.
|
|
123
|
+
*/
|
|
124
|
+
QUEUE_FULL: "QUEUE_FULL",
|
|
125
|
+
/**
|
|
126
|
+
* The call waited longer than `queueWaitMs` without starting, and was rejected rather than run
|
|
127
|
+
* stale. Retryable. `context` carries `{ waitedMs, queueWaitMs }`.
|
|
128
|
+
*/
|
|
129
|
+
QUEUE_TIMEOUT: "QUEUE_TIMEOUT",
|
|
130
|
+
/**
|
|
131
|
+
* The server no longer holds the definition a `pointer` named (evicted, restarted, another
|
|
132
|
+
* child). Retry with the full definition. Read from the error body's
|
|
133
|
+
* `code: "definition_not_cached"`.
|
|
134
|
+
*/
|
|
135
|
+
DEFINITION_NOT_CACHED: "DEFINITION_NOT_CACHED"
|
|
136
|
+
};
|
|
137
|
+
/** Error with a typed `code`: switch on it rather than on the message. */
|
|
138
|
+
var ComputeError = class extends Error {
|
|
139
|
+
code;
|
|
140
|
+
statusCode;
|
|
141
|
+
context;
|
|
142
|
+
originalError;
|
|
143
|
+
constructor(message, code = ErrorCodes.UNKNOWN_ERROR, options) {
|
|
144
|
+
const original = options?.originalError;
|
|
145
|
+
const cause = original === void 0 || original instanceof Error ? original : new Error(String(original));
|
|
146
|
+
super(message, cause && { cause });
|
|
147
|
+
this.name = "ComputeError";
|
|
148
|
+
this.code = code;
|
|
149
|
+
this.statusCode = options?.statusCode;
|
|
150
|
+
this.context = options?.context;
|
|
151
|
+
this.originalError = cause;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
/** A caller's signal cancelled the work. */
|
|
155
|
+
function abortedByCaller(context, originalError) {
|
|
156
|
+
return new ComputeError("Request aborted by caller", ErrorCodes.ABORTED, {
|
|
157
|
+
context,
|
|
158
|
+
originalError
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
var silent = {
|
|
162
|
+
debug() {},
|
|
163
|
+
info() {},
|
|
164
|
+
warn() {},
|
|
165
|
+
error() {}
|
|
166
|
+
};
|
|
167
|
+
var internalLogger = silent;
|
|
168
|
+
function getLogger() {
|
|
169
|
+
return internalLogger;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Route the package's logs to `logger`; `null` silences them (the default).
|
|
173
|
+
*
|
|
174
|
+
* @throws {ComputeError} `INVALID_CONFIG` if the logger lacks one of the four methods, rather
|
|
175
|
+
* than a "debug is not a function" later at an unrelated call site.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* import { setLogger } from '@selvajs/compute/core';
|
|
180
|
+
*
|
|
181
|
+
* setLogger(console);
|
|
182
|
+
* setLogger({
|
|
183
|
+
* debug: (msg, ...args) => myLogger.debug(msg, ...args),
|
|
184
|
+
* info: (msg, ...args) => myLogger.info(msg, ...args),
|
|
185
|
+
* warn: (msg, ...args) => myLogger.warn(msg, ...args),
|
|
186
|
+
* error: (msg, ...args) => myLogger.error(msg, ...args)
|
|
187
|
+
* });
|
|
188
|
+
* setLogger(null);
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
function setLogger(logger) {
|
|
192
|
+
if (logger === null) {
|
|
193
|
+
internalLogger = silent;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const missing = [
|
|
197
|
+
"debug",
|
|
198
|
+
"info",
|
|
199
|
+
"warn",
|
|
200
|
+
"error"
|
|
201
|
+
].filter((method) => typeof logger[method] !== "function");
|
|
202
|
+
if (missing.length > 0) throw new ComputeError(`Logger is missing required method(s): ${missing.join(", ")}. A logger must implement debug, info, warn and error.`, ErrorCodes.INVALID_CONFIG, { context: { missingMethods: missing } });
|
|
203
|
+
internalLogger = logger;
|
|
204
|
+
}
|
|
205
|
+
/** Shorthand for `setLogger(console)`. */
|
|
206
|
+
function enableDebugLogging() {
|
|
207
|
+
setLogger(console);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Case-insensitive field reads for wire payloads.
|
|
211
|
+
*
|
|
212
|
+
* Rhino Compute branches serialize the same field in different casings. mcneel 8.x/9.x send the IO
|
|
213
|
+
* schema PascalCase (`ParamType`, `Default`, `InnerTree`): those C# classes carry no
|
|
214
|
+
* `[JsonProperty]`. The VektorNode fork sends camelCase, except inside the `default` DataTree
|
|
215
|
+
* (`ParamName`, `InnerTree`), an external type it can't attribute. So one response can mix casings.
|
|
216
|
+
* Read the fields you need through here and leave the rest verbatim: rewriting every key corrupts
|
|
217
|
+
* user-authored ones such as value-list labels.
|
|
218
|
+
*/
|
|
219
|
+
/** Own keys only: a payload probed for `constructor` must not find `Object.prototype`'s. */
|
|
220
|
+
function findOwnKey(obj, name) {
|
|
221
|
+
if (!obj || typeof obj !== "object") return void 0;
|
|
222
|
+
if (Object.hasOwn(obj, name)) return name;
|
|
223
|
+
const lower = name.toLowerCase();
|
|
224
|
+
return Object.keys(obj).find((key) => key.toLowerCase() === lower);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Read `name` in any casing, preferring an exact-case match. `undefined` when no own key matches or
|
|
228
|
+
* `obj` isn't an object.
|
|
229
|
+
*/
|
|
230
|
+
function readField(obj, name) {
|
|
231
|
+
const key = findOwnKey(obj, name);
|
|
232
|
+
return key === void 0 ? void 0 : obj[key];
|
|
233
|
+
}
|
|
234
|
+
/** Whether `name` is present in any casing, even with a null or undefined value. */
|
|
235
|
+
function hasField(obj, name) {
|
|
236
|
+
return findOwnKey(obj, name) !== void 0;
|
|
237
|
+
}
|
|
238
|
+
var UNREADABLE = "<unreadable URL>";
|
|
239
|
+
/**
|
|
240
|
+
* Only a URL with a real host can be cut safely. Anything else could hold a secret at any position:
|
|
241
|
+
* `https://admin:p/ss@host` splits into a bad port and a path.
|
|
242
|
+
*/
|
|
243
|
+
function parseWithHost(url) {
|
|
244
|
+
try {
|
|
245
|
+
const parsed = new URL(url);
|
|
246
|
+
return parsed.host ? parsed : null;
|
|
247
|
+
} catch {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/** `url` without credentials, query or fragment, for errors and logs. */
|
|
252
|
+
function redactUrl(url) {
|
|
253
|
+
const parsed = parseWithHost(url);
|
|
254
|
+
if (!parsed) return UNREADABLE;
|
|
255
|
+
parsed.username = "";
|
|
256
|
+
parsed.password = "";
|
|
257
|
+
parsed.search = "";
|
|
258
|
+
parsed.hash = "";
|
|
259
|
+
return parsed.href;
|
|
260
|
+
}
|
|
261
|
+
/** Scheme and host alone. For a URL that was rejected, whose path can't be trusted either. */
|
|
262
|
+
function redactToOrigin(url) {
|
|
263
|
+
const parsed = parseWithHost(url);
|
|
264
|
+
return parsed ? `${parsed.protocol}//${parsed.host}` : UNREADABLE;
|
|
265
|
+
}
|
|
266
|
+
/** The parsed value, or `undefined` when `text` isn't JSON. */
|
|
267
|
+
function tryParseJson(text) {
|
|
268
|
+
try {
|
|
269
|
+
return JSON.parse(text);
|
|
270
|
+
} catch {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Validate a compute `serverUrl` and return it trimmed, without trailing slashes.
|
|
276
|
+
*
|
|
277
|
+
* @throws {ComputeError} `INVALID_CONFIG` when the URL is empty, isn't http(s), doesn't parse,
|
|
278
|
+
* embeds credentials, has a query or fragment, or names a blocked host.
|
|
279
|
+
*/
|
|
280
|
+
function validateServerUrl(raw, options) {
|
|
281
|
+
const trimmed = raw?.trim() ?? "";
|
|
282
|
+
if (!trimmed) throw new ComputeError("serverUrl is required", ErrorCodes.INVALID_CONFIG, { context: { receivedServerUrl: raw } });
|
|
283
|
+
const redacted = redactToOrigin(trimmed);
|
|
284
|
+
const invalid = (reason) => new ComputeError(`Invalid serverUrl: "${redacted}". ${reason}`, ErrorCodes.INVALID_CONFIG, { context: { receivedServerUrl: redacted } });
|
|
285
|
+
if (!/^https?:\/\//i.test(trimmed)) throw invalid("Must start with \"http://\" or \"https://\". For example: \"http://localhost:6500\" or \"https://example.com\"");
|
|
286
|
+
let parsed;
|
|
287
|
+
try {
|
|
288
|
+
parsed = new URL(trimmed);
|
|
289
|
+
} catch {
|
|
290
|
+
throw invalid("Must be a valid URL.");
|
|
291
|
+
}
|
|
292
|
+
if (parsed.username !== "" || parsed.password !== "") throw invalid("Must not embed credentials (user:pass@host) — fetch rejects credentialed URLs at request time. Pass the API key separately.");
|
|
293
|
+
if (trimmed.includes("?") || trimmed.includes("#")) throw invalid("Must not contain a query string or fragment — endpoint paths are appended to this URL (e.g. \"${serverUrl}/version\"), and a \"?\" or \"#\" suffix would corrupt every request path.");
|
|
294
|
+
const hostname = trimTrailing(parsed.hostname.toLowerCase(), ".");
|
|
295
|
+
if ((options?.blockedHosts ?? ["compute.rhino3d.com"]).map((h) => trimTrailing(h.toLowerCase(), ".")).includes(hostname)) throw new ComputeError("serverUrl must be set to your Compute server URL. The shared public endpoint is not allowed.", ErrorCodes.INVALID_CONFIG, { context: { receivedServerUrl: redacted } });
|
|
296
|
+
return trimTrailing(trimmed, "/");
|
|
297
|
+
}
|
|
298
|
+
/** A loop, not `/x+$/`: that regex retries from every position of a long run and goes quadratic. */
|
|
299
|
+
function trimTrailing(value, char) {
|
|
300
|
+
let end = value.length;
|
|
301
|
+
while (end > 0 && value[end - 1] === char) end--;
|
|
302
|
+
return value.slice(0, end);
|
|
303
|
+
}
|
|
304
|
+
var warned = /* @__PURE__ */ new Set();
|
|
305
|
+
/** Log `message` the first time `key` is seen: what it reports doesn't change per call. */
|
|
306
|
+
function warnOnce(key, message) {
|
|
307
|
+
if (warned.has(key)) return;
|
|
308
|
+
warned.add(key);
|
|
309
|
+
getLogger().warn(message);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* True only in a real browser, where an API key in the config is exposed to users. jsdom defines
|
|
313
|
+
* `window` too, so Node is ruled out by `process.versions.node`, and by jsdom's user-agent marker
|
|
314
|
+
* for setups that hide `process`.
|
|
315
|
+
*/
|
|
316
|
+
function isRealBrowser() {
|
|
317
|
+
if (typeof window === "undefined") return false;
|
|
318
|
+
if (globalThis.process?.versions?.node != null) return false;
|
|
319
|
+
const nav = globalThis.navigator;
|
|
320
|
+
const userAgent = typeof nav?.userAgent === "string" ? nav.userAgent : "";
|
|
321
|
+
if (/jsdom/i.test(userAgent)) return false;
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
function warnIfClientSide(functionName, suppress) {
|
|
325
|
+
if (suppress || !isRealBrowser()) return;
|
|
326
|
+
warnOnce(`client-side:${functionName}`, `Warning: ${functionName} is running on the client side. For better performance and security, consider running this on the server side.`);
|
|
327
|
+
}
|
|
328
|
+
/** `serverUrl` as `validateServerUrl` returns it: no trailing slash. */
|
|
329
|
+
function buildUrl(endpoint, serverUrl) {
|
|
330
|
+
return `${serverUrl}/${endpoint.replace(/^\/+/, "")}`;
|
|
331
|
+
}
|
|
332
|
+
function isLocalhost(serverUrl) {
|
|
333
|
+
const hostname = new URL(serverUrl).hostname.toLowerCase();
|
|
334
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
335
|
+
}
|
|
336
|
+
var DEFAULT_API_KEY_HEADER = "RhinoComputeKey";
|
|
337
|
+
/**
|
|
338
|
+
* Caller headers plus credentials. Every request to the server builds its headers here,
|
|
339
|
+
* so a liveness probe authenticates exactly like the solve it gates.
|
|
340
|
+
*/
|
|
341
|
+
function buildAuthHeaders(auth) {
|
|
342
|
+
return assertSendable(mergeUnder(auth.headers, credentialHeaders(auth)));
|
|
343
|
+
}
|
|
344
|
+
function buildHeaders(requestId, config) {
|
|
345
|
+
const headers = assertSendable(mergeUnder(config.headers, {
|
|
346
|
+
...credentialHeaders(config),
|
|
347
|
+
"X-Request-ID": requestId,
|
|
348
|
+
"Content-Type": "application/json"
|
|
349
|
+
}));
|
|
350
|
+
if (!config.apiKey && !config.authToken && !isLocalhost(config.serverUrl)) warnOnce(`no-auth:${config.serverUrl}`, `[Compute] Request [${requestId}] targets remote server (${config.serverUrl}) but no API key or auth token is configured. Requests may fail or be rate-limited. (warned once per server)`);
|
|
351
|
+
return headers;
|
|
352
|
+
}
|
|
353
|
+
/** `headers` with a JSON `Content-Type` that replaces one of any casing already there. */
|
|
354
|
+
function withJsonContentType(headers) {
|
|
355
|
+
return mergeUnder(headers, { "Content-Type": "application/json" });
|
|
356
|
+
}
|
|
357
|
+
function credentialHeaders(auth) {
|
|
358
|
+
return {
|
|
359
|
+
...auth.authToken && { Authorization: auth.authToken },
|
|
360
|
+
...auth.apiKey && { [auth.apiKeyHeader ?? DEFAULT_API_KEY_HEADER]: auth.apiKey }
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Header names are case-insensitive and fetch joins duplicates, so a caller key
|
|
365
|
+
* matching a transport key in any case is dropped rather than sent alongside it.
|
|
366
|
+
*/
|
|
367
|
+
function mergeUnder(caller, transport) {
|
|
368
|
+
const taken = new Set(Object.keys(transport).map((name) => name.toLowerCase()));
|
|
369
|
+
const kept = Object.entries(caller ?? {}).filter(([name]) => !taken.has(name.toLowerCase()));
|
|
370
|
+
return {
|
|
371
|
+
...Object.fromEntries(kept),
|
|
372
|
+
...transport
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Left to fetch, a bad value becomes a retried TypeError that quotes it, and the value may be the
|
|
377
|
+
* API key. `Headers` throws the same message, so its error is not kept as the cause.
|
|
378
|
+
*/
|
|
379
|
+
function assertSendable(headers) {
|
|
380
|
+
const check = new Headers();
|
|
381
|
+
for (const [name, value] of Object.entries(headers)) try {
|
|
382
|
+
check.set(name, value);
|
|
383
|
+
} catch {
|
|
384
|
+
throw new ComputeError(`Header "${name}" has an invalid name or value`, ErrorCodes.INVALID_CONFIG, { context: { header: name } });
|
|
385
|
+
}
|
|
386
|
+
return headers;
|
|
387
|
+
}
|
|
388
|
+
function generateRequestId() {
|
|
389
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
|
390
|
+
}
|
|
391
|
+
function getNodeBuffer() {
|
|
392
|
+
const buf = globalThis.Buffer;
|
|
393
|
+
return typeof buf === "function" ? buf : void 0;
|
|
394
|
+
}
|
|
395
|
+
function encodeStringToBase64(str) {
|
|
396
|
+
const Buffer = getNodeBuffer();
|
|
397
|
+
if (Buffer) return Buffer.from(str, "utf-8").toString("base64");
|
|
398
|
+
return base64ByteArray(new TextEncoder().encode(str));
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* WHATWG forgiving-base64 normalization: strip ASCII whitespace, then drop trailing padding where
|
|
402
|
+
* the spec allows it (total length a multiple of 4). `null` when the length can't be base64. Leaves
|
|
403
|
+
* the alphabet check to the decoders, which make it faster than a regex over a multi-MB payload.
|
|
404
|
+
*/
|
|
405
|
+
function stripBase64(str) {
|
|
406
|
+
let data = str.replace(/[\t\n\f\r ]/g, "");
|
|
407
|
+
if (data.length % 4 === 0) data = data.replace(/={1,2}$/, "");
|
|
408
|
+
return data.length % 4 === 1 ? null : data;
|
|
409
|
+
}
|
|
410
|
+
var B64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
411
|
+
/**
|
|
412
|
+
* Whether an untyped string is base64 content: the canonical padded form when confident, else
|
|
413
|
+
* `null` (treat it as plain text). A heuristic; pass a `Uint8Array` when it must be exact.
|
|
414
|
+
*/
|
|
415
|
+
function detectBase64Payload(str) {
|
|
416
|
+
const data = stripBase64(str);
|
|
417
|
+
if (data === null || data.length < 64) return null;
|
|
418
|
+
if (/[^A-Za-z0-9+/]/.test(data)) return null;
|
|
419
|
+
const rem = data.length % 4;
|
|
420
|
+
const lastValue = B64_ALPHABET.indexOf(data.charAt(data.length - 1));
|
|
421
|
+
if (rem === 2 && (lastValue & 15) !== 0) return null;
|
|
422
|
+
if (rem === 3 && (lastValue & 3) !== 0) return null;
|
|
423
|
+
return rem === 0 ? data : data + "==".slice(0, 4 - rem);
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Decode base64 to bytes, normalizing and validating the same way in Node and browsers.
|
|
427
|
+
* `packages/visualization/src/shared/encoding.ts` keeps a copy that throws its own error class;
|
|
428
|
+
* change both together.
|
|
429
|
+
*
|
|
430
|
+
* @throws {ComputeError} `ENCODING_ERROR` if invalid, or `ENVIRONMENT_ERROR` if the runtime has no decoder
|
|
431
|
+
*/
|
|
432
|
+
function decodeBase64ToBinary(base64File) {
|
|
433
|
+
const data = stripBase64(base64File);
|
|
434
|
+
const bytes = data === null ? null : decodeStripped(data);
|
|
435
|
+
if (bytes === null) throw new ComputeError("Invalid base64 input.", ErrorCodes.ENCODING_ERROR, { context: { inputLength: base64File.length } });
|
|
436
|
+
return bytes;
|
|
437
|
+
}
|
|
438
|
+
/** Decode {@link stripBase64} output; `null` when a character is outside the alphabet. */
|
|
439
|
+
function decodeStripped(data) {
|
|
440
|
+
const Buffer = getNodeBuffer();
|
|
441
|
+
if (Buffer) {
|
|
442
|
+
if (Buffer.byteLength(data, "utf8") !== data.length) return null;
|
|
443
|
+
if (data.includes("-") || data.includes("_")) return null;
|
|
444
|
+
const decoded = Buffer.from(data, "base64");
|
|
445
|
+
if (decoded.length !== Math.floor(data.length * 3 / 4)) return null;
|
|
446
|
+
return decoded.byteOffset === 0 && decoded.buffer.byteLength === decoded.length ? new Uint8Array(decoded.buffer, 0, decoded.length) : new Uint8Array(decoded);
|
|
447
|
+
}
|
|
448
|
+
if (typeof globalThis.atob === "function") {
|
|
449
|
+
let binary;
|
|
450
|
+
try {
|
|
451
|
+
binary = globalThis.atob(data);
|
|
452
|
+
} catch {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
const bytes = new Uint8Array(binary.length);
|
|
456
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i) & 255;
|
|
457
|
+
return bytes;
|
|
458
|
+
}
|
|
459
|
+
throw new ComputeError("Base64 decoding not supported in this environment.", ErrorCodes.ENVIRONMENT_ERROR, { context: { environmentInfo: "atob or Buffer not available" } });
|
|
460
|
+
}
|
|
461
|
+
/** UTF-8 byte length. Sizes every request body: `Buffer` counts without allocating the copy. */
|
|
462
|
+
function utf8ByteLength(str) {
|
|
463
|
+
const Buffer = getNodeBuffer();
|
|
464
|
+
return Buffer ? Buffer.byteLength(str, "utf-8") : new TextEncoder().encode(str).length;
|
|
465
|
+
}
|
|
466
|
+
function base64ByteArray(bytes) {
|
|
467
|
+
const Buffer = getNodeBuffer();
|
|
468
|
+
if (Buffer) return Buffer.from(bytes).toString("base64");
|
|
469
|
+
if (typeof globalThis.btoa === "function") {
|
|
470
|
+
const CHUNK = 32766;
|
|
471
|
+
const parts = [];
|
|
472
|
+
for (let i = 0; i < bytes.length; i += CHUNK) parts.push(globalThis.btoa(String.fromCharCode.apply(null, bytes.subarray(i, i + CHUNK))));
|
|
473
|
+
return parts.join("");
|
|
474
|
+
}
|
|
475
|
+
throw new ComputeError("Base64 encoding not supported in this environment.", ErrorCodes.ENVIRONMENT_ERROR, { context: { environmentInfo: "btoa or Buffer not available" } });
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Cap on an error body: it is read for its `code` and message only. A 500 is read in full instead,
|
|
479
|
+
* since a partial success carries the computed values.
|
|
480
|
+
*/
|
|
481
|
+
var ERROR_BODY_MAX_BYTES = 1 << 20;
|
|
482
|
+
/** Read a body as text, cancelling the download once it passes `limit` UTF-8 bytes. */
|
|
483
|
+
async function readBodyText(response, limit = Infinity) {
|
|
484
|
+
if (limit === Infinity) return {
|
|
485
|
+
text: await response.text(),
|
|
486
|
+
truncated: false
|
|
487
|
+
};
|
|
488
|
+
if (!response.body) {
|
|
489
|
+
const text = await response.text();
|
|
490
|
+
return {
|
|
491
|
+
text,
|
|
492
|
+
truncated: utf8ByteLength(text) > limit
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
const declared = Number(response.headers.get("Content-Length"));
|
|
496
|
+
if (!response.headers.has("Content-Encoding") && declared > limit) {
|
|
497
|
+
await response.body.cancel().catch(() => {});
|
|
498
|
+
return {
|
|
499
|
+
text: "",
|
|
500
|
+
truncated: true
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
const reader = response.body.getReader();
|
|
504
|
+
const decoder = new TextDecoder();
|
|
505
|
+
const parts = [];
|
|
506
|
+
let received = 0;
|
|
507
|
+
for (;;) {
|
|
508
|
+
const { done, value } = await reader.read();
|
|
509
|
+
if (done) break;
|
|
510
|
+
received += value.byteLength;
|
|
511
|
+
parts.push(decoder.decode(value, { stream: true }));
|
|
512
|
+
if (received > limit) {
|
|
513
|
+
await reader.cancel().catch(() => {});
|
|
514
|
+
return {
|
|
515
|
+
text: parts.join(""),
|
|
516
|
+
truncated: true
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
parts.push(decoder.decode());
|
|
521
|
+
return {
|
|
522
|
+
text: parts.join(""),
|
|
523
|
+
truncated: false
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Parse a W3C Server Timing header, as the solve endpoint emits it:
|
|
528
|
+
* `decode;dur=3, solve;dur=120, gh;dur=110, encode;dur=8, recomputed;desc="4/97"`, or
|
|
529
|
+
* `cache;desc="hit"` when the server answered from its result cache. Null when it carries no
|
|
530
|
+
* recognised metric.
|
|
531
|
+
*/
|
|
532
|
+
function parseServerTiming(headerValue) {
|
|
533
|
+
if (!headerValue) return null;
|
|
534
|
+
const timing = { raw: headerValue };
|
|
535
|
+
let sawMetric = false;
|
|
536
|
+
for (const part of headerValue.split(",")) {
|
|
537
|
+
const [rawName, ...params] = part.trim().split(";");
|
|
538
|
+
const name = rawName.trim().toLowerCase();
|
|
539
|
+
if (name === "decode" || name === "solve" || name === "encode" || name === "gh") {
|
|
540
|
+
const dur = Number(param(params, "dur"));
|
|
541
|
+
if (!Number.isFinite(dur)) continue;
|
|
542
|
+
timing[name] = dur;
|
|
543
|
+
sawMetric = true;
|
|
544
|
+
} else if (name === "recomputed") {
|
|
545
|
+
const [ran, total] = (param(params, "desc") ?? "").split("/").map(Number);
|
|
546
|
+
if (!Number.isInteger(ran) || !Number.isInteger(total)) continue;
|
|
547
|
+
timing.recomputed = {
|
|
548
|
+
ran,
|
|
549
|
+
total
|
|
550
|
+
};
|
|
551
|
+
sawMetric = true;
|
|
552
|
+
} else if (name === "cache" && param(params, "desc") === "hit") {
|
|
553
|
+
timing.cacheHit = true;
|
|
554
|
+
sawMetric = true;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return sawMetric ? timing : null;
|
|
558
|
+
}
|
|
559
|
+
function param(params, key) {
|
|
560
|
+
for (const p of params) {
|
|
561
|
+
const [k, ...v] = p.split("=");
|
|
562
|
+
if (k.trim().toLowerCase() !== key) continue;
|
|
563
|
+
return v.join("=").trim().replace(/^"(.*)"$/, "$1");
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
function fireServerTiming(response, requestId, onServerTiming) {
|
|
567
|
+
if (!onServerTiming) return;
|
|
568
|
+
const timing = parseServerTiming(response.headers.get("Server-Timing"));
|
|
569
|
+
if (!timing) return;
|
|
570
|
+
try {
|
|
571
|
+
onServerTiming(timing, requestId);
|
|
572
|
+
} catch (err) {
|
|
573
|
+
getLogger().debug(`onServerTiming callback threw ${err instanceof Error ? err.name : typeof err}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
/** What fetch, or a body read, rejects with when its signal fires: a caller abort or a timeout. */
|
|
577
|
+
function isAbortError(error) {
|
|
578
|
+
return error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
579
|
+
}
|
|
580
|
+
/** The most `AbortSignal.timeout` takes on Node, which wants a whole uint32. */
|
|
581
|
+
var MAX_TIMEOUT_MS = 2 ** 32 - 1;
|
|
582
|
+
/** `promise`'s outcome, or a rejection with `signal`'s reason if that fires first. */
|
|
583
|
+
function raceSignal(promise, signal) {
|
|
584
|
+
if (!signal) return promise;
|
|
585
|
+
return new Promise((resolve, reject) => {
|
|
586
|
+
const onAbort = () => reject(signal.reason);
|
|
587
|
+
if (signal.aborted) onAbort();
|
|
588
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
589
|
+
promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Compose a caller-supplied AbortSignal with an optional timeout; `undefined` when neither was
|
|
594
|
+
* given. `AbortSignal.timeout` rather than `setTimeout`: its timer isn't throttled in a hidden tab.
|
|
595
|
+
*/
|
|
596
|
+
function composeSignal(callerSignal, timeoutMs) {
|
|
597
|
+
const noCleanup = () => {};
|
|
598
|
+
if (typeof timeoutMs !== "number" || timeoutMs <= 0) return {
|
|
599
|
+
signal: callerSignal,
|
|
600
|
+
cleanup: noCleanup
|
|
601
|
+
};
|
|
602
|
+
const timeoutSignal = AbortSignal.timeout(Math.floor(timeoutMs));
|
|
603
|
+
if (!callerSignal) return {
|
|
604
|
+
signal: timeoutSignal,
|
|
605
|
+
cleanup: noCleanup
|
|
606
|
+
};
|
|
607
|
+
const ctrl = new AbortController();
|
|
608
|
+
const sources = [callerSignal, timeoutSignal];
|
|
609
|
+
const onAbort = function() {
|
|
610
|
+
ctrl.abort(this.reason);
|
|
611
|
+
};
|
|
612
|
+
for (const s of sources) {
|
|
613
|
+
if (s.aborted) {
|
|
614
|
+
ctrl.abort(s.reason);
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
s.addEventListener("abort", onAbort, { once: true });
|
|
618
|
+
}
|
|
619
|
+
return {
|
|
620
|
+
signal: ctrl.signal,
|
|
621
|
+
cleanup: () => {
|
|
622
|
+
for (const s of sources) s.removeEventListener("abort", onAbort);
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* A response's JSON text length, so byte-budgeted caches never re-serialize a huge tree. A WeakMap
|
|
628
|
+
* rather than a field keeps `JSON.stringify(response)` clean; it is keyed by identity, so a derived
|
|
629
|
+
* copy must re-register. `.length` stands in for UTF-8 bytes: the JSON is near-pure ASCII.
|
|
630
|
+
*/
|
|
631
|
+
var wireSizes = /* @__PURE__ */ new WeakMap();
|
|
632
|
+
/** Record `response`'s wire size. No-op for non-object/null values. */
|
|
633
|
+
function setResponseWireSize(response, size) {
|
|
634
|
+
if (typeof response !== "object" || response === null) return;
|
|
635
|
+
wireSizes.set(response, size);
|
|
636
|
+
}
|
|
637
|
+
/** The wire size recorded for `response`, or undefined when never registered. */
|
|
638
|
+
function getResponseWireSize(response) {
|
|
639
|
+
if (typeof response !== "object" || response === null) return void 0;
|
|
640
|
+
return wireSizes.get(response);
|
|
641
|
+
}
|
|
642
|
+
/** Upper bound for the raw server body stored on error `context.responseBody`. */
|
|
643
|
+
var MAX_CONTEXT_BODY_CHARS = 4096;
|
|
644
|
+
/** An allowlist: errors reach logs and telemetry, and `Set-Cookie` or a proxy's token must not. */
|
|
645
|
+
var CONTEXT_HEADERS = [
|
|
646
|
+
"content-length",
|
|
647
|
+
"content-type",
|
|
648
|
+
"retry-after",
|
|
649
|
+
"server-timing",
|
|
650
|
+
"www-authenticate",
|
|
651
|
+
"x-request-id"
|
|
652
|
+
];
|
|
653
|
+
function truncateBody(body) {
|
|
654
|
+
if (body.length <= MAX_CONTEXT_BODY_CHARS) return body;
|
|
655
|
+
return `${body.slice(0, MAX_CONTEXT_BODY_CHARS)}… [truncated ${body.length - MAX_CONTEXT_BODY_CHARS} chars]`;
|
|
656
|
+
}
|
|
657
|
+
function contextHeaders(headers) {
|
|
658
|
+
const kept = {};
|
|
659
|
+
for (const name of CONTEXT_HEADERS) {
|
|
660
|
+
const value = headers.get(name);
|
|
661
|
+
if (value !== null) kept[name] = value;
|
|
662
|
+
}
|
|
663
|
+
return kept;
|
|
664
|
+
}
|
|
665
|
+
var plainMessage = ({ status, statusText, bodyHint }) => `HTTP ${status}: ${statusText}${bodyHint}`;
|
|
666
|
+
var labelled = (label) => ({ statusText, bodyHint }) => `${label}: ${statusText}${bodyHint}`;
|
|
667
|
+
var STATUS_RULES = {
|
|
668
|
+
400: {
|
|
669
|
+
code: ErrorCodes.VALIDATION_ERROR,
|
|
670
|
+
message: labelled("Bad request")
|
|
671
|
+
},
|
|
672
|
+
401: { code: ErrorCodes.AUTH_ERROR },
|
|
673
|
+
403: { code: ErrorCodes.AUTH_ERROR },
|
|
674
|
+
404: {
|
|
675
|
+
code: ErrorCodes.NOT_FOUND,
|
|
676
|
+
message: ({ fullUrl }) => `Endpoint not found: ${fullUrl}`
|
|
677
|
+
},
|
|
678
|
+
413: {
|
|
679
|
+
code: ErrorCodes.VALIDATION_ERROR,
|
|
680
|
+
message: ({ requestSize }) => `Request too large: ${(requestSize / 1024).toFixed(2)}KB`
|
|
681
|
+
},
|
|
682
|
+
429: {
|
|
683
|
+
code: ErrorCodes.RATE_LIMIT,
|
|
684
|
+
message: ({ bodyHint }) => `Rate limit exceeded${bodyHint}`
|
|
685
|
+
},
|
|
686
|
+
500: {
|
|
687
|
+
code: ErrorCodes.COMPUTATION_ERROR,
|
|
688
|
+
message: labelled("Server error")
|
|
689
|
+
},
|
|
690
|
+
502: {
|
|
691
|
+
code: ErrorCodes.NETWORK_ERROR,
|
|
692
|
+
message: labelled("Bad gateway")
|
|
693
|
+
},
|
|
694
|
+
503: {
|
|
695
|
+
code: ErrorCodes.NETWORK_ERROR,
|
|
696
|
+
message: labelled("Service unavailable")
|
|
697
|
+
},
|
|
698
|
+
504: {
|
|
699
|
+
code: ErrorCodes.NETWORK_ERROR,
|
|
700
|
+
message: labelled("Gateway timeout")
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
/**
|
|
704
|
+
* `rawBody` is what came over the wire and goes on `context.responseBody`; `detail` may be a
|
|
705
|
+
* message rewritten from it and only feeds the error message.
|
|
706
|
+
*/
|
|
707
|
+
function throwHttpError(response, ctx, rawBody, detail, serverCode) {
|
|
708
|
+
const { status, statusText } = response;
|
|
709
|
+
const { fullUrl, requestId, requestSize, config } = ctx;
|
|
710
|
+
const trimmed = detail.trim();
|
|
711
|
+
const bodyHint = trimmed ? ` — ${trimmed.slice(0, 200)}${trimmed.length > 200 ? "…" : ""}` : "";
|
|
712
|
+
const rule = STATUS_RULES[status] ?? { code: ErrorCodes.UNKNOWN_ERROR };
|
|
713
|
+
const message = (rule.message ?? plainMessage)({
|
|
714
|
+
status,
|
|
715
|
+
statusText,
|
|
716
|
+
bodyHint,
|
|
717
|
+
fullUrl,
|
|
718
|
+
requestSize
|
|
719
|
+
});
|
|
720
|
+
const codes = config.serverErrorCodes;
|
|
721
|
+
throw new ComputeError(message, (serverCode && codes && Object.hasOwn(codes, serverCode) ? codes[serverCode] : void 0) ?? rule.code, {
|
|
722
|
+
statusCode: status,
|
|
723
|
+
context: {
|
|
724
|
+
url: fullUrl,
|
|
725
|
+
requestId,
|
|
726
|
+
method: "POST",
|
|
727
|
+
requestSize,
|
|
728
|
+
serverUrl: config.serverUrl,
|
|
729
|
+
responseBody: rawBody ? truncateBody(rawBody) : void 0,
|
|
730
|
+
responseHeaders: contextHeaders(response.headers)
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
/** A 3xx, or a browser's `redirect: 'manual'` stand-in for one, which hides the status. */
|
|
735
|
+
function isRedirect(response) {
|
|
736
|
+
return response.type === "opaqueredirect" || response.status >= 300 && response.status < 400;
|
|
737
|
+
}
|
|
738
|
+
/** Following a redirect would send the API key header, which fetch keeps cross-origin, to the target. */
|
|
739
|
+
function redirectError(response, ctx) {
|
|
740
|
+
const location = response.headers.get("Location") ?? void 0;
|
|
741
|
+
return new ComputeError(`Server redirected the request${location ? ` to ${location}` : ""}. Redirects are not followed, so credentials never leave serverUrl: set serverUrl to the address it redirects to.`, ErrorCodes.INVALID_CONFIG, {
|
|
742
|
+
...response.status > 0 && { statusCode: response.status },
|
|
743
|
+
context: {
|
|
744
|
+
url: ctx.fullUrl,
|
|
745
|
+
requestId: ctx.requestId,
|
|
746
|
+
location
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
function tooLargeError(response, ctx) {
|
|
751
|
+
const { maxResponseBytes } = ctx.config;
|
|
752
|
+
return new ComputeError(`Response body exceeded maxResponseBytes (${maxResponseBytes} bytes)`, ErrorCodes.RESPONSE_TOO_LARGE, {
|
|
753
|
+
statusCode: response.status,
|
|
754
|
+
context: {
|
|
755
|
+
url: ctx.fullUrl,
|
|
756
|
+
requestId: ctx.requestId,
|
|
757
|
+
maxResponseBytes
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
/** Sizes and identifiers only: bodies and solver messages can hold user data. */
|
|
762
|
+
function logDebug(ctx, message) {
|
|
763
|
+
if (ctx.config.debug) getLogger().debug(`Request [${ctx.requestId}] ${message}`);
|
|
764
|
+
}
|
|
765
|
+
/** Values plus errors or warnings: the solve ran, so this 500 is a partial success. */
|
|
766
|
+
function partialSuccessCounts(parsed) {
|
|
767
|
+
const solveErrors = readField(parsed, "errors");
|
|
768
|
+
const solveWarnings = readField(parsed, "warnings");
|
|
769
|
+
if (!readField(parsed, "values") || !(solveErrors || solveWarnings)) return null;
|
|
770
|
+
return {
|
|
771
|
+
errors: solveErrors?.length ?? 0,
|
|
772
|
+
warnings: solveWarnings?.length ?? 0
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Compute8's exception handler sends `{ error, message: "<category>: <detail>", stackTrace? }`;
|
|
777
|
+
* older servers sent PascalCase `Message`/`ExceptionType`/`StackTrace`.
|
|
778
|
+
*/
|
|
779
|
+
function serverErrorDetail(parsed) {
|
|
780
|
+
const serverMessage = typeof parsed?.message === "string" && parsed.message || typeof parsed?.Message === "string" && parsed.Message || "";
|
|
781
|
+
if (serverMessage) {
|
|
782
|
+
const exceptionType = typeof parsed?.ExceptionType === "string" && parsed.ExceptionType || "";
|
|
783
|
+
const prefix = exceptionType ? `${exceptionType}: ` : "";
|
|
784
|
+
const stack = parsed?.stackTrace ?? parsed?.StackTrace;
|
|
785
|
+
const stackStr = Array.isArray(stack) ? stack.join("\n") : stack || "";
|
|
786
|
+
return `${prefix}${serverMessage}${stackStr ? `\n${stackStr}` : ""}`;
|
|
787
|
+
}
|
|
788
|
+
if (parsed?.error) return typeof parsed.error === "string" ? parsed.error : JSON.stringify(parsed.error, null, 2);
|
|
789
|
+
}
|
|
790
|
+
async function handleErrorStatus(response, ctx, responseTime) {
|
|
791
|
+
const { maxResponseBytes = Infinity, onServerTiming } = ctx.config;
|
|
792
|
+
const isServerError = response.status === 500;
|
|
793
|
+
const { text: rawBody, truncated } = await readBodyText(response, isServerError ? maxResponseBytes : Math.min(ERROR_BODY_MAX_BYTES, maxResponseBytes));
|
|
794
|
+
if (truncated && isServerError) throw tooLargeError(response, ctx);
|
|
795
|
+
logDebug(ctx, `failed with HTTP ${response.status} in ${responseTime}ms (${rawBody.length} chars)`);
|
|
796
|
+
const parsed = truncated ? void 0 : tryParseJson(rawBody);
|
|
797
|
+
let detail = rawBody;
|
|
798
|
+
if (isServerError && parsed !== void 0) {
|
|
799
|
+
const partial = partialSuccessCounts(parsed);
|
|
800
|
+
if (partial) {
|
|
801
|
+
setResponseWireSize(parsed, rawBody.length);
|
|
802
|
+
logDebug(ctx, `completed in ${responseTime}ms with ${partial.errors} solver error(s), ${partial.warnings} warning(s)`);
|
|
803
|
+
fireServerTiming(response, ctx.requestId, onServerTiming);
|
|
804
|
+
return {
|
|
805
|
+
ok: true,
|
|
806
|
+
value: parsed
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
detail = serverErrorDetail(parsed) ?? rawBody;
|
|
810
|
+
}
|
|
811
|
+
const code = parsed?.code;
|
|
812
|
+
throwHttpError(response, ctx, rawBody, detail, typeof code === "string" ? code : void 0);
|
|
813
|
+
}
|
|
814
|
+
async function parseSuccessBody(response, ctx) {
|
|
815
|
+
const { maxResponseBytes = Infinity, signal } = ctx.config;
|
|
816
|
+
try {
|
|
817
|
+
const { text: rawBody, truncated } = await readBodyText(response, maxResponseBytes);
|
|
818
|
+
if (truncated) throw tooLargeError(response, ctx);
|
|
819
|
+
const parsed = JSON.parse(rawBody);
|
|
820
|
+
setResponseWireSize(parsed, rawBody.length);
|
|
821
|
+
return {
|
|
822
|
+
ok: true,
|
|
823
|
+
value: parsed
|
|
824
|
+
};
|
|
825
|
+
} catch (error) {
|
|
826
|
+
if (signal?.aborted || isAbortError(error) || error instanceof ComputeError) throw error;
|
|
827
|
+
const contentType = (response.headers.get("Content-Type") ?? "").toLowerCase();
|
|
828
|
+
if (contentType !== "" && !contentType.includes("json")) throw new ComputeError(`Server returned a non-JSON response (Content-Type: ${contentType}) — check the server URL / proxy configuration`, ErrorCodes.INVALID_RESPONSE, {
|
|
829
|
+
statusCode: response.status,
|
|
830
|
+
context: {
|
|
831
|
+
url: ctx.fullUrl,
|
|
832
|
+
requestId: ctx.requestId,
|
|
833
|
+
contentType
|
|
834
|
+
},
|
|
835
|
+
originalError: error
|
|
836
|
+
});
|
|
837
|
+
return {
|
|
838
|
+
ok: false,
|
|
839
|
+
retryable: true,
|
|
840
|
+
cause: new ComputeError("Failed to parse JSON response", ErrorCodes.NETWORK_ERROR, {
|
|
841
|
+
statusCode: response.status,
|
|
842
|
+
context: {
|
|
843
|
+
url: ctx.fullUrl,
|
|
844
|
+
requestId: ctx.requestId
|
|
845
|
+
},
|
|
846
|
+
originalError: error
|
|
847
|
+
})
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
/** Throws a {@link ComputeError} for anything a retry can't fix. */
|
|
852
|
+
async function handleResponse(response, ctx, startTime) {
|
|
853
|
+
const responseTime = Math.round(performance.now() - startTime);
|
|
854
|
+
if (isRedirect(response)) {
|
|
855
|
+
await response.body?.cancel().catch(() => {});
|
|
856
|
+
throw redirectError(response, ctx);
|
|
857
|
+
}
|
|
858
|
+
if (!response.ok) return handleErrorStatus(response, ctx, responseTime);
|
|
859
|
+
logDebug(ctx, `completed in ${responseTime}ms`);
|
|
860
|
+
fireServerTiming(response, ctx.requestId, ctx.config.onServerTiming);
|
|
861
|
+
return parseSuccessBody(response, ctx);
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Matched against the probe's error string, which `probeServer` builds with undici's `cause` in
|
|
865
|
+
* it. A browser collapses every failure into an opaque "Failed to fetch", which reads as unknown.
|
|
866
|
+
*/
|
|
867
|
+
var REFUSED_PATTERN = /ECONNREFUSED|ERR_CONNECTION_REFUSED|connection refused/i;
|
|
868
|
+
var DNS_PATTERN = /ENOTFOUND|EAI_AGAIN|getaddrinfo|ERR_NAME_NOT_RESOLVED|dns/i;
|
|
869
|
+
var TIMEOUT_PATTERN = /TimeoutError|ETIMEDOUT|ECONNRESET|EHOSTUNREACH|ENETUNREACH|abort|timed? ?out/i;
|
|
870
|
+
/**
|
|
871
|
+
* Classify a `ComputeServerStats.probeServer` result.
|
|
872
|
+
*
|
|
873
|
+
* A DNS failure is treated as retryable even though a missing record won't fix
|
|
874
|
+
* itself: `EAI_AGAIN` is a *timeout* talking to the resolver, and the two are
|
|
875
|
+
* not distinguishable from the error alone. Retrying a genuinely-wrong hostname
|
|
876
|
+
* costs one window; giving up on a resolver hiccup breaks a server that is fine.
|
|
877
|
+
*
|
|
878
|
+
* @param probe - The `{ online, status?, error? }` a probe returned. An `online`
|
|
879
|
+
* probe is not a failure and yields `null`.
|
|
880
|
+
*/
|
|
881
|
+
function classifyProbeFailure(probe) {
|
|
882
|
+
if (probe.online) return null;
|
|
883
|
+
if (probe.status !== void 0) {
|
|
884
|
+
if (probe.status === 401 || probe.status === 403) return {
|
|
885
|
+
verdict: "unauthorized",
|
|
886
|
+
retryable: false,
|
|
887
|
+
summary: `The server rejected the liveness probe with HTTP ${probe.status} — check the API key.`
|
|
888
|
+
};
|
|
889
|
+
const retryable = probe.status >= 500;
|
|
890
|
+
return {
|
|
891
|
+
verdict: "http_error",
|
|
892
|
+
retryable,
|
|
893
|
+
summary: retryable ? `The server answered HTTP ${probe.status} — it may still be starting up.` : `The server answered HTTP ${probe.status}, which will not change on retry.`
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
const error = probe.error ?? "";
|
|
897
|
+
if (REFUSED_PATTERN.test(error)) return {
|
|
898
|
+
verdict: "refused",
|
|
899
|
+
retryable: false,
|
|
900
|
+
summary: "Connection refused — the host is reachable but nothing is listening on that port. Rhino.Compute is not running, or the URL names the wrong port."
|
|
901
|
+
};
|
|
902
|
+
if (DNS_PATTERN.test(error)) return {
|
|
903
|
+
verdict: "dns",
|
|
904
|
+
retryable: true,
|
|
905
|
+
summary: "The server hostname could not be resolved — check the URL and DNS."
|
|
906
|
+
};
|
|
907
|
+
if (TIMEOUT_PATTERN.test(error)) return {
|
|
908
|
+
verdict: "timeout",
|
|
909
|
+
retryable: true,
|
|
910
|
+
summary: "No response before the timeout — the machine may be powered off, blocked by a firewall, or still booting."
|
|
911
|
+
};
|
|
912
|
+
return {
|
|
913
|
+
verdict: "unknown",
|
|
914
|
+
retryable: true,
|
|
915
|
+
summary: error ? `The connection failed: ${error}` : "The connection failed."
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
async function attemptFetch(ctx, policy, attempt, isFinal) {
|
|
919
|
+
const { signal, cleanup } = composeSignal(ctx.config.signal, ctx.config.timeoutMs);
|
|
920
|
+
const startTime = performance.now();
|
|
921
|
+
const send = ctx.config.fetch ?? fetch;
|
|
922
|
+
try {
|
|
923
|
+
const response = await send(ctx.fullUrl, {
|
|
924
|
+
method: "POST",
|
|
925
|
+
body: ctx.body,
|
|
926
|
+
headers: ctx.headers,
|
|
927
|
+
signal,
|
|
928
|
+
redirect: "manual"
|
|
929
|
+
});
|
|
930
|
+
if (!isFinal && isRetryableStatus(response.status, policy)) {
|
|
931
|
+
await readBodyText(response, ERROR_BODY_MAX_BYTES).catch(() => {});
|
|
932
|
+
return {
|
|
933
|
+
ok: false,
|
|
934
|
+
retryable: true,
|
|
935
|
+
delayMs: retryDelay(response.headers.get("Retry-After"), attempt, policy),
|
|
936
|
+
cause: new ComputeError(`HTTP ${response.status} ${response.statusText} (will retry)`, response.status === 429 ? ErrorCodes.RATE_LIMIT : ErrorCodes.NETWORK_ERROR, {
|
|
937
|
+
statusCode: response.status,
|
|
938
|
+
context: ctx.errorContext
|
|
939
|
+
})
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
return await handleResponse(response, ctx, startTime);
|
|
943
|
+
} catch (error) {
|
|
944
|
+
return classifyFetchError(error, ctx);
|
|
945
|
+
} finally {
|
|
946
|
+
cleanup();
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
function classifyFetchError(error, ctx) {
|
|
950
|
+
if (error instanceof ComputeError) return {
|
|
951
|
+
ok: false,
|
|
952
|
+
retryable: false,
|
|
953
|
+
cause: error
|
|
954
|
+
};
|
|
955
|
+
if (ctx.config.signal?.aborted) return {
|
|
956
|
+
ok: false,
|
|
957
|
+
retryable: false,
|
|
958
|
+
cause: abortedByCaller(ctx.errorContext, error)
|
|
959
|
+
};
|
|
960
|
+
if (isAbortError(error)) {
|
|
961
|
+
const { timeoutMs } = ctx.config;
|
|
962
|
+
return {
|
|
963
|
+
ok: false,
|
|
964
|
+
retryable: true,
|
|
965
|
+
cause: typeof timeoutMs === "number" && timeoutMs > 0 ? new ComputeError(`Request timed out after ${timeoutMs}ms`, ErrorCodes.TIMEOUT_ERROR, {
|
|
966
|
+
context: {
|
|
967
|
+
...ctx.errorContext,
|
|
968
|
+
timeoutMs
|
|
969
|
+
},
|
|
970
|
+
originalError: error
|
|
971
|
+
}) : new ComputeError(`Request aborted by the runtime (${error.name}): ${error.message}`, ErrorCodes.NETWORK_ERROR, {
|
|
972
|
+
context: ctx.errorContext,
|
|
973
|
+
originalError: error
|
|
974
|
+
})
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
if (error instanceof TypeError) return {
|
|
978
|
+
ok: false,
|
|
979
|
+
retryable: true,
|
|
980
|
+
cause: typeof window !== "undefined" && typeof window.document !== "undefined" ? new ComputeError(`Request failed: ${error.message} — in a browser this usually means a CORS misconfiguration on the server (or a network failure; the browser does not distinguish them)`, ErrorCodes.CORS_ERROR, {
|
|
981
|
+
context: ctx.errorContext,
|
|
982
|
+
originalError: error
|
|
983
|
+
}) : new ComputeError(`Network error: ${error.message}`, ErrorCodes.NETWORK_ERROR, {
|
|
984
|
+
context: ctx.errorContext,
|
|
985
|
+
originalError: error
|
|
986
|
+
})
|
|
987
|
+
};
|
|
988
|
+
return {
|
|
989
|
+
ok: false,
|
|
990
|
+
retryable: false,
|
|
991
|
+
cause: new ComputeError(error instanceof Error ? error.message : String(error), ErrorCodes.UNKNOWN_ERROR, {
|
|
992
|
+
context: ctx.errorContext,
|
|
993
|
+
originalError: error
|
|
994
|
+
})
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
function requireNumber(name, value, isValid) {
|
|
998
|
+
if (value !== void 0 && !isValid(value)) throw new ComputeError(`${name} is not usable: ${value}`, ErrorCodes.INVALID_CONFIG, { context: { [name]: value } });
|
|
999
|
+
}
|
|
1000
|
+
/** `NaN` fails every comparison, so unchecked it disables a loop's exit or a limit. */
|
|
1001
|
+
function validateNumbers({ timeoutMs, maxResponseBytes, retry }) {
|
|
1002
|
+
const notNegative = (n) => n >= 0;
|
|
1003
|
+
requireNumber("timeoutMs", timeoutMs, (n) => n <= MAX_TIMEOUT_MS);
|
|
1004
|
+
requireNumber("maxResponseBytes", maxResponseBytes, notNegative);
|
|
1005
|
+
requireNumber("retry.attempts", retry?.attempts, (n) => notNegative(n) && Number.isFinite(n));
|
|
1006
|
+
requireNumber("retry.baseDelayMs", retry?.baseDelayMs, notNegative);
|
|
1007
|
+
requireNumber("retry.maxDelayMs", retry?.maxDelayMs, notNegative);
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* POST `args` as JSON to `<serverUrl>/<endpoint>` with retry, timeout and abort handling, and
|
|
1011
|
+
* return the parsed response. Most callers want a higher-level API.
|
|
1012
|
+
*
|
|
1013
|
+
* `R` names the expected response shape; nothing checks it, so the default `unknown` forces a
|
|
1014
|
+
* narrowing.
|
|
1015
|
+
*
|
|
1016
|
+
* @example
|
|
1017
|
+
* const response = await fetchCompute('grasshopper', args, {
|
|
1018
|
+
* serverUrl: 'https://my-server.com',
|
|
1019
|
+
* timeoutMs: 30_000,
|
|
1020
|
+
* retry: { attempts: 2 },
|
|
1021
|
+
* signal: controller.signal
|
|
1022
|
+
* });
|
|
1023
|
+
*/
|
|
1024
|
+
async function fetchCompute(endpoint, args, config) {
|
|
1025
|
+
const requestId = generateRequestId();
|
|
1026
|
+
let body;
|
|
1027
|
+
try {
|
|
1028
|
+
body = JSON.stringify(args);
|
|
1029
|
+
} catch (error) {
|
|
1030
|
+
throw new ComputeError(`Request body is not JSON-serializable: ${error instanceof Error ? error.message : String(error)}`, ErrorCodes.INVALID_INPUT, {
|
|
1031
|
+
context: {
|
|
1032
|
+
endpoint,
|
|
1033
|
+
requestId
|
|
1034
|
+
},
|
|
1035
|
+
originalError: error
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
const requestSize = utf8ByteLength(body);
|
|
1039
|
+
const serverUrl = validateServerUrl(config.serverUrl, { blockedHosts: [] });
|
|
1040
|
+
validateNumbers(config);
|
|
1041
|
+
const fullUrl = buildUrl(endpoint, serverUrl);
|
|
1042
|
+
const headers = buildHeaders(requestId, config);
|
|
1043
|
+
const retryPolicy = resolveRetryPolicy(config.retry);
|
|
1044
|
+
const totalAttempts = retryPolicy.attempts + 1;
|
|
1045
|
+
if (config.debug) {
|
|
1046
|
+
const sizeKb = (requestSize / 1024).toFixed(2);
|
|
1047
|
+
getLogger().debug(`Starting compute request [${requestId}]: ${endpoint} (${sizeKb}KB)`);
|
|
1048
|
+
}
|
|
1049
|
+
const ctx = {
|
|
1050
|
+
endpoint,
|
|
1051
|
+
body,
|
|
1052
|
+
requestSize,
|
|
1053
|
+
fullUrl,
|
|
1054
|
+
requestId,
|
|
1055
|
+
headers,
|
|
1056
|
+
config,
|
|
1057
|
+
errorContext: {
|
|
1058
|
+
serverUrl,
|
|
1059
|
+
url: fullUrl,
|
|
1060
|
+
endpoint,
|
|
1061
|
+
requestId,
|
|
1062
|
+
requestSize
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
for (let attempt = 0;; attempt++) {
|
|
1066
|
+
const isFinal = attempt >= retryPolicy.attempts;
|
|
1067
|
+
const result = await attemptFetch(ctx, retryPolicy, attempt, isFinal);
|
|
1068
|
+
if (result.ok) return result.value;
|
|
1069
|
+
if (isFinal || !result.retryable) throw result.cause;
|
|
1070
|
+
const delayMs = result.delayMs ?? backoffDelay(attempt, retryPolicy);
|
|
1071
|
+
if (config.debug) getLogger().debug(`Request [${requestId}] retrying after ${delayMs}ms (attempt ${attempt + 2}/${totalAttempts}): ${result.cause.code}`);
|
|
1072
|
+
try {
|
|
1073
|
+
await sleep(delayMs, config.signal);
|
|
1074
|
+
} catch {
|
|
1075
|
+
throw abortedByCaller(ctx.errorContext, result.cause);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function isDefinitionRef(definition) {
|
|
1080
|
+
return typeof definition === "object" && !(definition instanceof Uint8Array) && typeof definition.key === "string" && typeof definition.load === "function";
|
|
1081
|
+
}
|
|
1082
|
+
/** A URL is already a server-side reference: it is never uploaded or keyed by server cache key. */
|
|
1083
|
+
function isDefinitionUrl(definition) {
|
|
1084
|
+
return typeof definition === "string" && /^https?:\/\//i.test(definition);
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* The `Sub Folder` convention, as authored on Selva's Grasshopper file components.
|
|
1088
|
+
*
|
|
1089
|
+
* `::` nests, matching Rhino's layer separator (`ROOT::Panels`), and `/` and `\` are accepted
|
|
1090
|
+
* because people type them out of habit. The plugin normalizes to `/` before sending, so these
|
|
1091
|
+
* helpers also cover payloads from an older plugin that still emit `::`.
|
|
1092
|
+
*
|
|
1093
|
+
* The first segment is the **root**, which names the archive rather than becoming a folder inside
|
|
1094
|
+
* it: `ROOT::Panels` downloads as `ROOT.zip` containing `Panels/…`. Files sharing a root travel
|
|
1095
|
+
* together; distinct roots produce separate archives.
|
|
1096
|
+
*/
|
|
1097
|
+
/**
|
|
1098
|
+
* Split a `Sub Folder` value into folder segments; `/`, `\` and `::` all separate.
|
|
1099
|
+
*
|
|
1100
|
+
* Exported because anything rendering a folder tree has to agree with the archive on where the
|
|
1101
|
+
* boundaries are — splitting on `/` alone leaves `Main::Panels` as one literal segment and shows
|
|
1102
|
+
* a folder named after the separator.
|
|
1103
|
+
*/
|
|
1104
|
+
var subFolderSegments = (subFolder) => (subFolder ?? "").replace(/::/g, "/").replace(/\\/g, "/").split("/").map((segment) => segment.trim()).filter((segment) => segment !== "");
|
|
1105
|
+
/** First `Sub Folder` segment, or `''` when the file sits at the top level. */
|
|
1106
|
+
var rootOf = (file) => subFolderSegments(file.subFolder)[0] ?? "";
|
|
1107
|
+
/**
|
|
1108
|
+
* Everything below the root, as a `/`-joined path. The root names the archive, so repeating it
|
|
1109
|
+
* inside would nest it twice.
|
|
1110
|
+
*/
|
|
1111
|
+
var pathBelowRoot = (file) => subFolderSegments(file.subFolder).slice(1).join("/");
|
|
1112
|
+
/**
|
|
1113
|
+
* Group files by their `Sub Folder` root, preserving encounter order.
|
|
1114
|
+
*
|
|
1115
|
+
* Rootless files group under `''` — a caller naming archives supplies its own fallback for that
|
|
1116
|
+
* bucket. Useful beyond downloading: a consumer writing to disk gets the same grouping without
|
|
1117
|
+
* touching the DOM.
|
|
1118
|
+
*/
|
|
1119
|
+
var groupFilesByRoot = (files) => {
|
|
1120
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1121
|
+
for (const file of files) {
|
|
1122
|
+
const root = rootOf(file);
|
|
1123
|
+
const bucket = groups.get(root);
|
|
1124
|
+
if (bucket) bucket.push(file);
|
|
1125
|
+
else groups.set(root, [file]);
|
|
1126
|
+
}
|
|
1127
|
+
return Array.from(groups, ([root, grouped]) => ({
|
|
1128
|
+
root,
|
|
1129
|
+
files: grouped
|
|
1130
|
+
}));
|
|
1131
|
+
};
|
|
1132
|
+
/**
|
|
1133
|
+
* Make a root usable as a download filename: path separators and the characters Windows forbids
|
|
1134
|
+
* would otherwise reach the download attribute verbatim and produce a broken or misdirected save.
|
|
1135
|
+
*/
|
|
1136
|
+
var toArchiveName = (root) => {
|
|
1137
|
+
const safe = root.replace(/[/\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim().replace(/^\.+/, "");
|
|
1138
|
+
return safe === "" ? "files" : safe;
|
|
1139
|
+
};
|
|
1140
|
+
/**
|
|
1141
|
+
* Decode the files in a compute response, plus any external `additionalFiles`, without
|
|
1142
|
+
* downloading them. Never throws: an unnamed or undecodable item and a failed external fetch are
|
|
1143
|
+
* logged and dropped, the rest still resolve. Colliding archive paths are renamed
|
|
1144
|
+
* (`model.txt` → `model-2.txt`), so a consumer keying by `path` loses nothing.
|
|
1145
|
+
*/
|
|
1146
|
+
var extractFilesFromComputeResponse = async (downloadableFiles, additionalFiles = null) => {
|
|
1147
|
+
const processedFiles = decodeResponseFiles(downloadableFiles);
|
|
1148
|
+
if (additionalFiles) {
|
|
1149
|
+
const filesArray = Array.isArray(additionalFiles) ? additionalFiles : [additionalFiles];
|
|
1150
|
+
processedFiles.push(...await fetchRemoteFiles(filesArray));
|
|
1151
|
+
}
|
|
1152
|
+
const taken = /* @__PURE__ */ new Set();
|
|
1153
|
+
return processedFiles.map((file) => {
|
|
1154
|
+
const path = uniqueArchivePath(file.path, taken);
|
|
1155
|
+
taken.add(path);
|
|
1156
|
+
if (path === file.path) return file;
|
|
1157
|
+
getLogger().warn(`Duplicate archive path "${file.path}" — storing as "${path}".`);
|
|
1158
|
+
return {
|
|
1159
|
+
...file,
|
|
1160
|
+
path,
|
|
1161
|
+
fileName: path.slice(path.lastIndexOf("/") + 1)
|
|
1162
|
+
};
|
|
1163
|
+
});
|
|
1164
|
+
};
|
|
1165
|
+
/** Downloads files from a compute response as a ZIP archive. */
|
|
1166
|
+
var downloadFileData = async (downloadableFiles, fileFoldername, additionalFiles = null, options = {}) => {
|
|
1167
|
+
if (typeof document === "undefined" || typeof Blob === "undefined") throw new ComputeError("File download functionality is only available in browser environments. This function requires the DOM API (document, Blob).", ErrorCodes.BROWSER_ONLY, { context: {
|
|
1168
|
+
environment: typeof window !== "undefined" ? "browser (SSR)" : "Node.js",
|
|
1169
|
+
documentAvailable: typeof document !== "undefined",
|
|
1170
|
+
blobAvailable: typeof Blob !== "undefined"
|
|
1171
|
+
} });
|
|
1172
|
+
try {
|
|
1173
|
+
await createAndDownloadZip(await extractFilesFromComputeResponse(downloadableFiles, additionalFiles), fileFoldername, options.saveBlob ?? saveFile);
|
|
1174
|
+
} catch (err) {
|
|
1175
|
+
if (err instanceof ComputeError) throw err;
|
|
1176
|
+
throw new ComputeError("Failed to download files from compute response", ErrorCodes.INVALID_STATE, {
|
|
1177
|
+
context: {
|
|
1178
|
+
fileCount: downloadableFiles.length,
|
|
1179
|
+
zipName: fileFoldername
|
|
1180
|
+
},
|
|
1181
|
+
originalError: err
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
};
|
|
1185
|
+
/**
|
|
1186
|
+
* Download one archive per `Sub Folder` root (see {@link groupFilesByRoot}). Files with no root go
|
|
1187
|
+
* into `fallbackName`, so a definition that never sets `Sub Folder` downloads as one archive.
|
|
1188
|
+
*
|
|
1189
|
+
* Archives are saved one at a time: browsers discard concurrent downloads issued in the same tick.
|
|
1190
|
+
* More than one save per gesture may prompt the user for permission.
|
|
1191
|
+
*
|
|
1192
|
+
* @param downloadableFiles - `FileData` items from the compute response.
|
|
1193
|
+
* @param fallbackName - Archive name for files with no `Sub Folder` root.
|
|
1194
|
+
* @param additionalFiles - Extra files to package; they carry no root and join the fallback archive.
|
|
1195
|
+
* @param options - `saveBlob` replaces the anchor download for every archive.
|
|
1196
|
+
*/
|
|
1197
|
+
var downloadFileDataByRoot = async (downloadableFiles, fallbackName, additionalFiles = null, options = {}) => {
|
|
1198
|
+
const groups = groupFilesByRoot(downloadableFiles);
|
|
1199
|
+
if (groups.length === 0) {
|
|
1200
|
+
await downloadFileData([], fallbackName, additionalFiles, options);
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
const extrasRoot = (groups.find((group) => group.root === "") ?? groups[0]).root;
|
|
1204
|
+
for (const { root, files } of groups) await downloadFileData(root === "" ? files : files.map((file) => ({
|
|
1205
|
+
...file,
|
|
1206
|
+
subFolder: pathBelowRoot(file)
|
|
1207
|
+
})), root === "" ? fallbackName : toArchiveName(root), root === extrasRoot ? additionalFiles : null, options);
|
|
1208
|
+
};
|
|
1209
|
+
/**
|
|
1210
|
+
* Zip-slip defense for a server-controlled path: drop `.`, `..` and drive-prefixed segments
|
|
1211
|
+
* (`C:`, and `C:evil`, which is relative to that drive's working directory) so no entry escapes
|
|
1212
|
+
* the extraction directory. `''` when nothing safe remains.
|
|
1213
|
+
*/
|
|
1214
|
+
var sanitizeArchivePath = (raw) => subFolderSegments(raw).filter((segment) => segment !== "." && segment !== ".." && !/^[a-zA-Z]:/.test(segment)).join("/");
|
|
1215
|
+
/** The `isBase64Encoded` wire flag. Some server branches send booleans as strings (`"True"`). */
|
|
1216
|
+
var isBase64Flag = (flag) => flag === true || typeof flag === "string" && flag.trim().toLowerCase() === "true";
|
|
1217
|
+
var joinArchivePath = (subFolder, name) => subFolder !== "" ? `${subFolder}/${name}` : name;
|
|
1218
|
+
var decodeResponseFiles = (dataItems) => {
|
|
1219
|
+
const processedFiles = [];
|
|
1220
|
+
dataItems.forEach((item) => {
|
|
1221
|
+
const rawName = readField(item, "fileName") ?? "";
|
|
1222
|
+
const rawType = readField(item, "fileType") ?? "";
|
|
1223
|
+
const fileName = sanitizeArchivePath(`${rawName}${rawType}`);
|
|
1224
|
+
if (fileName === "") {
|
|
1225
|
+
getLogger().warn(`Skipping file with unusable name "${rawName}${rawType}": no safe archive path remains after sanitization.`);
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
const rawSubFolder = readField(item, "subFolder");
|
|
1229
|
+
const subFolder = rawSubFolder ? sanitizeArchivePath(rawSubFolder) : "";
|
|
1230
|
+
const filePath = joinArchivePath(subFolder, fileName);
|
|
1231
|
+
const data = readField(item, "data");
|
|
1232
|
+
if (typeof data !== "string" || data === "") {
|
|
1233
|
+
getLogger().warn(`Skipping file "${filePath}": item carries no usable data.`);
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
let content = data;
|
|
1237
|
+
if (isBase64Flag(readField(item, "isBase64Encoded"))) try {
|
|
1238
|
+
content = decodeBase64ToBinary(data);
|
|
1239
|
+
} catch (err) {
|
|
1240
|
+
getLogger().warn(`Skipping file "${filePath}": base64 decode failed.`, err);
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
const metadata = readField(item, "metadata");
|
|
1244
|
+
processedFiles.push({
|
|
1245
|
+
fileName,
|
|
1246
|
+
content,
|
|
1247
|
+
path: filePath,
|
|
1248
|
+
subFolder,
|
|
1249
|
+
...metadata ? { metadata } : {}
|
|
1250
|
+
});
|
|
1251
|
+
});
|
|
1252
|
+
return processedFiles;
|
|
1253
|
+
};
|
|
1254
|
+
/** One dead URL must degrade the batch, not stall it forever. */
|
|
1255
|
+
var REMOTE_FILE_TIMEOUT_MS = 3e4;
|
|
1256
|
+
var fetchRemoteFiles = async (refs) => {
|
|
1257
|
+
return (await Promise.all(refs.map(async (file) => {
|
|
1258
|
+
try {
|
|
1259
|
+
const response = await fetch(file.filePath, { signal: AbortSignal.timeout(REMOTE_FILE_TIMEOUT_MS) });
|
|
1260
|
+
if (!response.ok) {
|
|
1261
|
+
getLogger().warn(`Failed to fetch additional file: ${redactUrl(file.filePath)}`);
|
|
1262
|
+
return null;
|
|
1263
|
+
}
|
|
1264
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
1265
|
+
const safeName = sanitizeArchivePath(file.fileName);
|
|
1266
|
+
if (safeName === "") {
|
|
1267
|
+
getLogger().warn(`Skipping fetched file with unusable name: ${file.fileName}`);
|
|
1268
|
+
return null;
|
|
1269
|
+
}
|
|
1270
|
+
const subFolder = file.subFolder ? sanitizeArchivePath(file.subFolder) : "";
|
|
1271
|
+
return {
|
|
1272
|
+
fileName: safeName,
|
|
1273
|
+
content: new Uint8Array(arrayBuffer),
|
|
1274
|
+
path: joinArchivePath(subFolder, safeName),
|
|
1275
|
+
subFolder
|
|
1276
|
+
};
|
|
1277
|
+
} catch (error) {
|
|
1278
|
+
const reason = error instanceof Error ? error.name : "unknown error";
|
|
1279
|
+
getLogger().error(`Error fetching additional file ${redactUrl(file.filePath)}: ${reason}`);
|
|
1280
|
+
return null;
|
|
1281
|
+
}
|
|
1282
|
+
}))).filter((f) => f !== null);
|
|
1283
|
+
};
|
|
1284
|
+
async function createAndDownloadZip(files, zipName, save) {
|
|
1285
|
+
const { zip, strToU8 } = await import('./esm.js-CRiT7ECX.js');
|
|
1286
|
+
const taken = new Set(files.map((file) => file.path));
|
|
1287
|
+
const zipData = {};
|
|
1288
|
+
for (const file of files) {
|
|
1289
|
+
const path = file.path === "__proto__" ? uniqueArchivePath(file.path, taken) : file.path;
|
|
1290
|
+
taken.add(path);
|
|
1291
|
+
zipData[path] = typeof file.content === "string" ? strToU8(file.content) : file.content;
|
|
1292
|
+
}
|
|
1293
|
+
const zipped = await new Promise((resolve, reject) => {
|
|
1294
|
+
zip(zipData, { level: 6 }, (err, data) => err ? reject(err) : resolve(data));
|
|
1295
|
+
});
|
|
1296
|
+
await save(new Blob([zipped], { type: "application/zip" }), `${zipName}.zip`);
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* First archive path not already taken in `taken`, disambiguating with a
|
|
1300
|
+
* numeric suffix before the extension: `dir/model.txt` → `dir/model-2.txt`.
|
|
1301
|
+
*/
|
|
1302
|
+
function uniqueArchivePath(path, taken) {
|
|
1303
|
+
if (!taken.has(path)) return path;
|
|
1304
|
+
const slash = path.lastIndexOf("/");
|
|
1305
|
+
const dot = path.lastIndexOf(".");
|
|
1306
|
+
const stemEnd = dot > slash ? dot : path.length;
|
|
1307
|
+
const stem = path.slice(0, stemEnd);
|
|
1308
|
+
const ext = path.slice(stemEnd);
|
|
1309
|
+
for (let i = 2;; i++) {
|
|
1310
|
+
const candidate = `${stem}-${i}${ext}`;
|
|
1311
|
+
if (!taken.has(candidate)) return candidate;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
function saveFile(blob, filename) {
|
|
1315
|
+
const url = URL.createObjectURL(blob);
|
|
1316
|
+
const a = document.createElement("a");
|
|
1317
|
+
a.href = url;
|
|
1318
|
+
a.download = filename;
|
|
1319
|
+
document.body.appendChild(a);
|
|
1320
|
+
a.click();
|
|
1321
|
+
a.remove();
|
|
1322
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e4);
|
|
1323
|
+
}
|
|
1324
|
+
// ../compute/dist/grasshopper.js
|
|
1325
|
+
/**
|
|
1326
|
+
* Server health and control: liveness, version, child processes, cache purges.
|
|
1327
|
+
*
|
|
1328
|
+
* @example
|
|
1329
|
+
* ```typescript
|
|
1330
|
+
* const stats = new ComputeServerStats('http://localhost:6500', 'your-api-key');
|
|
1331
|
+
*
|
|
1332
|
+
* try {
|
|
1333
|
+
* const isOnline = await stats.isServerOnline();
|
|
1334
|
+
* const children = await stats.getActiveChildren();
|
|
1335
|
+
* const version = await stats.getVersion();
|
|
1336
|
+
*
|
|
1337
|
+
* // Or get everything at once
|
|
1338
|
+
* const allStats = await stats.getServerStats();
|
|
1339
|
+
* } finally {
|
|
1340
|
+
* await stats.dispose(); // Clean up resources
|
|
1341
|
+
* }
|
|
1342
|
+
* ```
|
|
1343
|
+
*/
|
|
1344
|
+
var ComputeServerStats = class ComputeServerStats {
|
|
1345
|
+
serverUrl;
|
|
1346
|
+
headers;
|
|
1347
|
+
disposed = false;
|
|
1348
|
+
activeMonitors = /* @__PURE__ */ new Set();
|
|
1349
|
+
/** Timeout (ms) for the fast read/monitoring endpoints. */
|
|
1350
|
+
static DEFAULT_TIMEOUT_MS = 5e3;
|
|
1351
|
+
/** Timeout (ms) for child-lifecycle POSTs — a cold Windows child can take ~30s to spawn. */
|
|
1352
|
+
static LIFECYCLE_TIMEOUT_MS = 6e4;
|
|
1353
|
+
/** Floor for `monitor()`'s `intervalMs` — anything lower hot-loops the server. */
|
|
1354
|
+
static MIN_MONITOR_INTERVAL_MS = 100;
|
|
1355
|
+
/** Every control-plane answer is a count, a version or a short map. */
|
|
1356
|
+
static MAX_BODY_BYTES = 1 << 20;
|
|
1357
|
+
/**
|
|
1358
|
+
* @param serverUrl - Base URL of the Rhino Compute server with http:// or https:// scheme (e.g., 'http://localhost:6500')
|
|
1359
|
+
* @param auth - An API key, or the same auth fields a solve's `ComputeConfig` carries
|
|
1360
|
+
* (`apiKey`, `apiKeyHeader`, `authToken`, `headers`).
|
|
1361
|
+
*/
|
|
1362
|
+
constructor(serverUrl, auth) {
|
|
1363
|
+
this.serverUrl = validateServerUrl(serverUrl);
|
|
1364
|
+
this.headers = buildAuthHeaders(typeof auth === "string" ? { apiKey: auth } : auth ?? {});
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* Aborts after `timeoutMs` so a hung connection can't stall a probe or `monitor()`; `0` disables
|
|
1368
|
+
* it. Redirects are not followed: fetch would carry the API key header to the target.
|
|
1369
|
+
*/
|
|
1370
|
+
async fetchWithTimeout(url, init = {}, timeoutMs = ComputeServerStats.DEFAULT_TIMEOUT_MS) {
|
|
1371
|
+
const { signal, cleanup } = composeSignal(init.signal ?? void 0, timeoutMs);
|
|
1372
|
+
try {
|
|
1373
|
+
return await fetch(url, {
|
|
1374
|
+
...init,
|
|
1375
|
+
headers: init.method === "POST" ? withJsonContentType(this.headers) : this.headers,
|
|
1376
|
+
redirect: "manual",
|
|
1377
|
+
signal
|
|
1378
|
+
});
|
|
1379
|
+
} finally {
|
|
1380
|
+
cleanup();
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1384
|
+
* The response body of `path`, or `null` (logged) on a non-2xx or a network
|
|
1385
|
+
* failure. Throws only when disposed.
|
|
1386
|
+
*/
|
|
1387
|
+
async getText(path, init = {}, timeoutMs = ComputeServerStats.DEFAULT_TIMEOUT_MS) {
|
|
1388
|
+
this.ensureNotDisposed();
|
|
1389
|
+
const label = `${init.method ?? "GET"} ${path}`;
|
|
1390
|
+
try {
|
|
1391
|
+
const response = await this.fetchWithTimeout(`${this.serverUrl}${path}`, init, timeoutMs);
|
|
1392
|
+
if (!response.ok) {
|
|
1393
|
+
getLogger().warn(`[ComputeServerStats] ${label} failed:`, response.status);
|
|
1394
|
+
await response.body?.cancel().catch(() => {});
|
|
1395
|
+
return null;
|
|
1396
|
+
}
|
|
1397
|
+
const { text, truncated } = await readBodyText(response, ComputeServerStats.MAX_BODY_BYTES);
|
|
1398
|
+
if (truncated) {
|
|
1399
|
+
getLogger().warn(`[ComputeServerStats] ${label} answered with an oversized body`);
|
|
1400
|
+
return null;
|
|
1401
|
+
}
|
|
1402
|
+
return text;
|
|
1403
|
+
} catch (err) {
|
|
1404
|
+
getLogger().warn(`[ComputeServerStats] ${label} errored:`, err);
|
|
1405
|
+
return null;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
/**
|
|
1409
|
+
* Check if the server is online.
|
|
1410
|
+
*
|
|
1411
|
+
* This is a single-sample probe: it returns `true` only on a 2xx or a redirect
|
|
1412
|
+
* from the proxy liveness root `/`, and `false` for every other outcome (4xx/5xx,
|
|
1413
|
+
* network error, or timeout). A cold or briefly-busy-but-up server can therefore
|
|
1414
|
+
* read as offline — callers that gate on this (e.g. client construction)
|
|
1415
|
+
* should retry rather than treat a single `false` as authoritative.
|
|
1416
|
+
*
|
|
1417
|
+
* @param timeoutMs - Abort the probe after this many ms (default: 5000).
|
|
1418
|
+
* Pass `0` to disable the timeout. Prevents a hung connection from
|
|
1419
|
+
* stalling the caller indefinitely.
|
|
1420
|
+
*/
|
|
1421
|
+
async isServerOnline(timeoutMs = ComputeServerStats.DEFAULT_TIMEOUT_MS) {
|
|
1422
|
+
return (await this.probeServer(timeoutMs)).online;
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Detailed liveness probe backing {@link isServerOnline}.
|
|
1426
|
+
*
|
|
1427
|
+
* Reports what the probe actually saw so callers can distinguish "connection
|
|
1428
|
+
* failed" (`error` set) from "server answered non-2xx" (`status` set) — e.g.
|
|
1429
|
+
* a 401 from a proxy that requires an API key is a misconfiguration, not an
|
|
1430
|
+
* offline server. Same single-sample caveat as {@link isServerOnline}.
|
|
1431
|
+
*
|
|
1432
|
+
* @param timeoutMs - Abort the probe after this many ms (default: 5000).
|
|
1433
|
+
* Pass `0` to disable the timeout.
|
|
1434
|
+
* @param signal - Cancels the probe, which then reports the abort as its `error`.
|
|
1435
|
+
* @returns `online` plus either the HTTP `status` the server answered with,
|
|
1436
|
+
* or the `error` the connection attempt failed with.
|
|
1437
|
+
*/
|
|
1438
|
+
async probeServer(timeoutMs = ComputeServerStats.DEFAULT_TIMEOUT_MS, signal) {
|
|
1439
|
+
this.ensureNotDisposed();
|
|
1440
|
+
const url = `${this.serverUrl}/`;
|
|
1441
|
+
try {
|
|
1442
|
+
const response = await this.fetchWithTimeout(url, {
|
|
1443
|
+
method: "GET",
|
|
1444
|
+
signal
|
|
1445
|
+
}, timeoutMs);
|
|
1446
|
+
await response.body?.cancel().catch(() => {});
|
|
1447
|
+
return {
|
|
1448
|
+
online: response.ok || isRedirect(response),
|
|
1449
|
+
status: response.status
|
|
1450
|
+
};
|
|
1451
|
+
} catch (err) {
|
|
1452
|
+
const error = describeProbeError(err);
|
|
1453
|
+
getLogger().debug(`[ComputeServerStats] Fetch error: ${error}`);
|
|
1454
|
+
return {
|
|
1455
|
+
online: false,
|
|
1456
|
+
error
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Get the number of active child processes on the server.
|
|
1462
|
+
*
|
|
1463
|
+
* By default the proxy's `/activechildren` endpoint will *spawn* children up
|
|
1464
|
+
* to the configured count if none are running, then report the count — which
|
|
1465
|
+
* wakes (and bills) an idle server. Pass `{ initialize: false }` for a passive
|
|
1466
|
+
* read that reports the current count without spawning; use this for
|
|
1467
|
+
* monitoring or before a purge/probe where you must not wake the server.
|
|
1468
|
+
*
|
|
1469
|
+
* @param options.initialize - When `false`, append `?initialize=false` so the
|
|
1470
|
+
* server reports without spawning. Defaults to `true` (the server's default).
|
|
1471
|
+
* @returns Number of active children, or null if unavailable
|
|
1472
|
+
*/
|
|
1473
|
+
async getActiveChildren(options = {}) {
|
|
1474
|
+
const { initialize = true } = options;
|
|
1475
|
+
const body = initialize ? await this.getText("/activechildren", {}, ComputeServerStats.LIFECYCLE_TIMEOUT_MS) : await this.getText("/activechildren?initialize=false");
|
|
1476
|
+
if (body === null) return null;
|
|
1477
|
+
const text = body.trim();
|
|
1478
|
+
if (!/^\d+$/.test(text)) {
|
|
1479
|
+
getLogger().warn("[ComputeServerStats] /activechildren answered with a non-numeric body");
|
|
1480
|
+
return null;
|
|
1481
|
+
}
|
|
1482
|
+
return parseInt(text, 10);
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Get the server version information.
|
|
1486
|
+
*
|
|
1487
|
+
* @returns Version object with rhino, compute, and git_sha, or null if unavailable
|
|
1488
|
+
*/
|
|
1489
|
+
async getVersion() {
|
|
1490
|
+
const text = await this.getText("/version");
|
|
1491
|
+
if (text === null) return null;
|
|
1492
|
+
const json = tryParseJson(text);
|
|
1493
|
+
if (json == null) return {
|
|
1494
|
+
rhino: text,
|
|
1495
|
+
compute: "",
|
|
1496
|
+
git_sha: null
|
|
1497
|
+
};
|
|
1498
|
+
return {
|
|
1499
|
+
rhino: json.rhino ?? "",
|
|
1500
|
+
compute: json.compute ?? "",
|
|
1501
|
+
git_sha: json.git_sha ?? null
|
|
1502
|
+
};
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Get the plugins installed on the server.
|
|
1506
|
+
*
|
|
1507
|
+
* Returns a `name → version` map of non-core plugins the server has loaded,
|
|
1508
|
+
* or `null` if the request failed. Pass `kind` to choose which inventory:
|
|
1509
|
+
* `'gh'` (default) lists Grasshopper add-on assemblies via
|
|
1510
|
+
* `/plugins/gh/installed`; `'rhino'` lists Rhino plugins via
|
|
1511
|
+
* `/plugins/rhino/installed`. Plugins that ship with Rhino / are core
|
|
1512
|
+
* libraries are excluded by the server.
|
|
1513
|
+
*
|
|
1514
|
+
* @param kind - `'gh'` for Grasshopper add-ons (default) or `'rhino'` for Rhino plugins.
|
|
1515
|
+
* @returns Map of plugin name to version, or `null` on failure.
|
|
1516
|
+
*
|
|
1517
|
+
* @example
|
|
1518
|
+
* ```ts
|
|
1519
|
+
* const gh = await stats.getInstalledPlugins(); // Grasshopper add-ons
|
|
1520
|
+
* const selvaVersion = gh?.['Selva'] ?? null;
|
|
1521
|
+
* ```
|
|
1522
|
+
*/
|
|
1523
|
+
async getInstalledPlugins(kind = "gh") {
|
|
1524
|
+
const text = await this.getText(`/plugins/${kind}/installed`);
|
|
1525
|
+
const json = text === null ? void 0 : tryParseJson(text);
|
|
1526
|
+
return json && typeof json === "object" ? json : null;
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
* Get comprehensive server statistics.
|
|
1530
|
+
* Fetches all available server information in parallel.
|
|
1531
|
+
*
|
|
1532
|
+
* @returns Object containing server status and available stats
|
|
1533
|
+
*/
|
|
1534
|
+
async getServerStats() {
|
|
1535
|
+
this.ensureNotDisposed();
|
|
1536
|
+
if (!await this.isServerOnline()) return { isOnline: false };
|
|
1537
|
+
const [version, activeChildren] = await Promise.all([this.getVersion(), this.getActiveChildren({ initialize: false })]);
|
|
1538
|
+
return {
|
|
1539
|
+
isOnline: true,
|
|
1540
|
+
...version && { version },
|
|
1541
|
+
...activeChildren !== null && { activeChildren }
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* Purge the server's solve-results / URL-data cache.
|
|
1546
|
+
*
|
|
1547
|
+
* POSTs to `cache/purge` and returns the number of entries removed, or `null`
|
|
1548
|
+
* if the request failed. This clears cached solve responses and fetched
|
|
1549
|
+
* definition-URL data; it does NOT evict the definition cache (active
|
|
1550
|
+
* `pointer` references stay valid).
|
|
1551
|
+
*
|
|
1552
|
+
* **Caveat:** `cache/purge` is forwarded by the rhino.compute proxy to a
|
|
1553
|
+
* single round-robin-selected child, so in a multi-child deployment one call
|
|
1554
|
+
* purges one child's cache. Call repeatedly (or size the pool to 1) if you
|
|
1555
|
+
* need a fleet-wide purge.
|
|
1556
|
+
*
|
|
1557
|
+
* @returns Number of entries removed, or `null` on failure.
|
|
1558
|
+
*
|
|
1559
|
+
* @example
|
|
1560
|
+
* ```ts
|
|
1561
|
+
* const removed = await stats.purgeCache();
|
|
1562
|
+
* if (removed !== null) console.log(`Purged ${removed} cached solves`);
|
|
1563
|
+
* ```
|
|
1564
|
+
*/
|
|
1565
|
+
async purgeCache() {
|
|
1566
|
+
const text = await this.getText("/cache/purge", { method: "POST" });
|
|
1567
|
+
const purged = (text === null ? void 0 : tryParseJson(text))?.purged;
|
|
1568
|
+
return typeof purged === "number" ? purged : null;
|
|
1569
|
+
}
|
|
1570
|
+
/**
|
|
1571
|
+
* Best-effort fleet-wide cache purge across a multi-child deployment.
|
|
1572
|
+
*
|
|
1573
|
+
* A single {@link purgeCache} POST is forwarded by the rhino.compute proxy to
|
|
1574
|
+
* just ONE round-robin-selected child, so the other children keep serving
|
|
1575
|
+
* stale cached solves. There is no proxy endpoint that addresses children
|
|
1576
|
+
* individually, so this method reads the active child count (passively, never
|
|
1577
|
+
* spawning) and fires `2 × count` sequential purges, relying on the proxy's
|
|
1578
|
+
* round-robin to spread the hits across the pool.
|
|
1579
|
+
*
|
|
1580
|
+
* **This is best-effort, not a guarantee.** Round-robin can revisit one child
|
|
1581
|
+
* and skip another; under concurrent traffic the rotation drifts. The result's
|
|
1582
|
+
* `confident` flag is `true` only when the server reports a single child (where
|
|
1583
|
+
* one purge is exact) — surface it so callers don't over-promise. For a hard
|
|
1584
|
+
* fleet-wide guarantee, run the deployment at `--childcount 1` or add a
|
|
1585
|
+
* server-side fan-out endpoint.
|
|
1586
|
+
*
|
|
1587
|
+
* @returns `{ totalPurged, calls, children, confident }`, or `null` if the
|
|
1588
|
+
* child count couldn't be read (server unreachable). `totalPurged` sums the
|
|
1589
|
+
* per-call counts; `calls` is how many purges were issued; `children` is the
|
|
1590
|
+
* reported pool size; `confident` is `true` only at a single-child pool.
|
|
1591
|
+
*
|
|
1592
|
+
* @example
|
|
1593
|
+
* ```ts
|
|
1594
|
+
* const r = await stats.purgeAllChildren();
|
|
1595
|
+
* if (r && !r.confident) {
|
|
1596
|
+
* console.warn(`Purged ~${r.totalPurged} across ${r.children} children (best-effort)`);
|
|
1597
|
+
* }
|
|
1598
|
+
* ```
|
|
1599
|
+
*/
|
|
1600
|
+
async purgeAllChildren() {
|
|
1601
|
+
this.ensureNotDisposed();
|
|
1602
|
+
const children = await this.getActiveChildren({ initialize: false });
|
|
1603
|
+
if (children === null) {
|
|
1604
|
+
getLogger().warn("[ComputeServerStats] purgeAllChildren: could not read child count");
|
|
1605
|
+
return null;
|
|
1606
|
+
}
|
|
1607
|
+
if (children === 0) return {
|
|
1608
|
+
totalPurged: 0,
|
|
1609
|
+
calls: 0,
|
|
1610
|
+
children: 0,
|
|
1611
|
+
confident: true
|
|
1612
|
+
};
|
|
1613
|
+
const calls = children * 2;
|
|
1614
|
+
let totalPurged = 0;
|
|
1615
|
+
for (let i = 0; i < calls; i++) {
|
|
1616
|
+
const purged = await this.purgeCache();
|
|
1617
|
+
if (purged !== null) totalPurged += purged;
|
|
1618
|
+
}
|
|
1619
|
+
return {
|
|
1620
|
+
totalPurged,
|
|
1621
|
+
calls,
|
|
1622
|
+
children,
|
|
1623
|
+
confident: children === 1
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Get the server's current UTC clock.
|
|
1628
|
+
*
|
|
1629
|
+
* GETs `/servertime`, which the server emits as a JSON-encoded ISO-8601
|
|
1630
|
+
* timestamp (e.g. `"2026-06-18T08:30:00Z"`). Useful for detecting clock skew
|
|
1631
|
+
* between caller and server. Returns `null` if the request failed or the body
|
|
1632
|
+
* isn't a parseable date.
|
|
1633
|
+
*
|
|
1634
|
+
* @returns A `Date` for the server's UTC time, or `null` on failure.
|
|
1635
|
+
*/
|
|
1636
|
+
async getServerTime() {
|
|
1637
|
+
const text = await this.getText("/servertime");
|
|
1638
|
+
if (text === null) return null;
|
|
1639
|
+
const date = new Date(text.trim().replace(/^"|"$/g, ""));
|
|
1640
|
+
return isNaN(date.getTime()) ? null : date;
|
|
1641
|
+
}
|
|
1642
|
+
/**
|
|
1643
|
+
* Get how long the rhino.compute proxy has been idle.
|
|
1644
|
+
*
|
|
1645
|
+
* GETs `/idlespan` on the proxy, which returns the seconds elapsed since the
|
|
1646
|
+
* last request was forwarded to a compute child. This is a proxy-level metric
|
|
1647
|
+
* (not proxied to a child) used by autoscalers to decide when a node can be
|
|
1648
|
+
* drained. Returns `null` if unavailable.
|
|
1649
|
+
*
|
|
1650
|
+
* @returns Idle time in seconds, or `null` on failure.
|
|
1651
|
+
*/
|
|
1652
|
+
async getIdleSpan() {
|
|
1653
|
+
const text = await this.getText("/idlespan");
|
|
1654
|
+
if (text === null) return null;
|
|
1655
|
+
const seconds = parseFloat(text.trim());
|
|
1656
|
+
return isNaN(seconds) ? null : seconds;
|
|
1657
|
+
}
|
|
1658
|
+
/**
|
|
1659
|
+
* Fill the compute child pool up to the server's configured baseline.
|
|
1660
|
+
*
|
|
1661
|
+
* POSTs `/launch-children`. No-op when the pool is already at or above the
|
|
1662
|
+
* configured `--childcount`. Returns `{ spawned, active }` — how many children
|
|
1663
|
+
* were started and the resulting child count — or `null` on failure.
|
|
1664
|
+
*
|
|
1665
|
+
* To raise capacity above the baseline use {@link launchChild}; the baseline
|
|
1666
|
+
* itself can only be changed by restarting rhino.compute.
|
|
1667
|
+
*
|
|
1668
|
+
* @returns `{ spawned, active }`, or `null` on failure.
|
|
1669
|
+
*/
|
|
1670
|
+
async launchChildren() {
|
|
1671
|
+
return this.postJson("/launch-children");
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* Add a single compute child to the pool, optionally on a specific port.
|
|
1675
|
+
*
|
|
1676
|
+
* POSTs `/launch-child` (with `?port=N` when `port` is given). Unlike
|
|
1677
|
+
* {@link launchChildren}, this can push the pool above the baseline, up to the
|
|
1678
|
+
* server's `MaxChildren` cap. Returns `{ spawned: [port] }` on success, or
|
|
1679
|
+
* `null` on failure (server replies 400 for a bad port, 409 if the port is in
|
|
1680
|
+
* use, 503 at the max-children cap).
|
|
1681
|
+
*
|
|
1682
|
+
* @param port - Optional specific port to launch on; otherwise the next free one.
|
|
1683
|
+
* @returns `{ spawned }` listing the launched port, or `null` on failure.
|
|
1684
|
+
*/
|
|
1685
|
+
async launchChild(port) {
|
|
1686
|
+
const path = port === void 0 ? "/launch-child" : `/launch-child?port=${port}`;
|
|
1687
|
+
return this.postJson(path);
|
|
1688
|
+
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Gracefully shut down compute children without respawning them.
|
|
1691
|
+
*
|
|
1692
|
+
* POSTs `/shutdown-children`. With no `port` it shuts down every child; with
|
|
1693
|
+
* `port` it targets just that one. Children do not respawn, but the next
|
|
1694
|
+
* `/grasshopper` request auto-spawns the pool back to the baseline. Returns
|
|
1695
|
+
* `{ shutdown, active }` — how many were stopped and the remaining count — or
|
|
1696
|
+
* `null` on failure.
|
|
1697
|
+
*
|
|
1698
|
+
* @param port - Optional port to target; omit to shut down all children.
|
|
1699
|
+
* @returns `{ shutdown, active }`, or `null` on failure.
|
|
1700
|
+
*/
|
|
1701
|
+
async shutdownChildren(port) {
|
|
1702
|
+
const path = port === void 0 ? "/shutdown-children" : `/shutdown-children?port=${port}`;
|
|
1703
|
+
return this.postJson(path);
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Shut down compute children and respawn replacements (rolling restart).
|
|
1707
|
+
*
|
|
1708
|
+
* POSTs `/recycle-children`. With no `port` it recycles every child; with
|
|
1709
|
+
* `port` it recycles just that one. The server recycles sequentially (each
|
|
1710
|
+
* replacement is serving before the next child is stopped) so the pool never
|
|
1711
|
+
* drops to zero mid-recycle. Returns `{ shutdown, spawned, active }`, or
|
|
1712
|
+
* `null` on failure.
|
|
1713
|
+
*
|
|
1714
|
+
* @param port - Optional port to target; omit to recycle all children.
|
|
1715
|
+
* @returns `{ shutdown, spawned, active }`, or `null` on failure.
|
|
1716
|
+
*/
|
|
1717
|
+
async recycleChildren(port) {
|
|
1718
|
+
const path = port === void 0 ? "/recycle-children" : `/recycle-children?port=${port}`;
|
|
1719
|
+
return this.postJson(path);
|
|
1720
|
+
}
|
|
1721
|
+
/** A child-lifecycle POST: a spawn or recycle can take ~30 s. */
|
|
1722
|
+
async postJson(path) {
|
|
1723
|
+
const text = await this.getText(path, { method: "POST" }, ComputeServerStats.LIFECYCLE_TIMEOUT_MS);
|
|
1724
|
+
return text === null ? null : tryParseJson(text) ?? null;
|
|
1725
|
+
}
|
|
1726
|
+
/**
|
|
1727
|
+
* Continuously monitor server stats at specified interval.
|
|
1728
|
+
*
|
|
1729
|
+
* @param callback - Function called with stats on each interval
|
|
1730
|
+
* @param intervalMs - Milliseconds between checks (default: 5000). Must be a
|
|
1731
|
+
* finite number of at least 100 ms — lower values would hot-loop the server.
|
|
1732
|
+
* @returns Function to stop monitoring
|
|
1733
|
+
* @throws {ComputeError} `INVALID_CONFIG` if `intervalMs` is not a finite number >= 100.
|
|
1734
|
+
*
|
|
1735
|
+
* @example
|
|
1736
|
+
* ```typescript
|
|
1737
|
+
* const stopMonitoring = stats.monitor((data) => {
|
|
1738
|
+
* console.log('Server stats:', data);
|
|
1739
|
+
* }, 3000);
|
|
1740
|
+
*
|
|
1741
|
+
* // Later...
|
|
1742
|
+
* stopMonitoring();
|
|
1743
|
+
* ```
|
|
1744
|
+
*/
|
|
1745
|
+
monitor(callback, intervalMs = 5e3) {
|
|
1746
|
+
this.ensureNotDisposed();
|
|
1747
|
+
if (!Number.isFinite(intervalMs) || intervalMs < ComputeServerStats.MIN_MONITOR_INTERVAL_MS) throw new ComputeError(`monitor() intervalMs must be a finite number >= ${ComputeServerStats.MIN_MONITOR_INTERVAL_MS}ms, got ${intervalMs}. Sub-${ComputeServerStats.MIN_MONITOR_INTERVAL_MS}ms polling would hot-loop the server.`, ErrorCodes.INVALID_CONFIG, { context: { intervalMs } });
|
|
1748
|
+
let active = true;
|
|
1749
|
+
let currentTimeoutId = null;
|
|
1750
|
+
getLogger().info(`🔄 Starting server stats monitoring every ${intervalMs}ms`);
|
|
1751
|
+
const check = async () => {
|
|
1752
|
+
currentTimeoutId = null;
|
|
1753
|
+
if (!active || this.disposed) return;
|
|
1754
|
+
try {
|
|
1755
|
+
const _stats = await this.getServerStats();
|
|
1756
|
+
if (!active || this.disposed) return;
|
|
1757
|
+
try {
|
|
1758
|
+
callback(_stats);
|
|
1759
|
+
} catch (err) {
|
|
1760
|
+
getLogger().error("[ComputeServerStats] Monitor callback threw:", err);
|
|
1761
|
+
}
|
|
1762
|
+
} catch (err) {
|
|
1763
|
+
if (!active || this.disposed) getLogger().debug("[ComputeServerStats] Monitor poll cancelled during shutdown:", err);
|
|
1764
|
+
else getLogger().error("[ComputeServerStats] Failed to fetch stats during monitor:", err);
|
|
1765
|
+
}
|
|
1766
|
+
if (active && !this.disposed) currentTimeoutId = setTimeout(() => void check(), intervalMs);
|
|
1767
|
+
};
|
|
1768
|
+
const stopMonitoring = () => {
|
|
1769
|
+
active = false;
|
|
1770
|
+
if (currentTimeoutId !== null) {
|
|
1771
|
+
clearTimeout(currentTimeoutId);
|
|
1772
|
+
currentTimeoutId = null;
|
|
1773
|
+
}
|
|
1774
|
+
this.activeMonitors.delete(stopMonitoring);
|
|
1775
|
+
};
|
|
1776
|
+
this.activeMonitors.add(stopMonitoring);
|
|
1777
|
+
check();
|
|
1778
|
+
return stopMonitoring;
|
|
1779
|
+
}
|
|
1780
|
+
/**
|
|
1781
|
+
* Disposes of all resources and stops all active monitors.
|
|
1782
|
+
* Call this when you're done using the stats instance.
|
|
1783
|
+
*/
|
|
1784
|
+
async dispose() {
|
|
1785
|
+
if (this.disposed) return;
|
|
1786
|
+
this.disposed = true;
|
|
1787
|
+
for (const stopMonitor of this.activeMonitors) stopMonitor();
|
|
1788
|
+
this.activeMonitors.clear();
|
|
1789
|
+
}
|
|
1790
|
+
ensureNotDisposed() {
|
|
1791
|
+
if (this.disposed) throw new ComputeError("ComputeServerStats has been disposed and cannot be used", ErrorCodes.INVALID_STATE);
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
/**
|
|
1795
|
+
* undici reports every connection failure as `TypeError: fetch failed` and keeps what happened on
|
|
1796
|
+
* `cause`, whose message is empty when several addresses failed: its `code` is the one sure field.
|
|
1797
|
+
*/
|
|
1798
|
+
function describeProbeError(err) {
|
|
1799
|
+
if (!(err instanceof Error)) return String(err);
|
|
1800
|
+
const summary = `${err.name}: ${err.message}`;
|
|
1801
|
+
if (!(err.cause instanceof Error)) return summary;
|
|
1802
|
+
const { code } = err.cause;
|
|
1803
|
+
return `${summary}: ${typeof code === "string" ? `${code} ` : ""}${err.cause.message}`.trim();
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Server message for a `pointer` it can't resolve (evicted, or a different child in the pool).
|
|
1807
|
+
* Production servers scrub it, so the `definition_not_cached` code is the reliable signal; this
|
|
1808
|
+
* substring covers debug-mode servers and forks that emit no code.
|
|
1809
|
+
*/
|
|
1810
|
+
var DEFINITION_LOAD_FAILED = "Unable to load grasshopper definition";
|
|
1811
|
+
/** `core/` knows no backend's wire codes, so every Grasshopper request passes these in. */
|
|
1812
|
+
var GRASSHOPPER_SERVER_ERROR_CODES = { definition_not_cached: ErrorCodes.DEFINITION_NOT_CACHED };
|
|
1813
|
+
/** Attach the Grasshopper wire-code table without clobbering a caller's own entries. */
|
|
1814
|
+
function withGrasshopperErrorCodes(config) {
|
|
1815
|
+
return {
|
|
1816
|
+
...config,
|
|
1817
|
+
serverErrorCodes: {
|
|
1818
|
+
...GRASSHOPPER_SERVER_ERROR_CODES,
|
|
1819
|
+
...config.serverErrorCodes
|
|
1820
|
+
}
|
|
1821
|
+
};
|
|
1822
|
+
}
|
|
1823
|
+
function isDefinitionLoadMiss(error) {
|
|
1824
|
+
if (!(error instanceof ComputeError)) return false;
|
|
1825
|
+
return error.code === ErrorCodes.DEFINITION_NOT_CACHED || error.message.includes(DEFINITION_LOAD_FAILED);
|
|
1826
|
+
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Debug-only: names the outputs that produced nothing, usually a definition that didn't compute
|
|
1829
|
+
* (missing inputs, a guarded branch). An empty output can be legitimate, so this only warns.
|
|
1830
|
+
*/
|
|
1831
|
+
function warnOnEmptyInnerTrees(response, debug) {
|
|
1832
|
+
if (!debug) return;
|
|
1833
|
+
const values = readField(response, "values");
|
|
1834
|
+
if (!Array.isArray(values) || values.length === 0) return;
|
|
1835
|
+
const empty = [];
|
|
1836
|
+
for (const param of values) {
|
|
1837
|
+
const innerTree = readField(param, "innerTree");
|
|
1838
|
+
if (!innerTree || Object.keys(innerTree).length === 0) empty.push(readField(param, "paramName") ?? "<unnamed>");
|
|
1839
|
+
}
|
|
1840
|
+
if (empty.length === 0) return;
|
|
1841
|
+
const scope = empty.length === values.length ? "all" : `${empty.length}/${values.length}`;
|
|
1842
|
+
getLogger().warn(`Solve returned empty output(s) (${scope}): ${empty.join(", ")}. These parameters produced no data — check the definition's inputs and the branch feeding each.`);
|
|
1843
|
+
}
|
|
1844
|
+
/**
|
|
1845
|
+
* Run one solve. `GrasshopperClient.solve()` adds input validation and throws on solver errors.
|
|
1846
|
+
*
|
|
1847
|
+
* @param definition - A URL (sent as a pointer), base64 `.gh` content, raw `.gh` bytes, or a
|
|
1848
|
+
* `DefinitionRef` (loaded for the upload). Any other string is encoded as the definition text.
|
|
1849
|
+
* @returns The compute response, without the server's `pointer` and echoed `algo`.
|
|
1850
|
+
*
|
|
1851
|
+
* @example
|
|
1852
|
+
* await solveGrasshopperDefinition(trees, 'https://example.com/definition.gh', config);
|
|
1853
|
+
* await solveGrasshopperDefinition(trees, new Uint8Array(await readFile('model.gh')), config);
|
|
1854
|
+
*/
|
|
1855
|
+
async function solveGrasshopperDefinition(dataTree, definition, config) {
|
|
1856
|
+
warnIfClientSide("solveGrasshopperDefinition", config.suppressBrowserWarning);
|
|
1857
|
+
validateServerUrl(config.serverUrl);
|
|
1858
|
+
return (await uploadAndSolve(dataTree, definition, config)).response;
|
|
1859
|
+
}
|
|
1860
|
+
/**
|
|
1861
|
+
* Solve by `pointer: cacheKey` when a key is known, skipping the upload. With no key, or when the
|
|
1862
|
+
* server has evicted it, upload the full definition and report `missed: true`. A `DefinitionRef`
|
|
1863
|
+
* is loaded only on that upload path.
|
|
1864
|
+
*/
|
|
1865
|
+
async function solveWithServerCacheKey(dataTree, cacheKey, definition, config) {
|
|
1866
|
+
warnIfClientSide("solveWithServerCacheKey", config.suppressBrowserWarning);
|
|
1867
|
+
if (cacheKey !== null) try {
|
|
1868
|
+
return {
|
|
1869
|
+
...await runSolve({
|
|
1870
|
+
algo: null,
|
|
1871
|
+
pointer: cacheKey,
|
|
1872
|
+
values: dataTree
|
|
1873
|
+
}, config),
|
|
1874
|
+
missed: false
|
|
1875
|
+
};
|
|
1876
|
+
} catch (error) {
|
|
1877
|
+
if (!isDefinitionLoadMiss(error)) throw error;
|
|
1878
|
+
}
|
|
1879
|
+
return {
|
|
1880
|
+
...await uploadAndSolve(dataTree, definition, config),
|
|
1881
|
+
missed: true
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
async function uploadAndSolve(dataTree, definition, config) {
|
|
1885
|
+
return runSolve(prepareGrasshopperArgs(await materializeDefinition(definition, config), dataTree), config);
|
|
1886
|
+
}
|
|
1887
|
+
async function materializeDefinition(definition, config) {
|
|
1888
|
+
if (!isDefinitionRef(definition)) return definition;
|
|
1889
|
+
validateNumbers(config);
|
|
1890
|
+
const { signal, cleanup } = composeSignal(config.signal, config.timeoutMs);
|
|
1891
|
+
try {
|
|
1892
|
+
return await raceSignal(definition.load(signal), signal);
|
|
1893
|
+
} catch (error) {
|
|
1894
|
+
if (config.signal?.aborted) throw abortedByCaller({ definitionKey: definition.key }, error);
|
|
1895
|
+
if (signal?.aborted) throw new ComputeError(`Loading definition '${definition.key}' timed out after ${config.timeoutMs}ms`, ErrorCodes.TIMEOUT_ERROR, { context: {
|
|
1896
|
+
definitionKey: definition.key,
|
|
1897
|
+
timeoutMs: config.timeoutMs
|
|
1898
|
+
} });
|
|
1899
|
+
throw new ComputeError(`Failed to load definition bytes for ref '${definition.key}'`, ErrorCodes.INVALID_INPUT, {
|
|
1900
|
+
context: { definitionKey: definition.key },
|
|
1901
|
+
originalError: error
|
|
1902
|
+
});
|
|
1903
|
+
} finally {
|
|
1904
|
+
cleanup();
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
/**
|
|
1908
|
+
* POST a solve and split the server's `pointer` off the response. The server echoes the request's
|
|
1909
|
+
* base64 definition back as `algo`; it is dropped so a cached response doesn't pin a multi-MB copy
|
|
1910
|
+
* of the definition against the scheduler's byte budget.
|
|
1911
|
+
*/
|
|
1912
|
+
async function runSolve(args, config) {
|
|
1913
|
+
applyOptionalComputeSettings(args, config);
|
|
1914
|
+
const { maxResponseBytes } = config;
|
|
1915
|
+
const result = await fetchCompute("grasshopper", args, withGrasshopperErrorCodes({
|
|
1916
|
+
...config,
|
|
1917
|
+
maxResponseBytes: maxResponseBytes !== void 0 && args.algo ? maxResponseBytes + args.algo.length : maxResponseBytes
|
|
1918
|
+
}));
|
|
1919
|
+
assertResponseObject(result);
|
|
1920
|
+
const { pointer, algo: _algo, ...rest } = result;
|
|
1921
|
+
const response = readField(rest, "values") ? rest : {
|
|
1922
|
+
...rest,
|
|
1923
|
+
values: []
|
|
1924
|
+
};
|
|
1925
|
+
const wireSize = getResponseWireSize(result);
|
|
1926
|
+
if (wireSize !== void 0) {
|
|
1927
|
+
const algoLength = typeof _algo === "string" ? _algo.length : 0;
|
|
1928
|
+
setResponseWireSize(response, Math.max(0, wireSize - algoLength));
|
|
1929
|
+
}
|
|
1930
|
+
warnOnEmptyInnerTrees(response, config.debug);
|
|
1931
|
+
return {
|
|
1932
|
+
response,
|
|
1933
|
+
cacheKey: typeof pointer === "string" ? pointer : null
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
/** A 200 can carry valid JSON that isn't an object: `null` from a proxy, or a bare string. */
|
|
1937
|
+
function assertResponseObject(response) {
|
|
1938
|
+
if (!response || typeof response !== "object") throw new ComputeError("Invalid response structure", ErrorCodes.INVALID_RESPONSE, { context: { responseType: response === null ? "null" : typeof response } });
|
|
1939
|
+
}
|
|
1940
|
+
function prepareGrasshopperArgs(definition, dataTree) {
|
|
1941
|
+
const args = {
|
|
1942
|
+
algo: null,
|
|
1943
|
+
pointer: null,
|
|
1944
|
+
values: dataTree
|
|
1945
|
+
};
|
|
1946
|
+
if (definition instanceof Uint8Array) args.algo = base64ByteArray(definition);
|
|
1947
|
+
else if (isDefinitionUrl(definition)) args.pointer = definition;
|
|
1948
|
+
else args.algo = detectBase64Payload(definition) ?? encodeStringToBase64(definition);
|
|
1949
|
+
return args;
|
|
1950
|
+
}
|
|
1951
|
+
function applyOptionalComputeSettings(arglist, options) {
|
|
1952
|
+
if (options.cachesolve != null) arglist.cachesolve = options.cachesolve;
|
|
1953
|
+
if (options.modelunits != null) arglist.modelunits = options.modelunits;
|
|
1954
|
+
if (options.angletolerance != null) arglist.angletolerance = options.angletolerance;
|
|
1955
|
+
if (options.absolutetolerance != null) arglist.absolutetolerance = options.absolutetolerance;
|
|
1956
|
+
if (options.dataversion != null) arglist.dataversion = options.dataversion;
|
|
1957
|
+
if (options.selvaevents != null) arglist.selvaevents = options.selvaevents;
|
|
1958
|
+
}
|
|
1959
|
+
/**
|
|
1960
|
+
* `obj[key] = value` for a key taken from a wire payload. Assigning `__proto__` would call the
|
|
1961
|
+
* prototype setter and swap the object's prototype instead of storing the value.
|
|
1962
|
+
*/
|
|
1963
|
+
function setOwnField(obj, key, value) {
|
|
1964
|
+
if (key === "__proto__") Object.defineProperty(obj, key, {
|
|
1965
|
+
value,
|
|
1966
|
+
writable: true,
|
|
1967
|
+
enumerable: true,
|
|
1968
|
+
configurable: true
|
|
1969
|
+
});
|
|
1970
|
+
else obj[key] = value;
|
|
1971
|
+
}
|
|
1972
|
+
/**
|
|
1973
|
+
* Canonical matcher for a Grasshopper branch path key like `{0}`, `{0;1}`, or
|
|
1974
|
+
* the root path `{}`. This is the single source of truth for the branch-path
|
|
1975
|
+
* shape (`DataTreePath`); anything testing "does this string name a branch?"
|
|
1976
|
+
* should use this rather than re-inlining the regex.
|
|
1977
|
+
*
|
|
1978
|
+
* Matches `{}`, `{0}`, `{0;1;2}`, and negative indices like `{-1;2}` (GH_Path
|
|
1979
|
+
* allows them) — but NOT empty segments like `{0;}` / `{;}` / `{0;;1}`, which
|
|
1980
|
+
* would otherwise split to phantom 0s (`Number('') === 0`).
|
|
1981
|
+
*/
|
|
1982
|
+
var TREE_PATH_RE = /^\{(-?\d+(?:;-?\d+)*)?\}$/;
|
|
1983
|
+
/**
|
|
1984
|
+
* Membership test for a {@link DataTreeDefault}: an object keyed entirely by
|
|
1985
|
+
* branch paths, each mapping to an array of values. This is the one predicate
|
|
1986
|
+
* both the input-type parsers (to pass a tree-access default through untouched)
|
|
1987
|
+
* and `TreeBuilder` (to dispatch it to `fromDataTreeDefault`) ask — so the two
|
|
1988
|
+
* agree by construction on exactly which values are trees.
|
|
1989
|
+
*/
|
|
1990
|
+
function isDataTreeDefault(value) {
|
|
1991
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
1992
|
+
const entries = Object.entries(value);
|
|
1993
|
+
return entries.length > 0 && entries.every(([key, val]) => TREE_PATH_RE.test(key) && Array.isArray(val));
|
|
1994
|
+
}
|
|
1995
|
+
/** Every numeric CLR type Grasshopper serializes, so no numeric item stays a string. */
|
|
1996
|
+
var NUMERIC_ITEM_TYPES = /* @__PURE__ */ new Set([
|
|
1997
|
+
"System.Double",
|
|
1998
|
+
"System.Single",
|
|
1999
|
+
"System.Decimal",
|
|
2000
|
+
"System.Int32",
|
|
2001
|
+
"System.Int64"
|
|
2002
|
+
]);
|
|
2003
|
+
/** Integral wire item types: rounded like the scalar Integer path. */
|
|
2004
|
+
var INTEGER_ITEM_TYPES = /* @__PURE__ */ new Set(["System.Int32", "System.Int64"]);
|
|
2005
|
+
/**
|
|
2006
|
+
* Coerce a schema's `default`: array items are transformed and the rejected ones
|
|
2007
|
+
* filtered (none left → `undefined`); a rejected scalar becomes `undefined` when
|
|
2008
|
+
* `dropInvalidScalar`, else is kept verbatim for the parser to report.
|
|
2009
|
+
*/
|
|
2010
|
+
function coerceDefault(value, transform, dropInvalidScalar) {
|
|
2011
|
+
if (value === void 0 || value === null) return value;
|
|
2012
|
+
if (Array.isArray(value)) {
|
|
2013
|
+
const processed = value.map(transform).filter((v) => v !== null);
|
|
2014
|
+
return processed.length > 0 ? processed : void 0;
|
|
2015
|
+
}
|
|
2016
|
+
const transformed = transform(value);
|
|
2017
|
+
if (transformed !== null) return transformed;
|
|
2018
|
+
return dropInvalidScalar ? void 0 : value;
|
|
2019
|
+
}
|
|
2020
|
+
var numericTransformer = (value) => {
|
|
2021
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
2022
|
+
if (typeof value === "string") {
|
|
2023
|
+
const trimmed = value.trim();
|
|
2024
|
+
if (trimmed === "") return null;
|
|
2025
|
+
if (/^[+-]?0[xbo]/i.test(trimmed)) return null;
|
|
2026
|
+
const parsed = Number(trimmed);
|
|
2027
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
2028
|
+
}
|
|
2029
|
+
return null;
|
|
2030
|
+
};
|
|
2031
|
+
var booleanTransformer = (value) => {
|
|
2032
|
+
if (typeof value === "boolean") return value;
|
|
2033
|
+
if (typeof value === "string") {
|
|
2034
|
+
const lower = value.trim().toLowerCase();
|
|
2035
|
+
if (lower === "true") return true;
|
|
2036
|
+
if (lower === "false") return false;
|
|
2037
|
+
}
|
|
2038
|
+
return null;
|
|
2039
|
+
};
|
|
2040
|
+
var textTransformer = (value) => {
|
|
2041
|
+
if (typeof value === "string") {
|
|
2042
|
+
if (value.length >= 2 && value.startsWith("\"") && value.endsWith("\"")) return value.slice(1, -1);
|
|
2043
|
+
if (value.startsWith("\"")) return value.slice(1);
|
|
2044
|
+
return value;
|
|
2045
|
+
}
|
|
2046
|
+
return null;
|
|
2047
|
+
};
|
|
2048
|
+
var colorTransformer = (value) => {
|
|
2049
|
+
if (typeof value === "string") {
|
|
2050
|
+
let cleaned = value.trim();
|
|
2051
|
+
if (cleaned.startsWith("\"") && cleaned.endsWith("\"")) cleaned = cleaned.slice(1, -1).trim();
|
|
2052
|
+
return cleaned;
|
|
2053
|
+
}
|
|
2054
|
+
return null;
|
|
2055
|
+
};
|
|
2056
|
+
function objectTransformer(inputName) {
|
|
2057
|
+
return (value) => {
|
|
2058
|
+
if (typeof value === "object" && value !== null) return value;
|
|
2059
|
+
if (typeof value === "string" && value.trim() !== "") try {
|
|
2060
|
+
const parsed = JSON.parse(value);
|
|
2061
|
+
if (typeof parsed === "object" && parsed !== null) return parsed;
|
|
2062
|
+
getLogger().warn(`Parsed value for input ${inputName} is not an object`);
|
|
2063
|
+
return null;
|
|
2064
|
+
} catch {
|
|
2065
|
+
getLogger().warn(`Failed to parse the object value for input ${inputName}`);
|
|
2066
|
+
return null;
|
|
2067
|
+
}
|
|
2068
|
+
return null;
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2071
|
+
function dropDefault(input, message) {
|
|
2072
|
+
getLogger().warn(message);
|
|
2073
|
+
return {
|
|
2074
|
+
schema: {
|
|
2075
|
+
...input,
|
|
2076
|
+
default: null
|
|
2077
|
+
},
|
|
2078
|
+
warning: {
|
|
2079
|
+
code: ErrorCodes.MALFORMED_DEFAULT,
|
|
2080
|
+
message
|
|
2081
|
+
}
|
|
2082
|
+
};
|
|
2083
|
+
}
|
|
2084
|
+
/**
|
|
2085
|
+
* Flatten a raw input's `default` DataTree into the shape the type parsers take.
|
|
2086
|
+
* Never mutates `input`. A default it can't interpret is dropped with a `warning`.
|
|
2087
|
+
*/
|
|
2088
|
+
function normalizeDefault(input, label) {
|
|
2089
|
+
if (typeof input.default !== "object" || input.default === null) return { schema: input };
|
|
2090
|
+
if (Array.isArray(input.default) || isDataTreeDefault(input.default)) return { schema: input };
|
|
2091
|
+
if (!hasField(input.default, "innerTree")) return dropDefault(input, `Input "${label}" default had an unrecognized shape (no innerTree key); the default was dropped.`);
|
|
2092
|
+
const innerTree = readField(input.default, "innerTree") ?? {};
|
|
2093
|
+
if (Object.keys(innerTree).length === 0) return { schema: {
|
|
2094
|
+
...input,
|
|
2095
|
+
default: void 0
|
|
2096
|
+
} };
|
|
2097
|
+
if (input.treeAccess || input.atMost && input.atMost > 1) {
|
|
2098
|
+
const tree = {};
|
|
2099
|
+
const invalidItems = [];
|
|
2100
|
+
for (const [branch, items] of Object.entries(innerTree)) {
|
|
2101
|
+
if (!Array.isArray(items)) return dropDefault(input, `Input "${label}" default had a non-array innerTree branch ("${branch}"); the default was dropped.`);
|
|
2102
|
+
const parsed = [];
|
|
2103
|
+
for (const item of items) {
|
|
2104
|
+
const data = readField(item, "data");
|
|
2105
|
+
const type = readField(item, "type");
|
|
2106
|
+
if (type && NUMERIC_ITEM_TYPES.has(type)) {
|
|
2107
|
+
if (typeof data === "string" && data.trim() === "") continue;
|
|
2108
|
+
const num = numericTransformer(data);
|
|
2109
|
+
if (num === null) {
|
|
2110
|
+
invalidItems.push(`"${String(data)}" (${type})`);
|
|
2111
|
+
continue;
|
|
2112
|
+
}
|
|
2113
|
+
parsed.push(INTEGER_ITEM_TYPES.has(type) ? Math.round(num) : num);
|
|
2114
|
+
continue;
|
|
2115
|
+
}
|
|
2116
|
+
if (type === "System.Boolean") {
|
|
2117
|
+
const bool = booleanTransformer(data);
|
|
2118
|
+
if (bool === null) {
|
|
2119
|
+
invalidItems.push(`"${String(data)}" (${type})`);
|
|
2120
|
+
continue;
|
|
2121
|
+
}
|
|
2122
|
+
parsed.push(bool);
|
|
2123
|
+
continue;
|
|
2124
|
+
}
|
|
2125
|
+
if (type === "System.String" && typeof data === "string") {
|
|
2126
|
+
parsed.push(textTransformer(data));
|
|
2127
|
+
continue;
|
|
2128
|
+
}
|
|
2129
|
+
if (typeof data === "string" && type?.startsWith("Rhino.Geometry")) {
|
|
2130
|
+
try {
|
|
2131
|
+
parsed.push(JSON.parse(data));
|
|
2132
|
+
} catch {
|
|
2133
|
+
parsed.push(data);
|
|
2134
|
+
}
|
|
2135
|
+
continue;
|
|
2136
|
+
}
|
|
2137
|
+
parsed.push(data);
|
|
2138
|
+
}
|
|
2139
|
+
setOwnField(tree, branch, parsed);
|
|
2140
|
+
}
|
|
2141
|
+
if (invalidItems.length > 0) {
|
|
2142
|
+
const message = `Input "${label}" default contained ${invalidItems.length} tree value(s) that could not be parsed and were dropped: ${invalidItems.join(", ")}.`;
|
|
2143
|
+
getLogger().warn(`Input "${label}" default: dropped ${invalidItems.length} tree value(s)`);
|
|
2144
|
+
return {
|
|
2145
|
+
schema: {
|
|
2146
|
+
...input,
|
|
2147
|
+
default: tree
|
|
2148
|
+
},
|
|
2149
|
+
warning: {
|
|
2150
|
+
code: ErrorCodes.MALFORMED_DEFAULT,
|
|
2151
|
+
message
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
return { schema: {
|
|
2156
|
+
...input,
|
|
2157
|
+
default: tree
|
|
2158
|
+
} };
|
|
2159
|
+
}
|
|
2160
|
+
const allValues = [];
|
|
2161
|
+
for (const items of Object.values(innerTree)) {
|
|
2162
|
+
if (!Array.isArray(items)) continue;
|
|
2163
|
+
for (const item of items) if (item && typeof item === "object" && hasField(item, "data")) allValues.push(readField(item, "data"));
|
|
2164
|
+
}
|
|
2165
|
+
return { schema: {
|
|
2166
|
+
...input,
|
|
2167
|
+
default: allValues.length > 1 ? allValues : allValues[0]
|
|
2168
|
+
} };
|
|
2169
|
+
}
|
|
2170
|
+
/** Snap float noise (`0.30000000000000004`) to `decimalPlaces`; a real difference is kept. */
|
|
2171
|
+
function applyRounding(value, decimalPlaces) {
|
|
2172
|
+
const rounded = Number(value.toFixed(decimalPlaces));
|
|
2173
|
+
return Math.abs(value - rounded) < 1e-8 ? rounded : value;
|
|
2174
|
+
}
|
|
2175
|
+
var MAX_DECIMALS = 12;
|
|
2176
|
+
var SIGNIFICANT_DIGITS = 15;
|
|
2177
|
+
/**
|
|
2178
|
+
* Decimal places `x` is written with, ignoring float noise, at most 12:
|
|
2179
|
+
* `0.30000000000000004` → 1, `16384.2` → 1, `1e-7` → 7, `1.5e21` → 0.
|
|
2180
|
+
*/
|
|
2181
|
+
function decimalsOf(x) {
|
|
2182
|
+
if (!Number.isFinite(x)) return 0;
|
|
2183
|
+
const clean = Number(Math.abs(x).toPrecision(SIGNIFICANT_DIGITS));
|
|
2184
|
+
const [mantissa, exponent = "0"] = String(clean).split("e");
|
|
2185
|
+
const decimals = (mantissa.split(".")[1]?.length ?? 0) - Number(exponent);
|
|
2186
|
+
return Math.min(Math.max(decimals, 0), MAX_DECIMALS);
|
|
2187
|
+
}
|
|
2188
|
+
function getInputStepSize(value) {
|
|
2189
|
+
if (!Number.isFinite(value) || value === 0) return .1;
|
|
2190
|
+
const decimals = decimalsOf(value);
|
|
2191
|
+
if (decimals === 0) return Math.abs(value) >= 1 ? 1 : .1;
|
|
2192
|
+
return Number((10 ** -decimals).toFixed(decimals));
|
|
2193
|
+
}
|
|
2194
|
+
/** A server-authored `stepSize`, or `undefined` when absent or unusable. */
|
|
2195
|
+
function serverStepSize(schema) {
|
|
2196
|
+
return typeof schema.stepSize === "number" && Number.isFinite(schema.stepSize) && schema.stepSize > 0 ? schema.stepSize : void 0;
|
|
2197
|
+
}
|
|
2198
|
+
var labelOf = (schema) => schema.nickname || "unnamed";
|
|
2199
|
+
var listOr = (schema, value) => (schema.atMost ?? 1) > 1 ? [value] : value;
|
|
2200
|
+
var defaultStep = (schema) => serverStepSize(schema) ?? (schema.paramType === "Integer" ? 1 : .1);
|
|
2201
|
+
var mapNumbers = (value, fn) => Array.isArray(value) ? value.map((v) => typeof v === "number" ? fn(v) : v) : typeof value === "number" ? fn(value) : value;
|
|
2202
|
+
function computeNumeric(schema) {
|
|
2203
|
+
if (isDataTreeDefault(schema.default)) return {
|
|
2204
|
+
default: schema.default,
|
|
2205
|
+
stepSize: defaultStep(schema)
|
|
2206
|
+
};
|
|
2207
|
+
if (typeof schema.default === "string" && schema.default.trim() !== "" && numericTransformer(schema.default) === null) throw new ComputeError(`Invalid numeric default "${schema.default}" for input "${schema.name || "unknown"}"`, ErrorCodes.VALIDATION_ERROR, { context: {
|
|
2208
|
+
inputName: schema.name,
|
|
2209
|
+
default: schema.default
|
|
2210
|
+
} });
|
|
2211
|
+
const value = coerceDefault(schema.default, numericTransformer, true);
|
|
2212
|
+
if (schema.paramType === "Integer") return {
|
|
2213
|
+
default: mapNumbers(value, Math.round),
|
|
2214
|
+
stepSize: defaultStep(schema)
|
|
2215
|
+
};
|
|
2216
|
+
const firstValue = Array.isArray(value) ? value[0] : value;
|
|
2217
|
+
const stepSource = [
|
|
2218
|
+
firstValue,
|
|
2219
|
+
schema.minimum,
|
|
2220
|
+
schema.maximum
|
|
2221
|
+
].find((v) => typeof v === "number" && Number.isFinite(v) && v !== 0);
|
|
2222
|
+
const stepSize = serverStepSize(schema) ?? (stepSource !== void 0 ? getInputStepSize(stepSource) : .1);
|
|
2223
|
+
let decimalPlaces = decimalsOf(stepSize);
|
|
2224
|
+
if (decimalPlaces === 0 && typeof firstValue === "number" && firstValue !== 0 && Math.abs(firstValue) < 1) {
|
|
2225
|
+
const inferred = Math.ceil(-Math.log10(Math.abs(firstValue)));
|
|
2226
|
+
if (Number.isFinite(inferred) && inferred > 0) decimalPlaces = inferred;
|
|
2227
|
+
}
|
|
2228
|
+
decimalPlaces = Math.min(Math.max(decimalPlaces, 0), 12);
|
|
2229
|
+
return {
|
|
2230
|
+
default: mapNumbers(value, (n) => applyRounding(n, decimalPlaces)),
|
|
2231
|
+
stepSize
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
var numericParam = (schema, base, computed) => ({
|
|
2235
|
+
...base,
|
|
2236
|
+
paramType: schema.paramType,
|
|
2237
|
+
minimum: schema.minimum,
|
|
2238
|
+
maximum: schema.maximum,
|
|
2239
|
+
atLeast: schema.atLeast,
|
|
2240
|
+
atMost: schema.atMost,
|
|
2241
|
+
...computed
|
|
2242
|
+
});
|
|
2243
|
+
var numericParser = {
|
|
2244
|
+
parse(schema, base) {
|
|
2245
|
+
return numericParam(schema, base, computeNumeric(schema));
|
|
2246
|
+
},
|
|
2247
|
+
fallback(schema, base) {
|
|
2248
|
+
const safeValue = typeof schema.minimum === "number" && Number.isFinite(schema.minimum) && schema.minimum > 0 ? schema.minimum : 0;
|
|
2249
|
+
return numericParam(schema, base, {
|
|
2250
|
+
stepSize: defaultStep(schema),
|
|
2251
|
+
default: listOr(schema, safeValue)
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2254
|
+
};
|
|
2255
|
+
var booleanParser = {
|
|
2256
|
+
parse(schema, base) {
|
|
2257
|
+
if (isDataTreeDefault(schema.default)) return {
|
|
2258
|
+
...base,
|
|
2259
|
+
paramType: "Boolean",
|
|
2260
|
+
default: schema.default
|
|
2261
|
+
};
|
|
2262
|
+
const value = coerceDefault(schema.default, booleanTransformer, false);
|
|
2263
|
+
if (value !== void 0 && value !== null && typeof value !== "boolean" && !Array.isArray(value)) throw new ComputeError(`Invalid boolean default "${String(value)}" for input "${schema.name || "unknown"}"`, ErrorCodes.VALIDATION_ERROR, { context: {
|
|
2264
|
+
inputName: schema.name,
|
|
2265
|
+
default: schema.default
|
|
2266
|
+
} });
|
|
2267
|
+
return {
|
|
2268
|
+
...base,
|
|
2269
|
+
paramType: "Boolean",
|
|
2270
|
+
default: value
|
|
2271
|
+
};
|
|
2272
|
+
},
|
|
2273
|
+
fallback(schema, base) {
|
|
2274
|
+
return {
|
|
2275
|
+
...base,
|
|
2276
|
+
paramType: "Boolean",
|
|
2277
|
+
default: listOr(schema, false)
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
};
|
|
2281
|
+
var textParser = { parse(schema, base) {
|
|
2282
|
+
const value = coerceDefault(schema.default, textTransformer, false);
|
|
2283
|
+
return {
|
|
2284
|
+
...base,
|
|
2285
|
+
paramType: "Text",
|
|
2286
|
+
default: value
|
|
2287
|
+
};
|
|
2288
|
+
} };
|
|
2289
|
+
var valueListParser = {
|
|
2290
|
+
parse(schema, base, warn) {
|
|
2291
|
+
if (!schema.values || typeof schema.values !== "object" || Object.keys(schema.values).length === 0) {
|
|
2292
|
+
const inputName = labelOf(schema);
|
|
2293
|
+
throw new ComputeError(`Input "${inputName}" has no values defined (expected ValueList)`, ErrorCodes.INVALID_INPUT, { context: {
|
|
2294
|
+
inputName,
|
|
2295
|
+
expectedType: "ValueList"
|
|
2296
|
+
} });
|
|
2297
|
+
}
|
|
2298
|
+
let defaultValue;
|
|
2299
|
+
if (schema.default !== void 0 && schema.default !== null) {
|
|
2300
|
+
if (typeof schema.default === "object") throw new ComputeError(`ValueList input "${labelOf(schema)}" default is not a string-able value`, ErrorCodes.VALIDATION_ERROR, { context: {
|
|
2301
|
+
inputName: schema.name,
|
|
2302
|
+
default: schema.default
|
|
2303
|
+
} });
|
|
2304
|
+
const defaultLower = String(schema.default).toLowerCase();
|
|
2305
|
+
const match = Object.keys(schema.values).find((key) => key.toLowerCase() === defaultLower);
|
|
2306
|
+
defaultValue = match ?? String(schema.default);
|
|
2307
|
+
if (match === void 0) {
|
|
2308
|
+
const inputName = labelOf(schema);
|
|
2309
|
+
getLogger().warn(`ValueList input "${inputName}" default is not in available values`);
|
|
2310
|
+
warn?.({
|
|
2311
|
+
code: ErrorCodes.VALIDATION_ERROR,
|
|
2312
|
+
message: `ValueList input "${inputName}" default value "${schema.default}" is not in available values`
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
return {
|
|
2317
|
+
...base,
|
|
2318
|
+
paramType: "ValueList",
|
|
2319
|
+
values: schema.values,
|
|
2320
|
+
default: defaultValue
|
|
2321
|
+
};
|
|
2322
|
+
},
|
|
2323
|
+
fallback(schema, base) {
|
|
2324
|
+
return {
|
|
2325
|
+
...base,
|
|
2326
|
+
paramType: "ValueList",
|
|
2327
|
+
values: schema.values && typeof schema.values === "object" ? schema.values : {},
|
|
2328
|
+
default: void 0
|
|
2329
|
+
};
|
|
2330
|
+
}
|
|
2331
|
+
};
|
|
2332
|
+
var objectDefault = (schema) => coerceDefault(schema.default, objectTransformer(labelOf(schema)), true);
|
|
2333
|
+
function geometryFallback(schema, base) {
|
|
2334
|
+
return {
|
|
2335
|
+
...base,
|
|
2336
|
+
paramType: "Geometry",
|
|
2337
|
+
default: listOr(schema, null)
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
/** Keyed by canonical paramType. */
|
|
2341
|
+
var INPUT_TYPE_PARSERS = /* @__PURE__ */ new Map([
|
|
2342
|
+
["Number", numericParser],
|
|
2343
|
+
["Integer", numericParser],
|
|
2344
|
+
["Boolean", booleanParser],
|
|
2345
|
+
["Text", textParser],
|
|
2346
|
+
["ValueList", valueListParser],
|
|
2347
|
+
["Geometry", {
|
|
2348
|
+
parse(schema, base) {
|
|
2349
|
+
return {
|
|
2350
|
+
...base,
|
|
2351
|
+
paramType: "Geometry",
|
|
2352
|
+
default: objectDefault(schema)
|
|
2353
|
+
};
|
|
2354
|
+
},
|
|
2355
|
+
fallback: geometryFallback
|
|
2356
|
+
}],
|
|
2357
|
+
["File", { parse(schema, base) {
|
|
2358
|
+
return {
|
|
2359
|
+
...base,
|
|
2360
|
+
paramType: "File",
|
|
2361
|
+
acceptedFormats: schema.acceptedFormats,
|
|
2362
|
+
default: objectDefault(schema)
|
|
2363
|
+
};
|
|
2364
|
+
} }],
|
|
2365
|
+
["Color", { parse(schema, base) {
|
|
2366
|
+
const value = coerceDefault(schema.default, colorTransformer, false);
|
|
2367
|
+
return {
|
|
2368
|
+
...base,
|
|
2369
|
+
paramType: "Color",
|
|
2370
|
+
default: value
|
|
2371
|
+
};
|
|
2372
|
+
} }]
|
|
2373
|
+
]);
|
|
2374
|
+
var unknownTypeFallback = geometryFallback;
|
|
2375
|
+
var CANONICAL_PARAM_TYPES = new Map([...INPUT_TYPE_PARSERS.keys()].map((key) => [key.toLowerCase(), key]));
|
|
2376
|
+
/** An unknown paramType comes back unchanged, so its unknown-type error still surfaces. */
|
|
2377
|
+
function canonicalizeParamType(paramType) {
|
|
2378
|
+
return CANONICAL_PARAM_TYPES.get(paramType?.toLowerCase()) ?? paramType;
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Like {@link processInput}, but also returns every problem found on the way, in
|
|
2382
|
+
* order: a dropped default, warnings the parser recovered from, and the parser
|
|
2383
|
+
* error that forced the safe default. Entries carry the RAW declared `paramType`
|
|
2384
|
+
* so clients match on the casing they sent.
|
|
2385
|
+
*
|
|
2386
|
+
* A non-`ComputeError` failure still throws: it is a bug, not bad input.
|
|
2387
|
+
*/
|
|
2388
|
+
function processInputWithError(rawInput) {
|
|
2389
|
+
const label = rawInput.name || "unknown";
|
|
2390
|
+
const errors = [];
|
|
2391
|
+
const report = ({ code, message }) => {
|
|
2392
|
+
errors.push({
|
|
2393
|
+
inputName: label,
|
|
2394
|
+
paramType: rawInput.paramType,
|
|
2395
|
+
message,
|
|
2396
|
+
code
|
|
2397
|
+
});
|
|
2398
|
+
};
|
|
2399
|
+
const baseInput = {
|
|
2400
|
+
description: rawInput.description,
|
|
2401
|
+
name: rawInput.name,
|
|
2402
|
+
nickname: rawInput.nickname,
|
|
2403
|
+
treeAccess: rawInput.treeAccess,
|
|
2404
|
+
groupName: rawInput.groupName ?? void 0,
|
|
2405
|
+
id: rawInput.id
|
|
2406
|
+
};
|
|
2407
|
+
const paramType = canonicalizeParamType(rawInput.paramType);
|
|
2408
|
+
let schema = {
|
|
2409
|
+
...rawInput,
|
|
2410
|
+
paramType
|
|
2411
|
+
};
|
|
2412
|
+
try {
|
|
2413
|
+
const { schema: normalized, warning } = normalizeDefault(schema, label);
|
|
2414
|
+
schema = normalized;
|
|
2415
|
+
if (warning) report(warning);
|
|
2416
|
+
} catch (error) {
|
|
2417
|
+
schema = {
|
|
2418
|
+
...schema,
|
|
2419
|
+
default: null
|
|
2420
|
+
};
|
|
2421
|
+
report({
|
|
2422
|
+
code: ErrorCodes.MALFORMED_DEFAULT,
|
|
2423
|
+
message: `Input "${label}" default could not be normalized and was dropped: ${error instanceof Error ? error.message : String(error)}`
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2426
|
+
const parser = INPUT_TYPE_PARSERS.get(paramType);
|
|
2427
|
+
try {
|
|
2428
|
+
if (!parser) throw new ComputeError(`Unknown paramType: ${paramType}`, ErrorCodes.VALIDATION_ERROR, { context: {
|
|
2429
|
+
receivedParamType: paramType,
|
|
2430
|
+
paramName: rawInput.name
|
|
2431
|
+
} });
|
|
2432
|
+
return {
|
|
2433
|
+
input: parser.parse(schema, baseInput, report),
|
|
2434
|
+
errors
|
|
2435
|
+
};
|
|
2436
|
+
} catch (error) {
|
|
2437
|
+
if (!(error instanceof ComputeError)) throw new ComputeError(error instanceof Error ? error.message : String(error), ErrorCodes.VALIDATION_ERROR, {
|
|
2438
|
+
context: {
|
|
2439
|
+
paramName: rawInput.name,
|
|
2440
|
+
paramType
|
|
2441
|
+
},
|
|
2442
|
+
originalError: error
|
|
2443
|
+
});
|
|
2444
|
+
getLogger().error(`Validation error for input ${label}: ${error.code}`);
|
|
2445
|
+
report(error);
|
|
2446
|
+
return {
|
|
2447
|
+
input: (parser?.fallback ?? unknownTypeFallback)(schema, baseInput),
|
|
2448
|
+
errors
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
/** {@link processInputWithError} over a list, with every input's errors collected. */
|
|
2453
|
+
function processInputsWithErrors(rawInputs) {
|
|
2454
|
+
const inputs = [];
|
|
2455
|
+
const parseErrors = [];
|
|
2456
|
+
for (const raw of rawInputs) {
|
|
2457
|
+
const { input, errors } = processInputWithError(raw);
|
|
2458
|
+
inputs.push(input);
|
|
2459
|
+
parseErrors.push(...errors);
|
|
2460
|
+
}
|
|
2461
|
+
return {
|
|
2462
|
+
inputs,
|
|
2463
|
+
parseErrors
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2466
|
+
/**
|
|
2467
|
+
* Canonicalize a raw `/io` param record's field keys to camelCase, so the
|
|
2468
|
+
* parsers can read `schema.paramType` whichever casing the server sent. Values,
|
|
2469
|
+
* including `default` and the user-authored `values` map, pass through verbatim.
|
|
2470
|
+
*
|
|
2471
|
+
* A missing required field gets a fallback that keeps the type true: `paramType`
|
|
2472
|
+
* `''` surfaces as an unknown-type parse error, and `groupName` stays `null`
|
|
2473
|
+
* (not `''`) so "no group" differs from an empty group name.
|
|
2474
|
+
*/
|
|
2475
|
+
function normalizeInputSchema(raw) {
|
|
2476
|
+
const stepSize = readField(raw, "stepSize");
|
|
2477
|
+
return {
|
|
2478
|
+
id: readField(raw, "id") ?? "",
|
|
2479
|
+
name: readField(raw, "name") ?? "",
|
|
2480
|
+
nickname: readField(raw, "nickname") ?? null,
|
|
2481
|
+
description: readField(raw, "description") ?? "",
|
|
2482
|
+
paramType: readField(raw, "paramType") ?? "",
|
|
2483
|
+
treeAccess: readField(raw, "treeAccess") ?? false,
|
|
2484
|
+
minimum: readField(raw, "minimum") ?? null,
|
|
2485
|
+
maximum: readField(raw, "maximum") ?? null,
|
|
2486
|
+
atLeast: readField(raw, "atLeast") ?? 1,
|
|
2487
|
+
atMost: readField(raw, "atMost") ?? 1,
|
|
2488
|
+
stepSize: typeof stepSize === "number" && Number.isFinite(stepSize) ? stepSize : void 0,
|
|
2489
|
+
default: readField(raw, "default"),
|
|
2490
|
+
values: readField(raw, "values"),
|
|
2491
|
+
acceptedFormats: readField(raw, "acceptedFormats"),
|
|
2492
|
+
groupName: readField(raw, "groupName") ?? null
|
|
2493
|
+
};
|
|
2494
|
+
}
|
|
2495
|
+
function normalizeOutputSchema(raw) {
|
|
2496
|
+
return {
|
|
2497
|
+
name: readField(raw, "name") ?? "",
|
|
2498
|
+
nickname: readField(raw, "nickname") ?? null,
|
|
2499
|
+
paramType: readField(raw, "paramType") ?? "",
|
|
2500
|
+
id: readField(raw, "id") ?? ""
|
|
2501
|
+
};
|
|
2502
|
+
}
|
|
2503
|
+
/**
|
|
2504
|
+
* Fetches a definition's input/output schemas without per-type parsing.
|
|
2505
|
+
*
|
|
2506
|
+
* Field KEYS are canonicalized to camelCase and missing required fields get a fallback; a missing
|
|
2507
|
+
* or non-array `inputs` / `outputs` becomes `[]`. Field VALUES, notably `default` and the `values`
|
|
2508
|
+
* label map, pass through verbatim.
|
|
2509
|
+
*
|
|
2510
|
+
* @throws {ComputeError} If fetch fails or response is invalid
|
|
2511
|
+
*/
|
|
2512
|
+
async function fetchDefinitionIO(definition, config) {
|
|
2513
|
+
warnIfClientSide("fetchDefinitionIO", config.suppressBrowserWarning);
|
|
2514
|
+
validateServerUrl(config.serverUrl);
|
|
2515
|
+
const { algo, pointer } = prepareGrasshopperArgs(definition, []);
|
|
2516
|
+
if (!algo && !pointer) throw new ComputeError("Definition must resolve to either a URL pointer or base64 algo", ErrorCodes.INVALID_INPUT);
|
|
2517
|
+
const response = await fetchCompute("io", algo ? { algo } : { pointer }, withGrasshopperErrorCodes(config));
|
|
2518
|
+
assertResponseObject(response);
|
|
2519
|
+
const loadWarnings = nonEmptyStrings(readField(response, "warnings"));
|
|
2520
|
+
const loadErrors = nonEmptyStrings(readField(response, "errors"));
|
|
2521
|
+
const rawInputs = readField(response, "inputs");
|
|
2522
|
+
const rawOutputs = readField(response, "outputs");
|
|
2523
|
+
return {
|
|
2524
|
+
inputs: Array.isArray(rawInputs) ? rawInputs.map(normalizeInputSchema) : [],
|
|
2525
|
+
outputs: Array.isArray(rawOutputs) ? rawOutputs.map(normalizeOutputSchema) : [],
|
|
2526
|
+
...loadWarnings && { loadWarnings },
|
|
2527
|
+
...loadErrors && { loadErrors }
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* Server diagnostics as non-blank strings, or `undefined` when there are none.
|
|
2532
|
+
* Non-string entries are kept, not dropped: a fork reporting `{ message }`
|
|
2533
|
+
* objects must not yield an empty input list with no explanation.
|
|
2534
|
+
*/
|
|
2535
|
+
function nonEmptyStrings(value) {
|
|
2536
|
+
if (!Array.isArray(value)) return void 0;
|
|
2537
|
+
const cleaned = value.map(coerceDiagnostic).filter((v) => v !== void 0);
|
|
2538
|
+
return cleaned.length > 0 ? cleaned : void 0;
|
|
2539
|
+
}
|
|
2540
|
+
function coerceDiagnostic(value) {
|
|
2541
|
+
if (value === null || value === void 0) return void 0;
|
|
2542
|
+
let text;
|
|
2543
|
+
if (typeof value === "string") text = value;
|
|
2544
|
+
else if (typeof value === "object") {
|
|
2545
|
+
const message = readField(value, "message");
|
|
2546
|
+
if (typeof message === "string" && message.trim().length > 0) text = message;
|
|
2547
|
+
else try {
|
|
2548
|
+
text = JSON.stringify(value) ?? String(value);
|
|
2549
|
+
} catch {
|
|
2550
|
+
text = String(value);
|
|
2551
|
+
}
|
|
2552
|
+
} else text = String(value);
|
|
2553
|
+
return text.trim().length > 0 ? text : void 0;
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Fetches a definition's input/output schemas and parses each input into its
|
|
2557
|
+
* typed `InputParam`. An input that fails to parse gets a safe default
|
|
2558
|
+
* and an entry in `parseErrors`.
|
|
2559
|
+
*
|
|
2560
|
+
* @throws {ComputeError} If fetch fails or response is invalid
|
|
2561
|
+
*
|
|
2562
|
+
* @example
|
|
2563
|
+
* ```typescript
|
|
2564
|
+
* const { inputs, outputs } = await fetchParsedDefinitionIO(
|
|
2565
|
+
* 'https://example.com/definition.gh',
|
|
2566
|
+
* { serverUrl: 'http://localhost:6500', apiKey: 'YOUR_KEY' }
|
|
2567
|
+
* );
|
|
2568
|
+
*
|
|
2569
|
+
* // Inputs are now strongly typed
|
|
2570
|
+
* inputs.forEach(input => {
|
|
2571
|
+
* if (input.paramType === 'Number') {
|
|
2572
|
+
* console.log(input.minimum, input.maximum); // TypeScript knows these exist
|
|
2573
|
+
* }
|
|
2574
|
+
* });
|
|
2575
|
+
* ```
|
|
2576
|
+
*/
|
|
2577
|
+
async function fetchParsedDefinitionIO(definition, config) {
|
|
2578
|
+
const { inputs: rawInputs, outputs, loadWarnings, loadErrors } = await fetchDefinitionIO(definition, config);
|
|
2579
|
+
const { inputs, parseErrors } = processInputsWithErrors(rawInputs);
|
|
2580
|
+
return {
|
|
2581
|
+
inputs,
|
|
2582
|
+
outputs,
|
|
2583
|
+
...parseErrors.length > 0 && { parseErrors },
|
|
2584
|
+
...loadWarnings && { loadWarnings },
|
|
2585
|
+
...loadErrors && { loadErrors }
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
/**
|
|
2589
|
+
* For a response that never crossed the fetch boundary (custom executor), so carries no
|
|
2590
|
+
* wire-size hint. An unserializable response is sized 0 rather than failing the solve.
|
|
2591
|
+
*/
|
|
2592
|
+
function estimateResponseSize(response) {
|
|
2593
|
+
try {
|
|
2594
|
+
return JSON.stringify(response)?.length ?? 0;
|
|
2595
|
+
} catch {
|
|
2596
|
+
return 0;
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
/** The scheduler's response cache: LRU by bytes, with an optional TTL. */
|
|
2600
|
+
var ResponseCache = class {
|
|
2601
|
+
maxBytes;
|
|
2602
|
+
ttlMs;
|
|
2603
|
+
cacheErroredSolves;
|
|
2604
|
+
entries = /* @__PURE__ */ new Map();
|
|
2605
|
+
bytes = 0;
|
|
2606
|
+
hits = 0;
|
|
2607
|
+
misses = 0;
|
|
2608
|
+
evictions = 0;
|
|
2609
|
+
constructor(options) {
|
|
2610
|
+
const config = options || null;
|
|
2611
|
+
this.maxBytes = Math.max(0, config?.maxBytes ?? 0);
|
|
2612
|
+
this.ttlMs = config?.ttlMs ?? 0;
|
|
2613
|
+
this.cacheErroredSolves = config?.cacheErroredSolves ?? true;
|
|
2614
|
+
}
|
|
2615
|
+
/** A zero budget retains nothing, so it is off rather than a cache that can only ever miss. */
|
|
2616
|
+
get enabled() {
|
|
2617
|
+
return this.maxBytes > 0;
|
|
2618
|
+
}
|
|
2619
|
+
get(key) {
|
|
2620
|
+
if (!this.enabled) return null;
|
|
2621
|
+
const entry = this.entries.get(key);
|
|
2622
|
+
if (!entry) {
|
|
2623
|
+
this.misses += 1;
|
|
2624
|
+
return null;
|
|
2625
|
+
}
|
|
2626
|
+
if (this.ttlMs > 0 && Date.now() - entry.insertedAt > this.ttlMs) {
|
|
2627
|
+
this.drop(key);
|
|
2628
|
+
this.misses += 1;
|
|
2629
|
+
return null;
|
|
2630
|
+
}
|
|
2631
|
+
this.entries.delete(key);
|
|
2632
|
+
this.entries.set(key, entry);
|
|
2633
|
+
this.hits += 1;
|
|
2634
|
+
return entry.response;
|
|
2635
|
+
}
|
|
2636
|
+
set(key, response) {
|
|
2637
|
+
if (!this.enabled) return;
|
|
2638
|
+
const solveErrors = readField(response, "errors");
|
|
2639
|
+
if (!this.cacheErroredSolves && Array.isArray(solveErrors) && solveErrors.length > 0) return;
|
|
2640
|
+
if (readField(readField(readField(response, "selva"), "outcome"), "aborted") === true) return;
|
|
2641
|
+
const sizeBytes = getResponseWireSize(response) ?? estimateResponseSize(response);
|
|
2642
|
+
if (sizeBytes > this.maxBytes) return;
|
|
2643
|
+
this.drop(key);
|
|
2644
|
+
this.entries.set(key, {
|
|
2645
|
+
response,
|
|
2646
|
+
insertedAt: Date.now(),
|
|
2647
|
+
sizeBytes
|
|
2648
|
+
});
|
|
2649
|
+
this.bytes += sizeBytes;
|
|
2650
|
+
while (this.bytes > this.maxBytes && this.entries.size > 0) {
|
|
2651
|
+
const oldest = this.entries.keys().next().value;
|
|
2652
|
+
if (oldest === void 0) break;
|
|
2653
|
+
this.drop(oldest);
|
|
2654
|
+
this.evictions += 1;
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
clear() {
|
|
2658
|
+
this.entries.clear();
|
|
2659
|
+
this.bytes = 0;
|
|
2660
|
+
}
|
|
2661
|
+
stats() {
|
|
2662
|
+
return {
|
|
2663
|
+
entries: this.entries.size,
|
|
2664
|
+
bytes: this.bytes,
|
|
2665
|
+
hits: this.hits,
|
|
2666
|
+
misses: this.misses,
|
|
2667
|
+
evictions: this.evictions
|
|
2668
|
+
};
|
|
2669
|
+
}
|
|
2670
|
+
drop(key) {
|
|
2671
|
+
const entry = this.entries.get(key);
|
|
2672
|
+
if (!entry) return;
|
|
2673
|
+
this.entries.delete(key);
|
|
2674
|
+
this.bytes -= entry.sizeBytes;
|
|
2675
|
+
}
|
|
2676
|
+
};
|
|
2677
|
+
var nodeCrypto = globalThis.process?.getBuiltinModule?.("node:crypto");
|
|
2678
|
+
/** Lowercase hex SHA-256 of `input`. */
|
|
2679
|
+
function sha256Hex(input) {
|
|
2680
|
+
if (nodeCrypto) {
|
|
2681
|
+
const hash = nodeCrypto.createHash("sha256");
|
|
2682
|
+
if (typeof input === "string") hash.update(input, "utf16le");
|
|
2683
|
+
else hash.update(input);
|
|
2684
|
+
return hash.digest("hex");
|
|
2685
|
+
}
|
|
2686
|
+
return sha256HexPortable(input);
|
|
2687
|
+
}
|
|
2688
|
+
var K = new Int32Array([
|
|
2689
|
+
1116352408,
|
|
2690
|
+
1899447441,
|
|
2691
|
+
3049323471,
|
|
2692
|
+
3921009573,
|
|
2693
|
+
961987163,
|
|
2694
|
+
1508970993,
|
|
2695
|
+
2453635748,
|
|
2696
|
+
2870763221,
|
|
2697
|
+
3624381080,
|
|
2698
|
+
310598401,
|
|
2699
|
+
607225278,
|
|
2700
|
+
1426881987,
|
|
2701
|
+
1925078388,
|
|
2702
|
+
2162078206,
|
|
2703
|
+
2614888103,
|
|
2704
|
+
3248222580,
|
|
2705
|
+
3835390401,
|
|
2706
|
+
4022224774,
|
|
2707
|
+
264347078,
|
|
2708
|
+
604807628,
|
|
2709
|
+
770255983,
|
|
2710
|
+
1249150122,
|
|
2711
|
+
1555081692,
|
|
2712
|
+
1996064986,
|
|
2713
|
+
2554220882,
|
|
2714
|
+
2821834349,
|
|
2715
|
+
2952996808,
|
|
2716
|
+
3210313671,
|
|
2717
|
+
3336571891,
|
|
2718
|
+
3584528711,
|
|
2719
|
+
113926993,
|
|
2720
|
+
338241895,
|
|
2721
|
+
666307205,
|
|
2722
|
+
773529912,
|
|
2723
|
+
1294757372,
|
|
2724
|
+
1396182291,
|
|
2725
|
+
1695183700,
|
|
2726
|
+
1986661051,
|
|
2727
|
+
2177026350,
|
|
2728
|
+
2456956037,
|
|
2729
|
+
2730485921,
|
|
2730
|
+
2820302411,
|
|
2731
|
+
3259730800,
|
|
2732
|
+
3345764771,
|
|
2733
|
+
3516065817,
|
|
2734
|
+
3600352804,
|
|
2735
|
+
4094571909,
|
|
2736
|
+
275423344,
|
|
2737
|
+
430227734,
|
|
2738
|
+
506948616,
|
|
2739
|
+
659060556,
|
|
2740
|
+
883997877,
|
|
2741
|
+
958139571,
|
|
2742
|
+
1322822218,
|
|
2743
|
+
1537002063,
|
|
2744
|
+
1747873779,
|
|
2745
|
+
1955562222,
|
|
2746
|
+
2024104815,
|
|
2747
|
+
2227730452,
|
|
2748
|
+
2361852424,
|
|
2749
|
+
2428436474,
|
|
2750
|
+
2756734187,
|
|
2751
|
+
3204031479,
|
|
2752
|
+
3329325298
|
|
2753
|
+
]);
|
|
2754
|
+
/** Exported so tests can check it against Node's native hash. */
|
|
2755
|
+
function sha256HexPortable(input) {
|
|
2756
|
+
const state = new Sha256();
|
|
2757
|
+
if (typeof input === "string") state.updateString(input);
|
|
2758
|
+
else state.update(input);
|
|
2759
|
+
return state.digestHex();
|
|
2760
|
+
}
|
|
2761
|
+
var Sha256 = class {
|
|
2762
|
+
h = new Int32Array([
|
|
2763
|
+
1779033703,
|
|
2764
|
+
3144134277,
|
|
2765
|
+
1013904242,
|
|
2766
|
+
2773480762,
|
|
2767
|
+
1359893119,
|
|
2768
|
+
2600822924,
|
|
2769
|
+
528734635,
|
|
2770
|
+
1541459225
|
|
2771
|
+
]);
|
|
2772
|
+
w = /* @__PURE__ */ new Int32Array(64);
|
|
2773
|
+
pending = /* @__PURE__ */ new Uint8Array(64);
|
|
2774
|
+
pendingLength = 0;
|
|
2775
|
+
totalBytes = 0;
|
|
2776
|
+
update(bytes) {
|
|
2777
|
+
this.totalBytes += bytes.length;
|
|
2778
|
+
let offset = 0;
|
|
2779
|
+
if (this.pendingLength > 0) {
|
|
2780
|
+
const take = Math.min(64 - this.pendingLength, bytes.length);
|
|
2781
|
+
this.pending.set(bytes.subarray(0, take), this.pendingLength);
|
|
2782
|
+
this.pendingLength += take;
|
|
2783
|
+
offset = take;
|
|
2784
|
+
if (this.pendingLength < 64) return;
|
|
2785
|
+
this.compressBytes(this.pending, 0);
|
|
2786
|
+
this.pendingLength = 0;
|
|
2787
|
+
}
|
|
2788
|
+
for (; offset + 64 <= bytes.length; offset += 64) this.compressBytes(bytes, offset);
|
|
2789
|
+
this.pending.set(bytes.subarray(offset), 0);
|
|
2790
|
+
this.pendingLength = bytes.length - offset;
|
|
2791
|
+
}
|
|
2792
|
+
/**
|
|
2793
|
+
* Feed a string's UTF-16LE bytes straight into the message words, skipping a byte buffer.
|
|
2794
|
+
* Only on a fresh state: 32 code units fill a block exactly, so nothing may be pending.
|
|
2795
|
+
*/
|
|
2796
|
+
updateString(s) {
|
|
2797
|
+
const w = this.w;
|
|
2798
|
+
const whole = s.length - s.length % 32;
|
|
2799
|
+
for (let offset = 0; offset < whole; offset += 32) {
|
|
2800
|
+
for (let i = 0; i < 16; i++) {
|
|
2801
|
+
const c0 = s.charCodeAt(offset + 2 * i);
|
|
2802
|
+
const c1 = s.charCodeAt(offset + 2 * i + 1);
|
|
2803
|
+
w[i] = (c0 & 255) << 24 | c0 >>> 8 << 16 | (c1 & 255) << 8 | c1 >>> 8;
|
|
2804
|
+
}
|
|
2805
|
+
this.compress();
|
|
2806
|
+
}
|
|
2807
|
+
this.totalBytes += whole * 2;
|
|
2808
|
+
const rest = new Uint8Array((s.length - whole) * 2);
|
|
2809
|
+
for (let i = whole, j = 0; i < s.length; i++) {
|
|
2810
|
+
const code = s.charCodeAt(i);
|
|
2811
|
+
rest[j++] = code & 255;
|
|
2812
|
+
rest[j++] = code >>> 8;
|
|
2813
|
+
}
|
|
2814
|
+
this.update(rest);
|
|
2815
|
+
}
|
|
2816
|
+
digestHex() {
|
|
2817
|
+
const bitLength = this.totalBytes * 8;
|
|
2818
|
+
const tail = new Uint8Array(this.pendingLength < 56 ? 64 : 128);
|
|
2819
|
+
tail.set(this.pending.subarray(0, this.pendingLength));
|
|
2820
|
+
tail[this.pendingLength] = 128;
|
|
2821
|
+
const view = new DataView(tail.buffer);
|
|
2822
|
+
view.setUint32(tail.length - 8, Math.floor(bitLength / 4294967296));
|
|
2823
|
+
view.setUint32(tail.length - 4, bitLength >>> 0);
|
|
2824
|
+
for (let offset = 0; offset < tail.length; offset += 64) this.compressBytes(tail, offset);
|
|
2825
|
+
let hex = "";
|
|
2826
|
+
for (const word of this.h) hex += (word >>> 0).toString(16).padStart(8, "0");
|
|
2827
|
+
return hex;
|
|
2828
|
+
}
|
|
2829
|
+
compressBytes(bytes, offset) {
|
|
2830
|
+
const w = this.w;
|
|
2831
|
+
for (let i = 0; i < 16; i++) {
|
|
2832
|
+
const j = offset + i * 4;
|
|
2833
|
+
w[i] = bytes[j] << 24 | bytes[j + 1] << 16 | bytes[j + 2] << 8 | bytes[j + 3];
|
|
2834
|
+
}
|
|
2835
|
+
this.compress();
|
|
2836
|
+
}
|
|
2837
|
+
/** One block, from the 16 message words already in `w`. */
|
|
2838
|
+
compress() {
|
|
2839
|
+
const w = this.w;
|
|
2840
|
+
for (let i = 16; i < 64; i++) {
|
|
2841
|
+
const x = w[i - 15];
|
|
2842
|
+
const y = w[i - 2];
|
|
2843
|
+
const s0 = (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ x >>> 3;
|
|
2844
|
+
const s1 = (y >>> 17 | y << 15) ^ (y >>> 19 | y << 13) ^ y >>> 10;
|
|
2845
|
+
w[i] = w[i - 16] + s0 + w[i - 7] + s1 | 0;
|
|
2846
|
+
}
|
|
2847
|
+
const h = this.h;
|
|
2848
|
+
let a = h[0];
|
|
2849
|
+
let b = h[1];
|
|
2850
|
+
let c = h[2];
|
|
2851
|
+
let d = h[3];
|
|
2852
|
+
let e = h[4];
|
|
2853
|
+
let f = h[5];
|
|
2854
|
+
let g = h[6];
|
|
2855
|
+
let k = h[7];
|
|
2856
|
+
for (let i = 0; i < 64; i++) {
|
|
2857
|
+
const S1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
|
|
2858
|
+
const ch = e & f ^ ~e & g;
|
|
2859
|
+
const t1 = k + S1 + ch + K[i] + w[i] | 0;
|
|
2860
|
+
const t2 = ((a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10)) + (a & b ^ a & c ^ b & c) | 0;
|
|
2861
|
+
k = g;
|
|
2862
|
+
g = f;
|
|
2863
|
+
f = e;
|
|
2864
|
+
e = d + t1 | 0;
|
|
2865
|
+
d = c;
|
|
2866
|
+
c = b;
|
|
2867
|
+
b = a;
|
|
2868
|
+
a = t1 + t2 | 0;
|
|
2869
|
+
}
|
|
2870
|
+
h[0] = h[0] + a | 0;
|
|
2871
|
+
h[1] = h[1] + b | 0;
|
|
2872
|
+
h[2] = h[2] + c | 0;
|
|
2873
|
+
h[3] = h[3] + d | 0;
|
|
2874
|
+
h[4] = h[4] + e | 0;
|
|
2875
|
+
h[5] = h[5] + f | 0;
|
|
2876
|
+
h[6] = h[6] + g | 0;
|
|
2877
|
+
h[7] = h[7] + k | 0;
|
|
2878
|
+
}
|
|
2879
|
+
};
|
|
2880
|
+
/**
|
|
2881
|
+
* Solve-key hashing, public so an app-layer durable cache or a pre-solved bundle viewer can
|
|
2882
|
+
* reproduce the scheduler's exact key. A key that canonicalizes even slightly differently
|
|
2883
|
+
* misses every entry the scheduler wrote, or worse, collides differently.
|
|
2884
|
+
*
|
|
2885
|
+
* Keys are SHA-256: one scheduler's cache serves every user of a server, so a key a user can
|
|
2886
|
+
* collide on purpose lets them choose what another user's solve returns.
|
|
2887
|
+
*/
|
|
2888
|
+
/**
|
|
2889
|
+
* Deterministic stringify with sorted keys. {a:1,b:2} and {b:2,a:1} produce
|
|
2890
|
+
* the same string. Safely handles circular references and non-finite numbers.
|
|
2891
|
+
*
|
|
2892
|
+
* The output is a cache key, so the invariant that matters is: two payloads
|
|
2893
|
+
* that serialize differently on the wire must stringify differently here
|
|
2894
|
+
* (false misses are harmless; false hits serve the wrong cached solve).
|
|
2895
|
+
* Non-JSON values get unquoted markers (`{u8:…}`, `[Circular]`) that no JSON
|
|
2896
|
+
* value stringifies to, so a plain object can't pose as one.
|
|
2897
|
+
*/
|
|
2898
|
+
function stableStringify(value) {
|
|
2899
|
+
const path = /* @__PURE__ */ new WeakSet();
|
|
2900
|
+
const stringify = (v) => {
|
|
2901
|
+
if (v === null) return "null";
|
|
2902
|
+
if (typeof v === "number") return Number.isFinite(v) ? String(v) : "null";
|
|
2903
|
+
if (typeof v === "string" || typeof v === "boolean") return JSON.stringify(v);
|
|
2904
|
+
if (typeof v === "bigint") return `${v}n`;
|
|
2905
|
+
if (typeof v !== "object") return "undefined";
|
|
2906
|
+
if (v instanceof Uint8Array) return `{u8:${sha256Hex(v)}}`;
|
|
2907
|
+
if (path.has(v)) return "[Circular]";
|
|
2908
|
+
path.add(v);
|
|
2909
|
+
let out;
|
|
2910
|
+
if (Array.isArray(v)) {
|
|
2911
|
+
const parts = [];
|
|
2912
|
+
for (let i = 0; i < v.length; i++) parts.push(stringify(v[i]));
|
|
2913
|
+
out = `[${parts.join(",")}]`;
|
|
2914
|
+
} else if (typeof v.toJSON === "function") out = stringify(v.toJSON());
|
|
2915
|
+
else if (v instanceof Map) out = `{map:[${[...v.entries()].map(([k, val]) => `[${stringify(k)},${stringify(val)}]`).sort().join(",")}]}`;
|
|
2916
|
+
else if (v instanceof Set) out = `{set:[${[...v.values()].map(stringify).sort().join(",")}]}`;
|
|
2917
|
+
else out = `{${Object.keys(v).sort().map((k) => `${JSON.stringify(k)}:${stringify(v[k])}`).join(",")}}`;
|
|
2918
|
+
path.delete(v);
|
|
2919
|
+
return out;
|
|
2920
|
+
};
|
|
2921
|
+
return stringify(value);
|
|
2922
|
+
}
|
|
2923
|
+
/**
|
|
2924
|
+
* `hashSolveInput` from a precomputed {@link hashDefinition}, so the scheduler, which also keys its
|
|
2925
|
+
* server-cache-key map by that hash, passes over a multi-MB definition once per solve.
|
|
2926
|
+
*/
|
|
2927
|
+
function hashSolveInputForDefinition(definitionHash, dataTree) {
|
|
2928
|
+
return `${definitionHash}|t:${sha256Hex(stableStringify(dataTree))}`;
|
|
2929
|
+
}
|
|
2930
|
+
/**
|
|
2931
|
+
* A definition's identity, without its inputs. Strings and bytes are hashed over their full
|
|
2932
|
+
* content; a `DefinitionRef` uses its `key`.
|
|
2933
|
+
*/
|
|
2934
|
+
function hashDefinition(definition) {
|
|
2935
|
+
if (isDefinitionRef(definition)) return `r:${definition.key}`;
|
|
2936
|
+
return typeof definition === "string" ? `s:${sha256Hex(definition)}` : `u8:${sha256Hex(definition)}`;
|
|
2937
|
+
}
|
|
2938
|
+
var SERVER_CACHE_KEYS_MAX = 100;
|
|
2939
|
+
/** `NaN` passes `Math.max` and fails every `inFlight < limit`, so nothing would ever dispatch. */
|
|
2940
|
+
function concurrencyLimit(value) {
|
|
2941
|
+
if (Number.isNaN(value)) throw new ComputeError("maxConcurrent must be a number", ErrorCodes.INVALID_CONFIG, { context: { maxConcurrent: value } });
|
|
2942
|
+
return Math.max(1, Math.floor(value));
|
|
2943
|
+
}
|
|
2944
|
+
var u8DefinitionHashes = /* @__PURE__ */ new WeakMap();
|
|
2945
|
+
/**
|
|
2946
|
+
* Remembers a buffer's hash by identity: a buffer mutated after its first solve keeps its old
|
|
2947
|
+
* hash and is served the old content's cached solves.
|
|
2948
|
+
*/
|
|
2949
|
+
function hashDefinitionOnce(definition) {
|
|
2950
|
+
if (!(definition instanceof Uint8Array)) return hashDefinition(definition);
|
|
2951
|
+
let hash = u8DefinitionHashes.get(definition);
|
|
2952
|
+
if (hash === void 0) {
|
|
2953
|
+
hash = hashDefinition(definition);
|
|
2954
|
+
u8DefinitionHashes.set(definition, hash);
|
|
2955
|
+
}
|
|
2956
|
+
return hash;
|
|
2957
|
+
}
|
|
2958
|
+
/** One solve's input hashes, each taken on first use. */
|
|
2959
|
+
var SolveInputHashes = class {
|
|
2960
|
+
hashDefinition;
|
|
2961
|
+
dataTree;
|
|
2962
|
+
definitionMemo;
|
|
2963
|
+
keyMemo;
|
|
2964
|
+
constructor(hashDefinition, dataTree) {
|
|
2965
|
+
this.hashDefinition = hashDefinition;
|
|
2966
|
+
this.dataTree = dataTree;
|
|
2967
|
+
}
|
|
2968
|
+
get definitionHash() {
|
|
2969
|
+
return this.definitionMemo ??= this.hashDefinition();
|
|
2970
|
+
}
|
|
2971
|
+
get key() {
|
|
2972
|
+
return this.keyMemo ??= hashSolveInputForDefinition(this.definitionHash, this.dataTree);
|
|
2973
|
+
}
|
|
2974
|
+
};
|
|
2975
|
+
/**
|
|
2976
|
+
* The FIFO behind `queue` mode. Removing an item only drops it from `live`; the array is swept once
|
|
2977
|
+
* the dead entries outnumber the live ones, so aborting n queued solves costs O(n), not O(n²).
|
|
2978
|
+
*/
|
|
2979
|
+
var SolveQueue = class {
|
|
2980
|
+
items = [];
|
|
2981
|
+
head = 0;
|
|
2982
|
+
live = /* @__PURE__ */ new Set();
|
|
2983
|
+
get size() {
|
|
2984
|
+
return this.live.size;
|
|
2985
|
+
}
|
|
2986
|
+
push(item) {
|
|
2987
|
+
this.items.push(item);
|
|
2988
|
+
this.live.add(item);
|
|
2989
|
+
}
|
|
2990
|
+
remove(item) {
|
|
2991
|
+
if (this.live.delete(item)) this.compact();
|
|
2992
|
+
}
|
|
2993
|
+
shift() {
|
|
2994
|
+
while (this.head < this.items.length) {
|
|
2995
|
+
const item = this.items[this.head];
|
|
2996
|
+
this.items[this.head++] = void 0;
|
|
2997
|
+
if (item && this.live.delete(item)) {
|
|
2998
|
+
this.compact();
|
|
2999
|
+
return item;
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
compact() {
|
|
3004
|
+
if (this.live.size === 0) {
|
|
3005
|
+
this.items = [];
|
|
3006
|
+
this.head = 0;
|
|
3007
|
+
return;
|
|
3008
|
+
}
|
|
3009
|
+
const dead = this.items.length - this.live.size;
|
|
3010
|
+
if (dead <= 64 || dead <= this.live.size) return;
|
|
3011
|
+
this.items = this.items.filter((item) => item !== void 0 && this.live.has(item));
|
|
3012
|
+
this.head = 0;
|
|
3013
|
+
}
|
|
3014
|
+
};
|
|
3015
|
+
/**
|
|
3016
|
+
* Adds to a plain solve call:
|
|
3017
|
+
* - Scheduling (latest-wins for sliders, queue for jobs)
|
|
3018
|
+
* - Backpressure (bounded queue depth + queue-wait deadline)
|
|
3019
|
+
* - Cancellation (per-call signal + cancelAll)
|
|
3020
|
+
* - Optional response caching for repeated inputs
|
|
3021
|
+
* - Lifecycle hooks (start / settle / superseded) and state via subscribe()
|
|
3022
|
+
*
|
|
3023
|
+
* @example
|
|
3024
|
+
* ```ts
|
|
3025
|
+
* const scheduler = client.createScheduler({ mode: 'latest-wins', timeoutMs: 30_000 });
|
|
3026
|
+
*
|
|
3027
|
+
* // From a slider handler:
|
|
3028
|
+
* scheduler.solve(definition, tree).then((result) => {
|
|
3029
|
+
* updateMeshes(result);
|
|
3030
|
+
* }).catch((err) => {
|
|
3031
|
+
* if (err.code !== 'SUPERSEDED') showError(err);
|
|
3032
|
+
* });
|
|
3033
|
+
*
|
|
3034
|
+
* // From a UI binding:
|
|
3035
|
+
* scheduler.subscribe(() => {
|
|
3036
|
+
* showSpinner = scheduler.isSolving;
|
|
3037
|
+
* });
|
|
3038
|
+
* ```
|
|
3039
|
+
*/
|
|
3040
|
+
var SolveScheduler = class {
|
|
3041
|
+
executor;
|
|
3042
|
+
baseConfig;
|
|
3043
|
+
mode;
|
|
3044
|
+
maxConcurrent;
|
|
3045
|
+
maxQueueDepth;
|
|
3046
|
+
queueWaitMs;
|
|
3047
|
+
timeoutMs;
|
|
3048
|
+
retry;
|
|
3049
|
+
cache;
|
|
3050
|
+
reuseServerDefinitionCache;
|
|
3051
|
+
/** Definition hash → the server's cache key (`pointer`) for it. */
|
|
3052
|
+
serverCacheKeys = /* @__PURE__ */ new Map();
|
|
3053
|
+
/** A string definition re-sent unchanged is compared with this, far cheaper than hashing it. */
|
|
3054
|
+
lastStringDefinition = null;
|
|
3055
|
+
onStart;
|
|
3056
|
+
onSettle;
|
|
3057
|
+
onSuperseded;
|
|
3058
|
+
subscribers = /* @__PURE__ */ new Set();
|
|
3059
|
+
inFlight = /* @__PURE__ */ new Set();
|
|
3060
|
+
pendingForLatestWins = null;
|
|
3061
|
+
fifo = new SolveQueue();
|
|
3062
|
+
_lastResult = null;
|
|
3063
|
+
_lastError = null;
|
|
3064
|
+
_lastDurationMs = null;
|
|
3065
|
+
solveSeq = 0;
|
|
3066
|
+
/** seq of the solve that last wrote `_lastResult`/`_lastError`. */
|
|
3067
|
+
lastStateSeq = 0;
|
|
3068
|
+
disposed = false;
|
|
3069
|
+
constructor(executor, baseConfig, options = {}) {
|
|
3070
|
+
this.executor = executor;
|
|
3071
|
+
this.baseConfig = baseConfig;
|
|
3072
|
+
this.mode = options.mode ?? "latest-wins";
|
|
3073
|
+
if (this.mode !== "latest-wins" && this.mode !== "queue") throw new ComputeError(`Unknown scheduler mode '${String(this.mode)}'. For concurrent solves use { mode: 'queue', maxConcurrent: 4 }.`, ErrorCodes.INVALID_CONFIG, { context: { mode: this.mode } });
|
|
3074
|
+
this.maxConcurrent = concurrencyLimit(options.maxConcurrent ?? 1);
|
|
3075
|
+
this.maxQueueDepth = options.maxQueueDepth !== void 0 && options.maxQueueDepth > 0 ? Math.floor(options.maxQueueDepth) : void 0;
|
|
3076
|
+
this.queueWaitMs = options.queueWaitMs !== void 0 && options.queueWaitMs > 0 ? options.queueWaitMs : void 0;
|
|
3077
|
+
this.timeoutMs = options.timeoutMs;
|
|
3078
|
+
this.retry = options.retry;
|
|
3079
|
+
this.cache = new ResponseCache(options.cache);
|
|
3080
|
+
this.reuseServerDefinitionCache = options.reuseServerDefinitionCache ?? true;
|
|
3081
|
+
this.onStart = options.onStart;
|
|
3082
|
+
this.onSettle = options.onSettle;
|
|
3083
|
+
this.onSuperseded = options.onSuperseded;
|
|
3084
|
+
}
|
|
3085
|
+
get isSolving() {
|
|
3086
|
+
return this.inFlight.size > 0;
|
|
3087
|
+
}
|
|
3088
|
+
get hasPending() {
|
|
3089
|
+
return this.pendingForLatestWins !== null || this.fifo.size > 0;
|
|
3090
|
+
}
|
|
3091
|
+
get inFlightCount() {
|
|
3092
|
+
return this.inFlight.size;
|
|
3093
|
+
}
|
|
3094
|
+
get queueDepth() {
|
|
3095
|
+
return this.fifo.size + (this.pendingForLatestWins ? 1 : 0);
|
|
3096
|
+
}
|
|
3097
|
+
get lastResult() {
|
|
3098
|
+
return this._lastResult;
|
|
3099
|
+
}
|
|
3100
|
+
get lastError() {
|
|
3101
|
+
return this._lastError;
|
|
3102
|
+
}
|
|
3103
|
+
get lastDurationMs() {
|
|
3104
|
+
return this._lastDurationMs;
|
|
3105
|
+
}
|
|
3106
|
+
/**
|
|
3107
|
+
* Adjust how many solves may run at once, for when the compute server's worker
|
|
3108
|
+
* pool changes size after this scheduler was built.
|
|
3109
|
+
*
|
|
3110
|
+
* Raising it drains queued work immediately. Lowering it never interrupts work
|
|
3111
|
+
* already in flight — those finish above the new limit, and the cap applies from
|
|
3112
|
+
* the next dispatch. Values below 1 are clamped, since 0 would wedge the queue.
|
|
3113
|
+
*
|
|
3114
|
+
* @throws {ComputeError} `INVALID_CONFIG` for `NaN`, which would wedge it too.
|
|
3115
|
+
*/
|
|
3116
|
+
setMaxConcurrent(value) {
|
|
3117
|
+
const next = concurrencyLimit(value);
|
|
3118
|
+
if (next === this.maxConcurrent) return;
|
|
3119
|
+
const raised = next > this.maxConcurrent;
|
|
3120
|
+
this.maxConcurrent = next;
|
|
3121
|
+
if (raised) this.drainNext();
|
|
3122
|
+
}
|
|
3123
|
+
/** Subscribe to state changes. */
|
|
3124
|
+
subscribe(listener) {
|
|
3125
|
+
this.subscribers.add(listener);
|
|
3126
|
+
return () => this.subscribers.delete(listener);
|
|
3127
|
+
}
|
|
3128
|
+
notify() {
|
|
3129
|
+
for (const listener of this.subscribers) try {
|
|
3130
|
+
listener();
|
|
3131
|
+
} catch (err) {
|
|
3132
|
+
getLogger().error("[SolveScheduler] subscriber threw:", err);
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
/**
|
|
3136
|
+
* Schedule a solve. Returns a promise that:
|
|
3137
|
+
* - Resolves with the compute response on success.
|
|
3138
|
+
* - Rejects with `ComputeError` on failure.
|
|
3139
|
+
* - Rejects with `code: ErrorCodes.SUPERSEDED` when the call was canceled because
|
|
3140
|
+
* newer values arrived (latest-wins mode).
|
|
3141
|
+
* - Rejects with `code: ErrorCodes.ABORTED` when the call was canceled via
|
|
3142
|
+
* its own `signal` (queued or running) or `cancelAll()`.
|
|
3143
|
+
* - Rejects with `code: ErrorCodes.QUEUE_FULL` when `maxQueueDepth` is set and
|
|
3144
|
+
* the queue was already full (backpressure; `statusCode: 503`).
|
|
3145
|
+
* - Rejects with `code: ErrorCodes.QUEUE_TIMEOUT` when `queueWaitMs` is set and
|
|
3146
|
+
* the call sat queued longer than that before starting (`statusCode: 503`).
|
|
3147
|
+
*
|
|
3148
|
+
* Don't mutate a `Uint8Array` definition after solving it. Responses served
|
|
3149
|
+
* from the cache (and via `lastResult`) are shared objects, not copies —
|
|
3150
|
+
* treat them as immutable. Mutating one poisons every later cache hit for
|
|
3151
|
+
* that key.
|
|
3152
|
+
*
|
|
3153
|
+
* Partial-success contract: unlike `GrasshopperClient.solve()`, which throws
|
|
3154
|
+
* `COMPUTATION_ERROR` when the response carries solver errors, this RESOLVES
|
|
3155
|
+
* with the response as-is — check `response.errors` yourself if a partial
|
|
3156
|
+
* success must not be treated as a result (see `cacheErroredSolves` for the
|
|
3157
|
+
* caching side of the same distinction).
|
|
3158
|
+
*/
|
|
3159
|
+
solve(definition, dataTree, options) {
|
|
3160
|
+
return this.solveDetailed(definition, dataTree, options).then((detail) => detail.response);
|
|
3161
|
+
}
|
|
3162
|
+
/** {@link solve}, also resolving with whether this call hit the cache and how long it took. */
|
|
3163
|
+
solveDetailed(definition, dataTree, options) {
|
|
3164
|
+
if (this.disposed) return Promise.reject(new ComputeError("SolveScheduler has been disposed and cannot be used", ErrorCodes.INVALID_STATE));
|
|
3165
|
+
const hashes = new SolveInputHashes(() => this.hashDefinitionMemo(definition), dataTree);
|
|
3166
|
+
let key = "";
|
|
3167
|
+
if (this.cache.enabled || this.onStart || this.onSettle || this.onSuperseded) try {
|
|
3168
|
+
key = hashes.key;
|
|
3169
|
+
} catch (error) {
|
|
3170
|
+
return Promise.reject(new ComputeError("Solve input could not be hashed", ErrorCodes.INVALID_INPUT, { originalError: error }));
|
|
3171
|
+
}
|
|
3172
|
+
const seq = ++this.solveSeq;
|
|
3173
|
+
const ctx = {
|
|
3174
|
+
key,
|
|
3175
|
+
enqueuedAt: Date.now(),
|
|
3176
|
+
startedAt: null
|
|
3177
|
+
};
|
|
3178
|
+
if (options?.signal?.aborted) return Promise.reject(this.makeAbortError(ctx));
|
|
3179
|
+
const cached = this.cache.get(key);
|
|
3180
|
+
if (cached) {
|
|
3181
|
+
if (this.mode === "latest-wins") this.supersedeCurrent();
|
|
3182
|
+
const result = {
|
|
3183
|
+
status: "success",
|
|
3184
|
+
response: cached,
|
|
3185
|
+
durationMs: 0,
|
|
3186
|
+
fromCache: true
|
|
3187
|
+
};
|
|
3188
|
+
this.writeLastState(seq, {
|
|
3189
|
+
result: cached,
|
|
3190
|
+
durationMs: 0
|
|
3191
|
+
});
|
|
3192
|
+
this.runHook(this.onStart, ctx);
|
|
3193
|
+
this.runHook(this.onSettle, ctx, result);
|
|
3194
|
+
this.notify();
|
|
3195
|
+
return Promise.resolve({
|
|
3196
|
+
response: cached,
|
|
3197
|
+
fromCache: true,
|
|
3198
|
+
durationMs: 0
|
|
3199
|
+
});
|
|
3200
|
+
}
|
|
3201
|
+
return new Promise((resolve, reject) => {
|
|
3202
|
+
const item = {
|
|
3203
|
+
definition,
|
|
3204
|
+
dataTree,
|
|
3205
|
+
hashes,
|
|
3206
|
+
ctx,
|
|
3207
|
+
seq,
|
|
3208
|
+
resolve,
|
|
3209
|
+
reject,
|
|
3210
|
+
externalSignal: options?.signal,
|
|
3211
|
+
selvaevents: options?.selvaevents,
|
|
3212
|
+
onServerTiming: options?.onServerTiming
|
|
3213
|
+
};
|
|
3214
|
+
if (item.externalSignal) {
|
|
3215
|
+
item.onExternalAbort = () => {
|
|
3216
|
+
if (item.controller) item.controller.abort();
|
|
3217
|
+
else this.abortQueuedItem(item);
|
|
3218
|
+
};
|
|
3219
|
+
item.externalSignal.addEventListener("abort", item.onExternalAbort, { once: true });
|
|
3220
|
+
}
|
|
3221
|
+
this.enqueue(item);
|
|
3222
|
+
});
|
|
3223
|
+
}
|
|
3224
|
+
/** A slow solve settling late must not overwrite state a newer solve or cache hit published. */
|
|
3225
|
+
writeLastState(seq, state) {
|
|
3226
|
+
if (seq < this.lastStateSeq) return;
|
|
3227
|
+
this.lastStateSeq = seq;
|
|
3228
|
+
if ("result" in state) {
|
|
3229
|
+
this._lastResult = state.result;
|
|
3230
|
+
this._lastError = null;
|
|
3231
|
+
} else this._lastError = state.error;
|
|
3232
|
+
this._lastDurationMs = state.durationMs;
|
|
3233
|
+
}
|
|
3234
|
+
/** latest-wins: supersede the pending item and abort everything in flight. */
|
|
3235
|
+
supersedeCurrent() {
|
|
3236
|
+
if (this.pendingForLatestWins) {
|
|
3237
|
+
this.supersede(this.pendingForLatestWins);
|
|
3238
|
+
this.pendingForLatestWins = null;
|
|
3239
|
+
}
|
|
3240
|
+
for (const inflight of this.inFlight) {
|
|
3241
|
+
this.supersede(inflight);
|
|
3242
|
+
inflight.controller.abort();
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
dequeue(item) {
|
|
3246
|
+
if (this.pendingForLatestWins === item) this.pendingForLatestWins = null;
|
|
3247
|
+
this.fifo.remove(item);
|
|
3248
|
+
}
|
|
3249
|
+
abortQueuedItem(item) {
|
|
3250
|
+
this.dequeue(item);
|
|
3251
|
+
this.fail(item, this.makeAbortError(item.ctx));
|
|
3252
|
+
this.notify();
|
|
3253
|
+
}
|
|
3254
|
+
/** The structured context lets an HTTP layer map QUEUE_FULL to 503 + Retry-After. */
|
|
3255
|
+
shedAsQueueFull(item) {
|
|
3256
|
+
const err = new ComputeError("Solve queue is full; request rejected (backpressure)", ErrorCodes.QUEUE_FULL, {
|
|
3257
|
+
statusCode: 503,
|
|
3258
|
+
context: {
|
|
3259
|
+
queueDepth: this.fifo.size,
|
|
3260
|
+
maxQueueDepth: this.maxQueueDepth
|
|
3261
|
+
}
|
|
3262
|
+
});
|
|
3263
|
+
this.fail(item, err);
|
|
3264
|
+
this.notify();
|
|
3265
|
+
}
|
|
3266
|
+
armQueueWaitTimer(item) {
|
|
3267
|
+
if (this.queueWaitMs === void 0) return;
|
|
3268
|
+
const waitMs = this.queueWaitMs;
|
|
3269
|
+
item.queueWaitTimer = setTimeout(() => {
|
|
3270
|
+
if (item.settled) return;
|
|
3271
|
+
this.dequeue(item);
|
|
3272
|
+
const err = new ComputeError(`Solve waited longer than ${waitMs}ms in queue; rejected (backpressure)`, ErrorCodes.QUEUE_TIMEOUT, {
|
|
3273
|
+
statusCode: 503,
|
|
3274
|
+
context: {
|
|
3275
|
+
waitedMs: Date.now() - item.ctx.enqueuedAt,
|
|
3276
|
+
queueWaitMs: waitMs
|
|
3277
|
+
}
|
|
3278
|
+
});
|
|
3279
|
+
this.fail(item, err);
|
|
3280
|
+
this.notify();
|
|
3281
|
+
}, waitMs);
|
|
3282
|
+
}
|
|
3283
|
+
clearQueueWaitTimer(item) {
|
|
3284
|
+
if (item.queueWaitTimer !== void 0) {
|
|
3285
|
+
clearTimeout(item.queueWaitTimer);
|
|
3286
|
+
item.queueWaitTimer = void 0;
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
enqueue(item) {
|
|
3290
|
+
switch (this.mode) {
|
|
3291
|
+
case "latest-wins":
|
|
3292
|
+
this.supersedeCurrent();
|
|
3293
|
+
if (this.inFlight.size === 0) this.execute(item);
|
|
3294
|
+
else this.pendingForLatestWins = item;
|
|
3295
|
+
break;
|
|
3296
|
+
case "queue": if (this.inFlight.size < this.maxConcurrent) this.execute(item);
|
|
3297
|
+
else if (this.maxQueueDepth !== void 0 && this.fifo.size >= this.maxQueueDepth) this.shedAsQueueFull(item);
|
|
3298
|
+
else {
|
|
3299
|
+
this.armQueueWaitTimer(item);
|
|
3300
|
+
this.fifo.push(item);
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
this.notify();
|
|
3304
|
+
}
|
|
3305
|
+
async execute(item) {
|
|
3306
|
+
const controller = new AbortController();
|
|
3307
|
+
const inflight = item;
|
|
3308
|
+
inflight.controller = controller;
|
|
3309
|
+
this.inFlight.add(inflight);
|
|
3310
|
+
item.ctx.startedAt = Date.now();
|
|
3311
|
+
this.clearQueueWaitTimer(item);
|
|
3312
|
+
this.runHook(this.onStart, item.ctx);
|
|
3313
|
+
this.notify();
|
|
3314
|
+
const startTime = performance.now();
|
|
3315
|
+
try {
|
|
3316
|
+
const config = {
|
|
3317
|
+
...this.baseConfig,
|
|
3318
|
+
signal: controller.signal,
|
|
3319
|
+
...this.timeoutMs !== void 0 && { timeoutMs: this.timeoutMs },
|
|
3320
|
+
...this.retry !== void 0 && { retry: this.retry },
|
|
3321
|
+
...item.selvaevents !== void 0 && { selvaevents: item.selvaevents }
|
|
3322
|
+
};
|
|
3323
|
+
const callTiming = item.onServerTiming;
|
|
3324
|
+
if (callTiming) {
|
|
3325
|
+
const baseTiming = this.baseConfig.onServerTiming;
|
|
3326
|
+
config.onServerTiming = (timing, requestId) => {
|
|
3327
|
+
try {
|
|
3328
|
+
baseTiming?.(timing, requestId);
|
|
3329
|
+
} finally {
|
|
3330
|
+
callTiming(timing, requestId);
|
|
3331
|
+
}
|
|
3332
|
+
};
|
|
3333
|
+
}
|
|
3334
|
+
const { response, definitionReuploaded } = await this.runExecutor(item, config);
|
|
3335
|
+
const durationMs = performance.now() - startTime;
|
|
3336
|
+
if (!this.disposed) this.cache.set(item.ctx.key, response);
|
|
3337
|
+
if (!this.settleSuccess(item, {
|
|
3338
|
+
response,
|
|
3339
|
+
fromCache: false,
|
|
3340
|
+
definitionReuploaded,
|
|
3341
|
+
durationMs
|
|
3342
|
+
})) return;
|
|
3343
|
+
this.writeLastState(item.seq, {
|
|
3344
|
+
result: response,
|
|
3345
|
+
durationMs
|
|
3346
|
+
});
|
|
3347
|
+
this.runHook(this.onSettle, item.ctx, {
|
|
3348
|
+
status: "success",
|
|
3349
|
+
response,
|
|
3350
|
+
durationMs,
|
|
3351
|
+
fromCache: false,
|
|
3352
|
+
definitionReuploaded
|
|
3353
|
+
});
|
|
3354
|
+
} catch (error) {
|
|
3355
|
+
const durationMs = performance.now() - startTime;
|
|
3356
|
+
const err = this.normalizeExecutionError(error, inflight);
|
|
3357
|
+
this.writeLastState(item.seq, {
|
|
3358
|
+
error: err,
|
|
3359
|
+
durationMs
|
|
3360
|
+
});
|
|
3361
|
+
this.fail(item, err, durationMs);
|
|
3362
|
+
} finally {
|
|
3363
|
+
this.inFlight.delete(inflight);
|
|
3364
|
+
this.drainNext();
|
|
3365
|
+
this.notify();
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
async runExecutor(item, config) {
|
|
3369
|
+
const { definition, dataTree } = item;
|
|
3370
|
+
if (!this.reuseServerDefinitionCache || isDefinitionUrl(definition)) {
|
|
3371
|
+
const { response } = await this.executor(definition, dataTree, null, config);
|
|
3372
|
+
return { response };
|
|
3373
|
+
}
|
|
3374
|
+
const definitionHash = item.hashes.definitionHash;
|
|
3375
|
+
const knownKey = this.serverCacheKeys.get(definitionHash) ?? null;
|
|
3376
|
+
const result = await this.executor(definition, dataTree, knownKey, config);
|
|
3377
|
+
this.serverCacheKeys.delete(definitionHash);
|
|
3378
|
+
if (result.cacheKey) {
|
|
3379
|
+
this.serverCacheKeys.set(definitionHash, result.cacheKey);
|
|
3380
|
+
if (this.serverCacheKeys.size > SERVER_CACHE_KEYS_MAX) this.serverCacheKeys.delete(this.serverCacheKeys.keys().next().value);
|
|
3381
|
+
}
|
|
3382
|
+
return {
|
|
3383
|
+
response: result.response,
|
|
3384
|
+
definitionReuploaded: result.missed
|
|
3385
|
+
};
|
|
3386
|
+
}
|
|
3387
|
+
hashDefinitionMemo(definition) {
|
|
3388
|
+
if (typeof definition !== "string") return hashDefinitionOnce(definition);
|
|
3389
|
+
if (this.lastStringDefinition?.value !== definition) this.lastStringDefinition = {
|
|
3390
|
+
value: definition,
|
|
3391
|
+
hash: hashDefinition(definition)
|
|
3392
|
+
};
|
|
3393
|
+
return this.lastStringDefinition.hash;
|
|
3394
|
+
}
|
|
3395
|
+
drainNext() {
|
|
3396
|
+
if (this.disposed) return;
|
|
3397
|
+
if (this.mode === "latest-wins") {
|
|
3398
|
+
if (this.pendingForLatestWins && this.inFlight.size === 0) {
|
|
3399
|
+
const next = this.pendingForLatestWins;
|
|
3400
|
+
this.pendingForLatestWins = null;
|
|
3401
|
+
this.execute(next);
|
|
3402
|
+
}
|
|
3403
|
+
return;
|
|
3404
|
+
}
|
|
3405
|
+
while (this.fifo.size > 0 && this.inFlight.size < this.maxConcurrent) this.execute(this.fifo.shift());
|
|
3406
|
+
}
|
|
3407
|
+
supersede(item) {
|
|
3408
|
+
const err = new ComputeError("Superseded by newer solve", ErrorCodes.SUPERSEDED, { context: { enqueuedAt: item.ctx.enqueuedAt } });
|
|
3409
|
+
if (this.settleError(item, err)) this.runHook(this.onSuperseded, item.ctx);
|
|
3410
|
+
}
|
|
3411
|
+
makeAbortError(ctx) {
|
|
3412
|
+
return abortedByCaller({ enqueuedAt: ctx.enqueuedAt });
|
|
3413
|
+
}
|
|
3414
|
+
/**
|
|
3415
|
+
* The executor, `supersede`, `cancelAll`, abort and the queue limits can all race to settle one
|
|
3416
|
+
* item, and a promise ignores a second settle silently. The first settle wins; the return value
|
|
3417
|
+
* says whether this call won, so only the winner fires its hook. Every settle path goes through
|
|
3418
|
+
* here or {@link settleSuccess}.
|
|
3419
|
+
*/
|
|
3420
|
+
settleError(item, err) {
|
|
3421
|
+
if (!this.claimSettle(item, { error: err })) return false;
|
|
3422
|
+
item.reject(err);
|
|
3423
|
+
return true;
|
|
3424
|
+
}
|
|
3425
|
+
/**
|
|
3426
|
+
* Fires `onSettle` for queued items too, so a consumer counting solves in progress doesn't
|
|
3427
|
+
* leak one. A supersede settles through {@link settleError} and fires `onSuperseded` instead.
|
|
3428
|
+
*/
|
|
3429
|
+
fail(item, err, durationMs = 0) {
|
|
3430
|
+
if (this.settleError(item, err)) this.runHook(this.onSettle, item.ctx, {
|
|
3431
|
+
status: "error",
|
|
3432
|
+
error: err,
|
|
3433
|
+
durationMs
|
|
3434
|
+
});
|
|
3435
|
+
}
|
|
3436
|
+
settleSuccess(item, detail) {
|
|
3437
|
+
if (!this.claimSettle(item, { ok: true })) return false;
|
|
3438
|
+
item.resolve(detail);
|
|
3439
|
+
return true;
|
|
3440
|
+
}
|
|
3441
|
+
claimSettle(item, settled) {
|
|
3442
|
+
if (item.settled) return false;
|
|
3443
|
+
item.settled = settled;
|
|
3444
|
+
this.clearQueueWaitTimer(item);
|
|
3445
|
+
if (item.onExternalAbort) item.externalSignal?.removeEventListener("abort", item.onExternalAbort);
|
|
3446
|
+
return true;
|
|
3447
|
+
}
|
|
3448
|
+
normalizeExecutionError(error, item) {
|
|
3449
|
+
if (item.settled && "error" in item.settled) return item.settled.error;
|
|
3450
|
+
if (error instanceof ComputeError) return error;
|
|
3451
|
+
if (error instanceof Error && error.name === "AbortError") return this.makeAbortError(item.ctx);
|
|
3452
|
+
return new ComputeError(error instanceof Error ? error.message : String(error), ErrorCodes.UNKNOWN_ERROR, { originalError: error });
|
|
3453
|
+
}
|
|
3454
|
+
/** Cancel everything — in-flight and pending. */
|
|
3455
|
+
cancelAll() {
|
|
3456
|
+
if (this.pendingForLatestWins) {
|
|
3457
|
+
this.fail(this.pendingForLatestWins, this.makeAbortError(this.pendingForLatestWins.ctx));
|
|
3458
|
+
this.pendingForLatestWins = null;
|
|
3459
|
+
}
|
|
3460
|
+
for (let item = this.fifo.shift(); item; item = this.fifo.shift()) this.fail(item, this.makeAbortError(item.ctx));
|
|
3461
|
+
for (const inflight of this.inFlight) {
|
|
3462
|
+
const durationMs = inflight.ctx.startedAt ? Date.now() - inflight.ctx.startedAt : 0;
|
|
3463
|
+
this.fail(inflight, this.makeAbortError(inflight.ctx), durationMs);
|
|
3464
|
+
inflight.controller.abort();
|
|
3465
|
+
}
|
|
3466
|
+
this.notify();
|
|
3467
|
+
}
|
|
3468
|
+
clearCache() {
|
|
3469
|
+
this.cache.clear();
|
|
3470
|
+
}
|
|
3471
|
+
/**
|
|
3472
|
+
* Observability snapshot of the solve cache: current size plus lifetime
|
|
3473
|
+
* hit/miss/eviction counters.
|
|
3474
|
+
*
|
|
3475
|
+
* `hits`/`misses` count cache CONSULTATIONS, so `hits / (hits + misses)` is the
|
|
3476
|
+
* hit rate. A TTL-expired entry counts as a miss (the solve runs either way).
|
|
3477
|
+
* `evictions` counts only entries dropped under size/byte pressure — not
|
|
3478
|
+
* replace-in-place writes or TTL expiry, which are not capacity signals.
|
|
3479
|
+
* Counters are cumulative and survive `clearCache()`.
|
|
3480
|
+
*/
|
|
3481
|
+
cacheStats() {
|
|
3482
|
+
return this.cache.stats();
|
|
3483
|
+
}
|
|
3484
|
+
dispose() {
|
|
3485
|
+
if (this.disposed) return;
|
|
3486
|
+
this.disposed = true;
|
|
3487
|
+
this.cancelAll();
|
|
3488
|
+
this.subscribers.clear();
|
|
3489
|
+
this.clearCache();
|
|
3490
|
+
}
|
|
3491
|
+
runHook(hook, ...args) {
|
|
3492
|
+
if (!hook) return;
|
|
3493
|
+
try {
|
|
3494
|
+
hook(...args);
|
|
3495
|
+
} catch (err) {
|
|
3496
|
+
getLogger().error("[SolveScheduler] hook threw:", err);
|
|
3497
|
+
}
|
|
3498
|
+
}
|
|
3499
|
+
};
|
|
3500
|
+
function describeDefinition(definition) {
|
|
3501
|
+
if (isDefinitionRef(definition)) return `ref:${definition.key}`;
|
|
3502
|
+
if (typeof definition !== "string" || definition.length >= 200) return "...content...";
|
|
3503
|
+
return isDefinitionUrl(definition) ? redactUrl(definition) : definition;
|
|
3504
|
+
}
|
|
3505
|
+
/** Identifiers only: the error's `context` holds outputs and its message the server's words. */
|
|
3506
|
+
function describeFailure(error) {
|
|
3507
|
+
if (!(error instanceof ComputeError)) return `Compute failed: ${error instanceof Error ? error.name : typeof error}`;
|
|
3508
|
+
const status = error.statusCode === void 0 ? "" : ` HTTP ${error.statusCode}`;
|
|
3509
|
+
const requestId = error.context?.requestId;
|
|
3510
|
+
return `Compute failed: ${error.code}${status}${requestId ? ` [${requestId}]` : ""}`;
|
|
3511
|
+
}
|
|
3512
|
+
/**
|
|
3513
|
+
* Stands in for the input tree on errors: the tree can hold multi-MB geometry, and every logger
|
|
3514
|
+
* or telemetry sink that keeps the error would pin it. Never throws on a malformed tree.
|
|
3515
|
+
*/
|
|
3516
|
+
function summarizeDataTree(dataTree) {
|
|
3517
|
+
if (!Array.isArray(dataTree)) return [];
|
|
3518
|
+
return dataTree.map((tree) => {
|
|
3519
|
+
let items = 0;
|
|
3520
|
+
let bytes = 0;
|
|
3521
|
+
const innerTree = readField(tree, "innerTree");
|
|
3522
|
+
if (innerTree && typeof innerTree === "object") for (const branch of Object.values(innerTree)) {
|
|
3523
|
+
if (!Array.isArray(branch)) continue;
|
|
3524
|
+
items += branch.length;
|
|
3525
|
+
for (const item of branch) {
|
|
3526
|
+
const data = item?.data;
|
|
3527
|
+
if (typeof data === "string") bytes += data.length;
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
return {
|
|
3531
|
+
param: readField(tree, "paramName") ?? "<unnamed>",
|
|
3532
|
+
items,
|
|
3533
|
+
bytes
|
|
3534
|
+
};
|
|
3535
|
+
});
|
|
3536
|
+
}
|
|
3537
|
+
/**
|
|
3538
|
+
* The high-level API for solving Grasshopper definitions on a Rhino Compute server.
|
|
3539
|
+
*
|
|
3540
|
+
* In a browser, the server URL and API key are exposed to users: run it server-side, or proxy
|
|
3541
|
+
* requests through your own backend.
|
|
3542
|
+
*
|
|
3543
|
+
* @example
|
|
3544
|
+
* ```typescript
|
|
3545
|
+
* const client = await GrasshopperClient.create({
|
|
3546
|
+
* serverUrl: 'http://localhost:6500',
|
|
3547
|
+
* apiKey: 'your-api-key'
|
|
3548
|
+
* });
|
|
3549
|
+
*
|
|
3550
|
+
* try {
|
|
3551
|
+
* const io = await client.getIO(definitionUrl);
|
|
3552
|
+
* const result = await client.solve(definitionUrl, TreeBuilder.fromInputParams(io.inputs));
|
|
3553
|
+
* } finally {
|
|
3554
|
+
* await client.dispose(); // Clean up resources
|
|
3555
|
+
* }
|
|
3556
|
+
* ```
|
|
3557
|
+
*/
|
|
3558
|
+
var GrasshopperClient = class GrasshopperClient {
|
|
3559
|
+
config;
|
|
3560
|
+
serverStats;
|
|
3561
|
+
schedulers = /* @__PURE__ */ new Set();
|
|
3562
|
+
disposed = false;
|
|
3563
|
+
/**
|
|
3564
|
+
* Per-probe timeout for the `create()` liveness gate: a healthy `GET /` answers in milliseconds,
|
|
3565
|
+
* so this only bounds a silent server, and every extra second is paid once per retry.
|
|
3566
|
+
*/
|
|
3567
|
+
static CREATE_PROBE_TIMEOUT_MS = 2e3;
|
|
3568
|
+
constructor(config) {
|
|
3569
|
+
this.config = {
|
|
3570
|
+
...config,
|
|
3571
|
+
serverUrl: validateServerUrl(config.serverUrl),
|
|
3572
|
+
debug: config.debug ?? false
|
|
3573
|
+
};
|
|
3574
|
+
this.serverStats = new ComputeServerStats(this.config.serverUrl, this.config);
|
|
3575
|
+
}
|
|
3576
|
+
/**
|
|
3577
|
+
* Creates a client once a liveness probe (`GET /`) says the server is up. A cold server can read
|
|
3578
|
+
* as offline, so the probe retries with a short backoff, stopping early when
|
|
3579
|
+
* {@link classifyProbeFailure} says waiting can't change the answer. `config.signal` cancels the
|
|
3580
|
+
* ladder.
|
|
3581
|
+
*
|
|
3582
|
+
* @throws {ComputeError} `NETWORK_ERROR` if the server stays unreachable across all attempts.
|
|
3583
|
+
* `context.probeVerdict` carries the verdict, so a caller can render a specific cause.
|
|
3584
|
+
* @throws {ComputeError} `ABORTED` if `config.signal` fires first.
|
|
3585
|
+
* @throws {ComputeError} `INVALID_CONFIG` if the configuration is invalid.
|
|
3586
|
+
*/
|
|
3587
|
+
static async create(config, options = {}) {
|
|
3588
|
+
const client = new GrasshopperClient(config);
|
|
3589
|
+
const { signal } = config;
|
|
3590
|
+
const attempts = Math.max(1, (options.probe?.attempts ?? 2) + 1);
|
|
3591
|
+
const baseDelayMs = options.probe?.baseDelayMs ?? 250;
|
|
3592
|
+
const maxDelayMs = options.probe?.maxDelayMs ?? 1e3;
|
|
3593
|
+
let lastProbe;
|
|
3594
|
+
let failure = null;
|
|
3595
|
+
let used = 0;
|
|
3596
|
+
for (let attempt = 0; attempt < attempts && !signal?.aborted; attempt++) {
|
|
3597
|
+
used = attempt + 1;
|
|
3598
|
+
lastProbe = await client.serverStats.probeServer(GrasshopperClient.CREATE_PROBE_TIMEOUT_MS, signal);
|
|
3599
|
+
if (lastProbe.online) return client;
|
|
3600
|
+
failure = classifyProbeFailure(lastProbe);
|
|
3601
|
+
if (failure && !failure.retryable) break;
|
|
3602
|
+
if (attempt < attempts - 1) await sleep(Math.min(baseDelayMs * 2 ** attempt, maxDelayMs), signal).catch(() => {});
|
|
3603
|
+
}
|
|
3604
|
+
await client.dispose();
|
|
3605
|
+
if (signal?.aborted) throw abortedByCaller({
|
|
3606
|
+
serverUrl: client.config.serverUrl,
|
|
3607
|
+
attempts: used
|
|
3608
|
+
});
|
|
3609
|
+
const status = lastProbe?.status;
|
|
3610
|
+
throw new ComputeError(failure ? `Rhino Compute server is not available. ${failure.summary}` : "Rhino Compute server is not online", ErrorCodes.NETWORK_ERROR, {
|
|
3611
|
+
...status !== void 0 && { statusCode: status },
|
|
3612
|
+
context: {
|
|
3613
|
+
serverUrl: client.config.serverUrl,
|
|
3614
|
+
attempts: used,
|
|
3615
|
+
maxAttempts: attempts,
|
|
3616
|
+
...failure && {
|
|
3617
|
+
probeVerdict: failure.verdict,
|
|
3618
|
+
probeRetryable: failure.retryable
|
|
3619
|
+
},
|
|
3620
|
+
...status !== void 0 && { lastProbeStatus: status },
|
|
3621
|
+
...lastProbe?.error !== void 0 && { lastProbeError: lastProbe.error }
|
|
3622
|
+
}
|
|
3623
|
+
});
|
|
3624
|
+
}
|
|
3625
|
+
/**
|
|
3626
|
+
* Get input/output parameters of a Grasshopper definition.
|
|
3627
|
+
*/
|
|
3628
|
+
async getIO(definition) {
|
|
3629
|
+
this.ensureNotDisposed();
|
|
3630
|
+
return fetchParsedDefinitionIO(definition, this.config);
|
|
3631
|
+
}
|
|
3632
|
+
async getRawIO(definition) {
|
|
3633
|
+
this.ensureNotDisposed();
|
|
3634
|
+
return fetchDefinitionIO(definition, this.config);
|
|
3635
|
+
}
|
|
3636
|
+
/**
|
|
3637
|
+
* Run a compute job with a Grasshopper definition.
|
|
3638
|
+
*
|
|
3639
|
+
* @throws {ComputeError} with code INVALID_INPUT if definition is empty
|
|
3640
|
+
* @throws {ComputeError} with code NETWORK_ERROR if server is offline
|
|
3641
|
+
* @throws {ComputeError} with code COMPUTATION_ERROR if computation fails.
|
|
3642
|
+
* On a partial-success response (some outputs computed, some errored) the
|
|
3643
|
+
* error's `context.values` carries the outputs that did compute — pass
|
|
3644
|
+
* `{ values } as GrasshopperComputeResponse` to the response processors to
|
|
3645
|
+
* render them. `context.inputSummary` describes the inputs (param names,
|
|
3646
|
+
* item counts, byte sizes) without pinning the full data tree.
|
|
3647
|
+
*/
|
|
3648
|
+
async solve(definition, dataTree, options) {
|
|
3649
|
+
this.ensureNotDisposed();
|
|
3650
|
+
const describeCall = () => ({
|
|
3651
|
+
definition: describeDefinition(definition),
|
|
3652
|
+
inputSummary: summarizeDataTree(dataTree)
|
|
3653
|
+
});
|
|
3654
|
+
try {
|
|
3655
|
+
if (typeof definition === "string" && !definition.trim()) throw new ComputeError("Definition URL/content is required", ErrorCodes.INVALID_INPUT, { context: { receivedUrl: definition } });
|
|
3656
|
+
else if (definition instanceof Uint8Array && definition.length === 0) throw new ComputeError("Definition content is empty", ErrorCodes.INVALID_INPUT);
|
|
3657
|
+
else if (isDefinitionRef(definition) && !definition.key.trim()) throw new ComputeError("DefinitionRef key is empty", ErrorCodes.INVALID_INPUT);
|
|
3658
|
+
const result = await solveGrasshopperDefinition(dataTree, definition, {
|
|
3659
|
+
...this.config,
|
|
3660
|
+
...options?.signal !== void 0 && { signal: options.signal },
|
|
3661
|
+
...options?.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
3662
|
+
...options?.retry !== void 0 && { retry: options.retry },
|
|
3663
|
+
...options?.selvaevents !== void 0 && { selvaevents: options.selvaevents }
|
|
3664
|
+
});
|
|
3665
|
+
const solveErrors = readField(result, "errors");
|
|
3666
|
+
if (Array.isArray(solveErrors) && solveErrors.length > 0) throw new ComputeError(solveErrors.map(String).join("; ") || "Computation failed", ErrorCodes.COMPUTATION_ERROR, { context: {
|
|
3667
|
+
...describeCall(),
|
|
3668
|
+
errors: solveErrors,
|
|
3669
|
+
warnings: readField(result, "warnings"),
|
|
3670
|
+
values: result.values
|
|
3671
|
+
} });
|
|
3672
|
+
return result;
|
|
3673
|
+
} catch (error) {
|
|
3674
|
+
if (this.config.debug) getLogger().error(describeFailure(error));
|
|
3675
|
+
if (error instanceof ComputeError) throw error;
|
|
3676
|
+
throw new ComputeError(error instanceof Error ? error.message : String(error), ErrorCodes.COMPUTATION_ERROR, {
|
|
3677
|
+
context: describeCall(),
|
|
3678
|
+
originalError: error
|
|
3679
|
+
});
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
/**
|
|
3683
|
+
* Create a scheduler bound to this client. Use a scheduler for any UI surface
|
|
3684
|
+
* that fires solves frequently (sliders, live editors) or that needs cancel
|
|
3685
|
+
* semantics, response caching, or state observability.
|
|
3686
|
+
*
|
|
3687
|
+
* Multiple schedulers can be created from a single client — typically one per
|
|
3688
|
+
* UI surface so their queues stay independent.
|
|
3689
|
+
*
|
|
3690
|
+
* @example
|
|
3691
|
+
* ```ts
|
|
3692
|
+
* const sliderScheduler = client.createScheduler({ mode: 'latest-wins' });
|
|
3693
|
+
* const submitScheduler = client.createScheduler({ mode: 'queue', timeoutMs: 0 });
|
|
3694
|
+
* ```
|
|
3695
|
+
*/
|
|
3696
|
+
createScheduler(options) {
|
|
3697
|
+
this.ensureNotDisposed();
|
|
3698
|
+
const scheduler = new SolveScheduler((definition, dataTree, cacheKey, config) => solveWithServerCacheKey(dataTree, cacheKey, definition, config), this.config, options);
|
|
3699
|
+
this.schedulers.add(scheduler);
|
|
3700
|
+
return scheduler;
|
|
3701
|
+
}
|
|
3702
|
+
/** Disposes of client resources, including every scheduler it created. */
|
|
3703
|
+
async dispose() {
|
|
3704
|
+
if (this.disposed) return;
|
|
3705
|
+
this.disposed = true;
|
|
3706
|
+
for (const scheduler of this.schedulers) scheduler.dispose();
|
|
3707
|
+
this.schedulers.clear();
|
|
3708
|
+
await this.serverStats.dispose();
|
|
3709
|
+
}
|
|
3710
|
+
ensureNotDisposed() {
|
|
3711
|
+
if (this.disposed) throw new ComputeError("GrasshopperClient has been disposed and cannot be used", ErrorCodes.INVALID_STATE);
|
|
3712
|
+
}
|
|
3713
|
+
};
|
|
3714
|
+
function makeDecodeError(rhinoType, raw) {
|
|
3715
|
+
return {
|
|
3716
|
+
__decodeError: true,
|
|
3717
|
+
type: rhinoType,
|
|
3718
|
+
raw
|
|
3719
|
+
};
|
|
3720
|
+
}
|
|
3721
|
+
/**
|
|
3722
|
+
* Free every rhino3dm WASM object reachable from `value`.
|
|
3723
|
+
*
|
|
3724
|
+
* rhino3dm objects are emscripten bindings — JS GC never reclaims their WASM
|
|
3725
|
+
* heap allocation, so everything decoded from a solve response (`getValues`,
|
|
3726
|
+
* `getValue`) must be deleted explicitly or the heap
|
|
3727
|
+
* grows monotonically across solves (e.g. a UI decoding per slider tick).
|
|
3728
|
+
*
|
|
3729
|
+
* Walks arrays and plain objects recursively; anything exposing a `delete()`
|
|
3730
|
+
* method is treated as a WASM binding and freed (skipped if already deleted).
|
|
3731
|
+
* Safe to call more than once and on values containing no WASM objects.
|
|
3732
|
+
*/
|
|
3733
|
+
function disposeRhinoObjects(value) {
|
|
3734
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
3735
|
+
const walk = (v) => {
|
|
3736
|
+
if (!v || typeof v !== "object") return;
|
|
3737
|
+
if (seen.has(v)) return;
|
|
3738
|
+
seen.add(v);
|
|
3739
|
+
const del = v.delete;
|
|
3740
|
+
if (typeof del === "function") {
|
|
3741
|
+
const isDeleted = v.isDeleted;
|
|
3742
|
+
if (typeof isDeleted !== "function" || !isDeleted.call(v)) del.call(v);
|
|
3743
|
+
return;
|
|
3744
|
+
}
|
|
3745
|
+
if (Array.isArray(v)) {
|
|
3746
|
+
for (const item of v) walk(item);
|
|
3747
|
+
return;
|
|
3748
|
+
}
|
|
3749
|
+
const proto = Object.getPrototypeOf(v);
|
|
3750
|
+
if (proto === Object.prototype || proto === null) for (const item of Object.values(v)) walk(item);
|
|
3751
|
+
};
|
|
3752
|
+
walk(value);
|
|
3753
|
+
}
|
|
3754
|
+
var decoders = /* @__PURE__ */ new Map([["Rhino.Geometry.Point3d", (rhino, data) => {
|
|
3755
|
+
const d = data;
|
|
3756
|
+
if (!d || typeof d.X !== "number") return null;
|
|
3757
|
+
return new rhino.Point([
|
|
3758
|
+
d.X,
|
|
3759
|
+
d.Y,
|
|
3760
|
+
d.Z
|
|
3761
|
+
]);
|
|
3762
|
+
}], ["Rhino.Geometry.Line", (rhino, data) => {
|
|
3763
|
+
const d = data;
|
|
3764
|
+
if (!d || !d.From || !d.To) return null;
|
|
3765
|
+
return new rhino.Line([
|
|
3766
|
+
d.From.X,
|
|
3767
|
+
d.From.Y,
|
|
3768
|
+
d.From.Z
|
|
3769
|
+
], [
|
|
3770
|
+
d.To.X,
|
|
3771
|
+
d.To.Y,
|
|
3772
|
+
d.To.Z
|
|
3773
|
+
]);
|
|
3774
|
+
}]]);
|
|
3775
|
+
/**
|
|
3776
|
+
* Whether the parsed item looks like a rhino3dm serialization envelope
|
|
3777
|
+
* (`{version, archive3dm, opennurbs, data: "<base64>"}`). `CommonObject.decode` expects the WHOLE
|
|
3778
|
+
* envelope — unwrapping `.data` first hands it the bare base64 string, which throws or decodes to
|
|
3779
|
+
* garbage.
|
|
3780
|
+
*/
|
|
3781
|
+
function isDecodableEnvelope(parsedData) {
|
|
3782
|
+
return Boolean(parsedData && typeof parsedData === "object" && typeof parsedData.data === "string");
|
|
3783
|
+
}
|
|
3784
|
+
/**
|
|
3785
|
+
* Decode one typed payload from a solve response into a rhino3dm object.
|
|
3786
|
+
*
|
|
3787
|
+
* Every call yields exactly one of three outcomes:
|
|
3788
|
+
*
|
|
3789
|
+
* 1. **Decoded value** — a registered decoder recognized the shape, or the
|
|
3790
|
+
* payload was a rhino3dm serialization envelope and `CommonObject.decode`
|
|
3791
|
+
* succeeded.
|
|
3792
|
+
* 2. **Raw passthrough** (`=== parsedData`) — no decode path *applied*: no
|
|
3793
|
+
* decoder matched the type (or the matched decoder returned `null`, meaning
|
|
3794
|
+
* "not my shape") and the payload is not a decodable envelope. Not an error;
|
|
3795
|
+
* the caller keeps the parsed JSON as-is.
|
|
3796
|
+
* 3. **{@link RhinoDecodeError} sentinel** — a decode was *attempted and threw*
|
|
3797
|
+
* (a registered decoder threw and no envelope fallback could recover, or
|
|
3798
|
+
* `CommonObject.decode` threw). Detect with {@link isRhinoDecodeError}.
|
|
3799
|
+
*
|
|
3800
|
+
* A decoder returning `null` is a soft miss, never an error: it falls through
|
|
3801
|
+
* to the envelope fallback.
|
|
3802
|
+
*/
|
|
3803
|
+
function decodeRhinoGeometry(parsedData, rhinoType, rhino) {
|
|
3804
|
+
const decoder = decoders.get(rhinoType);
|
|
3805
|
+
let decoderThrew = false;
|
|
3806
|
+
if (decoder) try {
|
|
3807
|
+
const decoded = decoder(rhino, parsedData);
|
|
3808
|
+
if (decoded != null) return decoded;
|
|
3809
|
+
} catch (error) {
|
|
3810
|
+
getLogger().warn(`Failed to decode Rhino type ${rhinoType}:`, error);
|
|
3811
|
+
decoderThrew = true;
|
|
3812
|
+
}
|
|
3813
|
+
try {
|
|
3814
|
+
if (isDecodableEnvelope(parsedData)) return rhino.CommonObject.decode(parsedData);
|
|
3815
|
+
} catch (error) {
|
|
3816
|
+
getLogger().warn(`Failed to decode ${rhinoType} with CommonObject:`, error);
|
|
3817
|
+
return makeDecodeError(rhinoType, parsedData);
|
|
3818
|
+
}
|
|
3819
|
+
return decoderThrew ? makeDecodeError(rhinoType, parsedData) : parsedData;
|
|
3820
|
+
}
|
|
3821
|
+
var RHINO_GEOMETRY_PREFIX = "Rhino.Geometry.";
|
|
3822
|
+
var FILE_DATA_TYPE = "FileData";
|
|
3823
|
+
/** WebDisplay items are skipped entirely: kept, they would write `null` into the result. */
|
|
3824
|
+
function skipItem(type, stringOnly) {
|
|
3825
|
+
return type.includes("WebDisplay") || stringOnly && type !== "System.String";
|
|
3826
|
+
}
|
|
3827
|
+
var looksStructured = (text) => text.startsWith("{") || text.startsWith("[");
|
|
3828
|
+
function tryDecodeJSON(value) {
|
|
3829
|
+
if (typeof value !== "string") return value;
|
|
3830
|
+
const trimmed = value.trim();
|
|
3831
|
+
if (!looksStructured(trimmed) && !trimmed.startsWith("\"")) return value;
|
|
3832
|
+
const first = tryParseJson(trimmed) ?? value;
|
|
3833
|
+
return typeof first === "string" && looksStructured(first.trim()) ? tryParseJson(first) ?? first : first;
|
|
3834
|
+
}
|
|
3835
|
+
function decodeBySystemType(raw, type, rhino) {
|
|
3836
|
+
if (type === "System.String") return typeof raw === "string" ? raw.replace(/^"(.*)"$/, "$1") : raw;
|
|
3837
|
+
if (INTEGER_ITEM_TYPES.has(type)) {
|
|
3838
|
+
const value = Number.parseInt(String(raw), 10);
|
|
3839
|
+
return Number.isNaN(value) || Number.isSafeInteger(value) ? value : raw;
|
|
3840
|
+
}
|
|
3841
|
+
if (NUMERIC_ITEM_TYPES.has(type)) return Number.parseFloat(String(raw));
|
|
3842
|
+
if (type === "System.Boolean") return String(raw).toLowerCase() === "true";
|
|
3843
|
+
if (rhino && type.startsWith(RHINO_GEOMETRY_PREFIX)) return decodeRhinoGeometry(raw, type, rhino);
|
|
3844
|
+
return raw;
|
|
3845
|
+
}
|
|
3846
|
+
function extractItemValue(item, type, parseValues, rhino) {
|
|
3847
|
+
if (typeof item.data !== "string") return item.data;
|
|
3848
|
+
const raw = parseValues ? tryDecodeJSON(item.data) : item.data;
|
|
3849
|
+
if (parseValues && type.includes(FILE_DATA_TYPE)) return asFileData(raw) ?? raw;
|
|
3850
|
+
return decodeBySystemType(raw, type, rhino);
|
|
3851
|
+
}
|
|
3852
|
+
/**
|
|
3853
|
+
* A parsed `FileData` blob in the camelCase shape {@link FileData} documents, or
|
|
3854
|
+
* `null` when a required field is missing. Fields are read with `readField`,
|
|
3855
|
+
* since their casing varies by server branch.
|
|
3856
|
+
*/
|
|
3857
|
+
function asFileData(value) {
|
|
3858
|
+
if (!value || typeof value !== "object") return null;
|
|
3859
|
+
const fileName = readField(value, "fileName");
|
|
3860
|
+
const fileType = readField(value, "fileType");
|
|
3861
|
+
const subFolder = readField(value, "subFolder");
|
|
3862
|
+
const flag = readField(value, "isBase64Encoded");
|
|
3863
|
+
if (typeof fileName !== "string" || typeof fileType !== "string") return null;
|
|
3864
|
+
if (typeof subFolder !== "string") return null;
|
|
3865
|
+
if (!hasField(value, "data")) return null;
|
|
3866
|
+
if (typeof flag !== "boolean" && typeof flag !== "string") return null;
|
|
3867
|
+
const metadata = readField(value, "metadata");
|
|
3868
|
+
return {
|
|
3869
|
+
fileName,
|
|
3870
|
+
fileType,
|
|
3871
|
+
data: readField(value, "data"),
|
|
3872
|
+
isBase64Encoded: isBase64Flag(flag),
|
|
3873
|
+
subFolder,
|
|
3874
|
+
...metadata ? { metadata } : {}
|
|
3875
|
+
};
|
|
3876
|
+
}
|
|
3877
|
+
/** Partial-success and warnings-only responses can arrive with no `values` at all. */
|
|
3878
|
+
function getResponseParams(response) {
|
|
3879
|
+
const values = readField(response, "values");
|
|
3880
|
+
return Array.isArray(values) ? values : [];
|
|
3881
|
+
}
|
|
3882
|
+
/** A param's item type, tolerating items whose `type` is missing/non-string. */
|
|
3883
|
+
function itemType(item) {
|
|
3884
|
+
return typeof item.type === "string" ? item.type : "";
|
|
3885
|
+
}
|
|
3886
|
+
/** Tolerates a missing tree (warnings-only partial successes) and skips non-object items. */
|
|
3887
|
+
function forEachTreeItem(tree, handler) {
|
|
3888
|
+
if (!tree || typeof tree !== "object") return;
|
|
3889
|
+
for (const list of Object.values(tree)) if (Array.isArray(list)) {
|
|
3890
|
+
for (const item of list) if (item && typeof item === "object") handler(item);
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
/**
|
|
3894
|
+
* Read all output values from a Grasshopper Compute response, keyed by parameter
|
|
3895
|
+
* name (or ID when `byId`). Duplicate keys aggregate into an array.
|
|
3896
|
+
*
|
|
3897
|
+
* Geometry decoded via `rhino` lives on the WASM heap: free it with `dispose()`.
|
|
3898
|
+
*
|
|
3899
|
+
* @param options.parseValues - Parse complex data types into JS objects (default true).
|
|
3900
|
+
* @param options.rhino - Rhino3dm instance for geometry decoding.
|
|
3901
|
+
* @param options.stringOnly - Keep only string-typed items.
|
|
3902
|
+
*/
|
|
3903
|
+
function getValues(response, byId = false, options = {}) {
|
|
3904
|
+
const { parseValues = true, rhino, stringOnly = false } = options;
|
|
3905
|
+
const result = {};
|
|
3906
|
+
const aggregated = /* @__PURE__ */ new Set();
|
|
3907
|
+
for (const param of getResponseParams(response)) {
|
|
3908
|
+
const paramName = readField(param, "paramName");
|
|
3909
|
+
forEachTreeItem(readField(param, "innerTree"), (item) => {
|
|
3910
|
+
const type = itemType(item);
|
|
3911
|
+
if (skipItem(type, stringOnly)) return;
|
|
3912
|
+
const key = byId ? item.id : paramName;
|
|
3913
|
+
if (!key) return;
|
|
3914
|
+
const value = extractItemValue(item, type, parseValues, rhino);
|
|
3915
|
+
if (!Object.hasOwn(result, key)) setOwnField(result, key, value);
|
|
3916
|
+
else if (aggregated.has(key)) result[key].push(value);
|
|
3917
|
+
else {
|
|
3918
|
+
result[key] = [result[key], value];
|
|
3919
|
+
aggregated.add(key);
|
|
3920
|
+
}
|
|
3921
|
+
});
|
|
3922
|
+
}
|
|
3923
|
+
return {
|
|
3924
|
+
values: result,
|
|
3925
|
+
dispose: () => disposeRhinoObjects(result)
|
|
3926
|
+
};
|
|
3927
|
+
}
|
|
3928
|
+
/** Decode every file-data item in a response into {@link FileData} objects. */
|
|
3929
|
+
function extractFileData(response) {
|
|
3930
|
+
const output = [];
|
|
3931
|
+
for (const param of getResponseParams(response)) forEachTreeItem(readField(param, "innerTree"), (item) => {
|
|
3932
|
+
if (!itemType(item).includes(FILE_DATA_TYPE)) return;
|
|
3933
|
+
const file = asFileData(tryDecodeJSON(item.data));
|
|
3934
|
+
if (file) output.push(file);
|
|
3935
|
+
});
|
|
3936
|
+
return output;
|
|
3937
|
+
}
|
|
3938
|
+
/**
|
|
3939
|
+
* Read one parameter's value(s) from a response — `byName` matches a `ParamName`,
|
|
3940
|
+
* `byId` matches an item ID. Returns `undefined` if absent, a single value for one
|
|
3941
|
+
* match, or an array for several.
|
|
3942
|
+
*
|
|
3943
|
+
* Geometry decoded via `rhino` lives on the WASM heap: free it with
|
|
3944
|
+
* {@link disposeRhinoObjects} once consumed.
|
|
3945
|
+
*
|
|
3946
|
+
* @param parseOptions.parseValues - Parse raw data into formatted values (default true).
|
|
3947
|
+
* @param parseOptions.rhino - Rhino3dm instance for geometry decoding.
|
|
3948
|
+
* @param parseOptions.stringOnly - Keep only string-typed items.
|
|
3949
|
+
*/
|
|
3950
|
+
function getValue(response, options, parseOptions = {}) {
|
|
3951
|
+
const { parseValues = true, rhino, stringOnly = false } = parseOptions;
|
|
3952
|
+
for (const param of getResponseParams(response)) {
|
|
3953
|
+
const tree = readField(param, "innerTree");
|
|
3954
|
+
let matched = false;
|
|
3955
|
+
if ("byName" in options) {
|
|
3956
|
+
if (readField(param, "paramName") !== options.byName) continue;
|
|
3957
|
+
matched = true;
|
|
3958
|
+
}
|
|
3959
|
+
const collected = [];
|
|
3960
|
+
forEachTreeItem(tree, (item) => {
|
|
3961
|
+
if ("byId" in options) {
|
|
3962
|
+
if (item.id !== options.byId) return;
|
|
3963
|
+
matched = true;
|
|
3964
|
+
}
|
|
3965
|
+
const type = itemType(item);
|
|
3966
|
+
if (skipItem(type, stringOnly)) return;
|
|
3967
|
+
collected.push(extractItemValue(item, type, parseValues, rhino));
|
|
3968
|
+
});
|
|
3969
|
+
if (matched) {
|
|
3970
|
+
if (collected.length === 0) return void 0;
|
|
3971
|
+
if (collected.length === 1) return collected[0];
|
|
3972
|
+
return collected;
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
/** Reads parsed values and produced files out of one compute response. */
|
|
3977
|
+
var GrasshopperResponseProcessor = class {
|
|
3978
|
+
response;
|
|
3979
|
+
constructor(response) {
|
|
3980
|
+
this.response = response;
|
|
3981
|
+
}
|
|
3982
|
+
/**
|
|
3983
|
+
* Extract all values in the response.
|
|
3984
|
+
*
|
|
3985
|
+
* @typeParam T - Expected structure of the return value. Defaults to a simple key/value map. (later cast as needed)
|
|
3986
|
+
* @param byId - Key by parameter ID instead of name. Requires the VektorNode rhino.compute branch.
|
|
3987
|
+
* @param options - Controls parsing behavior such as Rhino geometry decoding.
|
|
3988
|
+
* @returns Parsed Grasshopper output values.
|
|
3989
|
+
*
|
|
3990
|
+
* @example
|
|
3991
|
+
* ```ts
|
|
3992
|
+
* const processor = new GrasshopperResponseProcessor(response);
|
|
3993
|
+
* const { values } = processor.getValues();
|
|
3994
|
+
* ```
|
|
3995
|
+
*
|
|
3996
|
+
*/
|
|
3997
|
+
getValues(byId = false, options = {}) {
|
|
3998
|
+
return getValues(this.response, byId, options);
|
|
3999
|
+
}
|
|
4000
|
+
/**
|
|
4001
|
+
* Retrieve a specific value by parameter name or ID.
|
|
4002
|
+
*
|
|
4003
|
+
* @param selector - `{ byName }` for the human-readable name, `{ byId }` for the parameter GUID.
|
|
4004
|
+
* @param options - Parsing configuration (e.g. disable parsing or enable Rhino).
|
|
4005
|
+
* @returns Single parsed value, array of values, or undefined if the parameter is absent.
|
|
4006
|
+
*
|
|
4007
|
+
* `byId` requires the VektorNode rhino.compute branch.
|
|
4008
|
+
*
|
|
4009
|
+
* @example
|
|
4010
|
+
* ```ts
|
|
4011
|
+
* const schema = processor.getValue({ byName: 'Schema' });
|
|
4012
|
+
* const output = processor.getValue({ byId: 'a4be1c1e-23f9-4c27-b942-7f3bb2c45c6f' });
|
|
4013
|
+
* ```
|
|
4014
|
+
*/
|
|
4015
|
+
getValue(selector, options) {
|
|
4016
|
+
return getValue(this.response, selector, options);
|
|
4017
|
+
}
|
|
4018
|
+
/**
|
|
4019
|
+
* Download all files generated by Grasshopper, optionally including
|
|
4020
|
+
* additional user-provided files.
|
|
4021
|
+
*
|
|
4022
|
+
* @param folderName - Name of the zip archive, without the extension.
|
|
4023
|
+
* @param additionalFiles - Extra files to package (single file, array, or null).
|
|
4024
|
+
*
|
|
4025
|
+
* @example
|
|
4026
|
+
* ```ts
|
|
4027
|
+
* await processor.getAndDownloadFiles('gh-output');
|
|
4028
|
+
* ```
|
|
4029
|
+
*
|
|
4030
|
+
* @example
|
|
4031
|
+
* ```ts
|
|
4032
|
+
* const extra = { fileName: 'notes.txt', filePath: 'https://example.com/notes.txt' };
|
|
4033
|
+
* await processor.getAndDownloadFiles('project', extra);
|
|
4034
|
+
* ```
|
|
4035
|
+
*/
|
|
4036
|
+
async getAndDownloadFiles(folderName, additionalFiles) {
|
|
4037
|
+
await downloadFileData(extractFileData(this.response), folderName, additionalFiles);
|
|
4038
|
+
}
|
|
4039
|
+
};
|
|
4040
|
+
/**
|
|
4041
|
+
* Read compute's `/grasshopper/schema` body: `[{ FileName, Schemas }]` per
|
|
4042
|
+
* uploaded file, or a bare object for a single file.
|
|
4043
|
+
*
|
|
4044
|
+
* Use this rather than unwrapping the body by hand: the wrapper keys' casing
|
|
4045
|
+
* varies by server branch, and a fixed-key read yields "no schemas" with a 200.
|
|
4046
|
+
* Only the two wrapper keys are read; schema contents pass through untouched.
|
|
4047
|
+
*
|
|
4048
|
+
* @typeParam TSchema - Your schema type (e.g. `UISchema`). Not inspected.
|
|
4049
|
+
*/
|
|
4050
|
+
function readSchemaResults(raw) {
|
|
4051
|
+
return (Array.isArray(raw) ? raw : [raw]).map((entry) => ({
|
|
4052
|
+
schemas: readField(entry, "schemas"),
|
|
4053
|
+
error: readField(entry, "error")
|
|
4054
|
+
}));
|
|
4055
|
+
}
|
|
4056
|
+
/**
|
|
4057
|
+
* Canonicalize a `/grasshopper/schema` body's key casing.
|
|
4058
|
+
*
|
|
4059
|
+
* Compute serializes the plugin's `UISchema`, whose camelCase wire names live in
|
|
4060
|
+
* Newtonsoft `[JsonProperty]` attributes. `Selva.gha` ILRepack-merges Newtonsoft,
|
|
4061
|
+
* so those attributes are `Selva!Newtonsoft.Json.JsonPropertyAttribute`. When
|
|
4062
|
+
* compute's OWN Newtonsoft serializes, it doesn't recognize them, reads no
|
|
4063
|
+
* attributes, and emits raw CLR names (`Inputs`, `SchemaVersion`). Nothing throws:
|
|
4064
|
+
* `schema.inputs` reads `undefined`, and so does the `schemaVersion` gate.
|
|
4065
|
+
*
|
|
4066
|
+
* A casing rule, not a key allowlist: the wire names are the CLR names run
|
|
4067
|
+
* through Newtonsoft's camelCase strategy, so reproducing it covers every key
|
|
4068
|
+
* without drifting each time `UISchema` gains a field.
|
|
4069
|
+
*/
|
|
4070
|
+
/** Maps keyed by the definition's author (dropdown labels): copied verbatim. */
|
|
4071
|
+
var USER_AUTHORED_MAPS = /* @__PURE__ */ new Set([
|
|
4072
|
+
"options",
|
|
4073
|
+
"defaultOptions",
|
|
4074
|
+
"values"
|
|
4075
|
+
]);
|
|
4076
|
+
/** Maps with author or hash keys whose entries are schema objects: keys verbatim, entries normalized. */
|
|
4077
|
+
var USER_KEYED_OBJECT_MAPS = /* @__PURE__ */ new Set(["optionMedia", "assets"]);
|
|
4078
|
+
var isUpper = (ch) => ch >= "A" && ch <= "Z";
|
|
4079
|
+
/**
|
|
4080
|
+
* Newtonsoft's `CamelCaseNamingStrategy`: a leading run of capitals is lowercased
|
|
4081
|
+
* whole, except the last one when a lowercase word follows. `UV` → `uv`,
|
|
4082
|
+
* `UVMapping` → `uvMapping` (a first-character rule gives `uVMapping`).
|
|
4083
|
+
*/
|
|
4084
|
+
function toCamelCase(key) {
|
|
4085
|
+
if (key.length === 0 || !isUpper(key[0])) return key;
|
|
4086
|
+
let run = 0;
|
|
4087
|
+
while (run < key.length && isUpper(key[run])) run++;
|
|
4088
|
+
if (run > 1 && run < key.length) run--;
|
|
4089
|
+
return key.slice(0, run).toLowerCase() + key.slice(run);
|
|
4090
|
+
}
|
|
4091
|
+
/**
|
|
4092
|
+
* Returns a schema whose structural keys are camelCase, whichever Newtonsoft
|
|
4093
|
+
* serialized it. Always a fresh object the caller may mutate; non-objects are
|
|
4094
|
+
* returned as-is.
|
|
4095
|
+
*/
|
|
4096
|
+
function normalizeUISchemaCasing(raw) {
|
|
4097
|
+
return normalizeValue(raw);
|
|
4098
|
+
}
|
|
4099
|
+
function normalizeValue(value) {
|
|
4100
|
+
if (Array.isArray(value)) return value.map(normalizeValue);
|
|
4101
|
+
if (value === null || typeof value !== "object") return value;
|
|
4102
|
+
const out = {};
|
|
4103
|
+
for (const [key, child] of Object.entries(value)) {
|
|
4104
|
+
const canonical = toCamelCase(key);
|
|
4105
|
+
setOwnField(out, canonical, USER_AUTHORED_MAPS.has(canonical) ? child : USER_KEYED_OBJECT_MAPS.has(canonical) ? normalizeEntries(child) : normalizeValue(child));
|
|
4106
|
+
}
|
|
4107
|
+
return out;
|
|
4108
|
+
}
|
|
4109
|
+
function normalizeEntries(value) {
|
|
4110
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return value;
|
|
4111
|
+
const out = {};
|
|
4112
|
+
for (const [key, child] of Object.entries(value)) setOwnField(out, key, normalizeValue(child));
|
|
4113
|
+
return out;
|
|
4114
|
+
}
|
|
4115
|
+
/**
|
|
4116
|
+
* Builds the Grasshopper data trees a solve takes as input.
|
|
4117
|
+
*
|
|
4118
|
+
* @example
|
|
4119
|
+
* ```ts
|
|
4120
|
+
* const tree = new TreeBuilder('MyParam')
|
|
4121
|
+
* .append([0], [1, 2, 3])
|
|
4122
|
+
* .append([1], [4, 5])
|
|
4123
|
+
* .toComputeFormat();
|
|
4124
|
+
* ```
|
|
4125
|
+
*/
|
|
4126
|
+
var TreeBuilder = class TreeBuilder {
|
|
4127
|
+
innerTree;
|
|
4128
|
+
paramName;
|
|
4129
|
+
constructor(paramName) {
|
|
4130
|
+
this.paramName = paramName;
|
|
4131
|
+
this.innerTree = {};
|
|
4132
|
+
}
|
|
4133
|
+
/** Append values to the branch at `path` (`[0, 1]` is `{0;1}`). A `null` item is skipped. */
|
|
4134
|
+
append(path, items) {
|
|
4135
|
+
const branch = this.innerTree[TreeBuilder.formatPathString(path)] ??= [];
|
|
4136
|
+
for (const item of items) if (item !== null) branch.push({ data: TreeBuilder.serializeValue(item) });
|
|
4137
|
+
return this;
|
|
4138
|
+
}
|
|
4139
|
+
/** Replace the tree with a branch-path map like `{ '{0;1}': [1, 2] }`. */
|
|
4140
|
+
fromDataTreeDefault(treeData) {
|
|
4141
|
+
this.innerTree = {};
|
|
4142
|
+
for (const [pathStr, items] of Object.entries(treeData)) {
|
|
4143
|
+
if (!Array.isArray(items)) continue;
|
|
4144
|
+
const path = TreeBuilder.parsePathString(pathStr);
|
|
4145
|
+
this.append(path, items);
|
|
4146
|
+
}
|
|
4147
|
+
return this;
|
|
4148
|
+
}
|
|
4149
|
+
/** Append a value, or each value of an array, to branch `{0}`. */
|
|
4150
|
+
appendFlat(values) {
|
|
4151
|
+
const items = Array.isArray(values) ? values : [values];
|
|
4152
|
+
return this.append([0], items);
|
|
4153
|
+
}
|
|
4154
|
+
/** The tree in the shape a solve request sends. */
|
|
4155
|
+
toComputeFormat() {
|
|
4156
|
+
return {
|
|
4157
|
+
ParamName: this.paramName,
|
|
4158
|
+
InnerTree: this.innerTree
|
|
4159
|
+
};
|
|
4160
|
+
}
|
|
4161
|
+
/**
|
|
4162
|
+
* One tree per input that has a default, keyed by its nickname. Defaults are coerced and
|
|
4163
|
+
* clamped by the same rules as {@link TreeBuilder.fromValues}.
|
|
4164
|
+
*/
|
|
4165
|
+
static fromInputParams(inputs) {
|
|
4166
|
+
return TreeBuilder.fromValues(inputs.map((input) => ({
|
|
4167
|
+
paramName: input.nickname || "unnamed",
|
|
4168
|
+
paramType: input.paramType,
|
|
4169
|
+
value: input.default,
|
|
4170
|
+
..."minimum" in input && {
|
|
4171
|
+
minimum: input.minimum,
|
|
4172
|
+
maximum: input.maximum
|
|
4173
|
+
}
|
|
4174
|
+
})));
|
|
4175
|
+
}
|
|
4176
|
+
/**
|
|
4177
|
+
* One tree per entry, coercing UI values the way Grasshopper reads them. Number and Integer
|
|
4178
|
+
* items go through the numeric coercion (Integer rounds) and are clamped to
|
|
4179
|
+
* `minimum`/`maximum`; Boolean items also accept `'true'`/`'false'`; every other type passes
|
|
4180
|
+
* through. An item that fails coercion is dropped with a warning. An entry left with no items
|
|
4181
|
+
* is omitted, so Grasshopper uses its own value; `''` is an item, not an empty value.
|
|
4182
|
+
*/
|
|
4183
|
+
static fromValues(entries) {
|
|
4184
|
+
const trees = [];
|
|
4185
|
+
for (const entry of entries) {
|
|
4186
|
+
const tree = new TreeBuilder(entry.paramName);
|
|
4187
|
+
const coerce = TreeBuilder.itemCoercer(entry);
|
|
4188
|
+
for (const [path, items] of TreeBuilder.branchesOf(entry.value)) {
|
|
4189
|
+
const kept = [];
|
|
4190
|
+
for (const item of items) {
|
|
4191
|
+
if (item === null || item === void 0) continue;
|
|
4192
|
+
const coerced = coerce(item);
|
|
4193
|
+
if (coerced === null) getLogger().warn(`${entry.paramName}: dropped an item that is not a valid ${entry.paramType}`);
|
|
4194
|
+
else kept.push(coerced);
|
|
4195
|
+
}
|
|
4196
|
+
if (kept.length > 0) tree.append(path, kept);
|
|
4197
|
+
}
|
|
4198
|
+
if (Object.keys(tree.innerTree).length > 0) trees.push(tree.toComputeFormat());
|
|
4199
|
+
}
|
|
4200
|
+
return trees;
|
|
4201
|
+
}
|
|
4202
|
+
static branchesOf(value) {
|
|
4203
|
+
if (!TreeBuilder.hasValidValue(value)) return [];
|
|
4204
|
+
if (isDataTreeDefault(value)) return Object.entries(value).map(([path, items]) => [TreeBuilder.parsePathString(path), items]);
|
|
4205
|
+
return [[[0], Array.isArray(value) ? value : [value]]];
|
|
4206
|
+
}
|
|
4207
|
+
/** `null` means the item was rejected. */
|
|
4208
|
+
static itemCoercer(entry) {
|
|
4209
|
+
const { paramName, minimum, maximum } = entry;
|
|
4210
|
+
const paramType = entry.paramType.toLowerCase();
|
|
4211
|
+
if (paramType === "number" || paramType === "integer") return (item) => {
|
|
4212
|
+
const n = numericTransformer(item);
|
|
4213
|
+
if (n === null) return null;
|
|
4214
|
+
const value = paramType === "integer" ? Math.round(n) : n;
|
|
4215
|
+
return TreeBuilder.clampValue(value, minimum, maximum, paramName);
|
|
4216
|
+
};
|
|
4217
|
+
if (paramType === "boolean") return booleanTransformer;
|
|
4218
|
+
return (item) => item;
|
|
4219
|
+
}
|
|
4220
|
+
/**
|
|
4221
|
+
* Set or add `paramName`'s tree to `newValue`: a scalar, an array (branch `{0}`), or a
|
|
4222
|
+
* branch-path map. Copy-on-write: returns a new array and leaves the caller's untouched, so
|
|
4223
|
+
* assign the result.
|
|
4224
|
+
*/
|
|
4225
|
+
static replaceTreeValue(trees, paramName, newValue) {
|
|
4226
|
+
const compiled = TreeBuilder.buildFromValue(paramName, newValue).toComputeFormat();
|
|
4227
|
+
const result = trees.slice();
|
|
4228
|
+
const idx = result.findIndex((t) => TreeBuilder.paramNameOf(t) === paramName);
|
|
4229
|
+
if (idx === -1) result.push(compiled);
|
|
4230
|
+
else result[idx] = compiled;
|
|
4231
|
+
return result;
|
|
4232
|
+
}
|
|
4233
|
+
static buildFromValue(paramName, value) {
|
|
4234
|
+
const tree = new TreeBuilder(paramName);
|
|
4235
|
+
if (isDataTreeDefault(value)) tree.fromDataTreeDefault(value);
|
|
4236
|
+
else tree.appendFlat(value);
|
|
4237
|
+
return tree;
|
|
4238
|
+
}
|
|
4239
|
+
/**
|
|
4240
|
+
* `paramName`'s whole tree from a solve result's `values`, keyed by branch path (`'{0;1}'`).
|
|
4241
|
+
* `null` when no tree has that param, an empty `Map` when it has no branches. An item without
|
|
4242
|
+
* `data` reads as `null` in place, so indices don't shift.
|
|
4243
|
+
*/
|
|
4244
|
+
static getTree(trees, paramName) {
|
|
4245
|
+
const tree = trees.find((t) => TreeBuilder.paramNameOf(t) === paramName);
|
|
4246
|
+
if (!tree) return null;
|
|
4247
|
+
const branches = /* @__PURE__ */ new Map();
|
|
4248
|
+
const inner = readField(tree, "InnerTree");
|
|
4249
|
+
if (!inner || typeof inner !== "object") return branches;
|
|
4250
|
+
for (const [path, items] of Object.entries(inner)) {
|
|
4251
|
+
if (!Array.isArray(items)) continue;
|
|
4252
|
+
branches.set(path, items.map((item) => item?.data !== void 0 ? TreeBuilder.deserializeValue(item.data) : null));
|
|
4253
|
+
}
|
|
4254
|
+
return branches;
|
|
4255
|
+
}
|
|
4256
|
+
/**
|
|
4257
|
+
* `paramName`'s value when its tree has a single branch: one item unwrapped (`5`, not `[5]`),
|
|
4258
|
+
* several as an array. `null` for a missing param or an empty tree.
|
|
4259
|
+
*
|
|
4260
|
+
* @throws {ComputeError} `INVALID_INPUT` when the tree has more than one branch; read those
|
|
4261
|
+
* with {@link TreeBuilder.getTree}.
|
|
4262
|
+
*/
|
|
4263
|
+
static getTreeValue(trees, paramName) {
|
|
4264
|
+
const tree = TreeBuilder.getTree(trees, paramName);
|
|
4265
|
+
if (!tree || tree.size === 0) return null;
|
|
4266
|
+
if (tree.size > 1) throw new ComputeError(`"${paramName}" has ${tree.size} branches; read it with TreeBuilder.getTree`, ErrorCodes.INVALID_INPUT, { context: {
|
|
4267
|
+
paramName,
|
|
4268
|
+
branchCount: tree.size
|
|
4269
|
+
} });
|
|
4270
|
+
const [items] = tree.values();
|
|
4271
|
+
if (items.length === 0) return null;
|
|
4272
|
+
return items.length === 1 ? items[0] : items;
|
|
4273
|
+
}
|
|
4274
|
+
static paramNameOf(tree) {
|
|
4275
|
+
return readField(tree, "ParamName");
|
|
4276
|
+
}
|
|
4277
|
+
/**
|
|
4278
|
+
* Parse a branch path like `"{0;1;2}"` into `[0, 1, 2]`.
|
|
4279
|
+
*
|
|
4280
|
+
* @throws {ComputeError} `INVALID_INPUT` for a malformed path, rather than
|
|
4281
|
+
* collapsing it to a default branch where two bad keys would merge.
|
|
4282
|
+
*/
|
|
4283
|
+
static parsePathString(pathStr) {
|
|
4284
|
+
const match = pathStr.match(TREE_PATH_RE);
|
|
4285
|
+
if (!match) throw new ComputeError(`Invalid Grasshopper tree path: "${pathStr}". Expected "{}", "{0}", or "{0;1;2}" (negative indices allowed, no empty segments).`, ErrorCodes.INVALID_INPUT, { context: { pathStr } });
|
|
4286
|
+
if (!match[1]) return [];
|
|
4287
|
+
return match[1].split(";").map(Number);
|
|
4288
|
+
}
|
|
4289
|
+
/** `[0, 1, 2]` → `"{0;1;2}"`. */
|
|
4290
|
+
static formatPathString(path) {
|
|
4291
|
+
return `{${path.join(";")}}`;
|
|
4292
|
+
}
|
|
4293
|
+
/** Booleans and numbers stay primitives: Grasshopper reads them typed. */
|
|
4294
|
+
static serializeValue(value) {
|
|
4295
|
+
return typeof value === "object" ? JSON.stringify(value) : value;
|
|
4296
|
+
}
|
|
4297
|
+
static deserializeValue(data) {
|
|
4298
|
+
if (typeof data !== "string") return data;
|
|
4299
|
+
if (data.startsWith("{") || data.startsWith("[")) try {
|
|
4300
|
+
return JSON.parse(data);
|
|
4301
|
+
} catch {
|
|
4302
|
+
return data;
|
|
4303
|
+
}
|
|
4304
|
+
const num = Number(data);
|
|
4305
|
+
if (Number.isFinite(num) && String(num) === data) return num;
|
|
4306
|
+
if (data === "true") return true;
|
|
4307
|
+
if (data === "false") return false;
|
|
4308
|
+
return data;
|
|
4309
|
+
}
|
|
4310
|
+
static hasValidValue(value) {
|
|
4311
|
+
if (value === void 0 || value === null) return false;
|
|
4312
|
+
if (typeof value === "string") return true;
|
|
4313
|
+
if (Array.isArray(value) && value.length === 0) return false;
|
|
4314
|
+
if (typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0) return false;
|
|
4315
|
+
return true;
|
|
4316
|
+
}
|
|
4317
|
+
static clampValue(value, min, max, inputName) {
|
|
4318
|
+
let result = value;
|
|
4319
|
+
if (min !== null && min !== void 0 && result < min) {
|
|
4320
|
+
getLogger().warn(`${inputName}: ${value} below min ${min}, clamping`);
|
|
4321
|
+
result = min;
|
|
4322
|
+
}
|
|
4323
|
+
if (max !== null && max !== void 0 && result > max) {
|
|
4324
|
+
getLogger().warn(`${inputName}: ${value} above max ${max}, clamping`);
|
|
4325
|
+
result = max;
|
|
4326
|
+
}
|
|
4327
|
+
return result;
|
|
4328
|
+
}
|
|
4329
|
+
};
|
|
4330
|
+
|
|
4331
|
+
export { ComputeError as C, ErrorCodes as E, GrasshopperClient as G, TreeBuilder as T, ComputeServerStats as a, GrasshopperResponseProcessor as b, classifyProbeFailure as c, subFolderSegments as d, enableDebugLogging as e, downloadFileDataByRoot as f, decodeBase64ToBinary as g, isDefinitionRef as i, normalizeUISchemaCasing as n, readSchemaResults as r, stableStringify as s };
|
|
4332
|
+
//# sourceMappingURL=grasshopper.js-BTMLax71.js.map
|