@sasjs/adapter 3.10.0 → 3.10.3
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 +5 -7
- package/index.js +2 -2
- package/node/index.js +2 -2
- package/node/types/errors/InvalidCsrfError.d.ts +3 -0
- package/package.json +6 -5
- package/src/api/viya/executeScript.ts +2 -2
- package/src/api/viya/writeStream.ts +1 -1
- package/src/job-execution/WebJobExecutor.ts +17 -9
- package/src/request/RequestClient.ts +33 -6
- package/src/request/Sas9RequestClient.ts +2 -2
- package/src/types/errors/InvalidCsrfError.ts +9 -0
- package/src/utils/getValidJson.ts +1 -1
- package/src/utils/parseSasViyaLog.ts +1 -1
- package/src/utils/parseWeboutResponse.ts +1 -1
- package/types/errors/InvalidCsrfError.d.ts +3 -0
package/package.json
CHANGED
|
@@ -44,18 +44,16 @@
|
|
|
44
44
|
"license": "ISC",
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@cypress/webpack-preprocessor": "5.9.1",
|
|
47
|
-
"@types/form-data": "2.5.0",
|
|
48
|
-
"cypress": "7.7.0",
|
|
49
|
-
"typedoc-neo-theme": "1.1.1",
|
|
50
|
-
"typedoc-plugin-external-module-name": "4.0.6",
|
|
51
47
|
"@types/axios": "0.14.0",
|
|
52
48
|
"@types/express": "4.17.13",
|
|
49
|
+
"@types/form-data": "2.5.0",
|
|
53
50
|
"@types/jest": "27.4.0",
|
|
54
51
|
"@types/mime": "2.0.3",
|
|
55
52
|
"@types/pem": "1.9.6",
|
|
56
53
|
"@types/tough-cookie": "4.0.1",
|
|
57
54
|
"copyfiles": "2.4.1",
|
|
58
55
|
"cp": "0.2.0",
|
|
56
|
+
"cypress": "7.7.0",
|
|
59
57
|
"dotenv": "16.0.0",
|
|
60
58
|
"express": "4.17.3",
|
|
61
59
|
"jest": "27.4.7",
|
|
@@ -63,6 +61,7 @@
|
|
|
63
61
|
"node-polyfill-webpack-plugin": "1.1.4",
|
|
64
62
|
"path": "0.12.7",
|
|
65
63
|
"pem": "1.14.6",
|
|
64
|
+
"prettier": "2.7.1",
|
|
66
65
|
"process": "0.11.10",
|
|
67
66
|
"rimraf": "3.0.2",
|
|
68
67
|
"semantic-release": "18.0.0",
|
|
@@ -72,6 +71,8 @@
|
|
|
72
71
|
"tslint": "6.1.3",
|
|
73
72
|
"tslint-config-prettier": "1.18.0",
|
|
74
73
|
"typedoc": "0.22.11",
|
|
74
|
+
"typedoc-neo-theme": "1.1.1",
|
|
75
|
+
"typedoc-plugin-external-module-name": "4.0.6",
|
|
75
76
|
"typedoc-plugin-rename-defaults": "0.4.0",
|
|
76
77
|
"typescript": "4.5.5",
|
|
77
78
|
"webpack": "5.69.0",
|
|
@@ -86,5 +87,5 @@
|
|
|
86
87
|
"https": "1.0.0",
|
|
87
88
|
"tough-cookie": "4.0.0"
|
|
88
89
|
},
|
|
89
|
-
"version": "3.10.
|
|
90
|
+
"version": "3.10.3"
|
|
90
91
|
}
|
|
@@ -240,7 +240,7 @@ export async function executeScript(
|
|
|
240
240
|
|
|
241
241
|
jobResult = await requestClient
|
|
242
242
|
.get<any>(resultLink, access_token, 'text/plain')
|
|
243
|
-
.catch(async (e) => {
|
|
243
|
+
.catch(async (e: any) => {
|
|
244
244
|
if (e instanceof NotFoundError) {
|
|
245
245
|
if (logLink) {
|
|
246
246
|
const logUrl = `${logLink.href}/content`
|
|
@@ -271,7 +271,7 @@ export async function executeScript(
|
|
|
271
271
|
})
|
|
272
272
|
|
|
273
273
|
return { result: jobResult?.result, log }
|
|
274
|
-
} catch (e) {
|
|
274
|
+
} catch (e: any) {
|
|
275
275
|
interface HttpError {
|
|
276
276
|
status: number
|
|
277
277
|
}
|
|
@@ -169,15 +169,23 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
169
169
|
? res.result.log.map((logLine: any) => logLine.line).join('\n')
|
|
170
170
|
: res.result.log
|
|
171
171
|
|
|
172
|
-
const resObj =
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
172
|
+
const resObj =
|
|
173
|
+
this.serverType === ServerType.Sasjs
|
|
174
|
+
? {
|
|
175
|
+
result: res.result._webout,
|
|
176
|
+
log: parsedSasjsServerLog
|
|
177
|
+
}
|
|
178
|
+
: res
|
|
179
|
+
|
|
180
|
+
if (
|
|
181
|
+
this.serverType === ServerType.Sasjs &&
|
|
182
|
+
res.result._webout.length < 1
|
|
183
|
+
) {
|
|
184
|
+
throw new JobExecutionError(
|
|
185
|
+
0,
|
|
186
|
+
`No webout was returned by job ${program}. Server type is SASJS and the calling function is WebJobExecutor. Please check the SAS log for more info.`,
|
|
187
|
+
parsedSasjsServerLog
|
|
188
|
+
)
|
|
181
189
|
}
|
|
182
190
|
|
|
183
191
|
this.requestClient!.appendRequest(resObj, sasJob, config.debug)
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
parseSourceCode,
|
|
20
20
|
createAxiosInstance
|
|
21
21
|
} from '../utils'
|
|
22
|
+
import { InvalidCsrfError } from '../types/errors/InvalidCsrfError'
|
|
22
23
|
|
|
23
24
|
export interface HttpClient {
|
|
24
25
|
get<T>(
|
|
@@ -206,7 +207,7 @@ export class RequestClient implements HttpClient {
|
|
|
206
207
|
|
|
207
208
|
return this.parseResponse<T>(response)
|
|
208
209
|
})
|
|
209
|
-
.catch(async (e) => {
|
|
210
|
+
.catch(async (e: any) => {
|
|
210
211
|
return await this.handleError(
|
|
211
212
|
e,
|
|
212
213
|
() =>
|
|
@@ -247,7 +248,7 @@ export class RequestClient implements HttpClient {
|
|
|
247
248
|
|
|
248
249
|
return this.parseResponse<T>(response)
|
|
249
250
|
})
|
|
250
|
-
.catch(async (e) => {
|
|
251
|
+
.catch(async (e: any) => {
|
|
251
252
|
return await this.handleError(e, () =>
|
|
252
253
|
this.post<T>(url, data, accessToken, contentType, overrideHeaders)
|
|
253
254
|
)
|
|
@@ -271,7 +272,7 @@ export class RequestClient implements HttpClient {
|
|
|
271
272
|
throwIfError(response)
|
|
272
273
|
return this.parseResponse<T>(response)
|
|
273
274
|
})
|
|
274
|
-
.catch(async (e) => {
|
|
275
|
+
.catch(async (e: any) => {
|
|
275
276
|
return await this.handleError(e, () =>
|
|
276
277
|
this.put<T>(url, data, accessToken, overrideHeaders)
|
|
277
278
|
)
|
|
@@ -290,7 +291,7 @@ export class RequestClient implements HttpClient {
|
|
|
290
291
|
throwIfError(response)
|
|
291
292
|
return this.parseResponse<T>(response)
|
|
292
293
|
})
|
|
293
|
-
.catch(async (e) => {
|
|
294
|
+
.catch(async (e: any) => {
|
|
294
295
|
return await this.handleError(e, () => this.delete<T>(url, accessToken))
|
|
295
296
|
})
|
|
296
297
|
}
|
|
@@ -308,7 +309,7 @@ export class RequestClient implements HttpClient {
|
|
|
308
309
|
throwIfError(response)
|
|
309
310
|
return this.parseResponse<T>(response)
|
|
310
311
|
})
|
|
311
|
-
.catch(async (e) => {
|
|
312
|
+
.catch(async (e: any) => {
|
|
312
313
|
return await this.handleError(e, () =>
|
|
313
314
|
this.patch<T>(url, data, accessToken)
|
|
314
315
|
)
|
|
@@ -498,6 +499,24 @@ export class RequestClient implements HttpClient {
|
|
|
498
499
|
throw e
|
|
499
500
|
}
|
|
500
501
|
|
|
502
|
+
if (e instanceof InvalidCsrfError) {
|
|
503
|
+
// Fetching root will inject CSRF token in cookie
|
|
504
|
+
await this.httpClient
|
|
505
|
+
.get('/', {
|
|
506
|
+
withCredentials: true
|
|
507
|
+
})
|
|
508
|
+
.catch((err) => {
|
|
509
|
+
throw prefixMessage(err, 'Error while re-fetching CSRF token.')
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
return await callback().catch((err: any) => {
|
|
513
|
+
throw prefixMessage(
|
|
514
|
+
err,
|
|
515
|
+
'Error while executing callback in handleError. '
|
|
516
|
+
)
|
|
517
|
+
})
|
|
518
|
+
}
|
|
519
|
+
|
|
501
520
|
if (response?.status === 403 || response?.status === 449) {
|
|
502
521
|
this.parseAndSetCsrfToken(response)
|
|
503
522
|
|
|
@@ -584,9 +603,17 @@ export class RequestClient implements HttpClient {
|
|
|
584
603
|
export const throwIfError = (response: AxiosResponse) => {
|
|
585
604
|
switch (response.status) {
|
|
586
605
|
case 400:
|
|
587
|
-
if (
|
|
606
|
+
if (
|
|
607
|
+
typeof response.data === 'object' &&
|
|
608
|
+
response.data.error === 'invalid_grant'
|
|
609
|
+
) {
|
|
610
|
+
// In SASVIYA when trying to get access token, if auth code is wrong status code will be 400 so in such case we return login required error.
|
|
588
611
|
throw new LoginRequiredError(response.data)
|
|
589
612
|
}
|
|
613
|
+
|
|
614
|
+
if (response.data.toLowerCase() === 'invalid csrf token!') {
|
|
615
|
+
throw new InvalidCsrfError()
|
|
616
|
+
}
|
|
590
617
|
break
|
|
591
618
|
case 401:
|
|
592
619
|
if (typeof response.data === 'object') {
|
|
@@ -68,7 +68,7 @@ export class Sas9RequestClient extends RequestClient {
|
|
|
68
68
|
throwIfError(response)
|
|
69
69
|
return this.parseResponse<T>(response)
|
|
70
70
|
})
|
|
71
|
-
.catch(async (e) => {
|
|
71
|
+
.catch(async (e: any) => {
|
|
72
72
|
return await this.handleError(
|
|
73
73
|
e,
|
|
74
74
|
() =>
|
|
@@ -113,7 +113,7 @@ export class Sas9RequestClient extends RequestClient {
|
|
|
113
113
|
throwIfError(response)
|
|
114
114
|
return this.parseResponse<T>(response)
|
|
115
115
|
})
|
|
116
|
-
.catch(async (e) => {
|
|
116
|
+
.catch(async (e: any) => {
|
|
117
117
|
return await this.handleError(e, () =>
|
|
118
118
|
this.post<T>(url, data, accessToken, contentType, overrideHeaders)
|
|
119
119
|
)
|
|
@@ -4,7 +4,7 @@ export const parseSasViyaLog = (logResponse: { items: any[] }) => {
|
|
|
4
4
|
log = logResponse.items
|
|
5
5
|
? logResponse.items.map((i) => i.line).join('\n')
|
|
6
6
|
: JSON.stringify(logResponse)
|
|
7
|
-
} catch (e) {
|
|
7
|
+
} catch (e: any) {
|
|
8
8
|
console.error('An error has occurred while parsing the log response', e)
|
|
9
9
|
log = logResponse
|
|
10
10
|
}
|
|
@@ -8,7 +8,7 @@ export const parseWeboutResponse = (response: string, url?: string): string => {
|
|
|
8
8
|
sasResponse = response
|
|
9
9
|
.split('>>weboutBEGIN<<')[1]
|
|
10
10
|
.split('>>weboutEND<<')[0]
|
|
11
|
-
} catch (e) {
|
|
11
|
+
} catch (e: any) {
|
|
12
12
|
if (url) throw new WeboutResponseError(url)
|
|
13
13
|
|
|
14
14
|
sasResponse = ''
|