@@ -11,6 +11,7 @@ import * as Option from "effect/Option";
1111import * as Stream from "effect/Stream" ;
1212
1313import { makeCursorAuth , type CursorAuthOptions } from "./auth.ts" ;
14+ import type { CursorTeam } from "./auth.ts" ;
1415import { loadCursorSdk } from "./sdk.ts" ;
1516
1617const { InMemoryCredentialStore } = loadCursorSdk ( ) ;
@@ -72,6 +73,8 @@ const makeHarness = Effect.fn("makeCursorAuthHarness")(function* (
7273} ) ;
7374
7475type Auth = Effect . Success < ReturnType < typeof makeCursorAuth > > ;
76+ const readApiKey = ( auth : Auth ) => Effect . map ( auth . readAccess , ( access ) => access ?. apiKey ) ;
77+ const requireApiKey = ( auth : Auth ) => Effect . map ( auth . requireAccess , ( access ) => access . apiKey ) ;
7578const phase = ( auth : Auth , phase : ProviderAuthState [ "phase" ] , session = owner ) =>
7679 auth . controller . subscribe ( session ) . pipe (
7780 Stream . filter ( ( state ) => state . phase === phase ) ,
@@ -112,15 +115,15 @@ it.layer(NodeServices.layer)("CursorAuth", (it) => {
112115 expect ( closedSession ) . toBe ( true ) ;
113116 expect ( closedRequest ) . toBe ( true ) ;
114117 expect ( Exit . isFailure ( yield * Fiber . await ( request ) ) ) . toBe ( true ) ;
115- expect ( yield * harness . auth . readApiKey ) . toBeUndefined ( ) ;
118+ expect ( yield * readApiKey ( harness . auth ) ) . toBeUndefined ( ) ;
116119 } ) . pipe ( Effect . scoped ) ,
117120 ) ;
118121
119122 it . effect ( "completes a remote browser login, saves its key and refreshes provider status" , ( ) =>
120123 Effect . gen ( function * ( ) {
121124 const harness = yield * makeHarness ( ) ;
122125 let stopped = false ;
123- expect ( yield * harness . auth . readApiKey ) . toBeUndefined ( ) ;
126+ expect ( yield * readApiKey ( harness . auth ) ) . toBeUndefined ( ) ;
124127 const starting = yield * harness . auth . controller . start (
125128 owner ,
126129 Effect . sync ( ( ) => {
@@ -133,11 +136,11 @@ it.layer(NodeServices.layer)("CursorAuth", (it) => {
133136 expect ( waiting . flowId ) . toBe ( starting . flowId ) ;
134137 expect ( harness . loginOptions ( ) ?. openBrowser ) . toBe ( false ) ;
135138 expect ( ( yield * harness . auth . controller . start ( owner ) ) . flowId ) . toBe ( starting . flowId ) ;
136- expect ( Exit . isFailure ( yield * Effect . exit ( harness . auth . requireApiKey ) ) ) . toBe ( true ) ;
139+ expect ( Exit . isFailure ( yield * Effect . exit ( requireApiKey ( harness . auth ) ) ) ) . toBe ( true ) ;
137140 yield * Effect . sync ( ( ) => harness . complete . resolve ( ) ) ;
138141 const succeeded = yield * phase ( harness . auth , "succeeded" ) ;
139142 expect ( succeeded . authorizationUrl ) . toBeNull ( ) ;
140- expect ( yield * harness . auth . requireApiKey ) . toBe ( "browser-key" ) ;
143+ expect ( yield * requireApiKey ( harness . auth ) ) . toBe ( "browser-key" ) ;
141144 expect ( harness . changes ) . toEqual ( [ true ] ) ;
142145 expect ( Object . values ( succeeded ) ) . not . toContain ( "browser-key" ) ;
143146 expect ( yield * Effect . promise ( ( ) => harness . store . load ( ) ) ) . toEqual ( harness . credentials ) ;
@@ -180,7 +183,7 @@ it.layer(NodeServices.layer)("CursorAuth", (it) => {
180183 expect ( harness . loginOptions ( ) ?. signal ?. aborted ) . toBe ( true ) ;
181184 yield * Effect . sync ( ( ) => harness . complete . resolve ( ) ) ;
182185 yield * Effect . promise ( ( ) => harness . returned . promise ) ;
183- expect ( yield * harness . auth . readApiKey ) . toBeUndefined ( ) ;
186+ expect ( yield * readApiKey ( harness . auth ) ) . toBeUndefined ( ) ;
184187 expect ( harness . changes ) . toEqual ( [ ] ) ;
185188 } ) . pipe ( Effect . scoped ) ,
186189 ) ;
@@ -208,12 +211,12 @@ it.layer(NodeServices.layer)("CursorAuth", (it) => {
208211 const failed = yield * phase ( harness . auth , "failed" ) ;
209212 expect ( failed . message ) . toBe ( rejectionMessage ) ;
210213 expect ( yield * Effect . promise ( ( ) => harness . store . load ( ) ) ) . toBeUndefined ( ) ;
211- expect ( yield * harness . auth . readApiKey ) . toBeUndefined ( ) ;
212- expect ( Exit . isFailure ( yield * Effect . exit ( harness . auth . requireApiKey ) ) ) . toBe ( true ) ;
214+ expect ( yield * readApiKey ( harness . auth ) ) . toBeUndefined ( ) ;
215+ expect ( Exit . isFailure ( yield * Effect . exit ( requireApiKey ( harness . auth ) ) ) ) . toBe ( true ) ;
213216 rejected = false ;
214217 yield * harness . auth . controller . start ( owner ) ;
215218 yield * phase ( harness . auth , "succeeded" ) ;
216- expect ( yield * harness . auth . requireApiKey ) . toBe ( "browser-key" ) ;
219+ expect ( yield * requireApiKey ( harness . auth ) ) . toBe ( "browser-key" ) ;
217220 } ) . pipe ( Effect . scoped ) ,
218221 ) ;
219222
@@ -225,13 +228,13 @@ it.layer(NodeServices.layer)("CursorAuth", (it) => {
225228 yield * Effect . promise ( ( ) => other . store . save ( { ...other . credentials , apiKey : "other-key" } ) ) ;
226229 const state = yield * harness . auth . controller . logout (
227230 Effect . gen ( function * ( ) {
228- expect ( yield * harness . auth . readApiKey ) . toBe ( "browser-key" ) ;
229- expect ( Exit . isFailure ( yield * Effect . exit ( harness . auth . requireApiKey ) ) ) . toBe ( true ) ;
231+ expect ( yield * readApiKey ( harness . auth ) ) . toBe ( "browser-key" ) ;
232+ expect ( Exit . isFailure ( yield * Effect . exit ( requireApiKey ( harness . auth ) ) ) ) . toBe ( true ) ;
230233 } ) ,
231234 ) ;
232235 expect ( state . message ) . toBe ( "Signed out of Cursor." ) ;
233- expect ( yield * harness . auth . readApiKey ) . toBeUndefined ( ) ;
234- expect ( yield * other . auth . requireApiKey ) . toBe ( "other-key" ) ;
236+ expect ( yield * readApiKey ( harness . auth ) ) . toBeUndefined ( ) ;
237+ expect ( yield * requireApiKey ( other . auth ) ) . toBe ( "other-key" ) ;
235238 expect ( harness . changes ) . toEqual ( [ false ] ) ;
236239 } ) . pipe ( Effect . scoped ) ,
237240 ) ;
@@ -245,7 +248,7 @@ it.layer(NodeServices.layer)("CursorAuth", (it) => {
245248 expect ( harness . loginOptions ( ) ?. signal ?. aborted ) . toBe ( true ) ;
246249 yield * Effect . sync ( ( ) => harness . complete . resolve ( ) ) ;
247250 yield * Effect . promise ( ( ) => harness . returned . promise ) ;
248- expect ( yield * harness . auth . readApiKey ) . toBeUndefined ( ) ;
251+ expect ( yield * readApiKey ( harness . auth ) ) . toBeUndefined ( ) ;
249252 } ) . pipe ( Effect . scoped ) ,
250253 ) ;
251254
@@ -265,7 +268,7 @@ it.layer(NodeServices.layer)("CursorAuth", (it) => {
265268 ) ,
266269 ) ;
267270 expect ( Exit . isFailure ( result ) ) . toBe ( true ) ;
268- expect ( yield * harness . auth . requireApiKey ) . toBe ( "browser-key" ) ;
271+ expect ( yield * requireApiKey ( harness . auth ) ) . toBe ( "browser-key" ) ;
269272 } ) . pipe ( Effect . scoped ) ,
270273 ) ;
271274
@@ -275,7 +278,7 @@ it.layer(NodeServices.layer)("CursorAuth", (it) => {
275278 Effect . gen ( function * ( ) {
276279 const harness = yield * makeHarness ( { apiKey : " explicit-key " } ) ;
277280 yield * Effect . promise ( ( ) => harness . store . save ( harness . credentials ) ) ;
278- expect ( yield * harness . auth . requireApiKey ) . toBe ( "explicit-key" ) ;
281+ expect ( yield * requireApiKey ( harness . auth ) ) . toBe ( "explicit-key" ) ;
279282 expect ( Exit . isFailure ( yield * Effect . exit ( harness . auth . controller . start ( owner ) ) ) ) . toBe ( true ) ;
280283 expect (
281284 Exit . isFailure ( yield * Effect . exit ( harness . auth . controller . logout ( Effect . void ) ) ) ,
@@ -285,13 +288,42 @@ it.layer(NodeServices.layer)("CursorAuth", (it) => {
285288 } ) . pipe ( Effect . scoped ) ,
286289 ) ;
287290
291+ it . effect . each < { name : string ; apiKey ?: string ; teamId ?: string ; expected ?: CursorTeam } > ( [
292+ { name : "the default team for browser sign-in" } ,
293+ {
294+ name : "CURSOR_TEAM_ID for browser sign-in" ,
295+ teamId : " 42 " ,
296+ expected : { id : 42 , name : undefined } ,
297+ } ,
298+ ...[ "abc" , "0" , "-1" , "1.5" , "1e3" ] . map ( ( teamId ) => ( {
299+ name : `the default team for an invalid CURSOR_TEAM_ID "${ teamId } "` ,
300+ teamId,
301+ } ) ) ,
302+ { name : "the default team for an explicit API key" , apiKey : "explicit-key" } ,
303+ {
304+ name : "CURSOR_TEAM_ID for an explicit API key" ,
305+ apiKey : "explicit-key" ,
306+ teamId : "42" ,
307+ expected : { id : 42 , name : undefined } ,
308+ } ,
309+ ] ) ( "uses $name" , ( { apiKey, teamId, expected } ) =>
310+ Effect . gen ( function * ( ) {
311+ const harness = yield * makeHarness ( {
312+ ...( apiKey ? { apiKey } : { } ) ,
313+ ...( teamId ? { teamId } : { } ) ,
314+ } ) ;
315+ yield * Effect . promise ( ( ) => harness . store . save ( harness . credentials ) ) ;
316+ expect ( ( yield * harness . auth . requireAccess ) . team ) . toEqual ( expected ) ;
317+ } ) . pipe ( Effect . scoped ) ,
318+ ) ;
319+
288320 it . effect ( "ignores expired browser credentials and rejects disabled sign-in" , ( ) =>
289321 Effect . gen ( function * ( ) {
290322 const harness = yield * makeHarness ( { enabled : false } ) ;
291323 yield * Effect . promise ( ( ) =>
292324 harness . store . save ( { ...harness . credentials , apiKeyExpiresAtMs : 0 } ) ,
293325 ) ;
294- expect ( yield * harness . auth . readApiKey ) . toBeUndefined ( ) ;
326+ expect ( yield * readApiKey ( harness . auth ) ) . toBeUndefined ( ) ;
295327 expect ( Exit . isFailure ( yield * Effect . exit ( harness . auth . controller . start ( owner ) ) ) ) . toBe ( true ) ;
296328 } ) . pipe ( Effect . scoped ) ,
297329 ) ;
0 commit comments