2018-10-29 23:23:46 +00:00
/* global XMLHttpRequest FormData */
'use strict'
let ajaxcfg = { }
class AjaxError extends Error {
constructor ( reason , data , xhr ) {
super ( reason )
this . data = data
this . xhr = xhr
}
}
export default class Ajax {
static async get ( opts ) {
if ( ! opts ) opts = { }
opts . method = 'get'
return Ajax . ajax ( opts )
}
static async post ( opts ) {
if ( ! opts ) opts = { }
opts . method = 'post'
return Ajax . ajax ( opts )
}
static async put ( opts ) {
if ( ! opts ) opts = { }
opts . method = 'put'
return Ajax . ajax ( opts )
}
static async patch ( opts ) {
if ( ! opts ) opts = { }
opts . method = 'patch'
return Ajax . ajax ( opts )
}
static async delete ( opts ) {
if ( ! opts ) opts = { }
opts . method = 'delete'
return Ajax . ajax ( opts )
}
static async head ( opts ) {
if ( ! opts ) opts = { }
opts . method = 'head'
return Ajax . ajax ( opts )
}
static async options ( opts ) {
if ( ! opts ) opts = { }
opts . method = 'options'
return Ajax . ajax ( opts )
}
static ajax ( opts ) {
return new Promise ( ( resolve , reject ) => {
if ( ! opts ) reject ( new Error ( 'Missing required options parameter.' ) )
if ( opts . method ) {
if ( ! [ 'get' , 'post' , 'put' , 'patch' , 'delete' , 'head' , 'options' ] . includes ( opts . method . toLowerCase ( ) ) ) reject ( new Error ( 'opts.method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.' ) )
opts . method = opts . method . toUpperCase ( )
}
var xhr = opts . xhr || new XMLHttpRequest ( )
var fd = null
var qs = ''
if ( opts . data && opts . method . toLowerCase ( ) !== 'get' ) {
fd = new FormData ( )
for ( let key in opts . data ) {
fd . append ( key , opts . data [ key ] )
}
} else if ( opts . data ) {
qs += '?'
let params = [ ]
for ( let key in opts . data ) {
params . push ( [ key , opts . data [ key ] ] . join ( '=' ) )
}
qs += params . join ( '&' )
}
xhr . onload = ( ) => {
if ( xhr . status !== 200 ) return xhr . onerror ( )
var data = xhr . response
resolve ( {
data ,
xhr
} )
}
xhr . onerror = ( ) => {
var data = xhr . response
// method not allowed
if ( xhr . status === 405 ) {
reject ( new AjaxError ( '405 Method Not Allowed' , data , xhr ) )
return
2018-10-29 23:35:27 +00:00
} else if ( xhr . status === 404 ) {
reject ( new AjaxError ( '404 Not Found' , data , xhr ) )
return
2018-10-29 23:23:46 +00:00
}
try {
// if the access token is invalid, try to use the refresh token
var json = JSON . parse ( data )
if ( json . error === 'access_denied' && json . hint . includes ( 'token' ) && json . hint . includes ( 'invalid' ) && ajaxcfg . refresh _token ) {
return Ajax . refresh ( opts )
} else if ( json . error === 'access_denied' && json . hint . includes ( 'token' ) && json . hint . includes ( 'revoked' ) ) {
reject ( new AjaxError ( 'token revoked' , data , xhr ) )
}
} catch ( e ) {
reject ( new AjaxError ( e . toString ( ) , data , xhr ) )
} finally {
2018-11-02 00:21:36 +00:00
reject ( new AjaxError ( data , xhr . status , xhr ) )
2018-10-29 23:23:46 +00:00
}
}
xhr . open ( opts . method || 'GET' , opts . url + qs || window . location . href )
if ( opts . headers ) {
for ( let key in opts . headers ) xhr . setRequestHeader ( key , opts . headers [ key ] )
}
if ( ajaxcfg . access _token && ! ( opts . headers || { } ) . Authorization ) xhr . setRequestHeader ( 'Authorization' , 'Bearer ' + ajaxcfg . access _token )
xhr . send ( fd )
} )
}
static refresh ( opts ) {
return new Promise ( ( resolve , reject ) => {
var xhr = new XMLHttpRequest ( )
var fd = new FormData ( )
const OAUTH _TOKEN _REQUEST = {
grant _type : 'refresh_token' ,
refresh _token : ajaxcfg . refresh _token ,
client _id : 'foxfile' ,
client _secret : 1
}
for ( var key in OAUTH _TOKEN _REQUEST ) {
fd . append ( key , OAUTH _TOKEN _REQUEST [ key ] )
}
// try original request
xhr . onload = ( ) => {
if ( xhr . status !== 200 ) return xhr . onerror ( )
if ( ajaxcfg . refresh ) ajaxcfg . refresh ( xhr . response )
var json = JSON . parse ( xhr . response )
ajaxcfg . access _token = json . access _token
ajaxcfg . refresh _token = json . refresh _token
return Ajax . ajax ( opts )
}
// if this fails, dont try again
xhr . onerror = ( ) => {
var data = xhr . response
reject ( new AjaxError ( xhr . status , data , xhr ) )
}
xhr . open ( 'POST' , ajaxcfg . refresh _url )
xhr . send ( fd )
} )
}
static setTokenData ( tokens ) {
if ( ! tokens ) throw new Error ( 'Missing tokens.' )
if ( ! tokens . access _token && ! tokens . refresh _token && ! tokens . refresh _url ) throw new Error ( 'Missing at least one of: access_token, refresh_token, refresh_url.' )
if ( tokens . access _token ) ajaxcfg . access _token = tokens . access _token
if ( tokens . refresh _token ) ajaxcfg . refresh _token = tokens . refresh _token
if ( tokens . refresh _url ) ajaxcfg . refresh _url = tokens . refresh _url
return true
}
static onRefresh ( func ) {
ajaxcfg . refresh = func
}
}