refactor(core): simplify integration credentials (#31968)

This commit is contained in:
Dax 2026-06-12 02:15:25 -04:00 committed by GitHub
commit 30aec297d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
112 changed files with 2467 additions and 47728 deletions

View file

@ -1,6 +1,6 @@
import { createServer } from "node:http"
import { Deferred, Effect } from "effect"
import { Connector } from "../../connector"
import { Integration } from "../../integration"
import { Credential } from "../../credential"
import { InstallationVersion } from "../../installation/version"
@ -27,10 +27,13 @@ type Claims = {
"https://api.openai.com/auth"?: { chatgpt_account_id?: string }
}
const browserMethodID = Integration.MethodID.make("chatgpt-browser")
const headlessMethodID = Integration.MethodID.make("chatgpt-headless")
export const browser = {
connectorID: Connector.ID.make("openai"),
method: new Connector.OAuthMethod({
id: Connector.MethodID.make("chatgpt-browser"),
integrationID: Integration.ID.make("openai"),
method: new Integration.OAuthMethod({
id: browserMethodID,
type: "oauth",
label: "ChatGPT Pro/Plus (browser)",
}),
@ -77,17 +80,17 @@ export const browser = {
instructions: "Complete authorization in your browser. This window will close automatically.",
callback: Deferred.await(code).pipe(
Effect.flatMap((value) => exchange(value, redirect, pkce)),
Effect.map(credential),
Effect.map((tokens) => credential(browserMethodID, tokens)),
),
}
}),
refresh: (value) => refresh(value),
} satisfies Connector.OAuthImplementation
} satisfies Integration.OAuthImplementation
export const headless = {
connectorID: Connector.ID.make("openai"),
method: new Connector.OAuthMethod({
id: Connector.MethodID.make("chatgpt-headless"),
integrationID: Integration.ID.make("openai"),
method: new Integration.OAuthMethod({
id: headlessMethodID,
type: "oauth",
label: "ChatGPT Pro/Plus (headless)",
}),
@ -124,6 +127,7 @@ export const headless = {
code_verifier: string
}
return credential(
headlessMethodID,
yield* exchange(data.authorization_code, `${issuer}/deviceauth/callback`, {
verifier: data.code_verifier,
challenge: "",
@ -139,7 +143,7 @@ export const headless = {
}
}),
refresh: (value) => refresh(value),
} satisfies Connector.OAuthImplementation
} satisfies Integration.OAuthImplementation
function headers(contentType: string) {
return { "Content-Type": contentType, "User-Agent": `opencode/${InstallationVersion}` }
@ -170,7 +174,7 @@ function refresh(value: Credential.OAuth) {
}).toString(),
}).pipe(
Effect.map((tokens) => {
const next = credential(tokens)
const next = credential(value.methodID, tokens)
return new Credential.OAuth({
...next,
metadata: next.metadata ?? value.metadata,
@ -190,10 +194,11 @@ function request<A>(url: string, init: RequestInit) {
})
}
function credential(tokens: TokenResponse) {
function credential(methodID: Integration.MethodID, tokens: TokenResponse) {
const accountID = extractAccountID(tokens)
return new Credential.OAuth({
type: "oauth",
methodID,
refresh: tokens.refresh_token,
access: tokens.access_token,
expires: Date.now() + (tokens.expires_in ?? 3600) * 1000,

View file

@ -2,14 +2,14 @@ import { Effect } from "effect"
import { ModelV2 } from "../../model"
import { PluginV2 } from "../../plugin"
import { ProviderV2 } from "../../provider"
import { Connector } from "../../connector"
import { Integration } from "../../integration"
import { browser, headless } from "./openai-auth"
export const OpenAIPlugin = PluginV2.define({
id: PluginV2.ID.make("openai"),
effect: Effect.gen(function* () {
const connectors = yield* Connector.Service
yield* connectors.update((editor) => {
const integrations = yield* Integration.Service
yield* integrations.update((editor) => {
editor.method.update(browser)
editor.method.update(headless)
})