Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion lib/contentstackClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Organization } from './organization/index'
import cloneDeep from 'lodash/cloneDeep'
import { User } from './user/index'
import error from './core/contentstackError'
import OAuthHandler from './core/oauthHandler'

export default function contentstackClient ({ http }) {
/**
Expand Down Expand Up @@ -172,12 +173,44 @@ export default function contentstackClient ({ http }) {
}, error)
}

/**
* @description The oauth call is used to sign in to your Contentstack account and obtain the accesstoken.
* @memberof ContentstackClient
* @func oauth
* @param {Object} parameters - oauth parameters
* @prop {string} parameters.appId - appId of the application
* @prop {string} parameters.clientId - clientId of the application
* @prop {string} parameters.clientId - clientId of the application
* @prop {string} parameters.responseType - responseType
* @prop {string} parameters.scope - scope
* @prop {string} parameters.clientSecret - clientSecret of the application
* @returns {OAuthHandler} Instance of OAuthHandler
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.oauth({ appId: <appId>, clientId: <clientId>, redirectUri: <redirectUri>, clientSecret: <clientSecret>, responseType: <responseType>, scope: <scope> })
* .then(() => console.log('Logged in successfully'))
*
*/
function oauth(params = {}) {
http.defaults.versioningStrategy = "path";
const appId = params.appId || '6400aa06db64de001a31c8a9';
const clientId = params.clientId || 'Ie0FEfTzlfAHL4xM';
const redirectUri = params.redirectUri || 'http://localhost:8184';
const responseType = params.responseType || 'code';
const scope = params.scope;
const clientSecret = params.clientSecret;
return new OAuthHandler(http, appId, clientId, redirectUri, clientSecret,responseType, scope);
}

return {
login: login,
logout: logout,
getUser: getUser,
stack: stack,
organization: organization,
axiosInstance: http
axiosInstance: http,
oauth,
}
}
55 changes: 45 additions & 10 deletions lib/core/concurrency-queue.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Axios from 'axios'
import OAuthHandler from './oauthHandler'
const defaultConfig = {
maxRequests: 5,
retryLimit: 5,
Expand Down Expand Up @@ -75,17 +76,17 @@ export function ConcurrencyQueue ({ axios, config }) {
request.formdata = request.data
request.data = transformFormData(request)
}
request.retryCount = request.retryCount || 0
if (request.headers.authorization && request.headers.authorization !== undefined) {
if (this.config.authorization && this.config.authorization !== undefined) {
request.headers.authorization = this.config.authorization
request.authorization = this.config.authorization
if (axios?.oauth?.accessToken) {
const isTokenExpired = axios.oauth.tokenExpiryTime && Date.now() > axios.oauth.tokenExpiryTime;
if (isTokenExpired) {
return refreshAccessToken().catch((error) => {
throw new Error('Failed to refresh access token: ' + error.message);
});
}
delete request.headers.authtoken
} else if (request.headers.authtoken && request.headers.authtoken !== undefined && this.config.authtoken && this.config.authtoken !== undefined) {
request.headers.authtoken = this.config.authtoken
request.authtoken = this.config.authtoken
}
}

request.retryCount = request?.retryCount || 0
setAuthorizationHeaders(request);
if (request.cancelToken === undefined) {
const source = Axios.CancelToken.source()
request.cancelToken = source.token
Expand All @@ -108,6 +109,40 @@ export function ConcurrencyQueue ({ axios, config }) {
})
}

const setAuthorizationHeaders = (request) => {
if (request.headers.authorization && request.headers.authorization !== undefined) {
if (this.config.authorization && this.config.authorization !== undefined) {
request.headers.authorization = this.config.authorization
request.authorization = this.config.authorization
}
delete request.headers.authtoken
} else if (request.headers.authtoken && request.headers.authtoken !== undefined && this.config.authtoken && this.config.authtoken !== undefined) {
request.headers.authtoken = this.config.authtoken
request.authtoken = this.config.authtoken
} else if (axios?.oauth?.accessToken) {
// If OAuth access token is available in axios instance
request.headers.authorization = `Bearer ${axios.oauth.accessToken}`;
request.authorization = `Bearer ${axios.oauth.accessToken}`;
delete request.headers.authtoken
}
}

//Refresh Access Token
const refreshAccessToken = async () => {
try {
await new OAuthHandler(axios).refreshAccessToken();
this.paused = false; // Resume the request queue once the token is refreshed
this.running.forEach(({ request, resolve, reject }) => {
resolve(request); // Retry the queued requests
});
this.running = []; // Clear the running queue
} catch (error) {
this.paused = false; // Ensure we stop queueing requests on failure
this.running.forEach(({ reject }) => reject(error)); // Reject all queued requests
this.running = []; // Clear the running queue
}
};

const delay = (time, isRefreshToken = false) => {
if (!this.paused) {
this.paused = true
Expand Down
22 changes: 22 additions & 0 deletions lib/core/contentstackHTTPClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,31 @@ export default function contentstackHttpClient (options) {
config.basePath = `/${config.basePath.split('/').filter(Boolean).join('/')}`
}
const baseURL = config.endpoint || `${protocol}://${hostname}:${port}${config.basePath}/{api-version}`
let uiHostName = hostname;
let developerHubBaseUrl = hostname;

if (hostname.endsWith('io')) {
uiHostName = hostname.replace('io', 'com');
}

if (hostname.startsWith('api')) {
uiHostName = uiHostName.replace('api', 'app');
}
const uiBaseUrl = config.endpoint || `${protocol}://${uiHostName}`;

developerHubBaseUrl = developerHubBaseUrl
?.replace('api', 'developerhub-api')
.replace(/^dev\d+/, 'dev') // Replaces any 'dev1', 'dev2', etc. with 'dev'
.replace('io', 'com')
.replace(/^http/, '') // Removing `http` if already present
.replace(/^/, 'https://'); // Adds 'https://' at the start if not already there

// set ui host name
const axiosOptions = {
// Axios
baseURL,
uiBaseUrl,
developerHubBaseUrl,
...config,
paramsSerializer: function (params) {
var query = params.query
Expand Down
Loading