1- import { Instance } from "@/project/instance"
2- import { Plugin } from "../plugin"
3- import { map , filter , pipe , fromEntries , mapValues } from "remeda"
1+ import { Effect , ManagedRuntime } from "effect"
42import z from "zod"
3+
54import { fn } from "@/util/fn"
6- import type { AuthOuathResult , Hooks } from "@opencode-ai/plugin"
7- import { NamedError } from "@opencode-ai/util/error"
8- import { Auth } from "@/auth"
5+ import * as S from "./auth-service"
96import { ProviderID } from "./schema"
107
11- export namespace ProviderAuth {
12- const state = Instance . state ( async ( ) => {
13- const methods = pipe (
14- await Plugin . list ( ) ,
15- filter ( ( x ) => x . auth ?. provider !== undefined ) ,
16- map ( ( x ) => [ x . auth ! . provider , x . auth ! ] as const ) ,
17- fromEntries ( ) ,
18- )
19- return { methods, pending : { } as Record < string , AuthOuathResult > }
20- } )
8+ // Separate runtime: ProviderAuthService can't join the shared runtime because
9+ // runtime.ts → auth-service.ts → provider/auth.ts creates a circular import.
10+ // AuthService is stateless file I/O so the duplicate instance is harmless.
11+ const rt = ManagedRuntime . make ( S . ProviderAuthService . defaultLayer )
2112
13+ function runPromise < A > ( f : ( service : S . ProviderAuthService . Service ) => Effect . Effect < A , S . ProviderAuthError > ) {
14+ return rt . runPromise ( S . ProviderAuthService . use ( f ) )
15+ }
16+
17+ export namespace ProviderAuth {
2218 export const Method = z
2319 . object ( {
2420 type : z . union ( [ z . literal ( "oauth" ) , z . literal ( "api" ) ] ) ,
@@ -30,15 +26,7 @@ export namespace ProviderAuth {
3026 export type Method = z . infer < typeof Method >
3127
3228 export async function methods ( ) {
33- const s = await state ( ) . then ( ( x ) => x . methods )
34- return mapValues ( s , ( x ) =>
35- x . methods . map (
36- ( y ) : Method => ( {
37- type : y . type ,
38- label : y . label ,
39- } ) ,
40- ) ,
41- )
29+ return runPromise ( ( service ) => service . methods ( ) )
4230 }
4331
4432 export const Authorization = z
@@ -57,19 +45,7 @@ export namespace ProviderAuth {
5745 providerID : ProviderID . zod ,
5846 method : z . number ( ) ,
5947 } ) ,
60- async ( input ) : Promise < Authorization | undefined > => {
61- const auth = await state ( ) . then ( ( s ) => s . methods [ input . providerID ] )
62- const method = auth . methods [ input . method ]
63- if ( method . type === "oauth" ) {
64- const result = await method . authorize ( )
65- await state ( ) . then ( ( s ) => ( s . pending [ input . providerID ] = result ) )
66- return {
67- url : result . url ,
68- method : result . method ,
69- instructions : result . instructions ,
70- }
71- }
72- } ,
48+ async ( input ) : Promise < Authorization | undefined > => runPromise ( ( service ) => service . authorize ( input ) ) ,
7349 )
7450
7551 export const callback = fn (
@@ -78,71 +54,18 @@ export namespace ProviderAuth {
7854 method : z . number ( ) ,
7955 code : z . string ( ) . optional ( ) ,
8056 } ) ,
81- async ( input ) => {
82- const match = await state ( ) . then ( ( s ) => s . pending [ input . providerID ] )
83- if ( ! match ) throw new OauthMissing ( { providerID : input . providerID } )
84- let result
85-
86- if ( match . method === "code" ) {
87- if ( ! input . code ) throw new OauthCodeMissing ( { providerID : input . providerID } )
88- result = await match . callback ( input . code )
89- }
90-
91- if ( match . method === "auto" ) {
92- result = await match . callback ( )
93- }
94-
95- if ( result ?. type === "success" ) {
96- if ( "key" in result ) {
97- await Auth . set ( input . providerID , {
98- type : "api" ,
99- key : result . key ,
100- } )
101- }
102- if ( "refresh" in result ) {
103- const info : Auth . Info = {
104- type : "oauth" ,
105- access : result . access ,
106- refresh : result . refresh ,
107- expires : result . expires ,
108- }
109- if ( result . accountId ) {
110- info . accountId = result . accountId
111- }
112- await Auth . set ( input . providerID , info )
113- }
114- return
115- }
116-
117- throw new OauthCallbackFailed ( { } )
118- } ,
57+ async ( input ) => runPromise ( ( service ) => service . callback ( input ) ) ,
11958 )
12059
12160 export const api = fn (
12261 z . object ( {
12362 providerID : ProviderID . zod ,
12463 key : z . string ( ) ,
12564 } ) ,
126- async ( input ) => {
127- await Auth . set ( input . providerID , {
128- type : "api" ,
129- key : input . key ,
130- } )
131- } ,
132- )
133-
134- export const OauthMissing = NamedError . create (
135- "ProviderAuthOauthMissing" ,
136- z . object ( {
137- providerID : ProviderID . zod ,
138- } ) ,
139- )
140- export const OauthCodeMissing = NamedError . create (
141- "ProviderAuthOauthCodeMissing" ,
142- z . object ( {
143- providerID : ProviderID . zod ,
144- } ) ,
65+ async ( input ) => runPromise ( ( service ) => service . api ( input ) ) ,
14566 )
14667
147- export const OauthCallbackFailed = NamedError . create ( "ProviderAuthOauthCallbackFailed" , z . object ( { } ) )
68+ export import OauthMissing = S . OauthMissing
69+ export import OauthCodeMissing = S . OauthCodeMissing
70+ export import OauthCallbackFailed = S . OauthCallbackFailed
14871}
0 commit comments