@anthonyhaussman/opencode-agy-auth 1.2.3-alpha.4 → 1.2.3-alpha.5

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/dist/index.js CHANGED
@@ -104,8 +104,6 @@ function updateStaticModelsWithPricing(staticModels) {
104
104
 
105
105
  // src/constants.ts
106
106
  var AGY_PROVIDER_ID = "google-agy";
107
- var AGY_AUTH_URL = "https://accounts.google.com/o/oauth2/auth";
108
- var AGY_TOKEN_URL = "https://oauth2.googleapis.com/token";
109
107
  var AGY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
110
108
  var AGY_CLIENT_SECRET = "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";
111
109
  var AGY_SCOPES = [
@@ -1583,7 +1581,11 @@ function createOAuthAuthorizeMethod(options) {
1583
1581
  const isHeadless = !!(process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY || process.env.OPENCODE_HEADLESS);
1584
1582
  const authorization = await authorizeAgy();
1585
1583
  if (!isHeadless) {
1586
- openBrowserUrl(authorization.url);
1584
+ if (options?.openBrowser) {
1585
+ options.openBrowser(authorization.url);
1586
+ } else {
1587
+ openBrowserUrl(authorization.url);
1588
+ }
1587
1589
  }
1588
1590
  return {
1589
1591
  url: authorization.url,
@@ -1637,16 +1639,23 @@ function parseOAuthCallbackInput(input) {
1637
1639
  }
1638
1640
  return { code: trimmed };
1639
1641
  }
1642
+ function defaultOpenBrowserLauncher(command, args) {
1643
+ const child = spawn(command, args, {
1644
+ stdio: "ignore",
1645
+ detached: true
1646
+ });
1647
+ child.unref?.();
1648
+ }
1649
+ var openBrowserLauncher = defaultOpenBrowserLauncher;
1640
1650
  function openBrowserUrl(url2) {
1651
+ if ((process.env.NODE_ENV === "test" || process.env.VITEST) && openBrowserLauncher === defaultOpenBrowserLauncher) {
1652
+ return;
1653
+ }
1641
1654
  try {
1642
1655
  const platform2 = process.platform;
1643
1656
  const command = platform2 === "darwin" ? "open" : platform2 === "win32" ? "rundll32" : "xdg-open";
1644
1657
  const args = platform2 === "win32" ? ["url.dll,FileProtocolHandler", url2] : [url2];
1645
- const child = spawn(command, args, {
1646
- stdio: "ignore",
1647
- detached: true
1648
- });
1649
- child.unref?.();
1658
+ openBrowserLauncher(command, args);
1650
1659
  } catch {
1651
1660
  }
1652
1661
  }
@@ -20669,6 +20678,7 @@ function defineOpenCodeV2Plugin(def) {
20669
20678
  import { homedir as homedir4 } from "os";
20670
20679
  import { join as join6 } from "path";
20671
20680
  import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
20681
+ import "http";
20672
20682
  var AGY_V2_QUOTA_COMMAND = "agy-quota";
20673
20683
  var AGY_V2_QUOTA_SUMMARY_COMMAND = "agy-quota-summary";
20674
20684
  var AGY_V2_QUOTA_COMMAND_TEMPLATE = `Retrieve Agy Code Assist quota usage for the current authenticated account.
@@ -20768,7 +20778,11 @@ function resolveModelTier2(baseModelId, init) {
20768
20778
  }
20769
20779
  return mapping["medium"] ?? mapping["high"];
20770
20780
  }
20781
+ var storedAuthOverrideForTesting = void 0;
20771
20782
  function loadStoredAuthFromJson() {
20783
+ if (storedAuthOverrideForTesting !== void 0) {
20784
+ return storedAuthOverrideForTesting;
20785
+ }
20772
20786
  const authPath = join6(homedir4(), ".local", "share", "opencode", "auth.json");
20773
20787
  try {
20774
20788
  if (existsSync6(authPath)) {
@@ -21055,16 +21069,10 @@ async function setupOpenCodeV2(ctx) {
21055
21069
  label: "Antigravity CLI (OAuth)"
21056
21070
  },
21057
21071
  authorize: async () => {
21058
- const authUrl = new URL(AGY_AUTH_URL);
21059
- authUrl.searchParams.set("client_id", AGY_CLIENT_ID);
21060
- authUrl.searchParams.set("response_type", "code");
21061
- authUrl.searchParams.set("redirect_uri", "http://localhost");
21062
- authUrl.searchParams.set("scope", AGY_SCOPES.join(" "));
21063
- authUrl.searchParams.set("access_type", "offline");
21064
- authUrl.searchParams.set("prompt", "consent");
21072
+ const authorization = await authorizeAgy();
21065
21073
  return {
21066
21074
  mode: "code",
21067
- url: authUrl.toString(),
21075
+ url: authorization.url,
21068
21076
  instructions: "Please complete Google account authorization in your browser. After authorization, copy the full redirect URL or code and paste it below:",
21069
21077
  callback: async (code) => {
21070
21078
  const trimmed = code.trim();
@@ -21073,35 +21081,21 @@ async function setupOpenCodeV2(ctx) {
21073
21081
  if (!authCode) {
21074
21082
  return { type: "failed", error: "Missing authorization code in callback input" };
21075
21083
  }
21076
- const tokenResponse = await agyFetch(AGY_TOKEN_URL, {
21077
- method: "POST",
21078
- headers: {
21079
- "Content-Type": "application/x-www-form-urlencoded"
21080
- },
21081
- body: new URLSearchParams({
21082
- client_id: AGY_CLIENT_ID,
21083
- client_secret: AGY_CLIENT_SECRET,
21084
- code: authCode,
21085
- grant_type: "authorization_code",
21086
- redirect_uri: "http://localhost"
21087
- })
21088
- });
21089
- if (!tokenResponse.ok) {
21090
- const errorText = await tokenResponse.text();
21091
- return { type: "failed", error: errorText };
21084
+ if (parsed.state && parsed.state !== authorization.state) {
21085
+ return { type: "failed", error: "State mismatch in callback input (possible CSRF attempt)" };
21092
21086
  }
21093
- const tokenPayload = await tokenResponse.json();
21094
- if (!tokenPayload.refresh_token) {
21095
- return { type: "failed", error: "Missing refresh token in response" };
21087
+ const exchangeResult = await exchangeAgyWithVerifier(authCode, authorization.verifier);
21088
+ if (exchangeResult.type !== "success") {
21089
+ return exchangeResult;
21096
21090
  }
21097
21091
  const initialRefresh = formatRefreshParts({
21098
- refreshToken: tokenPayload.refresh_token
21092
+ refreshToken: exchangeResult.refresh
21099
21093
  });
21100
21094
  let authRecord = {
21101
21095
  type: "oauth",
21102
21096
  refresh: initialRefresh,
21103
- access: tokenPayload.access_token,
21104
- expires: Date.now() + tokenPayload.expires_in * 1e3
21097
+ access: exchangeResult.access,
21098
+ expires: exchangeResult.expires
21105
21099
  };
21106
21100
  try {
21107
21101
  const projectContext = await ensureProjectContext(
@@ -21160,6 +21154,19 @@ async function setupOpenCodeV2(ctx) {
21160
21154
  }
21161
21155
  }
21162
21156
  }
21157
+ if (event.request?.headers) {
21158
+ if (typeof event.request.headers.delete === "function") {
21159
+ event.request.headers.delete("x-goog-api-key");
21160
+ event.request.headers.delete("api-key");
21161
+ } else {
21162
+ for (const key of Object.keys(event.request.headers)) {
21163
+ const lower = key.toLowerCase();
21164
+ if (lower === "x-goog-api-key" || lower === "api-key") {
21165
+ delete event.request.headers[key];
21166
+ }
21167
+ }
21168
+ }
21169
+ }
21163
21170
  try {
21164
21171
  const parsedUrl = new URL(rawUrl);
21165
21172
  let urlChanged = false;
@@ -21182,18 +21189,29 @@ async function setupOpenCodeV2(ctx) {
21182
21189
  }
21183
21190
  } catch {
21184
21191
  }
21185
- const hasAuth = typeof event.headers.get === "function" ? !!event.headers.get("Authorization") : Object.keys(event.headers).some((k) => k.toLowerCase() === "authorization");
21192
+ const hasAuth = typeof event.headers?.get === "function" ? !!event.headers.get("Authorization") : event.headers && Object.keys(event.headers).some((k) => k.toLowerCase() === "authorization");
21186
21193
  if (!hasAuth) {
21187
21194
  let token;
21188
21195
  if (typeof event.auth?.access === "string" && event.auth.access) {
21189
21196
  token = event.auth.access;
21190
21197
  } else if (typeof event.auth?.token === "string" && event.auth.token) {
21191
21198
  token = event.auth.token;
21192
- }
21193
- if (typeof event.headers.set === "function") {
21194
- event.headers.set("Authorization", `Bearer ${token || "dummy"}`);
21195
21199
  } else {
21196
- event.headers["Authorization"] = `Bearer ${token || "dummy"}`;
21200
+ const storedAuth = loadStoredAuthFromJson();
21201
+ if (storedAuth && isOAuthAuth(storedAuth)) {
21202
+ const resolved = resolveCachedAuth(storedAuth);
21203
+ token = resolved.access;
21204
+ }
21205
+ }
21206
+ if (token) {
21207
+ if (typeof event.headers?.set === "function") {
21208
+ event.headers.set("Authorization", `Bearer ${token}`);
21209
+ } else if (event.headers) {
21210
+ event.headers["Authorization"] = `Bearer ${token}`;
21211
+ }
21212
+ if (event.request?.headers && typeof event.request.headers.set === "function") {
21213
+ event.request.headers.set("Authorization", `Bearer ${token}`);
21214
+ }
21197
21215
  }
21198
21216
  }
21199
21217
  }