@organizaone/o1-code 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +10 -0
  2. package/bundled/qc-helper/docs/quickstart.md +1 -1
  3. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +42 -36
  4. package/chunks/{MaxSizedBox-5EOREWNX.js → MaxSizedBox-YRO4IP7D.js} +23 -23
  5. package/chunks/{StandaloneSessionPicker-3OCB32JD.js → StandaloneSessionPicker-HM6FRRNB.js} +39 -39
  6. package/chunks/{acp-subagent-executor-JTNA5F4Q.js → acp-subagent-executor-GKUWPZ3X.js} +24 -24
  7. package/chunks/{acpAgent-IS2JKYZV.js → acpAgent-NM2GJZPA.js} +65 -65
  8. package/chunks/{agent-U5KE7R4X.js → agent-VI6IBJKP.js} +11 -11
  9. package/chunks/{agent-headless-VL764VUV.js → agent-headless-RG2RANBY.js} +11 -11
  10. package/chunks/{anthropicContentGenerator-I7B3ZJTH.js → anthropicContentGenerator-OUXKGYR3.js} +5 -5
  11. package/chunks/{bridge-4GFWUTJN.js → bridge-ASDRIBGU.js} +24 -24
  12. package/chunks/{build-RFEU7TIS.js → build-HLEIVF4Y.js} +1 -1
  13. package/chunks/{chunk-WVEKU4MO.js → chunk-2R42INUX.js} +2 -2
  14. package/chunks/{chunk-KCIKBXEW.js → chunk-2S3QOYP4.js} +4 -4
  15. package/chunks/{chunk-SHDHN4UM.js → chunk-2TURUYOS.js} +1 -1
  16. package/chunks/{chunk-XNOIGECT.js → chunk-33RS64W5.js} +10 -10
  17. package/chunks/{chunk-4ZTCFNSU.js → chunk-3HBUBIMD.js} +1 -1
  18. package/chunks/{chunk-IF22E34Z.js → chunk-3LIB2FAU.js} +3 -3
  19. package/chunks/{chunk-GKX63AXY.js → chunk-3ODGANQH.js} +2 -2
  20. package/chunks/{chunk-7UG5NBEG.js → chunk-3T5ZVERP.js} +1 -1
  21. package/chunks/{chunk-IFJUYGAZ.js → chunk-4FEIAOCC.js} +1 -1
  22. package/chunks/{chunk-X2RYRNAP.js → chunk-4IDJJ4KI.js} +2 -2
  23. package/chunks/{chunk-JY65SH65.js → chunk-5W2RZUTF.js} +3 -3
  24. package/chunks/{chunk-TUQWDNKR.js → chunk-656G544G.js} +2 -2
  25. package/chunks/{chunk-A6R5ERJF.js → chunk-6CNTKWVU.js} +4 -4
  26. package/chunks/{chunk-NEG6TBRH.js → chunk-7QFVAEBE.js} +1 -1
  27. package/chunks/{chunk-KQRLWGYH.js → chunk-7UK4SIHI.js} +1 -1
  28. package/chunks/{chunk-C2RMEAXF.js → chunk-AC75ZC3R.js} +1 -1
  29. package/chunks/{chunk-SJLUEEH6.js → chunk-BMWNSOKM.js} +2 -2
  30. package/chunks/{chunk-VEFKFFT5.js → chunk-CK53F45C.js} +1 -1
  31. package/chunks/{chunk-DD5QAE42.js → chunk-CLYICZHJ.js} +4 -4
  32. package/chunks/{chunk-KPGPUSJ4.js → chunk-CPQGFFDW.js} +5 -5
  33. package/chunks/{chunk-4YYRPA6G.js → chunk-CS7C2L7J.js} +5 -5
  34. package/chunks/{chunk-XMR45LXQ.js → chunk-CVAGYXMP.js} +1 -1
  35. package/chunks/{chunk-3VVXMGS2.js → chunk-CWSGGQLH.js} +91 -26
  36. package/chunks/{chunk-L2OTZN7G.js → chunk-D4GF3Z3J.js} +1 -1
  37. package/chunks/{chunk-35XZ5JAH.js → chunk-DEULKIEJ.js} +1 -1
  38. package/chunks/{chunk-HFBSP3VC.js → chunk-EIPBVTYB.js} +1 -1
  39. package/chunks/{chunk-3RRITSOA.js → chunk-EQQUC6HX.js} +2 -2
  40. package/chunks/{chunk-73JQWXED.js → chunk-F477I5JN.js} +2 -2
  41. package/chunks/{chunk-DIVWC7JL.js → chunk-FIIOIJX6.js} +5 -5
  42. package/chunks/{chunk-VL3VAUJC.js → chunk-FRRKENS6.js} +3 -3
  43. package/chunks/{chunk-G7HMFP3U.js → chunk-GKCZEQC7.js} +270 -581
  44. package/chunks/{chunk-PVQB3PSU.js → chunk-GLKPKVRO.js} +1 -1
  45. package/chunks/{chunk-NWQPYJVP.js → chunk-GTNYSOQ2.js} +3 -3
  46. package/chunks/{chunk-LKTMEG3O.js → chunk-HFW4YMBT.js} +2 -2
  47. package/chunks/{chunk-WFUXHQZO.js → chunk-IBPY5AJI.js} +31 -9
  48. package/chunks/{chunk-Y2DKG24P.js → chunk-IPTVBAQ5.js} +1 -1
  49. package/chunks/{chunk-2TR3LXCO.js → chunk-IUHFMWMV.js} +4 -4
  50. package/chunks/{chunk-HWHXSAP6.js → chunk-J2OKRT7N.js} +10 -10
  51. package/chunks/{chunk-LDZQTXZL.js → chunk-JGEPZYTM.js} +4 -4
  52. package/chunks/{chunk-FNOLXMFM.js → chunk-JVFO6PPS.js} +1 -1
  53. package/chunks/{chunk-OCUQJADH.js → chunk-KAF4RHGK.js} +1 -1
  54. package/chunks/{chunk-XPFD45HB.js → chunk-KAW6TQNC.js} +6 -6
  55. package/chunks/{chunk-25B3YO64.js → chunk-KDS2IANW.js} +1 -1
  56. package/chunks/{chunk-ZCCCPNWD.js → chunk-KM2K4ERE.js} +1 -1
  57. package/chunks/{chunk-J5XJUCP6.js → chunk-L66MHJW7.js} +3 -3
  58. package/chunks/{chunk-NCYMEGY4.js → chunk-L6HTWOTF.js} +5 -5
  59. package/chunks/{chunk-SNSYYPUE.js → chunk-LBT6PT4Z.js} +7 -7
  60. package/chunks/{chunk-ZJYMX7GI.js → chunk-LIM5RBA5.js} +3 -3
  61. package/chunks/{chunk-FVXJFEVA.js → chunk-LQELD265.js} +1 -1
  62. package/chunks/{chunk-4D3AFN6X.js → chunk-LQWYK66V.js} +3 -3
  63. package/chunks/{chunk-OUANBR2O.js → chunk-LTQLCF23.js} +1 -1
  64. package/chunks/{chunk-ADSXYGOQ.js → chunk-LU2Z7WRX.js} +1 -1
  65. package/chunks/{chunk-KWUNXWMZ.js → chunk-MFSMNYXY.js} +8 -8
  66. package/chunks/{chunk-SRM5ACHK.js → chunk-MUX4EKXE.js} +1 -1
  67. package/chunks/{chunk-NIIG7L3H.js → chunk-N335XRGH.js} +1 -1
  68. package/chunks/{chunk-PIMJCQZQ.js → chunk-OOLEXGWB.js} +1 -1
  69. package/chunks/{chunk-ZOZJOC2D.js → chunk-OU5QAYET.js} +2 -2
  70. package/chunks/{chunk-5OZ6R5FD.js → chunk-OZ2OT5BC.js} +3 -3
  71. package/chunks/{chunk-YPHLY3RQ.js → chunk-PCCUFQHX.js} +5 -5
  72. package/chunks/{chunk-2XWTDVCK.js → chunk-PL7VG3H5.js} +2 -2
  73. package/chunks/{chunk-YNYV52Z4.js → chunk-Q2SEZDMU.js} +14 -3
  74. package/chunks/{chunk-PZG6YNNW.js → chunk-Q7ZF32SN.js} +1 -1
  75. package/chunks/{chunk-DGB4GDUC.js → chunk-QBCC6DDB.js} +15 -15
  76. package/chunks/{chunk-SRUCOHM3.js → chunk-QG6AA2EE.js} +6 -6
  77. package/chunks/{chunk-SD4FTFLM.js → chunk-QLXCD56R.js} +2 -2
  78. package/chunks/{chunk-OYF5BLWF.js → chunk-QP3UCTAH.js} +1 -1
  79. package/chunks/{chunk-B5RUUS5Z.js → chunk-R4FAETL7.js} +1 -1
  80. package/chunks/{chunk-TA5SQUCP.js → chunk-R5ILEKY4.js} +1 -1
  81. package/chunks/{chunk-2ZZOVOXT.js → chunk-RCVRWBNS.js} +2 -2
  82. package/chunks/{chunk-DFHGNP5W.js → chunk-RQ2LQ5RB.js} +17 -17
  83. package/chunks/{chunk-CXL3KGXN.js → chunk-RZQASTZP.js} +7 -7
  84. package/chunks/{chunk-MRDWUFJ3.js → chunk-SB7HLYND.js} +3 -3
  85. package/chunks/{chunk-NHVJTPZA.js → chunk-SRJTWTB2.js} +33 -33
  86. package/chunks/{chunk-B74GMYXF.js → chunk-SVMEPMAZ.js} +30 -30
  87. package/chunks/{chunk-YK4BICUN.js → chunk-SX5AXFZV.js} +3 -3
  88. package/chunks/{chunk-WI4BVBZO.js → chunk-SYR2YWGQ.js} +1 -1
  89. package/chunks/{chunk-SALGNBVH.js → chunk-U2A23HJU.js} +3 -3
  90. package/chunks/{chunk-V2WRTFQU.js → chunk-UFUFCLDL.js} +5 -5
  91. package/chunks/{chunk-QKJBBOEM.js → chunk-UKUAUI76.js} +2 -2
  92. package/chunks/{chunk-ZTD5FNCI.js → chunk-UUPZUWG5.js} +1 -1
  93. package/chunks/{chunk-UDJURQZ6.js → chunk-VCKGH2UF.js} +3 -3
  94. package/chunks/{chunk-BXRUYSL6.js → chunk-W3T7KUBS.js} +1 -1
  95. package/chunks/{chunk-AT74D3S6.js → chunk-WWRYYBOB.js} +12 -3
  96. package/chunks/{chunk-NHRNNWWS.js → chunk-XAVVXBNC.js} +1 -1
  97. package/chunks/{chunk-BBH77V6I.js → chunk-XCO4NKA5.js} +1 -1
  98. package/chunks/{chunk-N2PY5BWY.js → chunk-XJPQ7YBB.js} +1 -1
  99. package/chunks/{chunk-UQ6BHHFA.js → chunk-XLMO7VIH.js} +4 -4
  100. package/chunks/{chunk-IKDFLXTG.js → chunk-YB735VNN.js} +4 -4
  101. package/chunks/{chunk-CLRPG355.js → chunk-YBIK7JBH.js} +3 -3
  102. package/chunks/{chunk-GT5QP7HM.js → chunk-YLMKYLNH.js} +2 -2
  103. package/chunks/{chunk-HXLT4YHM.js → chunk-YNFJLMGL.js} +9 -9
  104. package/chunks/{chunk-KFOL4KHG.js → chunk-YQP3ETMA.js} +8 -8
  105. package/chunks/{chunk-5KLD2C2A.js → chunk-Z32ZO4N2.js} +1 -1
  106. package/chunks/{chunk-BO53R5FT.js → chunk-ZEVIKHNQ.js} +3 -3
  107. package/chunks/{chunk-XQGFM4KU.js → chunk-ZT4BSBY4.js} +5 -5
  108. package/chunks/{codex-subagent-executor-H23KDM2L.js → codex-subagent-executor-RHTAEFXD.js} +24 -24
  109. package/chunks/{contextCommand-FTM7H7IU.js → contextCommand-CQFH75BZ.js} +23 -23
  110. package/chunks/{core-runtime-EOPJ5NTV.js → core-runtime-5SGS3SVD.js} +21 -21
  111. package/chunks/{create-sub-session-TYQLJBIC.js → create-sub-session-G7VWSOXC.js} +22 -22
  112. package/chunks/{daemon-git-worktree-guard-XYJOCQD4.js → daemon-git-worktree-guard-IUFLX2O4.js} +21 -21
  113. package/chunks/{daemon-status-provider-WSERMTQ3.js → daemon-status-provider-6ZTLYNNK.js} +29 -29
  114. package/chunks/{daemon-trust-policy-2TLIJCGQ.js → daemon-trust-policy-254OGOCS.js} +27 -27
  115. package/chunks/{daemon-trust-policy-monitor-5WZ6JDKZ.js → daemon-trust-policy-monitor-LGXXCQEP.js} +27 -27
  116. package/chunks/{deferred-core-runtime-55WMDAXO.js → deferred-core-runtime-7OORZHNH.js} +21 -21
  117. package/chunks/{edit-UPV3RDKW.js → edit-V46XHSY7.js} +13 -13
  118. package/chunks/{en-S424EGDF.js → en-VJBVNTY4.js} +13 -0
  119. package/chunks/{enterPlanMode-IFHOH44O.js → enterPlanMode-ZPTXYQMB.js} +11 -11
  120. package/chunks/{environment-YEQIXHG6.js → environment-4JNOLQYX.js} +23 -23
  121. package/chunks/{errors-X2UJSPQL.js → errors-XFCASXKU.js} +23 -23
  122. package/chunks/{execution-tool-EXIGBLTL.js → execution-tool-45FRLDNU.js} +13 -13
  123. package/chunks/{execution-worker-6PKEW2P6.js → execution-worker-YUQGSB2E.js} +16 -16
  124. package/chunks/{exitPlanMode-7NRDPCOW.js → exitPlanMode-IVJH3OXX.js} +11 -11
  125. package/chunks/{fast-path-I65CU5I2.js → fast-path-XN7NK4CH.js} +2 -2
  126. package/chunks/{glob-XTHACKUG.js → glob-NHZYR52J.js} +11 -11
  127. package/chunks/{goal-tools-KL2MBM6T.js → goal-tools-GKFYH6GK.js} +11 -11
  128. package/chunks/{handleAutoUpdate-AN36IGA3.js → handleAutoUpdate-SLCHZHWT.js} +24 -24
  129. package/chunks/{i18n-ZOWYH5SP.js → i18n-4AFHUMG2.js} +22 -22
  130. package/chunks/{initializer-7VQKSVVS.js → initializer-CDFNNZPN.js} +27 -27
  131. package/chunks/{installationInfo-L6JLTT7O.js → installationInfo-WUQTTZHB.js} +21 -21
  132. package/chunks/{list-HZEUOA3H.js → list-K2EIWBPE.js} +29 -29
  133. package/chunks/{llm-VIAH4AFT.js → llm-TLNZYLXJ.js} +53 -53
  134. package/chunks/{llm-content-generator-AE3URFE7.js → llm-content-generator-OXL4S7KY.js} +3 -3
  135. package/chunks/{loadedSettingsAdapter-LLENP2KA.js → loadedSettingsAdapter-AUILEI5N.js} +27 -27
  136. package/chunks/{local-execution-environment-B2UY3HMI.js → local-execution-environment-OSK4IEYP.js} +16 -16
  137. package/chunks/{loggingContentGenerator-5I5NLC6I.js → loggingContentGenerator-FINQP2Y4.js} +12 -12
  138. package/chunks/{managed-npm-update-6XAPVQBT.js → managed-npm-update-5DFVQ475.js} +21 -21
  139. package/chunks/{mcp-PIYFXVT4.js → mcp-ZFQGAZRK.js} +27 -27
  140. package/chunks/{model-call-collection-7DIS7C2G.js → model-call-collection-3WVMJQ5M.js} +1 -1
  141. package/chunks/{model-configuration-J7N3CHD5.js → model-configuration-TCLVVCJS.js} +28 -28
  142. package/chunks/{modelConfigUtils-6YYQJIHD.js → modelConfigUtils-LNDNXLJV.js} +23 -23
  143. package/chunks/{monitor-5GBFRXN7.js → monitor-DVKR4R64.js} +11 -11
  144. package/chunks/{nonInteractiveCli-YFE2ILFH.js → nonInteractiveCli-JNH7PLWY.js} +56 -56
  145. package/chunks/{nonInteractiveToolExecutor-BRFDL2BK.js → nonInteractiveToolExecutor-L2K4LU2P.js} +12 -12
  146. package/chunks/{notebook-edit-ORYWDEMK.js → notebook-edit-LLJZI52V.js} +12 -12
  147. package/chunks/{omni-ANTNX2XB.js → omni-4T23JD65.js} +9 -9
  148. package/chunks/{openaiContentGenerator-AIWBAUPV.js → openaiContentGenerator-Y5AW2S3K.js} +7 -7
  149. package/chunks/{openaiResponsesContentGenerator-SABJHG34.js → openaiResponsesContentGenerator-VHLQZH36.js} +3 -3
  150. package/chunks/{processUtils-UAADVXTD.js → processUtils-OGQTTYVO.js} +2 -2
  151. package/chunks/{prompt-terminal-ledger-I7POO7OK.js → prompt-terminal-ledger-M23SMYZS.js} +22 -22
  152. package/chunks/{pt-OHD6RIUC.js → pt-7ZZUXID3.js} +13 -0
  153. package/chunks/{reactive-degrade-VHPS7U44.js → reactive-degrade-CQ7ALF7Z.js} +8 -8
  154. package/chunks/{read-file-SERUEXAP.js → read-file-TGXV7LRJ.js} +2 -2
  155. package/chunks/{resumeHistoryUtils-B6GT4AOO.js → resumeHistoryUtils-5UTZ2RZE.js} +26 -26
  156. package/chunks/{ripGrep-2NTNXBII.js → ripGrep-MJXCIT62.js} +3 -3
  157. package/chunks/{run-o1-code-serve-WROVR5TA.js → run-o1-code-serve-NFPIVOYJ.js} +32 -32
  158. package/chunks/{sandboxConfig-UVIRIBNM.js → sandboxConfig-UOAIYSNY.js} +21 -21
  159. package/chunks/{scheduled-tasks-ILH3HQXS.js → scheduled-tasks-4MX5JTOU.js} +27 -27
  160. package/chunks/{scheduler-Y2TYB53M.js → scheduler-ZZCLKFWM.js} +23 -23
  161. package/chunks/{serve-YUVXMXLS.js → serve-DGO6JMBA.js} +27 -27
  162. package/chunks/{server-K75VXRXS.js → server-N6BPWDPD.js} +57 -57
  163. package/chunks/{session-KZSKLSES.js → session-4YPHCRFC.js} +57 -57
  164. package/chunks/{session-attachments-root-MYYIOBTM.js → session-attachments-root-RSL2YSFZ.js} +21 -21
  165. package/chunks/{session-pr-refresh-33KB2JND.js → session-pr-refresh-RPM3VLUQ.js} +26 -26
  166. package/chunks/{settings-HVF3IJ2I.js → settings-GSPRMMOT.js} +26 -26
  167. package/chunks/{shell-PN27CAHY.js → shell-HWIE3YJY.js} +11 -11
  168. package/chunks/{skill-L6CRUQRR.js → skill-PAU4TRSD.js} +3 -3
  169. package/chunks/{skill-settings-3Y3SG5O5.js → skill-settings-UFOTSN37.js} +27 -27
  170. package/chunks/{spawnChannel-XSDXM46P.js → spawnChannel-7IQPYOPP.js} +23 -23
  171. package/chunks/{standalone-update-3LDGOGBF.js → standalone-update-U7HGJB2O.js} +23 -23
  172. package/chunks/{startInteractiveUI-GIDY23D3.js → startInteractiveUI-N7XQZNFX.js} +2780 -2438
  173. package/chunks/{team-create-LFN7HQGC.js → team-create-4QRHJTSV.js} +11 -11
  174. package/chunks/{team-plan-approval-EFVOZVSP.js → team-plan-approval-U6QCZ3I7.js} +11 -11
  175. package/chunks/{terminal-image-renderer-GOF6SZEL.js → terminal-image-renderer-QRYTSBBI.js} +21 -21
  176. package/chunks/{theme-manager-MQ7UIBL2.js → theme-manager-VFNWDS5X.js} +21 -21
  177. package/chunks/{tool-result-media-NQAPMXYD.js → tool-result-media-NLHN7JZU.js} +9 -9
  178. package/chunks/{tool-search-JJ7KQQ5S.js → tool-search-QGTV2ON5.js} +2 -2
  179. package/chunks/{total-session-admission-GTFQVE5J.js → total-session-admission-PUJHR6FR.js} +24 -24
  180. package/chunks/{trustedFolders-W3AE6S4D.js → trustedFolders-CLVE6DRI.js} +22 -22
  181. package/chunks/{update-relaunch-VIWAZWCG.js → update-relaunch-IPSN33OR.js} +5 -5
  182. package/chunks/{updateCheck-EHHLVFT3.js → updateCheck-REWSU2AC.js} +23 -23
  183. package/chunks/{upload-config-6Z3CPQTV.js → upload-config-W3AEV3WP.js} +6 -6
  184. package/chunks/{useAutoAcceptIndicator-2BDM2ZLG.js → useAutoAcceptIndicator-2JODXT2R.js} +30 -30
  185. package/chunks/{validateNonInterActiveAuth-SBUIY7JB.js → validateNonInterActiveAuth-P5P5SI6T.js} +53 -53
  186. package/chunks/{version-LJX5EMFD.js → version-KCTVVQ6T.js} +1 -1
  187. package/chunks/{web-fetch-NMKFGF5A.js → web-fetch-3Z32TKL7.js} +2 -2
  188. package/chunks/{web-search-FT3NC3MF.js → web-search-T7R5BOOJ.js} +7 -7
  189. package/chunks/{workflow-5WQJENZ6.js → workflow-XFMT6MFA.js} +12 -12
  190. package/chunks/{workspace-providers-status-U3G2IL7D.js → workspace-providers-status-E2DKABEG.js} +33 -33
  191. package/chunks/{workspace-registration-store-XGN5KM7D.js → workspace-registration-store-FWU3W65M.js} +1 -1
  192. package/chunks/{workspace-registry-V7Z7GRVC.js → workspace-registry-EX6Q35BY.js} +24 -24
  193. package/chunks/{workspace-runtime-coordinator-TEWHWJZI.js → workspace-runtime-coordinator-RIA3VIAY.js} +25 -25
  194. package/chunks/{workspace-service-JM6TECMD.js → workspace-service-DDCBDEWZ.js} +31 -31
  195. package/chunks/{workspace-skills-status-ESUOVYAN.js → workspace-skills-status-B4J7CHRJ.js} +30 -30
  196. package/chunks/{workspace-trust-reconciler-PGZAZMT3.js → workspace-trust-reconciler-HMJYGYMS.js} +30 -30
  197. package/chunks/{write-file-AHGK3PK4.js → write-file-HVNSGPXF.js} +13 -13
  198. package/chunks/{zoom-image-IU5DRM6D.js → zoom-image-WLBUTVWK.js} +2 -2
  199. package/cli.js +12 -12
  200. package/execution-worker.js +1 -1
  201. package/export-transcript-document.js +1 -1
  202. package/locales/en.js +19 -0
  203. package/locales/pt.js +19 -0
  204. package/package.json +2 -2
  205. package/release-notes.json +21 -0
  206. package/vendor/o1-connect/.lintstagedrc.mjs +7 -0
  207. package/vendor/o1-connect/README.md +15 -7
  208. package/vendor/o1-connect/VENDOR.json +4 -4
  209. package/vendor/o1-connect/lib.d.mts +9 -1
  210. package/vendor/o1-connect/lib.mjs +444 -861
  211. package/web-shell/assets/{abnfDiagram-VCTEODGH-PVbSspuv.js → abnfDiagram-VCTEODGH-x0S71JE3.js} +1 -1
  212. package/web-shell/assets/{arc-VsWasC21.js → arc-Cz75q_IV.js} +1 -1
  213. package/web-shell/assets/{architectureDiagram-5GKGNRK7-CQGJih80.js → architectureDiagram-5GKGNRK7-C_dL06R0.js} +1 -1
  214. package/web-shell/assets/{blockDiagram-NRAW4CY4-Df9FTUp0.js → blockDiagram-NRAW4CY4-Vs4QVgsM.js} +1 -1
  215. package/web-shell/assets/{c4Diagram-UCG6FXSJ-Cq2wSg56.js → c4Diagram-UCG6FXSJ-CgRK6Jz0.js} +1 -1
  216. package/web-shell/assets/channel-pE79vspw.js +1 -0
  217. package/web-shell/assets/{chunk-2Q5K7J3B-Chp7JPzQ.js → chunk-2Q5K7J3B-6wq4aY1J.js} +1 -1
  218. package/web-shell/assets/{chunk-5VM5RSS4-gml5kfyF.js → chunk-5VM5RSS4-Bo9m0SiQ.js} +1 -1
  219. package/web-shell/assets/{chunk-F27PBJKO-By_hW2gT.js → chunk-F27PBJKO-C4L0MjFe.js} +1 -1
  220. package/web-shell/assets/{chunk-G27WJ6UU-8NLL7TjL.js → chunk-G27WJ6UU-BDQDTWF7.js} +1 -1
  221. package/web-shell/assets/{chunk-JWPE2WC7-Bz8c6lcT.js → chunk-JWPE2WC7-DT5_JHb_.js} +1 -1
  222. package/web-shell/assets/{chunk-LCL6LL3I-ZkGZaXXw.js → chunk-LCL6LL3I-1yVri9gU.js} +1 -1
  223. package/web-shell/assets/{chunk-POPQ4Y6H-B8iYNlKK.js → chunk-POPQ4Y6H-CryAaWS9.js} +1 -1
  224. package/web-shell/assets/{chunk-SVP7TREG-DwVdGXs4.js → chunk-SVP7TREG-D0mJDzI7.js} +1 -1
  225. package/web-shell/assets/{chunk-XXDRQBXY-CsCbtvRS.js → chunk-XXDRQBXY-C5ffwsCM.js} +1 -1
  226. package/web-shell/assets/classDiagram-DTDB5LWJ-0QITOU6l.js +1 -0
  227. package/web-shell/assets/classDiagram-v2-JRS7N3AN-0QITOU6l.js +1 -0
  228. package/web-shell/assets/{cose-bilkent-JH36ORCC-DwnxQIaV.js → cose-bilkent-JH36ORCC-DHE8Zr-F.js} +1 -1
  229. package/web-shell/assets/{cynefin-OW5HDTMX-BvGw520V.js → cynefin-OW5HDTMX-BnL4xySG.js} +1 -1
  230. package/web-shell/assets/{cynefinDiagram-5FMLGOSQ-DErV7NUm.js → cynefinDiagram-5FMLGOSQ-C_Vfdoz6.js} +1 -1
  231. package/web-shell/assets/{dagre-3AP2YEHR-DUKJascy.js → dagre-3AP2YEHR-DYpnUd3X.js} +1 -1
  232. package/web-shell/assets/{diagram-S7CK7UJ4-DC2A1fK2.js → diagram-S7CK7UJ4-Oar04chd.js} +1 -1
  233. package/web-shell/assets/{diagram-UQ7AKVKN-Dv3eUqcO.js → diagram-UQ7AKVKN-CdWEMvLi.js} +1 -1
  234. package/web-shell/assets/{diagram-VSXAHHWV-B_k7qlTN.js → diagram-VSXAHHWV-Bir5CZNv.js} +1 -1
  235. package/web-shell/assets/{diagram-VX7I27RA-DH7Bx528.js → diagram-VX7I27RA-Bm1O69Id.js} +1 -1
  236. package/web-shell/assets/{diagram-Z3DM3KII-CtOVvMVx.js → diagram-Z3DM3KII-r1AOVQ0e.js} +1 -1
  237. package/web-shell/assets/{ebnfDiagram-PWID7BFC-DrkkLJdI.js → ebnfDiagram-PWID7BFC-DevtH3i5.js} +1 -1
  238. package/web-shell/assets/{erDiagram-SSCWMZ5O-C0uNwMNd.js → erDiagram-SSCWMZ5O-SFNjhQIj.js} +1 -1
  239. package/web-shell/assets/{flowDiagram-A5DVABFB-B3sbye5k.js → flowDiagram-A5DVABFB-DgJ1KxI-.js} +1 -1
  240. package/web-shell/assets/{ganttDiagram-EL5Y4UJY-D3Ms91Ay.js → ganttDiagram-EL5Y4UJY-oAT0EGwX.js} +1 -1
  241. package/web-shell/assets/{gitGraphDiagram-WWUBYQGX-BHrKQ3iH.js → gitGraphDiagram-WWUBYQGX-vCX1mSs_.js} +1 -1
  242. package/web-shell/assets/{index-DvuDn2OC.js → index-BEFE9XEw.js} +1 -1
  243. package/web-shell/assets/{index-BL5DGwqU.js → index-Cqj9WNLr.js} +3 -3
  244. package/web-shell/assets/{infoDiagram-RXCK75RN-DWyT73_I.js → infoDiagram-RXCK75RN-_NepfAGI.js} +1 -1
  245. package/web-shell/assets/{ishikawaDiagram-5VMMS53U-DybYyMJT.js → ishikawaDiagram-5VMMS53U-Bk3wYLfy.js} +1 -1
  246. package/web-shell/assets/{journeyDiagram-EYS64GPL-D-v8PiYH.js → journeyDiagram-EYS64GPL-DUUHuAKD.js} +1 -1
  247. package/web-shell/assets/{kanban-definition-3QL26DDD-BUWrNJxx.js → kanban-definition-3QL26DDD-BYaNwMqV.js} +1 -1
  248. package/web-shell/assets/{layout-DTXwh-A4.js → layout-CH_OWxT7.js} +1 -1
  249. package/web-shell/assets/{linear-C8iFKFtJ.js → linear-BEpGEQC7.js} +1 -1
  250. package/web-shell/assets/{mermaid.core-DZcsifbF.js → mermaid.core-DhaXOJnx.js} +6 -6
  251. package/web-shell/assets/{mindmap-definition-FBJOCRG2-D1OyJM6T.js → mindmap-definition-FBJOCRG2-Ci7nWQV9.js} +1 -1
  252. package/web-shell/assets/{pegDiagram-XKGWAZYB-b2dM3687.js → pegDiagram-XKGWAZYB-CgNvWMe-.js} +1 -1
  253. package/web-shell/assets/{pieDiagram-E7YTZNPT-n-qlKbdF.js → pieDiagram-E7YTZNPT-4V5XLQqW.js} +1 -1
  254. package/web-shell/assets/{quadrantDiagram-AXDQQJYC-DbiRHm_L.js → quadrantDiagram-AXDQQJYC-DPdypjO1.js} +1 -1
  255. package/web-shell/assets/{railroadDiagram-O6MQD6OU-CAUM_6wo.js → railroadDiagram-O6MQD6OU-BjXTf6pU.js} +1 -1
  256. package/web-shell/assets/{requirementDiagram-EFPCY7ZU-D_YoabOy.js → requirementDiagram-EFPCY7ZU-DJss5V5T.js} +1 -1
  257. package/web-shell/assets/{sankeyDiagram-P5KCCOFB-C17c2F-F.js → sankeyDiagram-P5KCCOFB-D75QSw7n.js} +1 -1
  258. package/web-shell/assets/{sequenceDiagram-WJ2MYXX4-DtEF8IM9.js → sequenceDiagram-WJ2MYXX4-BDhXaEt_.js} +1 -1
  259. package/web-shell/assets/{sizeCapture-X5ZJPWSS-CEayyeYf.js → sizeCapture-X5ZJPWSS-fFMG4DvB.js} +1 -1
  260. package/web-shell/assets/{stateDiagram-HBIQ2CUA-D34ANpKU.js → stateDiagram-HBIQ2CUA-B1p5bjb3.js} +1 -1
  261. package/web-shell/assets/stateDiagram-v2-4QOOHH4V-CSbHD2Wn.js +1 -0
  262. package/web-shell/assets/{swimlanes-XN3QIQJK-CxuDoZvW.js → swimlanes-XN3QIQJK-bPx7cEqz.js} +1 -1
  263. package/web-shell/assets/swimlanesDiagram-VK2B7HYN-DTnMbaNo.js +8 -0
  264. package/web-shell/assets/{timeline-definition-24CTP7MA-ewm8t6bY.js → timeline-definition-24CTP7MA-B3LCneiU.js} +1 -1
  265. package/web-shell/assets/{vennDiagram-4TSXK5OY-J5Luz0Pz.js → vennDiagram-4TSXK5OY-CFmjd4GT.js} +1 -1
  266. package/web-shell/assets/{wardleyDiagram-VM6X3IG4-g9-5UNQz.js → wardleyDiagram-VM6X3IG4-DXyVTjgN.js} +1 -1
  267. package/web-shell/assets/{xychartDiagram-S5SC5T6Z-Dy0uNlVX.js → xychartDiagram-S5SC5T6Z-y2w_UoEl.js} +1 -1
  268. package/web-shell/index.html +1 -1
  269. package/web-shell/sw.js +1 -1
  270. package/web-shell/assets/channel-8zIIJdbY.js +0 -1
  271. package/web-shell/assets/classDiagram-DTDB5LWJ-BZiDhVAk.js +0 -1
  272. package/web-shell/assets/classDiagram-v2-JRS7N3AN-BZiDhVAk.js +0 -1
  273. package/web-shell/assets/stateDiagram-v2-4QOOHH4V-BkgMHPaH.js +0 -1
  274. package/web-shell/assets/swimlanesDiagram-VK2B7HYN-B_dlOslo.js +0 -8
@@ -1,106 +1,85 @@
1
- // o1-connect-lib 9.0.0 - https://github.com/organizaone/o1-gateway (MIT)
1
+ // o1-connect-lib 9.4.0 - https://github.com/organizaone/o1-gateway (MIT)
2
2
 
3
3
  // src/shared/tunnel-protocol.ts
4
- import { createHash } from 'node:crypto';
5
- var TUNNEL_PATH = '/tunnel';
6
- var TUNNEL_PINS_PATH = '/tunnel/pins';
7
- var TUNNEL_PROTOCOL = 'o1gw-tunnel.v1';
8
- var TUNNEL_SERVERNAME = 'o1gw-tunnel';
9
- var CODE_PREFIX = 'o1gw1.';
4
+ import { createHash } from "node:crypto";
5
+ var TUNNEL_PATH = "/tunnel";
6
+ var TUNNEL_PINS_PATH = "/tunnel/pins";
7
+ var TUNNEL_PROTOCOL = "o1gw-tunnel.v1";
8
+ var TUNNEL_SERVERNAME = "o1gw-tunnel";
9
+ var CODE_PREFIX = "o1gw1.";
10
10
  var PIN = /^sha256\/[A-Za-z0-9+/]{43}=$/;
11
11
  var TOKEN = /^[0-9a-f]{64}$/;
12
12
  var DEVICE = /^[a-z0-9][a-z0-9_-]{0,31}$/i;
13
13
  var MAX_PINS = 4;
14
- var ConnectionCodeError = class extends Error {};
14
+ var MAX_HOSTS = 4;
15
+ var ConnectionCodeError = class extends Error {
16
+ };
15
17
  function pinOfSpki(spkiDer) {
16
- return `sha256/${createHash('sha256').update(spkiDer).digest('base64')}`;
18
+ return `sha256/${createHash("sha256").update(spkiDer).digest("base64")}`;
17
19
  }
18
20
  function isPin(s) {
19
21
  return PIN.test(s);
20
22
  }
21
23
  function fingerprint(pin) {
22
- if (!isPin(pin)) throw new ConnectionCodeError('not a pin');
23
- const hex = Buffer.from(pin.slice('sha256/'.length), 'base64')
24
- .toString('hex')
25
- .toUpperCase();
26
- return (hex.match(/.{4}/g) ?? []).join('-');
24
+ if (!isPin(pin)) throw new ConnectionCodeError("not a pin");
25
+ const hex = Buffer.from(pin.slice("sha256/".length), "base64").toString("hex").toUpperCase();
26
+ return (hex.match(/.{4}/g) ?? []).join("-");
27
27
  }
28
28
  function sniOfPin(pin) {
29
- if (!isPin(pin)) throw new ConnectionCodeError('not a pin');
30
- return `k-${Buffer.from(pin.slice('sha256/'.length), 'base64').toString('hex').slice(0, 20)}.o1gw.invalid`;
29
+ if (!isPin(pin)) throw new ConnectionCodeError("not a pin");
30
+ return `k-${Buffer.from(pin.slice("sha256/".length), "base64").toString("hex").slice(0, 20)}.o1gw.invalid`;
31
31
  }
32
32
  function isLoopbackHost(hostname) {
33
- return (
34
- hostname === '127.0.0.1' || hostname === 'localhost' || hostname === '[::1]'
35
- );
33
+ return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "[::1]";
36
34
  }
37
- function validateCode(c) {
38
- if (!c || typeof c !== 'object')
39
- throw new ConnectionCodeError('the code does not hold a connection');
40
- const o = c;
35
+ function originOf(value, what) {
41
36
  let url;
42
37
  try {
43
- url = new URL(String(o.url));
38
+ url = new URL(value);
44
39
  } catch {
45
- throw new ConnectionCodeError('the proxy URL is not a URL');
46
- }
47
- if (
48
- !(
49
- url.protocol === 'https:' ||
50
- (url.protocol === 'http:' && isLoopbackHost(url.hostname))
51
- )
52
- ) {
53
- throw new ConnectionCodeError('the proxy URL must be https');
54
- }
55
- if (
56
- url.pathname !== '/' ||
57
- url.search ||
58
- url.hash ||
59
- url.username ||
60
- url.password
61
- ) {
62
- throw new ConnectionCodeError("the proxy URL must be the proxy's base URL");
63
- }
64
- if (typeof o.device !== 'string' || !DEVICE.test(o.device))
65
- throw new ConnectionCodeError('the device name is not valid');
66
- if (
67
- !Array.isArray(o.pins) ||
68
- o.pins.length === 0 ||
69
- o.pins.length > MAX_PINS ||
70
- !o.pins.every((p) => typeof p === 'string' && isPin(p))
71
- ) {
72
- throw new ConnectionCodeError('the pin list is not valid');
73
- }
74
- if (typeof o.token !== 'string' || !TOKEN.test(o.token))
75
- throw new ConnectionCodeError('the device token is not valid');
76
- return {
77
- url: url.origin,
78
- device: o.device,
79
- pins: [...o.pins],
80
- token: o.token,
81
- };
40
+ throw new ConnectionCodeError(`the proxy ${what} is not a URL`);
41
+ }
42
+ if (!(url.protocol === "https:" || url.protocol === "http:" && isLoopbackHost(url.hostname))) {
43
+ throw new ConnectionCodeError(`the proxy ${what} must be https`);
44
+ }
45
+ if (url.pathname !== "/" || url.search || url.hash || url.username || url.password) {
46
+ throw new ConnectionCodeError(`the proxy ${what} must be the proxy's base URL`);
47
+ }
48
+ return url.origin;
49
+ }
50
+ function validateCode(c) {
51
+ if (!c || typeof c !== "object") throw new ConnectionCodeError("the code does not hold a connection");
52
+ const o = c;
53
+ const url = originOf(String(o.url), "URL");
54
+ if (typeof o.device !== "string" || !DEVICE.test(o.device)) throw new ConnectionCodeError("the device name is not valid");
55
+ if (!Array.isArray(o.pins) || o.pins.length === 0 || o.pins.length > MAX_PINS || !o.pins.every((p) => typeof p === "string" && isPin(p))) {
56
+ throw new ConnectionCodeError("the pin list is not valid");
57
+ }
58
+ if (typeof o.token !== "string" || !TOKEN.test(o.token)) throw new ConnectionCodeError("the device token is not valid");
59
+ let urls;
60
+ if (o.urls !== void 0) {
61
+ if (!Array.isArray(o.urls) || o.urls.length === 0 || o.urls.some((u) => typeof u !== "string")) throw new ConnectionCodeError("the failover host list is not valid");
62
+ urls = o.urls.map((u, i) => originOf(u, `failover host ${i + 1}`));
63
+ const all = [url, ...urls];
64
+ if (new Set(all).size !== all.length) throw new ConnectionCodeError("the failover host list repeats a host");
65
+ if (all.length > MAX_HOSTS) throw new ConnectionCodeError(`the code names more than ${MAX_HOSTS} hosts`);
66
+ }
67
+ return { url, ...urls === void 0 ? {} : { urls }, device: o.device, pins: [...o.pins], token: o.token };
82
68
  }
83
69
  function decodeConnectionCode(s) {
84
70
  const text = s.trim();
85
- if (!text.startsWith(CODE_PREFIX))
86
- throw new ConnectionCodeError(
87
- 'this is not an o1-connect code (it starts with o1gw1.)',
88
- );
71
+ if (!text.startsWith(CODE_PREFIX)) throw new ConnectionCodeError("this is not an o1-connect code (it starts with o1gw1.)");
89
72
  let parsed;
90
73
  try {
91
- parsed = JSON.parse(
92
- Buffer.from(text.slice(CODE_PREFIX.length), 'base64url').toString('utf8'),
93
- );
74
+ parsed = JSON.parse(Buffer.from(text.slice(CODE_PREFIX.length), "base64url").toString("utf8"));
94
75
  } catch {
95
- throw new ConnectionCodeError(
96
- 'the code is damaged: copy it again from the console',
97
- );
76
+ throw new ConnectionCodeError("the code is damaged: copy it again from the console");
98
77
  }
99
78
  return validateCode(parsed);
100
79
  }
101
80
 
102
81
  // src/client/inner.ts
103
- import tls3 from 'node:tls';
82
+ import tls3 from "node:tls";
104
83
 
105
84
  // src/client/peer-cert.ts
106
85
  var seen = /* @__PURE__ */ new WeakMap();
@@ -113,150 +92,115 @@ function peerCertificate(socket) {
113
92
  }
114
93
 
115
94
  // src/client/poll-client.ts
116
- import { randomBytes as randomBytes2 } from 'node:crypto';
117
- import http3 from 'node:http';
118
- import https2 from 'node:https';
119
- import { isIP as isIP2 } from 'node:net';
120
- import { Duplex as Duplex2 } from 'node:stream';
121
- import tls2 from 'node:tls';
95
+ import { randomBytes as randomBytes2 } from "node:crypto";
96
+ import http3 from "node:http";
97
+ import https2 from "node:https";
98
+ import { isIP as isIP2 } from "node:net";
99
+ import { Duplex as Duplex2 } from "node:stream";
100
+ import tls2 from "node:tls";
122
101
 
123
102
  // src/shared/tunnel-poll.ts
124
- var POLL_PATH = '/tunnel/poll';
103
+ var POLL_PATH = "/tunnel/poll";
125
104
  var POLL_VERSION = 1;
126
105
  var SESSION_BYTES = 32;
127
106
  var MAX_UP = 256 * 1024;
128
107
  var MAX_DOWN = 1024 * 1024;
129
108
  var POLL_WAIT_MS = 2e4;
130
- var TUNNEL_BUSY = 'tunnel_busy';
109
+ var TUNNEL_BUSY = "tunnel_busy";
131
110
  var REQUEST_HEAD = 1 + SESSION_BYTES + 8 + 8 + 1;
132
111
  var RESPONSE_HEAD = 1 + SESSION_BYTES + 8 + 1;
133
112
  var FLAG_CLOSE = 1;
134
113
  var FLAG_POLL = 2;
135
114
  var FLAG_OPEN = 4;
136
115
  var FLAG_CLOSED = 1;
137
- var PollFormatError = class extends Error {};
116
+ var PollFormatError = class extends Error {
117
+ };
138
118
  var ZERO_SESSION = Buffer.alloc(SESSION_BYTES);
139
119
  function sessionOf(id) {
140
- if (id.length !== SESSION_BYTES)
141
- throw new PollFormatError('the session id must be 32 bytes');
120
+ if (id.length !== SESSION_BYTES) throw new PollFormatError("the session id must be 32 bytes");
142
121
  return id;
143
122
  }
144
123
  function requestSession(id) {
145
- if (sessionOf(id).equals(ZERO_SESSION))
146
- throw new PollFormatError('the session id must not be all zero');
124
+ if (sessionOf(id).equals(ZERO_SESSION)) throw new PollFormatError("the session id must not be all zero");
147
125
  return id;
148
126
  }
149
127
  function toU64(n, what) {
150
- if (!Number.isSafeInteger(n) || n < 0)
151
- throw new PollFormatError(`${what} is out of range`);
128
+ if (!Number.isSafeInteger(n) || n < 0) throw new PollFormatError(`${what} is out of range`);
152
129
  return BigInt(n);
153
130
  }
154
131
  function fromU64(b, at, what) {
155
132
  const v = b.readBigUInt64BE(at);
156
- if (v > BigInt(Number.MAX_SAFE_INTEGER))
157
- throw new PollFormatError(`${what} is out of range`);
133
+ if (v > BigInt(Number.MAX_SAFE_INTEGER)) throw new PollFormatError(`${what} is out of range`);
158
134
  return Number(v);
159
135
  }
160
136
  function encodeRequest(r) {
161
- if (r.data.length > MAX_UP)
162
- throw new PollFormatError('the request carries too much data');
137
+ if (r.data.length > MAX_UP) throw new PollFormatError("the request carries too much data");
163
138
  const head = Buffer.alloc(REQUEST_HEAD);
164
139
  head[0] = POLL_VERSION;
165
140
  requestSession(r.session).copy(head, 1);
166
- head.writeBigUInt64BE(toU64(r.upOffset, 'upOffset'), 33);
167
- head.writeBigUInt64BE(toU64(r.ack, 'ack'), 41);
168
- head[49] =
169
- (r.close ? FLAG_CLOSE : 0) |
170
- (r.poll ? FLAG_POLL : 0) |
171
- (r.open ? FLAG_OPEN : 0);
141
+ head.writeBigUInt64BE(toU64(r.upOffset, "upOffset"), 33);
142
+ head.writeBigUInt64BE(toU64(r.ack, "ack"), 41);
143
+ head[49] = (r.close ? FLAG_CLOSE : 0) | (r.poll ? FLAG_POLL : 0) | (r.open ? FLAG_OPEN : 0);
172
144
  return Buffer.concat([head, r.data]);
173
145
  }
174
146
  function decodeResponse(b) {
175
- if (b.length < RESPONSE_HEAD)
176
- throw new PollFormatError('the answer is too short');
177
- if (b[0] !== POLL_VERSION)
178
- throw new PollFormatError("the answer is not a tunnel's");
179
- if (b.length - RESPONSE_HEAD > MAX_DOWN)
180
- throw new PollFormatError('the answer carries too much data');
147
+ if (b.length < RESPONSE_HEAD) throw new PollFormatError("the answer is too short");
148
+ if (b[0] !== POLL_VERSION) throw new PollFormatError("the answer is not a tunnel's");
149
+ if (b.length - RESPONSE_HEAD > MAX_DOWN) throw new PollFormatError("the answer carries too much data");
181
150
  return {
182
151
  session: Buffer.from(b.subarray(1, 33)),
183
- downOffset: fromU64(b, 33, 'downOffset'),
152
+ downOffset: fromU64(b, 33, "downOffset"),
184
153
  closed: (b[41] & FLAG_CLOSED) !== 0,
185
- data: Buffer.from(b.subarray(RESPONSE_HEAD)),
154
+ data: Buffer.from(b.subarray(RESPONSE_HEAD))
186
155
  };
187
156
  }
188
157
 
189
158
  // src/client/proxy-route.ts
190
- import http from 'node:http';
159
+ import http from "node:http";
191
160
  var LOOPBACK = /^(localhost|127(?:\.\d{1,3}){3}|::1)$/i;
192
161
  function bypassed(host, list) {
193
- return list
194
- .split(',')
195
- .map((s) => s.trim().toLowerCase())
196
- .filter(Boolean)
197
- .some(
198
- (entry) =>
199
- entry === '*' ||
200
- entry === host ||
201
- (entry.startsWith('.') && host.endsWith(entry)),
202
- );
162
+ return list.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean).some((entry) => entry === "*" || entry === host || entry.startsWith(".") && host.endsWith(entry));
203
163
  }
204
164
  function proxyFor(target, env = process.env) {
205
- const host = target.hostname.replace(/^\[|\]$/g, '').toLowerCase();
165
+ const host = target.hostname.replace(/^\[|\]$/g, "").toLowerCase();
206
166
  if (LOOPBACK.test(host)) return null;
207
- const raw = (env.HTTPS_PROXY || env.https_proxy || '').trim();
167
+ const raw = (env.HTTPS_PROXY || env.https_proxy || "").trim();
208
168
  if (!raw) return null;
209
- if (bypassed(host, env.NO_PROXY || env.no_proxy || '')) return null;
169
+ if (bypassed(host, env.NO_PROXY || env.no_proxy || "")) return null;
210
170
  let url;
211
171
  try {
212
- url = new URL(raw.includes('://') ? raw : `http://${raw}`);
172
+ url = new URL(raw.includes("://") ? raw : `http://${raw}`);
213
173
  } catch {
214
- throw new Error('HTTPS_PROXY is not a valid URL');
174
+ throw new Error("HTTPS_PROXY is not a valid URL");
215
175
  }
216
- if (url.protocol !== 'http:')
217
- throw new Error('HTTPS_PROXY must be an http:// proxy URL');
176
+ if (url.protocol !== "http:") throw new Error("HTTPS_PROXY must be an http:// proxy URL");
218
177
  const user = decodeURIComponent(url.username);
219
178
  const pass = decodeURIComponent(url.password);
220
179
  return {
221
- host: url.hostname.replace(/^\[|\]$/g, ''),
180
+ host: url.hostname.replace(/^\[|\]$/g, ""),
222
181
  port: Number(url.port || 80),
223
- ...(user || pass
224
- ? {
225
- authorization: `Basic ${Buffer.from(`${user}:${pass}`).toString('base64')}`,
226
- }
227
- : {}),
182
+ ...user || pass ? { authorization: `Basic ${Buffer.from(`${user}:${pass}`).toString("base64")}` } : {}
228
183
  };
229
184
  }
230
185
  var ProxyRefusedError = class extends Error {
231
186
  constructor(status) {
232
- super(
233
- status === 407
234
- ? "the network's proxy needs credentials (HTTP 407): put them in HTTPS_PROXY as http://user:password@host:port"
235
- : `the network's proxy refused the connection (HTTP ${status})`,
236
- );
187
+ super(status === 407 ? "the network's proxy needs credentials (HTTP 407): put them in HTTPS_PROXY as http://user:password@host:port" : `the network's proxy refused the connection (HTTP ${status})`);
237
188
  this.status = status;
238
189
  }
239
190
  status;
240
191
  };
241
192
  function connectVia(route, host, port) {
242
- const authority = host.includes(':')
243
- ? `[${host}]:${port}`
244
- : `${host}:${port}`;
193
+ const authority = host.includes(":") ? `[${host}]:${port}` : `${host}:${port}`;
245
194
  const req = http.request({
246
195
  host: route.host,
247
196
  port: route.port,
248
- method: 'CONNECT',
197
+ method: "CONNECT",
249
198
  path: authority,
250
199
  agent: false,
251
- headers: {
252
- Host: authority,
253
- ...(route.authorization
254
- ? { 'Proxy-Authorization': route.authorization }
255
- : {}),
256
- },
200
+ headers: { Host: authority, ...route.authorization ? { "Proxy-Authorization": route.authorization } : {} }
257
201
  });
258
202
  const socket = new Promise((resolve, reject) => {
259
- req.on('connect', (res, sock, head) => {
203
+ req.on("connect", (res, sock, head) => {
260
204
  if (res.statusCode !== 200) {
261
205
  sock.destroy();
262
206
  reject(new ProxyRefusedError(res.statusCode ?? 0));
@@ -265,27 +209,28 @@ function connectVia(route, host, port) {
265
209
  if (head.length) sock.unshift(head);
266
210
  resolve(sock);
267
211
  });
268
- req.on('response', (res) => {
212
+ req.on("response", (res) => {
269
213
  res.resume();
270
214
  reject(new ProxyRefusedError(res.statusCode ?? 0));
271
215
  });
272
- req.on('error', reject);
216
+ req.on("error", reject);
273
217
  });
274
218
  req.end();
275
219
  return { socket, abort: () => req.destroy() };
276
220
  }
277
221
 
278
222
  // src/client/ws-client.ts
279
- import { createHash as createHash2, randomBytes } from 'node:crypto';
280
- import http2 from 'node:http';
281
- import https from 'node:https';
282
- import { isIP } from 'node:net';
283
- import { Duplex } from 'node:stream';
284
- import tls from 'node:tls';
223
+ import { createHash as createHash2, randomBytes } from "node:crypto";
224
+ import http2 from "node:http";
225
+ import https from "node:https";
226
+ import { isIP } from "node:net";
227
+ import { Duplex } from "node:stream";
228
+ import tls from "node:tls";
285
229
 
286
230
  // src/client/ws-frame.ts
287
231
  var OP = { cont: 0, text: 1, binary: 2, close: 8, ping: 9, pong: 10 };
288
- var WsProtocolError = class extends Error {};
232
+ var WsProtocolError = class extends Error {
233
+ };
289
234
  function encodeFrame(opcode, payload, mask, fin = true) {
290
235
  const n = payload.length;
291
236
  const b0 = (fin ? 128 : 0) | opcode;
@@ -313,13 +258,12 @@ var FrameParser = class {
313
258
  push(chunk) {
314
259
  this.buf = this.buf.length ? Buffer.concat([this.buf, chunk]) : chunk;
315
260
  const out = [];
316
- for (;;) {
261
+ for (; ; ) {
317
262
  if (this.buf.length < 2) return out;
318
263
  const b0 = this.buf[0];
319
264
  const b1 = this.buf[1];
320
- if (b0 & 112) throw new WsProtocolError('reserved bits set');
321
- if (b1 & 128)
322
- throw new WsProtocolError('a server frame must not be masked');
265
+ if (b0 & 112) throw new WsProtocolError("reserved bits set");
266
+ if (b1 & 128) throw new WsProtocolError("a server frame must not be masked");
323
267
  const opcode = b0 & 15;
324
268
  const fin = (b0 & 128) !== 0;
325
269
  let n = b1 & 127;
@@ -331,14 +275,12 @@ var FrameParser = class {
331
275
  } else if (n === 127) {
332
276
  if (this.buf.length < 10) return out;
333
277
  const big = this.buf.readBigUInt64BE(2);
334
- if (big > BigInt(this.maxPayload))
335
- throw new WsProtocolError('frame too large');
278
+ if (big > BigInt(this.maxPayload)) throw new WsProtocolError("frame too large");
336
279
  n = Number(big);
337
280
  off = 10;
338
281
  }
339
- if (n > this.maxPayload) throw new WsProtocolError('frame too large');
340
- if (opcode >= 8 && (n > 125 || !fin))
341
- throw new WsProtocolError('bad control frame');
282
+ if (n > this.maxPayload) throw new WsProtocolError("frame too large");
283
+ if (opcode >= 8 && (n > 125 || !fin)) throw new WsProtocolError("bad control frame");
342
284
  if (this.buf.length < off + n) return out;
343
285
  out.push({ fin, opcode, payload: this.buf.subarray(off, off + n) });
344
286
  this.buf = this.buf.subarray(off + n);
@@ -349,27 +291,25 @@ var FrameParser = class {
349
291
  // src/client/ws-client.ts
350
292
  var TunnelBlockedError = class extends Error {
351
293
  constructor(status, detail) {
352
- super(
353
- detail ? `tunnel blocked: ${detail}` : `tunnel blocked (HTTP ${status})`,
354
- );
294
+ super(detail ? `tunnel blocked: ${detail}` : `tunnel blocked (HTTP ${status})`);
355
295
  this.status = status;
356
296
  }
357
297
  status;
358
298
  };
359
- var GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
299
+ var GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
360
300
  function defaultCa() {
361
301
  const get = tls.getCACertificates;
362
302
  if (!get) return void 0;
363
303
  try {
364
- return [...get('default'), ...get('system')];
304
+ return [...get("default"), ...get("system")];
365
305
  } catch {
366
306
  return void 0;
367
307
  }
368
308
  }
369
309
  function openWebSocket(url, opts) {
370
- const secure = url.protocol === 'https:';
371
- const key = randomBytes(16).toString('base64');
372
- const hostname = url.hostname.replace(/^\[|\]$/g, '');
310
+ const secure = url.protocol === "https:";
311
+ const key = randomBytes(16).toString("base64");
312
+ const hostname = url.hostname.replace(/^\[|\]$/g, "");
373
313
  const port = Number(url.port || (secure ? 443 : 80));
374
314
  return new Promise((resolve, reject) => {
375
315
  let done = false;
@@ -385,79 +325,48 @@ function openWebSocket(url, opts) {
385
325
  const timer = setTimeout(() => {
386
326
  connecting.abort?.();
387
327
  req?.destroy();
388
- settle(new Error('tunnel connect timeout'));
328
+ settle(new Error("tunnel connect timeout"));
389
329
  }, opts.timeoutMs ?? 15e3);
390
330
  timer.unref();
391
331
  const common = {
392
332
  host: hostname,
393
333
  port,
394
334
  path: url.pathname,
395
- method: 'GET',
335
+ method: "GET",
396
336
  headers: {
397
337
  Host: url.host,
398
- Connection: 'Upgrade',
399
- Upgrade: 'websocket',
400
- 'Sec-WebSocket-Version': '13',
401
- 'Sec-WebSocket-Key': key,
402
- 'Sec-WebSocket-Protocol': opts.protocol,
403
- ...(opts.userAgent ? { 'User-Agent': opts.userAgent } : {}),
404
- },
405
- };
406
- const outerTls = {
407
- ...(isIP(hostname) ? {} : { servername: hostname }),
408
- rejectUnauthorized: false,
409
- ca: opts.ca ?? defaultCa(),
338
+ Connection: "Upgrade",
339
+ Upgrade: "websocket",
340
+ "Sec-WebSocket-Version": "13",
341
+ "Sec-WebSocket-Key": key,
342
+ "Sec-WebSocket-Protocol": opts.protocol,
343
+ ...opts.userAgent ? { "User-Agent": opts.userAgent } : {}
344
+ }
410
345
  };
346
+ const outerTls = { ...isIP(hostname) ? {} : { servername: hostname }, rejectUnauthorized: false, ca: opts.ca ?? defaultCa() };
411
347
  const upgrade = (tunnelled) => {
412
348
  if (done) {
413
349
  tunnelled?.destroy();
414
350
  return;
415
351
  }
416
- const r = tunnelled
417
- ? http2.request({
418
- ...common,
419
- createConnection: () =>
420
- secure
421
- ? tls.connect({ ...outerTls, socket: tunnelled })
422
- : tunnelled,
423
- })
424
- : secure
425
- ? https.request({ ...common, ...outerTls, agent: false })
426
- : http2.request({ ...common, agent: false });
352
+ const r = tunnelled ? http2.request({ ...common, createConnection: () => secure ? tls.connect({ ...outerTls, socket: tunnelled }) : tunnelled }) : secure ? https.request({ ...common, ...outerTls, agent: false }) : http2.request({ ...common, agent: false });
427
353
  req = r;
428
- r.on('response', (res) => {
354
+ r.on("response", (res) => {
429
355
  res.resume();
430
356
  settle(new TunnelBlockedError(res.statusCode ?? 0));
431
357
  });
432
- r.on('error', (err) => settle(err));
433
- r.on('upgrade', (res, sock, head) => {
434
- const accept = createHash2('sha1')
435
- .update(key + GUID)
436
- .digest('base64');
437
- if (
438
- done ||
439
- res.headers['sec-websocket-accept'] !== accept ||
440
- res.headers['sec-websocket-protocol'] !== opts.protocol
441
- ) {
358
+ r.on("error", (err) => settle(err));
359
+ r.on("upgrade", (res, sock, head) => {
360
+ const accept = createHash2("sha1").update(key + GUID).digest("base64");
361
+ if (done || res.headers["sec-websocket-accept"] !== accept || res.headers["sec-websocket-protocol"] !== opts.protocol) {
442
362
  sock.destroy();
443
363
  settle(new TunnelBlockedError(101));
444
364
  return;
445
365
  }
446
366
  const tlsSock = sock;
447
- const outer = !secure
448
- ? 'plain'
449
- : tlsSock.authorized
450
- ? 'verified'
451
- : 'intercepted';
452
- const outerError =
453
- secure && !tlsSock.authorized && tlsSock.authorizationError
454
- ? String(tlsSock.authorizationError)
455
- : void 0;
456
- settle(null, {
457
- stream: wrap(sock, head, opts.pingMs ?? 3e4),
458
- outer,
459
- ...(outerError ? { outerError } : {}),
460
- });
367
+ const outer = !secure ? "plain" : tlsSock.authorized ? "verified" : "intercepted";
368
+ const outerError = secure && !tlsSock.authorized && tlsSock.authorizationError ? String(tlsSock.authorizationError) : void 0;
369
+ settle(null, { stream: wrap(sock, head, opts.pingMs ?? 3e4), outer, ...outerError ? { outerError } : {} });
461
370
  });
462
371
  r.end();
463
372
  };
@@ -474,13 +383,7 @@ function openWebSocket(url, opts) {
474
383
  }
475
384
  const via = connectVia(route, hostname, port);
476
385
  connecting.abort = via.abort;
477
- via.socket.then(upgrade, (err) =>
478
- settle(
479
- err instanceof ProxyRefusedError
480
- ? new TunnelBlockedError(err.status, err.message)
481
- : err,
482
- ),
483
- );
386
+ via.socket.then(upgrade, (err) => settle(err instanceof ProxyRefusedError ? new TunnelBlockedError(err.status, err.message) : err));
484
387
  });
485
388
  }
486
389
  function wrap(sock, head, pingMs) {
@@ -508,7 +411,7 @@ function wrap(sock, head, pingMs) {
508
411
  clearInterval(pinger);
509
412
  sock.destroy();
510
413
  cb(err);
511
- },
414
+ }
512
415
  });
513
416
  const failFrame = (err) => {
514
417
  setImmediate(() => duplex.destroy(err));
@@ -518,9 +421,7 @@ function wrap(sock, head, pingMs) {
518
421
  try {
519
422
  frames = parser.push(chunk);
520
423
  } catch (err) {
521
- failFrame(
522
- err instanceof WsProtocolError ? err : new WsProtocolError(String(err)),
523
- );
424
+ failFrame(err instanceof WsProtocolError ? err : new WsProtocolError(String(err)));
524
425
  return;
525
426
  }
526
427
  for (const f of frames) {
@@ -536,14 +437,14 @@ function wrap(sock, head, pingMs) {
536
437
  duplex.push(null);
537
438
  sock.end();
538
439
  } else if (f.opcode === OP.text) {
539
- failFrame(new WsProtocolError('text frame on a binary tunnel'));
440
+ failFrame(new WsProtocolError("text frame on a binary tunnel"));
540
441
  }
541
442
  }
542
443
  };
543
- sock.on('data', onData);
544
- sock.on('end', () => duplex.push(null));
545
- sock.on('error', (err) => duplex.destroy(err));
546
- sock.on('close', () => {
444
+ sock.on("data", onData);
445
+ sock.on("end", () => duplex.push(null));
446
+ sock.on("error", (err) => duplex.destroy(err));
447
+ sock.on("close", () => {
547
448
  clearInterval(pinger);
548
449
  if (!duplex.destroyed) duplex.destroy();
549
450
  });
@@ -556,7 +457,7 @@ function wrap(sock, head, pingMs) {
556
457
  // src/client/poll-client.ts
557
458
  var SessionGoneError = class extends Error {
558
459
  constructor() {
559
- super('tunnel session gone');
460
+ super("tunnel session gone");
560
461
  }
561
462
  };
562
463
  var EMPTY = Buffer.alloc(0);
@@ -566,34 +467,22 @@ var delay = (ms) => new Promise((r) => setTimeout(r, ms));
566
467
  function isBusy(r) {
567
468
  if (r.status !== 503 || r.body.length > 4096) return false;
568
469
  try {
569
- return JSON.parse(r.body.toString('utf8')).error?.type === TUNNEL_BUSY;
470
+ return JSON.parse(r.body.toString("utf8")).error?.type === TUNNEL_BUSY;
570
471
  } catch {
571
472
  return false;
572
473
  }
573
474
  }
574
475
  function settings(o) {
575
- return {
576
- timeoutMs: o.timeoutMs ?? 15e3,
577
- waitMs: o.waitMs ?? POLL_WAIT_MS,
578
- retryForMs: o.retryForMs ?? 3e4,
579
- busyForMs: o.busyForMs ?? 3e5,
580
- coalesceMs: o.coalesceMs ?? 5,
581
- };
476
+ return { timeoutMs: o.timeoutMs ?? 15e3, waitMs: o.waitMs ?? POLL_WAIT_MS, retryForMs: o.retryForMs ?? 3e4, busyForMs: o.busyForMs ?? 3e5, coalesceMs: o.coalesceMs ?? 5 };
582
477
  }
583
478
  function makeExchanger(base, o) {
584
- const secure = base.protocol === 'https:';
585
- const hostname = base.hostname.replace(/^\[|\]$/g, '');
479
+ const secure = base.protocol === "https:";
480
+ const hostname = base.hostname.replace(/^\[|\]$/g, "");
586
481
  const port = Number(base.port || (secure ? 443 : 80));
587
- const outerTls = {
588
- ...(isIP2(hostname) ? {} : { servername: hostname }),
589
- rejectUnauthorized: false,
590
- ca: o.ca ?? defaultCa(),
591
- };
482
+ const outerTls = { ...isIP2(hostname) ? {} : { servername: hostname }, rejectUnauthorized: false, ca: o.ca ?? defaultCa() };
592
483
  const route = proxyFor(base, o.env ?? process.env);
593
484
  const connectMs = o.timeoutMs ?? 15e3;
594
- const agent = secure
595
- ? new https2.Agent({ keepAlive: true, maxSockets: 2, ...outerTls })
596
- : new http3.Agent({ keepAlive: true, maxSockets: 2 });
485
+ const agent = secure ? new https2.Agent({ keepAlive: true, maxSockets: 2, ...outerTls }) : new http3.Agent({ keepAlive: true, maxSockets: 2 });
597
486
  if (route) {
598
487
  agent.createConnection = (_opts, cb) => {
599
488
  const via = connectVia(route, hostname, port);
@@ -608,80 +497,51 @@ function makeExchanger(base, o) {
608
497
  cb(err, sock);
609
498
  };
610
499
  const timer = setTimeout(() => {
611
- once(new Error('tunnel connect timeout'));
500
+ once(new Error("tunnel connect timeout"));
612
501
  via.abort();
613
502
  }, connectMs);
614
503
  via.socket.then(
615
- (sock) =>
616
- once(
617
- null,
618
- secure ? tls2.connect({ ...outerTls, socket: sock }) : sock,
619
- ),
620
- (err) =>
621
- once(
622
- err instanceof ProxyRefusedError
623
- ? new TunnelBlockedError(err.status, err.message)
624
- : err,
625
- ),
504
+ (sock) => once(null, secure ? tls2.connect({ ...outerTls, socket: sock }) : sock),
505
+ (err) => once(err instanceof ProxyRefusedError ? new TunnelBlockedError(err.status, err.message) : err)
626
506
  );
627
507
  return void 0;
628
508
  };
629
509
  }
630
- const post = (body, timeoutMs) =>
631
- new Promise((resolve, reject) => {
632
- const req = (secure ? https2 : http3).request(
633
- {
634
- host: hostname,
635
- port,
636
- path: POLL_PATH,
637
- method: 'POST',
638
- agent,
639
- ...(secure ? outerTls : {}),
640
- headers: {
641
- Host: base.host,
642
- 'Content-Type': 'application/octet-stream',
643
- 'Content-Length': String(body.length),
644
- ...(o.userAgent ? { 'User-Agent': o.userAgent } : {}),
645
- },
646
- },
647
- (res) => {
648
- const sock = res.socket;
649
- const outer = !secure
650
- ? 'plain'
651
- : sock?.authorized
652
- ? 'verified'
653
- : 'intercepted';
654
- const outerError =
655
- secure && !sock?.authorized && sock?.authorizationError
656
- ? String(sock.authorizationError)
657
- : void 0;
658
- const chunks = [];
659
- let size = 0;
660
- res.on('data', (c) => {
661
- size += c.length;
662
- if (size > MAX_ANSWER) {
663
- req.destroy(new Error('tunnel answer too large'));
664
- return;
665
- }
666
- chunks.push(c);
667
- });
668
- res.on('end', () =>
669
- resolve({
670
- status: res.statusCode ?? 0,
671
- body: Buffer.concat(chunks),
672
- outer,
673
- ...(outerError ? { outerError } : {}),
674
- }),
675
- );
676
- res.on('error', reject);
677
- },
678
- );
679
- req.setTimeout(timeoutMs, () =>
680
- req.destroy(new Error('tunnel exchange timeout')),
681
- );
682
- req.on('error', reject);
683
- req.end(body);
510
+ const post = (body, timeoutMs) => new Promise((resolve, reject) => {
511
+ const req = (secure ? https2 : http3).request({
512
+ host: hostname,
513
+ port,
514
+ path: POLL_PATH,
515
+ method: "POST",
516
+ agent,
517
+ ...secure ? outerTls : {},
518
+ headers: {
519
+ Host: base.host,
520
+ "Content-Type": "application/octet-stream",
521
+ "Content-Length": String(body.length),
522
+ ...o.userAgent ? { "User-Agent": o.userAgent } : {}
523
+ }
524
+ }, (res) => {
525
+ const sock = res.socket;
526
+ const outer = !secure ? "plain" : sock?.authorized ? "verified" : "intercepted";
527
+ const outerError = secure && !sock?.authorized && sock?.authorizationError ? String(sock.authorizationError) : void 0;
528
+ const chunks = [];
529
+ let size = 0;
530
+ res.on("data", (c) => {
531
+ size += c.length;
532
+ if (size > MAX_ANSWER) {
533
+ req.destroy(new Error("tunnel answer too large"));
534
+ return;
535
+ }
536
+ chunks.push(c);
537
+ });
538
+ res.on("end", () => resolve({ status: res.statusCode ?? 0, body: Buffer.concat(chunks), outer, ...outerError ? { outerError } : {} }));
539
+ res.on("error", reject);
684
540
  });
541
+ req.setTimeout(timeoutMs, () => req.destroy(new Error("tunnel exchange timeout")));
542
+ req.on("error", reject);
543
+ req.end(body);
544
+ });
685
545
  return { post, destroy: () => agent.destroy() };
686
546
  }
687
547
  var PollStream = class {
@@ -706,7 +566,7 @@ var PollStream = class {
706
566
  destroy: (err, cb) => {
707
567
  this.shutdown(true);
708
568
  cb(err);
709
- },
569
+ }
710
570
  });
711
571
  void this.downLoop();
712
572
  }
@@ -733,24 +593,11 @@ var PollStream = class {
733
593
  await delay(this.o.coalesceMs);
734
594
  while (!this.closed && this.pendingSize > 0) {
735
595
  const data = this.takePending();
736
- await this.exchange(
737
- {
738
- session: this.session,
739
- upOffset: this.sent,
740
- ack: this.received,
741
- close: false,
742
- poll: false,
743
- open: false,
744
- data,
745
- },
746
- this.o.timeoutMs,
747
- );
596
+ await this.exchange({ session: this.session, upOffset: this.sent, ack: this.received, close: false, poll: false, open: false, data }, this.o.timeoutMs);
748
597
  this.sent += data.length;
749
- while (this.held.length > 0 && this.pendingSize <= MAX_UP)
750
- this.held.shift()();
598
+ while (this.held.length > 0 && this.pendingSize <= MAX_UP) this.held.shift()();
751
599
  }
752
- if (this.finishing && !this.closed && this.pendingSize === 0)
753
- this.shutdown(true);
600
+ if (this.finishing && !this.closed && this.pendingSize === 0) this.shutdown(true);
754
601
  } catch (err) {
755
602
  this.fail(err);
756
603
  } finally {
@@ -769,21 +616,9 @@ var PollStream = class {
769
616
  async downLoop() {
770
617
  try {
771
618
  while (!this.closed) {
772
- const r = await this.exchange(
773
- {
774
- session: this.session,
775
- upOffset: this.sent,
776
- ack: this.received,
777
- close: false,
778
- poll: true,
779
- open: false,
780
- data: EMPTY,
781
- },
782
- this.o.waitMs + this.o.timeoutMs,
783
- );
619
+ const r = await this.exchange({ session: this.session, upOffset: this.sent, ack: this.received, close: false, poll: true, open: false, data: EMPTY }, this.o.waitMs + this.o.timeoutMs);
784
620
  if (this.closed) return;
785
- if (r.downOffset > this.received)
786
- throw new Error('tunnel stream out of order');
621
+ if (r.downOffset > this.received) throw new Error("tunnel stream out of order");
787
622
  const skip = this.received - r.downOffset;
788
623
  if (skip < r.data.length) {
789
624
  const fresh = Buffer.from(r.data.subarray(skip));
@@ -805,8 +640,8 @@ var PollStream = class {
805
640
  let firstFailure = 0;
806
641
  let firstBusy = 0;
807
642
  let wait = 250;
808
- for (;;) {
809
- if (this.closed) throw new Error('tunnel closed');
643
+ for (; ; ) {
644
+ if (this.closed) throw new Error("tunnel closed");
810
645
  let failure;
811
646
  let busy = false;
812
647
  try {
@@ -817,10 +652,8 @@ var PollStream = class {
817
652
  if (FATAL_STATUS.has(r.status)) throw failure;
818
653
  busy = isBusy(r);
819
654
  } catch (err) {
820
- if (err instanceof SessionGoneError || err instanceof PollFormatError)
821
- throw err;
822
- if (err instanceof TunnelBlockedError && FATAL_STATUS.has(err.status))
823
- throw err;
655
+ if (err instanceof SessionGoneError || err instanceof PollFormatError) throw err;
656
+ if (err instanceof TunnelBlockedError && FATAL_STATUS.has(err.status)) throw err;
824
657
  failure = err;
825
658
  }
826
659
  if (busy) {
@@ -849,19 +682,8 @@ var PollStream = class {
849
682
  if (this.closed) return;
850
683
  this.closed = true;
851
684
  if (sendClose) {
852
- const bye = encodeRequest({
853
- session: this.session,
854
- upOffset: this.sent,
855
- ack: this.received,
856
- close: true,
857
- poll: false,
858
- open: false,
859
- data: EMPTY,
860
- });
861
- this.ex
862
- .post(bye, 5e3)
863
- .catch(() => void 0)
864
- .finally(() => this.ex.destroy());
685
+ const bye = encodeRequest({ session: this.session, upOffset: this.sent, ack: this.received, close: true, poll: false, open: false, data: EMPTY });
686
+ this.ex.post(bye, 5e3).catch(() => void 0).finally(() => this.ex.destroy());
865
687
  } else {
866
688
  this.ex.destroy();
867
689
  }
@@ -871,15 +693,7 @@ var PollStream = class {
871
693
  async function openPollStream(base, opts = {}) {
872
694
  const ex = makeExchanger(base, opts);
873
695
  const session = randomBytes2(SESSION_BYTES);
874
- const open2 = encodeRequest({
875
- session,
876
- upOffset: 0,
877
- ack: 0,
878
- close: false,
879
- poll: false,
880
- open: true,
881
- data: EMPTY,
882
- });
696
+ const open2 = encodeRequest({ session, upOffset: 0, ack: 0, close: false, poll: false, open: true, data: EMPTY });
883
697
  const o = settings(opts);
884
698
  let first;
885
699
  let firstFailure = 0;
@@ -890,7 +704,7 @@ async function openPollStream(base, opts = {}) {
890
704
  } catch (err) {
891
705
  const t = Date.now();
892
706
  if (firstFailure === 0) firstFailure = t;
893
- if (err.code !== 'ECONNRESET' || t - firstFailure >= o.retryForMs) {
707
+ if (err.code !== "ECONNRESET" || t - firstFailure >= o.retryForMs) {
894
708
  ex.destroy();
895
709
  throw err;
896
710
  }
@@ -905,62 +719,35 @@ async function openPollStream(base, opts = {}) {
905
719
  let answered;
906
720
  try {
907
721
  answered = decodeResponse(first.body).session;
908
- } catch {}
722
+ } catch {
723
+ }
909
724
  if (!answered?.equals(session)) {
910
725
  ex.destroy();
911
- throw new TunnelBlockedError(
912
- 200,
913
- "the answer is not the tunnel's (a filter's page?)",
914
- );
726
+ throw new TunnelBlockedError(200, "the answer is not the tunnel's (a filter's page?)");
915
727
  }
916
728
  const stream = new PollStream(ex, session, opts).duplex;
917
- return {
918
- stream,
919
- outer: first.outer,
920
- ...(first.outerError ? { outerError: first.outerError } : {}),
921
- };
729
+ return { stream, outer: first.outer, ...first.outerError ? { outerError: first.outerError } : {} };
922
730
  }
923
731
 
924
732
  // src/client/inner.ts
925
733
  var IdentityMismatchError = class extends Error {
926
734
  constructor(received) {
927
- super('tunnel identity mismatch');
735
+ super("tunnel identity mismatch");
928
736
  this.received = received;
929
737
  }
930
738
  received;
931
739
  };
932
740
  async function connectInner(base, pins, opts = {}) {
933
- const outerOpts = {
934
- timeoutMs: opts.timeoutMs,
935
- ca: opts.ca,
936
- userAgent: opts.userAgent,
937
- env: opts.env,
938
- };
939
- const ws =
940
- opts.transport === 'post'
941
- ? await openPollStream(base, outerOpts)
942
- : await openWebSocket(new URL(TUNNEL_PATH, base), {
943
- protocol: TUNNEL_PROTOCOL,
944
- ...outerOpts,
945
- });
946
- opts.onOuter?.({
947
- outer: ws.outer,
948
- ...(ws.outerError ? { outerError: ws.outerError } : {}),
949
- });
741
+ const outerOpts = { timeoutMs: opts.timeoutMs, ca: opts.ca, userAgent: opts.userAgent, env: opts.env };
742
+ const ws = opts.transport === "post" ? await openPollStream(base, outerOpts) : await openWebSocket(new URL(TUNNEL_PATH, base), { protocol: TUNNEL_PROTOCOL, ...outerOpts });
743
+ opts.onOuter?.({ outer: ws.outer, ...ws.outerError ? { outerError: ws.outerError } : {} });
950
744
  const preferred = pins.at(-1);
951
- const servername =
952
- preferred && isPin(preferred) ? sniOfPin(preferred) : TUNNEL_SERVERNAME;
953
- const socket = tls3.connect({
954
- socket: ws.stream,
955
- servername,
956
- minVersion: 'TLSv1.3',
957
- rejectUnauthorized: false,
958
- ALPNProtocols: ['http/1.1'],
959
- });
960
- ws.stream.on('close', () => socket.destroy());
961
- ws.stream.on('end', () => socket.destroy());
962
- ws.stream.on('error', () => socket.destroy());
963
- socket.on('close', () => ws.stream.destroy());
745
+ const servername = preferred && isPin(preferred) ? sniOfPin(preferred) : TUNNEL_SERVERNAME;
746
+ const socket = tls3.connect({ socket: ws.stream, servername, minVersion: "TLSv1.3", rejectUnauthorized: false, ALPNProtocols: ["http/1.1"] });
747
+ ws.stream.on("close", () => socket.destroy());
748
+ ws.stream.on("end", () => socket.destroy());
749
+ ws.stream.on("error", () => socket.destroy());
750
+ socket.on("close", () => ws.stream.destroy());
964
751
  try {
965
752
  await new Promise((resolve, reject) => {
966
753
  let settled = false;
@@ -968,37 +755,32 @@ async function connectInner(base, pins, opts = {}) {
968
755
  if (settled) return;
969
756
  settled = true;
970
757
  clearTimeout(timer);
971
- socket.off('close', onClose);
972
- socket.off('secureConnect', onSecure);
758
+ socket.off("close", onClose);
759
+ socket.off("secureConnect", onSecure);
973
760
  if (err === null) {
974
- socket.off('error', onError);
761
+ socket.off("error", onError);
975
762
  resolve();
976
763
  return;
977
764
  }
978
- socket.once('close', () => socket.off('error', onError));
765
+ socket.once("close", () => socket.off("error", onError));
979
766
  reject(err);
980
767
  };
981
768
  const onError = (err) => finish(err);
982
- const onClose = () => finish(new Error('tunnel closed during handshake'));
769
+ const onClose = () => finish(new Error("tunnel closed during handshake"));
983
770
  const onSecure = () => finish(null);
984
- const timer = setTimeout(
985
- () => finish(new Error('tunnel handshake timeout')),
986
- opts.timeoutMs ?? 15e3,
987
- );
771
+ const timer = setTimeout(() => finish(new Error("tunnel handshake timeout")), opts.timeoutMs ?? 15e3);
988
772
  timer.unref();
989
- socket.on('error', onError);
990
- socket.on('close', onClose);
991
- socket.on('secureConnect', onSecure);
773
+ socket.on("error", onError);
774
+ socket.on("close", onClose);
775
+ socket.on("secureConnect", onSecure);
992
776
  });
993
777
  } catch (err) {
994
778
  socket.destroy();
995
779
  throw err;
996
780
  }
997
- socket.on('error', () => socket.destroy());
781
+ socket.on("error", () => socket.destroy());
998
782
  const peer = peerCertificate(socket);
999
- const received = peer
1000
- ? pinOfSpki(peer.publicKey.export({ type: 'spki', format: 'der' }))
1001
- : 'none';
783
+ const received = peer ? pinOfSpki(peer.publicKey.export({ type: "spki", format: "der" })) : "none";
1002
784
  if (!pins.includes(received)) {
1003
785
  socket.destroy();
1004
786
  throw new IdentityMismatchError(received);
@@ -1007,36 +789,24 @@ async function connectInner(base, pins, opts = {}) {
1007
789
  }
1008
790
 
1009
791
  // src/client/local-server.ts
1010
- import {
1011
- createHash as createHash3,
1012
- randomBytes as randomBytes3,
1013
- timingSafeEqual,
1014
- } from 'node:crypto';
1015
- import http5 from 'node:http';
792
+ import { createHash as createHash3, randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
793
+ import http5 from "node:http";
1016
794
 
1017
795
  // src/client/tunnel-agent.ts
1018
- import http4 from 'node:http';
796
+ import http4 from "node:http";
1019
797
  var TUNNEL_AGENT_MAX_SOCKETS = 4;
1020
798
  function canSwitch(err) {
1021
- if (err instanceof IdentityMismatchError || err instanceof BackoffError)
1022
- return false;
1023
- if (
1024
- err instanceof TunnelBlockedError &&
1025
- (err.status === 429 || err.status === 503)
1026
- )
1027
- return false;
799
+ if (err instanceof IdentityMismatchError || err instanceof BackoffError) return false;
800
+ if (err instanceof TunnelBlockedError && (err.status === 429 || err.status === 503)) return false;
1028
801
  return true;
1029
802
  }
1030
803
  function reasonOf(err) {
1031
- if (err instanceof TunnelBlockedError)
1032
- return err.status === 101 || err.status === 200
1033
- ? err.message
1034
- : `HTTP ${err.status}`;
804
+ if (err instanceof TunnelBlockedError) return err.status === 101 || err.status === 200 ? err.message : `HTTP ${err.status}`;
1035
805
  return err instanceof Error ? err.message : String(err);
1036
806
  }
1037
807
  var BackoffError = class extends Error {
1038
808
  constructor(waitMs) {
1039
- super('tunnel identity mismatch - waiting before retry');
809
+ super("tunnel identity mismatch - waiting before retry");
1040
810
  this.waitMs = waitMs;
1041
811
  }
1042
812
  waitMs;
@@ -1044,19 +814,16 @@ var BackoffError = class extends Error {
1044
814
  var baseAddRequest = http4.Agent.prototype.addRequest;
1045
815
  var TunnelAgent = class extends http4.Agent {
1046
816
  constructor(target, backoff, events = {}) {
1047
- super({
1048
- keepAlive: true,
1049
- maxSockets: TUNNEL_AGENT_MAX_SOCKETS,
1050
- maxFreeSockets: TUNNEL_AGENT_MAX_SOCKETS,
1051
- });
817
+ super({ keepAlive: true, maxSockets: TUNNEL_AGENT_MAX_SOCKETS, maxFreeSockets: TUNNEL_AGENT_MAX_SOCKETS });
1052
818
  this.target = target;
1053
819
  this.backoff = backoff;
1054
820
  this.events = events;
1055
- this.mode = target.transport ?? 'auto';
1056
- this.using = this.mode === 'post' ? 'post' : 'ws';
821
+ this.mode = target.transport ?? "auto";
822
+ this.using = this.mode === "post" ? "post" : "ws";
1057
823
  this.connect = target.connect ?? connectInner;
1058
824
  this.pins = [...target.pins];
1059
- this.on('free', () => this.drain());
825
+ this.targets = [target.url, ...target.urls ?? []];
826
+ this.on("free", () => this.drain());
1060
827
  }
1061
828
  target;
1062
829
  backoff;
@@ -1069,6 +836,9 @@ var TunnelAgent = class extends http4.Agent {
1069
836
  mode;
1070
837
  connect;
1071
838
  pins;
839
+ /** Every host the code names, first one first; `preferred` indexes it. */
840
+ targets;
841
+ preferred = 0;
1072
842
  /** Destroyed: no tunnel is opened any more, and one still opening is closed when it arrives. */
1073
843
  closed = false;
1074
844
  /**
@@ -1089,9 +859,7 @@ var TunnelAgent = class extends http4.Agent {
1089
859
  return n;
1090
860
  }
1091
861
  hasFree() {
1092
- return Object.values(this.freeSockets).some((list) =>
1093
- list?.some((s) => !s.destroyed),
1094
- );
862
+ return Object.values(this.freeSockets).some((list) => list?.some((s) => !s.destroyed));
1095
863
  }
1096
864
  canServe() {
1097
865
  return this.hasFree() || this.live() < TUNNEL_AGENT_MAX_SOCKETS;
@@ -1100,7 +868,7 @@ var TunnelAgent = class extends http4.Agent {
1100
868
  addRequest(req, options) {
1101
869
  if (!this.canServe()) {
1102
870
  this.waiting.push({ req, options });
1103
- req.once('close', () => {
871
+ req.once("close", () => {
1104
872
  const i = this.waiting.findIndex((w) => w.req === req);
1105
873
  if (i >= 0) this.waiting.splice(i, 1);
1106
874
  });
@@ -1122,9 +890,9 @@ var TunnelAgent = class extends http4.Agent {
1122
890
  destroy() {
1123
891
  this.closed = true;
1124
892
  for (const { req } of this.waiting.splice(0)) {
1125
- const err = new Error('tunnel agent closed');
893
+ const err = new Error("tunnel agent closed");
1126
894
  req.destroy(err);
1127
- process.nextTick(() => req.emit('error', err));
895
+ process.nextTick(() => req.emit("error", err));
1128
896
  }
1129
897
  super.destroy();
1130
898
  }
@@ -1133,7 +901,7 @@ var TunnelAgent = class extends http4.Agent {
1133
901
  createConnection(_options, callback) {
1134
902
  const done = callback ?? (() => void 0);
1135
903
  if (this.closed) {
1136
- done(new Error('tunnel agent closed'), void 0);
904
+ done(new Error("tunnel agent closed"), void 0);
1137
905
  return void 0;
1138
906
  }
1139
907
  const wait = this.backoff.blockedMs();
@@ -1142,143 +910,109 @@ var TunnelAgent = class extends http4.Agent {
1142
910
  return void 0;
1143
911
  }
1144
912
  this.opening += 1;
1145
- const attempt = (t) =>
1146
- this.connect(this.target.url, this.pins, {
1147
- ca: this.target.ca,
1148
- userAgent: this.target.userAgent,
1149
- env: this.target.env,
1150
- transport: t,
1151
- onOuter: (i) => this.events.onOuter?.(i),
1152
- });
1153
- const first = this.using;
1154
- attempt(first)
1155
- .catch((err) => {
1156
- if (this.mode !== 'auto' || first !== 'ws' || !canSwitch(err))
1157
- throw err;
1158
- return attempt('post').then(
1159
- (socket) => {
1160
- if (this.using !== 'post') {
1161
- this.using = 'post';
1162
- this.events.onTransport?.(
1163
- 'post',
1164
- `websocket blocked: ${reasonOf(err)}`,
1165
- );
1166
- }
1167
- return socket;
1168
- },
1169
- (postErr) => {
1170
- throw postErr instanceof IdentityMismatchError ? postErr : err;
1171
- },
1172
- );
1173
- })
1174
- .then(
913
+ const dial = (host, transport) => this.connect(this.targets[host], this.pins, { ca: this.target.ca, userAgent: this.target.userAgent, env: this.target.env, transport, onOuter: (i) => this.events.onOuter?.(i) });
914
+ const hosts = this.targets.map((_, i) => (this.preferred + i) % this.targets.length);
915
+ const transports = this.mode === "auto" ? this.using === "ws" ? ["ws", "post"] : ["post"] : [this.using === "post" ? "post" : "ws"];
916
+ const chain = transports.flatMap((transport) => hosts.map((host) => ({ host, transport })));
917
+ let firstErr = null;
918
+ const run = (i) => {
919
+ const at = chain[i];
920
+ return dial(at.host, at.transport).then(
1175
921
  (socket) => {
1176
- this.opening -= 1;
1177
- if (this.closed) {
1178
- socket.destroy();
1179
- done(new Error('tunnel agent closed'), void 0);
1180
- return;
922
+ if (this.preferred !== at.host) this.preferred = at.host;
923
+ if (this.mode === "auto" && this.using !== "post" && at.transport === "post") {
924
+ this.using = "post";
925
+ this.events.onTransport?.("post", firstErr === null ? null : `websocket blocked: ${reasonOf(firstErr)}`);
1181
926
  }
1182
- this.backoff.success();
1183
- this.events.onConnected?.();
1184
- socket.once('close', () => process.nextTick(() => this.drain()));
1185
- done(null, socket);
927
+ return socket;
1186
928
  },
1187
929
  (err) => {
1188
- this.opening -= 1;
1189
- if (err instanceof IdentityMismatchError) {
1190
- this.backoff.failure();
1191
- this.events.onMismatch?.(err.received);
1192
- }
1193
- done(err, void 0);
1194
- this.drain();
1195
- },
930
+ if (!(err instanceof Error)) throw err;
931
+ if (firstErr === null) firstErr = err;
932
+ if (i + 1 < chain.length && canSwitch(err)) return run(i + 1);
933
+ throw err instanceof IdentityMismatchError ? err : firstErr;
934
+ }
1196
935
  );
936
+ };
937
+ run(0).then(
938
+ (socket) => {
939
+ this.opening -= 1;
940
+ if (this.closed) {
941
+ socket.destroy();
942
+ done(new Error("tunnel agent closed"), void 0);
943
+ return;
944
+ }
945
+ this.backoff.success();
946
+ this.events.onConnected?.();
947
+ socket.once("close", () => process.nextTick(() => this.drain()));
948
+ done(null, socket);
949
+ },
950
+ (err) => {
951
+ this.opening -= 1;
952
+ if (err instanceof IdentityMismatchError) {
953
+ this.backoff.failure();
954
+ this.events.onMismatch?.(err.received);
955
+ }
956
+ done(err, void 0);
957
+ this.drain();
958
+ }
959
+ );
1197
960
  return void 0;
1198
961
  }
1199
962
  };
1200
963
 
1201
964
  // src/client/local-server.ts
1202
965
  function newLocalKey() {
1203
- return `o1gwl_${randomBytes3(32).toString('base64url')}`;
966
+ return `o1gwl_${randomBytes3(32).toString("base64url")}`;
1204
967
  }
1205
968
  function hashLocalKey(key) {
1206
- return createHash3('sha256').update(key, 'utf8').digest('hex');
969
+ return createHash3("sha256").update(key, "utf8").digest("hex");
1207
970
  }
1208
- var HOP = /* @__PURE__ */ new Set([
1209
- 'connection',
1210
- 'keep-alive',
1211
- 'proxy-authorization',
1212
- 'proxy-connection',
1213
- 'te',
1214
- 'trailer',
1215
- 'transfer-encoding',
1216
- 'upgrade',
1217
- 'host',
1218
- 'authorization',
1219
- 'x-api-key',
1220
- ]);
1221
- var LOOPBACK2 = /* @__PURE__ */ new Set(['127.0.0.1', 'localhost', '[::1]']);
971
+ var HOP = /* @__PURE__ */ new Set(["connection", "keep-alive", "proxy-authorization", "proxy-connection", "te", "trailer", "transfer-encoding", "upgrade", "host", "authorization", "x-api-key"]);
972
+ var LOOPBACK2 = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
1222
973
  function send(res, status, message) {
1223
- const body = JSON.stringify({
1224
- type: 'error',
1225
- error: { type: 'tunnel_error', message },
1226
- });
1227
- res
1228
- .writeHead(status, {
1229
- 'content-type': 'application/json',
1230
- 'content-length': Buffer.byteLength(body),
1231
- })
1232
- .end(body);
974
+ const body = JSON.stringify({ type: "error", error: { type: "tunnel_error", message } });
975
+ res.writeHead(status, { "content-type": "application/json", "content-length": Buffer.byteLength(body) }).end(body);
1233
976
  }
1234
977
  function keyOf(req) {
1235
- const bearer = /^Bearer\s+(.+)$/i.exec(
1236
- String(req.headers.authorization ?? '').trim(),
1237
- );
978
+ const bearer = /^Bearer\s+(.+)$/i.exec(String(req.headers.authorization ?? "").trim());
1238
979
  if (bearer) return bearer[1].trim();
1239
- const k = req.headers['x-api-key'];
1240
- return typeof k === 'string' && k.trim() ? k.trim() : void 0;
980
+ const k = req.headers["x-api-key"];
981
+ return typeof k === "string" && k.trim() ? k.trim() : void 0;
1241
982
  }
1242
983
  function sameHash(a, b) {
1243
- const x = Buffer.from(a, 'hex');
1244
- const y = Buffer.from(b, 'hex');
984
+ const x = Buffer.from(a, "hex");
985
+ const y = Buffer.from(b, "hex");
1245
986
  return x.length === y.length && x.length > 0 && timingSafeEqual(x, y);
1246
987
  }
1247
988
  var REPLAY_MAX_BYTES = 10 * 1024 * 1024;
1248
989
  function deadTunnel(err, reusedSocket) {
1249
990
  if (err instanceof SessionGoneError) return true;
1250
991
  const code = err?.code;
1251
- return reusedSocket && (code === 'ECONNRESET' || code === 'EPIPE');
992
+ return reusedSocket && (code === "ECONNRESET" || code === "EPIPE");
1252
993
  }
1253
994
  function describeError(err) {
1254
- if (err instanceof BackoffError)
1255
- return `tunnel identity mismatch - waiting before retry (${Math.ceil(err.waitMs / 6e4)} min)`;
1256
- if (err instanceof IdentityMismatchError) return 'tunnel identity mismatch';
995
+ if (err instanceof BackoffError) return `tunnel identity mismatch - waiting before retry (${Math.ceil(err.waitMs / 6e4)} min)`;
996
+ if (err instanceof IdentityMismatchError) return "tunnel identity mismatch";
1257
997
  if (err instanceof TunnelBlockedError) return err.message;
1258
- return 'tunnel unavailable';
998
+ return "tunnel unavailable";
1259
999
  }
1260
1000
  function startLocalServer(o) {
1261
1001
  const server = http5.createServer((req, res) => {
1262
1002
  const started = Date.now();
1263
- const route = (req.url ?? '/').split('?')[0].slice(0, 200);
1264
- const hostname = String(req.headers.host ?? '')
1265
- .toLowerCase()
1266
- .replace(/:\d+$/, '');
1267
- if (!LOOPBACK2.has(hostname))
1268
- return send(res, 403, 'this endpoint answers on 127.0.0.1 only');
1269
- if (req.headers.origin !== void 0)
1270
- return send(res, 403, 'browser requests are not accepted');
1003
+ const route = (req.url ?? "/").split("?")[0].slice(0, 200);
1004
+ const hostname = String(req.headers.host ?? "").toLowerCase().replace(/:\d+$/, "");
1005
+ if (!LOOPBACK2.has(hostname)) return send(res, 403, "this endpoint answers on 127.0.0.1 only");
1006
+ if (req.headers.origin !== void 0) return send(res, 403, "browser requests are not accepted");
1271
1007
  const key = keyOf(req);
1272
- if (!key || !sameHash(hashLocalKey(key), o.localKeyHash))
1273
- return send(res, 401, 'invalid or missing local key');
1008
+ if (!key || !sameHash(hashLocalKey(key), o.localKeyHash)) return send(res, 401, "invalid or missing local key");
1274
1009
  const headers = {};
1275
- for (const [name, value] of Object.entries(req.headers))
1276
- if (!HOP.has(name) && value !== void 0) headers[name] = value;
1010
+ for (const [name, value] of Object.entries(req.headers)) if (!HOP.has(name) && value !== void 0) headers[name] = value;
1277
1011
  headers.host = o.target.host;
1278
1012
  headers.authorization = `Bearer ${o.deviceToken}`;
1279
1013
  let kept = [];
1280
1014
  let keptBytes = 0;
1281
- req.on('data', (c) => {
1015
+ req.on("data", (c) => {
1282
1016
  if (!kept) return;
1283
1017
  keptBytes += c.length;
1284
1018
  if (keptBytes > REPLAY_MAX_BYTES) kept = null;
@@ -1286,33 +1020,18 @@ function startLocalServer(o) {
1286
1020
  });
1287
1021
  let upstream;
1288
1022
  const forward = (replay) => {
1289
- const via = replay
1290
- ? { createConnection: (opts, cb) => o.agent.createConnection(opts, cb) }
1291
- : { agent: o.agent };
1292
- const current = http5.request(
1293
- { ...via, method: req.method, path: req.url, headers, setHost: false },
1294
- (up) => {
1295
- const out = {};
1296
- for (const [name, value] of Object.entries(up.headers))
1297
- if (!HOP.has(name) && value !== void 0) out[name] = value;
1298
- res.writeHead(up.statusCode ?? 502, out);
1299
- up.pipe(res);
1300
- up.on('error', () => res.destroy());
1301
- up.on('end', () =>
1302
- o.log?.(
1303
- `${req.method} ${route} status=${up.statusCode} total=${Date.now() - started}ms`,
1304
- ),
1305
- );
1306
- },
1307
- );
1023
+ const via = replay ? { createConnection: (opts, cb) => o.agent.createConnection(opts, cb) } : { agent: o.agent };
1024
+ const current = http5.request({ ...via, method: req.method, path: req.url, headers, setHost: false }, (up) => {
1025
+ const out = {};
1026
+ for (const [name, value] of Object.entries(up.headers)) if (!HOP.has(name) && value !== void 0) out[name] = value;
1027
+ res.writeHead(up.statusCode ?? 502, out);
1028
+ up.pipe(res);
1029
+ up.on("error", () => res.destroy());
1030
+ up.on("end", () => o.log?.(`${req.method} ${route} status=${up.statusCode} total=${Date.now() - started}ms`));
1031
+ });
1308
1032
  upstream = current;
1309
- current.on('error', (err) => {
1310
- if (
1311
- !replay &&
1312
- !res.headersSent &&
1313
- kept &&
1314
- deadTunnel(err, current.reusedSocket)
1315
- ) {
1033
+ current.on("error", (err) => {
1034
+ if (!replay && !res.headersSent && kept && deadTunnel(err, current.reusedSocket)) {
1316
1035
  o.log?.(`${req.method} ${route} retry: the tunnel was gone`);
1317
1036
  const again = () => {
1318
1037
  if (kept && !res.destroyed) forward(true);
@@ -1320,30 +1039,29 @@ function startLocalServer(o) {
1320
1039
  };
1321
1040
  if (req.readableEnded) again();
1322
1041
  else {
1323
- req.once('end', again);
1042
+ req.once("end", again);
1324
1043
  req.resume();
1325
1044
  }
1326
1045
  return;
1327
1046
  }
1328
1047
  o.log?.(`${req.method} ${route} failed: ${describeError(err)}`);
1329
1048
  if (res.headersSent) res.destroy();
1330
- else if (err instanceof TunnelBlockedError && err.status === 429)
1331
- send(res, 429, 'Too many attempts');
1049
+ else if (err instanceof TunnelBlockedError && err.status === 429) send(res, 429, "Too many attempts");
1332
1050
  else send(res, 502, describeError(err));
1333
1051
  });
1334
1052
  if (replay) current.end(Buffer.concat(kept ?? []));
1335
1053
  else req.pipe(current);
1336
1054
  };
1337
1055
  forward(false);
1338
- res.on('close', () => {
1056
+ res.on("close", () => {
1339
1057
  if (!res.writableFinished) upstream.destroy();
1340
1058
  });
1341
- req.on('error', () => upstream.destroy());
1059
+ req.on("error", () => upstream.destroy());
1342
1060
  });
1343
1061
  return new Promise((resolve, reject) => {
1344
- server.once('error', reject);
1345
- server.listen(o.port, '127.0.0.1', () => {
1346
- server.off('error', reject);
1062
+ server.once("error", reject);
1063
+ server.listen(o.port, "127.0.0.1", () => {
1064
+ server.off("error", reject);
1347
1065
  resolve(server);
1348
1066
  });
1349
1067
  });
@@ -1380,27 +1098,17 @@ var IdentityBackoff = class {
1380
1098
  this.since = null;
1381
1099
  }
1382
1100
  snapshot() {
1383
- return {
1384
- mismatches: this.count,
1385
- since: this.since,
1386
- waitMs: this.blockedMs(),
1387
- };
1101
+ return { mismatches: this.count, since: this.since, waitMs: this.blockedMs() };
1388
1102
  }
1389
1103
  };
1390
1104
 
1391
1105
  // src/client/pin-sync.ts
1392
- import http6 from 'node:http';
1393
- import tls4 from 'node:tls';
1106
+ import http6 from "node:http";
1107
+ import tls4 from "node:tls";
1394
1108
  function mergePins(own, listed, via) {
1395
1109
  const unchanged = { pins: [...own], added: [], dropped: [] };
1396
1110
  if (via === null || !own.includes(via)) return unchanged;
1397
- if (
1398
- !Array.isArray(listed) ||
1399
- listed.length === 0 ||
1400
- listed.length > MAX_PINS ||
1401
- !listed.every((p) => typeof p === 'string' && isPin(p))
1402
- )
1403
- return unchanged;
1111
+ if (!Array.isArray(listed) || listed.length === 0 || listed.length > MAX_PINS || !listed.every((p) => typeof p === "string" && isPin(p))) return unchanged;
1404
1112
  const list = [...new Set(listed)];
1405
1113
  const added = list.filter((p) => !own.includes(p));
1406
1114
  if (list.includes(via)) {
@@ -1413,9 +1121,7 @@ function mergePins(own, listed, via) {
1413
1121
  function pinOfSocket(socket) {
1414
1122
  if (!(socket instanceof tls4.TLSSocket)) return null;
1415
1123
  const peer = peerCertificate(socket);
1416
- return peer
1417
- ? pinOfSpki(peer.publicKey.export({ type: 'spki', format: 'der' }))
1418
- : null;
1124
+ return peer ? pinOfSpki(peer.publicKey.export({ type: "spki", format: "der" })) : null;
1419
1125
  }
1420
1126
  var MAX_BODY = 16 * 1024;
1421
1127
  var short = (pin) => fingerprint(pin).slice(0, 19);
@@ -1447,44 +1153,28 @@ var PinSync = class {
1447
1153
  const now = (this.o.now ?? Date.now)();
1448
1154
  if (this.running || now - this.last < (this.o.intervalMs ?? 36e5)) return;
1449
1155
  this.last = now;
1450
- this.syncNow().catch((err) =>
1451
- this.o.log?.(
1452
- `pin check failed: ${err instanceof Error ? err.message : String(err)}`,
1453
- ),
1454
- );
1156
+ this.syncNow().catch((err) => this.o.log?.(`pin check failed: ${err instanceof Error ? err.message : String(err)}`));
1455
1157
  }
1456
1158
  async run() {
1457
1159
  this.last = (this.o.now ?? Date.now)();
1458
1160
  const { listed, via } = await this.fetch();
1459
1161
  const merged = mergePins(this.current, listed, via);
1460
- const changed =
1461
- merged.pins.length !== this.current.length ||
1462
- merged.pins.some((p, i) => p !== this.current[i]);
1162
+ const changed = merged.pins.length !== this.current.length || merged.pins.some((p, i) => p !== this.current[i]);
1463
1163
  if (changed) {
1464
1164
  this.current = merged.pins;
1465
1165
  this.o.onChange?.(this.pins);
1466
- this.o.log?.(
1467
- `proxy keys updated through the pinned tunnel: ${merged.added
1468
- .map((p) => `+${short(p)}`)
1469
- .concat(merged.dropped.map((p) => `-${short(p)}`))
1470
- .join(' ')}`,
1471
- );
1166
+ this.o.log?.(`proxy keys updated through the pinned tunnel: ${merged.added.map((p) => `+${short(p)}`).concat(merged.dropped.map((p) => `-${short(p)}`)).join(" ")}`);
1472
1167
  }
1473
1168
  if ((changed || this.unsaved) && !this.saveStopped) {
1474
1169
  try {
1475
- if ((await this.o.save(this.pins)) === false) {
1170
+ if (await this.o.save(this.pins) === false) {
1476
1171
  this.saveStopped = true;
1477
- this.o.log?.(
1478
- this.o.stoppedLine ??
1479
- 'config.bin now holds another configuration (setup ran since): the proxy keys learned by this run are no longer saved',
1480
- );
1172
+ this.o.log?.(this.o.stoppedLine ?? "config.bin now holds another configuration (setup ran since): the proxy keys learned by this run are no longer saved");
1481
1173
  }
1482
1174
  this.unsaved = false;
1483
1175
  } catch (err) {
1484
1176
  this.unsaved = true;
1485
- this.o.log?.(
1486
- `could not save the proxy keys (tried again at the next check): ${err instanceof Error ? err.message : String(err)}`,
1487
- );
1177
+ this.o.log?.(`could not save the proxy keys (tried again at the next check): ${err instanceof Error ? err.message : String(err)}`);
1488
1178
  }
1489
1179
  }
1490
1180
  return { ...merged, via };
@@ -1492,52 +1182,35 @@ var PinSync = class {
1492
1182
  fetch() {
1493
1183
  const { target } = this.o;
1494
1184
  return new Promise((resolve, reject) => {
1495
- const req = http6.request(
1496
- {
1497
- host: target.hostname,
1498
- port: target.port,
1499
- method: 'GET',
1500
- path: TUNNEL_PINS_PATH,
1501
- agent: this.o.agent,
1502
- setHost: false,
1503
- headers: {
1504
- host: target.host,
1505
- authorization: `Bearer ${this.o.deviceToken}`,
1506
- accept: 'application/json',
1507
- },
1508
- },
1509
- (res) => {
1510
- const via = pinOfSocket(res.socket);
1511
- const chunks = [];
1512
- let size = 0;
1513
- res.on('data', (c) => {
1514
- size += c.length;
1515
- if (size > MAX_BODY) req.destroy(new Error('pin list too large'));
1516
- else chunks.push(c);
1517
- });
1518
- res.on('error', reject);
1519
- res.on('end', () => {
1520
- if (res.statusCode !== 200)
1521
- return reject(
1522
- new Error(
1523
- `the proxy answered ${res.statusCode ?? 0} for its pins`,
1524
- ),
1525
- );
1526
- try {
1527
- resolve({
1528
- listed: JSON.parse(Buffer.concat(chunks).toString('utf8')).pins,
1529
- via,
1530
- });
1531
- } catch {
1532
- reject(new Error("the proxy's pin list is not JSON"));
1533
- }
1534
- });
1535
- },
1536
- );
1537
- req.setTimeout(this.o.timeoutMs ?? 3e4, () =>
1538
- req.destroy(new Error('pin check timeout')),
1539
- );
1540
- req.on('error', reject);
1185
+ const req = http6.request({
1186
+ host: target.hostname,
1187
+ port: target.port,
1188
+ method: "GET",
1189
+ path: TUNNEL_PINS_PATH,
1190
+ agent: this.o.agent,
1191
+ setHost: false,
1192
+ headers: { host: target.host, authorization: `Bearer ${this.o.deviceToken}`, accept: "application/json" }
1193
+ }, (res) => {
1194
+ const via = pinOfSocket(res.socket);
1195
+ const chunks = [];
1196
+ let size = 0;
1197
+ res.on("data", (c) => {
1198
+ size += c.length;
1199
+ if (size > MAX_BODY) req.destroy(new Error("pin list too large"));
1200
+ else chunks.push(c);
1201
+ });
1202
+ res.on("error", reject);
1203
+ res.on("end", () => {
1204
+ if (res.statusCode !== 200) return reject(new Error(`the proxy answered ${res.statusCode ?? 0} for its pins`));
1205
+ try {
1206
+ resolve({ listed: JSON.parse(Buffer.concat(chunks).toString("utf8")).pins, via });
1207
+ } catch {
1208
+ reject(new Error("the proxy's pin list is not JSON"));
1209
+ }
1210
+ });
1211
+ });
1212
+ req.setTimeout(this.o.timeoutMs ?? 3e4, () => req.destroy(new Error("pin check timeout")));
1213
+ req.on("error", reject);
1541
1214
  req.end();
1542
1215
  });
1543
1216
  }
@@ -1546,27 +1219,19 @@ var PinSync = class {
1546
1219
  // src/client/session.ts
1547
1220
  async function startTunnelSession(o) {
1548
1221
  const target = new URL(o.url);
1222
+ const failover = (o.urls ?? []).map((u) => new URL(u));
1549
1223
  const backoff = o.backoff ?? new IdentityBackoff();
1550
- const agent = new TunnelAgent(
1551
- {
1552
- url: target,
1553
- pins: o.pins,
1554
- userAgent: o.userAgent,
1555
- transport: o.transport,
1556
- },
1557
- backoff,
1558
- {
1559
- onOuter: o.onOuter,
1560
- onConnected: () => {
1561
- setImmediate(() => {
1562
- if (!agent.destroyed) pinSync.maybeSync();
1563
- });
1564
- o.onConnected?.();
1565
- },
1566
- onMismatch: o.onMismatch,
1567
- onTransport: o.onTransport,
1224
+ const agent = new TunnelAgent({ url: target, urls: failover, pins: o.pins, userAgent: o.userAgent, transport: o.transport }, backoff, {
1225
+ onOuter: o.onOuter,
1226
+ onConnected: () => {
1227
+ setImmediate(() => {
1228
+ if (!agent.destroyed) pinSync.maybeSync();
1229
+ });
1230
+ o.onConnected?.();
1568
1231
  },
1569
- );
1232
+ onMismatch: o.onMismatch,
1233
+ onTransport: o.onTransport
1234
+ });
1570
1235
  const pinSync = new PinSync({
1571
1236
  agent,
1572
1237
  target,
@@ -1575,18 +1240,11 @@ async function startTunnelSession(o) {
1575
1240
  log: o.log,
1576
1241
  onChange: (pins) => agent.setPins(pins),
1577
1242
  save: o.savePins,
1578
- stoppedLine: o.savePinsStoppedLine,
1243
+ stoppedLine: o.savePinsStoppedLine
1579
1244
  });
1580
1245
  let server;
1581
1246
  try {
1582
- server = await startLocalServer({
1583
- port: o.port,
1584
- localKeyHash: o.localKeyHash,
1585
- deviceToken: o.deviceToken,
1586
- target,
1587
- agent,
1588
- log: o.log,
1589
- });
1247
+ server = await startLocalServer({ port: o.port, localKeyHash: o.localKeyHash, deviceToken: o.deviceToken, target, agent, log: o.log });
1590
1248
  } catch (err) {
1591
1249
  agent.destroy();
1592
1250
  throw err;
@@ -1605,7 +1263,7 @@ async function startTunnelSession(o) {
1605
1263
  }
1606
1264
 
1607
1265
  // src/client/version.ts
1608
- var VERSION = true ? '9.0.0' : 'dev';
1266
+ var VERSION = true ? "9.4.0" : "dev";
1609
1267
 
1610
1268
  // src/client/lib.ts
1611
1269
  var version = VERSION;
@@ -1613,27 +1271,21 @@ var O1ConnectError = class extends Error {
1613
1271
  code;
1614
1272
  constructor(code, message, options) {
1615
1273
  super(message, options);
1616
- this.name = 'O1ConnectError';
1274
+ this.name = "O1ConnectError";
1617
1275
  this.code = code;
1618
1276
  }
1619
1277
  };
1620
- var DEFAULT_NAME = 'aipp-connect';
1621
- var TRANSPORTS = ['auto', 'websocket', 'post'];
1278
+ var DEFAULT_NAME = "aipp-connect";
1279
+ var TRANSPORTS = ["auto", "websocket", "post"];
1622
1280
  function entryName(name) {
1623
1281
  if (name === void 0) return DEFAULT_NAME;
1624
- if (typeof name !== 'string' || name.trim() === '')
1625
- throw new TypeError('name must be a non-empty string');
1282
+ if (typeof name !== "string" || name.trim() === "") throw new TypeError("name must be a non-empty string");
1626
1283
  return name;
1627
1284
  }
1628
1285
  function checkStore(store) {
1629
1286
  const s = store;
1630
- if (
1631
- !s ||
1632
- typeof s.get !== 'function' ||
1633
- typeof s.set !== 'function' ||
1634
- typeof s.delete !== 'function'
1635
- ) {
1636
- throw new TypeError('store must implement get, set and delete');
1287
+ if (!s || typeof s.get !== "function" || typeof s.set !== "function" || typeof s.delete !== "function") {
1288
+ throw new TypeError("store must implement get, set and delete");
1637
1289
  }
1638
1290
  return s;
1639
1291
  }
@@ -1646,10 +1298,7 @@ function withEntry(store, name, fn) {
1646
1298
  }
1647
1299
  const map = byName;
1648
1300
  const run = (map.get(name) ?? Promise.resolve()).then(fn);
1649
- const tail = run.then(
1650
- () => void 0,
1651
- () => void 0,
1652
- );
1301
+ const tail = run.then(() => void 0, () => void 0);
1653
1302
  map.set(name, tail);
1654
1303
  void tail.then(() => {
1655
1304
  if (map.get(name) === tail) map.delete(name);
@@ -1660,11 +1309,7 @@ async function viaStore(what, call) {
1660
1309
  try {
1661
1310
  return await call();
1662
1311
  } catch (err) {
1663
- throw new O1ConnectError(
1664
- 'store_failed',
1665
- `the secret store failed to ${what}`,
1666
- { cause: err },
1667
- );
1312
+ throw new O1ConnectError("store_failed", `the secret store failed to ${what}`, { cause: err });
1668
1313
  }
1669
1314
  }
1670
1315
  function parseSaved(raw) {
@@ -1672,150 +1317,98 @@ function parseSaved(raw) {
1672
1317
  try {
1673
1318
  o = JSON.parse(String(raw));
1674
1319
  } catch {
1675
- throw new O1ConnectError(
1676
- 'invalid_config',
1677
- 'the saved configuration is not JSON: run setup again',
1678
- );
1320
+ throw new O1ConnectError("invalid_config", "the saved configuration is not JSON: run setup again");
1679
1321
  }
1680
- if (!o || typeof o !== 'object' || o.v !== 1)
1681
- throw new O1ConnectError(
1682
- 'invalid_config',
1683
- 'the saved configuration is not one this library knows: run setup again',
1684
- );
1322
+ if (!o || typeof o !== "object" || o.v !== 1) throw new O1ConnectError("invalid_config", "the saved configuration is not one this library knows: run setup again");
1685
1323
  let code;
1686
1324
  try {
1687
1325
  code = validateCode(o);
1688
1326
  } catch (err) {
1689
- throw new O1ConnectError(
1690
- 'invalid_config',
1691
- `the saved configuration is not valid (${err instanceof Error ? err.message : String(err)}): run setup again`,
1692
- );
1327
+ throw new O1ConnectError("invalid_config", `the saved configuration is not valid (${err instanceof Error ? err.message : String(err)}): run setup again`);
1693
1328
  }
1694
- const transport = o.transport ?? 'auto';
1695
- if (!TRANSPORTS.includes(transport))
1696
- throw new O1ConnectError(
1697
- 'invalid_config',
1698
- 'the saved transport is not auto, websocket or post: run setup again',
1699
- );
1329
+ const transport = o.transport ?? "auto";
1330
+ if (!TRANSPORTS.includes(transport)) throw new O1ConnectError("invalid_config", "the saved transport is not auto, websocket or post: run setup again");
1700
1331
  return { v: 1, ...code, transport };
1701
1332
  }
1702
1333
  async function setup(code, opts) {
1703
1334
  const store = checkStore(opts?.store);
1704
- if (typeof opts.onFingerprint !== 'function')
1705
- throw new TypeError(
1706
- "onFingerprint is required: every key's fingerprint must be confirmed by the user",
1707
- );
1335
+ if (typeof opts.onFingerprint !== "function") throw new TypeError("onFingerprint is required: every key's fingerprint must be confirmed by the user");
1708
1336
  const name = entryName(opts.name);
1709
- const transport = opts.transport ?? 'auto';
1710
- if (!TRANSPORTS.includes(transport))
1711
- throw new TypeError('transport must be auto, websocket or post');
1337
+ const transport = opts.transport ?? "auto";
1338
+ if (!TRANSPORTS.includes(transport)) throw new TypeError("transport must be auto, websocket or post");
1712
1339
  let decoded;
1713
1340
  try {
1714
- decoded = decodeConnectionCode(String(code ?? ''));
1341
+ decoded = decodeConnectionCode(String(code ?? ""));
1715
1342
  } catch (err) {
1716
- throw new O1ConnectError(
1717
- 'invalid_code',
1718
- err instanceof ConnectionCodeError
1719
- ? err.message
1720
- : 'the connection code is not valid',
1721
- );
1343
+ throw new O1ConnectError("invalid_code", err instanceof ConnectionCodeError ? err.message : "the connection code is not valid");
1722
1344
  }
1723
1345
  const fingerprints = decoded.pins.map((p) => fingerprint(p));
1724
- const info = { device: decoded.device, url: decoded.url };
1725
- if ((await opts.onFingerprint([...fingerprints], { ...info })) !== true) {
1726
- throw new O1ConnectError(
1727
- 'fingerprint_rejected',
1728
- 'the proxy keys were not confirmed: nothing was saved',
1729
- );
1346
+ const info = { device: decoded.device, url: decoded.url, ...decoded.urls ? { urls: [...decoded.urls] } : {} };
1347
+ if (await opts.onFingerprint([...fingerprints], { ...info }) !== true) {
1348
+ throw new O1ConnectError("fingerprint_rejected", "the proxy keys were not confirmed: nothing was saved");
1730
1349
  }
1731
1350
  const saved = { v: 1, ...decoded, transport };
1732
- await withEntry(store, name, () =>
1733
- viaStore('save the configuration', () =>
1734
- store.set(name, JSON.stringify(saved)),
1735
- ),
1736
- );
1351
+ await withEntry(store, name, () => viaStore("save the configuration", () => store.set(name, JSON.stringify(saved))));
1737
1352
  return { ...info, fingerprints };
1738
1353
  }
1739
1354
  async function open(opts) {
1740
1355
  const store = checkStore(opts?.store);
1741
1356
  const name = entryName(opts.name);
1742
1357
  const port = opts.port ?? 0;
1743
- if (!Number.isInteger(port) || port < 0 || port > 65535)
1744
- throw new TypeError('port must be an integer from 0 to 65535');
1745
- const raw = await viaStore('read the configuration', () => store.get(name));
1746
- if (raw === null || raw === void 0)
1747
- throw new O1ConnectError(
1748
- 'not_set_up',
1749
- 'no o1-connect configuration in the store: run setup with a connection code',
1750
- );
1358
+ if (!Number.isInteger(port) || port < 0 || port > 65535) throw new TypeError("port must be an integer from 0 to 65535");
1359
+ const raw = await viaStore("read the configuration", () => store.get(name));
1360
+ if (raw === null || raw === void 0) throw new O1ConnectError("not_set_up", "no o1-connect configuration in the store: run setup with a connection code");
1751
1361
  const cfg = parseSaved(raw);
1752
- const log = opts.log
1753
- ? (line) => {
1754
- try {
1755
- opts.log(line);
1756
- } catch {}
1757
- }
1758
- : void 0;
1362
+ const log = opts.log ? (line) => {
1363
+ try {
1364
+ opts.log(line);
1365
+ } catch {
1366
+ }
1367
+ } : void 0;
1759
1368
  const apiKey = newLocalKey();
1760
1369
  let session;
1761
1370
  try {
1762
1371
  session = await startTunnelSession({
1763
1372
  url: cfg.url,
1373
+ urls: cfg.urls,
1764
1374
  pins: cfg.pins,
1765
1375
  deviceToken: cfg.token,
1766
1376
  transport: cfg.transport,
1767
1377
  port,
1768
1378
  localKeyHash: hashLocalKey(apiKey),
1769
- userAgent: `o1-connect-lib/${VERSION}`,
1379
+ // Only when the app asks (like the CLI's identify): absent, nothing about the client goes on the wire.
1380
+ userAgent: opts.identify === true ? `o1-connect-lib/${VERSION}` : void 0,
1770
1381
  log,
1771
1382
  onMismatch: (received) => {
1772
- log?.(
1773
- `TUNNEL IDENTITY MISMATCH: received ${received}; possible interception`,
1774
- );
1383
+ log?.(`TUNNEL IDENTITY MISMATCH: received ${received}; possible interception`);
1775
1384
  try {
1776
1385
  opts.onMismatch?.(received);
1777
- } catch {}
1386
+ } catch {
1387
+ }
1778
1388
  },
1779
- onTransport: (t, reason) => log?.(`${reason ?? 'transport'}, using ${t}`),
1389
+ onTransport: (t, reason) => log?.(`${reason ?? "transport"}, using ${t}`),
1780
1390
  // Pins learned during a key rotation: saved only while the store still holds this
1781
1391
  // configuration (same proxy, device and token), under the entry's lock; false (never
1782
1392
  // tried again by this connection) once setup replaced it or forget deleted it.
1783
- savePinsStoppedLine:
1784
- 'the store now holds another configuration, or none (setup or forget ran since): the proxy keys learned by this connection are no longer saved',
1785
- savePins: (pins) =>
1786
- withEntry(store, name, async () => {
1787
- const raw2 = await viaStore('read the configuration', () =>
1788
- store.get(name),
1789
- );
1790
- if (raw2 === null || raw2 === void 0) return false;
1791
- let current;
1792
- try {
1793
- current = parseSaved(raw2);
1794
- } catch {
1795
- return false;
1796
- }
1797
- if (
1798
- current.url !== cfg.url ||
1799
- current.device !== cfg.device ||
1800
- current.token !== cfg.token
1801
- )
1802
- return false;
1803
- await viaStore('save the configuration', () =>
1804
- store.set(name, JSON.stringify({ ...current, pins })),
1805
- );
1806
- return true;
1807
- }),
1393
+ savePinsStoppedLine: "the store now holds another configuration, or none (setup or forget ran since): the proxy keys learned by this connection are no longer saved",
1394
+ savePins: (pins) => withEntry(store, name, async () => {
1395
+ const raw2 = await viaStore("read the configuration", () => store.get(name));
1396
+ if (raw2 === null || raw2 === void 0) return false;
1397
+ let current;
1398
+ try {
1399
+ current = parseSaved(raw2);
1400
+ } catch {
1401
+ return false;
1402
+ }
1403
+ if (current.url !== cfg.url || current.device !== cfg.device || current.token !== cfg.token) return false;
1404
+ await viaStore("save the configuration", () => store.set(name, JSON.stringify({ ...current, pins })));
1405
+ return true;
1406
+ })
1808
1407
  });
1809
1408
  } catch (err) {
1810
1409
  const code = err.code;
1811
- if (code === 'EADDRINUSE')
1812
- throw new O1ConnectError('port_in_use', `port ${port} is in use`);
1813
- if (code === 'EACCES' || code === 'EADDRNOTAVAIL')
1814
- throw new O1ConnectError(
1815
- 'port_unavailable',
1816
- `cannot listen on 127.0.0.1:${port} (${code})`,
1817
- { cause: err },
1818
- );
1410
+ if (code === "EADDRINUSE") throw new O1ConnectError("port_in_use", `port ${port} is in use`);
1411
+ if (code === "EACCES" || code === "EADDRNOTAVAIL") throw new O1ConnectError("port_unavailable", `cannot listen on 127.0.0.1:${port} (${code})`, { cause: err });
1819
1412
  throw err;
1820
1413
  }
1821
1414
  if (opts.check !== false) {
@@ -1824,36 +1417,19 @@ async function open(opts) {
1824
1417
  } catch (err) {
1825
1418
  await session.close();
1826
1419
  if (err instanceof IdentityMismatchError || err instanceof BackoffError) {
1827
- throw new O1ConnectError(
1828
- 'identity_mismatch',
1829
- 'the proxy presented a key that is not pinned: possible interception (nothing was sent)',
1830
- );
1420
+ throw new O1ConnectError("identity_mismatch", "the proxy presented a key that is not pinned: possible interception (nothing was sent)");
1831
1421
  }
1832
- throw new O1ConnectError(
1833
- 'tunnel_unavailable',
1834
- `the tunnel did not answer: ${err instanceof Error ? err.message : String(err)}`,
1835
- );
1422
+ throw new O1ConnectError("tunnel_unavailable", `the tunnel did not answer: ${err instanceof Error ? err.message : String(err)}`);
1836
1423
  }
1837
1424
  }
1838
1425
  const baseUrl = `http://127.0.0.1:${session.port}`;
1839
- log?.(
1840
- `o1-connect library ${VERSION} for ${cfg.device} listening on ${baseUrl} (transport ${cfg.transport})`,
1841
- );
1842
- return {
1843
- baseUrl,
1844
- openaiBaseUrl: `${baseUrl}/v1`,
1845
- apiKey,
1846
- port: session.port,
1847
- device: cfg.device,
1848
- close: session.close,
1849
- };
1426
+ log?.(`o1-connect library ${VERSION} for ${cfg.device} listening on ${baseUrl} (transport ${cfg.transport})`);
1427
+ return { baseUrl, openaiBaseUrl: `${baseUrl}/v1`, apiKey, port: session.port, device: cfg.device, close: session.close };
1850
1428
  }
1851
1429
  async function forget(opts) {
1852
1430
  const store = checkStore(opts?.store);
1853
1431
  const name = entryName(opts.name);
1854
- await withEntry(store, name, () =>
1855
- viaStore('delete the configuration', () => store.delete(name)),
1856
- );
1432
+ await withEntry(store, name, () => viaStore("delete the configuration", () => store.delete(name)));
1857
1433
  }
1858
1434
  var MemorySecretStore = class {
1859
1435
  #values = /* @__PURE__ */ new Map();
@@ -1867,4 +1443,11 @@ var MemorySecretStore = class {
1867
1443
  this.#values.delete(name);
1868
1444
  }
1869
1445
  };
1870
- export { MemorySecretStore, O1ConnectError, forget, open, setup, version };
1446
+ export {
1447
+ MemorySecretStore,
1448
+ O1ConnectError,
1449
+ forget,
1450
+ open,
1451
+ setup,
1452
+ version
1453
+ };