@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.
- package/README.en.md +122 -0
- package/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +4 -35
- package/lib/abort-B7izMMna.mjs +51 -0
- package/lib/amazon-bedrock-D-shAr1X.mjs +917 -0
- package/lib/anthropic-BWsZFzU8.mjs +262 -0
- package/lib/anthropic-CMT1Qj1t.mjs +3115 -0
- package/lib/api-key-login-CpzSezsi.mjs +157 -0
- package/lib/aws-credentials-8Mgn5MAy.mjs +867 -0
- package/lib/azure-openai-responses-CNkHiLUh.mjs +274 -0
- package/lib/bun-shim.mjs +172 -7
- package/lib/bundled-references-CSuBco5p.mjs +55 -0
- package/lib/callback-server-BEFNf-jf.mjs +398 -0
- package/lib/client.js +110 -40
- package/lib/cursor-BIQfBC6V.mjs +135 -0
- package/lib/cursor-DNk6eXDd.mjs +5470 -0
- package/lib/cursor-MjSm74IJ.mjs +273 -0
- package/lib/device-code-OI_tQcmc.mjs +51 -0
- package/lib/devin-CldyPD8K.mjs +95 -0
- package/lib/devin-CzRpTUOA.mjs +114 -0
- package/lib/devin-DXOeNyU7.mjs +542 -0
- package/lib/error-B3bevhrs.mjs +1449 -0
- package/lib/event-stream-BDPi64mK.mjs +151 -0
- package/lib/github-copilot-4GaMtQmg.mjs +208 -0
- package/lib/github-copilot-B2HGSIJK.mjs +104 -0
- package/lib/gitlab-duo-akICyfeD.mjs +155 -0
- package/lib/gitlab-duo-workflow-CSEgYk3N.mjs +91 -0
- package/lib/google-antigravity-Dlkdhahq.mjs +198 -0
- package/lib/google-auth-DhqpOYrX.mjs +232 -0
- package/lib/google-gemini-cli-BG_LRdIV.mjs +850 -0
- package/lib/google-gemini-cli-zJhiOcND.mjs +211 -0
- package/lib/google-oauth-shared-CwNWYdmR.mjs +147 -0
- package/lib/google-shared-DzhCb9b0.mjs +760 -0
- package/lib/google-vertex-kscbkyRb.mjs +99 -0
- package/lib/google-zyDOG9x7.mjs +30 -0
- package/lib/identity-DnB63pS7.mjs +219 -0
- package/lib/idle-iterator-C6XbWcuB.mjs +366 -0
- package/lib/index.mjs +2865 -2745
- package/lib/kimi-DMVI-zrZ.mjs +236 -0
- package/lib/markit-M0jhziqU.mjs +1417 -0
- package/lib/minimax-code-BK-3eBbz.mjs +53 -0
- package/lib/models-CfT4coYT.mjs +104660 -0
- package/lib/ollama-BQMGPxtV.mjs +589 -0
- package/lib/openai-codex-CQL_kvYL.mjs +255 -0
- package/lib/openai-codex-responses-Cz-2qpC7.mjs +3144 -0
- package/lib/openai-completions-i8doczAk.mjs +1360 -0
- package/lib/openai-reasoning-fallback-DGVVLgd1.mjs +286 -0
- package/lib/openai-responses-DTkBiiy-.mjs +867 -0
- package/lib/opencode-DaJjcUbf.mjs +38 -0
- package/lib/perplexity-9b-RQ0mV.mjs +194 -0
- package/lib/proxy-ZtUcl6r5.mjs +190 -0
- package/lib/scrapers-CL-WgdU1.mjs +9198 -0
- package/lib/scrapers-CipyKyCH.mjs +9198 -0
- package/lib/scrapers-DGfrYhtw.mjs +9198 -0
- package/lib/scrapers-DSUPYoUF.mjs +9198 -0
- package/lib/scrapers-DZ2GXmp7.mjs +9198 -0
- package/lib/src-DTid0g4K.mjs +5001 -0
- package/lib/stream-C_RAoxJC.mjs +10236 -0
- package/lib/stream-markup-healing-2toHXWXM.mjs +491 -0
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/config/fields.d.ts +1 -1
- package/lib/types/config/settings.d.ts +16 -2
- package/lib/types/tools/omp/sdk.d.ts +6 -0
- package/lib/types/tools/omp/tools/fetch.d.ts +2 -0
- package/lib/types/tools/omp/tools/read.d.ts +2 -8
- package/lib/types/tools/omp/utils/image-loading.d.ts +10 -36
- package/lib/types/tools/read/adapter/index.d.ts +4 -1
- package/lib/types/tools/read-image/index.d.ts +4 -0
- package/lib/types/tools/shared/bun-shim.d.ts +35 -3
- package/lib/types/tools/shared/image-bridge.d.ts +98 -0
- package/lib/types/tools/shared/omp-prompt.d.ts +4 -2
- package/lib/utils-2Wq2eATG.mjs +8119 -0
- package/lib/utils-BnX8O3vi.mjs +12303 -0
- package/lib/utils-CE8N8P4Q.mjs +12315 -0
- package/lib/utils-C_MrQ_0z.mjs +12301 -0
- package/lib/utils-D0Z1fyoO.mjs +12299 -0
- package/lib/utils-DppGHXQB.mjs +51 -0
- package/lib/utils-W8WdSBpX.mjs +12315 -0
- package/lib/vision-guard-BDD4OrKo.mjs +92 -0
- package/lib/wafer-DRU0EjZX.mjs +17 -0
- package/lib/xai-oauth-DPHDXKD7.mjs +446 -0
- package/lib/xiaomi-Dd87KSg5.mjs +157 -0
- package/lib/zai-CFeOt-53.mjs +203 -0
- package/lib/zip-D6QXpvaJ.mjs +1316 -0
- package/package.json +14 -10
- package/presets/package.json +1 -1
- package/presets/tool-plus-ptc/preset.yml +1 -1
- package/presets/tool-plus-standard/preset.yml +1 -1
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
|
+
__installBunShim();
|
|
3
|
+
import { P as $env } from "./src-DTid0g4K.mjs";
|
|
4
|
+
import { c as OAuthError } from "./error-B3bevhrs.mjs";
|
|
5
|
+
import { i as getGeminiCliHeaders } from "./gemini-headers-DKUShltF.mjs";
|
|
6
|
+
import { n as runGoogleOAuthLogin, r as throwIfLoginCancelled, t as oauthFetch } from "./google-oauth-shared-CwNWYdmR.mjs";
|
|
7
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/registry/oauth/google-gemini-cli.ts
|
|
8
|
+
/**
|
|
9
|
+
* Gemini CLI OAuth flow (Google Cloud Code Assist)
|
|
10
|
+
* Standard Gemini models only (gemini-2.0-flash, gemini-2.5-*)
|
|
11
|
+
*/
|
|
12
|
+
const decode = (s) => atob(s);
|
|
13
|
+
const CLIENT_ID = decode("NjgxMjU1ODA5Mzk1LW9vOGZ0Mm9wcmRybnA5ZTNhcWY2YXYzaG1kaWIxMzVqLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29t");
|
|
14
|
+
const CLIENT_SECRET = decode("R09DU1BYLTR1SGdNUG0tMW83U2stZ2VWNkN1NWNsWEZzeGw=");
|
|
15
|
+
const CALLBACK_PORT = 8085;
|
|
16
|
+
const CALLBACK_PATH = "/oauth2callback";
|
|
17
|
+
const SCOPES = [
|
|
18
|
+
"https://www.googleapis.com/auth/cloud-platform",
|
|
19
|
+
"https://www.googleapis.com/auth/userinfo.email",
|
|
20
|
+
"https://www.googleapis.com/auth/userinfo.profile"
|
|
21
|
+
];
|
|
22
|
+
const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
23
|
+
const TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
24
|
+
const CODE_ASSIST_ENDPOINT = "https://cloudcode-pa.googleapis.com";
|
|
25
|
+
const TIER_FREE = "free-tier";
|
|
26
|
+
const TIER_LEGACY = "legacy-tier";
|
|
27
|
+
const TIER_STANDARD = "standard-tier";
|
|
28
|
+
function getDefaultTier(allowedTiers) {
|
|
29
|
+
if (!allowedTiers || allowedTiers.length === 0) return { id: TIER_LEGACY };
|
|
30
|
+
return allowedTiers.find((t) => t.isDefault) ?? { id: TIER_LEGACY };
|
|
31
|
+
}
|
|
32
|
+
function isVpcScAffectedUser(payload) {
|
|
33
|
+
if (!payload || typeof payload !== "object") return false;
|
|
34
|
+
if (!("error" in payload)) return false;
|
|
35
|
+
const error = payload.error;
|
|
36
|
+
if (!error?.details || !Array.isArray(error.details)) return false;
|
|
37
|
+
return error.details.some((detail) => detail.reason === "SECURITY_POLICY_VIOLATED");
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* LRO poll cadence and bound. Cloud Code Assist project provisioning normally
|
|
41
|
+
* completes within a handful of polls; the attempt cap converts a stuck
|
|
42
|
+
* `done: false` operation (or a service incident) into a bounded login error
|
|
43
|
+
* instead of the previous unbounded loop.
|
|
44
|
+
*/
|
|
45
|
+
const POLL_INTERVAL_MS = 5e3;
|
|
46
|
+
async function pollOperation(operationName, headers, signal, onProgress) {
|
|
47
|
+
for (let attempt = 0; attempt < 24; attempt += 1) {
|
|
48
|
+
if (attempt > 0) {
|
|
49
|
+
onProgress?.(`Waiting for project provisioning (attempt ${attempt + 1}/24)...`);
|
|
50
|
+
throwIfLoginCancelled(signal);
|
|
51
|
+
await Bun.sleep(POLL_INTERVAL_MS);
|
|
52
|
+
}
|
|
53
|
+
throwIfLoginCancelled(signal);
|
|
54
|
+
const response = await oauthFetch(`${CODE_ASSIST_ENDPOINT}/v1internal/${operationName}`, {
|
|
55
|
+
method: "GET",
|
|
56
|
+
headers
|
|
57
|
+
}, {
|
|
58
|
+
provider: "google-gemini-cli",
|
|
59
|
+
signal
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) throw new OAuthError(`Failed to poll operation: ${response.status} ${response.statusText}`, {
|
|
62
|
+
kind: "polling",
|
|
63
|
+
provider: "google-gemini-cli",
|
|
64
|
+
status: response.status
|
|
65
|
+
});
|
|
66
|
+
const data = await response.json();
|
|
67
|
+
if (data.done) return data;
|
|
68
|
+
}
|
|
69
|
+
throw new OAuthError(`Project provisioning did not complete after 24 attempts`, {
|
|
70
|
+
kind: "timeout",
|
|
71
|
+
provider: "google-gemini-cli"
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async function discoverProject(accessToken, onProgress, signal) {
|
|
75
|
+
const envProjectId = $env.GOOGLE_CLOUD_PROJECT || $env.GOOGLE_CLOUD_PROJECT_ID;
|
|
76
|
+
const headers = {
|
|
77
|
+
Authorization: `Bearer ${accessToken}`,
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
...getGeminiCliHeaders()
|
|
80
|
+
};
|
|
81
|
+
onProgress?.("Checking for existing Cloud Code Assist project...");
|
|
82
|
+
const loadResponse = await oauthFetch(`${CODE_ASSIST_ENDPOINT}/v1internal:loadCodeAssist`, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers,
|
|
85
|
+
body: JSON.stringify({
|
|
86
|
+
cloudaicompanionProject: envProjectId,
|
|
87
|
+
metadata: {
|
|
88
|
+
ideType: "IDE_UNSPECIFIED",
|
|
89
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
90
|
+
pluginType: "GEMINI",
|
|
91
|
+
duetProject: envProjectId
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}, {
|
|
95
|
+
provider: "google-gemini-cli",
|
|
96
|
+
signal
|
|
97
|
+
});
|
|
98
|
+
let data;
|
|
99
|
+
if (!loadResponse.ok) {
|
|
100
|
+
let errorPayload;
|
|
101
|
+
try {
|
|
102
|
+
errorPayload = await loadResponse.clone().json();
|
|
103
|
+
} catch {
|
|
104
|
+
errorPayload = void 0;
|
|
105
|
+
}
|
|
106
|
+
if (isVpcScAffectedUser(errorPayload)) data = { currentTier: { id: TIER_STANDARD } };
|
|
107
|
+
else {
|
|
108
|
+
const errorText = await loadResponse.text();
|
|
109
|
+
throw new OAuthError(`loadCodeAssist failed: ${loadResponse.status} ${loadResponse.statusText}: ${errorText}`, {
|
|
110
|
+
kind: "discovery",
|
|
111
|
+
provider: "google-gemini-cli",
|
|
112
|
+
status: loadResponse.status
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
} else data = await loadResponse.json();
|
|
116
|
+
if (data.currentTier) {
|
|
117
|
+
if (data.cloudaicompanionProject) return data.cloudaicompanionProject;
|
|
118
|
+
if (envProjectId) return envProjectId;
|
|
119
|
+
throw new OAuthError("This account requires setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID environment variable. See https://goo.gle/gemini-cli-auth-docs#workspace-gca", {
|
|
120
|
+
kind: "configuration",
|
|
121
|
+
provider: "google-gemini-cli"
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
const tierId = getDefaultTier(data.allowedTiers)?.id ?? TIER_FREE;
|
|
125
|
+
if (tierId !== TIER_FREE && !envProjectId) throw new OAuthError("This account requires setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID environment variable. See https://goo.gle/gemini-cli-auth-docs#workspace-gca", {
|
|
126
|
+
kind: "configuration",
|
|
127
|
+
provider: "google-gemini-cli"
|
|
128
|
+
});
|
|
129
|
+
onProgress?.("Provisioning Cloud Code Assist project (this may take a moment)...");
|
|
130
|
+
const onboardBody = {
|
|
131
|
+
tierId,
|
|
132
|
+
metadata: {
|
|
133
|
+
ideType: "IDE_UNSPECIFIED",
|
|
134
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
135
|
+
pluginType: "GEMINI"
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
if (tierId !== TIER_FREE && envProjectId) {
|
|
139
|
+
onboardBody.cloudaicompanionProject = envProjectId;
|
|
140
|
+
onboardBody.metadata.duetProject = envProjectId;
|
|
141
|
+
}
|
|
142
|
+
const onboardResponse = await oauthFetch(`${CODE_ASSIST_ENDPOINT}/v1internal:onboardUser`, {
|
|
143
|
+
method: "POST",
|
|
144
|
+
headers,
|
|
145
|
+
body: JSON.stringify(onboardBody)
|
|
146
|
+
}, {
|
|
147
|
+
provider: "google-gemini-cli",
|
|
148
|
+
signal
|
|
149
|
+
});
|
|
150
|
+
if (!onboardResponse.ok) {
|
|
151
|
+
const errorText = await onboardResponse.text();
|
|
152
|
+
throw new OAuthError(`onboardUser failed: ${onboardResponse.status} ${onboardResponse.statusText}: ${errorText}`, {
|
|
153
|
+
kind: "provisioning",
|
|
154
|
+
provider: "google-gemini-cli",
|
|
155
|
+
status: onboardResponse.status
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
let lroData = await onboardResponse.json();
|
|
159
|
+
if (!lroData.done && lroData.name) lroData = await pollOperation(lroData.name, headers, signal, onProgress);
|
|
160
|
+
const projectId = lroData.response?.cloudaicompanionProject?.id;
|
|
161
|
+
if (projectId) return projectId;
|
|
162
|
+
if (envProjectId) return envProjectId;
|
|
163
|
+
throw new OAuthError("Could not discover or provision a Google Cloud project. Try setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID environment variable. See https://goo.gle/gemini-cli-auth-docs#workspace-gca", {
|
|
164
|
+
kind: "validation",
|
|
165
|
+
provider: "google-gemini-cli"
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async function loginGeminiCli(ctrl) {
|
|
169
|
+
return runGoogleOAuthLogin(ctrl, {
|
|
170
|
+
provider: "google-gemini-cli",
|
|
171
|
+
clientId: CLIENT_ID,
|
|
172
|
+
clientSecret: CLIENT_SECRET,
|
|
173
|
+
authUrl: AUTH_URL,
|
|
174
|
+
tokenUrl: TOKEN_URL,
|
|
175
|
+
scopes: SCOPES,
|
|
176
|
+
callbackPort: CALLBACK_PORT,
|
|
177
|
+
callbackPath: CALLBACK_PATH,
|
|
178
|
+
discoverProject
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Refresh Google Cloud Code Assist token
|
|
183
|
+
*/
|
|
184
|
+
async function refreshGoogleCloudToken(refreshToken, projectId) {
|
|
185
|
+
const response = await fetch(TOKEN_URL, {
|
|
186
|
+
method: "POST",
|
|
187
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
188
|
+
body: new URLSearchParams({
|
|
189
|
+
client_id: CLIENT_ID,
|
|
190
|
+
client_secret: CLIENT_SECRET,
|
|
191
|
+
refresh_token: refreshToken,
|
|
192
|
+
grant_type: "refresh_token"
|
|
193
|
+
})
|
|
194
|
+
});
|
|
195
|
+
if (!response.ok) {
|
|
196
|
+
const error = await response.text();
|
|
197
|
+
throw new OAuthError(`Google Cloud token refresh failed: ${error}`, {
|
|
198
|
+
kind: "token-refresh",
|
|
199
|
+
provider: "google-gemini-cli"
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
const data = await response.json();
|
|
203
|
+
return {
|
|
204
|
+
refresh: data.refresh_token || refreshToken,
|
|
205
|
+
access: data.access_token,
|
|
206
|
+
expires: Date.now() + data.expires_in * 1e3 - 3e5,
|
|
207
|
+
projectId
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
export { loginGeminiCli, refreshGoogleCloudToken };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
|
+
__installBunShim();
|
|
3
|
+
import { c as OAuthError, h as LoginCancelledError } from "./error-B3bevhrs.mjs";
|
|
4
|
+
import { t as OAuthCallbackFlow } from "./callback-server-BEFNf-jf.mjs";
|
|
5
|
+
import { n as formatGoogleValidationRequiredMessage, t as extractGoogleValidationUrl } from "./google-validation-Cgbn3tWJ.mjs";
|
|
6
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/registry/oauth/google-oauth-shared.ts
|
|
7
|
+
/**
|
|
8
|
+
* Shared OAuth flow for Google-style providers (Gemini CLI, Antigravity).
|
|
9
|
+
*
|
|
10
|
+
* Both providers use the same authorization-code flow shape; only the client
|
|
11
|
+
* credentials, scopes, endpoint constants, and project-discovery logic differ.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Per-request timeout for the post-callback provisioning phase (token exchange,
|
|
15
|
+
* user-info, project discovery/onboarding, LRO polling). These Cloud Code
|
|
16
|
+
* Assist calls normally settle in well under this window; a longer stall means
|
|
17
|
+
* a hung endpoint that must surface a login error instead of hanging forever.
|
|
18
|
+
* The callback server's own 300s deadline covers only the browser-callback wait
|
|
19
|
+
* ({@link OAuthCallbackFlow}) and does not gate this phase.
|
|
20
|
+
*/
|
|
21
|
+
const OAUTH_REQUEST_TIMEOUT_MS = 3e4;
|
|
22
|
+
/**
|
|
23
|
+
* Throw {@link AIError.LoginCancelledError} when the controller signal has
|
|
24
|
+
* already aborted. Gates each provisioning round-trip, which the callback-wait
|
|
25
|
+
* cancellation checks in {@link OAuthCallbackFlow} do not reach.
|
|
26
|
+
*/
|
|
27
|
+
function throwIfLoginCancelled(signal) {
|
|
28
|
+
if (signal?.aborted) throw new LoginCancelledError(`OAuth login cancelled: ${String(signal.reason)}`);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* `fetch` for the provisioning phase: composes the controller signal with a
|
|
32
|
+
* per-request timeout so a stalled endpoint aborts instead of hanging login,
|
|
33
|
+
* and user cancellation aborts the in-flight request. Cancellation surfaces as
|
|
34
|
+
* {@link AIError.LoginCancelledError}; a timeout surfaces as an
|
|
35
|
+
* {@link AIError.OAuthError} with `kind: "timeout"`.
|
|
36
|
+
*/
|
|
37
|
+
async function oauthFetch(url, init, { provider, signal, timeoutMs = OAUTH_REQUEST_TIMEOUT_MS }) {
|
|
38
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
39
|
+
const requestSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
40
|
+
try {
|
|
41
|
+
return await fetch(url, {
|
|
42
|
+
...init,
|
|
43
|
+
signal: requestSignal
|
|
44
|
+
});
|
|
45
|
+
} catch (err) {
|
|
46
|
+
if (signal?.aborted) throw new LoginCancelledError(`OAuth login cancelled: ${String(signal.reason)}`);
|
|
47
|
+
if (timeoutSignal.aborted) throw new OAuthError(`Timed out after ${timeoutMs}ms waiting for ${url}`, {
|
|
48
|
+
kind: "timeout",
|
|
49
|
+
provider
|
|
50
|
+
});
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function getUserEmail(accessToken, provider, signal) {
|
|
55
|
+
try {
|
|
56
|
+
const response = await oauthFetch("https://www.googleapis.com/oauth2/v1/userinfo?alt=json", { headers: { Authorization: `Bearer ${accessToken}` } }, {
|
|
57
|
+
provider,
|
|
58
|
+
signal
|
|
59
|
+
});
|
|
60
|
+
if (response.ok) return (await response.json()).email;
|
|
61
|
+
} catch {}
|
|
62
|
+
}
|
|
63
|
+
var GoogleOAuthFlow = class extends OAuthCallbackFlow {
|
|
64
|
+
config;
|
|
65
|
+
constructor(ctrl, config) {
|
|
66
|
+
super(ctrl, {
|
|
67
|
+
preferredPort: config.callbackPort,
|
|
68
|
+
callbackPath: config.callbackPath,
|
|
69
|
+
callbackHostname: "127.0.0.1"
|
|
70
|
+
});
|
|
71
|
+
this.config = config;
|
|
72
|
+
}
|
|
73
|
+
async generateAuthUrl(state, redirectUri) {
|
|
74
|
+
const authParams = new URLSearchParams({
|
|
75
|
+
client_id: this.config.clientId,
|
|
76
|
+
response_type: "code",
|
|
77
|
+
redirect_uri: redirectUri,
|
|
78
|
+
scope: this.config.scopes.join(" "),
|
|
79
|
+
state,
|
|
80
|
+
access_type: "offline",
|
|
81
|
+
prompt: "consent"
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
url: `${this.config.authUrl}?${authParams.toString()}`,
|
|
85
|
+
instructions: "Complete the sign-in in your browser."
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async exchangeToken(code, _state, redirectUri) {
|
|
89
|
+
const { provider } = this.config;
|
|
90
|
+
const signal = this.ctrl.signal;
|
|
91
|
+
throwIfLoginCancelled(signal);
|
|
92
|
+
this.ctrl.onProgress?.("Exchanging authorization code for tokens...");
|
|
93
|
+
const tokenResponse = await oauthFetch(this.config.tokenUrl, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
96
|
+
body: new URLSearchParams({
|
|
97
|
+
client_id: this.config.clientId,
|
|
98
|
+
client_secret: this.config.clientSecret,
|
|
99
|
+
code,
|
|
100
|
+
grant_type: "authorization_code",
|
|
101
|
+
redirect_uri: redirectUri
|
|
102
|
+
})
|
|
103
|
+
}, {
|
|
104
|
+
provider,
|
|
105
|
+
signal
|
|
106
|
+
});
|
|
107
|
+
if (!tokenResponse.ok) {
|
|
108
|
+
const error = await tokenResponse.text();
|
|
109
|
+
throw new OAuthError(`Token exchange failed: ${error}`, {
|
|
110
|
+
kind: "token-exchange",
|
|
111
|
+
provider
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const tokenData = await tokenResponse.json();
|
|
115
|
+
if (!tokenData.refresh_token) throw new OAuthError("No refresh token received. Please try again.", {
|
|
116
|
+
kind: "validation",
|
|
117
|
+
provider
|
|
118
|
+
});
|
|
119
|
+
throwIfLoginCancelled(signal);
|
|
120
|
+
this.ctrl.onProgress?.("Getting user info...");
|
|
121
|
+
const email = await getUserEmail(tokenData.access_token, provider, signal);
|
|
122
|
+
throwIfLoginCancelled(signal);
|
|
123
|
+
let projectId;
|
|
124
|
+
try {
|
|
125
|
+
projectId = await this.config.discoverProject(tokenData.access_token, this.ctrl.onProgress, signal);
|
|
126
|
+
} catch (err) {
|
|
127
|
+
const validationUrl = extractGoogleValidationUrl(err instanceof Error ? err.message : String(err));
|
|
128
|
+
if (!validationUrl) throw err;
|
|
129
|
+
throw new OAuthError(formatGoogleValidationRequiredMessage(validationUrl, "sign in again", email), {
|
|
130
|
+
kind: "validation",
|
|
131
|
+
provider
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
refresh: tokenData.refresh_token,
|
|
136
|
+
access: tokenData.access_token,
|
|
137
|
+
expires: Date.now() + tokenData.expires_in * 1e3 - 3e5,
|
|
138
|
+
projectId,
|
|
139
|
+
email
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
async function runGoogleOAuthLogin(ctrl, config) {
|
|
144
|
+
return new GoogleOAuthFlow(ctrl, config).login();
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
export { runGoogleOAuthLogin as n, throwIfLoginCancelled as r, oauthFetch as t };
|