Skip to content

Commit 4783b50

Browse files
authored
Merge pull request #7 from contentstack/development
New feature and Request Concurrency support added
2 parents 11be117 + 51a6af5 commit 4783b50

File tree

120 files changed

+9151
-1593
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+9151
-1593
lines changed

.jsdoc.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
"lib/stack/environment/index.js",
2525
"lib/stack/deliveryToken/index.js",
2626
"lib/stack/roles/index.js",
27-
"lib/stack/webhook/index.js"
27+
"lib/stack/webhook/index.js",
28+
"lib/stack/workflow/index.js",
29+
"lib/stack/workflow/publishRules/index.js"
30+
2831
],
2932
"excludePattern": "(node_modules/|jsdocs)"
3033
},

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [v1.2.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.2.0) (.....)
4+
- Bug Fix
5+
- Release Items issue for API key resolved
6+
- Enhanchment
7+
- Request concurrency added in SDK
8+
- New Feature
9+
- Workflow module support added
310
## [v1.1.2](https://github.com/contentstack/contentstack-management-javascript/tree/v1.1.2) (2021-01-07)
411
- Bug Fix
512
- Retry count on multiple request failuer

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ contentstackClient.stack({ api_key: 'API_KEY' }).asset().create({ asset })
104104
- [Content Management API Docs](https://www.contentstack.com/docs/developers/apis/content-management-api)
105105

106106
### The MIT License (MIT)
107-
Copyright © 2012-2020 [Contentstack](https://www.contentstack.com/). All Rights Reserved
107+
Copyright © 2012-2021 [Contentstack](https://www.contentstack.com/). All Rights Reserved
108108

109109
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
110110

dist/es-modules/contentstack.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ import httpClient from './core/contentstackHTTPClient.js';
4444
* import * as contentstack from '@contentstack/management'
4545
* const client = contentstack.client({ timeout: 50000 })
4646
*
47+
* @prop {number=} params.maxRequests - Optional maximum number of requests SDK should send concurrently. Default is 5 concurrent request.
48+
* @example //Set the `maxRequests` to 5
49+
* import * as contentstack from '@contentstack/management'
50+
* const client = contentstack.client({ maxRequests: 5 })
51+
*
4752
* @prop {boolean=} params.retryOnError - Optional boolean for retry on failuer. Default is true
4853
* @example //Set the `retryOnError` to false
4954
* import * as contentstack from '@contentstack/management'
@@ -119,7 +124,7 @@ export function client() {
119124
var defaultParameter = {
120125
defaultHostName: 'api.contentstack.io'
121126
};
122-
var sdkAgent = "".concat(packages.name, "-javascript/").concat(packages.version);
127+
var sdkAgent = "contentstack-management-javascript/".concat(packages.version);
123128
var userAgentHeader = getUserAgent(sdkAgent, params.application, params.integration, params.feature);
124129
var requiredHeaders = {
125130
'X-User-Agent': sdkAgent,

dist/es-modules/contentstackClient.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ export default function contentstackClient(_ref) {
193193
logout: logout,
194194
getUser: getUser,
195195
stack: stack,
196-
organization: organization
196+
organization: organization,
197+
axiosInstance: http
197198
};
198199
}
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
2+
3+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
4+
5+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
6+
7+
import Axios from 'axios';
8+
var defaultConfig = {
9+
maxRequests: 5,
10+
retryLimit: 5,
11+
retryDelay: 300
12+
};
13+
export function ConcurrencyQueue(_ref) {
14+
var _this = this;
15+
16+
var axios = _ref.axios,
17+
config = _ref.config;
18+
19+
if (!axios) {
20+
throw Error('Axios instance is not present');
21+
}
22+
23+
if (config) {
24+
if (config.maxRequests && config.maxRequests <= 0) {
25+
throw Error('Concurrency Manager Error: minimum concurrent requests is 1');
26+
} else if (config.retryLimit && config.retryLimit <= 0) {
27+
throw Error('Retry Policy Error: minimum retry limit is 1');
28+
} else if (config.retryDelay && config.retryDelay < 300) {
29+
throw Error('Retry Policy Error: minimum retry delay for requests is 300');
30+
}
31+
}
32+
33+
this.config = Object.assign({}, defaultConfig, config);
34+
this.queue = [];
35+
this.running = [];
36+
this.paused = false; // Initial shift will check running request,
37+
// and adds request to running queue if max requests are not running
38+
39+
this.initialShift = function () {
40+
if (_this.running.length < _this.config.maxRequests && !_this.paused) {
41+
shift();
42+
}
43+
}; // INTERNAL: Shift the queued item to running queue
44+
45+
46+
var shift = function shift() {
47+
if (_this.queue.length && !_this.paused) {
48+
var queueItem = _this.queue.shift();
49+
50+
queueItem.resolve(queueItem.request);
51+
52+
_this.running.push(queueItem);
53+
}
54+
}; // Append the request at start of queue
55+
56+
57+
this.unshift = function (requestPromise) {
58+
_this.queue.unshift(requestPromise);
59+
};
60+
61+
this.push = function (requestPromise) {
62+
_this.queue.push(requestPromise);
63+
64+
_this.initialShift();
65+
};
66+
67+
this.clear = function () {
68+
var requests = _this.queue.splice(0, _this.queue.length);
69+
70+
requests.forEach(function (element) {
71+
element.request.source.cancel();
72+
});
73+
}; // Detach the interceptors
74+
75+
76+
this.detach = function () {
77+
axios.interceptors.request.eject(_this.interceptors.request);
78+
axios.interceptors.response.eject(_this.interceptors.response);
79+
_this.interceptors = {
80+
request: null,
81+
response: null
82+
};
83+
}; // Request interseptor to queue the request
84+
85+
86+
var requestHandler = function requestHandler(request) {
87+
request.retryCount = request.retryCount || 0;
88+
89+
if (request.headers.authorization && request.headers.authorization !== undefined) {
90+
delete request.headers.authtoken;
91+
}
92+
93+
if (request.cancelToken === undefined) {
94+
var source = Axios.CancelToken.source();
95+
request.cancelToken = source.token;
96+
request.source = source;
97+
}
98+
99+
if (_this.paused && request.retryCount > 0) {
100+
return new Promise(function (resolve) {
101+
_this.unshift({
102+
request: request,
103+
resolve: resolve
104+
});
105+
});
106+
} else if (request.retryCount > 0) {
107+
return request;
108+
}
109+
110+
return new Promise(function (resolve) {
111+
_this.push({
112+
request: request,
113+
resolve: resolve
114+
});
115+
});
116+
};
117+
118+
var delay = function delay(time) {
119+
if (!_this.paused) {
120+
_this.paused = true; // Check for current running request.
121+
// Wait for running queue to complete.
122+
// Wait and prosed the Queued request.
123+
124+
if (_this.running.length > 0) {
125+
setTimeout(function () {
126+
delay(time);
127+
}, time);
128+
}
129+
130+
return new Promise(function (resolve) {
131+
return setTimeout(function () {
132+
_this.paused = false;
133+
134+
for (var i = 0; i < _this.config.maxRequests; i++) {
135+
_this.initialShift();
136+
}
137+
}, time);
138+
});
139+
}
140+
}; // Response interceptor used for
141+
142+
143+
var responseHandler = function responseHandler(response) {
144+
_this.running.shift();
145+
146+
shift();
147+
return response;
148+
};
149+
150+
var responseErrorHandler = function responseErrorHandler(error) {
151+
var networkError = error.config.retryCount;
152+
var retryErrorType = null;
153+
154+
if (!_this.config.retryOnError || networkError > _this.config.retryLimit) {
155+
return Promise.reject(responseHandler(error));
156+
} // Error handling
157+
158+
159+
var wait = _this.config.retryDelay;
160+
var response = error.response;
161+
162+
if (!response) {
163+
if (error.code === 'ECONNABORTED') {
164+
error.response = _objectSpread(_objectSpread({}, error.response), {}, {
165+
status: 408,
166+
statusText: "timeout of ".concat(_this.config.timeout, "ms exceeded")
167+
});
168+
} else {
169+
return Promise.reject(responseHandler(error));
170+
}
171+
} else if (response.status === 429) {
172+
retryErrorType = "Error with status: ".concat(response.status);
173+
networkError++;
174+
175+
if (networkError > _this.config.retryLimit) {
176+
return Promise.reject(responseHandler(error));
177+
}
178+
179+
_this.running.shift();
180+
181+
wait = 1000; // Cooldown the running requests
182+
183+
delay(wait);
184+
error.config.retryCount = networkError;
185+
return axios(updateRequestConfig(error, retryErrorType, wait));
186+
} else if (_this.config.retryCondition && _this.config.retryCondition(error)) {
187+
retryErrorType = "Error with status: ".concat(response.status);
188+
networkError++;
189+
190+
if (networkError > _this.config.retryLimit) {
191+
return Promise.reject(responseHandler(error));
192+
}
193+
194+
if (_this.config.retryDelayOptions) {
195+
if (_this.config.retryDelayOptions.customBackoff) {
196+
wait = _this.config.retryDelayOptions.customBackoff(networkError, error);
197+
198+
if (wait && wait <= 0) {
199+
return Promise.reject(responseHandler(error));
200+
}
201+
} else if (_this.config.retryDelayOptions.base) {
202+
wait = _this.config.retryDelayOptions.base * networkError;
203+
}
204+
} else {
205+
wait = _this.config.retryDelay;
206+
}
207+
208+
error.config.retryCount = networkError;
209+
return new Promise(function (resolve) {
210+
return setTimeout(function () {
211+
return resolve(axios(updateRequestConfig(error, retryErrorType, wait)));
212+
}, wait);
213+
});
214+
}
215+
216+
return Promise.reject(responseHandler(error));
217+
};
218+
219+
this.interceptors = {
220+
request: null,
221+
response: null
222+
};
223+
224+
var updateRequestConfig = function updateRequestConfig(error, retryErrorType, wait) {
225+
var requestConfig = error.config;
226+
227+
_this.config.logHandler('warning', "".concat(retryErrorType, " error occurred. Waiting for ").concat(wait, " ms before retrying..."));
228+
229+
if (axios !== undefined && axios.defaults !== undefined) {
230+
if (axios.defaults.agent === requestConfig.agent) {
231+
delete requestConfig.agent;
232+
}
233+
234+
if (axios.defaults.httpAgent === requestConfig.httpAgent) {
235+
delete requestConfig.httpAgent;
236+
}
237+
238+
if (axios.defaults.httpsAgent === requestConfig.httpsAgent) {
239+
delete requestConfig.httpsAgent;
240+
}
241+
}
242+
243+
requestConfig.transformRequest = [function (data) {
244+
return data;
245+
}];
246+
return requestConfig;
247+
}; // Adds interseptors in axios to queue request
248+
249+
250+
this.interceptors.request = axios.interceptors.request.use(requestHandler);
251+
this.interceptors.response = axios.interceptors.response.use(responseHandler, responseErrorHandler);
252+
}

0 commit comments

Comments
 (0)