@xiaoso/dsh-tool-plus 0.1.0-beta.2 → 0.1.0-beta.3

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 (88) hide show
  1. package/README.en.md +122 -0
  2. package/README.md +3 -2
  3. package/THIRD_PARTY_NOTICES.md +4 -35
  4. package/lib/abort-B7izMMna.mjs +51 -0
  5. package/lib/amazon-bedrock-D-shAr1X.mjs +917 -0
  6. package/lib/anthropic-BWsZFzU8.mjs +262 -0
  7. package/lib/anthropic-CMT1Qj1t.mjs +3115 -0
  8. package/lib/api-key-login-CpzSezsi.mjs +157 -0
  9. package/lib/aws-credentials-8Mgn5MAy.mjs +867 -0
  10. package/lib/azure-openai-responses-CNkHiLUh.mjs +274 -0
  11. package/lib/bun-shim.mjs +172 -7
  12. package/lib/bundled-references-CSuBco5p.mjs +55 -0
  13. package/lib/callback-server-BEFNf-jf.mjs +398 -0
  14. package/lib/client.js +110 -40
  15. package/lib/cursor-BIQfBC6V.mjs +135 -0
  16. package/lib/cursor-DNk6eXDd.mjs +5470 -0
  17. package/lib/cursor-MjSm74IJ.mjs +273 -0
  18. package/lib/device-code-OI_tQcmc.mjs +51 -0
  19. package/lib/devin-CldyPD8K.mjs +95 -0
  20. package/lib/devin-CzRpTUOA.mjs +114 -0
  21. package/lib/devin-DXOeNyU7.mjs +542 -0
  22. package/lib/error-B3bevhrs.mjs +1449 -0
  23. package/lib/event-stream-BDPi64mK.mjs +151 -0
  24. package/lib/github-copilot-4GaMtQmg.mjs +208 -0
  25. package/lib/github-copilot-B2HGSIJK.mjs +104 -0
  26. package/lib/gitlab-duo-akICyfeD.mjs +155 -0
  27. package/lib/gitlab-duo-workflow-CSEgYk3N.mjs +91 -0
  28. package/lib/google-antigravity-Dlkdhahq.mjs +198 -0
  29. package/lib/google-auth-DhqpOYrX.mjs +232 -0
  30. package/lib/google-gemini-cli-BG_LRdIV.mjs +850 -0
  31. package/lib/google-gemini-cli-zJhiOcND.mjs +211 -0
  32. package/lib/google-oauth-shared-CwNWYdmR.mjs +147 -0
  33. package/lib/google-shared-DzhCb9b0.mjs +760 -0
  34. package/lib/google-vertex-kscbkyRb.mjs +99 -0
  35. package/lib/google-zyDOG9x7.mjs +30 -0
  36. package/lib/identity-DnB63pS7.mjs +219 -0
  37. package/lib/idle-iterator-C6XbWcuB.mjs +366 -0
  38. package/lib/index.mjs +2865 -2745
  39. package/lib/kimi-DMVI-zrZ.mjs +236 -0
  40. package/lib/markit-M0jhziqU.mjs +1417 -0
  41. package/lib/minimax-code-BK-3eBbz.mjs +53 -0
  42. package/lib/models-CfT4coYT.mjs +104660 -0
  43. package/lib/ollama-BQMGPxtV.mjs +589 -0
  44. package/lib/openai-codex-CQL_kvYL.mjs +255 -0
  45. package/lib/openai-codex-responses-Cz-2qpC7.mjs +3144 -0
  46. package/lib/openai-completions-i8doczAk.mjs +1360 -0
  47. package/lib/openai-reasoning-fallback-DGVVLgd1.mjs +286 -0
  48. package/lib/openai-responses-DTkBiiy-.mjs +867 -0
  49. package/lib/opencode-DaJjcUbf.mjs +38 -0
  50. package/lib/perplexity-9b-RQ0mV.mjs +194 -0
  51. package/lib/proxy-ZtUcl6r5.mjs +190 -0
  52. package/lib/scrapers-CL-WgdU1.mjs +9198 -0
  53. package/lib/scrapers-CipyKyCH.mjs +9198 -0
  54. package/lib/scrapers-DGfrYhtw.mjs +9198 -0
  55. package/lib/scrapers-DSUPYoUF.mjs +9198 -0
  56. package/lib/scrapers-DZ2GXmp7.mjs +9198 -0
  57. package/lib/src-DTid0g4K.mjs +5001 -0
  58. package/lib/stream-C_RAoxJC.mjs +10236 -0
  59. package/lib/stream-markup-healing-2toHXWXM.mjs +491 -0
  60. package/lib/types/client/locales.d.ts +1 -1
  61. package/lib/types/config/fields.d.ts +1 -1
  62. package/lib/types/config/settings.d.ts +16 -2
  63. package/lib/types/tools/omp/sdk.d.ts +6 -0
  64. package/lib/types/tools/omp/tools/fetch.d.ts +2 -0
  65. package/lib/types/tools/omp/tools/read.d.ts +2 -8
  66. package/lib/types/tools/omp/utils/image-loading.d.ts +10 -36
  67. package/lib/types/tools/read/adapter/index.d.ts +4 -1
  68. package/lib/types/tools/read-image/index.d.ts +4 -0
  69. package/lib/types/tools/shared/bun-shim.d.ts +35 -3
  70. package/lib/types/tools/shared/image-bridge.d.ts +98 -0
  71. package/lib/types/tools/shared/omp-prompt.d.ts +4 -2
  72. package/lib/utils-2Wq2eATG.mjs +8119 -0
  73. package/lib/utils-BnX8O3vi.mjs +12303 -0
  74. package/lib/utils-CE8N8P4Q.mjs +12315 -0
  75. package/lib/utils-C_MrQ_0z.mjs +12301 -0
  76. package/lib/utils-D0Z1fyoO.mjs +12299 -0
  77. package/lib/utils-DppGHXQB.mjs +51 -0
  78. package/lib/utils-W8WdSBpX.mjs +12315 -0
  79. package/lib/vision-guard-BDD4OrKo.mjs +92 -0
  80. package/lib/wafer-DRU0EjZX.mjs +17 -0
  81. package/lib/xai-oauth-DPHDXKD7.mjs +446 -0
  82. package/lib/xiaomi-Dd87KSg5.mjs +157 -0
  83. package/lib/zai-CFeOt-53.mjs +203 -0
  84. package/lib/zip-D6QXpvaJ.mjs +1316 -0
  85. package/package.json +14 -10
  86. package/presets/package.json +1 -1
  87. package/presets/tool-plus-ptc/preset.yml +1 -1
  88. package/presets/tool-plus-standard/preset.yml +1 -1
@@ -0,0 +1,38 @@
1
+ import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
+ __installBunShim();
3
+ import { _ as OnPromptRequiredError, h as LoginCancelledError, m as ApiKeyRequiredError } from "./error-B3bevhrs.mjs";
4
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/registry/oauth/opencode.ts
5
+ /**
6
+ * OpenCode Zen login flow.
7
+ *
8
+ * OpenCode Zen is a subscription service that provides access to various AI models
9
+ * (GPT-5.x, Claude 4.x, Gemini 3, etc.) through a unified API at opencode.ai/zen.
10
+ * This is not OAuth - it's a simple API key flow:
11
+ * 1. Open browser to https://opencode.ai/auth
12
+ * 2. User logs in and copies their API key
13
+ * 3. User pastes the API key back into the CLI
14
+ */
15
+ const AUTH_URL = "https://opencode.ai/auth";
16
+ /**
17
+ * Login to OpenCode Zen.
18
+ *
19
+ * Opens browser to auth page, prompts user to paste their API key.
20
+ * Returns the API key directly (not OAuthCredentials - this isn't OAuth).
21
+ */
22
+ async function loginOpenCode(options) {
23
+ if (!options.onPrompt) throw new OnPromptRequiredError("OpenCode Zen");
24
+ options.onAuth?.({
25
+ url: AUTH_URL,
26
+ instructions: "Log in and copy your API key"
27
+ });
28
+ const apiKey = await options.onPrompt({
29
+ message: "Paste your OpenCode Zen API key",
30
+ placeholder: "sk-..."
31
+ });
32
+ if (options.signal?.aborted) throw new LoginCancelledError();
33
+ const trimmed = apiKey.trim();
34
+ if (!trimmed) throw new ApiKeyRequiredError();
35
+ return trimmed;
36
+ }
37
+ //#endregion
38
+ export { loginOpenCode };
@@ -0,0 +1,194 @@
1
+ import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
+ __installBunShim();
3
+ import { D as Cookie, E as $, O as CookieMap, P as $env } from "./src-DTid0g4K.mjs";
4
+ import { V as ProviderHttpError, _ as OnPromptRequiredError, c as OAuthError, h as LoginCancelledError } from "./error-B3bevhrs.mjs";
5
+ import * as os from "node:os";
6
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/registry/oauth/perplexity.ts
7
+ /**
8
+ * Perplexity login and token refresh.
9
+ *
10
+ * Login paths (in priority order):
11
+ * 1. macOS native app: reads JWT from NSUserDefaults (`defaults read ai.perplexity.mac authToken`)
12
+ * 2. HTTP email OTP: `GET /api/auth/csrf` → `POST /api/auth/signin-email` → `POST /api/auth/signin-otp`
13
+ *
14
+ * No browser or manual cookie paste required.
15
+ * Refresh: Socket.IO `refreshJWT` RPC over authenticated WebSocket connection.
16
+ *
17
+ * Protocol: Engine.IO v4 + Socket.IO v4 over WebSocket (bypasses Cloudflare managed challenge).
18
+ * Architecture reverse-engineered from Perplexity macOS app (ai.perplexity.mac).
19
+ */
20
+ const API_VERSION = "2.18";
21
+ const NATIVE_APP_BUNDLE = "ai.perplexity.mac";
22
+ const APP_USER_AGENT = "Perplexity/641 CFNetwork/1568 Darwin/25.2.0";
23
+ function serializeCookies(cookies) {
24
+ let header = "";
25
+ for (const [name, value] of cookies) header += `${header ? "; " : ""}${name}=${value}`;
26
+ return header;
27
+ }
28
+ function rememberCookies(cookies, response) {
29
+ for (const setCookie of response.headers.getSetCookie()) {
30
+ const cookie = Cookie.parse(setCookie);
31
+ if (cookie.isExpired()) cookies.delete(cookie.name);
32
+ else cookies.set(cookie.name, cookie.value);
33
+ }
34
+ }
35
+ /**
36
+ * Extract expiry from a JWT. Perplexity tokens generally lack an `exp` claim
37
+ * (their sessions are server-side and effectively non-expiring from the client's
38
+ * point of view), so we return a far-future sentinel when no `exp` is present.
39
+ * When `exp` IS present, subtract a 5-minute safety margin.
40
+ */
41
+ const NEVER_EXPIRES = 864e13;
42
+ function getJwtExpiry(token) {
43
+ try {
44
+ const parts = token.split(".");
45
+ if (parts.length !== 3) return NEVER_EXPIRES;
46
+ const payload = parts[1] ?? "";
47
+ const decoded = JSON.parse(atob(payload.replace(/-/g, "+").replace(/_/g, "/")));
48
+ if (typeof decoded?.exp === "number" && Number.isFinite(decoded.exp)) return decoded.exp * 1e3 - 3e5;
49
+ } catch {}
50
+ return NEVER_EXPIRES;
51
+ }
52
+ /** Build OAuthCredentials from a Perplexity JWT string. */
53
+ function jwtToCredentials(jwt, email) {
54
+ return {
55
+ access: jwt,
56
+ refresh: jwt,
57
+ expires: getJwtExpiry(jwt),
58
+ email
59
+ };
60
+ }
61
+ /**
62
+ * Read the Perplexity JWT from the native macOS Catalyst app's UserDefaults.
63
+ * Tokens are stored in NSUserDefaults (not Keychain), readable by any same-UID process.
64
+ */
65
+ async function extractFromNativeApp() {
66
+ if (os.platform() !== "darwin") return null;
67
+ try {
68
+ const result = await $`defaults read ${NATIVE_APP_BUNDLE} authToken`.quiet().nothrow();
69
+ if (result.exitCode !== 0) return null;
70
+ const token = result.text().trim();
71
+ if (!token || token === "(null)") return null;
72
+ return token;
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+ /**
78
+ * Send email OTP and exchange it for a Perplexity JWT via HTTP endpoints.
79
+ */
80
+ async function httpEmailLogin(ctrl) {
81
+ if (!ctrl.onPrompt) throw new OnPromptRequiredError("Perplexity");
82
+ const trimmedEmail = (await ctrl.onPrompt({
83
+ message: "Enter your Perplexity email address",
84
+ placeholder: "user@example.com"
85
+ })).trim();
86
+ if (!trimmedEmail) throw new OAuthError("Email is required for Perplexity login", {
87
+ kind: "validation",
88
+ provider: "perplexity"
89
+ });
90
+ if (ctrl.signal?.aborted) throw new LoginCancelledError();
91
+ const fetchImpl = ctrl.fetch ?? fetch;
92
+ const cookies = new CookieMap();
93
+ const request = async (url, init = {}) => {
94
+ const headers = new Headers(init.headers);
95
+ if (cookies.size > 0) headers.set("Cookie", serializeCookies(cookies));
96
+ const response = await fetchImpl(url, {
97
+ ...init,
98
+ headers
99
+ });
100
+ rememberCookies(cookies, response);
101
+ return response;
102
+ };
103
+ ctrl.onProgress?.("Fetching Perplexity CSRF token...");
104
+ const csrfResponse = await request("https://www.perplexity.ai/api/auth/csrf", {
105
+ headers: {
106
+ "User-Agent": APP_USER_AGENT,
107
+ "X-App-ApiVersion": API_VERSION
108
+ },
109
+ signal: ctrl.signal
110
+ });
111
+ if (!csrfResponse.ok) throw new ProviderHttpError(`Perplexity CSRF request failed: ${csrfResponse.status}`, csrfResponse.status);
112
+ const csrfData = await csrfResponse.json();
113
+ if (!csrfData.csrfToken) throw new OAuthError("Perplexity CSRF response missing csrfToken", {
114
+ kind: "validation",
115
+ provider: "perplexity"
116
+ });
117
+ ctrl.onProgress?.("Sending login code to your email...");
118
+ const sendResponse = await request("https://www.perplexity.ai/api/auth/signin-email", {
119
+ method: "POST",
120
+ headers: {
121
+ "Content-Type": "application/json",
122
+ "User-Agent": APP_USER_AGENT,
123
+ "X-App-ApiVersion": API_VERSION
124
+ },
125
+ body: JSON.stringify({
126
+ email: trimmedEmail,
127
+ csrfToken: csrfData.csrfToken
128
+ }),
129
+ signal: ctrl.signal
130
+ });
131
+ if (!sendResponse.ok) {
132
+ const body = await sendResponse.text();
133
+ throw new ProviderHttpError(`Perplexity send login code failed (${sendResponse.status}): ${body}`, sendResponse.status);
134
+ }
135
+ const trimmedOtp = (await ctrl.onPrompt({
136
+ message: "Enter the code sent to your email",
137
+ placeholder: "123456"
138
+ })).trim();
139
+ if (!trimmedOtp) throw new OAuthError("OTP code is required", {
140
+ kind: "validation",
141
+ provider: "perplexity"
142
+ });
143
+ if (ctrl.signal?.aborted) throw new LoginCancelledError();
144
+ ctrl.onProgress?.("Verifying login code...");
145
+ const verifyResponse = await request("https://www.perplexity.ai/api/auth/signin-otp", {
146
+ method: "POST",
147
+ headers: {
148
+ "Content-Type": "application/json",
149
+ "User-Agent": APP_USER_AGENT,
150
+ "X-App-ApiVersion": API_VERSION
151
+ },
152
+ body: JSON.stringify({
153
+ email: trimmedEmail,
154
+ otp: trimmedOtp,
155
+ csrfToken: csrfData.csrfToken
156
+ }),
157
+ signal: ctrl.signal
158
+ });
159
+ const verifyData = await verifyResponse.json();
160
+ if (!verifyResponse.ok) {
161
+ const reason = verifyData.text ?? verifyData.error_code ?? verifyData.status ?? "OTP verification failed";
162
+ throw new OAuthError(`Perplexity OTP verification failed: ${reason}`, {
163
+ kind: "validation",
164
+ provider: "perplexity",
165
+ status: verifyResponse.status
166
+ });
167
+ }
168
+ if (!verifyData.token) throw new OAuthError("Perplexity OTP verification response missing token", {
169
+ kind: "validation",
170
+ provider: "perplexity"
171
+ });
172
+ return jwtToCredentials(verifyData.token, trimmedEmail);
173
+ }
174
+ /**
175
+ * Login to Perplexity.
176
+ *
177
+ * Tries auto-extraction from the desktop app, then runs HTTP email OTP login.
178
+ *
179
+ * No browser/manual token paste fallback is used.
180
+ */
181
+ async function loginPerplexity(ctrl) {
182
+ if (!ctrl.onPrompt) throw new OnPromptRequiredError("Perplexity");
183
+ if (!$env.PI_AUTH_NO_BORROW) {
184
+ ctrl.onProgress?.("Checking for Perplexity desktop app...");
185
+ const nativeJwt = await extractFromNativeApp();
186
+ if (nativeJwt) {
187
+ ctrl.onProgress?.("Found Perplexity JWT from native app");
188
+ return jwtToCredentials(nativeJwt);
189
+ }
190
+ }
191
+ return httpEmailLogin(ctrl);
192
+ }
193
+ //#endregion
194
+ export { loginPerplexity };
@@ -0,0 +1,190 @@
1
+ import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
+ __installBunShim();
3
+ import { n as StreamTimeoutError, r as ValidationError, v as AbortError } from "./error-B3bevhrs.mjs";
4
+ import * as tls from "node:tls";
5
+ import * as net from "node:net";
6
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/utils/proxy.ts
7
+ /**
8
+ * Checks if a host is local or cloud metadata, which should always bypass the proxy
9
+ * (e.g. localhost, 127/8, ::1, 169.254.169.254, metadata.google.internal).
10
+ */
11
+ function isLocalOrMetadataHost(host) {
12
+ const lowerHost = host.toLowerCase();
13
+ if (lowerHost === "localhost" || lowerHost.endsWith(".localhost") || lowerHost === "metadata.google.internal") return true;
14
+ const ip = lowerHost.replace(/^\[|\]$/g, "");
15
+ const v4 = ip.match(/^(\d{1,3})\.(\d{1,3})\.\d{1,3}\.\d{1,3}$/);
16
+ if (v4) {
17
+ const a = Number(v4[1]);
18
+ const b = Number(v4[2]);
19
+ if (a === 127 || a === 10 || a === 0) return true;
20
+ if (a === 169 && b === 254) return true;
21
+ if (a === 192 && b === 168) return true;
22
+ if (a === 172 && b >= 16 && b <= 31) return true;
23
+ return false;
24
+ }
25
+ if (ip === "::1" || ip === "::") return true;
26
+ if (/^fe[89ab][0-9a-f]:/.test(ip)) return true;
27
+ if (/^f[cd][0-9a-f]{2}:/.test(ip)) return true;
28
+ return false;
29
+ }
30
+ /**
31
+ * Check if the url should bypass the proxy due to hard-coded localhost/metadata checks
32
+ * or custom NO_PROXY/no_proxy environment variables rules.
33
+ */
34
+ function shouldBypassProxy(urlObj) {
35
+ if (isLocalOrMetadataHost(urlObj.hostname)) return true;
36
+ const noProxyVal = Bun.env.NO_PROXY || Bun.env.no_proxy;
37
+ if (!noProxyVal) return false;
38
+ const rules = noProxyVal.split(/[,\s]+/).map((r) => r.trim()).filter(Boolean);
39
+ const targetHost = urlObj.hostname.toLowerCase();
40
+ const targetPort = urlObj.port || (urlObj.protocol === "https:" || urlObj.protocol === "wss:" ? "443" : "80");
41
+ for (const rule of rules) {
42
+ if (rule === "*") return true;
43
+ let ruleHost = rule.toLowerCase();
44
+ let rulePort;
45
+ if (ruleHost.includes("]:")) {
46
+ const lastColon = ruleHost.lastIndexOf(":");
47
+ rulePort = ruleHost.slice(lastColon + 1);
48
+ ruleHost = ruleHost.slice(0, lastColon);
49
+ } else if (!ruleHost.includes("]") && ruleHost.includes(":")) {
50
+ const lastColon = ruleHost.lastIndexOf(":");
51
+ rulePort = ruleHost.slice(lastColon + 1);
52
+ ruleHost = ruleHost.slice(0, lastColon);
53
+ }
54
+ ruleHost = ruleHost.replace(/^\[|\]$/g, "");
55
+ if (rulePort && rulePort !== targetPort) continue;
56
+ if (ruleHost.startsWith(".")) {
57
+ const suffix = ruleHost;
58
+ if (targetHost === ruleHost.slice(1) || targetHost.endsWith(suffix)) return true;
59
+ } else if (targetHost === ruleHost || targetHost.endsWith(`.${ruleHost}`)) return true;
60
+ }
61
+ return false;
62
+ }
63
+ const proxyCache = /* @__PURE__ */ new Map();
64
+ /**
65
+ * Normalizes provider id (e.g. github-copilot -> PI_PROXY_GITHUB_COPILOT) and looks it up.
66
+ * If not found, falls back to PI_PROXY. Results are memoized because env values are static
67
+ * for the lifetime of the process and this function is called for every outgoing request.
68
+ */
69
+ function getProxyForProvider(provider) {
70
+ if (proxyCache.has(provider)) return proxyCache.get(provider);
71
+ const envKey = `PI_PROXY_${provider.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
72
+ const value = Bun.env[envKey] || Bun.env.PI_PROXY;
73
+ proxyCache.set(provider, value);
74
+ return value;
75
+ }
76
+ /** Resolves provider-specific and standard proxy variables for a target URL, honoring NO_PROXY. */
77
+ function getProxyForUrl(provider, url) {
78
+ if (shouldBypassProxy(url)) return void 0;
79
+ const protocolProxy = url.protocol === "https:" || url.protocol === "wss:" ? Bun.env.HTTPS_PROXY || Bun.env.https_proxy : Bun.env.HTTP_PROXY || Bun.env.http_proxy;
80
+ return getProxyForProvider(provider) || protocolProxy || Bun.env.ALL_PROXY || Bun.env.all_proxy || void 0;
81
+ }
82
+ /**
83
+ * Tunnel a socket connection through an HTTP CONNECT proxy.
84
+ * This is used specifically to wrap Node's `http2.connect(baseUrl, { createConnection })` for Cursor.
85
+ */
86
+ async function connectProxiedSocket(proxyUrlStr, targetUrlStr, options) {
87
+ if (options?.signal?.aborted) throw new AbortError("Proxy tunnel aborted");
88
+ const proxyUrl = new URL(proxyUrlStr);
89
+ const targetUrl = new URL(targetUrlStr);
90
+ const useProxySsl = proxyUrl.protocol === "https:";
91
+ const proxyPort = proxyUrl.port ? parseInt(proxyUrl.port, 10) : useProxySsl ? 443 : 80;
92
+ const proxyHost = proxyUrl.hostname;
93
+ const targetPort = targetUrl.port ? parseInt(targetUrl.port, 10) : 443;
94
+ const targetHost = targetUrl.hostname;
95
+ const { promise, resolve, reject } = Promise.withResolvers();
96
+ const readyEvent = useProxySsl ? "secureConnect" : "connect";
97
+ let rawSocket;
98
+ let tunnelSocket;
99
+ let timeout;
100
+ let responseData = "";
101
+ let settled = false;
102
+ const cleanup = () => {
103
+ if (timeout) {
104
+ clearTimeout(timeout);
105
+ timeout = void 0;
106
+ }
107
+ options?.signal?.removeEventListener("abort", onAbort);
108
+ rawSocket?.off("error", onRawError);
109
+ rawSocket?.off(readyEvent, onProxyReady);
110
+ rawSocket?.off("data", onProxyData);
111
+ tunnelSocket?.off("secureConnect", onTunnelReady);
112
+ tunnelSocket?.off("error", onTunnelError);
113
+ };
114
+ const destroyInProgress = () => {
115
+ tunnelSocket?.destroy();
116
+ rawSocket?.destroy();
117
+ };
118
+ const rejectOnce = (error) => {
119
+ if (settled) return;
120
+ settled = true;
121
+ cleanup();
122
+ destroyInProgress();
123
+ reject(error);
124
+ };
125
+ const resolveOnce = (socket) => {
126
+ if (settled) return;
127
+ settled = true;
128
+ cleanup();
129
+ resolve(socket);
130
+ };
131
+ const onAbort = () => rejectOnce(new AbortError("Proxy tunnel aborted"));
132
+ const onRawError = (error) => rejectOnce(error);
133
+ const onTunnelError = (error) => rejectOnce(error);
134
+ const onTunnelReady = () => {
135
+ if (!tunnelSocket) return;
136
+ resolveOnce(tunnelSocket);
137
+ };
138
+ const onProxyData = (chunk) => {
139
+ if (!rawSocket) return;
140
+ responseData += chunk.toString("binary");
141
+ if (!responseData.includes("\r\n\r\n")) return;
142
+ rawSocket.off("data", onProxyData);
143
+ rawSocket.off("error", onRawError);
144
+ const firstLine = responseData.split("\r\n")[0];
145
+ if (!firstLine.includes(" 200 ")) {
146
+ rejectOnce(new ValidationError(`Proxy tunnel failed: ${firstLine}`));
147
+ return;
148
+ }
149
+ const tlsOptions = options?.tls;
150
+ tunnelSocket = tls.connect({
151
+ ...tlsOptions,
152
+ socket: rawSocket,
153
+ servername: tlsOptions?.servername ?? targetHost,
154
+ ALPNProtocols: tlsOptions?.ALPNProtocols ?? ["h2"]
155
+ });
156
+ tunnelSocket.once("secureConnect", onTunnelReady);
157
+ tunnelSocket.once("error", onTunnelError);
158
+ };
159
+ const onProxyReady = () => {
160
+ if (!rawSocket) return;
161
+ let connectReq = `CONNECT ${targetHost}:${targetPort} HTTP/1.1\r\nHost: ${targetHost}:${targetPort}\r\n`;
162
+ if (proxyUrl.username || proxyUrl.password) {
163
+ const creds = Buffer.from(`${decodeURIComponent(proxyUrl.username)}:${decodeURIComponent(proxyUrl.password)}`).toString("base64");
164
+ connectReq += `Proxy-Authorization: Basic ${creds}\r\n`;
165
+ }
166
+ connectReq += "\r\n";
167
+ rawSocket.write(connectReq);
168
+ rawSocket.on("data", onProxyData);
169
+ };
170
+ options?.signal?.addEventListener("abort", onAbort, { once: true });
171
+ if (options?.timeoutMs !== void 0 && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0) {
172
+ const timeoutMs = Math.trunc(options.timeoutMs);
173
+ timeout = setTimeout(() => {
174
+ rejectOnce(new StreamTimeoutError(`Proxy tunnel timed out after ${timeoutMs}ms`));
175
+ }, timeoutMs);
176
+ timeout.unref?.();
177
+ }
178
+ rawSocket = useProxySsl ? tls.connect({
179
+ host: proxyHost,
180
+ port: proxyPort
181
+ }) : net.connect({
182
+ host: proxyHost,
183
+ port: proxyPort
184
+ });
185
+ rawSocket.once("error", onRawError);
186
+ rawSocket.once(readyEvent, onProxyReady);
187
+ return promise;
188
+ }
189
+ //#endregion
190
+ export { shouldBypassProxy as a, isLocalOrMetadataHost as i, getProxyForProvider as n, getProxyForUrl as r, connectProxiedSocket as t };