@@ -81,13 +81,51 @@ async function fetchRelease(
8181 return null ;
8282 }
8383 const releases = ( await res . json ( ) ) as GitHubRelease [ ] ;
84+ console . log (
85+ "GitHub releases:" ,
86+ releases . map ( ( r ) => ( { tag : r . tag_name , assets : r . assets . map ( ( a ) => a . name ) } ) ) ,
87+ ) ;
8488 return (
8589 releases . find ( ( r ) =>
8690 r . assets . some ( ( a ) => a . name === ASSET_NAMES . x64 || a . name === ASSET_NAMES . arm64 ) ,
8791 ) ?? null
8892 ) ;
8993}
9094
95+ export function buildReleaseFromTag ( tag : string ) : CachedRelease {
96+ const base = `https://github.com/${ GITHUB_OWNER } /${ GITHUB_REPO } /releases/download/${ tag } ` ;
97+ return {
98+ tag,
99+ assets : {
100+ x64 : `${ base } /${ ASSET_NAMES . x64 } ` ,
101+ arm64 : `${ base } /${ ASSET_NAMES . arm64 } ` ,
102+ } ,
103+ } ;
104+ }
105+
106+ interface NpmDistTags {
107+ alpha ?: string ;
108+ latest ?: string ;
109+ }
110+
111+ async function fetchLatestVersionFromNpm ( ) : Promise < string | null > {
112+ try {
113+ const res = await fetch ( "https://registry.npmjs.com/vite-plus" , {
114+ headers : { Accept : "application/vnd.npm.install-v1+json" } ,
115+ } ) ;
116+ if ( ! res . ok ) {
117+ console . error ( `npm registry error: ${ res . status } ${ res . statusText } ` ) ;
118+ return null ;
119+ }
120+ const data = ( await res . json ( ) ) as { "dist-tags" ?: NpmDistTags } ;
121+ // Windows installers are currently published under the alpha dist-tag
122+ return data [ "dist-tags" ] ?. alpha ?? data [ "dist-tags" ] ?. latest ?? null ;
123+ } catch ( err ) {
124+ console . error ( "Failed to fetch version from npm registry:" , err ) ;
125+ return null ;
126+ }
127+ }
128+
91129function cacheKey ( tag : string | undefined ) : string {
92130 return tag ? `release:tag:${ tag } ` : "release:latest" ;
93131}
@@ -106,21 +144,32 @@ async function getRelease(
106144
107145 try {
108146 const release = await fetchRelease ( tag , githubToken ) ;
109- if ( ! release ) return null ;
110- const parsed = parseRelease ( release ) ;
111- if ( parsed ) {
112- const ttl = tag ? TAGGED_CACHE_TTL : LATEST_CACHE_TTL ;
113- const staleTtl = ttl + 3600 ;
114- await Promise . all ( [
115- kv . put ( key , parsed , { ttl } ) ,
116- kv . put ( staleCacheKey ( tag ) , parsed , { ttl : staleTtl } ) ,
117- ] ) ;
147+ if ( release ) {
148+ const parsed = parseRelease ( release ) ;
149+ if ( parsed ) {
150+ const ttl = tag ? TAGGED_CACHE_TTL : LATEST_CACHE_TTL ;
151+ const staleTtl = ttl + 3600 ;
152+ await Promise . all ( [
153+ kv . put ( key , parsed , { ttl } ) ,
154+ kv . put ( staleCacheKey ( tag ) , parsed , { ttl : staleTtl } ) ,
155+ ] ) ;
156+ return parsed ;
157+ }
118158 }
119- return parsed ;
120159 } catch ( err ) {
121160 console . error ( "Failed to fetch release from GitHub:" , err ) ;
122- return await kv . get < CachedRelease > ( staleCacheKey ( tag ) ) ;
123161 }
162+
163+ // Fallback 1: stale KV cache
164+ const stale = await kv . get < CachedRelease > ( staleCacheKey ( tag ) ) ;
165+ if ( stale ) return stale ;
166+
167+ // Fallback 2: construct download URLs from tag or npm registry version
168+ if ( tag ) return buildReleaseFromTag ( tag ) ;
169+ const version = await fetchLatestVersionFromNpm ( ) ;
170+ if ( version ) return buildReleaseFromTag ( `v${ version } ` ) ;
171+
172+ return null ;
124173}
125174
126175export const GET = defineHandler ( async ( c ) => {
0 commit comments