@organizaone/o1-code 0.5.1 → 0.6.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 (298) hide show
  1. package/README.md +8 -8
  2. package/bundled/qc-helper/docs/configuration/auth.md +14 -3
  3. package/bundled/qc-helper/docs/integration-jetbrains.md +1 -1
  4. package/bundled/qc-helper/docs/integration-vscode.md +1 -1
  5. package/bundled/qc-helper/docs/integration-zed.md +1 -1
  6. package/bundled/qc-helper/docs/quickstart.md +1 -1
  7. package/bundled/qc-helper/docs/support/troubleshooting.md +1 -1
  8. package/chunks/{MaxSizedBox-ZOFIKGJG.js → MaxSizedBox-5EOREWNX.js} +28 -28
  9. package/chunks/{StandaloneSessionPicker-6S2C7YZK.js → StandaloneSessionPicker-3OCB32JD.js} +44 -44
  10. package/chunks/{acp-subagent-executor-HGIGYENO.js → acp-subagent-executor-JTNA5F4Q.js} +28 -28
  11. package/chunks/{acpAgent-SXUNXWWP.js → acpAgent-IS2JKYZV.js} +70 -70
  12. package/chunks/{agent-7GI5MAMY.js → agent-U5KE7R4X.js} +15 -15
  13. package/chunks/{agent-headless-7ZSKSLIE.js → agent-headless-VL764VUV.js} +15 -15
  14. package/chunks/{anthropicContentGenerator-FHJ5JNYR.js → anthropicContentGenerator-I7B3ZJTH.js} +5 -5
  15. package/chunks/{bridge-5YHUATCB.js → bridge-4GFWUTJN.js} +28 -28
  16. package/chunks/{ca-ZH46FQUI.js → ca-D47KKMP2.js} +2 -2
  17. package/chunks/{chunk-Z6HFYF3D.js → chunk-25B3YO64.js} +1 -1
  18. package/chunks/{chunk-GLT2QUV7.js → chunk-2TR3LXCO.js} +4 -4
  19. package/chunks/{chunk-3CMD4E67.js → chunk-2XWTDVCK.js} +9 -9
  20. package/chunks/{chunk-26GB3MTV.js → chunk-2ZZOVOXT.js} +2 -2
  21. package/chunks/{chunk-UZSRQ26K.js → chunk-35XZ5JAH.js} +1 -1
  22. package/chunks/{chunk-F6UT36OB.js → chunk-3RRITSOA.js} +2 -2
  23. package/chunks/{chunk-7PXVBJL3.js → chunk-3VVXMGS2.js} +1 -1
  24. package/chunks/{chunk-6LOAUBTH.js → chunk-4D3AFN6X.js} +3 -3
  25. package/chunks/{chunk-SE3HMQLW.js → chunk-4YYRPA6G.js} +5 -5
  26. package/chunks/{chunk-MQ3QD65Z.js → chunk-4ZTCFNSU.js} +1 -1
  27. package/chunks/{chunk-3YZPY6YA.js → chunk-5KLD2C2A.js} +1 -1
  28. package/chunks/{chunk-D42MFAOX.js → chunk-5OZ6R5FD.js} +3 -3
  29. package/chunks/{chunk-ABTF7TPE.js → chunk-73JQWXED.js} +2 -2
  30. package/chunks/{chunk-ZFT5MBI6.js → chunk-7UG5NBEG.js} +1 -1
  31. package/chunks/{chunk-VJ3EJJ5K.js → chunk-A6R5ERJF.js} +4 -4
  32. package/chunks/{chunk-RYBAJ5II.js → chunk-ADSXYGOQ.js} +1 -1
  33. package/chunks/{chunk-3YLEHHA7.js → chunk-AT74D3S6.js} +3 -3
  34. package/chunks/{chunk-R5WDYBMX.js → chunk-B5RUUS5Z.js} +1 -1
  35. package/chunks/{chunk-GW3TK3X2.js → chunk-B74GMYXF.js} +30 -30
  36. package/chunks/{chunk-PB4XGSE6.js → chunk-BBH77V6I.js} +1 -1
  37. package/chunks/{chunk-FMDABBCA.js → chunk-BO53R5FT.js} +3 -3
  38. package/chunks/{chunk-YQF62HFY.js → chunk-BXRUYSL6.js} +1 -1
  39. package/chunks/{chunk-TYAUV2TE.js → chunk-C2RMEAXF.js} +1 -1
  40. package/chunks/{chunk-E6JZE22X.js → chunk-CLRPG355.js} +3 -3
  41. package/chunks/{chunk-2J53EWTP.js → chunk-CXL3KGXN.js} +7 -7
  42. package/chunks/{chunk-KVQMH7W2.js → chunk-DD5QAE42.js} +4 -4
  43. package/chunks/{chunk-MDQYCFNT.js → chunk-DFHGNP5W.js} +17 -17
  44. package/chunks/{chunk-X655UILS.js → chunk-DGB4GDUC.js} +15 -15
  45. package/chunks/{chunk-KCHIL32J.js → chunk-DIVWC7JL.js} +6 -6
  46. package/chunks/{chunk-EBTQTM56.js → chunk-FNOLXMFM.js} +1 -1
  47. package/chunks/{chunk-WCFNOALO.js → chunk-FVXJFEVA.js} +1 -1
  48. package/chunks/{chunk-G3W4UY3G.js → chunk-G7HMFP3U.js} +3457 -1431
  49. package/chunks/{chunk-L7LXG6TN.js → chunk-GKX63AXY.js} +2 -2
  50. package/chunks/{chunk-GN6HVKBI.js → chunk-GT5QP7HM.js} +2 -2
  51. package/chunks/{chunk-3GGCMM7C.js → chunk-HFBSP3VC.js} +1 -1
  52. package/chunks/{chunk-MRJJAG44.js → chunk-HWHXSAP6.js} +10 -10
  53. package/chunks/{chunk-W2MWOPYK.js → chunk-HXLT4YHM.js} +9 -9
  54. package/chunks/{chunk-MRBPTAOV.js → chunk-IF22E34Z.js} +3 -3
  55. package/chunks/{chunk-GHYY2N2S.js → chunk-IFJUYGAZ.js} +1 -1
  56. package/chunks/{chunk-ZZXUYKAG.js → chunk-IKDFLXTG.js} +4 -4
  57. package/chunks/{chunk-M5G6OKEY.js → chunk-J5XJUCP6.js} +4 -4
  58. package/chunks/{chunk-LJU6OPEU.js → chunk-JY65SH65.js} +3 -3
  59. package/chunks/{chunk-JDPRCTE4.js → chunk-KCIKBXEW.js} +4 -4
  60. package/chunks/{chunk-SE33PFPT.js → chunk-KFOL4KHG.js} +8 -8
  61. package/chunks/{chunk-ODSVNOLT.js → chunk-KPGPUSJ4.js} +5 -5
  62. package/chunks/{chunk-6MEAGROF.js → chunk-KQRLWGYH.js} +1 -1
  63. package/chunks/{chunk-TXIBLU7T.js → chunk-KWUNXWMZ.js} +8 -8
  64. package/chunks/{chunk-34ORCXAX.js → chunk-L2OTZN7G.js} +1 -1
  65. package/chunks/{chunk-ELAUQQIT.js → chunk-LDZQTXZL.js} +4 -4
  66. package/chunks/{chunk-XFV6QC4A.js → chunk-LKTMEG3O.js} +2 -2
  67. package/chunks/{chunk-DLJHG562.js → chunk-MRDWUFJ3.js} +4 -4
  68. package/chunks/{chunk-RTFUUYHW.js → chunk-N2PY5BWY.js} +1 -1
  69. package/chunks/{chunk-734USTD3.js → chunk-NCYMEGY4.js} +5 -5
  70. package/chunks/{chunk-KJVLRZBK.js → chunk-NEG6TBRH.js} +1 -1
  71. package/chunks/{chunk-2CATNMFQ.js → chunk-NHRNNWWS.js} +1 -1
  72. package/chunks/{chunk-PSL5VFNJ.js → chunk-NHVJTPZA.js} +33 -33
  73. package/chunks/{chunk-IL4VUEEH.js → chunk-NIIG7L3H.js} +1 -1
  74. package/chunks/{chunk-GFBAQUJG.js → chunk-NTUVIB2G.js} +1 -1
  75. package/chunks/{chunk-HGW4END7.js → chunk-NWQPYJVP.js} +3 -3
  76. package/chunks/{chunk-7TZRKZWC.js → chunk-OCUQJADH.js} +1 -1
  77. package/chunks/{chunk-L6J57N2A.js → chunk-OUANBR2O.js} +1 -1
  78. package/chunks/{chunk-H65LZ7Q4.js → chunk-OYF5BLWF.js} +1 -1
  79. package/chunks/{chunk-MDQFX2C5.js → chunk-PIMJCQZQ.js} +1 -1
  80. package/chunks/{chunk-KI7AYT4Y.js → chunk-PVQB3PSU.js} +1 -1
  81. package/chunks/{chunk-JSB66IE5.js → chunk-PZG6YNNW.js} +1 -1
  82. package/chunks/{chunk-WBW6J5R3.js → chunk-QKJBBOEM.js} +2 -2
  83. package/chunks/{chunk-CVU3EIFH.js → chunk-SALGNBVH.js} +3 -3
  84. package/chunks/{chunk-MXIQ6C7B.js → chunk-SD4FTFLM.js} +2 -2
  85. package/chunks/{chunk-RIX6ATSB.js → chunk-SHDHN4UM.js} +59 -21
  86. package/chunks/{chunk-MGVVXFYW.js → chunk-SJLUEEH6.js} +2 -2
  87. package/chunks/{chunk-AJS6HD3U.js → chunk-SNSYYPUE.js} +7 -7
  88. package/chunks/{chunk-NVNIFGY3.js → chunk-SQX3PXHY.js} +2 -2
  89. package/chunks/{chunk-B67EYF6M.js → chunk-SRM5ACHK.js} +1 -1
  90. package/chunks/{chunk-2QN2TID2.js → chunk-SRUCOHM3.js} +6 -6
  91. package/chunks/{chunk-LHCVJ6NV.js → chunk-TA5SQUCP.js} +1 -1
  92. package/chunks/{chunk-GWX3EC6J.js → chunk-TUQWDNKR.js} +2 -2
  93. package/chunks/{chunk-NBCYYKYK.js → chunk-UDJURQZ6.js} +3 -3
  94. package/chunks/{chunk-LHY2PDWX.js → chunk-UQ6BHHFA.js} +5 -5
  95. package/chunks/{chunk-WQNNHDDX.js → chunk-V2WRTFQU.js} +5 -5
  96. package/chunks/{chunk-A2K4A5O2.js → chunk-VEFKFFT5.js} +1 -1
  97. package/chunks/{chunk-PLYNCSHX.js → chunk-VFSP4ZUZ.js} +6 -6
  98. package/chunks/{chunk-2OQC7O74.js → chunk-VL3VAUJC.js} +3 -3
  99. package/chunks/{chunk-GAM5VJT7.js → chunk-WI4BVBZO.js} +1 -1
  100. package/chunks/{chunk-CHZDN4DI.js → chunk-WVEKU4MO.js} +2 -2
  101. package/chunks/{chunk-JOGRE2ZT.js → chunk-X2RYRNAP.js} +2 -2
  102. package/chunks/{chunk-B2PLLGOC.js → chunk-XMR45LXQ.js} +1 -1
  103. package/chunks/{chunk-OVOSIR5V.js → chunk-XNOIGECT.js} +11 -11
  104. package/chunks/{chunk-6DOSH2VF.js → chunk-XPFD45HB.js} +240 -10
  105. package/chunks/{chunk-C2IESIWR.js → chunk-XQGFM4KU.js} +5 -5
  106. package/chunks/{chunk-6QYP53HJ.js → chunk-Y2DKG24P.js} +1 -1
  107. package/chunks/{chunk-MX7QDQRT.js → chunk-YK4BICUN.js} +3 -3
  108. package/chunks/{chunk-22SKH7LF.js → chunk-YNYV52Z4.js} +2 -2
  109. package/chunks/{chunk-K5JXFVNB.js → chunk-YPHLY3RQ.js} +5 -5
  110. package/chunks/{chunk-RRWM6VZS.js → chunk-ZCCCPNWD.js} +1 -1
  111. package/chunks/{chunk-GMR3LAWE.js → chunk-ZHTRFFVQ.js} +1 -1
  112. package/chunks/{chunk-2DNMFYMU.js → chunk-ZJYMX7GI.js} +3 -3
  113. package/chunks/{chunk-TDBZBCLU.js → chunk-ZOZJOC2D.js} +2 -2
  114. package/chunks/{chunk-LERXWKRT.js → chunk-ZQPD7WDS.js} +1 -1
  115. package/chunks/{chunk-EMIGZJZT.js → chunk-ZTD5FNCI.js} +1 -1
  116. package/chunks/{codex-subagent-executor-NO5C6VPN.js → codex-subagent-executor-H23KDM2L.js} +28 -28
  117. package/chunks/{contextCommand-VWARZSMR.js → contextCommand-FTM7H7IU.js} +27 -27
  118. package/chunks/{core-runtime-KL6UEQWI.js → core-runtime-EOPJ5NTV.js} +25 -25
  119. package/chunks/{create-sub-session-CY7EFJX5.js → create-sub-session-TYQLJBIC.js} +26 -26
  120. package/chunks/{daemon-git-worktree-guard-CPIBCRZO.js → daemon-git-worktree-guard-XYJOCQD4.js} +25 -25
  121. package/chunks/{daemon-status-provider-BN3RF2FL.js → daemon-status-provider-WSERMTQ3.js} +33 -33
  122. package/chunks/{daemon-trust-policy-4CK5U5IC.js → daemon-trust-policy-2TLIJCGQ.js} +31 -31
  123. package/chunks/{daemon-trust-policy-monitor-CUNFNI4N.js → daemon-trust-policy-monitor-5WZ6JDKZ.js} +31 -31
  124. package/chunks/{de-OBLDRYWI.js → de-LJ7XKJ7L.js} +2 -2
  125. package/chunks/{deferred-core-runtime-CBJTZJPH.js → deferred-core-runtime-55WMDAXO.js} +25 -25
  126. package/chunks/{edit-RM227QNR.js → edit-UPV3RDKW.js} +17 -17
  127. package/chunks/{en-NKO6N4BL.js → en-S424EGDF.js} +19 -2
  128. package/chunks/{enterPlanMode-PYAHJFSQ.js → enterPlanMode-IFHOH44O.js} +15 -15
  129. package/chunks/{environment-DD54IMFM.js → environment-YEQIXHG6.js} +27 -27
  130. package/chunks/{errors-HI6DJG4B.js → errors-X2UJSPQL.js} +27 -27
  131. package/chunks/{execution-tool-V3VSCW6K.js → execution-tool-EXIGBLTL.js} +17 -17
  132. package/chunks/{execution-worker-WBHEON6Q.js → execution-worker-6PKEW2P6.js} +20 -20
  133. package/chunks/{exitPlanMode-HOZQZ5T7.js → exitPlanMode-7NRDPCOW.js} +15 -15
  134. package/chunks/{fast-path-7HGISECB.js → fast-path-I65CU5I2.js} +2 -2
  135. package/chunks/{fr-24RYKQP7.js → fr-XXSQXQDX.js} +2 -2
  136. package/chunks/{glob-3Z2KONQG.js → glob-XTHACKUG.js} +15 -15
  137. package/chunks/{goal-tools-SZZFOYEQ.js → goal-tools-KL2MBM6T.js} +15 -15
  138. package/chunks/{handleAutoUpdate-YW4VDPGO.js → handleAutoUpdate-AN36IGA3.js} +28 -28
  139. package/chunks/{i18n-3EQ4CCDM.js → i18n-ZOWYH5SP.js} +26 -26
  140. package/chunks/{image-gen-GJRWPVTR.js → image-gen-72F4XQEU.js} +3 -3
  141. package/chunks/{initializer-G4SCU6JQ.js → initializer-7VQKSVVS.js} +32 -32
  142. package/chunks/{installationInfo-3QFLR7CO.js → installationInfo-L6JLTT7O.js} +25 -25
  143. package/chunks/{ja-NY2HNPE4.js → ja-CI32MYX2.js} +2 -2
  144. package/chunks/{list-S4KQBUXO.js → list-HZEUOA3H.js} +33 -33
  145. package/chunks/{llm-HBFVSHNO.js → llm-VIAH4AFT.js} +87 -58
  146. package/chunks/{llm-content-generator-WWIIJ3YF.js → llm-content-generator-AE3URFE7.js} +3 -3
  147. package/chunks/{loadedSettingsAdapter-4FCPSPON.js → loadedSettingsAdapter-LLENP2KA.js} +31 -31
  148. package/chunks/{local-execution-environment-PUSM6PGS.js → local-execution-environment-B2UY3HMI.js} +20 -20
  149. package/chunks/{loggingContentGenerator-OMYQPXBM.js → loggingContentGenerator-5I5NLC6I.js} +16 -16
  150. package/chunks/{managed-npm-update-MUWFIXMB.js → managed-npm-update-6XAPVQBT.js} +25 -25
  151. package/chunks/{mcp-IFIMZMMB.js → mcp-PIYFXVT4.js} +31 -31
  152. package/chunks/{model-call-collection-RJ3QGO3O.js → model-call-collection-7DIS7C2G.js} +1 -1
  153. package/chunks/{model-configuration-AQOY5NHG.js → model-configuration-J7N3CHD5.js} +32 -32
  154. package/chunks/{modelConfigUtils-3WCZU5US.js → modelConfigUtils-6YYQJIHD.js} +27 -27
  155. package/chunks/{monitor-Z4DAPTBI.js → monitor-5GBFRXN7.js} +15 -15
  156. package/chunks/{nonInteractiveCli-EIFDEYFS.js → nonInteractiveCli-YFE2ILFH.js} +61 -61
  157. package/chunks/{nonInteractiveToolExecutor-NS2HFUO5.js → nonInteractiveToolExecutor-BRFDL2BK.js} +16 -16
  158. package/chunks/{notebook-edit-TXNVV4NZ.js → notebook-edit-ORYWDEMK.js} +16 -16
  159. package/chunks/{omni-EANTWQG5.js → omni-ANTNX2XB.js} +11 -11
  160. package/chunks/{openaiContentGenerator-JU5KLG5T.js → openaiContentGenerator-AIWBAUPV.js} +7 -7
  161. package/chunks/{openaiResponsesContentGenerator-BQZ54E6V.js → openaiResponsesContentGenerator-SABJHG34.js} +3 -3
  162. package/chunks/{processUtils-PVRINBPF.js → processUtils-UAADVXTD.js} +2 -2
  163. package/chunks/{prompt-terminal-ledger-LDPMNEHI.js → prompt-terminal-ledger-I7POO7OK.js} +26 -26
  164. package/chunks/{pt-DFSLPV3S.js → pt-OHD6RIUC.js} +19 -2
  165. package/chunks/{reactive-degrade-5HVNIKLO.js → reactive-degrade-VHPS7U44.js} +8 -8
  166. package/chunks/{read-file-H4L4HPEH.js → read-file-SERUEXAP.js} +2 -2
  167. package/chunks/{resumeHistoryUtils-TMGVZMKJ.js → resumeHistoryUtils-B6GT4AOO.js} +31 -31
  168. package/chunks/{ripGrep-YVUC4DXT.js → ripGrep-2NTNXBII.js} +3 -3
  169. package/chunks/{ru-VIGQVLUG.js → ru-6VYU34XF.js} +2 -2
  170. package/chunks/{run-o1-code-serve-LAIBSEHT.js → run-o1-code-serve-WROVR5TA.js} +32 -32
  171. package/chunks/{sandboxConfig-UYUFPT6T.js → sandboxConfig-UVIRIBNM.js} +25 -25
  172. package/chunks/{scheduled-tasks-JFRIRKTA.js → scheduled-tasks-ILH3HQXS.js} +31 -31
  173. package/chunks/{scheduler-2PWRO4UB.js → scheduler-Y2TYB53M.js} +27 -27
  174. package/chunks/{serve-5NOYAIKF.js → serve-YUVXMXLS.js} +31 -31
  175. package/chunks/{server-VJ4WGSUY.js → server-K75VXRXS.js} +64 -62
  176. package/chunks/{session-CGV7TJGH.js → session-KZSKLSES.js} +62 -62
  177. package/chunks/{session-attachments-root-COVGVQZC.js → session-attachments-root-MYYIOBTM.js} +25 -25
  178. package/chunks/{session-pr-refresh-SX33MGB4.js → session-pr-refresh-33KB2JND.js} +30 -30
  179. package/chunks/{settings-XRNF45NA.js → settings-HVF3IJ2I.js} +30 -30
  180. package/chunks/{shell-RX3LXNJP.js → shell-PN27CAHY.js} +15 -15
  181. package/chunks/{skill-KCPU5AV6.js → skill-L6CRUQRR.js} +3 -3
  182. package/chunks/{skill-settings-PAEWMBXK.js → skill-settings-3Y3SG5O5.js} +31 -31
  183. package/chunks/{spawnChannel-SNCSRXCH.js → spawnChannel-XSDXM46P.js} +27 -27
  184. package/chunks/{standalone-update-WPASUR47.js → standalone-update-3LDGOGBF.js} +27 -27
  185. package/chunks/{startInteractiveUI-ZX3UUKMI.js → startInteractiveUI-GIDY23D3.js} +3985 -3527
  186. package/chunks/{team-create-LV77LY5U.js → team-create-LFN7HQGC.js} +15 -15
  187. package/chunks/{team-plan-approval-VBIL6SV3.js → team-plan-approval-EFVOZVSP.js} +15 -15
  188. package/chunks/{terminal-image-renderer-ADP6QUHM.js → terminal-image-renderer-GOF6SZEL.js} +25 -25
  189. package/chunks/{theme-manager-EUUSF2Q7.js → theme-manager-MQ7UIBL2.js} +26 -26
  190. package/chunks/{tool-result-media-JVU7TVUQ.js → tool-result-media-NQAPMXYD.js} +11 -11
  191. package/chunks/{tool-search-PEJVNWOB.js → tool-search-JJ7KQQ5S.js} +2 -2
  192. package/chunks/{total-session-admission-N7ME7DLF.js → total-session-admission-GTFQVE5J.js} +28 -28
  193. package/chunks/{trustedFolders-G3EG6RNC.js → trustedFolders-W3AE6S4D.js} +26 -26
  194. package/chunks/{update-relaunch-OAYGBIDB.js → update-relaunch-VIWAZWCG.js} +5 -5
  195. package/chunks/{updateCheck-JKYZNZTK.js → updateCheck-EHHLVFT3.js} +27 -27
  196. package/chunks/{upload-config-LPONQVLM.js → upload-config-6Z3CPQTV.js} +6 -6
  197. package/chunks/{useAutoAcceptIndicator-AZBWWHTT.js → useAutoAcceptIndicator-2BDM2ZLG.js} +33 -33
  198. package/chunks/{validateNonInterActiveAuth-5K6TQOCW.js → validateNonInterActiveAuth-SBUIY7JB.js} +58 -58
  199. package/chunks/{version-7MOVE5JZ.js → version-LJX5EMFD.js} +1 -1
  200. package/chunks/{web-fetch-ALDHPFKB.js → web-fetch-NMKFGF5A.js} +4 -4
  201. package/chunks/{web-search-4FXUXV76.js → web-search-FT3NC3MF.js} +8 -8
  202. package/chunks/{workflow-W6TQFKWS.js → workflow-5WQJENZ6.js} +16 -16
  203. package/chunks/{workspace-providers-status-JRU6E7KT.js → workspace-providers-status-U3G2IL7D.js} +37 -37
  204. package/chunks/{workspace-registration-store-2VLHZRVP.js → workspace-registration-store-XGN5KM7D.js} +1 -1
  205. package/chunks/{workspace-registry-BYB7WBWO.js → workspace-registry-V7Z7GRVC.js} +28 -28
  206. package/chunks/{workspace-runtime-coordinator-EEAZTJ6X.js → workspace-runtime-coordinator-TEWHWJZI.js} +29 -29
  207. package/chunks/{workspace-service-7SCTZ2HS.js → workspace-service-JM6TECMD.js} +35 -35
  208. package/chunks/{workspace-skills-status-HDLEGK3V.js → workspace-skills-status-ESUOVYAN.js} +34 -34
  209. package/chunks/{workspace-trust-reconciler-SONZ46YA.js → workspace-trust-reconciler-PGZAZMT3.js} +34 -34
  210. package/chunks/{write-file-BIRFPH4F.js → write-file-AHGK3PK4.js} +17 -17
  211. package/chunks/{zh-ZJAHWOYM.js → zh-KRQU675V.js} +19 -2
  212. package/chunks/{zh-TW-S4AGRCDA.js → zh-TW-K657U7LC.js} +19 -2
  213. package/chunks/{zoom-image-UFU3VEIY.js → zoom-image-IU5DRM6D.js} +2 -2
  214. package/cli.js +12 -12
  215. package/examples/starter/README.md +1 -1
  216. package/execution-worker.js +1 -1
  217. package/export-transcript-document.js +1 -1
  218. package/locales/ca.js +3 -2
  219. package/locales/de.js +3 -2
  220. package/locales/en.js +27 -2
  221. package/locales/fr.js +3 -2
  222. package/locales/ja.js +2 -2
  223. package/locales/pt.js +27 -2
  224. package/locales/ru.js +2 -2
  225. package/locales/zh-TW.js +26 -2
  226. package/locales/zh.js +26 -2
  227. package/package.json +5 -5
  228. package/release-notes.json +14 -0
  229. package/vendor/o1-connect/README.md +23 -0
  230. package/vendor/o1-connect/VENDOR.json +10 -0
  231. package/vendor/o1-connect/lib.d.mts +147 -0
  232. package/vendor/o1-connect/lib.mjs +1870 -0
  233. package/vendor/tree-sitter/tree-sitter-bash.wasm +0 -0
  234. package/vendor/tree-sitter/tree-sitter.wasm +0 -0
  235. package/web-shell/assets/{abnfDiagram-VCTEODGH-BvoMbUn4.js → abnfDiagram-VCTEODGH-PVbSspuv.js} +1 -1
  236. package/web-shell/assets/{arc-DbQBncMt.js → arc-VsWasC21.js} +1 -1
  237. package/web-shell/assets/{architectureDiagram-5GKGNRK7-C8RG0dgJ.js → architectureDiagram-5GKGNRK7-CQGJih80.js} +1 -1
  238. package/web-shell/assets/{blockDiagram-NRAW4CY4-pL2S69WR.js → blockDiagram-NRAW4CY4-Df9FTUp0.js} +1 -1
  239. package/web-shell/assets/{c4Diagram-UCG6FXSJ-BtqW-kE-.js → c4Diagram-UCG6FXSJ-Cq2wSg56.js} +1 -1
  240. package/web-shell/assets/channel-8zIIJdbY.js +1 -0
  241. package/web-shell/assets/{chunk-2Q5K7J3B-DH8xQogC.js → chunk-2Q5K7J3B-Chp7JPzQ.js} +1 -1
  242. package/web-shell/assets/{chunk-5VM5RSS4-BH3myFbn.js → chunk-5VM5RSS4-gml5kfyF.js} +1 -1
  243. package/web-shell/assets/{chunk-F27PBJKO-iY2yWixd.js → chunk-F27PBJKO-By_hW2gT.js} +1 -1
  244. package/web-shell/assets/{chunk-G27WJ6UU-D_j7Xo_Y.js → chunk-G27WJ6UU-8NLL7TjL.js} +1 -1
  245. package/web-shell/assets/{chunk-JWPE2WC7-CxBsiYSx.js → chunk-JWPE2WC7-Bz8c6lcT.js} +1 -1
  246. package/web-shell/assets/{chunk-LCL6LL3I-DQbc3B6E.js → chunk-LCL6LL3I-ZkGZaXXw.js} +1 -1
  247. package/web-shell/assets/{chunk-POPQ4Y6H-BdaRtQLf.js → chunk-POPQ4Y6H-B8iYNlKK.js} +1 -1
  248. package/web-shell/assets/{chunk-SVP7TREG-D58Lphw-.js → chunk-SVP7TREG-DwVdGXs4.js} +1 -1
  249. package/web-shell/assets/{chunk-XXDRQBXY-BSmrr5ej.js → chunk-XXDRQBXY-CsCbtvRS.js} +1 -1
  250. package/web-shell/assets/classDiagram-DTDB5LWJ-BZiDhVAk.js +1 -0
  251. package/web-shell/assets/classDiagram-v2-JRS7N3AN-BZiDhVAk.js +1 -0
  252. package/web-shell/assets/{cose-bilkent-JH36ORCC-DYv3YjD8.js → cose-bilkent-JH36ORCC-DwnxQIaV.js} +1 -1
  253. package/web-shell/assets/{cynefin-OW5HDTMX-ChRVKOIc.js → cynefin-OW5HDTMX-BvGw520V.js} +1 -1
  254. package/web-shell/assets/{cynefinDiagram-5FMLGOSQ-2dgun5lr.js → cynefinDiagram-5FMLGOSQ-DErV7NUm.js} +1 -1
  255. package/web-shell/assets/{dagre-3AP2YEHR-IGE15SAI.js → dagre-3AP2YEHR-DUKJascy.js} +1 -1
  256. package/web-shell/assets/{diagram-S7CK7UJ4-BHcZWynB.js → diagram-S7CK7UJ4-DC2A1fK2.js} +1 -1
  257. package/web-shell/assets/{diagram-UQ7AKVKN-DalYrZk-.js → diagram-UQ7AKVKN-Dv3eUqcO.js} +1 -1
  258. package/web-shell/assets/{diagram-VSXAHHWV-CMKHsUs7.js → diagram-VSXAHHWV-B_k7qlTN.js} +1 -1
  259. package/web-shell/assets/{diagram-VX7I27RA-DgrQKlmX.js → diagram-VX7I27RA-DH7Bx528.js} +1 -1
  260. package/web-shell/assets/{diagram-Z3DM3KII-CVdgT4Q4.js → diagram-Z3DM3KII-CtOVvMVx.js} +1 -1
  261. package/web-shell/assets/{ebnfDiagram-PWID7BFC-BV7RGD_D.js → ebnfDiagram-PWID7BFC-DrkkLJdI.js} +1 -1
  262. package/web-shell/assets/{erDiagram-SSCWMZ5O-NbSHPXJb.js → erDiagram-SSCWMZ5O-C0uNwMNd.js} +1 -1
  263. package/web-shell/assets/{flowDiagram-A5DVABFB-BnKFiusj.js → flowDiagram-A5DVABFB-B3sbye5k.js} +1 -1
  264. package/web-shell/assets/{ganttDiagram-EL5Y4UJY-BVBViIDh.js → ganttDiagram-EL5Y4UJY-D3Ms91Ay.js} +1 -1
  265. package/web-shell/assets/{gitGraphDiagram-WWUBYQGX-Dpi8eTTY.js → gitGraphDiagram-WWUBYQGX-BHrKQ3iH.js} +1 -1
  266. package/web-shell/assets/{index-DtvQ3DEH.js → index-BL5DGwqU.js} +4 -4
  267. package/web-shell/assets/{index-D-kPo23X.js → index-DvuDn2OC.js} +1 -1
  268. package/web-shell/assets/{infoDiagram-RXCK75RN-BpAv0FDb.js → infoDiagram-RXCK75RN-DWyT73_I.js} +1 -1
  269. package/web-shell/assets/{ishikawaDiagram-5VMMS53U-B7958rb5.js → ishikawaDiagram-5VMMS53U-DybYyMJT.js} +1 -1
  270. package/web-shell/assets/{journeyDiagram-EYS64GPL-C3KfVyTV.js → journeyDiagram-EYS64GPL-D-v8PiYH.js} +1 -1
  271. package/web-shell/assets/{kanban-definition-3QL26DDD-DXrBR6gr.js → kanban-definition-3QL26DDD-BUWrNJxx.js} +1 -1
  272. package/web-shell/assets/{layout-D4sWObAV.js → layout-DTXwh-A4.js} +1 -1
  273. package/web-shell/assets/{linear-Cwd2KGkf.js → linear-C8iFKFtJ.js} +1 -1
  274. package/web-shell/assets/{mermaid.core-B2gOqjPo.js → mermaid.core-DZcsifbF.js} +6 -6
  275. package/web-shell/assets/{mindmap-definition-FBJOCRG2-Oxi-8t2C.js → mindmap-definition-FBJOCRG2-D1OyJM6T.js} +1 -1
  276. package/web-shell/assets/{pegDiagram-XKGWAZYB-XhK_Omz8.js → pegDiagram-XKGWAZYB-b2dM3687.js} +1 -1
  277. package/web-shell/assets/{pieDiagram-E7YTZNPT-th4P1FI2.js → pieDiagram-E7YTZNPT-n-qlKbdF.js} +1 -1
  278. package/web-shell/assets/{quadrantDiagram-AXDQQJYC-BWHRjMh9.js → quadrantDiagram-AXDQQJYC-DbiRHm_L.js} +1 -1
  279. package/web-shell/assets/{railroadDiagram-O6MQD6OU-D4h49f-M.js → railroadDiagram-O6MQD6OU-CAUM_6wo.js} +1 -1
  280. package/web-shell/assets/{requirementDiagram-EFPCY7ZU-DSG8xXCi.js → requirementDiagram-EFPCY7ZU-D_YoabOy.js} +1 -1
  281. package/web-shell/assets/{sankeyDiagram-P5KCCOFB-Tt-9UBxT.js → sankeyDiagram-P5KCCOFB-C17c2F-F.js} +1 -1
  282. package/web-shell/assets/{sequenceDiagram-WJ2MYXX4-BOh5x5rY.js → sequenceDiagram-WJ2MYXX4-DtEF8IM9.js} +1 -1
  283. package/web-shell/assets/{sizeCapture-X5ZJPWSS-DP0VY8RY.js → sizeCapture-X5ZJPWSS-CEayyeYf.js} +1 -1
  284. package/web-shell/assets/{stateDiagram-HBIQ2CUA-Bqhxdcnc.js → stateDiagram-HBIQ2CUA-D34ANpKU.js} +1 -1
  285. package/web-shell/assets/stateDiagram-v2-4QOOHH4V-BkgMHPaH.js +1 -0
  286. package/web-shell/assets/{swimlanes-XN3QIQJK-g1wrt3v8.js → swimlanes-XN3QIQJK-CxuDoZvW.js} +1 -1
  287. package/web-shell/assets/swimlanesDiagram-VK2B7HYN-B_dlOslo.js +8 -0
  288. package/web-shell/assets/{timeline-definition-24CTP7MA-GGkTR6Uu.js → timeline-definition-24CTP7MA-ewm8t6bY.js} +1 -1
  289. package/web-shell/assets/{vennDiagram-4TSXK5OY-yDSKCBuy.js → vennDiagram-4TSXK5OY-J5Luz0Pz.js} +1 -1
  290. package/web-shell/assets/{wardleyDiagram-VM6X3IG4-Cmfcjc_f.js → wardleyDiagram-VM6X3IG4-g9-5UNQz.js} +1 -1
  291. package/web-shell/assets/{xychartDiagram-S5SC5T6Z-B9EjOHFX.js → xychartDiagram-S5SC5T6Z-Dy0uNlVX.js} +1 -1
  292. package/web-shell/index.html +1 -1
  293. package/web-shell/sw.js +1 -1
  294. package/web-shell/assets/channel-D6P_9m4V.js +0 -1
  295. package/web-shell/assets/classDiagram-DTDB5LWJ-BW3KY7XN.js +0 -1
  296. package/web-shell/assets/classDiagram-v2-JRS7N3AN-BW3KY7XN.js +0 -1
  297. package/web-shell/assets/stateDiagram-v2-4QOOHH4V-X9Lr9vnN.js +0 -1
  298. package/web-shell/assets/swimlanesDiagram-VK2B7HYN-DCoSHHNU.js +0 -8
@@ -0,0 +1,1870 @@
1
+ // o1-connect-lib 9.0.0 - https://github.com/organizaone/o1-gateway (MIT)
2
+
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.';
10
+ var PIN = /^sha256\/[A-Za-z0-9+/]{43}=$/;
11
+ var TOKEN = /^[0-9a-f]{64}$/;
12
+ var DEVICE = /^[a-z0-9][a-z0-9_-]{0,31}$/i;
13
+ var MAX_PINS = 4;
14
+ var ConnectionCodeError = class extends Error {};
15
+ function pinOfSpki(spkiDer) {
16
+ return `sha256/${createHash('sha256').update(spkiDer).digest('base64')}`;
17
+ }
18
+ function isPin(s) {
19
+ return PIN.test(s);
20
+ }
21
+ 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('-');
27
+ }
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`;
31
+ }
32
+ function isLoopbackHost(hostname) {
33
+ return (
34
+ hostname === '127.0.0.1' || hostname === 'localhost' || hostname === '[::1]'
35
+ );
36
+ }
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;
41
+ let url;
42
+ try {
43
+ url = new URL(String(o.url));
44
+ } 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
+ };
82
+ }
83
+ function decodeConnectionCode(s) {
84
+ 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
+ );
89
+ let parsed;
90
+ try {
91
+ parsed = JSON.parse(
92
+ Buffer.from(text.slice(CODE_PREFIX.length), 'base64url').toString('utf8'),
93
+ );
94
+ } catch {
95
+ throw new ConnectionCodeError(
96
+ 'the code is damaged: copy it again from the console',
97
+ );
98
+ }
99
+ return validateCode(parsed);
100
+ }
101
+
102
+ // src/client/inner.ts
103
+ import tls3 from 'node:tls';
104
+
105
+ // src/client/peer-cert.ts
106
+ var seen = /* @__PURE__ */ new WeakMap();
107
+ function peerCertificate(socket) {
108
+ const kept = seen.get(socket);
109
+ if (kept) return kept;
110
+ const cert = socket.getPeerX509Certificate();
111
+ if (cert) seen.set(socket, cert);
112
+ return cert;
113
+ }
114
+
115
+ // 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';
122
+
123
+ // src/shared/tunnel-poll.ts
124
+ var POLL_PATH = '/tunnel/poll';
125
+ var POLL_VERSION = 1;
126
+ var SESSION_BYTES = 32;
127
+ var MAX_UP = 256 * 1024;
128
+ var MAX_DOWN = 1024 * 1024;
129
+ var POLL_WAIT_MS = 2e4;
130
+ var TUNNEL_BUSY = 'tunnel_busy';
131
+ var REQUEST_HEAD = 1 + SESSION_BYTES + 8 + 8 + 1;
132
+ var RESPONSE_HEAD = 1 + SESSION_BYTES + 8 + 1;
133
+ var FLAG_CLOSE = 1;
134
+ var FLAG_POLL = 2;
135
+ var FLAG_OPEN = 4;
136
+ var FLAG_CLOSED = 1;
137
+ var PollFormatError = class extends Error {};
138
+ var ZERO_SESSION = Buffer.alloc(SESSION_BYTES);
139
+ function sessionOf(id) {
140
+ if (id.length !== SESSION_BYTES)
141
+ throw new PollFormatError('the session id must be 32 bytes');
142
+ return id;
143
+ }
144
+ function requestSession(id) {
145
+ if (sessionOf(id).equals(ZERO_SESSION))
146
+ throw new PollFormatError('the session id must not be all zero');
147
+ return id;
148
+ }
149
+ function toU64(n, what) {
150
+ if (!Number.isSafeInteger(n) || n < 0)
151
+ throw new PollFormatError(`${what} is out of range`);
152
+ return BigInt(n);
153
+ }
154
+ function fromU64(b, at, what) {
155
+ const v = b.readBigUInt64BE(at);
156
+ if (v > BigInt(Number.MAX_SAFE_INTEGER))
157
+ throw new PollFormatError(`${what} is out of range`);
158
+ return Number(v);
159
+ }
160
+ function encodeRequest(r) {
161
+ if (r.data.length > MAX_UP)
162
+ throw new PollFormatError('the request carries too much data');
163
+ const head = Buffer.alloc(REQUEST_HEAD);
164
+ head[0] = POLL_VERSION;
165
+ 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);
172
+ return Buffer.concat([head, r.data]);
173
+ }
174
+ 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');
181
+ return {
182
+ session: Buffer.from(b.subarray(1, 33)),
183
+ downOffset: fromU64(b, 33, 'downOffset'),
184
+ closed: (b[41] & FLAG_CLOSED) !== 0,
185
+ data: Buffer.from(b.subarray(RESPONSE_HEAD)),
186
+ };
187
+ }
188
+
189
+ // src/client/proxy-route.ts
190
+ import http from 'node:http';
191
+ var LOOPBACK = /^(localhost|127(?:\.\d{1,3}){3}|::1)$/i;
192
+ 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
+ );
203
+ }
204
+ function proxyFor(target, env = process.env) {
205
+ const host = target.hostname.replace(/^\[|\]$/g, '').toLowerCase();
206
+ if (LOOPBACK.test(host)) return null;
207
+ const raw = (env.HTTPS_PROXY || env.https_proxy || '').trim();
208
+ if (!raw) return null;
209
+ if (bypassed(host, env.NO_PROXY || env.no_proxy || '')) return null;
210
+ let url;
211
+ try {
212
+ url = new URL(raw.includes('://') ? raw : `http://${raw}`);
213
+ } catch {
214
+ throw new Error('HTTPS_PROXY is not a valid URL');
215
+ }
216
+ if (url.protocol !== 'http:')
217
+ throw new Error('HTTPS_PROXY must be an http:// proxy URL');
218
+ const user = decodeURIComponent(url.username);
219
+ const pass = decodeURIComponent(url.password);
220
+ return {
221
+ host: url.hostname.replace(/^\[|\]$/g, ''),
222
+ port: Number(url.port || 80),
223
+ ...(user || pass
224
+ ? {
225
+ authorization: `Basic ${Buffer.from(`${user}:${pass}`).toString('base64')}`,
226
+ }
227
+ : {}),
228
+ };
229
+ }
230
+ var ProxyRefusedError = class extends Error {
231
+ 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
+ );
237
+ this.status = status;
238
+ }
239
+ status;
240
+ };
241
+ function connectVia(route, host, port) {
242
+ const authority = host.includes(':')
243
+ ? `[${host}]:${port}`
244
+ : `${host}:${port}`;
245
+ const req = http.request({
246
+ host: route.host,
247
+ port: route.port,
248
+ method: 'CONNECT',
249
+ path: authority,
250
+ agent: false,
251
+ headers: {
252
+ Host: authority,
253
+ ...(route.authorization
254
+ ? { 'Proxy-Authorization': route.authorization }
255
+ : {}),
256
+ },
257
+ });
258
+ const socket = new Promise((resolve, reject) => {
259
+ req.on('connect', (res, sock, head) => {
260
+ if (res.statusCode !== 200) {
261
+ sock.destroy();
262
+ reject(new ProxyRefusedError(res.statusCode ?? 0));
263
+ return;
264
+ }
265
+ if (head.length) sock.unshift(head);
266
+ resolve(sock);
267
+ });
268
+ req.on('response', (res) => {
269
+ res.resume();
270
+ reject(new ProxyRefusedError(res.statusCode ?? 0));
271
+ });
272
+ req.on('error', reject);
273
+ });
274
+ req.end();
275
+ return { socket, abort: () => req.destroy() };
276
+ }
277
+
278
+ // 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';
285
+
286
+ // src/client/ws-frame.ts
287
+ var OP = { cont: 0, text: 1, binary: 2, close: 8, ping: 9, pong: 10 };
288
+ var WsProtocolError = class extends Error {};
289
+ function encodeFrame(opcode, payload, mask, fin = true) {
290
+ const n = payload.length;
291
+ const b0 = (fin ? 128 : 0) | opcode;
292
+ const m = mask ? 128 : 0;
293
+ let head;
294
+ if (n < 126) head = Buffer.from([b0, m | n]);
295
+ else if (n < 65536) head = Buffer.from([b0, m | 126, n >> 8, n & 255]);
296
+ else {
297
+ head = Buffer.alloc(10);
298
+ head[0] = b0;
299
+ head[1] = m | 127;
300
+ head.writeBigUInt64BE(BigInt(n), 2);
301
+ }
302
+ if (!mask) return Buffer.concat([head, payload]);
303
+ const body = Buffer.from(payload);
304
+ for (let i = 0; i < body.length; i++) body[i] ^= mask[i & 3];
305
+ return Buffer.concat([head, mask, body]);
306
+ }
307
+ var FrameParser = class {
308
+ constructor(maxPayload = 16 * 1024 * 1024) {
309
+ this.maxPayload = maxPayload;
310
+ }
311
+ maxPayload;
312
+ buf = Buffer.alloc(0);
313
+ push(chunk) {
314
+ this.buf = this.buf.length ? Buffer.concat([this.buf, chunk]) : chunk;
315
+ const out = [];
316
+ for (;;) {
317
+ if (this.buf.length < 2) return out;
318
+ const b0 = this.buf[0];
319
+ 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');
323
+ const opcode = b0 & 15;
324
+ const fin = (b0 & 128) !== 0;
325
+ let n = b1 & 127;
326
+ let off = 2;
327
+ if (n === 126) {
328
+ if (this.buf.length < 4) return out;
329
+ n = this.buf.readUInt16BE(2);
330
+ off = 4;
331
+ } else if (n === 127) {
332
+ if (this.buf.length < 10) return out;
333
+ const big = this.buf.readBigUInt64BE(2);
334
+ if (big > BigInt(this.maxPayload))
335
+ throw new WsProtocolError('frame too large');
336
+ n = Number(big);
337
+ off = 10;
338
+ }
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');
342
+ if (this.buf.length < off + n) return out;
343
+ out.push({ fin, opcode, payload: this.buf.subarray(off, off + n) });
344
+ this.buf = this.buf.subarray(off + n);
345
+ }
346
+ }
347
+ };
348
+
349
+ // src/client/ws-client.ts
350
+ var TunnelBlockedError = class extends Error {
351
+ constructor(status, detail) {
352
+ super(
353
+ detail ? `tunnel blocked: ${detail}` : `tunnel blocked (HTTP ${status})`,
354
+ );
355
+ this.status = status;
356
+ }
357
+ status;
358
+ };
359
+ var GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
360
+ function defaultCa() {
361
+ const get = tls.getCACertificates;
362
+ if (!get) return void 0;
363
+ try {
364
+ return [...get('default'), ...get('system')];
365
+ } catch {
366
+ return void 0;
367
+ }
368
+ }
369
+ function openWebSocket(url, opts) {
370
+ const secure = url.protocol === 'https:';
371
+ const key = randomBytes(16).toString('base64');
372
+ const hostname = url.hostname.replace(/^\[|\]$/g, '');
373
+ const port = Number(url.port || (secure ? 443 : 80));
374
+ return new Promise((resolve, reject) => {
375
+ let done = false;
376
+ let req;
377
+ const connecting = {};
378
+ const settle = (err, value) => {
379
+ if (done) return;
380
+ done = true;
381
+ clearTimeout(timer);
382
+ if (err) reject(err);
383
+ else resolve(value);
384
+ };
385
+ const timer = setTimeout(() => {
386
+ connecting.abort?.();
387
+ req?.destroy();
388
+ settle(new Error('tunnel connect timeout'));
389
+ }, opts.timeoutMs ?? 15e3);
390
+ timer.unref();
391
+ const common = {
392
+ host: hostname,
393
+ port,
394
+ path: url.pathname,
395
+ method: 'GET',
396
+ headers: {
397
+ 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(),
410
+ };
411
+ const upgrade = (tunnelled) => {
412
+ if (done) {
413
+ tunnelled?.destroy();
414
+ return;
415
+ }
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 });
427
+ req = r;
428
+ r.on('response', (res) => {
429
+ res.resume();
430
+ settle(new TunnelBlockedError(res.statusCode ?? 0));
431
+ });
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
+ ) {
442
+ sock.destroy();
443
+ settle(new TunnelBlockedError(101));
444
+ return;
445
+ }
446
+ 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
+ });
461
+ });
462
+ r.end();
463
+ };
464
+ let route;
465
+ try {
466
+ route = proxyFor(url, opts.env ?? process.env);
467
+ } catch (err) {
468
+ settle(err);
469
+ return;
470
+ }
471
+ if (!route) {
472
+ upgrade();
473
+ return;
474
+ }
475
+ const via = connectVia(route, hostname, port);
476
+ 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
+ );
484
+ });
485
+ }
486
+ function wrap(sock, head, pingMs) {
487
+ const parser = new FrameParser();
488
+ let closeSent = false;
489
+ const send2 = (opcode, payload, cb) => {
490
+ sock.write(encodeFrame(opcode, payload, randomBytes(4)), cb);
491
+ };
492
+ const duplex = new Duplex({
493
+ read() {
494
+ sock.resume();
495
+ },
496
+ write(chunk, _enc, cb) {
497
+ send2(OP.binary, chunk, cb);
498
+ },
499
+ final(cb) {
500
+ if (!closeSent) {
501
+ closeSent = true;
502
+ send2(OP.close, Buffer.from([3, 232]));
503
+ }
504
+ sock.end();
505
+ cb();
506
+ },
507
+ destroy(err, cb) {
508
+ clearInterval(pinger);
509
+ sock.destroy();
510
+ cb(err);
511
+ },
512
+ });
513
+ const failFrame = (err) => {
514
+ setImmediate(() => duplex.destroy(err));
515
+ };
516
+ const onData = (chunk) => {
517
+ let frames;
518
+ try {
519
+ frames = parser.push(chunk);
520
+ } catch (err) {
521
+ failFrame(
522
+ err instanceof WsProtocolError ? err : new WsProtocolError(String(err)),
523
+ );
524
+ return;
525
+ }
526
+ for (const f of frames) {
527
+ if (f.opcode === OP.binary || f.opcode === OP.cont) {
528
+ if (!duplex.push(Buffer.from(f.payload))) sock.pause();
529
+ } else if (f.opcode === OP.ping) {
530
+ send2(OP.pong, Buffer.from(f.payload));
531
+ } else if (f.opcode === OP.close) {
532
+ if (!closeSent) {
533
+ closeSent = true;
534
+ send2(OP.close, Buffer.from(f.payload.subarray(0, 2)));
535
+ }
536
+ duplex.push(null);
537
+ sock.end();
538
+ } else if (f.opcode === OP.text) {
539
+ failFrame(new WsProtocolError('text frame on a binary tunnel'));
540
+ }
541
+ }
542
+ };
543
+ sock.on('data', onData);
544
+ sock.on('end', () => duplex.push(null));
545
+ sock.on('error', (err) => duplex.destroy(err));
546
+ sock.on('close', () => {
547
+ clearInterval(pinger);
548
+ if (!duplex.destroyed) duplex.destroy();
549
+ });
550
+ const pinger = setInterval(() => send2(OP.ping, Buffer.alloc(0)), pingMs);
551
+ pinger.unref();
552
+ if (head.length) onData(head);
553
+ return duplex;
554
+ }
555
+
556
+ // src/client/poll-client.ts
557
+ var SessionGoneError = class extends Error {
558
+ constructor() {
559
+ super('tunnel session gone');
560
+ }
561
+ };
562
+ var EMPTY = Buffer.alloc(0);
563
+ var MAX_ANSWER = RESPONSE_HEAD + MAX_DOWN;
564
+ var FATAL_STATUS = /* @__PURE__ */ new Set([400, 403, 429]);
565
+ var delay = (ms) => new Promise((r) => setTimeout(r, ms));
566
+ function isBusy(r) {
567
+ if (r.status !== 503 || r.body.length > 4096) return false;
568
+ try {
569
+ return JSON.parse(r.body.toString('utf8')).error?.type === TUNNEL_BUSY;
570
+ } catch {
571
+ return false;
572
+ }
573
+ }
574
+ 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
+ };
582
+ }
583
+ function makeExchanger(base, o) {
584
+ const secure = base.protocol === 'https:';
585
+ const hostname = base.hostname.replace(/^\[|\]$/g, '');
586
+ 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
+ };
592
+ const route = proxyFor(base, o.env ?? process.env);
593
+ 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 });
597
+ if (route) {
598
+ agent.createConnection = (_opts, cb) => {
599
+ const via = connectVia(route, hostname, port);
600
+ let settled = false;
601
+ const once = (err, sock) => {
602
+ if (settled) {
603
+ sock?.destroy();
604
+ return;
605
+ }
606
+ settled = true;
607
+ clearTimeout(timer);
608
+ cb(err, sock);
609
+ };
610
+ const timer = setTimeout(() => {
611
+ once(new Error('tunnel connect timeout'));
612
+ via.abort();
613
+ }, connectMs);
614
+ 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
+ ),
626
+ );
627
+ return void 0;
628
+ };
629
+ }
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);
684
+ });
685
+ return { post, destroy: () => agent.destroy() };
686
+ }
687
+ var PollStream = class {
688
+ constructor(ex, session, opts) {
689
+ this.ex = ex;
690
+ this.session = session;
691
+ this.o = settings(opts);
692
+ this.duplex = new Duplex2({
693
+ read: () => void 0,
694
+ write: (chunk, _enc, cb) => {
695
+ this.pending.push(Buffer.from(chunk));
696
+ this.pendingSize += chunk.length;
697
+ if (this.pendingSize > MAX_UP) this.held.push(() => cb());
698
+ else cb();
699
+ this.kickUp();
700
+ },
701
+ final: (cb) => {
702
+ this.finishing = true;
703
+ this.kickUp();
704
+ cb();
705
+ },
706
+ destroy: (err, cb) => {
707
+ this.shutdown(true);
708
+ cb(err);
709
+ },
710
+ });
711
+ void this.downLoop();
712
+ }
713
+ ex;
714
+ session;
715
+ duplex;
716
+ o;
717
+ /** Upstream bytes the proxy has confirmed. */
718
+ sent = 0;
719
+ /** Downstream bytes received. */
720
+ received = 0;
721
+ pending = [];
722
+ pendingSize = 0;
723
+ held = [];
724
+ upRunning = false;
725
+ finishing = false;
726
+ closed = false;
727
+ kickUp() {
728
+ if (!this.upRunning && !this.closed) void this.upLoop();
729
+ }
730
+ async upLoop() {
731
+ this.upRunning = true;
732
+ try {
733
+ await delay(this.o.coalesceMs);
734
+ while (!this.closed && this.pendingSize > 0) {
735
+ 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
+ );
748
+ this.sent += data.length;
749
+ while (this.held.length > 0 && this.pendingSize <= MAX_UP)
750
+ this.held.shift()();
751
+ }
752
+ if (this.finishing && !this.closed && this.pendingSize === 0)
753
+ this.shutdown(true);
754
+ } catch (err) {
755
+ this.fail(err);
756
+ } finally {
757
+ this.upRunning = false;
758
+ }
759
+ if (!this.closed && this.pendingSize > 0) this.kickUp();
760
+ }
761
+ takePending() {
762
+ const all = Buffer.concat(this.pending);
763
+ const data = all.subarray(0, MAX_UP);
764
+ const rest = all.subarray(MAX_UP);
765
+ this.pending = rest.length > 0 ? [rest] : [];
766
+ this.pendingSize = rest.length;
767
+ return data;
768
+ }
769
+ async downLoop() {
770
+ try {
771
+ 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
+ );
784
+ if (this.closed) return;
785
+ if (r.downOffset > this.received)
786
+ throw new Error('tunnel stream out of order');
787
+ const skip = this.received - r.downOffset;
788
+ if (skip < r.data.length) {
789
+ const fresh = Buffer.from(r.data.subarray(skip));
790
+ this.received += fresh.length;
791
+ this.duplex.push(fresh);
792
+ }
793
+ if (r.closed) {
794
+ this.duplex.push(null);
795
+ this.shutdown(true);
796
+ return;
797
+ }
798
+ }
799
+ } catch (err) {
800
+ this.fail(err);
801
+ }
802
+ }
803
+ async exchange(req, timeoutMs) {
804
+ const body = encodeRequest(req);
805
+ let firstFailure = 0;
806
+ let firstBusy = 0;
807
+ let wait = 250;
808
+ for (;;) {
809
+ if (this.closed) throw new Error('tunnel closed');
810
+ let failure;
811
+ let busy = false;
812
+ try {
813
+ const r = await this.ex.post(body, timeoutMs);
814
+ if (r.status === 200) return decodeResponse(r.body);
815
+ if (r.status === 404) throw new SessionGoneError();
816
+ failure = new TunnelBlockedError(r.status);
817
+ if (FATAL_STATUS.has(r.status)) throw failure;
818
+ busy = isBusy(r);
819
+ } 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;
824
+ failure = err;
825
+ }
826
+ if (busy) {
827
+ const t2 = Date.now();
828
+ if (firstBusy === 0) firstBusy = t2;
829
+ if (t2 - firstBusy >= this.o.busyForMs) throw failure;
830
+ firstFailure = 0;
831
+ await delay(Math.min(wait, 1e3));
832
+ wait = Math.min(wait * 2, 4e3);
833
+ continue;
834
+ }
835
+ const t = Date.now();
836
+ if (firstFailure === 0) firstFailure = t;
837
+ if (t - firstFailure >= this.o.retryForMs) throw failure;
838
+ await delay(wait);
839
+ wait = Math.min(wait * 2, 4e3);
840
+ }
841
+ }
842
+ fail(err) {
843
+ if (this.closed) return;
844
+ this.closed = true;
845
+ this.ex.destroy();
846
+ this.duplex.destroy(err);
847
+ }
848
+ shutdown(sendClose) {
849
+ if (this.closed) return;
850
+ this.closed = true;
851
+ 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());
865
+ } else {
866
+ this.ex.destroy();
867
+ }
868
+ if (!this.duplex.destroyed) this.duplex.destroy();
869
+ }
870
+ };
871
+ async function openPollStream(base, opts = {}) {
872
+ const ex = makeExchanger(base, opts);
873
+ 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
+ });
883
+ const o = settings(opts);
884
+ let first;
885
+ let firstFailure = 0;
886
+ let wait = 100;
887
+ while (first === void 0) {
888
+ try {
889
+ first = await ex.post(open2, o.timeoutMs);
890
+ } catch (err) {
891
+ const t = Date.now();
892
+ if (firstFailure === 0) firstFailure = t;
893
+ if (err.code !== 'ECONNRESET' || t - firstFailure >= o.retryForMs) {
894
+ ex.destroy();
895
+ throw err;
896
+ }
897
+ await delay(wait);
898
+ wait = Math.min(wait * 2, 4e3);
899
+ }
900
+ }
901
+ if (first.status !== 200) {
902
+ ex.destroy();
903
+ throw new TunnelBlockedError(first.status);
904
+ }
905
+ let answered;
906
+ try {
907
+ answered = decodeResponse(first.body).session;
908
+ } catch {}
909
+ if (!answered?.equals(session)) {
910
+ ex.destroy();
911
+ throw new TunnelBlockedError(
912
+ 200,
913
+ "the answer is not the tunnel's (a filter's page?)",
914
+ );
915
+ }
916
+ const stream = new PollStream(ex, session, opts).duplex;
917
+ return {
918
+ stream,
919
+ outer: first.outer,
920
+ ...(first.outerError ? { outerError: first.outerError } : {}),
921
+ };
922
+ }
923
+
924
+ // src/client/inner.ts
925
+ var IdentityMismatchError = class extends Error {
926
+ constructor(received) {
927
+ super('tunnel identity mismatch');
928
+ this.received = received;
929
+ }
930
+ received;
931
+ };
932
+ 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
+ });
950
+ 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());
964
+ try {
965
+ await new Promise((resolve, reject) => {
966
+ let settled = false;
967
+ const finish = (err) => {
968
+ if (settled) return;
969
+ settled = true;
970
+ clearTimeout(timer);
971
+ socket.off('close', onClose);
972
+ socket.off('secureConnect', onSecure);
973
+ if (err === null) {
974
+ socket.off('error', onError);
975
+ resolve();
976
+ return;
977
+ }
978
+ socket.once('close', () => socket.off('error', onError));
979
+ reject(err);
980
+ };
981
+ const onError = (err) => finish(err);
982
+ const onClose = () => finish(new Error('tunnel closed during handshake'));
983
+ const onSecure = () => finish(null);
984
+ const timer = setTimeout(
985
+ () => finish(new Error('tunnel handshake timeout')),
986
+ opts.timeoutMs ?? 15e3,
987
+ );
988
+ timer.unref();
989
+ socket.on('error', onError);
990
+ socket.on('close', onClose);
991
+ socket.on('secureConnect', onSecure);
992
+ });
993
+ } catch (err) {
994
+ socket.destroy();
995
+ throw err;
996
+ }
997
+ socket.on('error', () => socket.destroy());
998
+ const peer = peerCertificate(socket);
999
+ const received = peer
1000
+ ? pinOfSpki(peer.publicKey.export({ type: 'spki', format: 'der' }))
1001
+ : 'none';
1002
+ if (!pins.includes(received)) {
1003
+ socket.destroy();
1004
+ throw new IdentityMismatchError(received);
1005
+ }
1006
+ return socket;
1007
+ }
1008
+
1009
+ // 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';
1016
+
1017
+ // src/client/tunnel-agent.ts
1018
+ import http4 from 'node:http';
1019
+ var TUNNEL_AGENT_MAX_SOCKETS = 4;
1020
+ 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;
1028
+ return true;
1029
+ }
1030
+ function reasonOf(err) {
1031
+ if (err instanceof TunnelBlockedError)
1032
+ return err.status === 101 || err.status === 200
1033
+ ? err.message
1034
+ : `HTTP ${err.status}`;
1035
+ return err instanceof Error ? err.message : String(err);
1036
+ }
1037
+ var BackoffError = class extends Error {
1038
+ constructor(waitMs) {
1039
+ super('tunnel identity mismatch - waiting before retry');
1040
+ this.waitMs = waitMs;
1041
+ }
1042
+ waitMs;
1043
+ };
1044
+ var baseAddRequest = http4.Agent.prototype.addRequest;
1045
+ var TunnelAgent = class extends http4.Agent {
1046
+ constructor(target, backoff, events = {}) {
1047
+ super({
1048
+ keepAlive: true,
1049
+ maxSockets: TUNNEL_AGENT_MAX_SOCKETS,
1050
+ maxFreeSockets: TUNNEL_AGENT_MAX_SOCKETS,
1051
+ });
1052
+ this.target = target;
1053
+ this.backoff = backoff;
1054
+ this.events = events;
1055
+ this.mode = target.transport ?? 'auto';
1056
+ this.using = this.mode === 'post' ? 'post' : 'ws';
1057
+ this.connect = target.connect ?? connectInner;
1058
+ this.pins = [...target.pins];
1059
+ this.on('free', () => this.drain());
1060
+ }
1061
+ target;
1062
+ backoff;
1063
+ events;
1064
+ /** Tunnels being opened: not yet in `sockets`, where Node would count them. */
1065
+ opening = 0;
1066
+ /** Requests waiting for a tunnel, in arrival order. */
1067
+ waiting = [];
1068
+ using;
1069
+ mode;
1070
+ connect;
1071
+ pins;
1072
+ /** Destroyed: no tunnel is opened any more, and one still opening is closed when it arrives. */
1073
+ closed = false;
1074
+ /**
1075
+ * The pins new tunnels are checked against (and the newest one asked for),
1076
+ * from now on: what pin-sync learned through a pinned tunnel. Tunnels
1077
+ * already open keep going.
1078
+ */
1079
+ setPins(pins) {
1080
+ this.pins = [...pins];
1081
+ }
1082
+ get transport() {
1083
+ return this.using;
1084
+ }
1085
+ live() {
1086
+ let n = this.opening;
1087
+ for (const list of Object.values(this.sockets)) n += list?.length ?? 0;
1088
+ for (const list of Object.values(this.freeSockets)) n += list?.length ?? 0;
1089
+ return n;
1090
+ }
1091
+ hasFree() {
1092
+ return Object.values(this.freeSockets).some((list) =>
1093
+ list?.some((s) => !s.destroyed),
1094
+ );
1095
+ }
1096
+ canServe() {
1097
+ return this.hasFree() || this.live() < TUNNEL_AGENT_MAX_SOCKETS;
1098
+ }
1099
+ /** Called by http.ClientRequest for every request; not in @types/node. */
1100
+ addRequest(req, options) {
1101
+ if (!this.canServe()) {
1102
+ this.waiting.push({ req, options });
1103
+ req.once('close', () => {
1104
+ const i = this.waiting.findIndex((w) => w.req === req);
1105
+ if (i >= 0) this.waiting.splice(i, 1);
1106
+ });
1107
+ return;
1108
+ }
1109
+ baseAddRequest.call(this, req, options);
1110
+ }
1111
+ drain() {
1112
+ while (this.waiting.length > 0 && this.canServe()) {
1113
+ const next = this.waiting.shift();
1114
+ if (next.req.destroyed) continue;
1115
+ baseAddRequest.call(this, next.req, next.options);
1116
+ }
1117
+ }
1118
+ /** Whether destroy() ran: the agent opens nothing any more. */
1119
+ get destroyed() {
1120
+ return this.closed;
1121
+ }
1122
+ destroy() {
1123
+ this.closed = true;
1124
+ for (const { req } of this.waiting.splice(0)) {
1125
+ const err = new Error('tunnel agent closed');
1126
+ req.destroy(err);
1127
+ process.nextTick(() => req.emit('error', err));
1128
+ }
1129
+ super.destroy();
1130
+ }
1131
+ // Node calls this with a callback for asynchronous sockets; returning nothing
1132
+ // tells it to wait for the callback.
1133
+ createConnection(_options, callback) {
1134
+ const done = callback ?? (() => void 0);
1135
+ if (this.closed) {
1136
+ done(new Error('tunnel agent closed'), void 0);
1137
+ return void 0;
1138
+ }
1139
+ const wait = this.backoff.blockedMs();
1140
+ if (wait > 0) {
1141
+ done(new BackoffError(wait), void 0);
1142
+ return void 0;
1143
+ }
1144
+ 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(
1175
+ (socket) => {
1176
+ this.opening -= 1;
1177
+ if (this.closed) {
1178
+ socket.destroy();
1179
+ done(new Error('tunnel agent closed'), void 0);
1180
+ return;
1181
+ }
1182
+ this.backoff.success();
1183
+ this.events.onConnected?.();
1184
+ socket.once('close', () => process.nextTick(() => this.drain()));
1185
+ done(null, socket);
1186
+ },
1187
+ (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
+ },
1196
+ );
1197
+ return void 0;
1198
+ }
1199
+ };
1200
+
1201
+ // src/client/local-server.ts
1202
+ function newLocalKey() {
1203
+ return `o1gwl_${randomBytes3(32).toString('base64url')}`;
1204
+ }
1205
+ function hashLocalKey(key) {
1206
+ return createHash3('sha256').update(key, 'utf8').digest('hex');
1207
+ }
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]']);
1222
+ 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);
1233
+ }
1234
+ function keyOf(req) {
1235
+ const bearer = /^Bearer\s+(.+)$/i.exec(
1236
+ String(req.headers.authorization ?? '').trim(),
1237
+ );
1238
+ 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;
1241
+ }
1242
+ function sameHash(a, b) {
1243
+ const x = Buffer.from(a, 'hex');
1244
+ const y = Buffer.from(b, 'hex');
1245
+ return x.length === y.length && x.length > 0 && timingSafeEqual(x, y);
1246
+ }
1247
+ var REPLAY_MAX_BYTES = 10 * 1024 * 1024;
1248
+ function deadTunnel(err, reusedSocket) {
1249
+ if (err instanceof SessionGoneError) return true;
1250
+ const code = err?.code;
1251
+ return reusedSocket && (code === 'ECONNRESET' || code === 'EPIPE');
1252
+ }
1253
+ 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';
1257
+ if (err instanceof TunnelBlockedError) return err.message;
1258
+ return 'tunnel unavailable';
1259
+ }
1260
+ function startLocalServer(o) {
1261
+ const server = http5.createServer((req, res) => {
1262
+ 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');
1271
+ const key = keyOf(req);
1272
+ if (!key || !sameHash(hashLocalKey(key), o.localKeyHash))
1273
+ return send(res, 401, 'invalid or missing local key');
1274
+ const headers = {};
1275
+ for (const [name, value] of Object.entries(req.headers))
1276
+ if (!HOP.has(name) && value !== void 0) headers[name] = value;
1277
+ headers.host = o.target.host;
1278
+ headers.authorization = `Bearer ${o.deviceToken}`;
1279
+ let kept = [];
1280
+ let keptBytes = 0;
1281
+ req.on('data', (c) => {
1282
+ if (!kept) return;
1283
+ keptBytes += c.length;
1284
+ if (keptBytes > REPLAY_MAX_BYTES) kept = null;
1285
+ else kept.push(c);
1286
+ });
1287
+ let upstream;
1288
+ 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
+ );
1308
+ upstream = current;
1309
+ current.on('error', (err) => {
1310
+ if (
1311
+ !replay &&
1312
+ !res.headersSent &&
1313
+ kept &&
1314
+ deadTunnel(err, current.reusedSocket)
1315
+ ) {
1316
+ o.log?.(`${req.method} ${route} retry: the tunnel was gone`);
1317
+ const again = () => {
1318
+ if (kept && !res.destroyed) forward(true);
1319
+ else if (!res.destroyed) send(res, 502, describeError(err));
1320
+ };
1321
+ if (req.readableEnded) again();
1322
+ else {
1323
+ req.once('end', again);
1324
+ req.resume();
1325
+ }
1326
+ return;
1327
+ }
1328
+ o.log?.(`${req.method} ${route} failed: ${describeError(err)}`);
1329
+ if (res.headersSent) res.destroy();
1330
+ else if (err instanceof TunnelBlockedError && err.status === 429)
1331
+ send(res, 429, 'Too many attempts');
1332
+ else send(res, 502, describeError(err));
1333
+ });
1334
+ if (replay) current.end(Buffer.concat(kept ?? []));
1335
+ else req.pipe(current);
1336
+ };
1337
+ forward(false);
1338
+ res.on('close', () => {
1339
+ if (!res.writableFinished) upstream.destroy();
1340
+ });
1341
+ req.on('error', () => upstream.destroy());
1342
+ });
1343
+ return new Promise((resolve, reject) => {
1344
+ server.once('error', reject);
1345
+ server.listen(o.port, '127.0.0.1', () => {
1346
+ server.off('error', reject);
1347
+ resolve(server);
1348
+ });
1349
+ });
1350
+ }
1351
+
1352
+ // src/client/backoff.ts
1353
+ var IdentityBackoff = class {
1354
+ constructor(now = Date.now, baseMs = 6e4, maxMs = 60 * 6e4) {
1355
+ this.now = now;
1356
+ this.baseMs = baseMs;
1357
+ this.maxMs = maxMs;
1358
+ }
1359
+ now;
1360
+ baseMs;
1361
+ maxMs;
1362
+ failures = 0;
1363
+ until = 0;
1364
+ count = 0;
1365
+ since = null;
1366
+ blockedMs() {
1367
+ return Math.max(0, this.until - this.now());
1368
+ }
1369
+ failure() {
1370
+ const t = this.now();
1371
+ this.count += 1;
1372
+ this.since ??= t;
1373
+ this.until = t + Math.min(this.baseMs * 2 ** this.failures, this.maxMs);
1374
+ this.failures += 1;
1375
+ }
1376
+ success() {
1377
+ this.failures = 0;
1378
+ this.until = 0;
1379
+ this.count = 0;
1380
+ this.since = null;
1381
+ }
1382
+ snapshot() {
1383
+ return {
1384
+ mismatches: this.count,
1385
+ since: this.since,
1386
+ waitMs: this.blockedMs(),
1387
+ };
1388
+ }
1389
+ };
1390
+
1391
+ // src/client/pin-sync.ts
1392
+ import http6 from 'node:http';
1393
+ import tls4 from 'node:tls';
1394
+ function mergePins(own, listed, via) {
1395
+ const unchanged = { pins: [...own], added: [], dropped: [] };
1396
+ 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;
1404
+ const list = [...new Set(listed)];
1405
+ const added = list.filter((p) => !own.includes(p));
1406
+ if (list.includes(via)) {
1407
+ return { pins: list, added, dropped: own.filter((p) => !list.includes(p)) };
1408
+ }
1409
+ const room = Math.max(0, MAX_PINS - own.length);
1410
+ const learned = room > 0 ? added.slice(-room) : [];
1411
+ return { pins: [...own, ...learned], added: learned, dropped: [] };
1412
+ }
1413
+ function pinOfSocket(socket) {
1414
+ if (!(socket instanceof tls4.TLSSocket)) return null;
1415
+ const peer = peerCertificate(socket);
1416
+ return peer
1417
+ ? pinOfSpki(peer.publicKey.export({ type: 'spki', format: 'der' }))
1418
+ : null;
1419
+ }
1420
+ var MAX_BODY = 16 * 1024;
1421
+ var short = (pin) => fingerprint(pin).slice(0, 19);
1422
+ var PinSync = class {
1423
+ constructor(o) {
1424
+ this.o = o;
1425
+ this.current = [...o.pins];
1426
+ }
1427
+ o;
1428
+ current;
1429
+ last = Number.NEGATIVE_INFINITY;
1430
+ running = null;
1431
+ /** The pins in memory are not on disk yet (a save failed). */
1432
+ unsaved = false;
1433
+ /** config.bin belongs to another configuration now: nothing more is saved by this run. */
1434
+ saveStopped = false;
1435
+ get pins() {
1436
+ return [...this.current];
1437
+ }
1438
+ /** Asks the proxy now; one request at a time. */
1439
+ syncNow() {
1440
+ this.running ??= this.run().finally(() => {
1441
+ this.running = null;
1442
+ });
1443
+ return this.running;
1444
+ }
1445
+ /** Asks when the last try is older than the interval; failures are logged, never thrown. */
1446
+ maybeSync() {
1447
+ const now = (this.o.now ?? Date.now)();
1448
+ if (this.running || now - this.last < (this.o.intervalMs ?? 36e5)) return;
1449
+ 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
+ );
1455
+ }
1456
+ async run() {
1457
+ this.last = (this.o.now ?? Date.now)();
1458
+ const { listed, via } = await this.fetch();
1459
+ 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]);
1463
+ if (changed) {
1464
+ this.current = merged.pins;
1465
+ 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
+ );
1472
+ }
1473
+ if ((changed || this.unsaved) && !this.saveStopped) {
1474
+ try {
1475
+ if ((await this.o.save(this.pins)) === false) {
1476
+ 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
+ );
1481
+ }
1482
+ this.unsaved = false;
1483
+ } catch (err) {
1484
+ 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
+ );
1488
+ }
1489
+ }
1490
+ return { ...merged, via };
1491
+ }
1492
+ fetch() {
1493
+ const { target } = this.o;
1494
+ 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);
1541
+ req.end();
1542
+ });
1543
+ }
1544
+ };
1545
+
1546
+ // src/client/session.ts
1547
+ async function startTunnelSession(o) {
1548
+ const target = new URL(o.url);
1549
+ 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,
1568
+ },
1569
+ );
1570
+ const pinSync = new PinSync({
1571
+ agent,
1572
+ target,
1573
+ deviceToken: o.deviceToken,
1574
+ pins: o.pins,
1575
+ log: o.log,
1576
+ onChange: (pins) => agent.setPins(pins),
1577
+ save: o.savePins,
1578
+ stoppedLine: o.savePinsStoppedLine,
1579
+ });
1580
+ let server;
1581
+ 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
+ });
1590
+ } catch (err) {
1591
+ agent.destroy();
1592
+ throw err;
1593
+ }
1594
+ let closing = null;
1595
+ const close = () => {
1596
+ closing ??= new Promise((resolve) => {
1597
+ agent.destroy();
1598
+ server.close(() => resolve());
1599
+ server.closeIdleConnections();
1600
+ setImmediate(() => server.closeAllConnections());
1601
+ });
1602
+ return closing;
1603
+ };
1604
+ return { agent, pinSync, server, target, port: server.address().port, close };
1605
+ }
1606
+
1607
+ // src/client/version.ts
1608
+ var VERSION = true ? '9.0.0' : 'dev';
1609
+
1610
+ // src/client/lib.ts
1611
+ var version = VERSION;
1612
+ var O1ConnectError = class extends Error {
1613
+ code;
1614
+ constructor(code, message, options) {
1615
+ super(message, options);
1616
+ this.name = 'O1ConnectError';
1617
+ this.code = code;
1618
+ }
1619
+ };
1620
+ var DEFAULT_NAME = 'aipp-connect';
1621
+ var TRANSPORTS = ['auto', 'websocket', 'post'];
1622
+ function entryName(name) {
1623
+ 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');
1626
+ return name;
1627
+ }
1628
+ function checkStore(store) {
1629
+ 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');
1637
+ }
1638
+ return s;
1639
+ }
1640
+ var entryLocks = /* @__PURE__ */ new WeakMap();
1641
+ function withEntry(store, name, fn) {
1642
+ let byName = entryLocks.get(store);
1643
+ if (!byName) {
1644
+ byName = /* @__PURE__ */ new Map();
1645
+ entryLocks.set(store, byName);
1646
+ }
1647
+ const map = byName;
1648
+ const run = (map.get(name) ?? Promise.resolve()).then(fn);
1649
+ const tail = run.then(
1650
+ () => void 0,
1651
+ () => void 0,
1652
+ );
1653
+ map.set(name, tail);
1654
+ void tail.then(() => {
1655
+ if (map.get(name) === tail) map.delete(name);
1656
+ });
1657
+ return run;
1658
+ }
1659
+ async function viaStore(what, call) {
1660
+ try {
1661
+ return await call();
1662
+ } catch (err) {
1663
+ throw new O1ConnectError(
1664
+ 'store_failed',
1665
+ `the secret store failed to ${what}`,
1666
+ { cause: err },
1667
+ );
1668
+ }
1669
+ }
1670
+ function parseSaved(raw) {
1671
+ let o;
1672
+ try {
1673
+ o = JSON.parse(String(raw));
1674
+ } catch {
1675
+ throw new O1ConnectError(
1676
+ 'invalid_config',
1677
+ 'the saved configuration is not JSON: run setup again',
1678
+ );
1679
+ }
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
+ );
1685
+ let code;
1686
+ try {
1687
+ code = validateCode(o);
1688
+ } 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
+ );
1693
+ }
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
+ );
1700
+ return { v: 1, ...code, transport };
1701
+ }
1702
+ async function setup(code, opts) {
1703
+ 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
+ );
1708
+ 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');
1712
+ let decoded;
1713
+ try {
1714
+ decoded = decodeConnectionCode(String(code ?? ''));
1715
+ } catch (err) {
1716
+ throw new O1ConnectError(
1717
+ 'invalid_code',
1718
+ err instanceof ConnectionCodeError
1719
+ ? err.message
1720
+ : 'the connection code is not valid',
1721
+ );
1722
+ }
1723
+ 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
+ );
1730
+ }
1731
+ 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
+ );
1737
+ return { ...info, fingerprints };
1738
+ }
1739
+ async function open(opts) {
1740
+ const store = checkStore(opts?.store);
1741
+ const name = entryName(opts.name);
1742
+ 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
+ );
1751
+ const cfg = parseSaved(raw);
1752
+ const log = opts.log
1753
+ ? (line) => {
1754
+ try {
1755
+ opts.log(line);
1756
+ } catch {}
1757
+ }
1758
+ : void 0;
1759
+ const apiKey = newLocalKey();
1760
+ let session;
1761
+ try {
1762
+ session = await startTunnelSession({
1763
+ url: cfg.url,
1764
+ pins: cfg.pins,
1765
+ deviceToken: cfg.token,
1766
+ transport: cfg.transport,
1767
+ port,
1768
+ localKeyHash: hashLocalKey(apiKey),
1769
+ userAgent: `o1-connect-lib/${VERSION}`,
1770
+ log,
1771
+ onMismatch: (received) => {
1772
+ log?.(
1773
+ `TUNNEL IDENTITY MISMATCH: received ${received}; possible interception`,
1774
+ );
1775
+ try {
1776
+ opts.onMismatch?.(received);
1777
+ } catch {}
1778
+ },
1779
+ onTransport: (t, reason) => log?.(`${reason ?? 'transport'}, using ${t}`),
1780
+ // Pins learned during a key rotation: saved only while the store still holds this
1781
+ // configuration (same proxy, device and token), under the entry's lock; false (never
1782
+ // 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
+ }),
1808
+ });
1809
+ } catch (err) {
1810
+ 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
+ );
1819
+ throw err;
1820
+ }
1821
+ if (opts.check !== false) {
1822
+ try {
1823
+ await session.pinSync.syncNow();
1824
+ } catch (err) {
1825
+ await session.close();
1826
+ 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
+ );
1831
+ }
1832
+ throw new O1ConnectError(
1833
+ 'tunnel_unavailable',
1834
+ `the tunnel did not answer: ${err instanceof Error ? err.message : String(err)}`,
1835
+ );
1836
+ }
1837
+ }
1838
+ 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
+ };
1850
+ }
1851
+ async function forget(opts) {
1852
+ const store = checkStore(opts?.store);
1853
+ const name = entryName(opts.name);
1854
+ await withEntry(store, name, () =>
1855
+ viaStore('delete the configuration', () => store.delete(name)),
1856
+ );
1857
+ }
1858
+ var MemorySecretStore = class {
1859
+ #values = /* @__PURE__ */ new Map();
1860
+ async get(name) {
1861
+ return this.#values.get(name) ?? null;
1862
+ }
1863
+ async set(name, value) {
1864
+ this.#values.set(name, String(value));
1865
+ }
1866
+ async delete(name) {
1867
+ this.#values.delete(name);
1868
+ }
1869
+ };
1870
+ export { MemorySecretStore, O1ConnectError, forget, open, setup, version };