@@ -429,55 +429,55 @@ async function handleStatus(
429429}
430430
431431
432- // Dynamic homepage. Reads /users.txt (also deployed as a static asset
433- // by CI) for the canonical list of users we want dashboards for, then
434- // probes /{user}.html via the ASSETS binding to see which are ready vs
435- // still queued/mining. Output is cached in Workers Cache for 30s so
436- // repeated visits don't fan out to N internal asset probes each time .
432+ // Dynamic homepage. Reads /deployed.json (a CI-generated manifest of
433+ // users whose dashboard HTML actually exists) and / users.txt (the
434+ // canonical list of users we want), then computes deployed vs queued.
435+ // Only 2 subrequests instead of probing each /{user}.html individually
436+ // (which blew the Worker's 50/req subrequest limit at 80+ users) .
437437async function handleIndex ( env : Env , url : URL ) : Promise < Response > {
438438 const cache = caches . default ;
439- const cacheKey = new Request ( "https://internal-index.invalid/v1 " ) ;
439+ const cacheKey = new Request ( "https://internal-index.invalid/v2 " ) ;
440440 const cached = await cache . match ( cacheKey ) ;
441441 if ( cached ) return cached ;
442442
443- // Read users.txt from the deployed assets.
444443 const probeBase = new URL ( url . toString ( ) ) ;
445444 probeBase . search = "" ;
446- const usersTxtUrl = new URL ( probeBase . toString ( ) ) ;
447- usersTxtUrl . pathname = "/users.txt" ;
448- let users : string [ ] = [ ] ;
449- try {
450- const r = await env . ASSETS . fetch ( new Request ( usersTxtUrl . toString ( ) ) ) ;
451- if ( r . ok ) {
452- const txt = await r . text ( ) ;
453- users = txt . split ( "\n" )
454- . map ( ( l ) => l . split ( "#" , 1 ) [ 0 ] . trim ( ) )
455- . filter ( ( l ) => l . length > 0 ) ;
456- }
457- } catch { }
458445
459- // Add pirate (intentionally not in users.txt — built locally).
460- if ( ! users . includes ( "pirate" ) ) users . unshift ( "pirate" ) ;
461-
462- // Probe each user's /<u>.html for deploy status in parallel.
463- const states = await Promise . all ( users . map ( async ( u ) => {
464- const probeUrl = new URL ( probeBase . toString ( ) ) ;
465- probeUrl . pathname = `/${ u } .html` ;
446+ async function fetchAsset ( path : string ) : Promise < string | null > {
466447 try {
467- const r = await env . ASSETS . fetch ( new Request ( probeUrl . toString ( ) ) ) ;
468- return { user : u , deployed : r . status === 200 } ;
448+ const u = new URL ( probeBase . toString ( ) ) ;
449+ u . pathname = path ;
450+ const r = await env . ASSETS . fetch ( new Request ( u . toString ( ) ) ) ;
451+ if ( ! r . ok ) return null ;
452+ return await r . text ( ) ;
469453 } catch {
470- return { user : u , deployed : false } ;
454+ return null ;
471455 }
472- } ) ) ;
456+ }
457+
458+ // Parse users.txt — comment-aware, one login per line.
459+ const usersTxt = await fetchAsset ( "/users.txt" ) ;
460+ const wanted : string [ ] = ( usersTxt ?? "" )
461+ . split ( "\n" )
462+ . map ( ( l ) => l . split ( "#" , 1 ) [ 0 ] . trim ( ) )
463+ . filter ( ( l ) => l . length > 0 ) ;
464+
465+ // Parse deployed.json — JSON array of logins.
466+ let deployedSet = new Set < string > ( ) ;
467+ const depJson = await fetchAsset ( "/deployed.json" ) ;
468+ if ( depJson ) {
469+ try {
470+ const arr = JSON . parse ( depJson ) as string [ ] ;
471+ if ( Array . isArray ( arr ) ) deployedSet = new Set ( arr ) ;
472+ } catch { }
473+ }
474+ // Pirate is always deployed (committed in /public).
475+ deployedSet . add ( "pirate" ) ;
473476
474- const deployed = states
475- . filter ( ( s ) => s . deployed )
476- . map ( ( s ) => s . user )
477+ const allUsers = new Set < string > ( [ ...wanted , ...deployedSet ] ) ;
478+ const deployed = [ ...allUsers ] . filter ( ( u ) => deployedSet . has ( u ) )
477479 . sort ( ( a , b ) => a . toLowerCase ( ) . localeCompare ( b . toLowerCase ( ) ) ) ;
478- const queued = states
479- . filter ( ( s ) => ! s . deployed )
480- . map ( ( s ) => s . user )
480+ const queued = [ ...allUsers ] . filter ( ( u ) => ! deployedSet . has ( u ) )
481481 . sort ( ( a , b ) => a . toLowerCase ( ) . localeCompare ( b . toLowerCase ( ) ) ) ;
482482
483483 const html = indexPage ( deployed , queued ) ;
0 commit comments