@xiaoso/dsh-tool-plus 0.1.16 → 0.1.17-beta.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 (109) hide show
  1. package/lib/{abort-DZ54CaKU.mjs → abort-BTblp0Rt.mjs} +2 -2
  2. package/lib/{alibaba-coding-plan-DODpkcqi.mjs → alibaba-coding-plan-t3R4YKCB.mjs} +3 -3
  3. package/lib/{alibaba-token-plan-C6lpKCda.mjs → alibaba-token-plan-CO4djG1y.mjs} +4 -4
  4. package/lib/{alibaba-token-plan-CHGyWOfX.mjs → alibaba-token-plan-CUjYJX0-.mjs} +1 -1
  5. package/lib/{anthropic-Dv_GGX6g.mjs → anthropic-nf7w6so1.mjs} +48 -21
  6. package/lib/{api-key-validation-MnMf_ihX.mjs → api-key-validation-C_tZ7Y9a.mjs} +2 -2
  7. package/lib/behavior-BwvTUtag.mjs +111 -0
  8. package/lib/{browser-render-BZXt548F.mjs → browser-render-BQaEVK_n.mjs} +4 -4
  9. package/lib/{reference-CtvM4zLU.mjs → bundled-references-CrQ4dQcT.mjs} +57 -4
  10. package/lib/cascade-BWjRTD1q.mjs +30265 -0
  11. package/lib/{cline-pass-BT9CBEOj.mjs → cline-pass-Bjm-O8GG.mjs} +2 -2
  12. package/lib/cloudflare-CKXRJ0l9.mjs +37 -0
  13. package/lib/{cloudflare-ai-gateway-DReN6ohJ.mjs → cloudflare-ai-gateway-BpnBSjwV.mjs} +8 -4
  14. package/lib/cloudflare-workers-ai-odj9XswL.mjs +32 -0
  15. package/lib/collapse-_nkb2dn7.mjs +1945 -0
  16. package/lib/{coreweave-C82HrLpb.mjs → coreweave-CGDZOD8-.mjs} +1 -1
  17. package/lib/{coreweave-C68UgRQO.mjs → coreweave-DwffcgW5.mjs} +4 -4
  18. package/lib/cursor-BgOuV7Qf.mjs +794 -0
  19. package/lib/{cursor-_gHHq-Dq.mjs → cursor-CF1iHHbv.mjs} +68 -19
  20. package/lib/{cursor-proto-Cr_WEMuv.mjs → cursor-proto-BuNTjX3L.mjs} +823 -23
  21. package/lib/{devin-QpfTSl9H.mjs → devin-7OEeEb80.mjs} +112 -31
  22. package/lib/{devin-proto-DYhp4Ty6.mjs → devin-proto-C-QreeAv.mjs} +71 -5
  23. package/lib/{dom-DG3sPESc.mjs → dom-BmbZv4v9.mjs} +598 -182
  24. package/lib/{error-O63pC8zg.mjs → error-8LVo7tug.mjs} +725 -104
  25. package/lib/factory-droid-ChhmsGWb.mjs +71 -0
  26. package/lib/{fs-promises-shim-B2YFWkcd.mjs → fs-promises-shim-CANAxFWh.mjs} +10 -1
  27. package/lib/{github-copilot-BMEcw8N1.mjs → github-copilot-QwevdT30.mjs} +4 -4
  28. package/lib/{github-copilot-headers-DnjGEbko.mjs → github-copilot-headers-CAUZ0rUD.mjs} +138 -26
  29. package/lib/{gitlab-duo-DnHqJjFY.mjs → gitlab-duo-DigV7k_o.mjs} +2 -2
  30. package/lib/{google-antigravity-B1mSckrK.mjs → google-antigravity-D-oe0r8A.mjs} +6 -7
  31. package/lib/{google-gemini-cli-DJwThCCn.mjs → google-gemini-cli-CQBHgGJT.mjs} +5 -6
  32. package/lib/{google-oauth-shared-BctLpVUN.mjs → google-oauth-shared-CvgVIUwJ.mjs} +2 -2
  33. package/lib/google-validation-CdvRj4ec.mjs +126 -0
  34. package/lib/id-EJwVLDHE.mjs +2548 -0
  35. package/lib/index.mjs +248 -258
  36. package/lib/{kilo-BEgEwMJQ.mjs → kilo-5r6OffCa.mjs} +2 -2
  37. package/lib/{kimi-T9NldEIJ.mjs → kimi-DOOtbXmm.mjs} +9 -10
  38. package/lib/{launch-BIWNyrBB.mjs → launch-DkAjib7h.mjs} +1 -1
  39. package/lib/{markit-Dvp2JPdT.mjs → markit-CCcyeAds.mjs} +359 -140
  40. package/lib/{models-DnXMYGcJ.mjs → models-DCpDT_im.mjs} +199203 -112275
  41. package/lib/{muse-code-CNvqqAp6.mjs → muse-code-CYf8zj_B.mjs} +5 -5
  42. package/lib/{openai-codex-D5-CyTxa.mjs → openai-codex-Cj-TvSFh.mjs} +13 -10
  43. package/lib/{perplexity-A2PEoGaC.mjs → perplexity-Dh_Qgsmx.mjs} +68 -25
  44. package/lib/{pkce-BYjmugmw.mjs → pkce-DO-jBJLV.mjs} +1 -1
  45. package/lib/pricing-DusBEhwm.mjs +593 -0
  46. package/lib/{readability-uGhqb4GC.mjs → readability-XHK0o3bv.mjs} +287 -27
  47. package/lib/{scrapers-C1ujjV8k.mjs → scrapers-B6PADOVm.mjs} +13 -13
  48. package/lib/slugify-ynYWBIA5.mjs +11 -0
  49. package/lib/snowflake-B_jap6lz.mjs +666 -0
  50. package/lib/snowflake-Cu1ZyOp6.mjs +151 -0
  51. package/lib/{src-AELUUb5U.mjs → src-BhinCSpi.mjs} +1172 -458
  52. package/lib/{stream-AVOoe5Hj.mjs → stream-D2ivg3GH.mjs} +3740 -5311
  53. package/lib/{turndown-D6fof1OX.mjs → turndown-Vya8SavL.mjs} +82 -30
  54. package/lib/types/tools/hashline/native/index.d.ts +2 -2
  55. package/lib/types/tools/hashline/native/policy.d.ts +19 -21
  56. package/lib/types/tools/omp/session/agent-storage.d.ts +3 -3
  57. package/lib/types/tools/shared/bun-named-shim.d.ts +5 -0
  58. package/lib/{types-BLrLohwK.mjs → types-tH1v9uRm.mjs} +2 -2
  59. package/lib/{utils-cZX3f_Ls.mjs → utils-C_Ncya1r.mjs} +1737 -509
  60. package/lib/utils-D2tK38xq.mjs +34006 -0
  61. package/lib/{utils-I4I8azHN.mjs → utils-DrDwmNtu.mjs} +8 -3
  62. package/lib/{xai-oauth-CbeldUSV.mjs → xai-oauth-DLLzX6my.mjs} +4 -4
  63. package/lib/{xiaomi-Dl3VSs04.mjs → xiaomi-CqK-KivK.mjs} +2 -2
  64. package/lib/{zai-FyjGSypr.mjs → zai-DoJ2xPIH.mjs} +2 -2
  65. package/lib/{zip-DRrycScC.mjs → zip-DG1mUV6X.mjs} +1 -1
  66. package/package.json +8 -8
  67. package/lib/amazon-bedrock-Dx0rr9dY.mjs +0 -996
  68. package/lib/anthropic-ClCw0PV_.mjs +0 -3624
  69. package/lib/anthropic-wire-lbGAFzYb.mjs +0 -927
  70. package/lib/azure-openai-responses-WE_bgFWp.mjs +0 -285
  71. package/lib/bundled-references-DY3EJxZV.mjs +0 -56
  72. package/lib/cloudflare-ai-gateway-CrMa97Ap.mjs +0 -44
  73. package/lib/collapse-CkMNRNr7.mjs +0 -2304
  74. package/lib/cursor-C6jaIJDg.mjs +0 -283
  75. package/lib/cursor-D-XZYDf_.mjs +0 -4544
  76. package/lib/deterministic-id-CUEIMSqR.mjs +0 -17
  77. package/lib/devin-ExGIghmx.mjs +0 -69
  78. package/lib/devin-u0ljw5P6.mjs +0 -628
  79. package/lib/effort-BdtQMN-_.mjs +0 -23
  80. package/lib/event-stream-BKEtb45Y.mjs +0 -167
  81. package/lib/gemini-headers-Co9cVvex.mjs +0 -54
  82. package/lib/google-auth-qAN-6DMW.mjs +0 -232
  83. package/lib/google-gemini-cli-B2Aw1S5w.mjs +0 -844
  84. package/lib/google-lTxuq28n.mjs +0 -38
  85. package/lib/google-shared-Y01j9xOr.mjs +0 -856
  86. package/lib/google-validation-BEkNs-Bx.mjs +0 -18
  87. package/lib/google-vertex-DcM-FRC5.mjs +0 -99
  88. package/lib/hosts-00rjRzUD.mjs +0 -203
  89. package/lib/id-AL5obQzR.mjs +0 -71
  90. package/lib/idle-iterator-D0ZXEcUq.mjs +0 -366
  91. package/lib/ollama-6R0oXZks.mjs +0 -574
  92. package/lib/openai-codex-responses-C8bnBWOe.mjs +0 -3232
  93. package/lib/openai-completions-DNr3mUsn.mjs +0 -1430
  94. package/lib/openai-configuration-update-xMYUjaK_.mjs +0 -150
  95. package/lib/openai-reasoning-fallback-Ju-5pSR8.mjs +0 -380
  96. package/lib/openai-responses-CjpafAEr.mjs +0 -861
  97. package/lib/protobuf-BMgDYu_U.mjs +0 -717
  98. package/lib/provider-response-SqKSkkUc.mjs +0 -22
  99. package/lib/proxy-DxvCQOCA.mjs +0 -230
  100. package/lib/request-debug-BwPOqN_j.mjs +0 -183
  101. package/lib/sanitize-text-BCf5KmCf.mjs +0 -33
  102. package/lib/sse-debug-B-tkLCPW.mjs +0 -11
  103. package/lib/stream-markup-healing-CN3RsqG9.mjs +0 -267
  104. package/lib/strict-tool-validation-CBTz1dAA.mjs +0 -105
  105. package/lib/taxonomy-DSIM99rS.mjs +0 -15392
  106. package/lib/thinking-ngMwf_1Y.mjs +0 -336
  107. package/lib/type-guards-CttAANEx.mjs +0 -11
  108. package/lib/utils-CE3DSebh.mjs +0 -11763
  109. package/lib/vision-guard-BCpXWUj3.mjs +0 -77
@@ -0,0 +1,666 @@
1
+ import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
+ __installBunShim();
3
+ import { H as $env, k as warn } from "./src-BhinCSpi.mjs";
4
+ import { _ as LoginCancelledError, h as OAuthError, t as ConfigurationError } from "./error-8LVo7tug.mjs";
5
+ import { i as auth } from "./cascade-BWjRTD1q.mjs";
6
+ import { NativeOAuthCallback } from "@oh-my-pi/pi-natives";
7
+ import * as os from "node:os";
8
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/auth.ts
9
+ /**
10
+ * Typed accessors over the compiled auth stratum (`rules/auth/*.kdl`): per
11
+ * provider display metadata, env-var fallbacks and the declarative login /
12
+ * refresh flow that `@oh-my-pi/pi-ai`'s registry engines interpret.
13
+ */
14
+ const providers = auth.providers;
15
+ const byId = Object.fromEntries(providers.map((p) => [p.id, p]));
16
+ /** Every compiled auth provider in `/login` display order. */
17
+ function authProviders() {
18
+ return providers;
19
+ }
20
+ /** The compiled auth policy for one provider id, if declared. */
21
+ function authPolicyFor(provider) {
22
+ return byId[provider];
23
+ }
24
+ //#endregion
25
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/registry/oauth/native-scheme-callback.ts
26
+ /** Connect OAuth's AbortSignals to the native, recoverable desktop callback receiver. */
27
+ async function createNativeSchemeCallbackReceiver(scheme, options = {}) {
28
+ options.signal?.throwIfAborted();
29
+ const receiver = new NativeOAuthCallback({ scheme });
30
+ const cancel = () => receiver.cancel();
31
+ const detach = () => options.signal?.removeEventListener("abort", cancel);
32
+ options.signal?.addEventListener("abort", cancel, { once: true });
33
+ try {
34
+ if (!await receiver.start()) {
35
+ await receiver.dispose();
36
+ detach();
37
+ return;
38
+ }
39
+ options.signal?.throwIfAborted();
40
+ } catch (error) {
41
+ try {
42
+ await receiver.dispose();
43
+ } catch (cleanupError) {
44
+ throw new AggregateError([error, cleanupError], "Native OAuth setup and recovery both failed");
45
+ } finally {
46
+ detach();
47
+ }
48
+ throw error;
49
+ }
50
+ return {
51
+ async dispose() {
52
+ try {
53
+ await receiver.dispose();
54
+ } finally {
55
+ detach();
56
+ }
57
+ },
58
+ async waitForCallback(signal, timeoutMs) {
59
+ signal?.throwIfAborted();
60
+ signal?.addEventListener("abort", cancel, { once: true });
61
+ try {
62
+ return await receiver.waitForCallback(timeoutMs);
63
+ } finally {
64
+ signal?.removeEventListener("abort", cancel);
65
+ }
66
+ }
67
+ };
68
+ }
69
+ //#endregion
70
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/registry/oauth/oauth.html
71
+ var oauth_default = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <meta name=\"color-scheme\" content=\"dark light\" />\n <title>omp · authentication</title>\n <style>\n :root {\n --bg: #000;\n --card: #0b0b0d;\n --ink-1: #f4f4f5;\n --ink-2: #b4b4bb;\n --ink-3: #7a7a83;\n --line-1: rgb(255 255 255 / 0.07);\n --line-2: rgb(255 255 255 / 0.12);\n --top-lit: rgb(255 255 255 / 0.22);\n --accent-a: #22d3ee;\n --accent-b: #f472b6;\n --accent-gradient: linear-gradient(135deg, var(--accent-a), var(--accent-b));\n --ok: #4ade80;\n --ok-soft: rgb(74 222 128 / 0.12);\n --bad: #f87171;\n --bad-soft: rgb(248 113 113 / 0.12);\n --pending: #a1a1aa;\n --pending-soft: rgb(161 161 170 / 0.12);\n --glow-a: rgb(34 211 238 / 0.1);\n --glow-b: rgb(244 114 182 / 0.08);\n --shadow: 0 30px 60px -20px rgb(0 0 0 / 0.8);\n --btn-bg: #f4f4f5;\n --btn-fg: #000;\n --r-control: 8px;\n --r-panel: 16px;\n --sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n color-scheme: dark;\n }\n\n @media (prefers-color-scheme: light) {\n :root {\n --bg: #fafafa;\n --card: #fff;\n --ink-1: #111113;\n --ink-2: #4b4b52;\n --ink-3: #83838b;\n --line-1: rgb(0 0 0 / 0.08);\n --line-2: rgb(0 0 0 / 0.12);\n --top-lit: rgb(0 0 0 / 0.04);\n --accent-a: #0891b2;\n --accent-b: #db2777;\n --ok: #16a34a;\n --ok-soft: rgb(22 163 74 / 0.1);\n --bad: #dc2626;\n --bad-soft: rgb(220 38 38 / 0.1);\n --pending: #71717a;\n --pending-soft: rgb(113 113 122 / 0.1);\n --glow-a: rgb(8 145 178 / 0.08);\n --glow-b: rgb(219 39 119 / 0.06);\n --shadow: 0 20px 50px -24px rgb(0 0 0 / 0.18);\n --btn-bg: #111113;\n --btn-fg: #fff;\n color-scheme: light;\n }\n }\n\n * {\n box-sizing: border-box;\n }\n\n body {\n margin: 0;\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1.5rem;\n font-family: var(--sans);\n background: var(--bg);\n color: var(--ink-1);\n -webkit-font-smoothing: antialiased;\n overflow-x: clip;\n }\n\n /* ambient glow */\n .glow {\n position: fixed;\n inset: 0;\n pointer-events: none;\n background:\n radial-gradient(ellipse 50vw 40vh at 38% 30%, var(--glow-a), transparent 70%),\n radial-gradient(ellipse 50vw 40vh at 64% 64%, var(--glow-b), transparent 70%);\n }\n\n .container {\n position: relative;\n width: 100%;\n max-width: 400px;\n padding: 2rem 2rem 1.75rem;\n background: var(--card);\n border: 1px solid var(--line-1);\n border-radius: var(--r-panel);\n box-shadow: var(--shadow);\n overflow: hidden;\n animation: rise 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;\n }\n /* top-lit hairline */\n .container::before {\n content: \"\";\n position: absolute;\n top: 0;\n left: 12%;\n right: 12%;\n height: 1px;\n background: linear-gradient(90deg, transparent, var(--top-lit), transparent);\n }\n @keyframes rise {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n }\n\n .brand {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-bottom: 1.75rem;\n }\n .omp-mark {\n flex: none;\n display: block;\n }\n .wordmark {\n font-size: 13px;\n font-weight: 600;\n letter-spacing: -0.01em;\n }\n .wordmark-sub {\n margin-left: auto;\n font-family: var(--mono);\n font-size: 12px;\n color: var(--ink-3);\n }\n\n .status {\n display: inline-flex;\n align-items: center;\n gap: 0.45rem;\n padding: 0.22rem 0.6rem 0.22rem 0.5rem;\n margin-bottom: 1rem;\n border-radius: 999px;\n font-size: 12px;\n font-weight: 500;\n color: var(--pending);\n background: var(--pending-soft);\n }\n .status-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: currentColor;\n }\n .status-word {\n display: none;\n }\n .container:not(.success):not(.error) .status-pending,\n .success .status-success,\n .error .status-error {\n display: inline;\n }\n .container:not(.success):not(.error) .status-dot {\n animation: pulse 1.4s ease-in-out infinite;\n }\n @keyframes pulse {\n 50% {\n opacity: 0.35;\n }\n }\n .success .status {\n color: var(--ok);\n background: var(--ok-soft);\n }\n .error .status {\n color: var(--bad);\n background: var(--bad-soft);\n }\n\n h1 {\n margin: 0 0 0.5rem;\n font-size: 1.35rem;\n font-weight: 600;\n letter-spacing: -0.02em;\n line-height: 1.25;\n text-wrap: balance;\n }\n p {\n margin: 0 0 1.5rem;\n font-size: 0.9rem;\n line-height: 1.6;\n color: var(--ink-2);\n }\n p:last-of-type:not(:has(+ .btn)) {\n margin-bottom: 0.25rem;\n }\n .error p {\n font-family: var(--mono);\n font-size: 0.8rem;\n padding: 0.6rem 0.75rem;\n border: 1px solid var(--line-1);\n border-radius: var(--r-control);\n overflow-wrap: anywhere;\n }\n\n .btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n padding: 0.6rem 1rem;\n font: inherit;\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--btn-fg);\n background: var(--btn-bg);\n border: none;\n border-radius: var(--r-control);\n cursor: pointer;\n transition: opacity 0.15s;\n }\n .btn:hover {\n opacity: 0.86;\n }\n .btn:focus-visible {\n outline: 2px solid var(--accent-a);\n outline-offset: 2px;\n }\n .error .btn {\n color: var(--ink-1);\n background: transparent;\n border: 1px solid var(--line-2);\n }\n\n /* auto-close progress */\n .timer {\n position: absolute;\n left: 0;\n bottom: 0;\n height: 2px;\n width: 100%;\n background: var(--accent-gradient);\n transform-origin: left;\n transform: scaleX(0);\n }\n .countdown .timer {\n animation: countdown 3s linear forwards;\n }\n @keyframes countdown {\n from {\n transform: scaleX(1);\n }\n to {\n transform: scaleX(0);\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .container,\n .countdown .timer,\n .status-dot {\n animation: none !important;\n }\n }\n </style>\n </head>\n <body>\n <span aria-hidden=\"true\" class=\"glow\"></span>\n <div id=\"app\" class=\"container\">\n <div class=\"brand\">\n <svg class=\"omp-mark\" viewBox=\"0 0 64 64\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n <defs>\n <linearGradient id=\"omp-mark-grad\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\">\n <stop offset=\"0\" stop-color=\"oklch(0.7 0.24 340)\" />\n <stop offset=\".5\" stop-color=\"oklch(0.62 0.21 295)\" />\n <stop offset=\"1\" stop-color=\"oklch(0.81 0.14 200)\" />\n </linearGradient>\n </defs>\n <path fill=\"url(#omp-mark-grad)\" d=\"M10 14h44v9H43v33h-9V23h-9v22h-9V23H10z\" />\n </svg>\n <span class=\"wordmark\">omp</span>\n <span class=\"wordmark-sub\">oauth</span>\n </div>\n\n <div class=\"status\" role=\"status\">\n <span aria-hidden=\"true\" class=\"status-dot\"></span>\n <span class=\"status-word status-pending\">Waiting</span>\n <span class=\"status-word status-success\">Connected</span>\n <span class=\"status-word status-error\">Failed</span>\n </div>\n\n <h1 id=\"title\">Authentication</h1>\n <p id=\"message\"></p>\n <button onclick=\"window.close()\" class=\"btn\">Close window</button>\n <span aria-hidden=\"true\" class=\"timer\"></span>\n </div>\n\n <script id=\"server-state\" type=\"application/json\">\n __OAUTH_STATE__\n <\/script>\n\n <script>\n let serverState;\n try {\n serverState = JSON.parse(document.getElementById(\"server-state\").textContent);\n } catch {\n const params = new URLSearchParams(window.location.search);\n serverState = {\n ok: params.get(\"ok\") === \"1\",\n error: params.get(\"error\") || \"Authentication failed\",\n };\n }\n\n const app = document.getElementById(\"app\");\n const title = document.getElementById(\"title\");\n const message = document.getElementById(\"message\");\n\n if (serverState.ok) {\n const closeButton = document.querySelector(\".btn\");\n app.classList.add(\"success\", \"countdown\");\n title.textContent = \"Authentication successful\";\n message.textContent = \"You have successfully logged in.\";\n window.close();\n setTimeout(() => {\n app.classList.remove(\"countdown\");\n closeButton.remove();\n message.innerHTML = \"You have successfully logged in.<br>Please close this tab manually.\";\n }, 300);\n } else {\n app.classList.add(\"error\");\n title.textContent = \"Authentication failed\";\n message.textContent = serverState.error || \"An error occurred\";\n }\n <\/script>\n </body>\n</html>\n";
72
+ //#endregion
73
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/registry/oauth/callback-server.ts
74
+ /**
75
+ * Abstract base class for OAuth flows with local callback servers.
76
+ *
77
+ * Handles:
78
+ * - Port allocation (tries expected port, falls back to random)
79
+ * - Callback server setup and request handling
80
+ * - Common OAuth flow logic
81
+ *
82
+ * Providers extend this and implement:
83
+ * - generateAuthUrl(): Build provider-specific authorization URL
84
+ * - exchangeToken(): Exchange authorization code for tokens
85
+ */
86
+ const DEFAULT_TIMEOUT = 3e5;
87
+ const DEFAULT_HOSTNAME = "localhost";
88
+ const CALLBACK_PATH = "/callback";
89
+ const IPV4_LOOPBACK = "127.0.0.1";
90
+ const IPV6_LOOPBACK = "::1";
91
+ /**
92
+ * How many times a random-port bind may be redrawn when the ephemeral port it
93
+ * landed on is already held on {@link IPV6_LOOPBACK} by that exact address.
94
+ * Small on purpose: each redraw picks a fresh port, so a repeat collision is
95
+ * vanishingly unlikely.
96
+ */
97
+ const IPV6_COMPANION_ATTEMPTS = 4;
98
+ /**
99
+ * Path served by {@link OAuthCallbackFlow} that 302-redirects to the pending
100
+ * authorization URL. Kept out of {@link OAuthCallbackFlowOptions} because it
101
+ * lives on the loopback callback server alongside {@link CALLBACK_PATH} and
102
+ * must never clash with a provider-registered redirect URI (all known
103
+ * providers register `/callback`-shaped paths).
104
+ */
105
+ const LAUNCH_PATH = "/launch";
106
+ /**
107
+ * Whether a failed bind means "another process already holds this port".
108
+ * Bun surfaces `EADDRINUSE` on the error's `code` where the platform reports
109
+ * it, and otherwise only in the message, so both are checked.
110
+ */
111
+ function isAddressInUse(error) {
112
+ const code = error?.code;
113
+ if (typeof code === "string") return code === "EADDRINUSE";
114
+ return error instanceof Error && /EADDRINUSE|in use/i.test(error.message);
115
+ }
116
+ /** Keep JSON data inside the template's script element; JSON.parse restores the original text. */
117
+ function serializeCallbackState(state) {
118
+ return JSON.stringify(state).replaceAll("<", "\\u003c");
119
+ }
120
+ /**
121
+ * Whether this host exposes an IPv6 loopback (`::1`) the companion listener can
122
+ * bind. A kernel with IPv6 disabled (`ipv6.disable=1`) lists no internal IPv6
123
+ * address, and the `::1` companion bind there fails with a generic Bun error
124
+ * {@link isAddressInUse} cannot distinguish from a real collision — Bun reuses
125
+ * its "Is port X in use?" message for every listen failure (oven-sh/bun#7187) —
126
+ * so the dual-bind path must be skipped up front rather than misread as a
127
+ * conflict (issue #8814).
128
+ */
129
+ function ipv6LoopbackAvailable() {
130
+ const interfaces = os.networkInterfaces();
131
+ for (const name in interfaces) {
132
+ const addresses = interfaces[name];
133
+ if (!addresses) continue;
134
+ for (const address of addresses) if (address.internal && address.family === "IPv6") return true;
135
+ }
136
+ return false;
137
+ }
138
+ function parseNativeCallback(input, redirectUri, expectedState) {
139
+ let callback;
140
+ let expected;
141
+ try {
142
+ callback = new URL(input);
143
+ expected = new URL(redirectUri);
144
+ } catch {
145
+ throw new OAuthError("OAuth application callback was not a valid URL", { kind: "device-auth" });
146
+ }
147
+ if (callback.protocol !== expected.protocol || callback.host !== expected.host || callback.pathname !== expected.pathname) throw new OAuthError("OAuth application returned an unexpected callback target", { kind: "device-auth" });
148
+ const state = callback.searchParams.get("state") ?? "";
149
+ if (expectedState && state !== expectedState) throw new OAuthError("State mismatch - possible CSRF attack", { kind: "device-auth" });
150
+ const error = callback.searchParams.get("error");
151
+ if (error) {
152
+ const description = callback.searchParams.get("error_description") || error;
153
+ throw new OAuthError(`Authorization failed: ${description}`, { kind: "device-auth" });
154
+ }
155
+ const code = callback.searchParams.get("code") ?? callback.searchParams.get("authCode");
156
+ if (!code) throw new OAuthError("OAuth application callback omitted the authorization code", { kind: "device-auth" });
157
+ return {
158
+ code,
159
+ state
160
+ };
161
+ }
162
+ /**
163
+ * Abstract base class for OAuth flows with local callback servers.
164
+ */
165
+ var OAuthCallbackFlow = class {
166
+ ctrl;
167
+ preferredPort;
168
+ callbackPath;
169
+ callbackHostname;
170
+ redirectUri;
171
+ allowPortFallback;
172
+ #manualInputOnly;
173
+ #nativeScheme;
174
+ #callbackResolve;
175
+ #callbackReject;
176
+ /**
177
+ * Authorization URL the `/launch` route currently redirects to. Set by
178
+ * {@link login} after {@link generateAuthUrl} and before {@link OAuthController.onAuth}
179
+ * fires, cleared when the server stops. `undefined` before the flow reaches
180
+ * that point and after it finishes, so `/launch` returns 503 rather than
181
+ * a stale URL.
182
+ */
183
+ #pendingAuthUrl;
184
+ constructor(ctrl, preferredPortOrOptions, callbackPath = CALLBACK_PATH) {
185
+ this.ctrl = ctrl;
186
+ if (typeof preferredPortOrOptions === "number") {
187
+ this.preferredPort = preferredPortOrOptions;
188
+ this.callbackPath = callbackPath;
189
+ this.callbackHostname = DEFAULT_HOSTNAME;
190
+ this.allowPortFallback = true;
191
+ this.#manualInputOnly = false;
192
+ this.#nativeScheme = false;
193
+ return;
194
+ }
195
+ this.preferredPort = preferredPortOrOptions.preferredPort;
196
+ this.callbackPath = preferredPortOrOptions.callbackPath ?? CALLBACK_PATH;
197
+ this.callbackHostname = preferredPortOrOptions.callbackHostname ?? DEFAULT_HOSTNAME;
198
+ this.redirectUri = preferredPortOrOptions.redirectUri;
199
+ this.allowPortFallback = preferredPortOrOptions.allowPortFallback ?? true;
200
+ this.#manualInputOnly = preferredPortOrOptions.manualInputOnly ?? false;
201
+ this.#nativeScheme = preferredPortOrOptions.nativeScheme ?? false;
202
+ }
203
+ /**
204
+ * Generate CSRF state token. Override if provider needs custom state generation.
205
+ */
206
+ generateState() {
207
+ const bytes = /* @__PURE__ */ new Uint8Array(16);
208
+ crypto.getRandomValues(bytes);
209
+ return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
210
+ }
211
+ #loginCancelledError() {
212
+ return new LoginCancelledError(`OAuth callback cancelled: ${this.ctrl.signal?.reason}`);
213
+ }
214
+ #throwIfCancelled() {
215
+ if (this.ctrl.signal?.aborted) throw this.#loginCancelledError();
216
+ }
217
+ /**
218
+ * Execute the OAuth login flow.
219
+ */
220
+ async login() {
221
+ const state = this.generateState();
222
+ this.#throwIfCancelled();
223
+ const { server, redirectUri, launchUrl } = this.#manualInputOnly ? {
224
+ server: void 0,
225
+ redirectUri: this.#buildRedirectUri(),
226
+ launchUrl: void 0
227
+ } : await this.#startCallbackServer(state);
228
+ const receiverAbort = new AbortController();
229
+ let receiver;
230
+ let nativeCallback;
231
+ try {
232
+ this.#throwIfCancelled();
233
+ if (this.#nativeScheme) {
234
+ const redirect = new URL(redirectUri);
235
+ if (redirect.protocol !== "http:" && redirect.protocol !== "https:") try {
236
+ receiver = await createNativeSchemeCallbackReceiver(redirect.protocol.slice(0, -1), { signal: this.ctrl.signal });
237
+ } catch (error) {
238
+ this.#throwIfCancelled();
239
+ this.#reportNativeWarning("Native OAuth callback setup failed; paste the authorization code instead", error);
240
+ }
241
+ }
242
+ this.#throwIfCancelled();
243
+ if (receiver) {
244
+ nativeCallback = receiver.waitForCallback(receiverAbort.signal).then((input) => parseNativeCallback(input, redirectUri, state));
245
+ nativeCallback.catch(() => void 0);
246
+ }
247
+ const { url: authUrl, instructions } = await this.generateAuthUrl(state, redirectUri);
248
+ this.#throwIfCancelled();
249
+ this.#pendingAuthUrl = authUrl;
250
+ this.ctrl.onAuth?.({
251
+ url: authUrl,
252
+ launchUrl,
253
+ instructions
254
+ });
255
+ this.#throwIfCancelled();
256
+ this.ctrl.onProgress?.(receiver || !this.#manualInputOnly ? "Waiting for browser authentication..." : "Waiting for pasted authorization code...");
257
+ this.#throwIfCancelled();
258
+ let callback;
259
+ try {
260
+ callback = await this.#waitForCallback(state, nativeCallback);
261
+ } catch (error) {
262
+ this.#throwIfCancelled();
263
+ throw error;
264
+ }
265
+ this.#throwIfCancelled();
266
+ receiverAbort.abort("OAuth callback received");
267
+ await nativeCallback?.catch(() => void 0);
268
+ this.ctrl.onProgress?.("Exchanging authorization code for tokens...");
269
+ this.#throwIfCancelled();
270
+ return await this.exchangeToken(callback.code, state, redirectUri);
271
+ } finally {
272
+ this.#pendingAuthUrl = void 0;
273
+ receiverAbort.abort("OAuth login finished");
274
+ await nativeCallback?.catch(() => void 0);
275
+ if (receiver) try {
276
+ await receiver.dispose();
277
+ } catch (error) {
278
+ this.#reportNativeWarning("Native OAuth callback cleanup failed; recovery information was retained", error);
279
+ }
280
+ server?.stop();
281
+ }
282
+ }
283
+ /**
284
+ * Surface native callback failures without allowing reporting hooks to
285
+ * replace the login result they are meant to describe.
286
+ */
287
+ #reportNativeWarning(message, error) {
288
+ const warning = `${message}: ${error instanceof Error ? error.message : String(error)}`;
289
+ warn(warning, { error });
290
+ try {
291
+ this.ctrl.onProgress?.(warning);
292
+ } catch (progressError) {
293
+ warn("OAuth progress callback failed while reporting a native callback warning", { error: progressError });
294
+ }
295
+ }
296
+ #buildRedirectUri() {
297
+ return this.redirectUri ?? `http://${this.callbackHostname}:${this.preferredPort}${this.callbackPath}`;
298
+ }
299
+ /**
300
+ * Start callback server, trying preferred port first, falling back to random.
301
+ * `launchUrl` is `undefined` when the caller configured `callbackPath` to
302
+ * collide with {@link LAUNCH_PATH} — the callback handler resolves the real
303
+ * callback in that case, so advertising a self-redirecting URL would be
304
+ * incorrect.
305
+ */
306
+ async #startCallbackServer(expectedState) {
307
+ try {
308
+ const server = this.#createServer(this.preferredPort, expectedState);
309
+ const actualPort = this.#resolveServerPort(server);
310
+ const launchUrl = this.#launchUrlIfSafe(actualPort);
311
+ if (this.redirectUri) return {
312
+ server,
313
+ redirectUri: this.redirectUri,
314
+ launchUrl
315
+ };
316
+ return {
317
+ server,
318
+ redirectUri: `http://${this.callbackHostname}:${actualPort}${this.callbackPath}`,
319
+ launchUrl
320
+ };
321
+ } catch (cause) {
322
+ if (this.redirectUri) throw new ConfigurationError(`OAuth callback port ${this.preferredPort} is in use, but oauth.redirectUri (${this.redirectUri}) requires this exact port. Free port ${this.preferredPort} (e.g. stop the process bound to it) and retry, or change oauth.redirectUri to point at an available port.`, { cause });
323
+ if (!this.allowPortFallback) throw new ConfigurationError(`OAuth callback port ${this.preferredPort} is in use. The OAuth provider validates redirect URIs against its registered callback, so falling back to a random port would be rejected. Free port ${this.preferredPort} (e.g. stop the process bound to it) and retry, or set oauth.callbackPort/oauth.redirectUri to a port the provider has registered.`, { cause });
324
+ const server = this.#createServer(0, expectedState);
325
+ const actualPort = this.#resolveServerPort(server);
326
+ const redirectUri = `http://${this.callbackHostname}:${actualPort}${this.callbackPath}`;
327
+ const launchUrl = this.#launchUrlIfSafe(actualPort);
328
+ this.ctrl.onProgress?.(`Preferred port ${this.preferredPort} unavailable, using port ${actualPort}`);
329
+ return {
330
+ server,
331
+ redirectUri,
332
+ launchUrl
333
+ };
334
+ }
335
+ }
336
+ /**
337
+ * Read the numeric port a callback server bound to. `Bun.Server.port` is
338
+ * declared `number | undefined` because Unix-socket servers have no port,
339
+ * but every callback flow uses TCP; a missing port here indicates a
340
+ * configuration error rather than a fallback case.
341
+ */
342
+ #resolveServerPort(server) {
343
+ const port = server.port;
344
+ if (typeof port !== "number") throw new ConfigurationError("OAuth callback server bound to a non-TCP endpoint; expected a numeric port. Check `oauth.callbackPort`/`oauth.redirectUri`.");
345
+ return port;
346
+ }
347
+ /**
348
+ * Build the `/launch` URL served by the callback server bound to `port`, or
349
+ * `undefined` when it must not be advertised:
350
+ * - the configured `callbackPath` (or a `redirectUri` whose pathname
351
+ * resolves to {@link LAUNCH_PATH}) would collide with the launch route;
352
+ * - the flow's `redirectUri` never returns to this loopback server: fixed
353
+ * non-loopback hosts, or custom schemes like GitLab Duo's `vscode://`
354
+ * URI — which `new URL` parses without complaint, so a scheme/host check
355
+ * is required, not just the parse failure path. Advertising a localhost
356
+ * `/launch` target for such flows misrepresents the callback endpoint
357
+ * and hands remote users a URL that resolves nowhere.
358
+ * Kept short (~30 chars) so UIs can advertise it as a
359
+ * viewport-truncation-safe copy target for the full authorization URL.
360
+ */
361
+ #launchUrlIfSafe(port) {
362
+ if (this.callbackPath === LAUNCH_PATH) return void 0;
363
+ if (this.redirectUri) try {
364
+ const parsed = new URL(this.redirectUri);
365
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
366
+ if (parsed.hostname !== "localhost" && parsed.hostname !== "127.0.0.1" && parsed.hostname !== "[::1]") return;
367
+ if (parsed.pathname === LAUNCH_PATH) return void 0;
368
+ } catch {
369
+ return;
370
+ }
371
+ return `http://${this.callbackHostname}:${port}${LAUNCH_PATH}`;
372
+ }
373
+ /**
374
+ * Create the HTTP listener(s) for the OAuth callback.
375
+ *
376
+ * `localhost` is not a single endpoint: it resolves to both
377
+ * {@link IPV4_LOOPBACK} and {@link IPV6_LOOPBACK}, and clients commonly try
378
+ * `::1` first. Binding only the IPv4 literal hands the authorization code to
379
+ * whatever holds the IPv6 loopback on the same port — a dev server on
380
+ * `*:3000` is the common case — which answers from its own routes while this
381
+ * flow waits out the full {@link DEFAULT_TIMEOUT}. Nothing detects it either:
382
+ * a specific-address bind coexists with another process's wildcard bind, so
383
+ * `Bun.serve` reports the port as free and the random-port fallback in
384
+ * {@link #startCallbackServer} never runs.
385
+ *
386
+ * Binding both loopback literals fixes the delivery rather than dodging it:
387
+ * the kernel routes a connection to the most specific matching bind, so our
388
+ * `::1` listener receives `localhost` traffic that would otherwise reach a
389
+ * process bound to the `::` wildcard. Both listeners answer the same routes,
390
+ * so which family the client resolves stops mattering.
391
+ *
392
+ * A genuine collision — another process on exactly this loopback address and
393
+ * port — still raises EADDRINUSE and reaches the caller's in-use policy. A
394
+ * host that cannot bind `::1` at all (IPv6 disabled, address unavailable) is
395
+ * not a collision: the IPv4 listener is the only reachable endpoint there, so
396
+ * it serves alone.
397
+ */
398
+ #createServer(port, expectedState) {
399
+ if (this.callbackHostname !== DEFAULT_HOSTNAME) return this.#serve(this.callbackHostname, port, expectedState);
400
+ const dualStack = ipv6LoopbackAvailable();
401
+ for (let attempt = 0;; attempt++) {
402
+ const primary = this.#serve(IPV4_LOOPBACK, port, expectedState);
403
+ const boundPort = primary.port;
404
+ if (typeof boundPort !== "number") return primary;
405
+ if (!dualStack) return primary;
406
+ let companion;
407
+ try {
408
+ companion = this.#serve(IPV6_LOOPBACK, boundPort, expectedState);
409
+ } catch (cause) {
410
+ if (!isAddressInUse(cause)) return primary;
411
+ primary.stop(true);
412
+ if (port !== 0 || attempt >= IPV6_COMPANION_ATTEMPTS) throw cause;
413
+ continue;
414
+ }
415
+ return {
416
+ get port() {
417
+ return primary.port;
418
+ },
419
+ stop: (closeActiveConnections) => {
420
+ companion.stop(closeActiveConnections);
421
+ return primary.stop(closeActiveConnections);
422
+ }
423
+ };
424
+ }
425
+ }
426
+ /** Bind one loopback listener serving the callback and launch routes. */
427
+ #serve(hostname, port, expectedState) {
428
+ return Bun.serve({
429
+ hostname,
430
+ port,
431
+ reusePort: false,
432
+ fetch: (req) => this.#handleCallback(req, expectedState)
433
+ });
434
+ }
435
+ /**
436
+ * Handle OAuth callback HTTP request. Two routes on the same loopback server:
437
+ * - `callbackPath` (default `/callback`) — the provider redirect target.
438
+ * - {@link LAUNCH_PATH} (`/launch`) — 302 to the pending authorization URL so
439
+ * viewport-safe copy targets can survive TUI truncation.
440
+ *
441
+ * `callbackPath` wins any collision: an OMP config that pins the provider
442
+ * redirect at `/launch` (via `oauth.callbackPath` or a loopback
443
+ * `oauth.redirectUri`) must resolve the callback normally rather than
444
+ * self-redirect. `#startCallbackServer` also suppresses `launchUrl` in that
445
+ * case, so the launch route is never advertised when it would collide.
446
+ */
447
+ #handleCallback(req, expectedState) {
448
+ const url = new URL(req.url);
449
+ if (url.pathname !== this.callbackPath) {
450
+ if (url.pathname === LAUNCH_PATH) {
451
+ const pending = this.#pendingAuthUrl;
452
+ if (!pending) return new Response("OAuth launch URL is no longer active", { status: 503 });
453
+ return Response.redirect(pending, 302);
454
+ }
455
+ return new Response("Not Found", { status: 404 });
456
+ }
457
+ const code = url.searchParams.get("code");
458
+ const state = url.searchParams.get("state") || "";
459
+ const error = url.searchParams.get("error") || "";
460
+ const errorDescription = url.searchParams.get("error_description") || error;
461
+ let resultState;
462
+ if (error) resultState = {
463
+ ok: false,
464
+ error: `Authorization failed: ${errorDescription}`
465
+ };
466
+ else if (!code) resultState = {
467
+ ok: false,
468
+ error: "Missing authorization code"
469
+ };
470
+ else if (expectedState && state !== expectedState) resultState = {
471
+ ok: false,
472
+ error: "State mismatch - possible CSRF attack"
473
+ };
474
+ else resultState = {
475
+ ok: true,
476
+ code,
477
+ state
478
+ };
479
+ if (resultState.ok) {
480
+ const resolve = this.#callbackResolve;
481
+ queueMicrotask(() => {
482
+ resolve?.({
483
+ code: resultState.code,
484
+ state: resultState.state
485
+ });
486
+ });
487
+ } else if (error && (!expectedState || state === expectedState)) {
488
+ const reject = this.#callbackReject;
489
+ const message = resultState.error ?? `Authorization failed: ${errorDescription}`;
490
+ queueMicrotask(() => {
491
+ reject?.(new OAuthError(message, { kind: "device-auth" }));
492
+ });
493
+ }
494
+ return new Response(oauth_default.replaceAll("__OAUTH_STATE__", () => serializeCallbackState(resultState)), {
495
+ status: resultState.ok ? 200 : 500,
496
+ headers: { "Content-Type": "text/html" }
497
+ });
498
+ }
499
+ /**
500
+ * Wait for OAuth callback or manual input (whichever comes first).
501
+ */
502
+ #waitForCallback(expectedState, nativeCallback) {
503
+ const timeoutSignal = AbortSignal.timeout(DEFAULT_TIMEOUT);
504
+ const settledSignal = new AbortController();
505
+ const signals = this.ctrl.signal ? [
506
+ this.ctrl.signal,
507
+ timeoutSignal,
508
+ settledSignal.signal
509
+ ] : [timeoutSignal, settledSignal.signal];
510
+ const signal = AbortSignal.any(signals);
511
+ if (signal.aborted) return Promise.reject(this.#loginCancelledError());
512
+ const callback = Promise.withResolvers();
513
+ this.#callbackResolve = callback.resolve;
514
+ this.#callbackReject = callback.reject;
515
+ signal.addEventListener("abort", () => {
516
+ this.#callbackResolve = void 0;
517
+ this.#callbackReject = void 0;
518
+ callback.reject(new LoginCancelledError(`OAuth callback cancelled: ${signal.reason}`));
519
+ }, { once: true });
520
+ const callbackPromise = callback.promise;
521
+ const candidates = [callbackPromise];
522
+ if (nativeCallback) candidates.push(nativeCallback);
523
+ if (this.ctrl.onManualCodeInput) {
524
+ const requestManualInput = this.ctrl.onManualCodeInput;
525
+ const manualPromise = (async () => {
526
+ while (true) {
527
+ const result = await Promise.race([callbackPromise, requestManualInput(signal).then((input) => {
528
+ const parsed = parseCallbackInput(input);
529
+ if (!parsed.code) return null;
530
+ if (expectedState && parsed.state && parsed.state !== expectedState) return null;
531
+ return {
532
+ code: parsed.code,
533
+ state: parsed.state ?? ""
534
+ };
535
+ })]);
536
+ if (result) return result;
537
+ }
538
+ })();
539
+ candidates.push(manualPromise);
540
+ }
541
+ return Promise.race(candidates).finally(() => {
542
+ this.#callbackResolve = void 0;
543
+ this.#callbackReject = void 0;
544
+ settledSignal.abort("OAuth callback settled");
545
+ });
546
+ }
547
+ };
548
+ /**
549
+ * Parse a redirect URL or code string to extract code and state.
550
+ */
551
+ function parseCallbackInput(input) {
552
+ const value = input.trim();
553
+ if (!value) return {};
554
+ try {
555
+ const url = new URL(value);
556
+ return {
557
+ code: url.searchParams.get("code") ?? void 0,
558
+ state: url.searchParams.get("state") ?? void 0
559
+ };
560
+ } catch {}
561
+ if (value.includes("code=")) {
562
+ const params = new URLSearchParams(value.replace(/^[?#]/, ""));
563
+ return {
564
+ code: params.get("code") ?? void 0,
565
+ state: params.get("state") ?? void 0
566
+ };
567
+ }
568
+ const [code, state] = value.split("#", 2);
569
+ return {
570
+ code,
571
+ state
572
+ };
573
+ }
574
+ //#endregion
575
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/registry/snowflake.ts
576
+ const SNOWFLAKE_ACCOUNT_ORIGIN_PLACEHOLDER = "https://snowflake-account.invalid";
577
+ const INVALID_ACCOUNT_MESSAGE = "Paste your Snowflake account identifier (orgname-accountname) or account URL";
578
+ const DNS_LABEL = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
579
+ const LEGACY_SNOWSIGHT_REGION = /^[a-z]{2}(?:-gov)?-[a-z]+-\d+$/;
580
+ function isDnsLabel(label) {
581
+ return label.length <= 63 && DNS_LABEL.test(label);
582
+ }
583
+ /** Normalize account identifiers and Snowsight links without accepting arbitrary credential-receiving hosts. */
584
+ function normalizeSnowflakeAccountUrl(input) {
585
+ const value = input.trim();
586
+ if (!value) throw new ConfigurationError("Snowflake account is required: run /login snowflake or set SNOWFLAKE_ACCOUNT");
587
+ const scheme = /^([a-z][a-z0-9+.-]*):\/\//i.exec(value);
588
+ if (scheme && scheme[1].toLowerCase() !== "https") throw new ConfigurationError("Snowflake account URL must use https");
589
+ if (value.includes("\\")) throw new ConfigurationError(INVALID_ACCOUNT_MESSAGE);
590
+ let host;
591
+ if (scheme) {
592
+ const url = /^https:\/\/([^/?#]+)(.*)$/i.exec(value);
593
+ if (!url) throw new ConfigurationError(INVALID_ACCOUNT_MESSAGE);
594
+ host = url[1].toLowerCase().replaceAll("_", "-");
595
+ if (host.endsWith(":443")) host = host.slice(0, -4);
596
+ if (host === "app.snowflake.com") {
597
+ const segments = url[2].split(/[?#]/, 1)[0].split("/");
598
+ const org = segments[1]?.toLowerCase().replaceAll("_", "-") ?? "";
599
+ const account = segments[2]?.toLowerCase().replaceAll("_", "-") ?? "";
600
+ if (!isDnsLabel(org) || !isDnsLabel(account)) throw new ConfigurationError(INVALID_ACCOUNT_MESSAGE);
601
+ if (LEGACY_SNOWSIGHT_REGION.test(org)) throw new ConfigurationError("Legacy Snowsight links don't identify the account host; paste your account identifier (orgname-accountname) or account URL");
602
+ host = `${org}-${account}.snowflakecomputing.com`;
603
+ }
604
+ } else {
605
+ if (/[/?#]/.test(value)) throw new ConfigurationError(INVALID_ACCOUNT_MESSAGE);
606
+ host = value.toLowerCase().replaceAll("_", "-");
607
+ if (host.endsWith(":443")) host = host.slice(0, -4);
608
+ if (!host.endsWith(".snowflakecomputing.com") && !host.endsWith(".snowflakecomputing.cn")) host += ".snowflakecomputing.com";
609
+ }
610
+ if (host.endsWith(".snowflakecomputing.cn")) throw new ConfigurationError("Snowflake Cortex REST API is not available in China-region accounts (.snowflakecomputing.cn)");
611
+ if (!host.endsWith(".snowflakecomputing.com") || host.length === 23 || !host.split(".").every(isDnsLabel)) throw new ConfigurationError(INVALID_ACCOUNT_MESSAGE);
612
+ return `https://${host}`;
613
+ }
614
+ const INVALID_CREDENTIAL_MESSAGE = "Invalid Snowflake credential; run /login snowflake again";
615
+ /** Decode the registry's structured OAuth key; malformed JSON must never become a bearer token. */
616
+ function parseSnowflakeCredential(value) {
617
+ const trimmed = value.trim();
618
+ if (!trimmed) return null;
619
+ if (!trimmed.startsWith("{")) return { token: trimmed };
620
+ let credential;
621
+ try {
622
+ credential = JSON.parse(trimmed);
623
+ } catch {
624
+ throw new ConfigurationError(INVALID_CREDENTIAL_MESSAGE);
625
+ }
626
+ if (!credential || typeof credential !== "object" || !("token" in credential) || typeof credential.token !== "string" || !credential.token.trim() || !("enterpriseUrl" in credential) || typeof credential.enterpriseUrl !== "string" || !credential.enterpriseUrl.trim()) throw new ConfigurationError(INVALID_CREDENTIAL_MESSAGE);
627
+ let accountUrl;
628
+ try {
629
+ accountUrl = normalizeSnowflakeAccountUrl(credential.enterpriseUrl);
630
+ } catch (error) {
631
+ const reason = error instanceof Error ? error.message : String(error);
632
+ throw new ConfigurationError(`Invalid Snowflake credential account: ${reason}; run /login snowflake again`);
633
+ }
634
+ return {
635
+ token: credential.token.trim(),
636
+ accountUrl
637
+ };
638
+ }
639
+ const snowflakeTransport = { prepareRequest: (model, options) => {
640
+ const credential = parseSnowflakeCredential(options.apiKey?.trim() || $env.SNOWFLAKE_PAT || "");
641
+ if (!credential) return {
642
+ model,
643
+ options
644
+ };
645
+ let baseUrl = model.baseUrl;
646
+ if (baseUrl === SNOWFLAKE_ACCOUNT_ORIGIN_PLACEHOLDER || baseUrl.startsWith(`${SNOWFLAKE_ACCOUNT_ORIGIN_PLACEHOLDER}/`)) baseUrl = (credential.accountUrl ?? normalizeSnowflakeAccountUrl($env.SNOWFLAKE_ACCOUNT ?? "")) + baseUrl.slice(33);
647
+ else if (credential.accountUrl) {
648
+ let origin;
649
+ try {
650
+ origin = new URL(baseUrl).origin;
651
+ } catch {}
652
+ if (origin !== credential.accountUrl) throw new ConfigurationError("Snowflake OAuth account does not match the model endpoint");
653
+ }
654
+ return {
655
+ model: baseUrl === model.baseUrl ? model : {
656
+ ...model,
657
+ baseUrl
658
+ },
659
+ options: {
660
+ ...options,
661
+ apiKey: credential.token
662
+ }
663
+ };
664
+ } };
665
+ //#endregion
666
+ export { authProviders as a, authPolicyFor as i, snowflakeTransport as n, OAuthCallbackFlow as r, normalizeSnowflakeAccountUrl as t };