@@ -3,47 +3,86 @@ import path from "node:path";
33import download from "download" ;
44import { Duplex } from "node:stream" ;
55
6- // Define nitro version to download in env variable
7- const NITRO_VERSION = process . env . NITRO_VERSION || "0.2.11 " ;
6+ // Define nitro version to download in env variable ("latest" or tag "v1.2.3")
7+ const NITRO_VERSION = process . env . NITRO_VERSION || "latest " ;
88// The platform OS to download nitro for
99const PLATFORM = process . env . npm_config_platform || process . platform ;
1010// The platform architecture
1111//const ARCH = process.env.npm_config_arch || process.arch;
1212
13- const linuxVariants = {
14- "linux-amd64" : "linux-cpu" ,
15- "linux-amd64-cuda-12-0" : "linux-cuda-12-0" ,
16- "linux-amd64-cuda-11-7" : "linux-cuda-11-7" ,
13+ const releaseUrlPrefixVariants = {
14+ latest : "https://api.github.com/repos/janhq/nitro/releases/" ,
15+ tag : "https://api.github.com/repos/janhq/nitro/releases/tags/" ,
1716} ;
1817
19- const darwinVariants = {
20- "mac-arm64" : "mac-arm64" ,
21- "mac-amd64" : "mac-x64" ,
22- } ;
23-
24- const win32Variants = {
25- "win-amd64-cuda-12-0" : "win-cuda-12-0" ,
26- "win-amd64-cuda-11-7" : "win-cuda-11-7" ,
27- "win-amd64" : "win-cpu" ,
18+ const getReleaseInfo = async ( taggedVersion : string ) : Promise < any > => {
19+ const releaseUrlPrefix =
20+ taggedVersion === "latest"
21+ ? releaseUrlPrefixVariants . latest
22+ : taggedVersion . match ( / ^ \d + \. \d + \. \d + $ / gi)
23+ ? releaseUrlPrefixVariants . tag
24+ : undefined ;
25+ if ( ! releaseUrlPrefix ) throw Error ( `Invalid version: ${ taggedVersion } ` ) ;
26+ const url = `${ releaseUrlPrefix } ${ taggedVersion } ` ;
27+ console . log ( `[Getting release info] ${ url } ` ) ;
28+ const response = await fetch ( url , {
29+ headers : {
30+ Accept : "application/vnd.github+json" ,
31+ "X-GitHub-Api-Version" : "2022-11-28" ,
32+ } ,
33+ } ) ;
34+ if ( ! response . ok )
35+ throw Error ( `Failed to fetch release info: ${ response . status } ` ) ;
36+ return await response . json ( ) ;
2837} ;
2938
30- // Mapping to installation variants
31- const variantMapping : Record < string , Record < string , string > > = {
32- darwin : darwinVariants ,
33- linux : linuxVariants ,
34- win32 : win32Variants ,
39+ const extractDownloadInfo = async (
40+ /* releaseInfo */
41+ {
42+ html_url,
43+ tag_name,
44+ name,
45+ prerelease,
46+ assets,
47+ } : {
48+ html_url : string ;
49+ tag_name : string ;
50+ name : string ;
51+ prerelease : boolean ;
52+ assets : {
53+ name : string ;
54+ size : number ;
55+ browser_download_url : string ;
56+ } [ ] ;
57+ } ,
58+ /* variants for filter for in format {suffix: dir} */
59+ suffixVariants : Record < string , string > ,
60+ ) : Promise < Record < string , { url : string ; dir : string } > > => {
61+ console . log ( `[Release URL][prerelease=${ prerelease } ] ${ html_url } ` ) ;
62+ const assetNames = assets . map ( ( { name } : { name : string } ) => name ) ;
63+ const assetsToDownloads = Object . entries ( suffixVariants ) . reduce (
64+ (
65+ dict : Record < string , { url : string ; dir : string } > ,
66+ [ suffix , dir ] : [ string , string ] ,
67+ ) => {
68+ // Skip if suffix is not in asset names
69+ if ( ! assetNames . includes ( `nitro-${ name } -${ suffix } .tar.gz` ) ) return dict ;
70+ // Else add the download url
71+ dict [ suffix ] = {
72+ url : `https://github.com/janhq/nitro/releases/download/${ tag_name } /nitro-${ name } -${ suffix } .tar.gz` ,
73+ dir,
74+ } ;
75+ return dict ;
76+ } ,
77+ { } ,
78+ ) ;
79+ // If empty then no assets were found
80+ if ( ! Object . keys ( assetsToDownloads ) . length )
81+ throw Error ( "Failed to find any asset to download" ) ;
82+ // Return the dict of download info
83+ return assetsToDownloads ;
3584} ;
3685
37- if ( ! ( PLATFORM in variantMapping ) ) {
38- throw Error ( `Invalid platform: ${ PLATFORM } ` ) ;
39- }
40- // Get download config for this platform
41- const variantConfig : Record < string , string > = variantMapping [ PLATFORM ] ;
42-
43- // Generate download link for each tarball
44- const getTarUrl = ( version : string , suffix : string ) =>
45- `https://github.com/janhq/nitro/releases/download/v${ version } /nitro-${ version } -${ suffix } .tar.gz` ;
46-
4786// Report download progress
4887const createProgressReporter =
4988 ( variant : string ) => ( stream : Promise < Buffer > & Duplex ) =>
@@ -65,28 +104,26 @@ const createProgressReporter =
65104
66105// Download single binary
67106const downloadBinary = async (
68- version : string ,
69107 suffix : string ,
70- destDirPath : string ,
108+ { url , dir } : { url : string ; dir : string } ,
71109) => {
72- const tarUrl = getTarUrl ( version , suffix ) ;
73- console . log ( `Downloading ${ tarUrl } to ${ destDirPath } ` ) ;
110+ console . log ( `Downloading ${ url } to ${ dir } ...` ) ;
74111 const progressReporter = createProgressReporter ( suffix ) ;
75112 await progressReporter (
76- download ( tarUrl , destDirPath , {
113+ download ( url , dir , {
77114 strip : 1 ,
78115 extract : true ,
79116 } ) ,
80117 ) ;
81118 // Set mode of downloaded binaries to executable
82- ( fs . readdirSync ( destDirPath , { recursive : true } ) as string [ ] )
119+ ( fs . readdirSync ( dir , { recursive : true } ) as string [ ] )
83120 . filter (
84121 ( fname ) =>
85- fname . includes ( "nitro" ) &&
86- fs . lstatSync ( path . join ( destDirPath , fname ) ) . isFile ( ) ,
122+ fname . includes ( "nitro" ) && fs . lstatSync ( path . join ( dir , fname ) ) . isFile ( ) ,
87123 )
88124 . forEach ( ( nitroBinary ) => {
89- const absPath = path . join ( destDirPath , nitroBinary ) ;
125+ const absPath = path . join ( dir , nitroBinary ) ;
126+ // Set mode executable for nitro binary
90127 fs . chmodSync (
91128 absPath ,
92129 fs . constants . S_IRWXU | fs . constants . S_IRWXG | fs . constants . S_IRWXO ,
@@ -96,13 +133,19 @@ const downloadBinary = async (
96133
97134// Download the binaries
98135const downloadBinaries = (
99- version : string ,
100- config : Record < string , string > ,
136+ /* downloadInfo */
137+ downloadInfo : Record < string , { url : string ; dir : string } > ,
138+ /* The absolute path to the directory where binaries will be downloaded */
101139 absBinDirPath : string ,
102140) => {
103- return Object . entries ( config ) . reduce (
104- ( p : Promise < any > , [ k , v ] ) =>
105- p . then ( ( ) => downloadBinary ( version , k , path . join ( absBinDirPath , v ) ) ) ,
141+ return Object . entries ( downloadInfo ) . reduce (
142+ (
143+ p : Promise < any > ,
144+ [ suffix , { url, dir } ] : [ string , { url : string ; dir : string } ] ,
145+ ) =>
146+ p . then ( ( ) =>
147+ downloadBinary ( suffix , { url, dir : path . join ( absBinDirPath , dir ) } ) ,
148+ ) ,
106149 Promise . resolve ( ) ,
107150 ) ;
108151} ;
@@ -126,19 +169,51 @@ const verifyDownloadedBinaries = (absBinDirPath: string) => {
126169 } ) ;
127170} ;
128171
172+ const linuxVariants = {
173+ "linux-amd64" : "linux-cpu" ,
174+ "linux-amd64-cuda-12-0" : "linux-cuda-12-0" ,
175+ "linux-amd64-cuda-11-7" : "linux-cuda-11-7" ,
176+ } ;
177+
178+ const darwinVariants = {
179+ "mac-arm64" : "mac-arm64" ,
180+ "mac-amd64" : "mac-x64" ,
181+ } ;
182+
183+ const win32Variants = {
184+ "win-amd64-cuda-12-0" : "win-cuda-12-0" ,
185+ "win-amd64-cuda-11-7" : "win-cuda-11-7" ,
186+ "win-amd64" : "win-cpu" ,
187+ } ;
188+
189+ // Mapping to installation variants
190+ const variantMapping : Record < string , Record < string , string > > = {
191+ darwin : darwinVariants ,
192+ linux : linuxVariants ,
193+ win32 : win32Variants ,
194+ } ;
195+
196+ if ( ! ( PLATFORM in variantMapping ) ) {
197+ throw Error ( `Invalid platform: ${ PLATFORM } ` ) ;
198+ }
199+
200+ // Get download config for this platform
201+ const variantConfig : Record < string , string > = variantMapping [ PLATFORM ] ;
129202// Call the download function with version and config
130203export const downloadNitro = async ( absBinDirPath : string ) => {
131204 // Return early without downloading if nitro binaries are already downloaded
132205 if ( verifyDownloadedBinaries ( absBinDirPath ) ) {
133206 //console.log("Nitro binaries are already downloaded!");
134207 return ;
135208 }
136- return await downloadBinaries ( NITRO_VERSION , variantConfig , absBinDirPath ) ;
209+ const releaseInfo = await getReleaseInfo ( NITRO_VERSION ) ;
210+ const downloadInfo = await extractDownloadInfo ( releaseInfo , variantConfig ) ;
211+ return await downloadBinaries ( downloadInfo , absBinDirPath ) ;
137212} ;
138213
139214// Run script if called directly instead of import as module
140215if ( require . main === module ) {
141216 // Assume calling the source typescript files
142217 // bin path will be relative to the source code root
143- downloadNitro ( path . join ( __dirname , '..' , ".." , "bin" ) ) ;
218+ downloadNitro ( path . join ( __dirname , ".." , ".." , "bin" ) ) ;
144219}
0 commit comments