uapi-json 1.17.5 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/package.json +22 -19
- package/src/Request/uapi-parser.js +3 -2
- package/src/Request/uapi-request.js +23 -4
- package/src/Services/Air/AirFormat.js +1 -1
- package/src/Services/Air/AirParser.js +2 -2
- package/src/Services/Terminal/Terminal.js +16 -0
- package/src/Services/Terminal/TerminalErrors.js +1 -0
- package/src/Services/Terminal/TerminalParser.js +3 -3
package/README.md
CHANGED
|
@@ -89,6 +89,24 @@ It also has several useful helpers to handle errors.
|
|
|
89
89
|
|
|
90
90
|
`logFunction` - set custom logging function that should match next shape `(...args) => {}`. Will receive all requests and responses from uapi/terminal.
|
|
91
91
|
|
|
92
|
+
`httpsAgent` - set custom HTTPS agent for all requests created by the service. If the agent has `options.timeout`, that value is used as the request timeout.
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
const https = require('https');
|
|
96
|
+
|
|
97
|
+
const TerminalService = uAPI.createTerminalService({
|
|
98
|
+
auth,
|
|
99
|
+
options: {
|
|
100
|
+
httpsAgent: new https.Agent({
|
|
101
|
+
keepAlive: true,
|
|
102
|
+
maxSockets: 1,
|
|
103
|
+
maxFreeSockets: 1,
|
|
104
|
+
timeout: 90000,
|
|
105
|
+
}),
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
92
110
|
### Auth object
|
|
93
111
|
<a name="auth"></a>
|
|
94
112
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uapi-json",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "Travelport Universal API",
|
|
5
5
|
"main": "src/",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
6
9
|
"files": [
|
|
7
10
|
"src/",
|
|
8
11
|
"README.md",
|
|
@@ -27,37 +30,37 @@
|
|
|
27
30
|
"node",
|
|
28
31
|
"travelport"
|
|
29
32
|
],
|
|
30
|
-
"author": "Mark Orel <mail.ormark@gmail.com>",
|
|
31
33
|
"contributors": [
|
|
32
|
-
"Dmitry Chertousov <d.chertousov@gmail.com>",
|
|
33
34
|
"Artem Pylypchuk <articicejuice@gmail.com>",
|
|
34
|
-
"
|
|
35
|
+
"Dmytro Chertousov <d.chertousov@gmail.com>",
|
|
36
|
+
"Mark Orel <mail.ormark@gmail.com>",
|
|
35
37
|
"Mark Omarov <dev.mark.omarov@gmail.com>",
|
|
36
|
-
"Oleksii Duvanov <colden.aid@gmail.com>"
|
|
38
|
+
"Oleksii Duvanov <colden.aid@gmail.com>",
|
|
39
|
+
"Yevhenii Huselietov <d46k16@gmail.com>"
|
|
37
40
|
],
|
|
38
41
|
"license": "MIT",
|
|
39
42
|
"dependencies": {
|
|
40
|
-
"axios": "
|
|
43
|
+
"axios": "~1.15.0",
|
|
41
44
|
"galileo-screen": "1.0.5",
|
|
42
|
-
"handlebars": "
|
|
43
|
-
"handlebars-helper-equal": "
|
|
44
|
-
"joi": "
|
|
45
|
-
"moment": "
|
|
46
|
-
"node-errors-helpers": "
|
|
47
|
-
"pretty-data": "
|
|
48
|
-
"promise-retry": "
|
|
49
|
-
"xml2js": "
|
|
45
|
+
"handlebars": "~4.7.9",
|
|
46
|
+
"handlebars-helper-equal": "~1.0.0",
|
|
47
|
+
"joi": "~18.1.2",
|
|
48
|
+
"moment": "~2.30.1",
|
|
49
|
+
"node-errors-helpers": "~1.0.0",
|
|
50
|
+
"pretty-data": "~0.40.0",
|
|
51
|
+
"promise-retry": "~2.0.1",
|
|
52
|
+
"xml2js": "~0.6.2"
|
|
50
53
|
},
|
|
51
54
|
"devDependencies": {
|
|
52
55
|
"chai": "^4.5.0",
|
|
53
56
|
"eslint": "^8.39.0",
|
|
54
57
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
55
|
-
"eslint-plugin-import": "^2.
|
|
56
|
-
"mocha": "^11.5
|
|
58
|
+
"eslint-plugin-import": "^2.32.0",
|
|
59
|
+
"mocha": "^11.7.5",
|
|
57
60
|
"nyc": "^17.1.0",
|
|
58
|
-
"proxyquire": "
|
|
59
|
-
"readline2": "
|
|
60
|
-
"sinon": "^
|
|
61
|
+
"proxyquire": "~2.1.3",
|
|
62
|
+
"readline2": "~1.0.1",
|
|
63
|
+
"sinon": "^21.0.0",
|
|
61
64
|
"sinon-chai": "^3.7.0"
|
|
62
65
|
}
|
|
63
66
|
}
|
|
@@ -36,8 +36,9 @@ function mergeLeaf(item) {
|
|
|
36
36
|
return { ...item, ...leaf };
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
function Parser(root, uapiVersion, env, debug, config, provider) {
|
|
39
|
+
function Parser(root, uapiVersion, env, debug, config, provider, log) {
|
|
40
40
|
this.debug = debug;
|
|
41
|
+
this.log = log || console.info;
|
|
41
42
|
if (!config) {
|
|
42
43
|
this.config = defaultConfig(uapiVersion);
|
|
43
44
|
} else {
|
|
@@ -212,7 +213,7 @@ Parser.prototype.parse = function (xml) {
|
|
|
212
213
|
|
|
213
214
|
const end = new Date() - start;
|
|
214
215
|
if (this.debug > 1) {
|
|
215
|
-
|
|
216
|
+
this.log('uAPI_Parse execution time: %dms', end);
|
|
216
217
|
}
|
|
217
218
|
|
|
218
219
|
return data[self.rootObject];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const handlebars = require('handlebars');
|
|
2
2
|
const axios = require('axios');
|
|
3
|
+
const https = require('https');
|
|
3
4
|
const { pd } = require('pretty-data');
|
|
4
5
|
const {
|
|
5
6
|
RequestValidationError,
|
|
@@ -13,6 +14,14 @@ const configInit = require('../config');
|
|
|
13
14
|
|
|
14
15
|
handlebars.registerHelper('equal', require('handlebars-helper-equal'));
|
|
15
16
|
|
|
17
|
+
const REQUEST_AGENT_OPTIONS = {
|
|
18
|
+
keepAlive: true,
|
|
19
|
+
keepAliveMsecs: 5000,
|
|
20
|
+
maxSockets: 20,
|
|
21
|
+
maxFreeSockets: 20,
|
|
22
|
+
};
|
|
23
|
+
const httpsAgent = new https.Agent(REQUEST_AGENT_OPTIONS);
|
|
24
|
+
|
|
16
25
|
/**
|
|
17
26
|
* basic function for requests/responses
|
|
18
27
|
* @param {string} service service url for current response (gateway)
|
|
@@ -43,6 +52,15 @@ module.exports = function uapiRequest(
|
|
|
43
52
|
|
|
44
53
|
const config = configInit(auth.region);
|
|
45
54
|
const log = options.logFunction || console.log;
|
|
55
|
+
const customHttpsAgent = options.httpsAgent;
|
|
56
|
+
const requestHttpsAgent = customHttpsAgent || httpsAgent;
|
|
57
|
+
const requestTimeout = (
|
|
58
|
+
customHttpsAgent
|
|
59
|
+
&& customHttpsAgent.options
|
|
60
|
+
&& typeof customHttpsAgent.options.timeout === 'number'
|
|
61
|
+
)
|
|
62
|
+
? customHttpsAgent.options.timeout
|
|
63
|
+
: config.timeout || 5000;
|
|
46
64
|
|
|
47
65
|
// Performing checks
|
|
48
66
|
if (!service || service.length <= 0) {
|
|
@@ -64,7 +82,7 @@ module.exports = function uapiRequest(
|
|
|
64
82
|
}
|
|
65
83
|
|
|
66
84
|
// create a v52 uAPI parser with default params and request data in env
|
|
67
|
-
const uParser = new Parser(rootObject, 'v52_0', params, debugMode, null, auth.provider);
|
|
85
|
+
const uParser = new Parser(rootObject, 'v52_0', params, debugMode, null, auth.provider, log);
|
|
68
86
|
|
|
69
87
|
const validateInput = () => (
|
|
70
88
|
Promise.resolve(params)
|
|
@@ -85,7 +103,8 @@ module.exports = function uapiRequest(
|
|
|
85
103
|
const response = await axios.request({
|
|
86
104
|
url: service,
|
|
87
105
|
method: 'POST',
|
|
88
|
-
timeout:
|
|
106
|
+
timeout: requestTimeout,
|
|
107
|
+
httpsAgent: requestHttpsAgent,
|
|
89
108
|
auth: {
|
|
90
109
|
username: auth.username,
|
|
91
110
|
password: auth.password,
|
|
@@ -156,7 +175,6 @@ module.exports = function uapiRequest(
|
|
|
156
175
|
};
|
|
157
176
|
|
|
158
177
|
const validateSOAP = function (parsedXML) {
|
|
159
|
-
console.log(parsedXML);
|
|
160
178
|
if (parsedXML['SOAP:Fault']) {
|
|
161
179
|
if (debugMode > 2) {
|
|
162
180
|
log('Parsed error response', pd.json(parsedXML));
|
|
@@ -169,7 +187,8 @@ module.exports = function uapiRequest(
|
|
|
169
187
|
params,
|
|
170
188
|
debugMode,
|
|
171
189
|
errParserConfig,
|
|
172
|
-
auth.provider
|
|
190
|
+
auth.provider,
|
|
191
|
+
log
|
|
173
192
|
);
|
|
174
193
|
const errData = errParser.mergeLeafRecursive(parsedXML['SOAP:Fault'][0]); // parse error data
|
|
175
194
|
return errorHandler.call(errParser, errData);
|
|
@@ -197,7 +197,7 @@ function formatPassengerCategories(pricingInfo) {
|
|
|
197
197
|
|
|
198
198
|
[code] = list;
|
|
199
199
|
if (!list[0] || list.length !== 1) { // TODO throw error
|
|
200
|
-
console.
|
|
200
|
+
console.warn('Warning: different categories '
|
|
201
201
|
+ list.join() + ' in single fare calculation ' + key + ' in fare ' + key);
|
|
202
202
|
}
|
|
203
203
|
passengerCounts[code] = count;
|
|
@@ -218,7 +218,7 @@ function airPrice(obj) {
|
|
|
218
218
|
|
|
219
219
|
let pricingSolution = 0;
|
|
220
220
|
if (priceKeys.length > 1) {
|
|
221
|
-
console.
|
|
221
|
+
console.warn('More than one solution found in booking. Resolving the cheapest one.');
|
|
222
222
|
const solutions = priceKeys.map((key) => pricingSolutions[key]);
|
|
223
223
|
|
|
224
224
|
[pricingSolution] = solutions.sort(
|
|
@@ -347,7 +347,7 @@ function airPriceRspPricingSolutionXML(obj) {
|
|
|
347
347
|
let pricingSolution = 0;
|
|
348
348
|
if (pricingSolutions.length > 1) {
|
|
349
349
|
// TODO: Check result for multiple passenger type results.
|
|
350
|
-
console.
|
|
350
|
+
console.warn('More than one solution found in booking. Resolving the cheapest one.');
|
|
351
351
|
[pricingSolution] = pricingSolutions.sort(
|
|
352
352
|
(a, b) => parseFloat(a.$.TotalPrice.slice(3)) - parseFloat(b.$.TotalPrice.slice(3))
|
|
353
353
|
);
|
|
@@ -207,6 +207,8 @@ module.exports = function (settings) {
|
|
|
207
207
|
|
|
208
208
|
// Get terminal ID
|
|
209
209
|
const getTerminalId = (sessionToken) => getHashSubstr(sessionToken);
|
|
210
|
+
const isClosed = () => state.terminalState === TERMINAL_STATE_CLOSED;
|
|
211
|
+
const isInitialized = () => state.terminalState !== TERMINAL_STATE_NONE;
|
|
210
212
|
|
|
211
213
|
const terminal = {
|
|
212
214
|
getToken: async () => {
|
|
@@ -251,6 +253,20 @@ module.exports = function (settings) {
|
|
|
251
253
|
throw err;
|
|
252
254
|
}
|
|
253
255
|
},
|
|
256
|
+
isClosed,
|
|
257
|
+
isInitialized,
|
|
258
|
+
closeSessionSafe: async () => {
|
|
259
|
+
if (isClosed()) {
|
|
260
|
+
console.warn('UAPI-JSON WARNING: Terminal session is already closed');
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (!isInitialized()) {
|
|
264
|
+
console.warn('UAPI-JSON WARNING: Terminal session is not initialized');
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
await terminal.closeSession().catch(console.error);
|
|
269
|
+
},
|
|
254
270
|
closeSession: () => getSessionToken()
|
|
255
271
|
.then(
|
|
256
272
|
(sessionToken) => service.closeSession({
|
|
@@ -50,6 +50,7 @@ Object.assign(TerminalRuntimeError, createErrorsList({
|
|
|
50
50
|
InvalidAccount: ['Invalid account', errorCodes.Validation],
|
|
51
51
|
TerminalUnexpectedError: ['Unexpected error message is returned by Travelport system. Please check PNR and try again later.', errorCodes.Validation],
|
|
52
52
|
TerminalUnexpectedFinancialError: ['Unexpected error message is returned by Travelport system. Please check PNR and new Fare calculation. If the problem persists, contact your local helpdesk.', errorCodes.Validation],
|
|
53
|
+
InvalidResponseFromHCA: 'Invalid response from HCA',
|
|
53
54
|
}, TerminalRuntimeError));
|
|
54
55
|
|
|
55
56
|
module.exports = {
|
|
@@ -24,12 +24,12 @@ function errorHandler(rsp) {
|
|
|
24
24
|
screen: faultString,
|
|
25
25
|
pcc: utils.getErrorPcc(rsp.faultstring),
|
|
26
26
|
});
|
|
27
|
+
case '2614':
|
|
28
|
+
throw new TerminalRuntimeError.InvalidResponseFromHCA({ screen: faultString });
|
|
27
29
|
case '6207': // Error retrieving AccessProfile Unable to retrieve enough Dynamic GTIDs for this transaction
|
|
28
30
|
case '6119': // Host system error
|
|
29
31
|
case '14058': // Could not locate Session Token Information Session May Have Timed Out
|
|
30
|
-
throw new RequestRuntimeError.UAPIServiceError({
|
|
31
|
-
screen: faultString,
|
|
32
|
-
});
|
|
32
|
+
throw new RequestRuntimeError.UAPIServiceError({ screen: faultString });
|
|
33
33
|
default:
|
|
34
34
|
throw new RequestRuntimeError.UnhandledError(null, new TerminalRuntimeError(rsp));
|
|
35
35
|
}
|