77 * - Managing file uploads and downloads
88 */
99
10- export interface ProjectsConfig {
11- baseUrl : string ;
12- bearerToken : string ;
13- }
14-
1510class ProjectsError extends Error {
1611 statusCode : number | undefined ;
1712 constructor ( message : string , statusCode ?: number ) {
@@ -181,10 +176,42 @@ export interface FilePreloadResponse {
181176 * Main Projects Service Client
182177 */
183178export class ProjectsClient {
184- private config : ProjectsConfig ;
179+ private baseUrl : string ;
180+ private bearerToken : string ;
181+ private cloudflareServiceToken ?: {
182+ clientId : string ;
183+ clientSecret : string ;
184+ } ;
185185
186- constructor ( config : ProjectsConfig ) {
187- this . config = config ;
186+ constructor (
187+ env : {
188+ ANACONDA_PROJECTS_URL : string ;
189+ CLOUDFLARE_SERVICE_TOKEN_CLIENT_ID ?: string ;
190+ CLOUDFLARE_SERVICE_TOKEN_CLIENT_SECRET ?: string ;
191+ } ,
192+ bearerToken : string
193+ ) {
194+ this . baseUrl = env . ANACONDA_PROJECTS_URL ;
195+ this . bearerToken = bearerToken ;
196+
197+ // Add Cloudflare Access headers if available in environment
198+ if ( env . CLOUDFLARE_SERVICE_TOKEN_CLIENT_ID && env . CLOUDFLARE_SERVICE_TOKEN_CLIENT_SECRET ) {
199+ this . cloudflareServiceToken = {
200+ clientId : env . CLOUDFLARE_SERVICE_TOKEN_CLIENT_ID ,
201+ clientSecret : env . CLOUDFLARE_SERVICE_TOKEN_CLIENT_SECRET ,
202+ } ;
203+ console . log (
204+ "ProjectsClient: Cloudflare Access headers configured (client ID present)"
205+ ) ;
206+ } else {
207+ console . log (
208+ "ProjectsClient: Cloudflare Access headers not configured" ,
209+ {
210+ hasClientId : ! ! env . CLOUDFLARE_SERVICE_TOKEN_CLIENT_ID ,
211+ hasClientSecret : ! ! env . CLOUDFLARE_SERVICE_TOKEN_CLIENT_SECRET ,
212+ }
213+ ) ;
214+ }
188215 }
189216
190217 /**
@@ -202,23 +229,31 @@ export class ProjectsClient {
202229
203230 for ( let attempt = 0 ; attempt < maxRetries ; attempt ++ ) {
204231 console . log (
205- `ProjectsClient request attempt ${ attempt + 1 } for ${ method } ${ this . config . baseUrl } ${ path } `
232+ `ProjectsClient request attempt ${ attempt + 1 } for ${ method } ${ this . baseUrl } ${ path } `
206233 ) ;
207234 try {
208- const url = `${ this . config . baseUrl } ${ path } ` ;
235+ const url = `${ this . baseUrl } ${ path } ` ;
236+
237+ const headers : Record < string , string > = {
238+ "Content-Type" : "application/json" ,
239+ "User-Agent" : "intheloop" ,
240+ Authorization : `Bearer ${ this . bearerToken } ` ,
241+ } ;
242+
243+ // Add Cloudflare Access headers if configured
244+ if ( this . cloudflareServiceToken ) {
245+ headers [ "CF-Access-Client-Id" ] = this . cloudflareServiceToken . clientId ;
246+ headers [ "CF-Access-Client-Secret" ] = this . cloudflareServiceToken . clientSecret ;
247+ }
209248
210249 const response = await fetch ( url , {
211250 method,
212- headers : {
213- "Content-Type" : "application/json" ,
214- Authorization : `Bearer ${ this . config . bearerToken } ` ,
215- "User-Agent" : "intheloop" ,
216- } ,
251+ headers,
217252 body : body ? JSON . stringify ( body ) : undefined ,
218253 } ) ;
219254
220255 console . log (
221- `ProjectsClient response status: ${ response . status } for ${ method } ${ this . config . baseUrl } ${ path } `
256+ `ProjectsClient response status: ${ response . status } for ${ method } ${ this . baseUrl } ${ path } `
222257 ) ;
223258
224259 if ( ! response . ok ) {
@@ -330,7 +365,7 @@ export class ProjectsClient {
330365 const queryString = params . toString ( ) ;
331366 if ( queryString ) url += `?${ queryString } ` ;
332367 } else {
333- url = nextPageUrl . replace ( this . config . baseUrl , "" ) ;
368+ url = nextPageUrl . replace ( this . baseUrl , "" ) ;
334369 }
335370
336371 let listResponse : ProjectListResponse =
@@ -457,3 +492,4 @@ export class ProjectsClient {
457492 ) ;
458493 }
459494}
495+
0 commit comments