docs: function GpIAM(credentials) {
    this.credentials = credentials;
    if(!this.credentials || !this.credentials.apikey || !this.credentials.iam_endpoint) {
      throw new Error('GpIAM: params need to be "apikey, iam_endpoint"');
    }
    this.tokenUrl = new URL('/identity/token', this.credentials.iam_endpoint);
  
    if(!this.GP_USE_APIKEY) {
      const now = new Date();
      this.ourCacheKey = `${this.credentials.iam_endpoint}#${this.credentials.apikey}`;
  
      this.updateToken = (async function updateToken(x) {
        const apikey = this.credentials.apikey;
        const cacheEntry = GpIAM.prototype.tokenCache[this.ourCacheKey] =
         GpIAM.prototype.tokenCache[this.ourCacheKey] || {/* initialized to empty */};
        // if(this.VERBOSE) {
        //   const tokenn = token.n = (token.n || 0) + 1;
        //   console.log(`Token count: ${tokenn} ${this.ourCacheKey}`);
        // }
  
        if (!cacheEntry.validUntil ||        // no token
            (now > cacheEntry.validUntil)) { // or expired
  
          delete this.access_token; // in case we run into a failure.
          const tokenResponse = await fetchToken(this.tokenUrl, Buffer.from(querystring.stringify({
            grant_type,
            apikey
          })));
  
          // save the entire response
          cacheEntry.tokenResponse = tokenResponse;
  
          // get the response time
          const { expires_in } = tokenResponse;
  
          cacheEntry.validUntil = new Date(now.getTime() + (1000 * expires_in * tokenExpiryThreshold));
          if(this.VERBOSE) {
            console.log('Fetched access token ');
          }
        }
        if(this.VERBOSE) {
          console.log(`Token valid until ${cacheEntry.validUntil}`);
        }
  
        // save off the access token
        this.access_token = cacheEntry.tokenResponse.access_token;
  
        return x;
      }).bind(this);
    }
  }